]> Savannah Git Hosting - gnulib.git/commitdiff
vasnprintf: Work around two grouping bugs on many platforms.
authorBruno Haible <bruno@clisp.org>
Fri, 11 Apr 2025 22:09:23 +0000 (00:09 +0200)
committerBruno Haible <bruno@clisp.org>
Fri, 11 Apr 2025 22:09:23 +0000 (00:09 +0200)
* m4/printf.m4 (gl_PRINTF_FLAG_GROUPING_INT_PRECISION): New macro.
(gl_PRINTF_FLAG_GROUPING_MULTIBYTE): New macro.
* m4/fprintf-posix.m4 (gl_FUNC_FPRINTF_IS_POSIX): Require
gl_PRINTF_FLAG_GROUPING_INT_PRECISION,
gl_PRINTF_FLAG_GROUPING_MULTIBYTE. Test
gl_cv_func_printf_flag_grouping_int_precision,
gl_cv_func_printf_flag_grouping_multibyte.
* m4/dprintf-posix.m4 (gl_FUNC_DPRINTF_IS_POSIX): Likewise.
* m4/snprintf-posix.m4 (gl_FUNC_SNPRINTF_IS_POSIX): Likewise.
* m4/sprintf-posix.m4 (gl_FUNC_SPRINTF_IS_POSIX): Likewise.
* m4/vasnprintf-posix.m4 (gl_FUNC_VASNPRINTF_IS_POSIX): Likewise.
* m4/vasprintf-posix.m4 (gl_FUNC_VASPRINTF_IS_POSIX): Likewise.
* m4/vdprintf-posix.m4 (gl_FUNC_VDPRINTF_IS_POSIX): Likewise.
* m4/vfprintf-posix.m4 (gl_FUNC_VFPRINTF_IS_POSIX): Likewise.
* m4/vsnprintf-posix.m4 (gl_FUNC_VSNPRINTF_IS_POSIX): Likewise.
* m4/vsprintf-posix.m4 (gl_FUNC_VSPRINTF_IS_POSIX): Likewise.
* m4/obstack-printf-posix.m4 (gl_FUNC_OBSTACK_PRINTF_IS_POSIX):
Likewise.
* m4/vasnprintf.m4 (gl_PREREQ_VASNPRINTF_FLAG_GROUPING): Require
gl_PRINTF_FLAG_GROUPING_INT_PRECISION,
gl_PRINTF_FLAG_GROUPING_MULTIBYTE. Test
gl_cv_func_printf_flag_grouping_int_precision,
gl_cv_func_printf_flag_grouping_multibyte. Define the C macro
NEED_PRINTF_FLAG_GROUPING_INT.
* lib/vasnprintf.c (thousands_separator_char): New function.
(THOUSEP_CHAR_MAXLEN): New macro.
(thousands_separator_wchar): New function.
(THOUSEP_WCHAR_MAXLEN): New macro.
(MAX_ROOM_NEEDED): Improve the room estimate for FLAG_GROUP.
(VASNPRINTF): Add code for emitting thousands separators in the %f, %F,
%g, %G implementations and in the code relies the system's
sprintf/snprintf/swprintf function. Test NEED_PRINTF_FLAG_GROUPING and
NEED_PRINTF_FLAG_GROUPING_INT where needed.
* tests/test-vasnprintf-posix2.c (main): Add tests of the grouping flag.
* tests/test-vasnwprintf-posix2.c (main): Likewise.
* tests/test-vasnprintf-posix2.sh: Test in both French locales, not only
in one of them.
* tests/test-vasnwprintf-posix2.sh: Likewise.
* modules/vasnprintf-posix-tests (Depends-on): Add localeconv.
* modules/vasnwprintf-posix-tests (Depends-on): Likewise.
* doc/posix-functions/fprintf.texi: Mention the grouping bug with
precision on integers and the grouping bug with a multibyte thousands
separator.
* doc/posix-functions/vfprintf.texi: Likewise.
* doc/posix-functions/printf.texi: Likewise.
* doc/posix-functions/vprintf.texi: Likewise.
* doc/posix-functions/sprintf.texi: Likewise.
* doc/posix-functions/vsprintf.texi: Likewise.
* doc/posix-functions/snprintf.texi: Likewise.
* doc/posix-functions/vsnprintf.texi: Likewise.
* doc/posix-functions/dprintf.texi: Likewise.
* doc/posix-functions/vdprintf.texi: Likewise.
* doc/posix-functions/fwprintf.texi: Likewise.
* doc/posix-functions/vfwprintf.texi: Likewise.
* doc/posix-functions/wprintf.texi: Likewise.
* doc/posix-functions/vwprintf.texi: Likewise.
* doc/posix-functions/swprintf.texi: Likewise.
* doc/posix-functions/vswprintf.texi: Likewise.
* doc/posix-functions/asprintf.texi: Likewise.
* doc/posix-functions/vasprintf.texi: Likewise.
* doc/glibc-functions/obstack_printf.texi: Likewise.
* doc/glibc-functions/obstack_vprintf.texi: Likewise.

41 files changed:
ChangeLog
doc/glibc-functions/obstack_printf.texi
doc/glibc-functions/obstack_vprintf.texi
doc/posix-functions/asprintf.texi
doc/posix-functions/dprintf.texi
doc/posix-functions/fprintf.texi
doc/posix-functions/fwprintf.texi
doc/posix-functions/printf.texi
doc/posix-functions/snprintf.texi
doc/posix-functions/sprintf.texi
doc/posix-functions/swprintf.texi
doc/posix-functions/vasprintf.texi
doc/posix-functions/vdprintf.texi
doc/posix-functions/vfprintf.texi
doc/posix-functions/vfwprintf.texi
doc/posix-functions/vprintf.texi
doc/posix-functions/vsnprintf.texi
doc/posix-functions/vsprintf.texi
doc/posix-functions/vswprintf.texi
doc/posix-functions/vwprintf.texi
doc/posix-functions/wprintf.texi
lib/vasnprintf.c
m4/dprintf-posix.m4
m4/fprintf-posix.m4
m4/obstack-printf-posix.m4
m4/printf.m4
m4/snprintf-posix.m4
m4/sprintf-posix.m4
m4/vasnprintf-posix.m4
m4/vasnprintf.m4
m4/vasprintf-posix.m4
m4/vdprintf-posix.m4
m4/vfprintf-posix.m4
m4/vsnprintf-posix.m4
m4/vsprintf-posix.m4
modules/vasnprintf-posix-tests
modules/vasnwprintf-posix-tests
tests/test-vasnprintf-posix2.c
tests/test-vasnprintf-posix2.sh
tests/test-vasnwprintf-posix2.c
tests/test-vasnwprintf-posix2.sh

index dedd3ca34ee41c2bfe6335b5e27dd31a30190a01..1794562eafcc8133ad53c3ecaeb61b6d6c205ba9 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,69 @@
+2025-04-11  Bruno Haible  <bruno@clisp.org>
+
+       vasnprintf: Work around two grouping bugs on many platforms.
+       * m4/printf.m4 (gl_PRINTF_FLAG_GROUPING_INT_PRECISION): New macro.
+       (gl_PRINTF_FLAG_GROUPING_MULTIBYTE): New macro.
+       * m4/fprintf-posix.m4 (gl_FUNC_FPRINTF_IS_POSIX): Require
+       gl_PRINTF_FLAG_GROUPING_INT_PRECISION,
+       gl_PRINTF_FLAG_GROUPING_MULTIBYTE. Test
+       gl_cv_func_printf_flag_grouping_int_precision,
+       gl_cv_func_printf_flag_grouping_multibyte.
+       * m4/dprintf-posix.m4 (gl_FUNC_DPRINTF_IS_POSIX): Likewise.
+       * m4/snprintf-posix.m4 (gl_FUNC_SNPRINTF_IS_POSIX): Likewise.
+       * m4/sprintf-posix.m4 (gl_FUNC_SPRINTF_IS_POSIX): Likewise.
+       * m4/vasnprintf-posix.m4 (gl_FUNC_VASNPRINTF_IS_POSIX): Likewise.
+       * m4/vasprintf-posix.m4 (gl_FUNC_VASPRINTF_IS_POSIX): Likewise.
+       * m4/vdprintf-posix.m4 (gl_FUNC_VDPRINTF_IS_POSIX): Likewise.
+       * m4/vfprintf-posix.m4 (gl_FUNC_VFPRINTF_IS_POSIX): Likewise.
+       * m4/vsnprintf-posix.m4 (gl_FUNC_VSNPRINTF_IS_POSIX): Likewise.
+       * m4/vsprintf-posix.m4 (gl_FUNC_VSPRINTF_IS_POSIX): Likewise.
+       * m4/obstack-printf-posix.m4 (gl_FUNC_OBSTACK_PRINTF_IS_POSIX):
+       Likewise.
+       * m4/vasnprintf.m4 (gl_PREREQ_VASNPRINTF_FLAG_GROUPING): Require
+       gl_PRINTF_FLAG_GROUPING_INT_PRECISION,
+       gl_PRINTF_FLAG_GROUPING_MULTIBYTE. Test
+       gl_cv_func_printf_flag_grouping_int_precision,
+       gl_cv_func_printf_flag_grouping_multibyte. Define the C macro
+       NEED_PRINTF_FLAG_GROUPING_INT.
+       * lib/vasnprintf.c (thousands_separator_char): New function.
+       (THOUSEP_CHAR_MAXLEN): New macro.
+       (thousands_separator_wchar): New function.
+       (THOUSEP_WCHAR_MAXLEN): New macro.
+       (MAX_ROOM_NEEDED): Improve the room estimate for FLAG_GROUP.
+       (VASNPRINTF): Add code for emitting thousands separators in the %f, %F,
+       %g, %G implementations and in the code relies the system's
+       sprintf/snprintf/swprintf function. Test NEED_PRINTF_FLAG_GROUPING and
+       NEED_PRINTF_FLAG_GROUPING_INT where needed.
+       * tests/test-vasnprintf-posix2.c (main): Add tests of the grouping flag.
+       * tests/test-vasnwprintf-posix2.c (main): Likewise.
+       * tests/test-vasnprintf-posix2.sh: Test in both French locales, not only
+       in one of them.
+       * tests/test-vasnwprintf-posix2.sh: Likewise.
+       * modules/vasnprintf-posix-tests (Depends-on): Add localeconv.
+       * modules/vasnwprintf-posix-tests (Depends-on): Likewise.
+       * doc/posix-functions/fprintf.texi: Mention the grouping bug with
+       precision on integers and the grouping bug with a multibyte thousands
+       separator.
+       * doc/posix-functions/vfprintf.texi: Likewise.
+       * doc/posix-functions/printf.texi: Likewise.
+       * doc/posix-functions/vprintf.texi: Likewise.
+       * doc/posix-functions/sprintf.texi: Likewise.
+       * doc/posix-functions/vsprintf.texi: Likewise.
+       * doc/posix-functions/snprintf.texi: Likewise.
+       * doc/posix-functions/vsnprintf.texi: Likewise.
+       * doc/posix-functions/dprintf.texi: Likewise.
+       * doc/posix-functions/vdprintf.texi: Likewise.
+       * doc/posix-functions/fwprintf.texi: Likewise.
+       * doc/posix-functions/vfwprintf.texi: Likewise.
+       * doc/posix-functions/wprintf.texi: Likewise.
+       * doc/posix-functions/vwprintf.texi: Likewise.
+       * doc/posix-functions/swprintf.texi: Likewise.
+       * doc/posix-functions/vswprintf.texi: Likewise.
+       * doc/posix-functions/asprintf.texi: Likewise.
+       * doc/posix-functions/vasprintf.texi: Likewise.
+       * doc/glibc-functions/obstack_printf.texi: Likewise.
+       * doc/glibc-functions/obstack_vprintf.texi: Likewise.
+
 2025-04-11  Bruno Haible  <bruno@clisp.org>
 
        vasnprintf: Follow glibc's behaviour on glibc systems.
index 1f2d1ad5a1d535b728162a651dae46daf24ddbb1..c96a674ac2d9a99ac4ce348771fdc5f28a75a544 100644 (file)
@@ -42,6 +42,14 @@ printf @code{"%f"}, @code{"%e"}, @code{"%g"} of Infinity and NaN yields an
 incorrect result on some platforms:
 AIX 7.3, Solaris 11.4, mingw, MSVC 14.
 @item
+This function doesn't support the @code{'} flag together with a precision
+on an integer argument correctly on some platforms:
+glibc 2.36, FreeBSD 14.0, NetBSD 10.0, Solaris 11, Cygwin 3.6.0, Haiku.
+@item
+This function doesn't support the @code{'} flag correctly in locales where
+the thousands separator is a multibyte character on some platforms:
+NetBSD 10.0, Solaris 11 OpenIndiana.
+@item
 This function does not support the @samp{a} and @samp{A} directives on some
 platforms:
 FreeBSD 5.2.1, OpenBSD 4.0, AIX 5.2, HP-UX 11,
index c94df7b26c7421fe16b8071b3658e068ebaf126d..5fe389c4863cead8e323219f9ce2cb11390def74 100644 (file)
@@ -42,6 +42,14 @@ printf @code{"%f"}, @code{"%e"}, @code{"%g"} of Infinity and NaN yields an
 incorrect result on some platforms:
 AIX 7.3, Solaris 11.4, mingw, MSVC 14.
 @item
+This function doesn't support the @code{'} flag together with a precision
+on an integer argument correctly on some platforms:
+glibc 2.36, FreeBSD 14.0, NetBSD 10.0, Solaris 11, Cygwin 3.6.0, Haiku.
+@item
+This function doesn't support the @code{'} flag correctly in locales where
+the thousands separator is a multibyte character on some platforms:
+NetBSD 10.0, Solaris 11 OpenIndiana.
+@item
 This function does not support the @samp{a} and @samp{A} directives on some
 platforms:
 FreeBSD 5.2.1, OpenBSD 4.0, AIX 5.2, HP-UX 11,
index bf5fbb8f0abf72b4f003cb24099c9ccf06ea049f..dbbed305b5867ded526229d36d0288707daed7a9 100644 (file)
@@ -71,6 +71,14 @@ NetBSD 3.0.
 This function doesn't support the @code{'} flag on some platforms:
 NetBSD 3.0, Cygwin 1.5.24.
 @item
+This function doesn't support the @code{'} flag together with a precision
+on an integer argument correctly on some platforms:
+glibc 2.36, FreeBSD 14.0, NetBSD 10.0, Solaris 11, Cygwin 3.6.0, Haiku.
+@item
+This function doesn't support the @code{'} flag correctly in locales where
+the thousands separator is a multibyte character on some platforms:
+NetBSD 10.0, Solaris 11 OpenIndiana.
+@item
 This function does not round the argument of the @samp{a} directive correctly
 on some platforms:
 macOS 14, FreeBSD 14.0, NetBSD 10.0, OpenBSD 7.5, AIX 7.3, Solaris 11.4.
index e19b75c89131878c14d07dbca7d0b252752cd14c..da9446ae99de4258130b52432cfc4ffee1c931f7 100644 (file)
@@ -28,6 +28,14 @@ printf @code{"%f"}, @code{"%e"}, @code{"%g"} of Infinity and NaN yields an
 incorrect result on some platforms:
 AIX 7.3, Solaris 11.4.
 @item
+This function doesn't support the @code{'} flag together with a precision
+on an integer argument correctly on some platforms:
+glibc 2.36, FreeBSD 14.0, NetBSD 10.0, Solaris 11, Cygwin 3.6.0, Haiku.
+@item
+This function doesn't support the @code{'} flag correctly in locales where
+the thousands separator is a multibyte character on some platforms:
+NetBSD 10.0, Solaris 11 OpenIndiana.
+@item
 This function does not support the @samp{a} and @samp{A} directives on some
 platforms:
 Solaris 11.4.
index 5509008d820976681ded93dab5908c9857c4ae42..407ad6bc306ae46147eb385230aefc7591616833 100644 (file)
@@ -58,6 +58,14 @@ NetBSD 3.0, mingw, MSVC 14.
 This function doesn't support the @code{'} flag on some platforms:
 NetBSD 3.0, Cygwin 1.5.24, mingw, MSVC 14.
 @item
+This function doesn't support the @code{'} flag together with a precision
+on an integer argument correctly on some platforms:
+glibc 2.36, FreeBSD 14.0, NetBSD 10.0, Solaris 11, Cygwin 3.6.0, Haiku.
+@item
+This function doesn't support the @code{'} flag correctly in locales where
+the thousands separator is a multibyte character on some platforms:
+NetBSD 10.0, Solaris 11 OpenIndiana.
+@item
 This function does not round the argument of the @samp{a} directive correctly
 on some platforms:
 macOS 14, FreeBSD 14.0, NetBSD 10.0, OpenBSD 7.5, AIX 7.3, Solaris 11.4.
index e408a0f8f8446d79745435c722bc45ac1c40eb6a..0dd8ec828a6f20604777937a28b0181a185fef82 100644 (file)
@@ -24,6 +24,14 @@ This function does not support size specifiers as in C23 (@code{w8},
 @code{wf64}) on some platforms:
 glibc 2.37, musl libc, macOS 14, FreeBSD 13.2, NetBSD 10.0, OpenBSD 7.5, AIX 7.3, Solaris 11.4, Cygwin 3.5.3, mingw, MSVC, Android 9.0.
 @item
+This function doesn't support the @code{'} flag together with a precision
+on an integer argument correctly on some platforms:
+glibc 2.36, FreeBSD 14.0, NetBSD 10.0, Solaris 11, Cygwin 3.6.0, Haiku.
+@item
+This function doesn't support the @code{'} flag correctly in locales where
+the thousands separator is a multibyte character on some platforms:
+NetBSD 10.0, Solaris 11 OpenIndiana.
+@item
 This function does not support the @samp{b} directive, required by ISO C23,
 on some platforms:
 glibc 2.34, musl libc, macOS 14, FreeBSD 13.2, NetBSD 10.0, OpenBSD 7.5,
index aba01687b8349d992f2db3850b582d8f042a95aa..2b2c24053143deea0f006c344855eeff9896666a 100644 (file)
@@ -30,6 +30,14 @@ printf @code{"%f"}, @code{"%e"}, @code{"%g"} of Infinity and NaN yields an
 incorrect result on some platforms:
 AIX 7.3, Solaris 11.4, mingw, MSVC 14.
 @item
+This function doesn't support the @code{'} flag together with a precision
+on an integer argument correctly on some platforms:
+glibc 2.36, FreeBSD 14.0, NetBSD 10.0, Solaris 11, Cygwin 3.6.0, Haiku.
+@item
+This function doesn't support the @code{'} flag correctly in locales where
+the thousands separator is a multibyte character on some platforms:
+NetBSD 10.0, Solaris 11 OpenIndiana.
+@item
 This function does not support the @samp{a} and @samp{A} directives on some
 platforms:
 FreeBSD 5.2.1, OpenBSD 4.0, AIX 5.2, HP-UX 11,
index b7e0f8445ab0108287fa0a2a9ed16e8eea8cf0e1..a1aea4ea4b8116d87b6f818595462db655b3c2a2 100644 (file)
@@ -43,6 +43,14 @@ printf @code{"%f"}, @code{"%e"}, @code{"%g"} of Infinity and NaN yields an
 incorrect result on some platforms:
 AIX 7.3, Solaris 11.4, mingw, MSVC 14.
 @item
+This function doesn't support the @code{'} flag together with a precision
+on an integer argument correctly on some platforms:
+glibc 2.36, FreeBSD 14.0, NetBSD 10.0, Solaris 11, Cygwin 3.6.0, Haiku.
+@item
+This function doesn't support the @code{'} flag correctly in locales where
+the thousands separator is a multibyte character on some platforms:
+NetBSD 10.0, Solaris 11 OpenIndiana.
+@item
 This function does not support the @samp{a} and @samp{A} directives on some
 platforms:
 FreeBSD 5.2.1, OpenBSD 4.0, AIX 5.2, HP-UX 11,
index 5b666609eef0585290d6c3b7ca41bc6efd84b0d9..3b0bc0f7250df4f4b157ebb7a271327eb7acf55b 100644 (file)
@@ -27,6 +27,14 @@ printf @code{"%f"}, @code{"%e"}, @code{"%g"} of Infinity and NaN yields an
 incorrect result on some platforms:
 AIX 7.3, Solaris 11.4, mingw, MSVC 14.
 @item
+This function doesn't support the @code{'} flag together with a precision
+on an integer argument correctly on some platforms:
+glibc 2.36, FreeBSD 14.0, NetBSD 10.0, Solaris 11, Cygwin 3.6.0, Haiku.
+@item
+This function doesn't support the @code{'} flag correctly in locales where
+the thousands separator is a multibyte character on some platforms:
+NetBSD 10.0, Solaris 11 OpenIndiana.
+@item
 This function does not support the @samp{a} and @samp{A} directives on some
 platforms:
 FreeBSD 5.2.1, OpenBSD 4.0, AIX 5.2, HP-UX 11,
index 7f6ee3848f13463dcca42bea5a296e1ba29c72bf..944dd4798cf2caf9cf7ec4035f225cd76d488694 100644 (file)
@@ -60,6 +60,14 @@ characters on some platforms:
 musl libc 1.2.3,
 macOS 14, FreeBSD 13.1, NetBSD 10.0, OpenBSD 7.2, AIX 7.2, mingw.
 @item
+This function doesn't support the @code{'} flag together with a precision
+on an integer argument correctly on some platforms:
+glibc 2.36, FreeBSD 14.0, NetBSD 10.0, Solaris 11, Cygwin 3.6.0, Haiku.
+@item
+This function doesn't support the @code{'} flag correctly in locales where
+the thousands separator is a multibyte character on some platforms:
+NetBSD 10.0, Solaris 11 OpenIndiana.
+@item
 This function does not support the @samp{b} directive, required by ISO C23,
 on some platforms:
 glibc 2.34, musl libc, macOS 14, FreeBSD 13.2, NetBSD 10.0, OpenBSD 7.5,
index 7c45295759412209b20c86077ac60d50ef8f8958..8805d6fb9a8d61859439f22581be2c6d97cbdb4d 100644 (file)
@@ -45,6 +45,14 @@ printf @code{"%f"}, @code{"%e"}, @code{"%g"} of Infinity and NaN yields an
 incorrect result on some platforms:
 AIX 7.3, Solaris 11.4.
 @item
+This function doesn't support the @code{'} flag together with a precision
+on an integer argument correctly on some platforms:
+glibc 2.36, FreeBSD 14.0, NetBSD 10.0, Solaris 11, Cygwin 3.6.0, Haiku.
+@item
+This function doesn't support the @code{'} flag correctly in locales where
+the thousands separator is a multibyte character on some platforms:
+NetBSD 10.0, Solaris 11 OpenIndiana.
+@item
 This function does not support the @samp{a} and @samp{A} directives on some
 platforms:
 FreeBSD 5.2.1, OpenBSD 4.0, Solaris 11.4, Cygwin 1.5.x.
index 619ff1260eb0ead249d32c1ce36b191938c9a247..3277f6edb64ac32375bcf077ec0ec2f44a9de4b7 100644 (file)
@@ -28,6 +28,14 @@ printf @code{"%f"}, @code{"%e"}, @code{"%g"} of Infinity and NaN yields an
 incorrect result on some platforms:
 AIX 7.3, Solaris 11.4.
 @item
+This function doesn't support the @code{'} flag together with a precision
+on an integer argument correctly on some platforms:
+glibc 2.36, FreeBSD 14.0, NetBSD 10.0, Solaris 11, Cygwin 3.6.0, Haiku.
+@item
+This function doesn't support the @code{'} flag correctly in locales where
+the thousands separator is a multibyte character on some platforms:
+NetBSD 10.0, Solaris 11 OpenIndiana.
+@item
 This function does not support the @samp{a} and @samp{A} directives on some
 platforms:
 Solaris 11.4.
index ffebd0983d87e3de01a921242f4557cffa948882..cdf1f75cc8fd9de4866b4f1fb2b820f724a79809 100644 (file)
@@ -30,6 +30,14 @@ printf @code{"%f"}, @code{"%e"}, @code{"%g"} of Infinity and NaN yields an
 incorrect result on some platforms:
 AIX 7.3, Solaris 11.4, mingw, MSVC 14.
 @item
+This function doesn't support the @code{'} flag together with a precision
+on an integer argument correctly on some platforms:
+glibc 2.36, FreeBSD 14.0, NetBSD 10.0, Solaris 11, Cygwin 3.6.0, Haiku.
+@item
+This function doesn't support the @code{'} flag correctly in locales where
+the thousands separator is a multibyte character on some platforms:
+NetBSD 10.0, Solaris 11 OpenIndiana.
+@item
 This function does not support the @samp{a} and @samp{A} directives on some
 platforms:
 FreeBSD 5.2.1, OpenBSD 4.0, AIX 5.2, HP-UX 11,
index e92f3e08c7a3cfbec619d4e0d70e0eb90472ac8a..0e7bb752fa6b47ac578e68c67bc08cea744a23ea 100644 (file)
@@ -24,6 +24,14 @@ This function does not support size specifiers as in C23 (@code{w8},
 @code{wf64}) on some platforms:
 glibc 2.37, musl libc, macOS 14, FreeBSD 13.2, NetBSD 10.0, OpenBSD 7.5, AIX 7.3, Solaris 11.4, Cygwin 3.5.3, mingw, MSVC, Android 9.0.
 @item
+This function doesn't support the @code{'} flag together with a precision
+on an integer argument correctly on some platforms:
+glibc 2.36, FreeBSD 14.0, NetBSD 10.0, Solaris 11, Cygwin 3.6.0, Haiku.
+@item
+This function doesn't support the @code{'} flag correctly in locales where
+the thousands separator is a multibyte character on some platforms:
+NetBSD 10.0, Solaris 11 OpenIndiana.
+@item
 This function does not support the @samp{b} directive, required by ISO C23,
 on some platforms:
 glibc 2.34, musl libc, macOS 14, FreeBSD 13.2, NetBSD 10.0, OpenBSD 7.5,
index 85bdf6977d3f935cd68d8c07e40ab8e6cf458d31..ad82631b32515b1dba0712f01a4fb43dddc51699 100644 (file)
@@ -30,6 +30,14 @@ printf @code{"%f"}, @code{"%e"}, @code{"%g"} of Infinity and NaN yields an
 incorrect result on some platforms:
 AIX 7.3, Solaris 11.4, mingw, MSVC 14.
 @item
+This function doesn't support the @code{'} flag together with a precision
+on an integer argument correctly on some platforms:
+glibc 2.36, FreeBSD 14.0, NetBSD 10.0, Solaris 11, Cygwin 3.6.0, Haiku.
+@item
+This function doesn't support the @code{'} flag correctly in locales where
+the thousands separator is a multibyte character on some platforms:
+NetBSD 10.0, Solaris 11 OpenIndiana.
+@item
 This function does not support the @samp{a} and @samp{A} directives on some
 platforms:
 FreeBSD 5.2.1, OpenBSD 4.0, AIX 5.2, HP-UX 11,
index e0372e8be7b0dc07385ea2debbf83db916c8433f..0dc8280a7c37d22a5bda83f98ba87d17082bf730 100644 (file)
@@ -40,6 +40,14 @@ printf @code{"%f"}, @code{"%e"}, @code{"%g"} of Infinity and NaN yields an
 incorrect result on some platforms:
 AIX 7.3, Solaris 11.4, mingw, MSVC 14.
 @item
+This function doesn't support the @code{'} flag together with a precision
+on an integer argument correctly on some platforms:
+glibc 2.36, FreeBSD 14.0, NetBSD 10.0, Solaris 11, Cygwin 3.6.0, Haiku.
+@item
+This function doesn't support the @code{'} flag correctly in locales where
+the thousands separator is a multibyte character on some platforms:
+NetBSD 10.0, Solaris 11 OpenIndiana.
+@item
 This function does not support the @samp{a} and @samp{A} directives on some
 platforms:
 FreeBSD 5.2.1, OpenBSD 4.0, AIX 5.2, HP-UX 11,
index 7289400e54ed2d4423fd36ffd846ef2b4adf99e5..fb231106218a0d74fb7533d1e0d9adc48da98f32 100644 (file)
@@ -27,6 +27,14 @@ printf @code{"%f"}, @code{"%e"}, @code{"%g"} of Infinity and NaN yields an
 incorrect result on some platforms:
 AIX 7.3, Solaris 11.4, mingw, MSVC 14.
 @item
+This function doesn't support the @code{'} flag together with a precision
+on an integer argument correctly on some platforms:
+glibc 2.36, FreeBSD 14.0, NetBSD 10.0, Solaris 11, Cygwin 3.6.0, Haiku.
+@item
+This function doesn't support the @code{'} flag correctly in locales where
+the thousands separator is a multibyte character on some platforms:
+NetBSD 10.0, Solaris 11 OpenIndiana.
+@item
 This function does not support the @samp{a} and @samp{A} directives on some
 platforms:
 FreeBSD 5.2.1, OpenBSD 4.0, AIX 5.2, HP-UX 11,
index 03a6c06eed9f7278e9d2d3c5b68f820bdb2076e7..b237e8b086e313b0a1b2d49f71c645bf73fbb5ed 100644 (file)
@@ -26,6 +26,14 @@ This function does not support size specifiers as in C23 (@code{w8},
 @code{wf64}) on some platforms:
 glibc 2.37, musl libc, macOS 14, FreeBSD 13.2, NetBSD 10.0, OpenBSD 7.5, AIX 7.3, Solaris 11.4, Cygwin 3.5.3, mingw, MSVC, Android 9.0.
 @item
+This function doesn't support the @code{'} flag together with a precision
+on an integer argument correctly on some platforms:
+glibc 2.36, FreeBSD 14.0, NetBSD 10.0, Solaris 11, Cygwin 3.6.0, Haiku.
+@item
+This function doesn't support the @code{'} flag correctly in locales where
+the thousands separator is a multibyte character on some platforms:
+NetBSD 10.0, Solaris 11 OpenIndiana.
+@item
 This function does not support the @samp{b} directive, required by ISO C23,
 on some platforms:
 glibc 2.34, musl libc, macOS 14, FreeBSD 13.2, NetBSD 10.0, OpenBSD 7.5,
index 7065c7163c2b952af8750a6284067e3bd101ef42..faa34281437c9d249bb91b6a908ff38e6aa424ed 100644 (file)
@@ -27,6 +27,14 @@ This function does not support size specifiers as in C23 (@code{w8},
 @code{wf64}) on some platforms:
 glibc 2.37, musl libc, macOS 14, FreeBSD 13.2, NetBSD 10.0, OpenBSD 7.5, AIX 7.3, Solaris 11.4, Cygwin 3.5.3, mingw, MSVC, Android 9.0.
 @item
+This function doesn't support the @code{'} flag together with a precision
+on an integer argument correctly on some platforms:
+glibc 2.36, FreeBSD 14.0, NetBSD 10.0, Solaris 11, Cygwin 3.6.0, Haiku.
+@item
+This function doesn't support the @code{'} flag correctly in locales where
+the thousands separator is a multibyte character on some platforms:
+NetBSD 10.0, Solaris 11 OpenIndiana.
+@item
 This function does not support the @samp{b} directive, required by ISO C23,
 on some platforms:
 glibc 2.34, musl libc, macOS 14, FreeBSD 13.2, NetBSD 10.0, OpenBSD 7.5,
index ab169cf7ae625703abd454972bca4f4642f435e9..47353bcce86fc04c76199a7f3bdcd61549fa205e 100644 (file)
@@ -27,6 +27,14 @@ This function does not support size specifiers as in C23 (@code{w8},
 @code{wf64}) on some platforms:
 glibc 2.37, musl libc, macOS 14, FreeBSD 13.2, NetBSD 10.0, OpenBSD 7.5, AIX 7.3, Solaris 11.4, Cygwin 3.5.3, mingw, MSVC, Android 9.0.
 @item
+This function doesn't support the @code{'} flag together with a precision
+on an integer argument correctly on some platforms:
+glibc 2.36, FreeBSD 14.0, NetBSD 10.0, Solaris 11, Cygwin 3.6.0, Haiku.
+@item
+This function doesn't support the @code{'} flag correctly in locales where
+the thousands separator is a multibyte character on some platforms:
+NetBSD 10.0, Solaris 11 OpenIndiana.
+@item
 This function does not support the @samp{b} directive, required by ISO C23,
 on some platforms:
 glibc 2.34, musl libc, macOS 14, FreeBSD 13.2, NetBSD 10.0, OpenBSD 7.5,
index f91300cbd15c9e74d895b3c2964b477a1edf1466..45e7c724a5e763371cba01d88ffd7a49f005e0cf 100644 (file)
@@ -88,7 +88,7 @@
 #include <errno.h>      /* errno */
 #include <limits.h>     /* CHAR_BIT, INT_MAX, INT_WIDTH, LONG_WIDTH */
 #include <float.h>      /* DBL_MAX_EXP, LDBL_MAX_EXP, LDBL_MANT_DIG */
-#if HAVE_NL_LANGINFO
+#if HAVE_NL_LANGINFO || __GLIBC__ >= 2 || defined __CYGWIN__
 # include <langinfo.h>
 #endif
 #ifndef VASNPRINTF
@@ -371,7 +371,7 @@ local_wctomb (char *s, wchar_t wc)
 # endif
 #endif
 
-#if NEED_PRINTF_DIRECTIVE_A || NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_INFINITE_LONG_DOUBLE || NEED_PRINTF_DOUBLE || NEED_PRINTF_INFINITE_DOUBLE || (NEED_WPRINTF_DIRECTIVE_LA && WIDE_CHAR_VERSION)
+#if NEED_PRINTF_DIRECTIVE_A || NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_INFINITE_LONG_DOUBLE || NEED_PRINTF_DOUBLE || NEED_PRINTF_INFINITE_DOUBLE || (NEED_WPRINTF_DIRECTIVE_LA && WIDE_CHAR_VERSION) || (NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION || NEED_PRINTF_FLAG_GROUPING || NEED_PRINTF_FLAG_GROUPING_INT)
 /* Determine the decimal-point character according to the current locale.  */
 # ifndef decimal_point_char_defined
 #  define decimal_point_char_defined 1
@@ -398,6 +398,94 @@ decimal_point_char (void)
 # endif
 #endif
 
+#if (!WIDE_CHAR_VERSION && (NEED_PRINTF_DOUBLE || NEED_PRINTF_LONG_DOUBLE)) || ((!WIDE_CHAR_VERSION || !DCHAR_IS_TCHAR) && (NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION || NEED_PRINTF_FLAG_GROUPING || NEED_PRINTF_FLAG_GROUPING_INT))
+/* Determine the thousands-separator character according to the current
+   locale.
+   It is a single multibyte character.
+   In glibc: 35x ".", 90x ",", 23x U+202F, 1x U+2019, 1x U+066C, on other
+   systems also U+00A0.  */
+# ifndef thousands_separator_char_defined
+#  define thousands_separator_char_defined 1
+static const char *
+thousands_separator_char (char stackbuf[10])
+{
+  /* Determine it in a multithread-safe way.  We know nl_langinfo is
+     multithread-safe on glibc systems, on Mac OS X systems, and on NetBSD,
+     but is not required to be multithread-safe by POSIX.  sprintf(), however,
+     is multithread-safe.  localeconv() is rarely multithread-safe.  */
+#  if HAVE_NL_LANGINFO && (__GLIBC__ || defined __UCLIBC__ || (defined __APPLE__ && defined __MACH__) || defined __NetBSD__)
+  return nl_langinfo (THOUSEP);
+#  elif 1
+  sprintf (stackbuf, "%'.0f", 1000.0);
+  /* Now stackbuf = "1<thousep>000".  */
+  stackbuf[strlen (stackbuf) - 3] = '\0';
+#   if defined __sun
+  /* Solaris specific hack: Replace wrong result (0xC2 means U+00A0).  */
+  if (strcmp (&stackbuf[1], "\302") == 0)
+    strcpy (&stackbuf[1], MB_CUR_MAX > 1 ? "\302\240" : "\240");
+#   endif
+  return &stackbuf[1];
+#  else
+  return localeconv () -> thousands_sep;
+#  endif
+}
+# endif
+#endif
+/* Maximum number of 'char' in the char[] representation of the thousands
+   separator.  */
+#define THOUSEP_CHAR_MAXLEN 3
+
+#if WIDE_CHAR_VERSION && ((NEED_PRINTF_DOUBLE || NEED_PRINTF_LONG_DOUBLE) || ((NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION || NEED_PRINTF_FLAG_GROUPING || NEED_PRINTF_FLAG_GROUPING_INT) && DCHAR_IS_TCHAR))
+/* Determine the thousands-separator character, as a wide character, according
+   to the current locale.
+   It is a single wide character.  */
+# ifndef thousands_separator_wchar_defined
+#  define thousands_separator_wchar_defined 1
+static const wchar_t *
+thousands_separator_wchar (wchar_t stackbuf[10])
+{
+#  if __GLIBC__ >= 2 || defined __CYGWIN__
+  /* On glibc, in the unibyte locale fr_FR, the *wprintf routines use U+202F
+     as separator, which cannot be represented in the locale encoding.  */
+  stackbuf[0] =
+    (wchar_t) (unsigned long) nl_langinfo (_NL_NUMERIC_THOUSANDS_SEP_WC);
+  stackbuf[1] = L'\0';
+  return stackbuf;
+#  elif defined __sun
+  /* Use sprintf, because swprintf retrieves a wrong value for the
+     thousands-separator wide character (e.g. (wchar_t) 0xffffffa0).  */
+  char tmp[10];
+  sprintf (tmp, "%'.0f", 1000.0);
+  /* Now tmp = L"1<thousep>000".  */
+  tmp[strlen (tmp) - 3] = '\0';
+  /* Solaris specific hack: Replace wrong result (0xC2 means U+00A0).  */
+  if (strcmp (&tmp[1], "\302") == 0)
+    strcpy (&tmp[1], MB_CUR_MAX > 1 ? "\302\240" : "\240");
+  if (tmp[1] != '\0')
+    {
+      mbstate_t state;
+      mbszero (&state);
+      if ((int) mbrtowc (&stackbuf[0], &tmp[1], strlen (&tmp[1]), &state) > 0)
+        stackbuf[1] = L'\0';
+      else
+        stackbuf[0] = L'\0';
+    }
+  else
+    stackbuf[0] = L'\0';
+  return stackbuf;
+#  else
+  swprintf (stackbuf, 10, L"%'.0f", 1000.0);
+  /* Now stackbuf = L"1<thousep>000".  */
+  stackbuf[local_wcslen (stackbuf) - 3] = '\0';
+  return &stackbuf[1];
+#  endif
+}
+# endif
+#endif
+/* Maximum number of 'wchar_t' in the wchar_t[] representation of the thousands
+   separator.  */
+#define THOUSEP_WCHAR_MAXLEN 1
+
 #if NEED_PRINTF_INFINITE_DOUBLE && !NEED_PRINTF_DOUBLE
 
 /* Equivalent to !isfinite(x) || x == 0, but does not require libm.  */
@@ -1852,8 +1940,15 @@ MAX_ROOM_NEEDED (const arguments *ap, size_t arg_index, FCHAR_T conversion,
         }
       if (tmp_length < precision)
         tmp_length = precision;
-      /* Multiply by 2, as an estimate for FLAG_GROUP.  */
-      tmp_length = xsum (tmp_length, tmp_length);
+      /* Account for thousands separators.  */
+      if (flags & FLAG_GROUP)
+        {
+# if WIDE_CHAR_VERSION
+          tmp_length = xsum (tmp_length, tmp_length / 3 * THOUSEP_WCHAR_MAXLEN);
+# else
+          tmp_length = xsum (tmp_length, tmp_length / 3 * THOUSEP_CHAR_MAXLEN);
+# endif
+        }
       /* Add 1, to account for a leading sign.  */
       tmp_length = xsum (tmp_length, 1);
       break;
@@ -4903,6 +4998,16 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
                         }
                     }
 # endif
+                /* Account for thousands separators.  */
+                if (flags & FLAG_GROUP)
+                  {
+# if WIDE_CHAR_VERSION
+                    tmp_length = xsum (tmp_length, tmp_length / 3 * THOUSEP_WCHAR_MAXLEN);
+# else
+
+                    tmp_length = xsum (tmp_length, tmp_length / 3 * THOUSEP_CHAR_MAXLEN);
+# endif
+                  }
                 /* Account for sign, decimal point etc. */
                 tmp_length = xsum (tmp_length, 12);
 
@@ -4998,12 +5103,49 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
                                 ndigits = strlen (digits);
 
                                 if (ndigits > precision)
-                                  do
-                                    {
-                                      --ndigits;
-                                      *p++ = digits[ndigits];
-                                    }
-                                  while (ndigits > precision);
+                                  {
+                                    const DCHAR_T *thousep = NULL;
+                                    DCHAR_T thousep_buf[10];
+#   if !WIDE_CHAR_VERSION
+                                    size_t thousep_len;
+#   endif
+
+                                    if ((flags & FLAG_GROUP)
+                                        && (ndigits - precision > 3))
+                                      {
+                                        /* Determine the thousands separator of the
+                                           current locale.  */
+#   if WIDE_CHAR_VERSION
+                                        /* DCHAR_T is wchar_t.  */
+                                        thousep = thousands_separator_wchar (thousep_buf);
+#   else
+                                        /* DCHAR_T is char.  */
+                                        thousep = thousands_separator_char (thousep_buf);
+                                        thousep_len = strlen (thousep);
+#   endif
+                                        if (*thousep == 0)
+                                          thousep = NULL;
+                                      }
+
+                                    for (;;)
+                                      {
+                                        --ndigits;
+                                        *p++ = digits[ndigits];
+                                        if (ndigits == precision)
+                                          break;
+                                        if (thousep != NULL
+                                            /* implies (flags & FLAG_GROUP) */
+                                            && ((ndigits - precision) % 3) == 0)
+                                          {
+#   if WIDE_CHAR_VERSION
+                                            *p++ = thousep[0];
+#   else
+                                            memcpy (p, thousep, thousep_len);
+                                            p += thousep_len;
+#   endif
+                                          }
+                                      }
+                                  }
                                 else
                                   *p++ = '0';
                                 /* Here ndigits <= precision.  */
@@ -5258,8 +5400,49 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
                                           {
                                             size_t ecount = exponent + 1;
                                             /* Note: count <= precision = ndigits.  */
-                                            for (; ecount > 0; ecount--)
-                                              *p++ = digits[--ndigits];
+
+                                            const DCHAR_T *thousep = NULL;
+                                            DCHAR_T thousep_buf[10];
+#   if !WIDE_CHAR_VERSION
+                                            size_t thousep_len;
+#   endif
+
+                                            if ((flags & FLAG_GROUP) && (ecount > 3))
+                                              {
+                                                /* Determine the thousands separator of the
+                                                   current locale.  */
+#   if WIDE_CHAR_VERSION
+                                                /* DCHAR_T is wchar_t.  */
+                                                thousep = thousands_separator_wchar (thousep_buf);
+#   else
+                                                /* DCHAR_T is char.  */
+                                                thousep = thousands_separator_char (thousep_buf);
+                                                thousep_len = strlen (thousep);
+#   endif
+                                                if (*thousep == 0)
+                                                  thousep = NULL;
+                                              }
+
+                                            if (ecount > 0)
+                                              for (;;)
+                                                {
+                                                  --ndigits;
+                                                  *p++ = digits[ndigits];
+                                                  if (--ecount == 0)
+                                                    break;
+                                                  if (thousep != NULL
+                                                      /* implies (flags & FLAG_GROUP) */
+                                                      && (ecount % 3) == 0)
+                                                    {
+#   if WIDE_CHAR_VERSION
+                                                      *p++ = thousep[0];
+#   else
+                                                      memcpy (p, thousep, thousep_len);
+                                                      p += thousep_len;
+#   endif
+                                                    }
+                                                }
+
                                             if ((flags & FLAG_ALT) || ndigits > nzeroes)
                                               {
                                                 *p++ = decimal_point_char ();
@@ -5460,12 +5643,49 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
                                 ndigits = strlen (digits);
 
                                 if (ndigits > precision)
-                                  do
-                                    {
-                                      --ndigits;
-                                      *p++ = digits[ndigits];
-                                    }
-                                  while (ndigits > precision);
+                                  {
+                                    const DCHAR_T *thousep = NULL;
+                                    DCHAR_T thousep_buf[10];
+#   if !WIDE_CHAR_VERSION
+                                    size_t thousep_len;
+#   endif
+
+                                    if ((flags & FLAG_GROUP)
+                                        && (ndigits - precision > 3))
+                                      {
+                                        /* Determine the thousands separator of the
+                                           current locale.  */
+#   if WIDE_CHAR_VERSION
+                                        /* DCHAR_T is wchar_t.  */
+                                        thousep = thousands_separator_wchar (thousep_buf);
+#   else
+                                        /* DCHAR_T is char.  */
+                                        thousep = thousands_separator_char (thousep_buf);
+                                        thousep_len = strlen (thousep);
+#   endif
+                                        if (*thousep == 0)
+                                          thousep = NULL;
+                                      }
+
+                                    for (;;)
+                                      {
+                                        --ndigits;
+                                        *p++ = digits[ndigits];
+                                        if (ndigits == precision)
+                                          break;
+                                        if (thousep != NULL
+                                            /* implies (flags & FLAG_GROUP) */
+                                            && ((ndigits - precision) % 3) == 0)
+                                          {
+#   if WIDE_CHAR_VERSION
+                                            *p++ = thousep[0];
+#   else
+                                            memcpy (p, thousep, thousep_len);
+                                            p += thousep_len;
+#   endif
+                                          }
+                                      }
+                                  }
                                 else
                                   *p++ = '0';
                                 /* Here ndigits <= precision.  */
@@ -5728,8 +5948,49 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
                                           {
                                             size_t ecount = exponent + 1;
                                             /* Note: ecount <= precision = ndigits.  */
-                                            for (; ecount > 0; ecount--)
-                                              *p++ = digits[--ndigits];
+
+                                            const DCHAR_T *thousep = NULL;
+                                            DCHAR_T thousep_buf[10];
+#   if !WIDE_CHAR_VERSION
+                                            size_t thousep_len;
+#   endif
+
+                                            if ((flags & FLAG_GROUP) && (ecount > 3))
+                                              {
+                                                /* Determine the thousands separator of the
+                                                   current locale.  */
+#   if WIDE_CHAR_VERSION
+                                                /* DCHAR_T is wchar_t.  */
+                                                thousep = thousands_separator_wchar (thousep_buf);
+#   else
+                                                /* DCHAR_T is char.  */
+                                                thousep = thousands_separator_char (thousep_buf);
+                                                thousep_len = strlen (thousep);
+#   endif
+                                                if (*thousep == 0)
+                                                  thousep = NULL;
+                                              }
+
+                                            if (ecount > 0)
+                                              for (;;)
+                                                {
+                                                  --ndigits;
+                                                  *p++ = digits[ndigits];
+                                                  if (--ecount == 0)
+                                                    break;
+                                                  if (thousep != NULL
+                                                      /* implies (flags & FLAG_GROUP) */
+                                                      && (ecount % 3) == 0)
+                                                    {
+#   if WIDE_CHAR_VERSION
+                                                      *p++ = thousep[0];
+#   else
+                                                      memcpy (p, thousep, thousep_len);
+                                                      p += thousep_len;
+#   endif
+                                                    }
+                                                }
+
                                             if ((flags & FLAG_ALT) || ndigits > nzeroes)
                                               {
                                                 *p++ = decimal_point_char ();
@@ -5937,13 +6198,13 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
               {
                 arg_type type = a.arg[dp->arg_index].type;
                 int flags = dp->flags;
-#if (WIDE_CHAR_VERSION && MUSL_LIBC) || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION
+#if (WIDE_CHAR_VERSION && MUSL_LIBC) || NEED_PRINTF_FLAG_LEFTADJUST || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION || NEED_PRINTF_FLAG_GROUPING || NEED_PRINTF_FLAG_GROUPING_INT
                 int has_width;
 #endif
-#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_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION
+#if !USE_SNPRINTF || WIDE_CHAR_VERSION || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || NEED_PRINTF_FLAG_LEFTADJUST || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION || NEED_PRINTF_FLAG_GROUPING || NEED_PRINTF_FLAG_GROUPING_INT
                 size_t width;
 #endif
-#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_FLAG_ALT_PRECISION_ZERO || 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) || NEED_PRINTF_FLAG_LEFTADJUST || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION || NEED_PRINTF_FLAG_GROUPING || NEED_PRINTF_FLAG_GROUPING_INT
                 int has_precision;
                 size_t precision;
 #endif
@@ -5952,9 +6213,14 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
 #else
 #               define prec_ourselves 0
 #endif
+#if NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION || NEED_PRINTF_FLAG_GROUPING || NEED_PRINTF_FLAG_GROUPING_INT
+                int group_ourselves;
+#else
+#               define group_ourselves 0
+#endif
 #if (WIDE_CHAR_VERSION && MUSL_LIBC) || NEED_PRINTF_FLAG_LEFTADJUST
 #               define pad_ourselves 1
-#elif !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION
+#elif !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION || NEED_PRINTF_FLAG_GROUPING || NEED_PRINTF_FLAG_GROUPING_INT
                 int pad_ourselves;
 #else
 #               define pad_ourselves 0
@@ -5969,10 +6235,10 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
                 TCHAR_T *tmp;
 #endif
 
-#if (WIDE_CHAR_VERSION && MUSL_LIBC) || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION
+#if (WIDE_CHAR_VERSION && MUSL_LIBC) || NEED_PRINTF_FLAG_LEFTADJUST || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION || NEED_PRINTF_FLAG_GROUPING || NEED_PRINTF_FLAG_GROUPING_INT
                 has_width = 0;
 #endif
-#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_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION
+#if !USE_SNPRINTF || WIDE_CHAR_VERSION || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || NEED_PRINTF_FLAG_LEFTADJUST || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION || NEED_PRINTF_FLAG_GROUPING || NEED_PRINTF_FLAG_GROUPING_INT
                 width = 0;
                 if (dp->width_start != dp->width_end)
                   {
@@ -6003,13 +6269,13 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
                     if (width > (size_t) INT_MAX)
                       goto overflow;
 # define WIDTH_IS_CHECKED 1
-# if (WIDE_CHAR_VERSION && MUSL_LIBC) || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION
+# if (WIDE_CHAR_VERSION && MUSL_LIBC) || NEED_PRINTF_FLAG_LEFTADJUST || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION || NEED_PRINTF_FLAG_GROUPING || NEED_PRINTF_FLAG_GROUPING_INT
                     has_width = 1;
 # endif
                   }
 #endif
 
-#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_FLAG_ALT_PRECISION_ZERO || 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) || NEED_PRINTF_FLAG_LEFTADJUST || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION || NEED_PRINTF_FLAG_GROUPING || NEED_PRINTF_FLAG_GROUPING_INT
                 has_precision = 0;
                 precision = 6;
                 if (dp->precision_start != dp->precision_end)
@@ -6074,8 +6340,37 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
                   }
 #endif
 
+                /* Decide whether to add the thousands separators ourselves.  */
+#if NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION || NEED_PRINTF_FLAG_GROUPING || NEED_PRINTF_FLAG_GROUPING_INT
+                if (flags & FLAG_GROUP)
+                  {
+                    switch (dp->conversion)
+                      {
+                      case 'd': case 'i': case 'u':
+# if NEED_PRINTF_FLAG_GROUPING || NEED_PRINTF_FLAG_GROUPING_INT
+                        group_ourselves = 1;
+# else
+                        group_ourselves = prec_ourselves;
+# endif
+                        break;
+                      case 'f': case 'F': case 'g': case 'G':
+# if NEED_PRINTF_FLAG_GROUPING
+                        group_ourselves = 1;
+# else
+                        group_ourselves = prec_ourselves;
+# endif
+                        break;
+                      default:
+                        group_ourselves = 0;
+                        break;
+                      }
+                  }
+                else
+                  group_ourselves = 0;
+#endif
+
                 /* Decide whether to perform the padding ourselves.  */
-#if !((WIDE_CHAR_VERSION && MUSL_LIBC) || NEED_PRINTF_FLAG_LEFTADJUST) && (!DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION)
+#if !((WIDE_CHAR_VERSION && MUSL_LIBC) || NEED_PRINTF_FLAG_LEFTADJUST) && (!DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION || NEED_PRINTF_FLAG_GROUPING || NEED_PRINTF_FLAG_GROUPING_INT)
                 switch (dp->conversion)
                   {
 # if !DCHAR_IS_TCHAR || ENABLE_UNISTDIO
@@ -6092,7 +6387,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
                     pad_ourselves = 1;
                     break;
                   default:
-                    pad_ourselves = prec_ourselves;
+                    pad_ourselves = prec_ourselves | group_ourselves;
                     break;
                   }
 #endif
@@ -6125,14 +6420,8 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
                    sprintf.  */
                 fbp = buf;
                 *fbp++ = '%';
-#if NEED_PRINTF_FLAG_GROUPING
-                /* The underlying implementation doesn't support the ' flag.
-                   Produce no grouping characters in this case; this is
-                   acceptable because the grouping is locale dependent.  */
-#else
-                if (flags & FLAG_GROUP)
+                if ((flags & FLAG_GROUP) && !group_ourselves)
                   *fbp++ = '\'';
-#endif
                 if (flags & FLAG_LEFT)
                   *fbp++ = '-';
                 if (flags & FLAG_SHOWSIGN)
@@ -6947,6 +7236,124 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
                       }
 #endif
 
+#if NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION || NEED_PRINTF_FLAG_GROUPING || NEED_PRINTF_FLAG_GROUPING_INT
+                    if (group_ourselves) /* implies (flags & FLAG_GROUP) */
+                      /* Handle the grouping.  */
+                      switch (dp->conversion)
+                        {
+                        /* These are the only conversion to which grouping
+                           applies.  */
+                        case 'd': case 'i': case 'u':
+                        case 'f': case 'F': case 'g': case 'G':
+                          {
+                            /* Determine the thousands separator of the current
+                               locale.  */
+                            const TCHAR_T *thousep;
+                            TCHAR_T thousep_buf[10];
+
+# if WIDE_CHAR_VERSION && DCHAR_IS_TCHAR
+                            /* TCHAR_T is wchar_t.  */
+                            thousep = thousands_separator_wchar (thousep_buf);
+# else
+                            /* TCHAR_T is char.  */
+                            thousep = thousands_separator_char (thousep_buf);
+# endif
+
+                            /* Nothing to do in locales where thousep is the empty
+                               string.  */
+                            if (*thousep != 0)
+                              {
+                                /* Since FLAG_LOCALIZED is only supported on glibc
+                                   systems, here we can assume that all digits are
+                                   the ASCII digits '0'..'9'.  */
+                                TCHAR_T *number_ptr =
+# if USE_SNPRINTF
+                                  (TCHAR_T *) (result + length);
+# else
+                                  tmp;
+# endif
+                                TCHAR_T *end_ptr = number_ptr + count;
+
+                                /* Find where the leading digits start.  */
+                                TCHAR_T *digits_ptr = number_ptr;
+                                if (count >= 1
+                                    && (*digits_ptr == '-' || *digits_ptr == '+'
+                                        || *digits_ptr == ' '))
+                                  digits_ptr++;
+
+                                /* Find where the leading digits end.  */
+                                TCHAR_T *digits_end_ptr;
+                                switch (dp->conversion)
+                                  {
+                                  case 'd': case 'i': case 'u':
+                                    digits_end_ptr = end_ptr;
+                                    break;
+                                  case 'f': case 'F': case 'g': case 'G':
+                                    {
+                                      TCHAR_T decimal_point = decimal_point_char ();
+                                      for (digits_end_ptr = digits_ptr;
+                                           digits_end_ptr < end_ptr;
+                                           digits_end_ptr++)
+                                        if (*digits_end_ptr == decimal_point
+                                            || *digits_end_ptr == 'e')
+                                          break;
+                                    }
+                                    break;
+                                  }
+
+                                /* Determine the number of thousands separators
+                                   to insert.  */
+                                size_t insert = digits_end_ptr - digits_ptr;
+                                insert = (insert > 0 ? (insert - 1) / 3 : 0);
+                                if (insert > 0)
+                                  {
+# if WIDE_CHAR_VERSION && DCHAR_IS_TCHAR
+#                                   define thousep_len 1
+# else
+                                    size_t thousep_len = strlen (thousep);
+# endif
+# if USE_SNPRINTF
+                                    size_t digits_offset = digits_ptr - number_ptr;
+                                    size_t digits_end_offset = digits_end_ptr - number_ptr;
+                                    size_t n =
+                                      xsum (length,
+                                            (count + insert * thousep_len + TCHARS_PER_DCHAR - 1)
+                                            / TCHARS_PER_DCHAR);
+                                    length += (count + TCHARS_PER_DCHAR - 1) / TCHARS_PER_DCHAR;
+                                    ENSURE_ALLOCATION (n);
+                                    length -= (count + TCHARS_PER_DCHAR - 1) / TCHARS_PER_DCHAR;
+                                    number_ptr = (TCHAR_T *) (result + length);
+                                    end_ptr = number_ptr + count;
+                                    digits_ptr = number_ptr + digits_offset;
+                                    digits_end_ptr = number_ptr + digits_end_offset;
+# endif
+
+                                    count += insert * thousep_len;
+
+                                    const TCHAR_T *p = end_ptr;
+                                    TCHAR_T *q = end_ptr + insert * thousep_len;
+                                    while (p > digits_end_ptr)
+                                      *--q = *--p;
+                                    for (; insert > 0; insert--)
+                                      {
+                                        *--q = *--p;
+                                        *--q = *--p;
+                                        *--q = *--p;
+# if WIDE_CHAR_VERSION && DCHAR_IS_TCHAR
+                                        *--q = *thousep;
+# else
+                                        q -= thousep_len;
+                                        memcpy (q, thousep, thousep_len);
+# endif
+                                      }
+                                    /* Here q == p.  Done with the insertions.  */
+                                  }
+                              }
+                          }
+                          break;
+                        }
+#endif
+
 #if !USE_SNPRINTF
                     if (count >= tmp_length)
                       /* tmp_length was incorrectly calculated - fix the
@@ -6957,6 +7364,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
 #if !DCHAR_IS_TCHAR
                     /* Convert from TCHAR_T[] to DCHAR_T[].  */
                     if (dp->conversion == 'c' || dp->conversion == 's'
+                        || (flags & FLAG_GROUP)
 # if __GLIBC__ >= 2 && !defined __UCLIBC__
                         || (flags & FLAG_LOCALIZED)
 # endif
@@ -7098,7 +7506,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
                     /* Here count <= allocated - length.  */
 
                     /* Perform padding.  */
-#if (WIDE_CHAR_VERSION && MUSL_LIBC) || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION
+#if (WIDE_CHAR_VERSION && MUSL_LIBC) || NEED_PRINTF_FLAG_LEFTADJUST || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION || NEED_PRINTF_FLAG_GROUPING || NEED_PRINTF_FLAG_GROUPING_INT
                     if (pad_ourselves && has_width)
                       {
                         size_t w;
index 37a54c3de5e4e8be9a1f5f46211abd046c98ae45..fa83b9a83ea8ea575ba6627d70c6a4faa79b9a01 100644 (file)
@@ -1,5 +1,5 @@
 # dprintf-posix.m4
-# serial 10
+# serial 11
 dnl Copyright (C) 2007-2025 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -33,6 +33,8 @@ AC_DEFUN([gl_FUNC_DPRINTF_IS_POSIX],
   AC_REQUIRE([gl_PRINTF_DIRECTIVE_LC])
   AC_REQUIRE([gl_PRINTF_POSITIONS])
   AC_REQUIRE([gl_PRINTF_FLAG_GROUPING])
+  AC_REQUIRE([gl_PRINTF_FLAG_GROUPING_INT_PRECISION])
+  AC_REQUIRE([gl_PRINTF_FLAG_GROUPING_MULTIBYTE])
   AC_REQUIRE([gl_PRINTF_FLAG_LEFTADJUST])
   AC_REQUIRE([gl_PRINTF_FLAG_ZERO])
   AC_REQUIRE([gl_PRINTF_FLAG_ALT_PRECISION_ZERO])
@@ -67,19 +69,27 @@ AC_DEFUN([gl_FUNC_DPRINTF_IS_POSIX],
                                                   *yes)
                                                     case "$gl_cv_func_printf_flag_grouping" in
                                                       *yes)
-                                                        case "$gl_cv_func_printf_flag_leftadjust" in
+                                                        case "$gl_cv_func_printf_flag_grouping_int_precision" in
                                                           *yes)
-                                                            case "$gl_cv_func_printf_flag_zero" in
+                                                            case "$gl_cv_func_printf_flag_grouping_multibyte" in
                                                               *yes)
-                                                                case "$gl_cv_func_printf_flag_alt_precision_zero" in
+                                                                case "$gl_cv_func_printf_flag_leftadjust" in
                                                                   *yes)
-                                                                    case "$gl_cv_func_printf_precision" in
+                                                                    case "$gl_cv_func_printf_flag_zero" in
                                                                       *yes)
-                                                                        case "$gl_cv_func_printf_enomem" in
+                                                                        case "$gl_cv_func_printf_flag_alt_precision_zero" in
                                                                           *yes)
-                                                                            # dprintf exists and is
-                                                                            # already POSIX compliant.
-                                                                            gl_cv_func_dprintf_posix=yes
+                                                                            case "$gl_cv_func_printf_precision" in
+                                                                              *yes)
+                                                                                case "$gl_cv_func_printf_enomem" in
+                                                                                  *yes)
+                                                                                    # dprintf exists and is
+                                                                                    # already POSIX compliant.
+                                                                                    gl_cv_func_dprintf_posix=yes
+                                                                                    ;;
+                                                                                esac
+                                                                                ;;
+                                                                            esac
                                                                             ;;
                                                                         esac
                                                                         ;;
index e6a149a0cf22bb14cdffb497bf98e4e9b5355a34..62116311dee34d2237f9c53fe85132dbd095ea5a 100644 (file)
@@ -1,5 +1,5 @@
 # fprintf-posix.m4
-# serial 21
+# serial 22
 dnl Copyright (C) 2007-2025 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -33,6 +33,8 @@ AC_DEFUN([gl_FUNC_FPRINTF_IS_POSIX],
   AC_REQUIRE([gl_PRINTF_DIRECTIVE_LC])
   AC_REQUIRE([gl_PRINTF_POSITIONS])
   AC_REQUIRE([gl_PRINTF_FLAG_GROUPING])
+  AC_REQUIRE([gl_PRINTF_FLAG_GROUPING_INT_PRECISION])
+  AC_REQUIRE([gl_PRINTF_FLAG_GROUPING_MULTIBYTE])
   AC_REQUIRE([gl_PRINTF_FLAG_LEFTADJUST])
   AC_REQUIRE([gl_PRINTF_FLAG_ZERO])
   AC_REQUIRE([gl_PRINTF_FLAG_ALT_PRECISION_ZERO])
@@ -65,19 +67,27 @@ AC_DEFUN([gl_FUNC_FPRINTF_IS_POSIX],
                                                 *yes)
                                                   case "$gl_cv_func_printf_flag_grouping" in
                                                     *yes)
-                                                      case "$gl_cv_func_printf_flag_leftadjust" in
+                                                      case "$gl_cv_func_printf_flag_grouping_int_precision" in
                                                         *yes)
-                                                          case "$gl_cv_func_printf_flag_zero" in
+                                                          case "$gl_cv_func_printf_flag_grouping_multibyte" in
                                                             *yes)
-                                                              case "$gl_cv_func_printf_flag_alt_precision_zero" in
+                                                              case "$gl_cv_func_printf_flag_leftadjust" in
                                                                 *yes)
-                                                                  case "$gl_cv_func_printf_precision" in
+                                                                  case "$gl_cv_func_printf_flag_zero" in
                                                                     *yes)
-                                                                      case "$gl_cv_func_printf_enomem" in
+                                                                      case "$gl_cv_func_printf_flag_alt_precision_zero" in
                                                                         *yes)
-                                                                          # fprintf exists and is
-                                                                          # already POSIX compliant.
-                                                                          gl_cv_func_fprintf_posix=yes
+                                                                          case "$gl_cv_func_printf_precision" in
+                                                                            *yes)
+                                                                              case "$gl_cv_func_printf_enomem" in
+                                                                                *yes)
+                                                                                  # fprintf exists and is
+                                                                                  # already POSIX compliant.
+                                                                                  gl_cv_func_fprintf_posix=yes
+                                                                                  ;;
+                                                                              esac
+                                                                              ;;
+                                                                          esac
                                                                           ;;
                                                                       esac
                                                                       ;;
index 288f88a2d92893cd74d4a1fa17fca1df72999f26..17494513e72174db40215dcb963c2d85af61e235 100644 (file)
@@ -1,5 +1,5 @@
 # obstack-printf-posix.m4
-# serial 11
+# serial 12
 dnl Copyright (C) 2008-2025 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -37,6 +37,8 @@ AC_DEFUN([gl_FUNC_OBSTACK_PRINTF_IS_POSIX],
   AC_REQUIRE([gl_PRINTF_DIRECTIVE_LC])
   AC_REQUIRE([gl_PRINTF_POSITIONS])
   AC_REQUIRE([gl_PRINTF_FLAG_GROUPING])
+  AC_REQUIRE([gl_PRINTF_FLAG_GROUPING_INT_PRECISION])
+  AC_REQUIRE([gl_PRINTF_FLAG_GROUPING_MULTIBYTE])
   AC_REQUIRE([gl_PRINTF_FLAG_LEFTADJUST])
   AC_REQUIRE([gl_PRINTF_FLAG_ZERO])
   AC_REQUIRE([gl_PRINTF_FLAG_ALT_PRECISION_ZERO])
@@ -71,19 +73,27 @@ AC_DEFUN([gl_FUNC_OBSTACK_PRINTF_IS_POSIX],
                                                   *yes)
                                                     case "$gl_cv_func_printf_flag_grouping" in
                                                       *yes)
-                                                        case "$gl_cv_func_printf_flag_leftadjust" in
+                                                        case "$gl_cv_func_printf_flag_grouping_int_precision" in
                                                           *yes)
-                                                            case "$gl_cv_func_printf_flag_zero" in
+                                                            case "$gl_cv_func_printf_flag_grouping_multibyte" in
                                                               *yes)
-                                                                case "$gl_cv_func_printf_flag_alt_precision_zero" in
+                                                                case "$gl_cv_func_printf_flag_leftadjust" in
                                                                   *yes)
-                                                                    case "$gl_cv_func_printf_precision" in
+                                                                    case "$gl_cv_func_printf_flag_zero" in
                                                                       *yes)
-                                                                        case "$gl_cv_func_printf_enomem" in
+                                                                        case "$gl_cv_func_printf_flag_alt_precision_zero" in
                                                                           *yes)
-                                                                            # obstack_printf exists and is
-                                                                            # already POSIX compliant.
-                                                                            gl_cv_func_obstack_printf_posix=yes
+                                                                            case "$gl_cv_func_printf_precision" in
+                                                                              *yes)
+                                                                                case "$gl_cv_func_printf_enomem" in
+                                                                                  *yes)
+                                                                                    # obstack_printf exists and is
+                                                                                    # already POSIX compliant.
+                                                                                    gl_cv_func_obstack_printf_posix=yes
+                                                                                    ;;
+                                                                                esac
+                                                                                ;;
+                                                                            esac
                                                                             ;;
                                                                         esac
                                                                         ;;
index 0bfd8eece9c58d30ee5aabbaaee5f8330ea59b4b..62319e4af38fa45722e4e8341b3a66b982a17cb7 100644 (file)
@@ -1,5 +1,5 @@
 # printf.m4
-# serial 95
+# serial 96
 dnl Copyright (C) 2003, 2007-2025 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -1186,6 +1186,112 @@ changequote([,])dnl
     ])
 ])
 
+dnl Test whether the *printf family of functions supports POSIX/XSI format
+dnl strings with the ' flag for grouping of decimal digits on integers,
+dnl together with a precision.
+dnl Result is gl_cv_func_printf_flag_grouping_int_precision.
+
+AC_DEFUN([gl_PRINTF_FLAG_GROUPING_INT_PRECISION],
+[
+  AC_REQUIRE([AC_PROG_CC])
+  AC_REQUIRE([AC_CANONICAL_HOST])
+  AC_CACHE_CHECK([whether printf supports grouping on integers with a precision],
+    [gl_cv_func_printf_flag_grouping_int_precision],
+    [
+      dnl Prepare a guess, used when cross-compiling or when specific locales
+      dnl are not available.
+      case "$host_os" in
+        # Guess no on FreeBSD, NetBSD, Solaris, Cygwin, Haiku.
+        freebsd* | dragonfly* | netbsd* | solaris* | cygwin* | haiku*)
+          gl_cv_func_printf_flag_grouping_int_precision="guessing no";;
+        *)
+          gl_cv_func_printf_flag_grouping_int_precision="guessing yes";;
+      esac
+      AC_RUN_IFELSE(
+        [AC_LANG_SOURCE([[
+#include <locale.h>
+#include <stdio.h>
+#include <string.h>
+static char buf[100];
+int main ()
+{
+  if (setlocale (LC_ALL, "fr_FR.UTF-8") != NULL
+      || setlocale (LC_ALL, "fr_FR") != NULL
+      || setlocale (LC_ALL, "fr_FR.ISO-8859-1") != NULL
+      || setlocale (LC_ALL, "fr_FR.ISO8859-1") != NULL)
+    {
+      if (sprintf (buf, "%'.10d", 1000) < 0)
+        return 1;
+      if (strlen (buf) == 10 && strcmp (buf, "0000001000") != 0)
+        /* The sprintf implementation has produced fewer than 10 digits.  */
+        return 2;
+      else
+        return 0;
+    }
+  return 3;
+}]])],
+        [gl_cv_func_printf_flag_grouping_int_precision=yes],
+        [if test $? = 2; then
+           gl_cv_func_printf_flag_grouping_int_precision=no
+         fi
+        ],
+        [:])
+    ])
+])
+
+dnl Test whether the *printf family of functions supports POSIX/XSI format
+dnl strings with the ' flag for grouping of decimal digits, when the thousands
+dnl separator is a multibyte character (such as U+00A0 or U+202F in a UTF-8
+dnl locale).
+dnl Result is gl_cv_func_printf_flag_grouping_multibyte.
+
+AC_DEFUN([gl_PRINTF_FLAG_GROUPING_MULTIBYTE],
+[
+  AC_REQUIRE([AC_PROG_CC])
+  AC_REQUIRE([AC_CANONICAL_HOST])
+  AC_CACHE_CHECK([whether printf supports grouping with a multibyte separator],
+    [gl_cv_func_printf_flag_grouping_multibyte],
+    [
+      dnl Prepare a guess, used when cross-compiling or when specific locales
+      dnl are not available.
+      case "$host_os" in
+        # Guess no on NetBSD and Solaris 11 OpenIndiana.
+        netbsd* | solaris*)
+          gl_cv_func_printf_flag_grouping_multibyte="guessing no";;
+        *)
+          gl_cv_func_printf_flag_grouping_multibyte="guessing yes";;
+      esac
+      AC_RUN_IFELSE(
+        [AC_LANG_SOURCE([[
+#include <locale.h>
+#include <stdio.h>
+#include <string.h>
+static char buf[100];
+int main ()
+{
+  if (setlocale (LC_ALL, "fr_FR.UTF-8") == NULL)
+    return 0;
+  if (sprintf (buf, "%'.0f", 1000.0) < 0)
+    return 1;
+  if (strlen (localeconv ()->thousands_sep) > 1)
+    {
+      if (strlen (buf) <= 4 + 1)
+        return 2;
+      else
+        return 3;
+    }
+  return 0;
+}]])],
+        [:],
+        [case $? in
+           2) gl_cv_func_printf_flag_grouping_multibyte=no ;;
+           3) gl_cv_func_printf_flag_grouping_multibyte=yes ;;
+         esac
+        ],
+        [:])
+    ])
+])
+
 dnl Test whether the *printf family of functions supports the - flag correctly.
 dnl (ISO C99.) See
 dnl <https://lists.gnu.org/r/bug-coreutils/2008-02/msg00035.html>
@@ -2161,20 +2267,22 @@ dnl 11 = gl_PRINTF_DIRECTIVE_LS
 dnl 12 = gl_PRINTF_DIRECTIVE_LC
 dnl 13 = gl_PRINTF_POSITIONS
 dnl 14 = gl_PRINTF_FLAG_GROUPING
-dnl 15 = gl_PRINTF_FLAG_LEFTADJUST
-dnl 16 = gl_PRINTF_FLAG_ZERO
-dnl 17 = gl_PRINTF_FLAG_ALT_PRECISION_ZERO
-dnl 18 = gl_PRINTF_PRECISION
-dnl 19 = gl_PRINTF_ENOMEM
-dnl 20 = gl_SNPRINTF_PRESENCE
-dnl 21 = gl_SNPRINTF_TRUNCATION_C99
-dnl 22 = gl_SNPRINTF_RETVAL_C99
-dnl 23 = gl_SNPRINTF_DIRECTIVE_N
-dnl 24 = gl_SNPRINTF_SIZE1
-dnl 25 = gl_VSNPRINTF_ZEROSIZE_C99
-dnl 26 = gl_SWPRINTF_WORKS
-dnl 27 = gl_SWPRINTF_DIRECTIVE_LA
-dnl 28 = gl_SWPRINTF_DIRECTIVE_LC
+dnl 15 = gl_PRINTF_FLAG_GROUPING_INT_PRECISION
+dnl 16 = gl_PRINTF_FLAG_GROUPING_MULTIBYTE
+dnl 17 = gl_PRINTF_FLAG_LEFTADJUST
+dnl 18 = gl_PRINTF_FLAG_ZERO
+dnl 19 = gl_PRINTF_FLAG_ALT_PRECISION_ZERO
+dnl 20 = gl_PRINTF_PRECISION
+dnl 21 = gl_PRINTF_ENOMEM
+dnl 22 = gl_SNPRINTF_PRESENCE
+dnl 23 = gl_SNPRINTF_TRUNCATION_C99
+dnl 24 = gl_SNPRINTF_RETVAL_C99
+dnl 25 = gl_SNPRINTF_DIRECTIVE_N
+dnl 26 = gl_SNPRINTF_SIZE1
+dnl 27 = gl_VSNPRINTF_ZEROSIZE_C99
+dnl 28 = gl_SWPRINTF_WORKS
+dnl 29 = gl_SWPRINTF_DIRECTIVE_LA
+dnl 30 = gl_SWPRINTF_DIRECTIVE_LC
 dnl
 dnl 1 = checking whether printf supports size specifiers as in C99...
 dnl 2 = checking whether printf supports size specifiers as in C23...
@@ -2190,62 +2298,64 @@ dnl 11 = checking whether printf supports the 'ls' directive...
 dnl 12 = checking whether printf supports the 'lc' directive correctly...
 dnl 13 = checking whether printf supports POSIX/XSI format strings with positions...
 dnl 14 = checking whether printf supports the grouping flag...
-dnl 15 = checking whether printf supports the left-adjust flag correctly...
-dnl 16 = checking whether printf supports the zero flag correctly...
-dnl 17 = checking whether printf supports the alternative flag with a zero precision...
-dnl 18 = checking whether printf supports large precisions...
-dnl 19 = checking whether printf survives out-of-memory conditions...
-dnl 20 = checking for snprintf...
-dnl 21 = checking whether snprintf truncates the result as in C99...
-dnl 22 = checking whether snprintf returns a byte count as in C99...
-dnl 23 = checking whether snprintf fully supports the 'n' directive...
-dnl 24 = checking whether snprintf respects a size of 1...
-dnl 25 = checking whether vsnprintf respects a zero size as in C99...
-dnl 26 = checking whether swprintf works...
-dnl 27 = checking whether swprintf supports the 'La' and 'LA' directives...
-dnl 28 = checking whether swprintf supports the 'lc' directive...
+dnl 15 = checking whether printf supports grouping on integers with a precision...
+dnl 16 = checking whether printf supports grouping with a multibyte separator...
+dnl 17 = checking whether printf supports the left-adjust flag correctly...
+dnl 18 = checking whether printf supports the zero flag correctly...
+dnl 19 = checking whether printf supports the alternative flag with a zero precision...
+dnl 20 = checking whether printf supports large precisions...
+dnl 21 = checking whether printf survives out-of-memory conditions...
+dnl 22 = checking for snprintf...
+dnl 23 = checking whether snprintf truncates the result as in C99...
+dnl 24 = checking whether snprintf returns a byte count as in C99...
+dnl 25 = checking whether snprintf fully supports the 'n' directive...
+dnl 26 = checking whether snprintf respects a size of 1...
+dnl 27 = checking whether vsnprintf respects a zero size as in C99...
+dnl 28 = checking whether swprintf works...
+dnl 29 = checking whether swprintf supports the 'La' and 'LA' directives...
+dnl 30 = checking whether swprintf supports the 'lc' directive...
 dnl
 dnl . = yes, # = no.
 dnl
-dnl                                  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
-dnl   musl libc 1.2.3                .  #  .  .  .  .  #  #  .  .  .  #  .  .  .  .  ?  .  .  .  .  .  .  .  .  #  .  #
-dnl   glibc 2.35                     .  #  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .
-dnl   glibc 2.5                      .  #  .  .  .  .  #  #  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  #  .
-dnl   glibc 2.3.6                    .  #  .  .  .  #  #  #  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  #  .
-dnl   FreeBSD 14.0                   .  .  .  .  .  #  .  .  .  .  .  .  .  .  .  .  .  .  #  .  .  .  .  .  .  #  .  #
-dnl   FreeBSD 13.0                   .  #  .  .  .  #  #  #  .  .  .  .  .  .  .  .  .  .  #  .  .  .  .  .  .  #  .  #
-dnl   FreeBSD 5.4, 6.1               .  #  .  .  .  #  #  #  .  .  .  .  .  .  .  #  ?  .  #  .  .  .  .  .  .  #  ?  ?
-dnl   Mac OS X 10.13.5               .  #  .  .  #  #  #  #  .  #  .  .  .  .  .  .  .  .  .  .  .  .  #  .  .  #  ?  ?
-dnl   Mac OS X 10.5.8                .  #  .  .  #  #  #  #  .  .  .  .  .  .  .  #  #  .  .  .  .  .  .  .  .  #  ?  ?
-dnl   Mac OS X 10.3.9                .  #  .  .  .  #  #  #  .  .  .  .  .  .  .  #  #  .  #  .  .  .  .  .  .  #  ?  ?
-dnl   OpenBSD 6.0, 6.7               .  #  .  .  .  #  #  #  .  .  .  .  .  .  .  .  .  .  #  .  .  .  .  .  .  #  .  #
-dnl   OpenBSD 3.9, 4.0               .  #  .  #  #  #  #  #  #  .  #  .  .  #  .  #  ?  .  #  .  .  .  .  .  .  #  ?  ?
-dnl   Cygwin 1.7.0 (2009)            .  #  .  .  #  .  #  #  .  .  ?  ?  .  .  .  .  ?  .  ?  .  .  .  .  .  .  ?  ?  ?
-dnl   Cygwin 1.5.25 (2008)           .  #  .  .  #  #  #  #  .  .  #  ?  .  .  .  .  ?  .  #  .  .  .  .  .  .  ?  ?  ?
-dnl   Cygwin 1.5.19 (2006)           #  #  .  .  #  #  #  #  #  .  #  ?  .  #  .  #  ?  #  #  .  .  .  .  .  .  ?  ?  ?
-dnl   Solaris 11.4                   .  #  .  #  #  #  #  #  .  .  #  .  .  .  .  #  .  .  .  .  .  .  .  .  .  .  #  .
-dnl   Solaris 11.3                   .  #  .  .  .  #  #  #  .  .  #  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  #  .
-dnl   Solaris 11.0                   .  #  .  #  #  #  #  #  .  .  #  .  .  .  .  #  .  .  .  .  .  .  .  .  .  ?  ?  ?
-dnl   Solaris 10                     .  #  .  #  #  #  #  #  .  .  #  .  .  .  .  #  .  #  .  .  .  .  .  .  .  .  #  .
-dnl   Solaris 2.6 ... 9              #  #  .  #  #  #  #  #  #  .  #  .  .  .  .  #  ?  #  .  .  .  #  .  .  .  ?  ?  ?
-dnl   Solaris 2.5.1                  #  #  .  #  #  #  #  #  #  .  #  .  .  .  .  #  ?  .  .  #  #  #  #  #  #  ?  ?  ?
-dnl   AIX 7.1                        .  #  .  #  #  #  #  #  .  .  .  .  .  .  .  #  .  #  .  .  .  .  .  .  .  #  .  .
-dnl   AIX 5.2                        .  #  .  #  #  #  #  #  .  .  .  .  .  .  .  #  ?  .  .  .  .  .  .  .  .  #  ?  ?
-dnl   AIX 4.3.2, 5.1                 #  #  .  #  #  #  #  #  #  .  .  .  .  .  .  #  ?  .  .  .  .  #  .  .  .  #  ?  ?
-dnl   HP-UX 11.31                    .  #  .  .  .  #  #  #  .  .  .  ?  .  .  .  #  ?  .  .  .  .  #  #  .  .  ?  ?  ?
-dnl   HP-UX 11.{00,11,23}            #  #  .  .  .  #  #  #  #  .  .  ?  .  .  .  #  ?  .  .  .  .  #  #  .  #  ?  ?  ?
-dnl   HP-UX 10.20                    #  #  .  #  .  #  #  #  #  .  ?  ?  .  .  #  #  ?  .  .  .  .  #  #  ?  #  ?  ?  ?
-dnl   IRIX 6.5                       #  #  .  #  #  #  #  #  #  .  #  .  .  .  .  #  ?  .  .  .  .  #  .  .  .  #  ?  ?
-dnl   OSF/1 5.1                      #  #  .  #  #  #  #  #  #  .  .  ?  .  .  .  #  ?  .  .  .  .  #  .  .  #  ?  ?  ?
-dnl   OSF/1 4.0d                     #  #  .  #  #  #  #  #  #  .  .  ?  .  .  .  #  ?  .  .  #  #  #  #  #  #  ?  ?  ?
-dnl   NetBSD 9.0                     .  #  .  .  .  #  #  #  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  #  .  #
-dnl   NetBSD 5.0                     .  #  .  .  #  #  #  #  .  .  .  .  .  .  .  #  ?  .  #  .  .  .  .  .  .  #  ?  ?
-dnl   NetBSD 4.0                     .  #  ?  ?  ?  ?  #  #  ?  .  ?  .  .  ?  ?  ?  ?  ?  ?  .  .  .  ?  ?  ?  #  ?  ?
-dnl   NetBSD 3.0                     .  #  .  .  .  #  #  #  #  .  ?  .  #  #  ?  #  ?  .  #  .  .  .  .  .  .  #  ?  ?
-dnl   Haiku                          .  #  .  .  #  #  #  #  #  .  #  ?  .  .  .  .  ?  .  ?  .  .  ?  .  .  .  .  #  .
-dnl   BeOS                           #  #  #  .  #  #  #  #  #  .  ?  ?  #  .  ?  .  ?  #  ?  .  .  ?  .  .  .  ?  ?  ?
-dnl   Android 4.3                    .  #  .  #  #  #  #  #  #  #  #  ?  .  #  .  #  ?  .  #  .  .  .  #  .  .  ?  ?  ?
-dnl   old mingw / msvcrt             #  #  #  #  #  #  #  #  #  .  .  ?  #  #  .  #  ?  #  ?  .  #  #  #  .  .  #  ?  ?
-dnl   MSVC 9                         #  #  #  #  #  #  #  #  #  #  .  ?  #  #  .  #  ?  #  ?  #  #  #  #  .  .  #  ?  ?
-dnl   mingw 2009-2011                .  #  #  .  #  .  #  #  .  .  .  ?  #  #  .  .  ?  .  ?  .  .  .  .  .  .  #  ?  ?
-dnl   mingw-w64 2011                 #  #  #  #  #  #  #  #  #  .  .  ?  #  #  .  #  ?  #  ?  .  #  #  #  .  .  #  ?  ?
+dnl                                  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
+dnl   musl libc 1.2.3                .  #  .  .  .  .  #  #  .  .  .  #  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  #  .  #
+dnl   glibc 2.35                     .  #  .  .  .  .  .  .  .  .  .  .  .  .  #  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .
+dnl   glibc 2.5                      .  #  .  .  .  .  #  #  .  .  .  .  .  .  #  .  .  .  .  .  .  .  .  .  .  .  .  .  #  .
+dnl   glibc 2.3.6                    .  #  .  .  .  #  #  #  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  #  .
+dnl   FreeBSD 14.0                   .  .  .  .  .  #  .  .  .  .  .  .  .  .  #  .  .  .  .  .  #  .  .  .  .  .  .  #  .  #
+dnl   FreeBSD 13.0                   .  #  .  .  .  #  #  #  .  .  .  .  .  .  #  .  .  .  .  .  #  .  .  .  .  .  .  #  .  #
+dnl   FreeBSD 5.4, 6.1               .  #  .  .  .  #  #  #  .  .  .  .  .  .  .  .  .  #  ?  .  #  .  .  .  .  .  .  #  ?  ?
+dnl   Mac OS X 10.13.5               .  #  .  .  #  #  #  #  .  #  .  .  .  .  ?  ?  .  .  .  .  .  .  .  .  #  .  .  #  ?  ?
+dnl   Mac OS X 10.5.8                .  #  .  .  #  #  #  #  .  .  .  .  .  .  ?  ?  .  #  #  .  .  .  .  .  .  .  .  #  ?  ?
+dnl   Mac OS X 10.3.9                .  #  .  .  .  #  #  #  .  .  .  .  .  .  ?  ?  .  #  #  .  #  .  .  .  .  .  .  #  ?  ?
+dnl   OpenBSD 6.0, 6.7               .  #  .  .  .  #  #  #  .  .  .  .  .  .  .  .  .  .  .  .  #  .  .  .  .  .  .  #  .  #
+dnl   OpenBSD 3.9, 4.0               .  #  .  #  #  #  #  #  #  .  #  .  .  #  ?  ?  .  #  ?  .  #  .  .  .  .  .  .  #  ?  ?
+dnl   Cygwin 1.7.0 (2009)            .  #  .  .  #  .  #  #  .  .  ?  ?  .  .  ?  ?  .  .  ?  .  ?  .  .  .  .  .  .  ?  ?  ?
+dnl   Cygwin 1.5.25 (2008)           .  #  .  .  #  #  #  #  .  .  #  ?  .  .  ?  ?  .  .  ?  .  #  .  .  .  .  .  .  ?  ?  ?
+dnl   Cygwin 1.5.19 (2006)           #  #  .  .  #  #  #  #  #  .  #  ?  .  #  ?  ?  .  #  ?  #  #  .  .  .  .  .  .  ?  ?  ?
+dnl   Solaris 11.4                   .  #  .  #  #  #  #  #  .  .  #  .  .  .  #  #  .  #  .  .  .  .  .  .  .  .  .  .  #  .
+dnl   Solaris 11.3                   .  #  .  .  .  #  #  #  .  .  #  .  .  .  ?  ?  .  .  .  .  .  .  .  .  .  .  .  .  #  .
+dnl   Solaris 11.0                   .  #  .  #  #  #  #  #  .  .  #  .  .  .  ?  ?  .  #  .  .  .  .  .  .  .  .  .  ?  ?  ?
+dnl   Solaris 10                     .  #  .  #  #  #  #  #  .  .  #  .  .  .  ?  ?  .  #  .  #  .  .  .  .  .  .  .  .  #  .
+dnl   Solaris 2.6 ... 9              #  #  .  #  #  #  #  #  #  .  #  .  .  .  ?  ?  .  #  ?  #  .  .  .  #  .  .  .  ?  ?  ?
+dnl   Solaris 2.5.1                  #  #  .  #  #  #  #  #  #  .  #  .  .  .  ?  ?  .  #  ?  .  .  #  #  #  #  #  #  ?  ?  ?
+dnl   AIX 7.1                        .  #  .  #  #  #  #  #  .  .  .  .  .  .  ?  ?  .  #  .  #  .  .  .  .  .  .  .  #  .  .
+dnl   AIX 5.2                        .  #  .  #  #  #  #  #  .  .  .  .  .  .  ?  ?  .  #  ?  .  .  .  .  .  .  .  .  #  ?  ?
+dnl   AIX 4.3.2, 5.1                 #  #  .  #  #  #  #  #  #  .  .  .  .  .  ?  ?  .  #  ?  .  .  .  .  #  .  .  .  #  ?  ?
+dnl   HP-UX 11.31                    .  #  .  .  .  #  #  #  .  .  .  ?  .  .  ?  ?  .  #  ?  .  .  .  .  #  #  .  .  ?  ?  ?
+dnl   HP-UX 11.{00,11,23}            #  #  .  .  .  #  #  #  #  .  .  ?  .  .  ?  ?  .  #  ?  .  .  .  .  #  #  .  #  ?  ?  ?
+dnl   HP-UX 10.20                    #  #  .  #  .  #  #  #  #  .  ?  ?  .  .  ?  ?  #  #  ?  .  .  .  .  #  #  ?  #  ?  ?  ?
+dnl   IRIX 6.5                       #  #  .  #  #  #  #  #  #  .  #  .  .  .  ?  ?  .  #  ?  .  .  .  .  #  .  .  .  #  ?  ?
+dnl   OSF/1 5.1                      #  #  .  #  #  #  #  #  #  .  .  ?  .  .  ?  ?  .  #  ?  .  .  .  .  #  .  .  #  ?  ?  ?
+dnl   OSF/1 4.0d                     #  #  .  #  #  #  #  #  #  .  .  ?  .  .  ?  ?  .  #  ?  .  .  #  #  #  #  #  #  ?  ?  ?
+dnl   NetBSD 9.0                     .  #  .  .  .  #  #  #  .  .  .  .  .  .  #  #  .  .  .  .  .  .  .  .  .  .  .  #  .  #
+dnl   NetBSD 5.0                     .  #  .  .  #  #  #  #  .  .  .  .  .  .  ?  ?  .  #  ?  .  #  .  .  .  .  .  .  #  ?  ?
+dnl   NetBSD 4.0                     .  #  ?  ?  ?  ?  #  #  ?  .  ?  .  .  ?  ?  ?  ?  ?  ?  ?  ?  .  .  .  ?  ?  ?  #  ?  ?
+dnl   NetBSD 3.0                     .  #  .  .  .  #  #  #  #  .  ?  .  #  #  ?  ?  ?  #  ?  .  #  .  .  .  .  .  .  #  ?  ?
+dnl   Haiku                          .  #  .  .  #  #  #  #  #  .  #  ?  .  .  #  .  .  .  ?  .  ?  .  .  ?  .  .  .  .  #  .
+dnl   BeOS                           #  #  #  .  #  #  #  #  #  .  ?  ?  #  .  ?  ?  ?  .  ?  #  ?  .  .  ?  .  .  .  ?  ?  ?
+dnl   Android 4.3                    .  #  .  #  #  #  #  #  #  #  #  ?  .  #  ?  ?  .  #  ?  .  #  .  .  .  #  .  .  ?  ?  ?
+dnl   old mingw / msvcrt             #  #  #  #  #  #  #  #  #  .  .  ?  #  #  ?  ?  .  #  ?  #  ?  .  #  #  #  .  .  #  ?  ?
+dnl   MSVC 9                         #  #  #  #  #  #  #  #  #  #  .  ?  #  #  ?  ?  .  #  ?  #  ?  #  #  #  #  .  .  #  ?  ?
+dnl   mingw 2009-2011                .  #  #  .  #  .  #  #  .  .  .  ?  #  #  ?  ?  .  .  ?  .  ?  .  .  .  .  .  .  #  ?  ?
+dnl   mingw-w64 2011                 #  #  #  #  #  #  #  #  #  .  .  ?  #  #  ?  ?  .  #  ?  #  ?  .  #  #  #  .  .  #  ?  ?
index b8d238b6379b2bd10cc26fa4a7d1bb0dcd37b7fa..4794cc3ae26bb9f3c851aadfa1263968c88e488e 100644 (file)
@@ -1,5 +1,5 @@
 # snprintf-posix.m4
-# serial 22
+# serial 23
 dnl Copyright (C) 2007-2025 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -33,6 +33,8 @@ AC_DEFUN([gl_FUNC_SNPRINTF_IS_POSIX],
   AC_REQUIRE([gl_PRINTF_DIRECTIVE_LC])
   AC_REQUIRE([gl_PRINTF_POSITIONS])
   AC_REQUIRE([gl_PRINTF_FLAG_GROUPING])
+  AC_REQUIRE([gl_PRINTF_FLAG_GROUPING_INT_PRECISION])
+  AC_REQUIRE([gl_PRINTF_FLAG_GROUPING_MULTIBYTE])
   AC_REQUIRE([gl_PRINTF_FLAG_LEFTADJUST])
   AC_REQUIRE([gl_PRINTF_FLAG_ZERO])
   AC_REQUIRE([gl_PRINTF_FLAG_ALT_PRECISION_ZERO])
@@ -72,29 +74,37 @@ AC_DEFUN([gl_FUNC_SNPRINTF_IS_POSIX],
                                                   *yes)
                                                     case "$gl_cv_func_printf_flag_grouping" in
                                                       *yes)
-                                                        case "$gl_cv_func_printf_flag_leftadjust" in
+                                                        case "$gl_cv_func_printf_flag_grouping_int_precision" in
                                                           *yes)
-                                                            case "$gl_cv_func_printf_flag_zero" in
+                                                            case "$gl_cv_func_printf_flag_grouping_multibyte" in
                                                               *yes)
-                                                                case "$gl_cv_func_printf_flag_alt_precision_zero" in
+                                                                case "$gl_cv_func_printf_flag_leftadjust" in
                                                                   *yes)
-                                                                    case "$gl_cv_func_printf_precision" in
+                                                                    case "$gl_cv_func_printf_flag_zero" in
                                                                       *yes)
-                                                                        case "$gl_cv_func_printf_enomem" in
+                                                                        case "$gl_cv_func_printf_flag_alt_precision_zero" in
                                                                           *yes)
-                                                                            case "$gl_cv_func_snprintf_truncation_c99" in
+                                                                            case "$gl_cv_func_printf_precision" in
                                                                               *yes)
-                                                                                case "$gl_cv_func_snprintf_retval_c99" in
+                                                                                case "$gl_cv_func_printf_enomem" in
                                                                                   *yes)
-                                                                                    case m4_ifdef([gl_PRINTF_SUPPORT_N_DIRECTIVE],["$gl_cv_func_snprintf_directive_n"],["yes"]) in
+                                                                                    case "$gl_cv_func_snprintf_truncation_c99" in
                                                                                       *yes)
-                                                                                        case "$gl_cv_func_snprintf_size1" in
+                                                                                        case "$gl_cv_func_snprintf_retval_c99" in
                                                                                           *yes)
-                                                                                            case "$gl_cv_func_vsnprintf_zerosize_c99" in
+                                                                                            case m4_ifdef([gl_PRINTF_SUPPORT_N_DIRECTIVE],["$gl_cv_func_snprintf_directive_n"],["yes"]) in
                                                                                               *yes)
-                                                                                                # snprintf exists and is
-                                                                                                # already POSIX compliant.
-                                                                                                gl_cv_func_snprintf_posix=yes
+                                                                                                case "$gl_cv_func_snprintf_size1" in
+                                                                                                  *yes)
+                                                                                                    case "$gl_cv_func_vsnprintf_zerosize_c99" in
+                                                                                                      *yes)
+                                                                                                        # snprintf exists and is
+                                                                                                        # already POSIX compliant.
+                                                                                                        gl_cv_func_snprintf_posix=yes
+                                                                                                        ;;
+                                                                                                    esac
+                                                                                                    ;;
+                                                                                                esac
                                                                                                 ;;
                                                                                             esac
                                                                                             ;;
index fe07f061fa9bf5603645590dff3cd31ebe0bb528..1bd9f9cbf16b8fa24f5a9b4b54d2a67ec5c21937 100644 (file)
@@ -1,5 +1,5 @@
 # sprintf-posix.m4
-# serial 19
+# serial 20
 dnl Copyright (C) 2007-2025 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -33,6 +33,8 @@ AC_DEFUN([gl_FUNC_SPRINTF_IS_POSIX],
   AC_REQUIRE([gl_PRINTF_DIRECTIVE_LC])
   AC_REQUIRE([gl_PRINTF_POSITIONS])
   AC_REQUIRE([gl_PRINTF_FLAG_GROUPING])
+  AC_REQUIRE([gl_PRINTF_FLAG_GROUPING_INT_PRECISION])
+  AC_REQUIRE([gl_PRINTF_FLAG_GROUPING_MULTIBYTE])
   AC_REQUIRE([gl_PRINTF_FLAG_LEFTADJUST])
   AC_REQUIRE([gl_PRINTF_FLAG_ZERO])
   AC_REQUIRE([gl_PRINTF_FLAG_ALT_PRECISION_ZERO])
@@ -65,19 +67,27 @@ AC_DEFUN([gl_FUNC_SPRINTF_IS_POSIX],
                                                 *yes)
                                                   case "$gl_cv_func_printf_flag_grouping" in
                                                     *yes)
-                                                      case "$gl_cv_func_printf_flag_leftadjust" in
+                                                      case "$gl_cv_func_printf_flag_grouping_int_precision" in
                                                         *yes)
-                                                          case "$gl_cv_func_printf_flag_zero" in
+                                                          case "$gl_cv_func_printf_flag_grouping_multibyte" in
                                                             *yes)
-                                                              case "$gl_cv_func_printf_flag_alt_precision_zero" in
+                                                              case "$gl_cv_func_printf_flag_leftadjust" in
                                                                 *yes)
-                                                                  case "$gl_cv_func_printf_precision" in
+                                                                  case "$gl_cv_func_printf_flag_zero" in
                                                                     *yes)
-                                                                      case "$gl_cv_func_printf_enomem" in
+                                                                      case "$gl_cv_func_printf_flag_alt_precision_zero" in
                                                                         *yes)
-                                                                          # sprintf exists and is
-                                                                          # already POSIX compliant.
-                                                                          gl_cv_func_sprintf_posix=yes
+                                                                          case "$gl_cv_func_printf_precision" in
+                                                                            *yes)
+                                                                              case "$gl_cv_func_printf_enomem" in
+                                                                                *yes)
+                                                                                  # sprintf exists and is
+                                                                                  # already POSIX compliant.
+                                                                                  gl_cv_func_sprintf_posix=yes
+                                                                                  ;;
+                                                                              esac
+                                                                              ;;
+                                                                          esac
                                                                           ;;
                                                                       esac
                                                                       ;;
index ba8a1520100452430e0c0f0cd000cb33f1ab1994..ae073fda3714dfd988d8acfac56dca516c050c6f 100644 (file)
@@ -1,5 +1,5 @@
 # vasnprintf-posix.m4
-# serial 20
+# serial 21
 dnl Copyright (C) 2007-2025 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -32,6 +32,8 @@ AC_DEFUN_ONCE([gl_FUNC_VASNPRINTF_IS_POSIX],
   AC_REQUIRE([gl_PRINTF_DIRECTIVE_LC])
   AC_REQUIRE([gl_PRINTF_POSITIONS])
   AC_REQUIRE([gl_PRINTF_FLAG_GROUPING])
+  AC_REQUIRE([gl_PRINTF_FLAG_GROUPING_INT_PRECISION])
+  AC_REQUIRE([gl_PRINTF_FLAG_GROUPING_MULTIBYTE])
   AC_REQUIRE([gl_PRINTF_FLAG_LEFTADJUST])
   AC_REQUIRE([gl_PRINTF_FLAG_ZERO])
   AC_REQUIRE([gl_PRINTF_FLAG_ALT_PRECISION_ZERO])
@@ -65,21 +67,29 @@ AC_DEFUN_ONCE([gl_FUNC_VASNPRINTF_IS_POSIX],
                                                 *yes)
                                                   case "$gl_cv_func_printf_flag_grouping" in
                                                     *yes)
-                                                      case "$gl_cv_func_printf_flag_leftadjust" in
+                                                      case "$gl_cv_func_printf_flag_grouping_int_precision" in
                                                         *yes)
-                                                          case "$gl_cv_func_printf_flag_zero" in
+                                                          case "$gl_cv_func_printf_flag_grouping_multibyte" in
                                                             *yes)
-                                                              case "$gl_cv_func_printf_flag_alt_precision_zero" in
+                                                              case "$gl_cv_func_printf_flag_leftadjust" in
                                                                 *yes)
-                                                                  case "$gl_cv_func_printf_precision" in
+                                                                  case "$gl_cv_func_printf_flag_zero" in
                                                                     *yes)
-                                                                      case "$gl_cv_func_printf_enomem" in
+                                                                      case "$gl_cv_func_printf_flag_alt_precision_zero" in
                                                                         *yes)
-                                                                          if test $ac_cv_func_vasnprintf = yes; then
-                                                                            # vasnprintf exists and is
-                                                                            # already POSIX compliant.
-                                                                            gl_cv_func_vasnprintf_posix=yes
-                                                                          fi
+                                                                          case "$gl_cv_func_printf_precision" in
+                                                                            *yes)
+                                                                              case "$gl_cv_func_printf_enomem" in
+                                                                                *yes)
+                                                                                  if test $ac_cv_func_vasnprintf = yes; then
+                                                                                    # vasnprintf exists and is
+                                                                                    # already POSIX compliant.
+                                                                                    gl_cv_func_vasnprintf_posix=yes
+                                                                                  fi
+                                                                                  ;;
+                                                                              esac
+                                                                              ;;
+                                                                          esac
                                                                           ;;
                                                                       esac
                                                                       ;;
index ab1b871eda82ed698165e94cb19c44a1e4b082ad..35fdbc5e9417278cccde9601a8dd4bb6f36b1854 100644 (file)
@@ -1,5 +1,5 @@
 # vasnprintf.m4
-# serial 54
+# serial 55
 dnl Copyright (C) 2002-2004, 2006-2025 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -358,8 +358,19 @@ AC_DEFUN([gl_PREREQ_VASNPRINTF_DIRECTIVE_LC],
 AC_DEFUN([gl_PREREQ_VASNPRINTF_FLAG_GROUPING],
 [
   AC_REQUIRE([gl_PRINTF_FLAG_GROUPING])
-  case "$gl_cv_func_printf_flag_grouping" in
-    *yes)
+  AC_REQUIRE([gl_PRINTF_FLAG_GROUPING_INT_PRECISION])
+  AC_REQUIRE([gl_PRINTF_FLAG_GROUPING_MULTIBYTE])
+  case "$gl_cv_func_printf_flag_grouping,$gl_cv_func_printf_flag_grouping_multibyte" in
+    *yes,*yes)
+      case "$gl_cv_func_printf_flag_grouping_int_precision" in
+        *yes)
+          ;;
+        *)
+          AC_DEFINE([NEED_PRINTF_FLAG_GROUPING_INT], [1],
+            [Define if the vasnprintf implementation needs special code for the
+             ' flag, for integer directives only.])
+          ;;
+      esac
       ;;
     *)
       AC_DEFINE([NEED_PRINTF_FLAG_GROUPING], [1],
index edd5832fd0b193da837712eebbf416d34acc6ede..692729c66ff896d62c4b22364c5a555bf4aa9812 100644 (file)
@@ -1,5 +1,5 @@
 # vasprintf-posix.m4
-# serial 20
+# serial 21
 dnl Copyright (C) 2007-2025 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -33,6 +33,8 @@ AC_DEFUN([gl_FUNC_VASPRINTF_IS_POSIX],
   AC_REQUIRE([gl_PRINTF_DIRECTIVE_LC])
   AC_REQUIRE([gl_PRINTF_POSITIONS])
   AC_REQUIRE([gl_PRINTF_FLAG_GROUPING])
+  AC_REQUIRE([gl_PRINTF_FLAG_GROUPING_INT_PRECISION])
+  AC_REQUIRE([gl_PRINTF_FLAG_GROUPING_MULTIBYTE])
   AC_REQUIRE([gl_PRINTF_FLAG_LEFTADJUST])
   AC_REQUIRE([gl_PRINTF_FLAG_ZERO])
   AC_REQUIRE([gl_PRINTF_FLAG_ALT_PRECISION_ZERO])
@@ -66,21 +68,29 @@ AC_DEFUN([gl_FUNC_VASPRINTF_IS_POSIX],
                                                 *yes)
                                                   case "$gl_cv_func_printf_flag_grouping" in
                                                     *yes)
-                                                      case "$gl_cv_func_printf_flag_leftadjust" in
+                                                      case "$gl_cv_func_printf_flag_grouping_int_precision" in
                                                         *yes)
-                                                          case "$gl_cv_func_printf_flag_zero" in
+                                                          case "$gl_cv_func_printf_flag_grouping_multibyte" in
                                                             *yes)
-                                                              case "$gl_cv_func_printf_flag_alt_precision_zero" in
+                                                              case "$gl_cv_func_printf_flag_leftadjust" in
                                                                 *yes)
-                                                                  case "$gl_cv_func_printf_precision" in
+                                                                  case "$gl_cv_func_printf_flag_zero" in
                                                                     *yes)
-                                                                      case "$gl_cv_func_printf_enomem" in
+                                                                      case "$gl_cv_func_printf_flag_alt_precision_zero" in
                                                                         *yes)
-                                                                          if test $ac_cv_func_vasprintf = yes; then
-                                                                            # vasprintf exists and is
-                                                                            # already POSIX compliant.
-                                                                            gl_cv_func_vasprintf_posix=yes
-                                                                          fi
+                                                                          case "$gl_cv_func_printf_precision" in
+                                                                            *yes)
+                                                                              case "$gl_cv_func_printf_enomem" in
+                                                                                *yes)
+                                                                                  if test $ac_cv_func_vasprintf = yes; then
+                                                                                    # vasprintf exists and is
+                                                                                    # already POSIX compliant.
+                                                                                    gl_cv_func_vasprintf_posix=yes
+                                                                                  fi
+                                                                                  ;;
+                                                                              esac
+                                                                              ;;
+                                                                          esac
                                                                           ;;
                                                                       esac
                                                                       ;;
index ceec8523e5192fb6eef5d06a146de3868ab6099f..063bbf5ebc7120cc00961183cb1f3314f0737c4c 100644 (file)
@@ -1,5 +1,5 @@
 # vdprintf-posix.m4
-# serial 10
+# serial 11
 dnl Copyright (C) 2007-2025 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -33,6 +33,8 @@ AC_DEFUN([gl_FUNC_VDPRINTF_IS_POSIX],
   AC_REQUIRE([gl_PRINTF_DIRECTIVE_LC])
   AC_REQUIRE([gl_PRINTF_POSITIONS])
   AC_REQUIRE([gl_PRINTF_FLAG_GROUPING])
+  AC_REQUIRE([gl_PRINTF_FLAG_GROUPING_INT_PRECISION])
+  AC_REQUIRE([gl_PRINTF_FLAG_GROUPING_MULTIBYTE])
   AC_REQUIRE([gl_PRINTF_FLAG_LEFTADJUST])
   AC_REQUIRE([gl_PRINTF_FLAG_ZERO])
   AC_REQUIRE([gl_PRINTF_FLAG_ALT_PRECISION_ZERO])
@@ -67,19 +69,27 @@ AC_DEFUN([gl_FUNC_VDPRINTF_IS_POSIX],
                                                   *yes)
                                                     case "$gl_cv_func_printf_flag_grouping" in
                                                       *yes)
-                                                        case "$gl_cv_func_printf_flag_leftadjust" in
+                                                        case "$gl_cv_func_printf_flag_grouping_int_precision" in
                                                           *yes)
-                                                            case "$gl_cv_func_printf_flag_zero" in
+                                                            case "$gl_cv_func_printf_flag_grouping_multibyte" in
                                                               *yes)
-                                                                case "$gl_cv_func_printf_flag_alt_precision_zero" in
+                                                                case "$gl_cv_func_printf_flag_leftadjust" in
                                                                   *yes)
-                                                                    case "$gl_cv_func_printf_precision" in
+                                                                    case "$gl_cv_func_printf_flag_zero" in
                                                                       *yes)
-                                                                        case "$gl_cv_func_printf_enomem" in
+                                                                        case "$gl_cv_func_printf_flag_alt_precision_zero" in
                                                                           *yes)
-                                                                            # vdprintf exists and is
-                                                                            # already POSIX compliant.
-                                                                            gl_cv_func_vdprintf_posix=yes
+                                                                            case "$gl_cv_func_printf_precision" in
+                                                                              *yes)
+                                                                                case "$gl_cv_func_printf_enomem" in
+                                                                                  *yes)
+                                                                                    # vdprintf exists and is
+                                                                                    # already POSIX compliant.
+                                                                                    gl_cv_func_vdprintf_posix=yes
+                                                                                    ;;
+                                                                                esac
+                                                                                ;;
+                                                                            esac
                                                                             ;;
                                                                         esac
                                                                         ;;
index 6d9ed3a18a85de103ef88391a66440fe9a20e654..083cb42e9cb484e02162efcb95582521f2027e44 100644 (file)
@@ -1,5 +1,5 @@
 # vfprintf-posix.m4
-# serial 21
+# serial 22
 dnl Copyright (C) 2007-2025 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -33,6 +33,8 @@ AC_DEFUN([gl_FUNC_VFPRINTF_IS_POSIX],
   AC_REQUIRE([gl_PRINTF_DIRECTIVE_LC])
   AC_REQUIRE([gl_PRINTF_POSITIONS])
   AC_REQUIRE([gl_PRINTF_FLAG_GROUPING])
+  AC_REQUIRE([gl_PRINTF_FLAG_GROUPING_INT_PRECISION])
+  AC_REQUIRE([gl_PRINTF_FLAG_GROUPING_MULTIBYTE])
   AC_REQUIRE([gl_PRINTF_FLAG_LEFTADJUST])
   AC_REQUIRE([gl_PRINTF_FLAG_ZERO])
   AC_REQUIRE([gl_PRINTF_FLAG_ALT_PRECISION_ZERO])
@@ -65,19 +67,27 @@ AC_DEFUN([gl_FUNC_VFPRINTF_IS_POSIX],
                                                 *yes)
                                                   case "$gl_cv_func_printf_flag_grouping" in
                                                     *yes)
-                                                      case "$gl_cv_func_printf_flag_leftadjust" in
+                                                      case "$gl_cv_func_printf_flag_grouping_int_precision" in
                                                         *yes)
-                                                          case "$gl_cv_func_printf_flag_zero" in
+                                                          case "$gl_cv_func_printf_flag_grouping_multibyte" in
                                                             *yes)
-                                                              case "$gl_cv_func_printf_flag_alt_precision_zero" in
+                                                              case "$gl_cv_func_printf_flag_leftadjust" in
                                                                 *yes)
-                                                                  case "$gl_cv_func_printf_precision" in
+                                                                  case "$gl_cv_func_printf_flag_zero" in
                                                                     *yes)
-                                                                      case "$gl_cv_func_printf_enomem" in
+                                                                      case "$gl_cv_func_printf_flag_alt_precision_zero" in
                                                                         *yes)
-                                                                          # vfprintf exists and is
-                                                                          # already POSIX compliant.
-                                                                          gl_cv_func_vfprintf_posix=yes
+                                                                          case "$gl_cv_func_printf_precision" in
+                                                                            *yes)
+                                                                              case "$gl_cv_func_printf_enomem" in
+                                                                                *yes)
+                                                                                  # vfprintf exists and is
+                                                                                  # already POSIX compliant.
+                                                                                  gl_cv_func_vfprintf_posix=yes
+                                                                                  ;;
+                                                                              esac
+                                                                              ;;
+                                                                          esac
                                                                           ;;
                                                                       esac
                                                                       ;;
index c01c4c462f92f842fd5d4dbc390406ba0ac0be49..405fa19b696438369bc5d2fd815ba73faaabdd3f 100644 (file)
@@ -1,5 +1,5 @@
 # vsnprintf-posix.m4
-# serial 23
+# serial 24
 dnl Copyright (C) 2007-2025 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -33,6 +33,8 @@ AC_DEFUN([gl_FUNC_VSNPRINTF_IS_POSIX],
   AC_REQUIRE([gl_PRINTF_DIRECTIVE_LC])
   AC_REQUIRE([gl_PRINTF_POSITIONS])
   AC_REQUIRE([gl_PRINTF_FLAG_GROUPING])
+  AC_REQUIRE([gl_PRINTF_FLAG_GROUPING_INT_PRECISION])
+  AC_REQUIRE([gl_PRINTF_FLAG_GROUPING_MULTIBYTE])
   AC_REQUIRE([gl_PRINTF_FLAG_LEFTADJUST])
   AC_REQUIRE([gl_PRINTF_FLAG_ZERO])
   AC_REQUIRE([gl_PRINTF_FLAG_ALT_PRECISION_ZERO])
@@ -73,29 +75,37 @@ AC_DEFUN([gl_FUNC_VSNPRINTF_IS_POSIX],
                                                   *yes)
                                                     case "$gl_cv_func_printf_flag_grouping" in
                                                       *yes)
-                                                        case "$gl_cv_func_printf_flag_leftadjust" in
+                                                        case "$gl_cv_func_printf_flag_grouping_int_precision" in
                                                           *yes)
-                                                            case "$gl_cv_func_printf_flag_zero" in
+                                                            case "$gl_cv_func_printf_flag_grouping_multibyte" in
                                                               *yes)
-                                                                case "$gl_cv_func_printf_flag_alt_precision_zero" in
+                                                                case "$gl_cv_func_printf_flag_leftadjust" in
                                                                   *yes)
-                                                                    case "$gl_cv_func_printf_precision" in
+                                                                    case "$gl_cv_func_printf_flag_zero" in
                                                                       *yes)
-                                                                        case "$gl_cv_func_printf_enomem" in
+                                                                        case "$gl_cv_func_printf_flag_alt_precision_zero" in
                                                                           *yes)
-                                                                            case "$gl_cv_func_snprintf_truncation_c99" in
+                                                                            case "$gl_cv_func_printf_precision" in
                                                                               *yes)
-                                                                                case "$gl_cv_func_snprintf_retval_c99" in
+                                                                                case "$gl_cv_func_printf_enomem" in
                                                                                   *yes)
-                                                                                    case m4_ifdef([gl_PRINTF_SUPPORT_N_DIRECTIVE],["$gl_cv_func_snprintf_directive_n"],["yes"]) in
+                                                                                    case "$gl_cv_func_snprintf_truncation_c99" in
                                                                                       *yes)
-                                                                                        case "$gl_cv_func_snprintf_size1" in
+                                                                                        case "$gl_cv_func_snprintf_retval_c99" in
                                                                                           *yes)
-                                                                                            case "$gl_cv_func_vsnprintf_zerosize_c99" in
+                                                                                            case m4_ifdef([gl_PRINTF_SUPPORT_N_DIRECTIVE],["$gl_cv_func_snprintf_directive_n"],["yes"]) in
                                                                                               *yes)
-                                                                                                # vsnprintf exists and is
-                                                                                                # already POSIX compliant.
-                                                                                                gl_cv_func_vsnprintf_posix=yes
+                                                                                                case "$gl_cv_func_snprintf_size1" in
+                                                                                                  *yes)
+                                                                                                    case "$gl_cv_func_vsnprintf_zerosize_c99" in
+                                                                                                      *yes)
+                                                                                                        # vsnprintf exists and is
+                                                                                                        # already POSIX compliant.
+                                                                                                        gl_cv_func_vsnprintf_posix=yes
+                                                                                                        ;;
+                                                                                                    esac
+                                                                                                    ;;
+                                                                                                esac
                                                                                                 ;;
                                                                                             esac
                                                                                             ;;
index 9c42bd775d696ab35bc6132856a9cbffd32cba18..6a8ad623c1b92c58f63dc7f74ebd6aa90ec015ff 100644 (file)
@@ -1,5 +1,5 @@
 # vsprintf-posix.m4
-# serial 19
+# serial 20
 dnl Copyright (C) 2007-2025 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -33,6 +33,8 @@ AC_DEFUN([gl_FUNC_VSPRINTF_IS_POSIX],
   AC_REQUIRE([gl_PRINTF_DIRECTIVE_LC])
   AC_REQUIRE([gl_PRINTF_POSITIONS])
   AC_REQUIRE([gl_PRINTF_FLAG_GROUPING])
+  AC_REQUIRE([gl_PRINTF_FLAG_GROUPING_INT_PRECISION])
+  AC_REQUIRE([gl_PRINTF_FLAG_GROUPING_MULTIBYTE])
   AC_REQUIRE([gl_PRINTF_FLAG_LEFTADJUST])
   AC_REQUIRE([gl_PRINTF_FLAG_ZERO])
   AC_REQUIRE([gl_PRINTF_FLAG_ALT_PRECISION_ZERO])
@@ -65,19 +67,27 @@ AC_DEFUN([gl_FUNC_VSPRINTF_IS_POSIX],
                                                 *yes)
                                                   case "$gl_cv_func_printf_flag_grouping" in
                                                     *yes)
-                                                      case "$gl_cv_func_printf_flag_leftadjust" in
+                                                      case "$gl_cv_func_printf_flag_grouping_int_precision" in
                                                         *yes)
-                                                          case "$gl_cv_func_printf_flag_zero" in
+                                                          case "$gl_cv_func_printf_flag_grouping_multibyte" in
                                                             *yes)
-                                                              case "$gl_cv_func_printf_flag_alt_precision_zero" in
+                                                              case "$gl_cv_func_printf_flag_leftadjust" in
                                                                 *yes)
-                                                                  case "$gl_cv_func_printf_precision" in
+                                                                  case "$gl_cv_func_printf_flag_zero" in
                                                                     *yes)
-                                                                      case "$gl_cv_func_printf_enomem" in
+                                                                      case "$gl_cv_func_printf_flag_alt_precision_zero" in
                                                                         *yes)
-                                                                          # vsprintf exists and is
-                                                                          # already POSIX compliant.
-                                                                          gl_cv_func_vsprintf_posix=yes
+                                                                          case "$gl_cv_func_printf_precision" in
+                                                                            *yes)
+                                                                              case "$gl_cv_func_printf_enomem" in
+                                                                                *yes)
+                                                                                  # vsprintf exists and is
+                                                                                  # already POSIX compliant.
+                                                                                  gl_cv_func_vsprintf_posix=yes
+                                                                                  ;;
+                                                                              esac
+                                                                              ;;
+                                                                          esac
                                                                           ;;
                                                                       esac
                                                                       ;;
index 5e2c388fec85fe3a3c6a238dd3579410b34bef31..43d57264e7d1d8cc47e1014b7567233d8731eb80 100644 (file)
@@ -16,6 +16,7 @@ float-h
 nan
 snan
 setlocale
+localeconv
 
 configure.ac:
 AC_REQUIRE([gl_LONG_DOUBLE_VS_DOUBLE])
index 3d47d8893b98033e0570d713e7c1fa3eae71f281..d62437f2f5e49889567aba80a5b7b059ece5582d 100644 (file)
@@ -17,6 +17,7 @@ float-h
 nan
 snan
 setlocale
+localeconv
 wcscmp
 wcsspn
 wmemcmp
index 221292d7099667912f812c88ee87dd8fc4cfeb9e..1f43aa5e6e1dc56bed3fe93a6360a7129ae4d4ab 100644 (file)
@@ -59,5 +59,375 @@ main (int argc, char *argv[])
     free (result);
   }
 
+  /* Test that a locale dependent grouping separator is used correctly.  */
+  {
+    const char *separator =
+      localeconv ()->thousands_sep; /* = nl_langinfo (THOUSEP) */
+    size_t separator_len = strlen (separator);
+
+    /* Tests of %d directive with grouping separator.  */
+    {
+      size_t length;
+      char *result = asnprintf (NULL, &length, "%'d", 1000);
+      ASSERT (result != NULL);
+      ASSERT (length == 4 + separator_len);
+      ASSERT (memcmp (result, "1", 1) == 0
+              && memcmp (result + 1, separator, separator_len) == 0
+              && strcmp (result + 1 + separator_len, "000") == 0);
+      free (result);
+    }
+    {
+      size_t length;
+      char *result = asnprintf (NULL, &length, "%'d", -1000);
+      ASSERT (result != NULL);
+      ASSERT (length == 5 + separator_len);
+      ASSERT (memcmp (result, "-1", 2) == 0
+              && memcmp (result + 2, separator, separator_len) == 0
+              && strcmp (result + 2 + separator_len, "000") == 0);
+      free (result);
+    }
+    {
+      size_t length;
+      char *result = asnprintf (NULL, &length, "%'d", -142857);
+      ASSERT (result != NULL);
+      ASSERT (length == 7 + separator_len);
+      ASSERT (memcmp (result, "-142", 4) == 0
+              && memcmp (result + 4, separator, separator_len) == 0
+              && strcmp (result + 4 + separator_len, "857") == 0);
+      free (result);
+    }
+    {
+      size_t length;
+      char *result = asnprintf (NULL, &length, "%'d", 2147483647);
+      ASSERT (result != NULL);
+      ASSERT (length == 10 + 3 * separator_len);
+      ASSERT (memcmp (result, "2", 1) == 0
+              && memcmp (result + 1, separator, separator_len) == 0
+              && memcmp (result + 1 + separator_len, "147", 3) == 0
+              && memcmp (result + 4 + separator_len, separator, separator_len) == 0
+              && memcmp (result + 4 + 2 * separator_len, "483", 3) == 0
+              && memcmp (result + 7 + 2 * separator_len, separator, separator_len) == 0
+              && strcmp (result + 7 + 3 * separator_len, "647") == 0);
+      free (result);
+    }
+    {
+      size_t length;
+      char *result = asnprintf (NULL, &length, "%'d", -2147483647);
+      ASSERT (result != NULL);
+      ASSERT (length == 11 + 3 * separator_len);
+      ASSERT (memcmp (result, "-2", 2) == 0
+              && memcmp (result + 2, separator, separator_len) == 0
+              && memcmp (result + 2 + separator_len, "147", 3) == 0
+              && memcmp (result + 5 + separator_len, separator, separator_len) == 0
+              && memcmp (result + 5 + 2 * separator_len, "483", 3) == 0
+              && memcmp (result + 8 + 2 * separator_len, separator, separator_len) == 0
+              && strcmp (result + 8 + 3 * separator_len, "647") == 0);
+      free (result);
+    }
+    {
+      size_t length;
+      char *result = asnprintf (NULL, &length, "%'.10d", 1000);
+      ASSERT (result != NULL);
+      if (length == 10 + separator_len)
+        {
+          /* Most implementations don't add the grouping character within the
+             leading zeroes.  */
+          ASSERT (length == 10 + separator_len);
+          ASSERT (memcmp (result, "0000001", 7) == 0
+                  && memcmp (result + 7, separator, separator_len) == 0
+                  && strcmp (result + 7 + separator_len, "000") == 0);
+        }
+      else
+        {
+          /* But there are good arguments for adding the grouping character
+             within the leading zeroes.
+             <https://sourceware.org/bugzilla/show_bug.cgi?id=23432>  */
+          ASSERT (length == 10 + 3 * separator_len);
+          ASSERT (memcmp (result, "0", 1) == 0
+                  && memcmp (result + 1, separator, separator_len) == 0
+                  && memcmp (result + 1 + separator_len, "000", 3) == 0
+                  && memcmp (result + 4 + separator_len, separator, separator_len) == 0
+                  && memcmp (result + 4 + 2 * separator_len, "001", 3) == 0
+                  && memcmp (result + 7 + 2 * separator_len, separator, separator_len) == 0
+                  && strcmp (result + 7 + 3 * separator_len, "000") == 0);
+        }
+      free (result);
+    }
+    {
+      size_t length;
+      char *result = asnprintf (NULL, &length, "%'.10d", -1000);
+      ASSERT (result != NULL);
+      if (length == 11 + separator_len)
+        {
+          /* Most implementations don't add the grouping character within the
+             leading zeroes.  */
+          ASSERT (length == 11 + separator_len);
+          ASSERT (memcmp (result, "-0000001", 8) == 0
+                  && memcmp (result + 8, separator, separator_len) == 0
+                  && strcmp (result + 8 + separator_len, "000") == 0);
+        }
+      else
+        {
+          /* But there are good arguments for adding the grouping character
+             within the leading zeroes.
+             <https://sourceware.org/bugzilla/show_bug.cgi?id=23432>  */
+          ASSERT (length == 11 + 3 * separator_len);
+          ASSERT (memcmp (result, "-0", 2) == 0
+                  && memcmp (result + 2, separator, separator_len) == 0
+                  && memcmp (result + 2 + separator_len, "000", 3) == 0
+                  && memcmp (result + 5 + separator_len, separator, separator_len) == 0
+                  && memcmp (result + 5 + 2 * separator_len, "001", 3) == 0
+                  && memcmp (result + 8 + 2 * separator_len, separator, separator_len) == 0
+                  && strcmp (result + 8 + 3 * separator_len, "000") == 0);
+        }
+      free (result);
+    }
+    {
+      size_t length;
+      char *result = asnprintf (NULL, &length, "%'10d", 1000);
+      ASSERT (result != NULL);
+      if (separator_len > 0)
+        {
+          if (length == 10)
+            {
+              /* Result according to POSIX, which says that the width is
+                 measured in "bytes".
+                 <https://pubs.opengroup.org/onlinepubs/9799919799/functions/fprintf.html>
+                 <https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/V1_chap05.html#tag_05>  */
+              ASSERT (length == 10);
+              ASSERT (memcmp (result, "      1" + separator_len, 7 - separator_len) == 0
+                      && memcmp (result + 7 - separator_len, separator, separator_len) == 0
+                      && strcmp (result + 7, "000") == 0);
+            }
+          else
+            {
+              /* Result according to glibc, which measures the width in
+                 multibyte characters or column positions.
+                 <https://sourceware.org/bugzilla/show_bug.cgi?id=28943>
+                 <https://sourceware.org/bugzilla/show_bug.cgi?id=30883>
+                 <https://sourceware.org/bugzilla/show_bug.cgi?id=31542>  */
+              ASSERT (length == 9 + separator_len);
+              ASSERT (memcmp (result, "     1", 6) == 0
+                      && memcmp (result + 6, separator, separator_len) == 0
+                      && strcmp (result + 6 + separator_len, "000") == 0);
+            }
+        }
+      else
+        {
+          ASSERT (length == 10);
+          ASSERT (strcmp (result, "      1000") == 0);
+        }
+      free (result);
+    }
+    {
+      size_t length;
+      char *result = asnprintf (NULL, &length, "%'10d", -1000);
+      ASSERT (result != NULL);
+      if (separator_len > 0)
+        {
+          if (length == 10)
+            {
+              /* Result according to POSIX, which says that the width is
+                 measured in "bytes".
+                 <https://pubs.opengroup.org/onlinepubs/9799919799/functions/fprintf.html>
+                 <https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/V1_chap05.html#tag_05>  */
+              ASSERT (length == 10);
+              ASSERT (memcmp (result, "     -1" + separator_len, 7 - separator_len) == 0
+                      && memcmp (result + 7 - separator_len, separator, separator_len) == 0
+                      && strcmp (result + 7, "000") == 0);
+            }
+          else
+            {
+              /* Result according to glibc, which measures the width in
+                 multibyte characters or column positions.
+                 <https://sourceware.org/bugzilla/show_bug.cgi?id=28943>
+                 <https://sourceware.org/bugzilla/show_bug.cgi?id=30883>
+                 <https://sourceware.org/bugzilla/show_bug.cgi?id=31542>  */
+              ASSERT (length == 9 + separator_len);
+              ASSERT (memcmp (result, "    -1", 6) == 0
+                      && memcmp (result + 6, separator, separator_len) == 0
+                      && strcmp (result + 6 + separator_len, "000") == 0);
+            }
+        }
+      else
+        {
+          ASSERT (length == 10);
+          ASSERT (strcmp (result, "     -1000") == 0);
+        }
+      free (result);
+    }
+
+    /* Tests of %f directive with grouping separator.  */
+    {
+      size_t length;
+      char *result = asnprintf (NULL, &length, "%'.0f", 1000.0);
+      ASSERT (result != NULL);
+      ASSERT (length == 4 + separator_len);
+      ASSERT (memcmp (result, "1", 1) == 0
+              && memcmp (result + 1, separator, separator_len) == 0
+              && strcmp (result + 1 + separator_len, "000") == 0);
+      free (result);
+    }
+    {
+      size_t length;
+      char *result = asnprintf (NULL, &length, "%'.5f", 3141592653.5897932386);
+      ASSERT (result != NULL);
+      ASSERT (length == 16 + 3 * separator_len);
+      ASSERT (memcmp (result, "3", 1) == 0
+              && memcmp (result + 1, separator, separator_len) == 0
+              && memcmp (result + 1 + separator_len, "141", 3) == 0
+              && memcmp (result + 4 + separator_len, separator, separator_len) == 0
+              && memcmp (result + 4 + 2 * separator_len, "592", 3) == 0
+              && memcmp (result + 7 + 2 * separator_len, separator, separator_len) == 0
+              && strcmp (result + 7 + 3 * separator_len, "653,58979") == 0);
+      free (result);
+    }
+    {
+      size_t length;
+      char *result = asnprintf (NULL, &length, "%'.5f", -3141592653.5897932386);
+      ASSERT (result != NULL);
+      ASSERT (length == 17 + 3 * separator_len);
+      ASSERT (memcmp (result, "-3", 2) == 0
+              && memcmp (result + 2, separator, separator_len) == 0
+              && memcmp (result + 2 + separator_len, "141", 3) == 0
+              && memcmp (result + 5 + separator_len, separator, separator_len) == 0
+              && memcmp (result + 5 + 2 * separator_len, "592", 3) == 0
+              && memcmp (result + 8 + 2 * separator_len, separator, separator_len) == 0
+              && strcmp (result + 8 + 3 * separator_len, "653,58979") == 0);
+      free (result);
+    }
+    {
+      size_t length;
+      char *result = asnprintf (NULL, &length, "%'010.0f", 1000.0);
+      ASSERT (result != NULL);
+      if (separator_len > 0)
+        {
+          if (length == 10)
+            {
+              /* Result according to POSIX, which says that the width is
+                 measured in "bytes".
+                 <https://pubs.opengroup.org/onlinepubs/9799919799/functions/fprintf.html>
+                 <https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/V1_chap05.html#tag_05>  */
+              ASSERT (length == 10);
+              ASSERT (memcmp (result, "0000001" + separator_len, 7 - separator_len) == 0
+                      && memcmp (result + 7 - separator_len, separator, separator_len) == 0
+                      && strcmp (result + 7, "000") == 0);
+            }
+          else
+            {
+              /* Result according to glibc, which measures the width in
+                 multibyte characters or column positions.
+                 <https://sourceware.org/bugzilla/show_bug.cgi?id=28943>
+                 <https://sourceware.org/bugzilla/show_bug.cgi?id=30883>
+                 <https://sourceware.org/bugzilla/show_bug.cgi?id=31542>  */
+              ASSERT (length == 9 + separator_len);
+              ASSERT (memcmp (result, "000001", 6) == 0
+                      && memcmp (result + 6, separator, separator_len) == 0
+                      && strcmp (result + 6 + separator_len, "000") == 0);
+            }
+        }
+      else
+        {
+          ASSERT (length == 10);
+          ASSERT (strcmp (result, "0000001000") == 0);
+        }
+      free (result);
+    }
+
+    /* Tests of %g directive with grouping separator.  */
+    {
+      size_t length;
+      char *result = asnprintf (NULL, &length, "%'g", 1000.0);
+      ASSERT (result != NULL);
+      ASSERT (length == 4 + separator_len);
+      ASSERT (memcmp (result, "1", 1) == 0
+              && memcmp (result + 1, separator, separator_len) == 0
+              && strcmp (result + 1 + separator_len, "000") == 0);
+      free (result);
+    }
+    {
+      size_t length;
+      char *result = asnprintf (NULL, &length, "%'g", -142857.0);
+      ASSERT (result != NULL);
+      ASSERT (length == 7 + separator_len);
+      ASSERT (memcmp (result, "-142", 4) == 0
+              && memcmp (result + 4, separator, separator_len) == 0
+              && strcmp (result + 4 + separator_len, "857") == 0);
+      free (result);
+    }
+    {
+      size_t length;
+      char *result = asnprintf (NULL, &length, "%'.5g", 3141592653.5897932386);
+      ASSERT (result != NULL);
+      ASSERT (length == 10);
+      ASSERT (strcmp (result, "3,1416e+09") == 0);
+      free (result);
+    }
+    {
+      size_t length;
+      char *result = asnprintf (NULL, &length, "%'.5g", -3141592653.5897932386);
+      ASSERT (result != NULL);
+      ASSERT (length == 11);
+      ASSERT (strcmp (result, "-3,1416e+09") == 0);
+      free (result);
+    }
+    {
+      size_t length;
+      char *result =
+        asnprintf (NULL, &length, "%'.50g",
+                   42351647362715016953416125033982098102569580078125.0);
+      ASSERT (result != NULL);
+      ASSERT (length == 50 + 16 * separator_len);
+      ASSERT (memcmp (result, "42", 2) == 0
+              && memcmp (result + 2, separator, separator_len) == 0
+              && memcmp (result + 2 + separator_len, "351", 3) == 0
+              && memcmp (result + 5 + separator_len, separator, separator_len) == 0
+              && memcmp (result + 5 + 2 * separator_len, "647", 3) == 0
+              && memcmp (result + 8 + 2 * separator_len, separator, separator_len) == 0
+              && memcmp (result + 8 + 3 * separator_len, "362", 3) == 0
+              && memcmp (result + 11 + 3 * separator_len, separator, separator_len) == 0
+              && memcmp (result + 11 + 4 * separator_len, "715", 3) == 0
+              && memcmp (result + 14 + 4 * separator_len, separator, separator_len) == 0);
+      free (result);
+    }
+    {
+      size_t length;
+      char *result = asnprintf (NULL, &length, "%'010g", 1000.0);
+      ASSERT (result != NULL);
+      if (separator_len > 0)
+        {
+          if (length == 10)
+            {
+              /* Result according to POSIX, which says that the width is
+                 measured in "bytes".
+                 <https://pubs.opengroup.org/onlinepubs/9799919799/functions/fprintf.html>
+                 <https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/V1_chap05.html#tag_05>  */
+              ASSERT (length == 10);
+              ASSERT (memcmp (result, "0000001" + separator_len, 7 - separator_len) == 0
+                      && memcmp (result + 7 - separator_len, separator, separator_len) == 0
+                      && strcmp (result + 7, "000") == 0);
+            }
+          else
+            {
+              /* Result according to glibc, which measures the width in
+                 multibyte characters or column positions.
+                 <https://sourceware.org/bugzilla/show_bug.cgi?id=28943>
+                 <https://sourceware.org/bugzilla/show_bug.cgi?id=30883>
+                 <https://sourceware.org/bugzilla/show_bug.cgi?id=31542>  */
+              ASSERT (length == 9 + separator_len);
+              ASSERT (memcmp (result, "000001", 6) == 0
+                      && memcmp (result + 6, separator, separator_len) == 0
+                      && strcmp (result + 6 + separator_len, "000") == 0);
+            }
+        }
+      else
+        {
+          ASSERT (length == 10);
+          ASSERT (strcmp (result, "0000001000") == 0);
+        }
+      free (result);
+    }
+  }
+
   return test_exit_status;
 }
index e488e94e97f0435bad325b325f6afff6364e4e57..90c2fc180c3897a46194251b8f2f9d968e44da18 100755 (executable)
@@ -3,19 +3,13 @@
 # Test whether a french locale is installed.
 : "${LOCALE_FR=fr_FR}"
 : "${LOCALE_FR_UTF8=fr_FR.UTF-8}"
-if test $LOCALE_FR != none; then
-  testlocale=$LOCALE_FR
-else
-  if test $LOCALE_FR_UTF8 != none; then
-    testlocale=$LOCALE_FR_UTF8
+if test $LOCALE_FR = none && test $LOCALE_FR_UTF8 = none; then
+  if test -f /usr/bin/localedef; then
+    echo "Skipping test: no french locale is installed"
   else
-    if test -f /usr/bin/localedef; then
-      echo "Skipping test: no french locale is installed"
-    else
-      echo "Skipping test: no french locale is supported"
-    fi
-    exit 77
+    echo "Skipping test: no french locale is supported"
   fi
+  exit 77
 fi
 
 if $LC_NUMERIC_IMPLEMENTED; then
@@ -25,5 +19,11 @@ else
   exit 77
 fi
 
-LC_ALL=$testlocale \
-${CHECKER} ./test-vasnprintf-posix2${EXEEXT}
+if test $LOCALE_FR != none; then
+  LC_ALL=$LOCALE_FR      ${CHECKER} ./test-vasnprintf-posix2${EXEEXT} || exit 1
+fi
+if test $LOCALE_FR_UTF8 != none; then
+  LC_ALL=$LOCALE_FR_UTF8 ${CHECKER} ./test-vasnprintf-posix2${EXEEXT} || exit 1
+fi
+
+exit 0
index fde409376e4ef0ee292e626894898bcff569ab4a..3794d5f7c483582cd09c1ab0882796a7412ea2fe 100644 (file)
 #include <stdlib.h>
 #include <string.h>
 #include <wchar.h>
+#if __GLIBC__ >= 2 || defined __CYGWIN__
+# include <langinfo.h>
+# include <stdint.h>
+#endif
 
 #include "macros.h"
 
@@ -60,5 +64,276 @@ main (int argc, char *argv[])
     free (result);
   }
 
+  /* Test that a locale dependent grouping separator is used correctly.  */
+  {
+    wchar_t separator[10];
+#if __GLIBC__ >= 2 || defined __CYGWIN__
+    /* On glibc, in the unibyte locale fr_FR, the *wprintf routines use U+202F
+       as separator, which cannot be represented in the locale encoding.  */
+    separator[0] = (wchar_t) (uintptr_t) nl_langinfo (_NL_NUMERIC_THOUSANDS_SEP_WC);
+    separator[1] = L'\0';
+#else
+    const char *separator_mb =
+      localeconv ()->thousands_sep; /* = nl_langinfo (THOUSEP) */
+    mbstowcs (separator, separator_mb, SIZEOF (separator));
+#endif
+    size_t separator_len = wcslen (separator);
+
+    /* Tests of %d directive with grouping separator.  */
+    {
+      size_t length;
+      wchar_t *result = asnwprintf (NULL, &length, L"%'d", 1000);
+      ASSERT (result != NULL);
+      ASSERT (length == 4 + separator_len);
+      ASSERT (wmemcmp (result, L"1", 1) == 0
+              && wmemcmp (result + 1, separator, separator_len) == 0
+              && wcscmp (result + 1 + separator_len, L"000") == 0);
+      free (result);
+    }
+    {
+      size_t length;
+      wchar_t *result = asnwprintf (NULL, &length, L"%'d", -1000);
+      ASSERT (result != NULL);
+      ASSERT (length == 5 + separator_len);
+      ASSERT (wmemcmp (result, L"-1", 2) == 0
+              && wmemcmp (result + 2, separator, separator_len) == 0
+              && wcscmp (result + 2 + separator_len, L"000") == 0);
+      free (result);
+    }
+    {
+      size_t length;
+      wchar_t *result = asnwprintf (NULL, &length, L"%'d", -142857);
+      ASSERT (result != NULL);
+      ASSERT (length == 7 + separator_len);
+      ASSERT (wmemcmp (result, L"-142", 4) == 0
+              && wmemcmp (result + 4, separator, separator_len) == 0
+              && wcscmp (result + 4 + separator_len, L"857") == 0);
+      free (result);
+    }
+    {
+      size_t length;
+      wchar_t *result = asnwprintf (NULL, &length, L"%'d", 2147483647);
+      ASSERT (result != NULL);
+      ASSERT (length == 10 + 3 * separator_len);
+      ASSERT (wmemcmp (result, L"2", 1) == 0
+              && wmemcmp (result + 1, separator, separator_len) == 0
+              && wmemcmp (result + 1 + separator_len, L"147", 3) == 0
+              && wmemcmp (result + 4 + separator_len, separator, separator_len) == 0
+              && wmemcmp (result + 4 + 2 * separator_len, L"483", 3) == 0
+              && wmemcmp (result + 7 + 2 * separator_len, separator, separator_len) == 0
+              && wcscmp (result + 7 + 3 * separator_len, L"647") == 0);
+      free (result);
+    }
+    {
+      size_t length;
+      wchar_t *result = asnwprintf (NULL, &length, L"%'d", -2147483647);
+      ASSERT (result != NULL);
+      ASSERT (length == 11 + 3 * separator_len);
+      ASSERT (wmemcmp (result, L"-2", 2) == 0
+              && wmemcmp (result + 2, separator, separator_len) == 0
+              && wmemcmp (result + 2 + separator_len, L"147", 3) == 0
+              && wmemcmp (result + 5 + separator_len, separator, separator_len) == 0
+              && wmemcmp (result + 5 + 2 * separator_len, L"483", 3) == 0
+              && wmemcmp (result + 8 + 2 * separator_len, separator, separator_len) == 0
+              && wcscmp (result + 8 + 3 * separator_len, L"647") == 0);
+      free (result);
+    }
+    {
+      size_t length;
+      wchar_t *result = asnwprintf (NULL, &length, L"%'.10d", 1000);
+      ASSERT (result != NULL);
+      if (length == 10 + separator_len)
+        {
+          /* Most implementations don't add the grouping character within the
+             leading zeroes.  */
+          ASSERT (length == 10 + separator_len);
+          ASSERT (wmemcmp (result, L"0000001", 7) == 0
+                  && wmemcmp (result + 7, separator, separator_len) == 0
+                  && wcscmp (result + 7 + separator_len, L"000") == 0);
+        }
+      else
+        {
+          /* But there are good arguments for adding the grouping character
+             within the leading zeroes too.
+             <https://sourceware.org/bugzilla/show_bug.cgi?id=23432>  */
+          ASSERT (length == 10 + 3 * separator_len);
+          ASSERT (wmemcmp (result, L"0", 1) == 0
+                  && wmemcmp (result + 1, separator, separator_len) == 0
+                  && wmemcmp (result + 1 + separator_len, L"000", 3) == 0
+                  && wmemcmp (result + 4 + separator_len, separator, separator_len) == 0
+                  && wmemcmp (result + 4 + 2 * separator_len, L"001", 3) == 0
+                  && wmemcmp (result + 7 + 2 * separator_len, separator, separator_len) == 0
+                  && wcscmp (result + 7 + 3 * separator_len, L"000") == 0);
+        }
+      free (result);
+    }
+    {
+      size_t length;
+      wchar_t *result = asnwprintf (NULL, &length, L"%'.10d", -1000);
+      ASSERT (result != NULL);
+      if (length == 11 + separator_len)
+        {
+          /* Most implementations don't add the grouping character within the
+             leading zeroes.  */
+          ASSERT (length == 11 + separator_len);
+          ASSERT (wmemcmp (result, L"-0000001", 8) == 0
+                  && wmemcmp (result + 8, separator, separator_len) == 0
+                  && wcscmp (result + 8 + separator_len, L"000") == 0);
+        }
+      else
+        {
+          /* But there are good arguments for adding the grouping character
+             within the leading zeroes too.
+             <https://sourceware.org/bugzilla/show_bug.cgi?id=23432>  */
+          ASSERT (length == 11 + 3 * separator_len);
+          ASSERT (wmemcmp (result, L"-0", 2) == 0
+                  && wmemcmp (result + 2, separator, separator_len) == 0
+                  && wmemcmp (result + 2 + separator_len, L"000", 3) == 0
+                  && wmemcmp (result + 5 + separator_len, separator, separator_len) == 0
+                  && wmemcmp (result + 5 + 2 * separator_len, L"001", 3) == 0
+                  && wmemcmp (result + 8 + 2 * separator_len, separator, separator_len) == 0
+                  && wcscmp (result + 8 + 3 * separator_len, L"000") == 0);
+        }
+      free (result);
+    }
+    {
+      size_t length;
+      wchar_t *result = asnwprintf (NULL, &length, L"%'10d", 1000);
+      ASSERT (result != NULL);
+      ASSERT (length == 10);
+      ASSERT (wmemcmp (result, L"      1" + separator_len, 7 - separator_len) == 0
+              && wmemcmp (result + 7 - separator_len, separator, separator_len) == 0
+              && wcscmp (result + 7, L"000") == 0);
+      free (result);
+    }
+    {
+      size_t length;
+      wchar_t *result = asnwprintf (NULL, &length, L"%'10d", -1000);
+      ASSERT (result != NULL);
+      ASSERT (length == 10);
+      ASSERT (wmemcmp (result, L"     -1" + separator_len, 7 - separator_len) == 0
+              && wmemcmp (result + 7 - separator_len, separator, separator_len) == 0
+              && wcscmp (result + 7, L"000") == 0);
+      free (result);
+    }
+
+    /* Tests of %f directive with grouping separator.  */
+    {
+      size_t length;
+      wchar_t *result = asnwprintf (NULL, &length, L"%'.0f", 1000.0);
+      ASSERT (result != NULL);
+      ASSERT (length == 4 + separator_len);
+      ASSERT (wmemcmp (result, L"1", 1) == 0
+              && wmemcmp (result + 1, separator, separator_len) == 0
+              && wcscmp (result + 1 + separator_len, L"000") == 0);
+      free (result);
+    }
+    {
+      size_t length;
+      wchar_t *result = asnwprintf (NULL, &length, L"%'.5f", 3141592653.5897932386);
+      ASSERT (result != NULL);
+      ASSERT (length == 16 + 3 * separator_len);
+      ASSERT (wmemcmp (result, L"3", 1) == 0
+              && wmemcmp (result + 1, separator, separator_len) == 0
+              && wmemcmp (result + 1 + separator_len, L"141", 3) == 0
+              && wmemcmp (result + 4 + separator_len, separator, separator_len) == 0
+              && wmemcmp (result + 4 + 2 * separator_len, L"592", 3) == 0
+              && wmemcmp (result + 7 + 2 * separator_len, separator, separator_len) == 0
+              && wcscmp (result + 7 + 3 * separator_len, L"653,58979") == 0);
+      free (result);
+    }
+    {
+      size_t length;
+      wchar_t *result = asnwprintf (NULL, &length, L"%'.5f", -3141592653.5897932386);
+      ASSERT (result != NULL);
+      ASSERT (length == 17 + 3 * separator_len);
+      ASSERT (wmemcmp (result, L"-3", 2) == 0
+              && wmemcmp (result + 2, separator, separator_len) == 0
+              && wmemcmp (result + 2 + separator_len, L"141", 3) == 0
+              && wmemcmp (result + 5 + separator_len, separator, separator_len) == 0
+              && wmemcmp (result + 5 + 2 * separator_len, L"592", 3) == 0
+              && wmemcmp (result + 8 + 2 * separator_len, separator, separator_len) == 0
+              && wcscmp (result + 8 + 3 * separator_len, L"653,58979") == 0);
+      free (result);
+    }
+    {
+      size_t length;
+      wchar_t *result = asnwprintf (NULL, &length, L"%'010.0f", 1000.0);
+      ASSERT (result != NULL);
+      ASSERT (length == 10);
+      ASSERT (wmemcmp (result, L"0000001" + separator_len, 7 - separator_len) == 0
+              && wmemcmp (result + 7 - separator_len, separator, separator_len) == 0
+              && wcscmp (result + 7, L"000") == 0);
+      free (result);
+    }
+
+    /* Tests of %g directive with grouping separator.  */
+    {
+      size_t length;
+      wchar_t *result = asnwprintf (NULL, &length, L"%'g", 1000.0);
+      ASSERT (result != NULL);
+      ASSERT (length == 4 + separator_len);
+      ASSERT (wmemcmp (result, L"1", 1) == 0
+              && wmemcmp (result + 1, separator, separator_len) == 0
+              && wcscmp (result + 1 + separator_len, L"000") == 0);
+      free (result);
+    }
+    {
+      size_t length;
+      wchar_t *result = asnwprintf (NULL, &length, L"%'g", -142857.0);
+      ASSERT (result != NULL);
+      ASSERT (length == 7 + separator_len);
+      ASSERT (wmemcmp (result, L"-142", 4) == 0
+              && wmemcmp (result + 4, separator, separator_len) == 0
+              && wcscmp (result + 4 + separator_len, L"857") == 0);
+      free (result);
+    }
+    {
+      size_t length;
+      wchar_t *result = asnwprintf (NULL, &length, L"%'.5g", 3141592653.5897932386);
+      ASSERT (result != NULL);
+      ASSERT (length == 10);
+      ASSERT (wcscmp (result, L"3,1416e+09") == 0);
+      free (result);
+    }
+    {
+      size_t length;
+      wchar_t *result = asnwprintf (NULL, &length, L"%'.5g", -3141592653.5897932386);
+      ASSERT (result != NULL);
+      ASSERT (length == 11);
+      ASSERT (wcscmp (result, L"-3,1416e+09") == 0);
+      free (result);
+    }
+    {
+      size_t length;
+      wchar_t *result =
+        asnwprintf (NULL, &length, L"%'.50g",
+                    42351647362715016953416125033982098102569580078125.0);
+      ASSERT (result != NULL);
+      ASSERT (length == 50 + 16 * separator_len);
+      ASSERT (wmemcmp (result, L"42", 2) == 0
+              && wmemcmp (result + 2, separator, separator_len) == 0
+              && wmemcmp (result + 2 + separator_len, L"351", 3) == 0
+              && wmemcmp (result + 5 + separator_len, separator, separator_len) == 0
+              && wmemcmp (result + 5 + 2 * separator_len, L"647", 3) == 0
+              && wmemcmp (result + 8 + 2 * separator_len, separator, separator_len) == 0
+              && wmemcmp (result + 8 + 3 * separator_len, L"362", 3) == 0
+              && wmemcmp (result + 11 + 3 * separator_len, separator, separator_len) == 0
+              && wmemcmp (result + 11 + 4 * separator_len, L"715", 3) == 0
+              && wmemcmp (result + 14 + 4 * separator_len, separator, separator_len) == 0);
+      free (result);
+    }
+    {
+      size_t length;
+      wchar_t *result = asnwprintf (NULL, &length, L"%'010g", 1000.0);
+      ASSERT (result != NULL);
+      ASSERT (length == 10);
+      ASSERT (wmemcmp (result, L"0000001" + separator_len, 7 - separator_len) == 0
+              && wmemcmp (result + 7 - separator_len, separator, separator_len) == 0
+              && wcscmp (result + 7, L"000") == 0);
+      free (result);
+    }
+  }
+
   return test_exit_status;
 }
index ecff3c9f65d8e937ef370bd62523f47c1960a26a..ceddec7ab654e2d9e9c99f9b4cf755d1a06ac04e 100755 (executable)
@@ -3,19 +3,13 @@
 # Test whether a french locale is installed.
 : "${LOCALE_FR=fr_FR}"
 : "${LOCALE_FR_UTF8=fr_FR.UTF-8}"
-if test $LOCALE_FR != none; then
-  testlocale=$LOCALE_FR
-else
-  if test $LOCALE_FR_UTF8 != none; then
-    testlocale=$LOCALE_FR_UTF8
+if test $LOCALE_FR = none && test $LOCALE_FR_UTF8 = none; then
+  if test -f /usr/bin/localedef; then
+    echo "Skipping test: no french locale is installed"
   else
-    if test -f /usr/bin/localedef; then
-      echo "Skipping test: no french locale is installed"
-    else
-      echo "Skipping test: no french locale is supported"
-    fi
-    exit 77
+    echo "Skipping test: no french locale is supported"
   fi
+  exit 77
 fi
 
 if $LC_NUMERIC_IMPLEMENTED; then
@@ -25,5 +19,11 @@ else
   exit 77
 fi
 
-LC_ALL=$testlocale \
-${CHECKER} ./test-vasnwprintf-posix2${EXEEXT}
+if test $LOCALE_FR != none; then
+  LC_ALL=$LOCALE_FR      ${CHECKER} ./test-vasnwprintf-posix2${EXEEXT} || exit 1
+fi
+if test $LOCALE_FR_UTF8 != none; then
+  LC_ALL=$LOCALE_FR_UTF8 ${CHECKER} ./test-vasnwprintf-posix2${EXEEXT} || exit 1
+fi
+
+exit 0