From 5826332ae5386719b3f34d3c94b4978910a9c0dc Mon Sep 17 00:00:00 2001 From: Bruno Haible Date: Wed, 3 May 2023 17:09:20 +0200 Subject: vasnprintf, vasnwprintf: Make '0' flag handling more ISO C compliant. * lib/vasnprintf.c (VASNPRINTF): When doing the padding ourselves, ignore the '0' flag if a precision is specified and the conversion is one of d, i, o, u, x, X, b, B. * tests/test-vasnprintf-posix.c (test_function): Update expected results accordingly. * tests/test-vasprintf-posix.c (test_function): Likewise. * tests/test-snprintf-posix.h (test_function): Likewise. * tests/test-sprintf-posix.h (test_function): Likewise. * tests/test-vasnwprintf-posix.c (test_function): Likewise. --- ChangeLog | 13 +++++++++++++ lib/vasnprintf.c | 25 ++++++++++++++++++++----- tests/test-snprintf-posix.h | 18 ++++-------------- tests/test-sprintf-posix.h | 18 ++++-------------- tests/test-vasnprintf-posix.c | 18 ++++-------------- tests/test-vasnwprintf-posix.c | 16 ++++------------ tests/test-vasprintf-posix.c | 18 ++++-------------- 7 files changed, 53 insertions(+), 73 deletions(-) diff --git a/ChangeLog b/ChangeLog index 6323068ffd..ac0153693e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,16 @@ +2023-05-03 Bruno Haible + + vasnprintf, vasnwprintf: Make '0' flag handling more ISO C compliant. + * lib/vasnprintf.c (VASNPRINTF): When doing the padding ourselves, + ignore the '0' flag if a precision is specified and the conversion is + one of d, i, o, u, x, X, b, B. + * tests/test-vasnprintf-posix.c (test_function): Update expected results + accordingly. + * tests/test-vasprintf-posix.c (test_function): Likewise. + * tests/test-snprintf-posix.h (test_function): Likewise. + * tests/test-sprintf-posix.h (test_function): Likewise. + * tests/test-vasnwprintf-posix.c (test_function): Likewise. + 2023-05-02 Paul Eggert mktime: include diff --git a/lib/vasnprintf.c b/lib/vasnprintf.c index efd610ebe4..802790e14e 100644 --- a/lib/vasnprintf.c +++ b/lib/vasnprintf.c @@ -5612,7 +5612,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, #if !USE_SNPRINTF || WIDE_CHAR_VERSION || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION size_t width; #endif -#if !USE_SNPRINTF || (WIDE_CHAR_VERSION && DCHAR_IS_TCHAR) || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || NEED_PRINTF_UNBOUNDED_PRECISION +#if !USE_SNPRINTF || (WIDE_CHAR_VERSION && DCHAR_IS_TCHAR) || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || (WIDE_CHAR_VERSION && MUSL_LIBC) || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION int has_precision; size_t precision; #endif @@ -5669,13 +5669,13 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, width = xsum (xtimes (width, 10), *digitp++ - '0'); while (digitp != dp->width_end); } -#if (WIDE_CHAR_VERSION && MUSL_LIBC) || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION +# if (WIDE_CHAR_VERSION && MUSL_LIBC) || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION has_width = 1; -#endif +# endif } #endif -#if !USE_SNPRINTF || (WIDE_CHAR_VERSION && DCHAR_IS_TCHAR) || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || NEED_PRINTF_UNBOUNDED_PRECISION +#if !USE_SNPRINTF || (WIDE_CHAR_VERSION && DCHAR_IS_TCHAR) || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || (WIDE_CHAR_VERSION && MUSL_LIBC) || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION has_precision = 0; precision = 6; if (dp->precision_start != dp->precision_end) @@ -6794,7 +6794,22 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, for (; pad > 0; pad--) *p++ = ' '; } - else if ((flags & FLAG_ZERO) && pad_ptr != NULL) + else if ((flags & FLAG_ZERO) && pad_ptr != NULL + /* ISO C says: "For d, i, o, u, x, and X + conversions, if a precision is + specified, the 0 flag is ignored. */ + && !(has_precision + && (dp->conversion == 'd' + || dp->conversion == 'i' + || dp->conversion == 'o' + || dp->conversion == 'u' + || dp->conversion == 'x' + || dp->conversion == 'X' + /* Although ISO C does not + require it, treat 'b' and 'B' + like 'x' and 'X'. */ + || dp->conversion == 'b' + || dp->conversion == 'B'))) { /* Pad with zeroes. */ DCHAR_T *q = end; diff --git a/tests/test-snprintf-posix.h b/tests/test-snprintf-posix.h index 5b81910ec3..482335a3ef 100644 --- a/tests/test-snprintf-posix.h +++ b/tests/test-snprintf-posix.h @@ -3187,14 +3187,9 @@ test_function (int (*my_snprintf) (char *, size_t, const char *, ...)) { /* Padding and precision. */ int retval = my_snprintf (result, sizeof (result), "%015.10x %d", 12348, 33, 44, 55); - /* Neither ISO C nor POSIX specify that the '0' flag is ignored when a width - and a precision are both present. But most implementations do so. */ - #ifdef __MINGW32__ - ASSERT (strcmp (result, "00000000000303c 33") == 0 /* mingw 5 */ - || strcmp (result, " 000000303c 33") == 0 /* mingw 10 */); - #else + /* ISO C 99 § 7.19.6.1.(6) says: "For d, i, o, u, x, and X conversions, if a + precision is specified, the 0 flag is ignored." */ ASSERT (strcmp (result, " 000000303c 33") == 0); - #endif ASSERT (retval == strlen (result)); } @@ -3250,14 +3245,9 @@ test_function (int (*my_snprintf) (char *, size_t, const char *, ...)) { /* FLAG_ALT with a positive number and padding and precision. */ int retval = my_snprintf (result, sizeof (result), "%0#15.10x %d", 12348, 33, 44, 55); - /* Neither ISO C nor POSIX specify that the '0' flag is ignored when a width - and a precision are both present. But most implementations do so. */ - #ifdef __MINGW32__ - ASSERT (strcmp (result, "0x000000000303c 33") == 0 /* mingw 5 */ - || strcmp (result, " 0x000000303c 33") == 0 /* mingw 10 */); - #else + /* ISO C 99 § 7.19.6.1.(6) says: "For d, i, o, u, x, and X conversions, if a + precision is specified, the 0 flag is ignored." */ ASSERT (strcmp (result, " 0x000000303c 33") == 0); - #endif ASSERT (retval == strlen (result)); } diff --git a/tests/test-sprintf-posix.h b/tests/test-sprintf-posix.h index a0b5eb3391..c0957a6967 100644 --- a/tests/test-sprintf-posix.h +++ b/tests/test-sprintf-posix.h @@ -3163,14 +3163,9 @@ test_function (int (*my_sprintf) (char *, const char *, ...)) { /* Padding and precision. */ int retval = my_sprintf (result, "%015.10x %d", 12348, 33, 44, 55); - /* Neither ISO C nor POSIX specify that the '0' flag is ignored when a width - and a precision are both present. But most implementations do so. */ - #ifdef __MINGW32__ - ASSERT (strcmp (result, "00000000000303c 33") == 0 /* mingw 5 */ - || strcmp (result, " 000000303c 33") == 0 /* mingw 10 */); - #else + /* ISO C 99 § 7.19.6.1.(6) says: "For d, i, o, u, x, and X conversions, if a + precision is specified, the 0 flag is ignored." */ ASSERT (strcmp (result, " 000000303c 33") == 0); - #endif ASSERT (retval == strlen (result)); } @@ -3226,14 +3221,9 @@ test_function (int (*my_sprintf) (char *, const char *, ...)) { /* FLAG_ALT with a positive number and padding and precision. */ int retval = my_sprintf (result, "%0#15.10x %d", 12348, 33, 44, 55); - /* Neither ISO C nor POSIX specify that the '0' flag is ignored when a width - and a precision are both present. But most implementations do so. */ - #ifdef __MINGW32__ - ASSERT (strcmp (result, "0x000000000303c 33") == 0 /* mingw 5 */ - || strcmp (result, " 0x000000303c 33") == 0 /* mingw 10 */); - #else + /* ISO C 99 § 7.19.6.1.(6) says: "For d, i, o, u, x, and X conversions, if a + precision is specified, the 0 flag is ignored." */ ASSERT (strcmp (result, " 0x000000303c 33") == 0); - #endif ASSERT (retval == strlen (result)); } diff --git a/tests/test-vasnprintf-posix.c b/tests/test-vasnprintf-posix.c index 51b1d26a33..33387c32e7 100644 --- a/tests/test-vasnprintf-posix.c +++ b/tests/test-vasnprintf-posix.c @@ -4145,14 +4145,9 @@ test_function (char * (*my_asnprintf) (char *, size_t *, const char *, ...)) char *result = my_asnprintf (NULL, &length, "%015.10x %d", 12348, 33, 44, 55); ASSERT (result != NULL); - /* Neither ISO C nor POSIX specify that the '0' flag is ignored when a width - and a precision are both present. But most implementations do so. */ - #ifdef __MINGW32__ - ASSERT (strcmp (result, "00000000000303c 33") == 0 /* mingw 5 */ - || strcmp (result, " 000000303c 33") == 0 /* mingw 10 */); - #else + /* ISO C 99 § 7.19.6.1.(6) says: "For d, i, o, u, x, and X conversions, if a + precision is specified, the 0 flag is ignored." */ ASSERT (strcmp (result, " 000000303c 33") == 0); - #endif ASSERT (length == strlen (result)); free (result); } @@ -4232,14 +4227,9 @@ test_function (char * (*my_asnprintf) (char *, size_t *, const char *, ...)) char *result = my_asnprintf (NULL, &length, "%0#15.10x %d", 12348, 33, 44, 55); ASSERT (result != NULL); - /* Neither ISO C nor POSIX specify that the '0' flag is ignored when a width - and a precision are both present. But most implementations do so. */ - #ifdef __MINGW32__ - ASSERT (strcmp (result, "0x000000000303c 33") == 0 /* mingw 5 */ - || strcmp (result, " 0x000000303c 33") == 0 /* mingw 10 */); - #else + /* ISO C 99 § 7.19.6.1.(6) says: "For d, i, o, u, x, and X conversions, if a + precision is specified, the 0 flag is ignored." */ ASSERT (strcmp (result, " 0x000000303c 33") == 0); - #endif ASSERT (length == strlen (result)); free (result); } diff --git a/tests/test-vasnwprintf-posix.c b/tests/test-vasnwprintf-posix.c index 67e6654e5c..351fc8b8c2 100644 --- a/tests/test-vasnwprintf-posix.c +++ b/tests/test-vasnwprintf-posix.c @@ -4203,13 +4203,9 @@ test_function (wchar_t * (*my_asnwprintf) (wchar_t *, size_t *, const wchar_t *, wchar_t *result = my_asnwprintf (NULL, &length, L"%015.10x %d", 12348, 33, 44, 55); ASSERT (result != NULL); - /* Neither ISO C nor POSIX specify that the '0' flag is ignored when a width - and a precision are both present. But most implementations do so. */ - #if MUSL_LIBC - ASSERT (wcscmp (result, L"00000000000303c 33") == 0); - #else + /* ISO C 99 § 7.24.2.1.(6) says: "For d, i, o, u, x, and X conversions, if a + precision is specified, the 0 flag is ignored." */ ASSERT (wcscmp (result, L" 000000303c 33") == 0); - #endif ASSERT (length == wcslen (result)); free (result); } @@ -4289,13 +4285,9 @@ test_function (wchar_t * (*my_asnwprintf) (wchar_t *, size_t *, const wchar_t *, wchar_t *result = my_asnwprintf (NULL, &length, L"%0#15.10x %d", 12348, 33, 44, 55); ASSERT (result != NULL); - /* Neither ISO C nor POSIX specify that the '0' flag is ignored when a width - and a precision are both present. But most implementations do so. */ - #if MUSL_LIBC - ASSERT (wcscmp (result, L"0x000000000303c 33") == 0); - #else + /* ISO C 99 § 7.24.2.1.(6) says: "For d, i, o, u, x, and X conversions, if a + precision is specified, the 0 flag is ignored." */ ASSERT (wcscmp (result, L" 0x000000303c 33") == 0); - #endif ASSERT (length == wcslen (result)); free (result); } diff --git a/tests/test-vasprintf-posix.c b/tests/test-vasprintf-posix.c index 858a477a43..897109537f 100644 --- a/tests/test-vasprintf-posix.c +++ b/tests/test-vasprintf-posix.c @@ -4086,14 +4086,9 @@ test_function (int (*my_asprintf) (char **, const char *, ...)) int retval = my_asprintf (&result, "%015.10x %d", 12348, 33, 44, 55); ASSERT (result != NULL); - /* Neither ISO C nor POSIX specify that the '0' flag is ignored when a width - and a precision are both present. But most implementations do so. */ - #ifdef __MINGW32__ - ASSERT (strcmp (result, "00000000000303c 33") == 0 /* mingw 5 */ - || strcmp (result, " 000000303c 33") == 0 /* mingw 10 */); - #else + /* ISO C 99 § 7.19.6.1.(6) says: "For d, i, o, u, x, and X conversions, if a + precision is specified, the 0 flag is ignored." */ ASSERT (strcmp (result, " 000000303c 33") == 0); - #endif ASSERT (retval == strlen (result)); free (result); } @@ -4173,14 +4168,9 @@ test_function (int (*my_asprintf) (char **, const char *, ...)) int retval = my_asprintf (&result, "%0#15.10x %d", 12348, 33, 44, 55); ASSERT (result != NULL); - /* Neither ISO C nor POSIX specify that the '0' flag is ignored when a width - and a precision are both present. But most implementations do so. */ - #ifdef __MINGW32__ - ASSERT (strcmp (result, "0x000000000303c 33") == 0 /* mingw 5 */ - || strcmp (result, " 0x000000303c 33") == 0 /* mingw 10 */); - #else + /* ISO C 99 § 7.19.6.1.(6) says: "For d, i, o, u, x, and X conversions, if a + precision is specified, the 0 flag is ignored." */ ASSERT (strcmp (result, " 0x000000303c 33") == 0); - #endif ASSERT (retval == strlen (result)); free (result); } -- cgit v1.2.1