Hi all,
This patch adds a new feature to the ``printf`` family of functions:
``%B`` conversion specifier for printing unsigned numbers in binary.
Behaviour is exactly as with ``%X``, only changing the base (16 -> 2).
``%b`` is already in use by some ``printf(1)`` implementations, so I
didn't use it for binary. Anyway, binary doesn't have letters, so only
the ``0b``/``0B`` specifier would change.
I also documented the new specifier in the man pages.
Disclaimer: I couldn't test it myself, so test it before applying it.
I also sent today a patch to add this specifier to glibc. They are
concerned about adding a new non-standard specifier, but if more C libs
are going to add it at the same time, it may become a thing.
Alex.
From 1a41d44571ccaf9ffaf36b2c2b96dd34e48eb5b7 Mon Sep 17 00:00:00 2001
From: Alejandro Colomar
Date: Mon, 27 Apr 2020 19:15:55 +0200
Subject: [PATCH 1/2] printf: Add %B conversion specifier for printing binary
---
lib/libc/stdio/vfprintf.c | 28
lib/libc/stdio/vfwprintf.c | 28
2 files changed, 40 insertions(+), 16 deletions(-)
diff --git a/lib/libc/stdio/vfprintf.c b/lib/libc/stdio/vfprintf.c
index 1d451a84f66..1e5cd3ad89b 100644
--- a/lib/libc/stdio/vfprintf.c
+++ b/lib/libc/stdio/vfprintf.c
@@ -310,9 +310,9 @@ __vfprintf(FILE *fp, const char *fmt0, __va_list ap)
char *dtoaresult = NULL;
#endif
- uintmax_t _umax;/* integer arguments %[diouxX] */
- enum { OCT, DEC, HEX } base;/* base for %[diouxX] conversion */
- int dprec; /* a copy of prec if %[diouxX], 0 otherwise */
+ uintmax_t _umax;/* integer arguments %[BdiouxX] */
+ enum { BIN, OCT, DEC, HEX } base; /* base for %[BdiouxX] conversion */
+ int dprec; /* a copy of prec if %[BdiouxX], 0 otherwise */
int realsz; /* field size expanded by dprec */
int size; /* size of converted field or string */
const char *xdigs; /* digits for %[xX] conversion */
@@ -320,7 +320,7 @@ __vfprintf(FILE *fp, const char *fmt0, __va_list ap)
struct __suio uio; /* output information: summary */
struct __siov iov[NIOV];/* ... and individual io vectors */
char buf[BUF]; /* buffer with space for digits of uintmax_t */
- char ox[2]; /* space for 0x; ox[1] is either x, X, or \0 */
+ char ox[2]; /* space for 0x; ox[1] is either x, X,B or \0 */
union arg *argtable;/* args, built due to positional arg */
union arg statargtable[STATIC_ARG_TBL_SIZE];
size_t argtablesiz;
@@ -891,6 +891,10 @@ fp_common:
_umax = UARG();
base = DEC;
goto nosign;
+ case 'B':
+ _umax = UARG();
+ base = BIN;
+ goto bin;
case 'X':
xdigs = xdigs_upper;
goto hex;
@@ -898,8 +902,8 @@ fp_common:
xdigs = xdigs_lower;
hex: _umax = UARG();
base = HEX;
- /* leading 0x/X only if non-zero */
- if (flags & ALT && _umax != 0)
+ /* leading 0x/X/B only if non-zero */
+bin: if (flags & ALT && _umax != 0)
ox[1] = ch;
/* unsigned conversions */
@@ -925,6 +929,13 @@ number:if ((dprec = prec) >= 0)
* a variable; hence this switch.
*/
switch (base) {
+ case BIN:
+ do {
+ *--cp = to_char(_umax & 1);
+ _umax >>= 1;
+ } while (_umax);
+ break;
+
case OCT:
do {
*--cp = to_char(_umax & 7);
@@ -980,7 +991,7 @@ number: if ((dprec = prec) >= 0)
* first be prefixed by any sign or other prefix; otherwise,
* it should be blank padded before the prefix is emitted.
* After any left-hand padding and prefixing, emit zeroes
-* required by a decimal %[diouxX] precision, then print the
+* required by a decimal %[BdiouxX] precision, then print the
* string proper, then emit zeroes required by any leftover
* floating precision; finally, if LADJUST, pad with blanks.
*
@@ -1000,7 +1011,7 @@ number: if ((dprec = prec) >= 0)
/* prefix */