From eb8da36e0b3a667444707fb7d0182e54bb2130d0 Mon Sep 17 00:00:00 2001 From: Bruno Haible Date: Sat, 25 Mar 2023 19:36:31 +0100 Subject: [PATCH] stdio: ISO C 23: Define _PRINTF_NAN_LEN_MAX. * lib/stdio.in.h (_PRINTF_NAN_LEN_MAX): New macro. * m4/stdio_h.m4 (gl_STDIO_H): Invoke gl_MUSL_LIBC. * modules/stdio (Files): Add m4/musl.m4. * tests/test-stdio.c: Check that _PRINTF_NAN_LEN_MAX is defined. Include nan.h, macros.h. (main): Check the value of _PRINTF_NAN_LEN_MAX. * modules/stdio-tests (Files): Add tests/nan.h, tests/macros.h, m4/exponentd.m4. (configure.ac): Invoke gl_DOUBLE_EXPONENT_LOCATION. --- ChangeLog | 13 +++++++++++++ lib/stdio.in.h | 31 +++++++++++++++++++++++++++++++ m4/stdio_h.m4 | 5 ++++- modules/stdio | 1 + modules/stdio-tests | 4 ++++ tests/test-stdio.c | 32 ++++++++++++++++++++++++++++++++ 6 files changed, 85 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 99664b24c1..9dd1b50086 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,16 @@ +2023-03-25 Bruno Haible + + stdio: ISO C 23: Define _PRINTF_NAN_LEN_MAX. + * lib/stdio.in.h (_PRINTF_NAN_LEN_MAX): New macro. + * m4/stdio_h.m4 (gl_STDIO_H): Invoke gl_MUSL_LIBC. + * modules/stdio (Files): Add m4/musl.m4. + * tests/test-stdio.c: Check that _PRINTF_NAN_LEN_MAX is defined. + Include nan.h, macros.h. + (main): Check the value of _PRINTF_NAN_LEN_MAX. + * modules/stdio-tests (Files): Add tests/nan.h, tests/macros.h, + m4/exponentd.m4. + (configure.ac): Invoke gl_DOUBLE_EXPONENT_LOCATION. + 2023-03-25 Bruno Haible Make some header file tests a bit stronger. diff --git a/lib/stdio.in.h b/lib/stdio.in.h index 098f841738..0ed3e7595c 100644 --- a/lib/stdio.in.h +++ b/lib/stdio.in.h @@ -204,6 +204,37 @@ # undef putc_unlocked #endif + +/* Maximum number of characters produced by printing a NaN value. */ +#ifndef _PRINTF_NAN_LEN_MAX +# if defined __FreeBSD__ || defined __DragonFly__ \ + || defined __NetBSD__ \ + || defined __OpenBSD__ \ + || (defined __APPLE__ && defined __MACH__) +/* On BSD systems, a NaN value prints as just "nan", without a sign. */ +# define _PRINTF_NAN_LEN_MAX 3 +# elif (__GLIBC__ >= 2) || MUSL_LIBC || defined __sun || defined __CYGWIN__ +/* glibc, musl libc, Solaris libc, and Cygwin produce "[-]nan". */ +# define _PRINTF_NAN_LEN_MAX 4 +# elif defined _AIX +/* AIX produces "[-]NaNQ". */ +# define _PRINTF_NAN_LEN_MAX 5 +# elif defined _WIN32 && !defined __CYGWIN__ +/* On native Windows, the output can be: + - with MSVC ucrt: "[-]nan" or "[-]nan(ind)" or "[-]nan(snan)", + - with mingw: "[-]1.#IND" or "[-]1.#QNAN". */ +# define _PRINTF_NAN_LEN_MAX 10 +# elif defined __sgi +/* On IRIX, the output typically is "[-]nan0xNNNNNNNN" with 8 hexadecimal + digits. */ +# define _PRINTF_NAN_LEN_MAX 14 +# else +/* We don't know, but 32 should be a safe maximum. */ +# define _PRINTF_NAN_LEN_MAX 32 +# endif +#endif + + #if @GNULIB_DPRINTF@ # if @REPLACE_DPRINTF@ # if !(defined __cplusplus && defined GNULIB_NAMESPACE) diff --git a/m4/stdio_h.m4 b/m4/stdio_h.m4 index 07569961f8..342b7d1f20 100644 --- a/m4/stdio_h.m4 +++ b/m4/stdio_h.m4 @@ -1,4 +1,4 @@ -# stdio_h.m4 serial 61 +# stdio_h.m4 serial 62 dnl Copyright (C) 2007-2023 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -40,6 +40,9 @@ AC_DEFUN_ONCE([gl_STDIO_H], attribute "__gnu_printf__" instead of "__printf__"]) fi + dnl For defining _PRINTF_NAN_LEN_MAX. + gl_MUSL_LIBC + dnl This ifdef is an optimization, to avoid performing a configure check whose dnl result is not used. But it does not make the test of dnl GNULIB_STDIO_H_NONBLOCKING or GNULIB_NONBLOCKING redundant. diff --git a/modules/stdio b/modules/stdio index b8662ef0a9..b4d866df9d 100644 --- a/modules/stdio +++ b/modules/stdio @@ -6,6 +6,7 @@ lib/stdio.in.h lib/stdio-read.c lib/stdio-write.c m4/stdio_h.m4 +m4/musl.m4 Depends-on: extensions diff --git a/modules/stdio-tests b/modules/stdio-tests index 5368a2c64c..52b753e2f7 100644 --- a/modules/stdio-tests +++ b/modules/stdio-tests @@ -1,5 +1,8 @@ Files: tests/test-stdio.c +tests/nan.h +tests/macros.h +m4/exponentd.m4 Depends-on: assert-h @@ -10,6 +13,7 @@ fread-tests fwrite-tests configure.ac: +gl_DOUBLE_EXPONENT_LOCATION Makefile.am: TESTS += test-stdio diff --git a/tests/test-stdio.c b/tests/test-stdio.c index a3b0a3e2ba..9794f4d856 100644 --- a/tests/test-stdio.c +++ b/tests/test-stdio.c @@ -23,6 +23,9 @@ /* Check that the various SEEK_* macros are defined. */ int sk[] = { SEEK_CUR, SEEK_END, SEEK_SET }; +/* Check that the _PRINTF_NAN_LEN_MAX macro is defined. */ +int pnlm[] = { _PRINTF_NAN_LEN_MAX }; + /* Check that NULL can be passed through varargs as a pointer type, per POSIX 2008. */ static_assert (sizeof NULL == sizeof (void *)); @@ -34,8 +37,37 @@ size_t t3; ssize_t t4; va_list t5; +#include + +#include "nan.h" +#include "macros.h" + int main (void) { +#if defined DBL_EXPBIT0_WORD && defined DBL_EXPBIT0_BIT + /* Check the value of _PRINTF_NAN_LEN_MAX. */ + { + #define NWORDS \ + ((sizeof (double) + sizeof (unsigned int) - 1) / sizeof (unsigned int)) + typedef union { double value; unsigned int word[NWORDS]; } memory_double; + + double value1; + memory_double value2; + char buf[64]; + + value1 = NaNd(); + sprintf (buf, "%g", value1); + ASSERT (strlen (buf) <= _PRINTF_NAN_LEN_MAX); + + value2.value = NaNd (); + #if DBL_EXPBIT0_BIT == 20 + value2.word[DBL_EXPBIT0_WORD] ^= 0x54321; + #endif + sprintf (buf, "%g", value2.value); + ASSERT (strlen (buf) <= _PRINTF_NAN_LEN_MAX); + } +#endif + return 0; } -- 2.39.5