* 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: 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.
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,
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,
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.
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.
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.
@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,
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,
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,
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,
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,
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.
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.
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,
@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,
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,
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,
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,
@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,
@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,
@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,
#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
# 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
# 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. */
}
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;
}
}
# 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);
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. */
{
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 ();
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. */
{
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 ();
{
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
#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
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)
{
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)
}
#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
pad_ourselves = 1;
break;
default:
- pad_ourselves = prec_ourselves;
+ pad_ourselves = prec_ourselves | group_ourselves;
break;
}
#endif
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)
}
#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
#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
/* 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;
# 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,
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])
*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
;;
# 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,
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])
*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
;;
# 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,
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])
*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
;;
# 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,
])
])
+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>
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...
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 # # # # # # # # # . . ? # # ? ? . # ? # ? . # # # . . # ? ?
# 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,
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])
*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
;;
# 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,
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])
*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
;;
# 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,
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])
*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
;;
# 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,
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],
# 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,
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])
*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
;;
# 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,
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])
*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
;;
# 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,
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])
*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
;;
# 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,
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])
*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
;;
# 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,
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])
*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
;;
nan
snan
setlocale
+localeconv
configure.ac:
AC_REQUIRE([gl_LONG_DOUBLE_VS_DOUBLE])
nan
snan
setlocale
+localeconv
wcscmp
wcsspn
wmemcmp
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;
}
# 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
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
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
+#if __GLIBC__ >= 2 || defined __CYGWIN__
+# include <langinfo.h>
+# include <stdint.h>
+#endif
#include "macros.h"
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;
}
# 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
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