*printf-posix: ISO C 23: Add %b directive for binary output of integers
This set of patches adds support for the %b format string directive, required by ISO C 23, to the *printf family of functions. So far, only glibc implements it (since version 2.35). For portability to the other platforms, use the *printf-posix modules. 2023-03-17 Bruno Haible *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. 2023-03-17 Bruno Haible vasnprintf, vasnwprintf: Simplify code. * lib/vasnprintf.c (MAX_ROOM_NEEDED): Remove dead code: The directives 'o', 'x', 'X' always take an unsigned integer argument. >From 21ed6e8365e371b9088df727d0449133df58e9bc Mon Sep 17 00:00:00 2001 From: Bruno Haible Date: Fri, 17 Mar 2023 22:33:24 +0100 Subject: [PATCH 1/2] vasnprintf, vasnwprintf: Simplify code. * lib/vasnprintf.c (MAX_ROOM_NEEDED): Remove dead code: The directives 'o', 'x', 'X' always take an unsigned integer argument. --- ChangeLog| 6 ++ lib/vasnprintf.c | 10 +- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/ChangeLog b/ChangeLog index 8318d7f6fc..62dd39e17f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2023-03-17 Bruno Haible + + vasnprintf, vasnwprintf: Simplify code. + * lib/vasnprintf.c (MAX_ROOM_NEEDED): Remove dead code: The directives + 'o', 'x', 'X' always take an unsigned integer argument. + 2023-03-17 Bruno Haible vasnwprintf: Fix test failure on OpenBSD. diff --git a/lib/vasnprintf.c b/lib/vasnprintf.c index 74a6712926..a49eb1dcd7 100644 --- a/lib/vasnprintf.c +++ b/lib/vasnprintf.c @@ -1654,13 +1654,13 @@ MAX_ROOM_NEEDED (const arguments *ap, size_t arg_index, FCHAR_T conversion, break; case 'o': - if (type == TYPE_LONGLONGINT || type == TYPE_ULONGLONGINT) + if (type == TYPE_ULONGLONGINT) tmp_length = (unsigned int) (sizeof (unsigned long long) * CHAR_BIT * 0.34 /* binary -> octal */
Re: *printf-posix: ISO C 23: Add %b directive for binary output of integers
On 17/03/2023 21:51, Bruno Haible wrote: This set of patches adds support for the %b format string directive, required by ISO C 23, to the *printf family of functions. So far, only glibc implements it (since version 2.35). For portability to the other platforms, use the *printf-posix modules. For my reference mainly... It's interesting that this conflicts with the POSIX specified %b directive for the printf(1) utility. cheers, Pádraig
Re: *printf-posix: ISO C 23: Add %b directive for binary output of integers
On Sat, Mar 18, 2023 at 11:50:47AM +, Pádraig Brady wrote: > On 17/03/2023 21:51, Bruno Haible wrote: > > This set of patches adds support for the %b format string directive, > > required > > by ISO C 23, to the *printf family of functions. > > > > So far, only glibc implements it (since version 2.35). For portability to > > the > > other platforms, use the *printf-posix modules. > > For my reference mainly... > > It's interesting that this conflicts with the POSIX specified %b directive > for the printf(1) utility. Another consideration: C23 admits that %#B is not available for portable use of outputting uppercase '0B...', you would have to manually write 0B%b instead. However, since glibc DOES support %B as the uppercase counterpart to %b, should we add that in gnulib (but this time under the auspices of *printf-gnu, rather than *printf-posix)? -- Eric Blake, Principal Software Engineer Red Hat, Inc. +1-919-301-3266 Virtualization: qemu.org | libvirt.org
Re: *printf-posix: ISO C 23: Add %b directive for binary output of integers
Some details of the %b implementation that I added on 2023-03-17 were incorrect. This patch fixes them, while adding new unit tests. 2023-03-22 Bruno Haible *printf-posix: Fix implementation of %b directive. * lib/vasnprintf.c (VASNPRINTF): In the %b directive implementation, fix the precision handling, and ignore the '0' flag when a width and a precision are both present. * tests/test-snprintf-posix.h (test_function): Add test cases for the %x directive and more test cases for 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. * modules/vasnwprintf-posix-tests (Files): Add m4/musl.m4. (configure.ac): Invoke gl_MUSL_LIBC. diff --git a/lib/vasnprintf.c b/lib/vasnprintf.c index 5cd52b5b6e..248444ca23 100644 --- a/lib/vasnprintf.c +++ b/lib/vasnprintf.c @@ -3217,6 +3217,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, { arg_type type = a.arg[dp->arg_index].type; int flags = dp->flags; +int has_width; size_t width; int has_precision; size_t precision; @@ -3229,6 +3230,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, DCHAR_T *pad_ptr; DCHAR_T *p; +has_width = 0; width = 0; if (dp->width_start != dp->width_end) { @@ -3256,10 +3258,11 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, width = xsum (xtimes (width, 10), *digitp++ - '0'); while (digitp != dp->width_end); } +has_width = 1; } has_precision = 0; -precision = 0; +precision = 1; if (dp->precision_start != dp->precision_end) { if (dp->precision_arg_index != ARG_NONE) @@ -,12 +3336,24 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, int need_prefix = ((flags & FLAG_ALT) && arg != 0); p = tmp_end; -do +/* "The result of converting a zero value with a precision + of zero is no characters." */ +if (!(has_precision && precision == 0 && arg == 0)) + { +do + { +*--p = '0' + (arg & 1); +arg = arg >> 1; + } +while (arg != 0); + } + +if (has_precision) { -*--p = '0' + (arg & 1); -arg = arg >> 1; +DCHAR_T *digits_start = tmp_end - precision; +while (p > digits_start) + *--p = '0'; } -while (arg != 0); pad_ptr = p; @@ -3365,7 +3380,12 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, for (p = tmp_end - pad; p < tmp_end; p++) *p = ' '; } -else if (flags & FLAG_ZERO) +else if ((flags & FLAG_ZERO) + /* Neither ISO C nor POSIX specify that the '0' +flag is ignored when a width and a precision +are both present. But most implementations +do so. */ + && !(has_width && has_precision)) { /* Pad with zeroes. */ for (p = tmp_start; p < pad_ptr; p++) diff --git a/modules/vasnwprintf-posix-tests b/modules/vasnwprintf-posix-tests index 667eb61103..6354e79f75 100644 --- a/modules/vasnwprintf-posix-tests +++ b/modules/vasnwprintf-posix-tests @@ -7,6 +7,7 @@ tests/minus-zero.h tests/infinity.h tests/nan.h tests/macros.h +m4/musl.m4 m4/locale-fr.m4 m4/codeset.m4 @@ -21,6 +22,7 @@ wmemcpy configure.ac: AC_REQUIRE([gl_LONG_DOUBLE_VS_DOUBLE]) +gl_MUSL_LIBC gt_LOCALE_FR gt_LOCALE_FR_UTF8 diff --git a/tests/test-snprintf-posix.h b/tests/test-snprintf-posix.h index 05c7be8059..a8993f947a 100644 --- a/tests/test-snprintf-posix.h +++ b/tests/test-snprintf-posix.h @@ -3091,6 +3091,190 @@ test_function (int (*my_snprintf) (char *, size_t, const char *, ...)) } #endif + /* Test the support of the 'x' conversion specifier for hexadecimal output of + integers. */ + + { /* Zero. */ +int retval = + my_snprintf (result, sizeof (result), "%x %d", 0, 33, 44, 55); +ASSERT (strcmp (result, "0 33") == 0); +ASSERT (retval