diff options
author | Bruno Haible <bruno@clisp.org> | 2023-03-17 22:45:56 +0100 |
---|---|---|
committer | Bruno Haible <bruno@clisp.org> | 2023-03-17 22:45:56 +0100 |
commit | bb7cf2b64d2caf381249dda65ee0fe6766d9b3c6 (patch) | |
tree | 8f677d8de76d0bdbcd61ec347e926ad1bd325e3a /lib | |
parent | 21ed6e8365e371b9088df727d0449133df58e9bc (diff) | |
download | gnulib-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.c | 2 | ||||
-rw-r--r-- | lib/printf-parse.h | 2 | ||||
-rw-r--r-- | lib/vasnprintf.c | 213 | ||||
-rw-r--r-- | lib/wprintf-parse.h | 2 |
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; |