summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorBruno Haible <bruno@clisp.org>2023-03-17 22:45:56 +0100
committerBruno Haible <bruno@clisp.org>2023-03-17 22:45:56 +0100
commitbb7cf2b64d2caf381249dda65ee0fe6766d9b3c6 (patch)
tree8f677d8de76d0bdbcd61ec347e926ad1bd325e3a /lib
parent21ed6e8365e371b9088df727d0449133df58e9bc (diff)
downloadgnulib-bb7cf2b64d2caf381249dda65ee0fe6766d9b3c6.tar.gz
*printf-posix: ISO C 23: Add %b directive for binary output of integers.
* lib/printf-parse.c (PRINTF_PARSE): Recognize the 'b' directive. * lib/printf-parse.h: Update comment. * lib/wprintf-parse.h: Likewise. * lib/vasnprintf.c (MAX_ROOM_NEEDED, VASNPRINTF): Add support for the 'b' directive. * m4/printf.m4 (gl_PRINTF_DIRECTIVE_B): New macro. * m4/vasnprintf.m4 (gl_PREREQ_VASNPRINTF_DIRECTIVE_B): New macro. (gl_PREREQ_VASNPRINTF_WITH_EXTRAS): Invoke it. * m4/vasnwprintf-posix.m4 (gl_FUNC_VASNWPRINTF_POSIX): Invoke gl_PREREQ_VASNPRINTF_DIRECTIVE_B. * m4/dprintf-posix.m4 (gl_FUNC_DPRINTF_POSIX): Require gl_PRINTF_DIRECTIVE_B and test its result. Invoke gl_PREREQ_VASNPRINTF_DIRECTIVE_B. * m4/fprintf-posix.m4 (gl_FUNC_FPRINTF_POSIX): Likewise. * m4/obstack-printf-posix.m4 (gl_FUNC_OBSTACK_PRINTF_POSIX): Likewise. * m4/snprintf-posix.m4 (gl_FUNC_SNPRINTF_POSIX): Likewise. * m4/sprintf-posix.m4 (gl_FUNC_SPRINTF_POSIX): Likewise. * m4/vasnprintf-posix.m4 (gl_FUNC_VASNPRINTF_POSIX): Likewise. * m4/vasprintf-posix.m4 (gl_FUNC_VASPRINTF_POSIX): Likewise. * m4/vdprintf-posix.m4 (gl_FUNC_VDPRINTF_POSIX): Likewise. * m4/vfprintf-posix.m4 (gl_FUNC_VFPRINTF_POSIX): Likewise. * m4/vsnprintf-posix.m4 (gl_FUNC_VSNPRINTF_POSIX): Likewise. * m4/vsprintf-posix.m4 (gl_FUNC_VSPRINTF_POSIX): Likewise. * tests/test-snprintf-posix.h (test_function): Add some tests of the %b directive. * tests/test-sprintf-posix.h (test_function): Likewise. * tests/test-vasnprintf-posix.c (test_function): Likewise. * tests/test-vasnwprintf-posix.c (test_function): Likewise. * tests/test-vasprintf-posix.c (test_function): Likewise. * doc/glibc-functions/asprintf.texi: Mention the 'b' directive. * doc/glibc-functions/obstack_printf.texi: Likewise. * doc/glibc-functions/obstack_vprintf.texi: Likewise. * doc/glibc-functions/vasprintf.texi: Likewise. * doc/posix-functions/dprintf.texi: Likewise. * doc/posix-functions/fprintf.texi: Likewise. * doc/posix-functions/fwprintf.texi: Likewise. * doc/posix-functions/printf.texi: Likewise. * doc/posix-functions/snprintf.texi: Likewise. * doc/posix-functions/sprintf.texi: Likewise. * doc/posix-functions/swprintf.texi: Likewise. * doc/posix-functions/vdprintf.texi: Likewise. * doc/posix-functions/vfprintf.texi: Likewise. * doc/posix-functions/vfwprintf.texi: Likewise. * doc/posix-functions/vprintf.texi: Likewise. * doc/posix-functions/vsnprintf.texi: Likewise. * doc/posix-functions/vsprintf.texi: Likewise. * doc/posix-functions/vswprintf.texi: Likewise. * doc/posix-functions/vwprintf.texi: Likewise. * doc/posix-functions/wprintf.texi: Likewise.
Diffstat (limited to 'lib')
-rw-r--r--lib/printf-parse.c2
-rw-r--r--lib/printf-parse.h2
-rw-r--r--lib/vasnprintf.c213
-rw-r--r--lib/wprintf-parse.h2
4 files changed, 216 insertions, 3 deletions
diff --git a/lib/printf-parse.c b/lib/printf-parse.c
index 3040749abd..6273dd773f 100644
--- a/lib/printf-parse.c
+++ b/lib/printf-parse.c
@@ -453,7 +453,7 @@ PRINTF_PARSE (const CHAR_T *format, DIRECTIVES *d, arguments *a)
else
type = TYPE_INT;
break;
- case 'o': case 'u': case 'x': case 'X':
+ case 'b': case 'o': case 'u': case 'x': case 'X':
/* If 'unsigned long long' is larger than 'unsigned long': */
if (flags >= 16 || (flags & 4))
type = TYPE_ULONGLONGINT;
diff --git a/lib/printf-parse.h b/lib/printf-parse.h
index 1f86e32c99..fcb3cc462e 100644
--- a/lib/printf-parse.h
+++ b/lib/printf-parse.h
@@ -61,7 +61,7 @@ typedef struct
const char* precision_start;
const char* precision_end;
size_t precision_arg_index;
- char conversion; /* d i o u x X f F e E g G a A c s p n U % but not C S */
+ char conversion; /* d i b o u x X f F e E g G a A c s p n U % but not C S */
size_t arg_index;
}
char_directive;
diff --git a/lib/vasnprintf.c b/lib/vasnprintf.c
index a49eb1dcd7..c2f10cb0c4 100644
--- a/lib/vasnprintf.c
+++ b/lib/vasnprintf.c
@@ -1653,6 +1653,25 @@ MAX_ROOM_NEEDED (const arguments *ap, size_t arg_index, FCHAR_T conversion,
tmp_length = xsum (tmp_length, 1);
break;
+ case 'b':
+ if (type == TYPE_ULONGLONGINT)
+ tmp_length =
+ (unsigned int) (sizeof (unsigned long long) * CHAR_BIT)
+ + 1; /* turn floor into ceil */
+ else if (type == TYPE_ULONGINT)
+ tmp_length =
+ (unsigned int) (sizeof (unsigned long) * CHAR_BIT)
+ + 1; /* turn floor into ceil */
+ else
+ tmp_length =
+ (unsigned int) (sizeof (unsigned int) * CHAR_BIT)
+ + 1; /* turn floor into ceil */
+ if (tmp_length < precision)
+ tmp_length = precision;
+ /* Add 2, to account for a prefix from the alternate form. */
+ tmp_length = xsum (tmp_length, 2);
+ break;
+
case 'o':
if (type == TYPE_ULONGLONGINT)
tmp_length =
@@ -3043,6 +3062,199 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
}
}
#endif
+#if NEED_PRINTF_DIRECTIVE_B
+ else if (dp->conversion == 'b')
+ {
+ arg_type type = a.arg[dp->arg_index].type;
+ int flags = dp->flags;
+ size_t width;
+ int has_precision;
+ size_t precision;
+ size_t tmp_length;
+ size_t count;
+ DCHAR_T tmpbuf[700];
+ DCHAR_T *tmp;
+ DCHAR_T *tmp_end;
+ DCHAR_T *tmp_start;
+ DCHAR_T *pad_ptr;
+ DCHAR_T *p;
+
+ width = 0;
+ if (dp->width_start != dp->width_end)
+ {
+ if (dp->width_arg_index != ARG_NONE)
+ {
+ int arg;
+
+ if (!(a.arg[dp->width_arg_index].type == TYPE_INT))
+ abort ();
+ arg = a.arg[dp->width_arg_index].a.a_int;
+ width = arg;
+ if (arg < 0)
+ {
+ /* "A negative field width is taken as a '-' flag
+ followed by a positive field width." */
+ flags |= FLAG_LEFT;
+ width = -width;
+ }
+ }
+ else
+ {
+ const FCHAR_T *digitp = dp->width_start;
+
+ do
+ width = xsum (xtimes (width, 10), *digitp++ - '0');
+ while (digitp != dp->width_end);
+ }
+ }
+
+ has_precision = 0;
+ precision = 0;
+ if (dp->precision_start != dp->precision_end)
+ {
+ if (dp->precision_arg_index != ARG_NONE)
+ {
+ int arg;
+
+ if (!(a.arg[dp->precision_arg_index].type == TYPE_INT))
+ abort ();
+ arg = a.arg[dp->precision_arg_index].a.a_int;
+ /* "A negative precision is taken as if the precision
+ were omitted." */
+ if (arg >= 0)
+ {
+ precision = arg;
+ has_precision = 1;
+ }
+ }
+ else
+ {
+ const FCHAR_T *digitp = dp->precision_start + 1;
+
+ precision = 0;
+ while (digitp != dp->precision_end)
+ precision = xsum (xtimes (precision, 10), *digitp++ - '0');
+ has_precision = 1;
+ }
+ }
+
+ /* Allocate a temporary buffer of sufficient size. */
+ if (type == TYPE_ULONGLONGINT)
+ tmp_length =
+ (unsigned int) (sizeof (unsigned long long) * CHAR_BIT)
+ + 1; /* turn floor into ceil */
+ else if (type == TYPE_ULONGINT)
+ tmp_length =
+ (unsigned int) (sizeof (unsigned long) * CHAR_BIT)
+ + 1; /* turn floor into ceil */
+ else
+ tmp_length =
+ (unsigned int) (sizeof (unsigned int) * CHAR_BIT)
+ + 1; /* turn floor into ceil */
+ if (tmp_length < precision)
+ tmp_length = precision;
+ /* Add 2, to account for a prefix from the alternate form. */
+ tmp_length = xsum (tmp_length, 2);
+
+ if (tmp_length < width)
+ tmp_length = width;
+
+ if (tmp_length <= sizeof (tmpbuf) / sizeof (DCHAR_T))
+ tmp = tmpbuf;
+ else
+ {
+ size_t tmp_memsize = xtimes (tmp_length, sizeof (DCHAR_T));
+
+ if (size_overflow_p (tmp_memsize))
+ /* Overflow, would lead to out of memory. */
+ goto out_of_memory;
+ tmp = (DCHAR_T *) malloc (tmp_memsize);
+ if (tmp == NULL)
+ /* Out of memory. */
+ goto out_of_memory;
+ }
+
+ tmp_end = tmp + tmp_length;
+
+ unsigned long long arg =
+ (type == TYPE_ULONGLONGINT ? a.arg[dp->arg_index].a.a_ulonglongint :
+ type == TYPE_ULONGINT ? a.arg[dp->arg_index].a.a_ulongint :
+ a.arg[dp->arg_index].a.a_uint);
+ int need_prefix = ((flags & FLAG_ALT) && arg != 0);
+
+ p = tmp_end;
+ do
+ {
+ *--p = '0' + (arg & 1);
+ arg = arg >> 1;
+ }
+ while (arg != 0);
+
+ pad_ptr = p;
+
+ if (need_prefix)
+ {
+ *--p = 'b'; *--p = '0';
+ }
+ tmp_start = p;
+
+ /* The generated string now extends from tmp_start to tmp_end,
+ with the zero padding insertion point being at pad_ptr,
+ tmp_start <= pad_ptr <= tmp_end. */
+ count = tmp_end - tmp_start;
+
+ if (count < width)
+ {
+ size_t pad = width - count;
+
+ if (flags & FLAG_LEFT)
+ {
+ /* Pad with spaces on the right. */
+ for (p = tmp_start; p < tmp_end; p++)
+ *(p - pad) = *p;
+ for (p = tmp_end - pad; p < tmp_end; p++)
+ *p = ' ';
+ }
+ else if (flags & FLAG_ZERO)
+ {
+ /* Pad with zeroes. */
+ for (p = tmp_start; p < pad_ptr; p++)
+ *(p - pad) = *p;
+ for (p = pad_ptr - pad; p < pad_ptr; p++)
+ *p = '0';
+ }
+ else
+ {
+ /* Pad with spaces on the left. */
+ for (p = tmp_start - pad; p < tmp_start; p++)
+ *p = ' ';
+ }
+
+ tmp_start = tmp_start - pad;
+ }
+
+ count = tmp_end - tmp_start;
+
+ if (count > tmp_length)
+ /* tmp_length was incorrectly calculated - fix the
+ code above! */
+ abort ();
+
+ /* Make room for the result. */
+ if (count >= allocated - length)
+ {
+ size_t n = xsum (length, count);
+
+ ENSURE_ALLOCATION (n);
+ }
+
+ /* Append the result. */
+ memcpy (result + length, tmp_start, count * sizeof (DCHAR_T));
+ if (tmp != tmpbuf)
+ free (tmp);
+ length += count;
+ }
+#endif
#if NEED_PRINTF_DIRECTIVE_A || NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_DOUBLE
else if ((dp->conversion == 'a' || dp->conversion == 'A')
# if !(NEED_PRINTF_DIRECTIVE_A || (NEED_PRINTF_LONG_DOUBLE && NEED_PRINTF_DOUBLE))
@@ -4826,6 +5038,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
switch (dp->conversion)
{
case 'd': case 'i': case 'u':
+ case 'b':
case 'o':
case 'x': case 'X': case 'p':
prec_ourselves = has_precision && (precision > 0);
diff --git a/lib/wprintf-parse.h b/lib/wprintf-parse.h
index 05799b8f15..86bdec9a21 100644
--- a/lib/wprintf-parse.h
+++ b/lib/wprintf-parse.h
@@ -55,7 +55,7 @@ typedef struct
const wchar_t* precision_start;
const wchar_t* precision_end;
size_t precision_arg_index;
- wchar_t conversion; /* d i o u x X f F e E g G a A c s p n U % but not C S */
+ wchar_t conversion; /* d i b o u x X f F e E g G a A c s p n U % but not C S */
size_t arg_index;
}
wchar_t_directive;