diff options
author | Joseph Myers <joseph@codesourcery.com> | 2023-06-19 18:52:12 +0000 |
---|---|---|
committer | Joseph Myers <joseph@codesourcery.com> | 2023-06-19 18:52:12 +0000 |
commit | 5f83b2674e42cd74257731b281f66d0442bf045f (patch) | |
tree | cb4d3f19d481d718c4800218f20afc93441199e3 | |
parent | 8022fc7d5119a22e9e0ac72798f649385b0e167a (diff) | |
download | glibc-5f83b2674e42cd74257731b281f66d0442bf045f.tar.gz glibc-5f83b2674e42cd74257731b281f66d0442bf045f.tar.xz glibc-5f83b2674e42cd74257731b281f66d0442bf045f.zip |
C2x printf %wN, %wfN support (bug 24466)
ISO C2x defines printf length modifiers wN (for intN_t / int_leastN_t / uintN_t / uint_leastN_t) and wfN (for int_fastN_t / uint_fastN_t). Add support for those length modifiers (such a feature was previously requested in bug 24466). scanf support is to be added separately. GCC 13 has format checking support for these modifiers. When used with the support for registering format specifiers, these modifiers are translated to existing flags in struct printf_info, rather than trying to add some way of distinguishing them without breaking the printf_info ABI. C2x requires an error to be returned for unsupported values of N; this is implemented for printf-family functions, but the parse_printf_format interface doesn't support error returns, so such an error gets discarded by that function. Tested for x86_64 and x86.
-rw-r--r-- | NEWS | 7 | ||||
-rw-r--r-- | manual/stdio.texi | 18 | ||||
-rw-r--r-- | stdio-common/Makefile | 1 | ||||
-rw-r--r-- | stdio-common/printf-parse.h | 9 | ||||
-rw-r--r-- | stdio-common/printf-parsemb.c | 56 | ||||
-rw-r--r-- | stdio-common/printf-prs.c | 3 | ||||
-rw-r--r-- | stdio-common/tst-printf-intn-main.c | 637 | ||||
-rw-r--r-- | stdio-common/tst-printf-intn.c | 26 | ||||
-rw-r--r-- | stdio-common/vfprintf-internal.c | 82 | ||||
-rw-r--r-- | wcsmbs/Makefile | 1 | ||||
-rw-r--r-- | wcsmbs/tst-wprintf-intn.c | 26 |
11 files changed, 851 insertions, 15 deletions
diff --git a/NEWS b/NEWS index 7a4df85f08..7cec03cc76 100644 --- a/NEWS +++ b/NEWS @@ -21,6 +21,13 @@ Major new features: * PRIb* and PRIB* macros from C2X have been added to <inttypes.h>. +* printf-family functions now support the wN format length modifiers for + arguments of type intN_t, int_leastN_t, uintN_t or uint_leastN_t (for + example, %w32d to print int32_t or int_least32_t in decimal, or %w32x + to print uint32_t or uint_least32_t in hexadecimal) and the wfN format + length modifiers for arguments of type int_fastN_t or uint_fastN_t, as + specified in draft ISO C2X. + * A new tunable, glibc.pthread.stack_hugetlb, can be used to disable Transparent Huge Pages (THP) in stack allocation at pthread_create. diff --git a/manual/stdio.texi b/manual/stdio.texi index 3820a24f3e..a981e6512a 100644 --- a/manual/stdio.texi +++ b/manual/stdio.texi @@ -2028,6 +2028,24 @@ Specifies that the argument is a @code{ptrdiff_t}. This modifier was introduced in @w{ISO C99}. +@item w@var{n} +Specifies that the argument is a @code{int@var{n}_t} or +@code{int_least@var{n}_t} (which are the same type), for conversions +taking signed integers, or @code{uint@var{n}_t} or +@code{uint_least@var{n}_t} (which are the same type), for conversions +taking unsigned integers. If the type is narrower than @code{int}, +the promoted argument is converted back to the specified type. + +This modifier was introduced in @w{ISO C2X}. + +@item wf@var{n} +Specifies that the argument is a @code{int_fast@var{n}_t} or +@code{uint_fast@var{n}_t}, as appropriate. If the type is narrower +than @code{int}, the promoted argument is converted back to the +specified type. + +This modifier was introduced in @w{ISO C2X}. + @item z @itemx Z Specifies that the argument is a @code{size_t}. diff --git a/stdio-common/Makefile b/stdio-common/Makefile index 4c15b97683..8871ec7668 100644 --- a/stdio-common/Makefile +++ b/stdio-common/Makefile @@ -219,6 +219,7 @@ tests := \ tst-printf-bz25691 \ tst-printf-fp-free \ tst-printf-fp-leak \ + tst-printf-intn \ tst-printf-oct \ tst-printf-round \ tst-printfsz \ diff --git a/stdio-common/printf-parse.h b/stdio-common/printf-parse.h index b25181496c..57673a331d 100644 --- a/stdio-common/printf-parse.h +++ b/stdio-common/printf-parse.h @@ -93,14 +93,17 @@ __find_specwc (const unsigned int *format) with the parsed details. POSN is the number of arguments already consumed. At most MAXTYPES - POSN types are filled in TYPES. Return the number of args consumed by this spec; *MAX_REF_ARG is updated so it - remains the highest argument index used. */ + remains the highest argument index used. *FAILED is set to indicate + whether parsing failed and printf should return with an error status. */ extern size_t __parse_one_specmb (const unsigned char *format, size_t posn, struct printf_spec *spec, - size_t *max_ref_arg) attribute_hidden; + size_t *max_ref_arg, + bool *failed) attribute_hidden; extern size_t __parse_one_specwc (const unsigned int *format, size_t posn, struct printf_spec *spec, - size_t *max_ref_arg) attribute_hidden; + size_t *max_ref_arg, + bool *failed) attribute_hidden; diff --git a/stdio-common/printf-parsemb.c b/stdio-common/printf-parsemb.c index c5d2704b02..414cbc7223 100644 --- a/stdio-common/printf-parsemb.c +++ b/stdio-common/printf-parsemb.c @@ -56,14 +56,17 @@ size_t attribute_hidden #ifdef COMPILE_WPRINTF __parse_one_specwc (const UCHAR_T *format, size_t posn, - struct printf_spec *spec, size_t *max_ref_arg) + struct printf_spec *spec, size_t *max_ref_arg, + bool *failed) #else __parse_one_specmb (const UCHAR_T *format, size_t posn, - struct printf_spec *spec, size_t *max_ref_arg) + struct printf_spec *spec, size_t *max_ref_arg, + bool *failed) #endif { unsigned int n; size_t nargs = 0; + bool is_fast; /* Skip the '%'. */ ++format; @@ -81,6 +84,8 @@ __parse_one_specmb (const UCHAR_T *format, size_t posn, spec->info.wide = sizeof (UCHAR_T) > 1; spec->info.is_binary128 = 0; + *failed = false; + /* Test for positional argument. */ if (ISDIGIT (*format)) { @@ -298,6 +303,53 @@ __parse_one_specmb (const UCHAR_T *format, size_t posn, #endif spec->info.is_long = sizeof (uintmax_t) > sizeof (unsigned int); break; + case L_('w'): + is_fast = false; + if (*format == L_('f')) + { + ++format; + is_fast = true; + } + int bitwidth = 0; + if (ISDIGIT (*format)) + bitwidth = read_int (&format); + if (is_fast) + switch (bitwidth) + { + case 8: + bitwidth = INT_FAST8_WIDTH; + break; + case 16: + bitwidth = INT_FAST16_WIDTH; + break; + case 32: + bitwidth = INT_FAST32_WIDTH; + break; + case 64: + bitwidth = INT_FAST64_WIDTH; + break; + } + switch (bitwidth) + { + case 8: + spec->info.is_char = 1; + break; + case 16: + spec->info.is_short = 1; + break; + case 32: + break; + case 64: + spec->info.is_long_double = 1; + spec->info.is_long = 1; + break; + default: + /* ISO C requires this error to be detected. */ + __set_errno (EINVAL); + *failed = true; + break; + } + break; default: /* Not a recognized modifier. Backup. */ --format; diff --git a/stdio-common/printf-prs.c b/stdio-common/printf-prs.c index 2408a2e328..9d8bf306e4 100644 --- a/stdio-common/printf-prs.c +++ b/stdio-common/printf-prs.c @@ -63,6 +63,7 @@ parse_printf_format (const char *fmt, size_t n, int *argtypes) size_t max_ref_arg; /* Highest index used in a positional arg. */ struct printf_spec spec; const unsigned char *f = (const unsigned char *) fmt; + bool failed; nargs = 0; max_ref_arg = 0; @@ -71,7 +72,7 @@ parse_printf_format (const char *fmt, size_t n, int *argtypes) for (f = __find_specmb (f); *f != '\0'; f = spec.next_fmt) { /* Parse this spec. */ - nargs += __parse_one_specmb (f, nargs, &spec, &max_ref_arg); + nargs += __parse_one_specmb (f, nargs, &spec, &max_ref_arg, &failed); /* If the width is determined by an argument, it is an int. */ if (spec.width_arg != -1 && (size_t) spec.width_arg < n) diff --git a/stdio-common/tst-printf-intn-main.c b/stdio-common/tst-printf-intn-main.c new file mode 100644 index 0000000000..bd70e9de73 --- /dev/null +++ b/stdio-common/tst-printf-intn-main.c @@ -0,0 +1,637 @@ +/* Test printf formats for intN_t, int_leastN_t and int_fastN_t types. + Copyright (C) 2023 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <https://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <inttypes.h> +#include <limits.h> +#include <stdio.h> +#include <string.h> +#include <wchar.h> + +#include <libc-diag.h> +#include <support/check.h> + +/* GCC does not know the %wN or %wfN length modifiers before GCC 13. */ +DIAG_PUSH_NEEDS_COMMENT; +#if !__GNUC_PREREQ (13, 0) +DIAG_IGNORE_NEEDS_COMMENT (12, "-Wformat"); +DIAG_IGNORE_NEEDS_COMMENT (12, "-Wformat-extra-args"); +#endif + +#define CHECK_PRINTF(EXPECTED, FMT, ...) \ + do \ + { \ + int ret = SNPRINTF (buf, sizeof buf / sizeof buf[0], L_(FMT), \ + __VA_ARGS__); \ + TEST_COMPARE_STRING_MACRO (buf, L_(EXPECTED)); \ + TEST_COMPARE (ret, STRLEN (L_(EXPECTED))); \ + } \ + while (0) + +#define CHECK_PRINTF_ERR(FMT, ...) \ + do \ + { \ + int ret = SNPRINTF (buf, sizeof buf / sizeof buf[0], L_(FMT), \ + __VA_ARGS__); \ + TEST_VERIFY (ret < 0); \ + TEST_COMPARE (errno, EINVAL); \ + } \ + while (0) + +static void +test_w8 (void) +{ + CHAR buf[1024]; + CHECK_PRINTF ("123", "%w8d", (int8_t) 123); + CHECK_PRINTF ("-123", "%w8d", (int8_t) -123); + CHECK_PRINTF ("123", "%w8i", (int8_t) 123); + CHECK_PRINTF ("-123", "%w8i", (int8_t) -123); + CHECK_PRINTF ("1111011", "%w8b", (uint8_t) 123); + CHECK_PRINTF ("1111011", "%w8B", (uint8_t) 123); + CHECK_PRINTF ("173", "%w8o", (uint8_t) 123); + CHECK_PRINTF ("123", "%w8u", (uint8_t) 123); + CHECK_PRINTF ("7b", "%w8x", (uint8_t) 123); + CHECK_PRINTF ("7B", "%w8X", (uint8_t) 123); + CHECK_PRINTF (" 123", "%5w8d", (int8_t) 123); + CHECK_PRINTF (" 123", "%*w8d", 5, (int8_t) 123); + CHECK_PRINTF ("0x7b", "%#w8x", (uint8_t) 123); + CHECK_PRINTF ("00123", "%.5w8d", (int8_t) 123); + CHECK_PRINTF ("00123", "%.*w8d", 5, (int8_t) 123); + CHECK_PRINTF (" 00123", "%8.5w8d", (int8_t) 123); + CHECK_PRINTF (" 00123", "%*.5w8d", 8, (int8_t) 123); + CHECK_PRINTF (" 00123", "%8.*w8d", 5, (int8_t) 123); + CHECK_PRINTF (" 00123", "%*.*w8d", 8, 5, (int8_t) 123); + CHECK_PRINTF ("00123 ", "%-8.5w8d", (int8_t) 123); + CHECK_PRINTF ("00123 ", "%-*.5w8d", 8, (int8_t) 123); + CHECK_PRINTF ("00123 ", "%-8.*w8d", 5, (int8_t) 123); + CHECK_PRINTF ("00123 ", "%-*.*w8d", 8, 5, (int8_t) 123); + { + int8_t n = -1; + CHECK_PRINTF ("12345", "%d%w8n", 12345, &n); + TEST_COMPARE (n, 5); + } + CHECK_PRINTF ("123", "%w8d", (int_least8_t) 123); + CHECK_PRINTF ("-123", "%w8d", (int_least8_t) -123); + CHECK_PRINTF ("123", "%w8i", (int_least8_t) 123); + CHECK_PRINTF ("-123", "%w8i", (int_least8_t) -123); + CHECK_PRINTF ("1111011", "%w8b", (uint_least8_t) 123); + CHECK_PRINTF ("1111011", "%w8B", (uint_least8_t) 123); + CHECK_PRINTF ("173", "%w8o", (uint_least8_t) 123); + CHECK_PRINTF ("123", "%w8u", (uint_least8_t) 123); + CHECK_PRINTF ("7b", "%w8x", (uint_least8_t) 123); + CHECK_PRINTF ("7B", "%w8X", (uint_least8_t) 123); + CHECK_PRINTF (" 123", "%5w8d", (int_least8_t) 123); + CHECK_PRINTF (" 123", "%*w8d", 5, (int_least8_t) 123); + CHECK_PRINTF ("0x7b", "%#w8x", (uint_least8_t) 123); + CHECK_PRINTF ("00123", "%.5w8d", (int_least8_t) 123); + CHECK_PRINTF ("00123", "%.*w8d", 5, (int_least8_t) 123); + CHECK_PRINTF (" 00123", "%8.5w8d", (int_least8_t) 123); + CHECK_PRINTF (" 00123", "%*.5w8d", 8, (int_least8_t) 123); + CHECK_PRINTF (" 00123", "%8.*w8d", 5, (int_least8_t) 123); + CHECK_PRINTF (" 00123", "%*.*w8d", 8, 5, (int_least8_t) 123); + CHECK_PRINTF ("00123 ", "%-8.5w8d", (int_least8_t) 123); + CHECK_PRINTF ("00123 ", "%-*.5w8d", 8, (int_least8_t) 123); + CHECK_PRINTF ("00123 ", "%-8.*w8d", 5, (int_least8_t) 123); + CHECK_PRINTF ("00123 ", "%-*.*w8d", 8, 5, (int_least8_t) 123); + { + int_least8_t ln = -1; + CHECK_PRINTF ("12345", "%d%w8n", 12345, &ln); + TEST_COMPARE (ln, 5); + } + /* Test truncation of value in promoted type not representable in + narrower type. */ + CHECK_PRINTF ("57", "%w8d", 12345); + CHECK_PRINTF ("-57", "%w8d", -12345); + CHECK_PRINTF ("-121", "%w8d", 1234567); + CHECK_PRINTF ("121", "%w8d", -1234567); + CHECK_PRINTF ("135", "%w8u", 1234567); + /* Test positional argument handling. */ + CHECK_PRINTF ("test 10 test2 20", "%4$s %3$w8d %2$s %1$w8d", + 276, "test2", 266, "test"); +} + +static void +test_wf8 (void) +{ + CHAR buf[1024]; + _Static_assert (sizeof (int_fast8_t) == sizeof (char), + "test assumes size of int_fast8_t"); + CHECK_PRINTF ("123", "%wf8d", (int_fast8_t) 123); + CHECK_PRINTF ("-123", "%wf8d", (int_fast8_t) -123); + CHECK_PRINTF ("123", "%wf8i", (int_fast8_t) 123); + CHECK_PRINTF ("-123", "%wf8i", (int_fast8_t) -123); + CHECK_PRINTF ("1111011", "%wf8b", (uint_fast8_t) 123); + CHECK_PRINTF ("1111011", "%wf8B", (uint_fast8_t) 123); + CHECK_PRINTF ("173", "%wf8o", (uint_fast8_t) 123); + CHECK_PRINTF ("123", "%wf8u", (uint_fast8_t) 123); + CHECK_PRINTF ("7b", "%wf8x", (uint_fast8_t) 123); + CHECK_PRINTF ("7B", "%wf8X", (uint_fast8_t) 123); + CHECK_PRINTF (" 123", "%5w8d", (int_fast8_t) 123); + CHECK_PRINTF (" 123", "%*w8d", 5, (int_fast8_t) 123); + CHECK_PRINTF ("0x7b", "%#w8x", (uint_fast8_t) 123); + CHECK_PRINTF ("00123", "%.5w8d", (int_fast8_t) 123); + CHECK_PRINTF ("00123", "%.*w8d", 5, (int_fast8_t) 123); + CHECK_PRINTF (" 00123", "%8.5w8d", (int_fast8_t) 123); + CHECK_PRINTF (" 00123", "%*.5w8d", 8, (int_fast8_t) 123); + CHECK_PRINTF (" 00123", "%8.*w8d", 5, (int_fast8_t) 123); + CHECK_PRINTF (" 00123", "%*.*w8d", 8, 5, (int_fast8_t) 123); + CHECK_PRINTF ("00123 ", "%-8.5w8d", (int_fast8_t) 123); + CHECK_PRINTF ("00123 ", "%-*.5w8d", 8, (int_fast8_t) 123); + CHECK_PRINTF ("00123 ", "%-8.*w8d", 5, (int_fast8_t) 123); + CHECK_PRINTF ("00123 ", "%-*.*w8d", 8, 5, (int_fast8_t) 123); + { + int_fast8_t n = -1; + CHECK_PRINTF ("12345", "%d%wf8n", 12345, &n); + TEST_COMPARE (n, 5); + } + /* Test truncation of value in promoted type not representable in + narrower type. */ + CHECK_PRINTF ("57", "%wf8d", 12345); + CHECK_PRINTF ("-57", "%wf8d", -12345); + CHECK_PRINTF ("-121", "%wf8d", 1234567); + CHECK_PRINTF ("121", "%wf8d", -1234567); + CHECK_PRINTF ("135", "%wf8u", 1234567); + /* Test positional argument handling. */ + CHECK_PRINTF ("test 10 test2 20", "%4$s %3$wf8d %2$s %1$wf8d", + 276, "test2", 266, "test"); +} + +static void +test_w16 (void) +{ + CHAR buf[1024]; + CHECK_PRINTF ("12345", "%w16d", (int16_t) 12345); + CHECK_PRINTF ("-12345", "%w16d", (int16_t) -12345); + CHECK_PRINTF ("12345", "%w16i", (int16_t) 12345); + CHECK_PRINTF ("-12345", "%w16i", (int16_t) -12345); + CHECK_PRINTF ("11000000111001", "%w16b", (uint16_t) 12345); + CHECK_PRINTF ("11000000111001", "%w16B", (uint16_t) 12345); + CHECK_PRINTF ("30071", "%w16o", (uint16_t) 12345); + CHECK_PRINTF ("12345", "%w16u", (uint16_t) 12345); + CHECK_PRINTF ("303a", "%w16x", (uint16_t) 12346); + CHECK_PRINTF ("303A", "%w16X", (uint16_t) 12346); + CHECK_PRINTF (" 12345", "%7w16d", (int16_t) 12345); + CHECK_PRINTF (" 12345", "%*w16d", 7, (int16_t) 12345); + CHECK_PRINTF ("0x3039", "%#w16x", (uint16_t) 12345); + CHECK_PRINTF ("0012345", "%.7w16d", (int16_t) 12345); + CHECK_PRINTF ("0012345", "%.*w16d", 7, (int16_t) 12345); + CHECK_PRINTF (" 0012345", "%10.7w16d", (int16_t) 12345); + CHECK_PRINTF (" 0012345", "%*.7w16d", 10, (int16_t) 12345); + CHECK_PRINTF (" 0012345", "%10.*w16d", 7, (int16_t) 12345); + CHECK_PRINTF (" 0012345", "%*.*w16d", 10, 7, (int16_t) 12345); + CHECK_PRINTF ("0012345 ", "%-10.7w16d", (int16_t) 12345); + CHECK_PRINTF ("0012345 ", "%-*.7w16d", 10, (int16_t) 12345); + CHECK_PRINTF ("0012345 ", "%-10.*w16d", 7, (int16_t) 12345); + CHECK_PRINTF ("0012345 ", "%-*.*w16d", 10, 7, (int16_t) 12345); + { + int16_t n = -1; + CHECK_PRINTF ("12345", "%d%w16n", 12345, &n); + TEST_COMPARE (n, 5); + } + CHECK_PRINTF ("12345", "%w16d", (int_least16_t) 12345); + CHECK_PRINTF ("-12345", "%w16d", (int_least16_t) -12345); + CHECK_PRINTF ("12345", "%w16i", (int_least16_t) 12345); + CHECK_PRINTF ("-12345", "%w16i", (int_least16_t) -12345); + CHECK_PRINTF ("11000000111001", "%w16b", (uint_least16_t) 12345); + CHECK_PRINTF ("11000000111001", "%w16B", (uint_least16_t) 12345); + CHECK_PRINTF ("30071", "%w16o", (uint_least16_t) 12345); + CHECK_PRINTF ("12345", "%w16u", (uint_least16_t) 12345); + CHECK_PRINTF ("303a", "%w16x", (uint_least16_t) 12346); + CHECK_PRINTF ("303A", "%w16X", (uint_least16_t) 12346); + CHECK_PRINTF (" 12345", "%7w16d", (int_least16_t) 12345); + CHECK_PRINTF (" 12345", "%*w16d", 7, (int_least16_t) 12345); + CHECK_PRINTF ("0x3039", "%#w16x", (uint_least16_t) 12345); + CHECK_PRINTF ("0012345", "%.7w16d", (int_least16_t) 12345); + CHECK_PRINTF ("0012345", "%.*w16d", 7, (int_least16_t) 12345); + CHECK_PRINTF (" 0012345", "%10.7w16d", (int_least16_t) 12345); + CHECK_PRINTF (" 0012345", "%*.7w16d", 10, (int_least16_t) 12345); + CHECK_PRINTF (" 0012345", "%10.*w16d", 7, (int_least16_t) 12345); + CHECK_PRINTF (" 0012345", "%*.*w16d", 10, 7, (int_least16_t) 12345); + CHECK_PRINTF ("0012345 ", "%-10.7w16d", (int_least16_t) 12345); + CHECK_PRINTF ("0012345 ", "%-*.7w16d", 10, (int_least16_t) 12345); + CHECK_PRINTF ("0012345 ", "%-10.*w16d", 7, (int_least16_t) 12345); + CHECK_PRINTF ("0012345 ", "%-*.*w16d", 10, 7, (int_least16_t) 12345); + { + int_least16_t ln = -1; + CHECK_PRINTF ("12345", "%d%w16n", 12345, &ln); + TEST_COMPARE (ln, 5); + } + /* Test truncation of value in promoted type not representable in + narrower type. */ + CHECK_PRINTF ("4464", "%w16d", 70000); + CHECK_PRINTF ("-4464", "%w16d", -70000); + CHECK_PRINTF ("-7616", "%w16d", 123456); + CHECK_PRINTF ("7616", "%w16d", -123456); + CHECK_PRINTF ("57920", "%w16u", 123456); + /* Test positional argument handling. */ + CHECK_PRINTF ("test 10 test2 20", "%4$s %3$w16d %2$s %1$w16d", + 65556, "test2", 65546, "test"); +} + +static void +test_wf16 (void) +{ + CHAR buf[1024]; + _Static_assert (sizeof (int_fast16_t) == sizeof (long int), + "test assumes size of int_fast16_t"); + CHECK_PRINTF ("1234567", "%wf16d", (int_fast16_t) 1234567); + CHECK_PRINTF ("-1234567", "%wf16d", (int_fast16_t) -1234567); + CHECK_PRINTF ("1234567", "%wf16i", (int_fast16_t) 1234567); + CHECK_PRINTF ("-1234567", "%wf16i", (int_fast16_t) -1234567); + CHECK_PRINTF ("100101101011010000111", "%wf16b", (uint_fast16_t) 1234567); + CHECK_PRINTF ("100101101011010000111", "%wf16B", (uint_fast16_t) 1234567); + CHECK_PRINTF ("4553207", "%wf16o", (uint_fast16_t) 1234567); + CHECK_PRINTF ("1234567", "%wf16u", (uint_fast16_t) 1234567); + CHECK_PRINTF ("12d687", "%wf16x", (uint_fast16_t) 1234567); + CHECK_PRINTF ("12D687", "%wf16X", (uint_fast16_t) 1234567); + CHECK_PRINTF (" 1234567", "%9wf16d", (int_fast16_t) 1234567); + CHECK_PRINTF (" 1234567", "%*wf16d", 9, (int_fast16_t) 1234567); + CHECK_PRINTF ("0x12d687", "%#wf16x", (uint_fast16_t) 1234567); + CHECK_PRINTF ("001234567", "%.9wf16d", (int_fast16_t) 1234567); + CHECK_PRINTF ("001234567", "%.*wf16d", 9, (int_fast16_t) 1234567); + CHECK_PRINTF (" 001234567", "%12.9wf16d", (int_fast16_t) 1234567); + CHECK_PRINTF (" 001234567", "%*.9wf16d", 12, (int_fast16_t) 1234567); + CHECK_PRINTF (" 001234567", "%12.*wf16d", 9, (int_fast16_t) 1234567); + CHECK_PRINTF (" 001234567", "%*.*wf16d", 12, 9, (int_fast16_t) 1234567); + CHECK_PRINTF ("001234567 ", "%-12.9wf16d", (int_fast16_t) 1234567); + CHECK_PRINTF ("001234567 ", "%-*.9wf16d", 12, (int_fast16_t) 1234567); + CHECK_PRINTF ("001234567 ", "%-12.*wf16d", 9, (int_fast16_t) 1234567); + CHECK_PRINTF ("001234567 ", "%-*.*wf16d", 12, 9, (int_fast16_t) 1234567); + { + int_fast16_t n = -1; + CHECK_PRINTF ("12345", "%d%wf16n", 12345, &n); + TEST_COMPARE (n, 5); + } + /* Test positional argument handling. */ + CHECK_PRINTF ("test 123456 test2 234567", "%4$s %3$wf16d %2$s %1$wf16d", + (int_fast16_t) 234567, "test2", (int_fast16_t) 123456, "test"); +#if INT_FAST16_MAX > 0x7fffffff + CHECK_PRINTF ("12345678901", "%wf16d", (int_fast16_t) 12345678901LL); + CHECK_PRINTF ("-12345678901", "%wf16d", (int_fast16_t) -12345678901LL); + CHECK_PRINTF ("12345678901", "%wf16i", (int_fast16_t) 12345678901LL); + CHECK_PRINTF ("-12345678901", "%wf16i", (int_fast16_t) -12345678901LL); + CHECK_PRINTF ("1011011111110111000001110000110101", "%wf16b", + (uint_fast16_t) 12345678901LL); + CHECK_PRINTF ("1011011111110111000001110000110101", "%wf16B", + (uint_fast16_t) 12345678901LL); + CHECK_PRINTF ("133767016065", "%wf16o", (uint_fast16_t) 12345678901LL); + CHECK_PRINTF ("12345678901", "%wf16u", (uint_fast16_t) 12345678901LL); + CHECK_PRINTF ("2dfdc1c35", "%wf16x", (uint_fast16_t) 12345678901LL); + CHECK_PRINTF ("2DFDC1C35", "%wf16X", (uint_fast16_t) 12345678901LL); + CHECK_PRINTF (" 12345678901", "%13wf16d", (int_fast16_t) 12345678901LL); + CHECK_PRINTF (" 12345678901", "%*wf16d", 13, (int_fast16_t) 12345678901LL); + CHECK_PRINTF ("0x2dfdc1c35", "%#wf16x", (uint_fast16_t) 12345678901LL); + CHECK_PRINTF ("0012345678901", "%.13wf16d", (int_fast16_t) 12345678901LL); + CHECK_PRINTF ("0012345678901", "%.*wf16d", 13, (int_fast16_t) 12345678901LL); + CHECK_PRINTF (" 0012345678901", "%16.13wf16d", + (int_fast16_t) 12345678901LL); + CHECK_PRINTF (" 0012345678901", "%*.13wf16d", 16, + (int_fast16_t) 12345678901LL); + CHECK_PRINTF (" 0012345678901", "%16.*wf16d", 13, + (int_fast16_t) 12345678901LL); + CHECK_PRINTF (" 0012345678901", "%*.*wf16d", 16, 13, + (int_fast16_t) 12345678901LL); + CHECK_PRINTF ("0012345678901 ", "%-16.13wf16d", + (int_fast16_t) 12345678901LL); + CHECK_PRINTF ("0012345678901 ", "%-*.13wf16d", 16, + (int_fast16_t) 12345678901LL); + CHECK_PRINTF ("0012345678901 ", "%-16.*wf16d", 13, + (int_fast16_t) 12345678901LL); + CHECK_PRINTF ("0012345678901 ", "%-*.*wf16d", 16, 13, + (int_fast16_t) 12345678901LL); + /* Test positional argument handling. */ + CHECK_PRINTF ("test 123456789012 test2 234567890123", + "%4$s %3$wf16d %2$s %1$wf16d", + (int_fast16_t) 234567890123ULL, "test2", + (int_fast16_t) 123456789012ULL, "test"); +#endif +} + +static void +test_w32 (void) +{ + CHAR buf[1024]; + CHECK_PRINTF ("1234567", "%w32d", (int32_t) 1234567); + CHECK_PRINTF ("-1234567", "%w32d", (int32_t) -1234567); + CHECK_PRINTF ("1234567", "%w32i", (int32_t) 1234567); + CHECK_PRINTF ("-1234567", "%w32i", (int32_t) -1234567); + CHECK_PRINTF ("100101101011010000111", "%w32b", (uint32_t) 1234567); + CHECK_PRINTF ("100101101011010000111", "%w32B", (uint32_t) 1234567); + CHECK_PRINTF ("4553207", "%w32o", (uint32_t) 1234567); + CHECK_PRINTF ("1234567", "%w32u", (uint32_t) 1234567); + CHECK_PRINTF ("12d687", "%w32x", (uint32_t) 1234567); + CHECK_PRINTF ("12D687", "%w32X", (uint32_t) 1234567); + CHECK_PRINTF (" 1234567", "%9w32d", (int32_t) 1234567); + CHECK_PRINTF (" 1234567", "%*w32d", 9, (int32_t) 1234567); + CHECK_PRINTF ("0x12d687", "%#w32x", (uint32_t) 1234567); + CHECK_PRINTF ("001234567", "%.9w32d", (int32_t) 1234567); + CHECK_PRINTF ("001234567", "%.*w32d", 9, (int32_t) 1234567); + CHECK_PRINTF (" 001234567", "%12.9w32d", (int32_t) 1234567); + CHECK_PRINTF (" 001234567", "%*.9w32d", 12, (int32_t) 1234567); + CHECK_PRINTF (" 001234567", "%12.*w32d", 9, (int32_t) 1234567); + CHECK_PRINTF (" 001234567", "%*.*w32d", 12, 9, (int32_t) 1234567); + CHECK_PRINTF ("001234567 ", "%-12.9w32d", (int32_t) 1234567); + CHECK_PRINTF ("001234567 ", "%-*.9w32d", 12, (int32_t) 1234567); + CHECK_PRINTF ("001234567 ", "%-12.*w32d", 9, (int32_t) 1234567); + CHECK_PRINTF ("001234567 ", "%-*.*w32d", 12, 9, (int32_t) 1234567); + { + int32_t n = -1; + CHECK_PRINTF ("12345", "%d%w32n", 12345, &n); + TEST_COMPARE (n, 5); + } + CHECK_PRINTF ("1234567", "%w32d", (int_least32_t) 1234567); + CHECK_PRINTF ("-1234567", "%w32d", (int_least32_t) -1234567); + CHECK_PRINTF ("1234567", "%w32i", (int_least32_t) 1234567); + CHECK_PRINTF ("-1234567", "%w32i", (int_least32_t) -1234567); + CHECK_PRINTF ("100101101011010000111", "%w32b", (uint_least32_t) 1234567); + CHECK_PRINTF ("100101101011010000111", "%w32B", (uint_least32_t) 1234567); + CHECK_PRINTF ("4553207", "%w32o", (uint_least32_t) 1234567); + CHECK_PRINTF ("1234567", "%w32u", (uint_least32_t) 1234567); + CHECK_PRINTF ("12d687", "%w32x", (uint_least32_t) 1234567); + CHECK_PRINTF ("12D687", "%w32X", (uint_least32_t) 1234567); + CHECK_PRINTF (" 1234567", "%9w32d", (int_least32_t) 1234567); + CHECK_PRINTF (" 1234567", "%*w32d", 9, (int_least32_t) 1234567); + CHECK_PRINTF ("0x12d687", "%#w32x", (uint_least32_t) 1234567); + CHECK_PRINTF ("001234567", "%.9w32d", (int_least32_t) 1234567); + CHECK_PRINTF ("001234567", "%.*w32d", 9, (int_least32_t) 1234567); + CHECK_PRINTF (" 001234567", "%12.9w32d", (int_least32_t) 1234567); + CHECK_PRINTF (" 001234567", "%*.9w32d", 12, (int_least32_t) 1234567); + CHECK_PRINTF (" 001234567", "%12.*w32d", 9, (int_least32_t) 1234567); + CHECK_PRINTF (" 001234567", "%*.*w32d", 12, 9, (int_least32_t) 1234567); + CHECK_PRINTF ("001234567 ", "%-12.9w32d", (int_least32_t) 1234567); + CHECK_PRINTF ("001234567 ", "%-*.9w32d", 12, (int_least32_t) 1234567); + CHECK_PRINTF ("001234567 ", "%-12.*w32d", 9, (int_least32_t) 1234567); + CHECK_PRINTF ("001234567 ", "%-*.*w32d", 12, 9, (int_least32_t) 1234567); + { + int_least32_t ln = -1; + CHECK_PRINTF ("12345", "%d%w32n", 12345, &ln); + TEST_COMPARE (ln, 5); + } + /* Test positional argument handling. */ + CHECK_PRINTF ("test 123456 test2 234567", "%4$s %3$w32d %2$s %1$w32d", + INT32_C (234567), "test2", INT32_C (123456), "test"); +} + +static void +test_wf32 (void) +{ + CHAR buf[1024]; + _Static_assert (sizeof (int_fast32_t) == sizeof (long int), + "test assumes size of int_fast32_t"); + CHECK_PRINTF ("1234567", "%wf32d", (int_fast32_t) 1234567); + CHECK_PRINTF ("-1234567", "%wf32d", (int_fast32_t) -1234567); + CHECK_PRINTF ("1234567", "%wf32i", (int_fast32_t) 1234567); + CHECK_PRINTF ("-1234567", "%wf32i", (int_fast32_t) -1234567); + CHECK_PRINTF ("100101101011010000111", "%wf32b", (uint_fast32_t) 1234567); + CHECK_PRINTF ("100101101011010000111", "%wf32B", (uint_fast32_t) 1234567); + CHECK_PRINTF ("4553207", "%wf32o", (uint_fast32_t) 1234567); + CHECK_PRINTF ("1234567", "%wf32u", (uint_fast32_t) 1234567); + CHECK_PRINTF ("12d687", "%wf32x", (uint_fast32_t) 1234567); + CHECK_PRINTF ("12D687", "%wf32X", (uint_fast32_t) 1234567); + CHECK_PRINTF (" 1234567", "%9wf32d", (int_fast32_t) 1234567); + CHECK_PRINTF (" 1234567", "%*wf32d", 9, (int_fast32_t) 1234567); + CHECK_PRINTF ("0x12d687", "%#wf32x", (uint_fast32_t) 1234567); + CHECK_PRINTF ("001234567", "%.9wf32d", (int_fast32_t) 1234567); + CHECK_PRINTF ("001234567", "%.*wf32d", 9, (int_fast32_t) 1234567); + CHECK_PRINTF (" 001234567", "%12.9wf32d", (int_fast32_t) 1234567); + CHECK_PRINTF (" 001234567", "%*.9wf32d", 12, (int_fast32_t) 1234567); + CHECK_PRINTF (" 001234567", "%12.*wf32d", 9, (int_fast32_t) 1234567); + CHECK_PRINTF (" 001234567", "%*.*wf32d", 12, 9, (int_fast32_t) 1234567); + CHECK_PRINTF ("001234567 ", "%-12.9wf32d", (int_fast32_t) 1234567); + CHECK_PRINTF ("001234567 ", "%-*.9wf32d", 12, (int_fast32_t) 1234567); + CHECK_PRINTF ("001234567 ", "%-12.*wf32d", 9, (int_fast32_t) 1234567); + CHECK_PRINTF ("001234567 ", "%-*.*wf32d", 12, 9, (int_fast32_t) 1234567); + { + int_fast32_t n = -1; + CHECK_PRINTF ("12345", "%d%wf32n", 12345, &n); + TEST_COMPARE (n, 5); + } + /* Test positional argument handling. */ + CHECK_PRINTF ("test 123456 test2 234567", "%4$s %3$wf32d %2$s %1$wf32d", + (int_fast32_t) 234567, "test2", (int_fast32_t) 123456, "test"); +#if INT_FAST32_MAX > 0x7fffffff + CHECK_PRINTF ("12345678901", "%wf32d", (int_fast32_t) 12345678901LL); + CHECK_PRINTF ("-12345678901", "%wf32d", (int_fast32_t) -12345678901LL); + CHECK_PRINTF ("12345678901", "%wf32i", (int_fast32_t) 12345678901LL); + CHECK_PRINTF ("-12345678901", "%wf32i", (int_fast32_t) -12345678901LL); + CHECK_PRINTF ("1011011111110111000001110000110101", "%wf32b", + (uint_fast32_t) 12345678901LL); + CHECK_PRINTF ("1011011111110111000001110000110101", "%wf32B", + (uint_fast32_t) 12345678901LL); + CHECK_PRINTF ("133767016065", "%wf32o", (uint_fast32_t) 12345678901LL); + CHECK_PRINTF ("12345678901", "%wf32u", (uint_fast32_t) 12345678901LL); + CHECK_PRINTF ("2dfdc1c35", "%wf32x", (uint_fast32_t) 12345678901LL); + CHECK_PRINTF ("2DFDC1C35", "%wf32X", (uint_fast32_t) 12345678901LL); + CHECK_PRINTF (" 12345678901", "%13wf32d", (int_fast32_t) 12345678901LL); + CHECK_PRINTF (" 12345678901", "%*wf32d", 13, (int_fast32_t) 12345678901LL); + CHECK_PRINTF ("0x2dfdc1c35", "%#wf32x", (uint_fast32_t) 12345678901LL); + CHECK_PRINTF ("0012345678901", "%.13wf32d", (int_fast32_t) 12345678901LL); + CHECK_PRINTF ("0012345678901", "%.*wf32d", 13, (int_fast32_t) 12345678901LL); + CHECK_PRINTF (" 0012345678901", "%16.13wf32d", + (int_fast32_t) 12345678901LL); + CHECK_PRINTF (" 0012345678901", "%*.13wf32d", 16, + (int_fast32_t) 12345678901LL); + CHECK_PRINTF (" 0012345678901", "%16.*wf32d", 13, + (int_fast32_t) 12345678901LL); + CHECK_PRINTF (" 0012345678901", "%*.*wf32d", 16, 13, + (int_fast32_t) 12345678901LL); + CHECK_PRINTF ("0012345678901 ", "%-16.13wf32d", + (int_fast32_t) 12345678901LL); + CHECK_PRINTF ("0012345678901 ", "%-*.13wf32d", 16, + (int_fast32_t) 12345678901LL); + CHECK_PRINTF ("0012345678901 ", "%-16.*wf32d", 13, + (int_fast32_t) 12345678901LL); + CHECK_PRINTF ("0012345678901 ", "%-*.*wf32d", 16, 13, + (int_fast32_t) 12345678901LL); + /* Test positional argument handling. */ + CHECK_PRINTF ("test 123456789012 test2 234567890123", + "%4$s %3$wf32d %2$s %1$wf32d", + (int_fast32_t) 234567890123ULL, "test2", + (int_fast32_t) 123456789012ULL, "test"); +#endif +} + +static void +test_w64 (void) +{ + CHAR buf[1024]; + CHECK_PRINTF ("12345678901", "%w64d", (int64_t) 12345678901LL); + CHECK_PRINTF ("-12345678901", "%w64d", (int64_t) -12345678901LL); + CHECK_PRINTF ("12345678901", "%w64i", (int64_t) 12345678901LL); + CHECK_PRINTF ("-12345678901", "%w64i", (int64_t) -12345678901LL); + CHECK_PRINTF ("1011011111110111000001110000110101", "%w64b", + (uint64_t) 12345678901LL); + CHECK_PRINTF ("1011011111110111000001110000110101", "%w64B", + (uint64_t) 12345678901LL); + CHECK_PRINTF ("133767016065", "%w64o", (uint64_t) 12345678901LL); + CHECK_PRINTF ("12345678901", "%w64u", (uint64_t) 12345678901LL); + CHECK_PRINTF ("2dfdc1c35", "%w64x", (uint64_t) 12345678901LL); + CHECK_PRINTF ("2DFDC1C35", "%w64X", (uint64_t) 12345678901LL); + CHECK_PRINTF (" 12345678901", "%13w64d", (int64_t) 12345678901LL); + CHECK_PRINTF (" 12345678901", "%*w64d", 13, (int64_t) 12345678901LL); + CHECK_PRINTF ("0x2dfdc1c35", "%#w64x", (uint64_t) 12345678901LL); + CHECK_PRINTF ("0012345678901", "%.13w64d", (int64_t) 12345678901LL); + CHECK_PRINTF ("0012345678901", "%.*w64d", 13, (int64_t) 12345678901LL); + CHECK_PRINTF (" 0012345678901", "%16.13w64d", (int64_t) 12345678901LL); + CHECK_PRINTF (" 0012345678901", "%*.13w64d", 16, (int64_t) 12345678901LL); + CHECK_PRINTF (" 0012345678901", "%16.*w64d", 13, (int64_t) 12345678901LL); + CHECK_PRINTF (" 0012345678901", "%*.*w64d", 16, 13, + (int64_t) 12345678901LL); + CHECK_PRINTF ("0012345678901 ", "%-16.13w64d", (int64_t) 12345678901LL); + CHECK_PRINTF ("0012345678901 ", "%-*.13w64d", 16, (int64_t) 12345678901LL); + CHECK_PRINTF ("0012345678901 ", "%-16.*w64d", 13, (int64_t) 12345678901LL); + CHECK_PRINTF ("0012345678901 ", "%-*.*w64d", 16, 13, + (int64_t) 12345678901LL); + { + int64_t n = -1; + CHECK_PRINTF ("12345", "%d%w64n", 12345, &n); + TEST_COMPARE (n, 5); + } + CHECK_PRINTF ("12345678901", "%w64d", (int_least64_t) 12345678901LL); + CHECK_PRINTF ("-12345678901", "%w64d", (int_least64_t) -12345678901LL); + CHECK_PRINTF ("12345678901", "%w64i", (int_least64_t) 12345678901LL); + CHECK_PRINTF ("-12345678901", "%w64i", (int_least64_t) -12345678901LL); + CHECK_PRINTF ("1011011111110111000001110000110101", "%w64b", + (uint_least64_t) 12345678901LL); + CHECK_PRINTF ("1011011111110111000001110000110101", "%w64B", + (uint_least64_t) 12345678901LL); + CHECK_PRINTF ("133767016065", "%w64o", (uint_least64_t) 12345678901LL); + CHECK_PRINTF ("12345678901", "%w64u", (uint_least64_t) 12345678901LL); + CHECK_PRINTF ("2dfdc1c35", "%w64x", (uint_least64_t) 12345678901LL); + CHECK_PRINTF ("2DFDC1C35", "%w64X", (uint_least64_t) 12345678901LL); + CHECK_PRINTF (" 12345678901", "%13w64d", (int_least64_t) 12345678901LL); + CHECK_PRINTF (" 12345678901", "%*w64d", 13, (int_least64_t) 12345678901LL); + CHECK_PRINTF ("0x2dfdc1c35", "%#w64x", (uint_least64_t) 12345678901LL); + CHECK_PRINTF ("0012345678901", "%.13w64d", (int_least64_t) 12345678901LL); + CHECK_PRINTF ("0012345678901", "%.*w64d", 13, (int_least64_t) 12345678901LL); + CHECK_PRINTF (" 0012345678901", "%16.13w64d", + (int_least64_t) 12345678901LL); + CHECK_PRINTF (" 0012345678901", "%*.13w64d", 16, + (int_least64_t) 12345678901LL); + CHECK_PRINTF (" 0012345678901", "%16.*w64d", 13, + (int_least64_t) 12345678901LL); + CHECK_PRINTF (" 0012345678901", "%*.*w64d", 16, 13, + (int_least64_t) 12345678901LL); + CHECK_PRINTF ("0012345678901 ", "%-16.13w64d", + (int_least64_t) 12345678901LL); + CHECK_PRINTF ("0012345678901 ", "%-*.13w64d", 16, + (int_least64_t) 12345678901LL); + CHECK_PRINTF ("0012345678901 ", "%-16.*w64d", 13, + (int_least64_t) 12345678901LL); + CHECK_PRINTF ("0012345678901 ", "%-*.*w64d", 16, 13, + (int_least64_t) 12345678901LL); + { + int_least64_t ln = -1; + CHECK_PRINTF ("12345", "%d%w64n", 12345, &ln); + TEST_COMPARE (ln, 5); + } + /* Test positional argument handling. */ + CHECK_PRINTF ("test 123456789012 test2 234567890123", + "%4$s %3$w64d %2$s %1$w64d", + INT64_C (234567890123), "test2", + INT64_C (123456789012), "test"); +} + +static void +test_wf64 (void) +{ + CHAR buf[1024]; + _Static_assert (sizeof (int_fast64_t) == sizeof (long long int), + "test assumes size of int_fast64_t"); + CHECK_PRINTF ("12345678901", "%wf64d", (int_fast64_t) 12345678901LL); + CHECK_PRINTF ("-12345678901", "%wf64d", (int_fast64_t) -12345678901LL); + CHECK_PRINTF ("12345678901", "%wf64i", (int_fast64_t) 12345678901LL); + CHECK_PRINTF ("-12345678901", "%wf64i", (int_fast64_t) -12345678901LL); + CHECK_PRINTF ("1011011111110111000001110000110101", "%wf64b", + (uint_fast64_t) 12345678901LL); + CHECK_PRINTF ("1011011111110111000001110000110101", "%wf64B", + (uint_fast64_t) 12345678901LL); + CHECK_PRINTF ("133767016065", "%wf64o", (uint_fast64_t) 12345678901LL); + CHECK_PRINTF ("12345678901", "%wf64u", (uint_fast64_t) 12345678901LL); + CHECK_PRINTF ("2dfdc1c35", "%wf64x", (uint_fast64_t) 12345678901LL); + CHECK_PRINTF ("2DFDC1C35", "%wf64X", (uint_fast64_t) 12345678901LL); + CHECK_PRINTF (" 12345678901", "%13wf64d", (int_fast64_t) 12345678901LL); + CHECK_PRINTF (" 12345678901", "%*wf64d", 13, (int_fast64_t) 12345678901LL); + CHECK_PRINTF ("0x2dfdc1c35", "%#wf64x", (uint_fast64_t) 12345678901LL); + CHECK_PRINTF ("0012345678901", "%.13wf64d", (int_fast64_t) 12345678901LL); + CHECK_PRINTF ("0012345678901", "%.*wf64d", 13, (int_fast64_t) 12345678901LL); + CHECK_PRINTF (" 0012345678901", "%16.13wf64d", + (int_fast64_t) 12345678901LL); + CHECK_PRINTF (" 0012345678901", "%*.13wf64d", 16, + (int_fast64_t) 12345678901LL); + CHECK_PRINTF (" 0012345678901", "%16.*wf64d", 13, + (int_fast64_t) 12345678901LL); + CHECK_PRINTF (" 0012345678901", "%*.*wf64d", 16, 13, + (int_fast64_t) 12345678901LL); + CHECK_PRINTF ("0012345678901 ", "%-16.13wf64d", + (int_fast64_t) 12345678901LL); + CHECK_PRINTF ("0012345678901 ", "%-*.13wf64d", 16, + (int_fast64_t) 12345678901LL); + CHECK_PRINTF ("0012345678901 ", "%-16.*wf64d", 13, + (int_fast64_t) 12345678901LL); + CHECK_PRINTF ("0012345678901 ", "%-*.*wf64d", 16, 13, + (int_fast64_t) 12345678901LL); + { + int_fast64_t n = -1; + CHECK_PRINTF ("12345", "%d%wf64n", 12345, &n); + TEST_COMPARE (n, 5); + } + /* Test positional argument handling. */ + CHECK_PRINTF ("test 123456789012 test2 234567890123", + "%4$s %3$wf64d %2$s %1$wf64d", + (int_fast64_t) 234567890123ULL, "test2", + (int_fast64_t) 123456789012ULL, "test"); +} + +static int +do_test (void) +{ + test_w8 (); + test_wf8 (); + test_w16 (); + test_wf16 (); + test_w32 (); + test_wf32 (); + test_w64 (); + test_wf64 (); + /* Bad N in %wN and %wfN are required to produce an error return + from printf functions (and can also be seen to be invalid at + compile time). */ + DIAG_PUSH_NEEDS_COMMENT; + DIAG_IGNORE_NEEDS_COMMENT (13, "-Wformat"); + DIAG_IGNORE_NEEDS_COMMENT (13, "-Wformat-extra-args"); + CHAR buf[1024]; + CHECK_PRINTF_ERR ("%w1d", 123); + CHECK_PRINTF_ERR ("%w123d", 123); + CHECK_PRINTF_ERR ("%w99999999999999999999d", 123); + CHECK_PRINTF_ERR ("%wf1d", 123); + CHECK_PRINTF_ERR ("%wf123d", 123); + CHECK_PRINTF_ERR ("%wf99999999999999999999d", 123); + CHECK_PRINTF_ERR ("%1$w1d", 123); + CHECK_PRINTF_ERR ("%1$w123d", 123); + CHECK_PRINTF_ERR ("%1$w99999999999999999999d", 123); + CHECK_PRINTF_ERR ("%1$wf1d", 123); + CHECK_PRINTF_ERR ("%1$wf123d", 123); + CHECK_PRINTF_ERR ("%1$wf99999999999999999999d", 123); + DIAG_POP_NEEDS_COMMENT; + return 0; +} + +DIAG_POP_NEEDS_COMMENT; + +#include <support/test-driver.c> diff --git a/stdio-common/tst-printf-intn.c b/stdio-common/tst-printf-intn.c new file mode 100644 index 0000000000..975aebecf7 --- /dev/null +++ b/stdio-common/tst-printf-intn.c @@ -0,0 +1,26 @@ +/* Test printf formats for intN_t, int_leastN_t and int_fastN_t types. + Narrow string version. + Copyright (C) 2023 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <https://www.gnu.org/licenses/>. */ + +#define SNPRINTF snprintf +#define TEST_COMPARE_STRING_MACRO TEST_COMPARE_STRING +#define STRLEN strlen +#define CHAR char +#define L_(C) C + +#include <tst-printf-intn-main.c> diff --git a/stdio-common/vfprintf-internal.c b/stdio-common/vfprintf-internal.c index c76c06e49b..f30a9e9f3a 100644 --- a/stdio-common/vfprintf-internal.c +++ b/stdio-common/vfprintf-internal.c @@ -315,7 +315,7 @@ static const uint8_t jump_table[] = /* 'h' */ 10, /* 'i' */ 15, /* 'j' */ 28, 0, /* 'l' */ 11, /* 'm' */ 24, /* 'n' */ 23, /* 'o' */ 17, /* 'p' */ 22, /* 'q' */ 12, 0, /* 's' */ 21, - /* 't' */ 27, /* 'u' */ 16, 0, 0, + /* 't' */ 27, /* 'u' */ 16, 0, /* 'w' */ 31, /* 'x' */ 18, 0, /* 'z' */ 13 }; @@ -356,7 +356,7 @@ static const uint8_t jump_table[] = #define STEP0_3_TABLE \ /* Step 0: at the beginning. */ \ - static JUMP_TABLE_TYPE step0_jumps[31] = \ + static JUMP_TABLE_TYPE step0_jumps[32] = \ { \ REF (form_unknown), \ REF (flag_space), /* for ' ' */ \ @@ -389,9 +389,10 @@ static const uint8_t jump_table[] = REF (mod_intmax_t), /* for 'j' */ \ REF (flag_i18n), /* for 'I' */ \ REF (form_binary), /* for 'B', 'b' */ \ + REF (mod_bitwidth), /* for 'w' */ \ }; \ /* Step 1: after processing width. */ \ - static JUMP_TABLE_TYPE step1_jumps[31] = \ + static JUMP_TABLE_TYPE step1_jumps[32] = \ { \ REF (form_unknown), \ REF (form_unknown), /* for ' ' */ \ @@ -424,9 +425,10 @@ static const uint8_t jump_table[] = REF (mod_intmax_t), /* for 'j' */ \ REF (form_unknown), /* for 'I' */ \ REF (form_binary), /* for 'B', 'b' */ \ + REF (mod_bitwidth), /* for 'w' */ \ }; \ /* Step 2: after processing precision. */ \ - static JUMP_TABLE_TYPE step2_jumps[31] = \ + static JUMP_TABLE_TYPE step2_jumps[32] = \ { \ REF (form_unknown), \ REF (form_unknown), /* for ' ' */ \ @@ -459,9 +461,10 @@ static const uint8_t jump_table[] = REF (mod_intmax_t), /* for 'j' */ \ REF (form_unknown), /* for 'I' */ \ REF (form_binary), /* for 'B', 'b' */ \ + REF (mod_bitwidth), /* for 'w' */ \ }; \ /* Step 3a: after processing first 'h' modifier. */ \ - static JUMP_TABLE_TYPE step3a_jumps[31] = \ + static JUMP_TABLE_TYPE step3a_jumps[32] = \ { \ REF (form_unknown), \ REF (form_unknown), /* for ' ' */ \ @@ -494,9 +497,10 @@ static const uint8_t jump_table[] = REF (form_unknown), /* for 'j' */ \ REF (form_unknown), /* for 'I' */ \ REF (form_binary), /* for 'B', 'b' */ \ + REF (form_unknown), /* for 'w' */ \ }; \ /* Step 3b: after processing first 'l' modifier. */ \ - static JUMP_TABLE_TYPE step3b_jumps[31] = \ + static JUMP_TABLE_TYPE step3b_jumps[32] = \ { \ REF (form_unknown), \ REF (form_unknown), /* for ' ' */ \ @@ -529,11 +533,12 @@ static const uint8_t jump_table[] = REF (form_unknown), /* for 'j' */ \ REF (form_unknown), /* for 'I' */ \ REF (form_binary), /* for 'B', 'b' */ \ + REF (form_unknown), /* for 'w' */ \ } #define STEP4_TABLE \ /* Step 4: processing format specifier. */ \ - static JUMP_TABLE_TYPE step4_jumps[31] = \ + static JUMP_TABLE_TYPE step4_jumps[32] = \ { \ REF (form_unknown), \ REF (form_unknown), /* for ' ' */ \ @@ -566,6 +571,7 @@ static const uint8_t jump_table[] = REF (form_unknown), /* for 'j' */ \ REF (form_unknown), /* for 'I' */ \ REF (form_binary), /* for 'B', 'b' */ \ + REF (form_unknown), /* for 'w' */ \ } /* Handle positional format specifiers. */ @@ -886,6 +892,56 @@ Xprintf_buffer (struct Xprintf_buffer *buf, const CHAR_T *format, is_long = sizeof (intmax_t) > sizeof (unsigned int); JUMP (*++f, step4_jumps); + /* Process 'wN' or 'wfN' modifier. */ + LABEL (mod_bitwidth): + ++f; + bool is_fast = false; + if (*f == L_('f')) + { + ++f; + is_fast = true; + } + int bitwidth = 0; + if (ISDIGIT (*f)) + bitwidth = read_int (&f); + if (is_fast) + switch (bitwidth) + { + case 8: + bitwidth = INT_FAST8_WIDTH; + break; + case 16: + bitwidth = INT_FAST16_WIDTH; + break; + case 32: + bitwidth = INT_FAST32_WIDTH; + break; + case 64: + bitwidth = INT_FAST64_WIDTH; + break; + } + switch (bitwidth) + { + case 8: + is_char = 1; + break; + case 16: + is_short = 1; + break; + case 32: + break; + case 64: + is_long_double = 1; + is_long = 1; + break; + default: + /* ISO C requires this error to be detected. */ + __set_errno (EINVAL); + Xprintf_buffer_mark_failed (buf); + goto all_done; + } + JUMP (*f, step4_jumps); + /* Process current format. */ while (1) { @@ -1053,11 +1109,19 @@ printf_positional (struct Xprintf_buffer * buf, const CHAR_T *format, } /* Parse the format specifier. */ + bool failed; #ifdef COMPILE_WPRINTF - nargs += __parse_one_specwc (f, nargs, &specs[nspecs], &max_ref_arg); + nargs += __parse_one_specwc (f, nargs, &specs[nspecs], &max_ref_arg, + &failed); #else - nargs += __parse_one_specmb (f, nargs, &specs[nspecs], &max_ref_arg); + nargs += __parse_one_specmb (f, nargs, &specs[nspecs], &max_ref_arg, + &failed); #endif + if (failed) + { + Xprintf_buffer_mark_failed (buf); + goto all_done; + } } /* Determine the number of arguments the format string consumes. */ diff --git a/wcsmbs/Makefile b/wcsmbs/Makefile index d8512c8801..22192985e1 100644 --- a/wcsmbs/Makefile +++ b/wcsmbs/Makefile @@ -170,6 +170,7 @@ tests := \ tst-wcstol-binary-gnu2x \ tst-wcstol-locale \ tst-wprintf-binary \ + tst-wprintf-intn \ tst-wscanf-binary-c11 \ tst-wscanf-binary-c2x \ tst-wscanf-binary-gnu11 \ diff --git a/wcsmbs/tst-wprintf-intn.c b/wcsmbs/tst-wprintf-intn.c new file mode 100644 index 0000000000..0c0eb80c2c --- /dev/null +++ b/wcsmbs/tst-wprintf-intn.c @@ -0,0 +1,26 @@ +/* Test printf formats for intN_t, int_leastN_t and int_fastN_t types. + Wide string version. + Copyright (C) 2023 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <https://www.gnu.org/licenses/>. */ + +#define SNPRINTF swprintf +#define TEST_COMPARE_STRING_MACRO TEST_COMPARE_STRING_WIDE +#define STRLEN wcslen +#define CHAR wchar_t +#define L_(C) L ## C + +#include "../stdio-common/tst-printf-intn-main.c" |