diff options
-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
@@ -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" |