summaryrefslogtreecommitdiffstats
path: root/gl/vasnprintf.c
diff options
context:
space:
mode:
Diffstat (limited to 'gl/vasnprintf.c')
-rw-r--r--gl/vasnprintf.c3029
1 files changed, 2668 insertions, 361 deletions
diff --git a/gl/vasnprintf.c b/gl/vasnprintf.c
index 277c39e3..f46e8701 100644
--- a/gl/vasnprintf.c
+++ b/gl/vasnprintf.c
@@ -1,5 +1,5 @@
1/* vsprintf with automatic memory allocation. 1/* vsprintf with automatic memory allocation.
2 Copyright (C) 1999, 2002-2023 Free Software Foundation, Inc. 2 Copyright (C) 1999, 2002-2025 Free Software Foundation, Inc.
3 3
4 This file is free software: you can redistribute it and/or modify 4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as 5 it under the terms of the GNU Lesser General Public License as
@@ -29,6 +29,7 @@
29 Depends on FCHAR_T. 29 Depends on FCHAR_T.
30 DCHAR_CPY memcpy like function for DCHAR_T[] arrays. 30 DCHAR_CPY memcpy like function for DCHAR_T[] arrays.
31 DCHAR_SET memset like function for DCHAR_T[] arrays. 31 DCHAR_SET memset like function for DCHAR_T[] arrays.
32 DCHAR_STRLEN strlen like function for DCHAR_T[] arrays.
32 DCHAR_MBSNLEN mbsnlen like function for DCHAR_T[] arrays. 33 DCHAR_MBSNLEN mbsnlen like function for DCHAR_T[] arrays.
33 SNPRINTF The system's snprintf (or similar) function. 34 SNPRINTF The system's snprintf (or similar) function.
34 This may be either snprintf or swprintf. 35 This may be either snprintf or swprintf.
@@ -64,7 +65,7 @@
64/* As of GCC 11.2.1, gcc -Wanalyzer-too-complex reports that main's 65/* As of GCC 11.2.1, gcc -Wanalyzer-too-complex reports that main's
65 use of CHECK macros expands to code that is too complicated for gcc 66 use of CHECK macros expands to code that is too complicated for gcc
66 -fanalyzer. Suppress the resulting bogus warnings. */ 67 -fanalyzer. Suppress the resulting bogus warnings. */
67#if 10 <= __GNUC__ 68#if _GL_GNUC_PREREQ (10, 0)
68# pragma GCC diagnostic ignored "-Wanalyzer-null-argument" 69# pragma GCC diagnostic ignored "-Wanalyzer-null-argument"
69#endif 70#endif
70 71
@@ -80,14 +81,15 @@
80#endif 81#endif
81 82
82#include <locale.h> /* localeconv() */ 83#include <locale.h> /* localeconv() */
84#include <stdint.h> /* PTRDIFF_MAX */
83#include <stdio.h> /* snprintf(), sprintf() */ 85#include <stdio.h> /* snprintf(), sprintf() */
84#include <stdlib.h> /* abort(), malloc(), realloc(), free() */ 86#include <stdlib.h> /* abort(), malloc(), realloc(), free() */
85#include <string.h> /* memcpy(), strlen() */ 87#include <string.h> /* memcpy(), strlen() */
86#include <wchar.h> /* mbstate_t, mbrtowc(), mbrlen(), wcrtomb() */ 88#include <wchar.h> /* mbstate_t, mbrtowc(), mbrlen(), wcrtomb(), mbszero() */
87#include <errno.h> /* errno */ 89#include <errno.h> /* errno */
88#include <limits.h> /* CHAR_BIT */ 90#include <limits.h> /* CHAR_BIT, INT_MAX, INT_WIDTH, LONG_WIDTH */
89#include <float.h> /* DBL_MAX_EXP, LDBL_MAX_EXP */ 91#include <float.h> /* DBL_MAX_EXP, LDBL_MAX_EXP, LDBL_MANT_DIG */
90#if HAVE_NL_LANGINFO 92#if HAVE_NL_LANGINFO || __GLIBC__ >= 2 || defined __CYGWIN__
91# include <langinfo.h> 93# include <langinfo.h>
92#endif 94#endif
93#ifndef VASNPRINTF 95#ifndef VASNPRINTF
@@ -103,29 +105,29 @@
103 105
104#include "attribute.h" 106#include "attribute.h"
105 107
106#if (NEED_PRINTF_DOUBLE || NEED_PRINTF_LONG_DOUBLE) && !defined IN_LIBINTL 108#if NEED_PRINTF_DOUBLE || NEED_PRINTF_LONG_DOUBLE || (NEED_WPRINTF_DIRECTIVE_LA && WIDE_CHAR_VERSION)
107# include <math.h> 109# include <math.h>
108# include "float+.h" 110# include "float+.h"
109#endif 111#endif
110 112
111#if (NEED_PRINTF_DOUBLE || NEED_PRINTF_INFINITE_DOUBLE) && !defined IN_LIBINTL 113#if NEED_PRINTF_DOUBLE || NEED_PRINTF_INFINITE_DOUBLE
112# include <math.h> 114# include <math.h>
113# include "isnand-nolibm.h" 115# include "isnand-nolibm.h"
114#endif 116#endif
115 117
116#if (NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_INFINITE_LONG_DOUBLE) && !defined IN_LIBINTL 118#if NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_INFINITE_LONG_DOUBLE || (NEED_WPRINTF_DIRECTIVE_LA && WIDE_CHAR_VERSION)
117# include <math.h> 119# include <math.h>
118# include "isnanl-nolibm.h" 120# include "isnanl-nolibm.h"
119# include "fpucw.h" 121# include "fpucw.h"
120#endif 122#endif
121 123
122#if (NEED_PRINTF_DIRECTIVE_A || NEED_PRINTF_DOUBLE) && !defined IN_LIBINTL 124#if NEED_PRINTF_DIRECTIVE_A || NEED_PRINTF_DOUBLE
123# include <math.h> 125# include <math.h>
124# include "isnand-nolibm.h" 126# include "isnand-nolibm.h"
125# include "printf-frexp.h" 127# include "printf-frexp.h"
126#endif 128#endif
127 129
128#if (NEED_PRINTF_DIRECTIVE_A || NEED_PRINTF_LONG_DOUBLE) && !defined IN_LIBINTL 130#if NEED_PRINTF_DIRECTIVE_A || NEED_PRINTF_LONG_DOUBLE || (NEED_WPRINTF_DIRECTIVE_LA && WIDE_CHAR_VERSION)
129# include <math.h> 131# include <math.h>
130# include "isnanl-nolibm.h" 132# include "isnanl-nolibm.h"
131# include "printf-frexpl.h" 133# include "printf-frexpl.h"
@@ -138,8 +140,6 @@
138# define VASNPRINTF vasnwprintf 140# define VASNPRINTF vasnwprintf
139# define FCHAR_T wchar_t 141# define FCHAR_T wchar_t
140# define DCHAR_T wchar_t 142# define DCHAR_T wchar_t
141# define TCHAR_T wchar_t
142# define DCHAR_IS_TCHAR 1
143# define DIRECTIVE wchar_t_directive 143# define DIRECTIVE wchar_t_directive
144# define DIRECTIVES wchar_t_directives 144# define DIRECTIVES wchar_t_directives
145# define PRINTF_PARSE wprintf_parse 145# define PRINTF_PARSE wprintf_parse
@@ -159,24 +159,46 @@
159# endif 159# endif
160#endif 160#endif
161#if WIDE_CHAR_VERSION 161#if WIDE_CHAR_VERSION
162 /* TCHAR_T is wchar_t. */ 162 /* DCHAR_T is wchar_t. */
163# define USE_SNPRINTF 1 163# if HAVE_DECL__SNWPRINTF || (HAVE_SWPRINTF && HAVE_WORKING_SWPRINTF)
164# if HAVE_DECL__SNWPRINTF 164# define TCHAR_T wchar_t
165 /* On Windows, the function swprintf() has a different signature than 165# define DCHAR_IS_TCHAR 1
166 on Unix; we use the function _snwprintf() or - on mingw - snwprintf() 166# define USE_SNPRINTF 1
167 instead. The mingw function snwprintf() has fewer bugs than the 167# if HAVE_DECL__SNWPRINTF
168 MSVCRT function _snwprintf(), so prefer that. */ 168 /* On Windows, the function swprintf() has a different signature than
169# if defined __MINGW32__ 169 on Unix; we use the function _snwprintf() or - on mingw - snwprintf()
170# define SNPRINTF snwprintf 170 instead. The mingw function snwprintf() has fewer bugs than the
171 MSVCRT function _snwprintf(), so prefer that. */
172# if defined __MINGW32__
173# define SNPRINTF snwprintf
174# else
175# define SNPRINTF _snwprintf
176# define USE_MSVC__SNPRINTF 1
177# endif
171# else 178# else
172# define SNPRINTF _snwprintf 179 /* Unix. */
173# define USE_MSVC__SNPRINTF 1 180# define SNPRINTF swprintf
174# endif 181# endif
175# else 182# else
176 /* Unix. */ 183 /* Old platforms such as NetBSD 3.0, OpenBSD 3.8, HP-UX 11.00, IRIX 6.5. */
177# define SNPRINTF swprintf 184# define TCHAR_T char
178# endif 185# endif
179#else 186#endif
187#ifndef DCHAR_STRLEN
188# if WIDE_CHAR_VERSION
189# define DCHAR_STRLEN local_wcslen
190# else
191# define DCHAR_STRLEN strlen
192# endif
193#endif
194#ifndef DCHAR_MBSNLEN
195# if WIDE_CHAR_VERSION
196# define DCHAR_MBSNLEN wcsnlen
197# else
198# define DCHAR_MBSNLEN mbsnlen
199# endif
200#endif
201#if !WIDE_CHAR_VERSION || !DCHAR_IS_TCHAR
180 /* TCHAR_T is char. */ 202 /* TCHAR_T is char. */
181 /* Use snprintf if it exists under the name 'snprintf' or '_snprintf'. 203 /* Use snprintf if it exists under the name 'snprintf' or '_snprintf'.
182 But don't use it on BeOS, since BeOS snprintf produces no output if the 204 But don't use it on BeOS, since BeOS snprintf produces no output if the
@@ -210,6 +232,12 @@
210/* Here we need to call the native sprintf, not rpl_sprintf. */ 232/* Here we need to call the native sprintf, not rpl_sprintf. */
211#undef sprintf 233#undef sprintf
212 234
235/* macOS 12's "warning: 'sprintf' is deprecated" is pointless,
236 as sprintf is used safely here. */
237#if defined __APPLE__ && defined __MACH__ && _GL_GNUC_PREREQ (4, 2)
238# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
239#endif
240
213/* GCC >= 4.0 with -Wall emits unjustified "... may be used uninitialized" 241/* GCC >= 4.0 with -Wall emits unjustified "... may be used uninitialized"
214 warnings in this file. Use -Dlint to suppress them. */ 242 warnings in this file. Use -Dlint to suppress them. */
215#if defined GCC_LINT || defined lint 243#if defined GCC_LINT || defined lint
@@ -218,6 +246,11 @@
218# define IF_LINT(Code) /* empty */ 246# define IF_LINT(Code) /* empty */
219#endif 247#endif
220 248
249/* Here we need only the most basic fields of 'struct lconv', and can
250 therefore use the system's localeconv() function, without needing a
251 dependency on module 'localeconv'. */
252#undef localeconv
253
221/* Avoid some warnings from "gcc -Wshadow". 254/* Avoid some warnings from "gcc -Wshadow".
222 This file doesn't use the exp() and remainder() functions. */ 255 This file doesn't use the exp() and remainder() functions. */
223#undef exp 256#undef exp
@@ -225,7 +258,7 @@
225#undef remainder 258#undef remainder
226#define remainder rem 259#define remainder rem
227 260
228#if (!USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF) && !WIDE_CHAR_VERSION 261#if (!USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || (PTRDIFF_MAX > INT_MAX)) && !WIDE_CHAR_VERSION
229# if (HAVE_STRNLEN && !defined _AIX) 262# if (HAVE_STRNLEN && !defined _AIX)
230# define local_strnlen strnlen 263# define local_strnlen strnlen
231# else 264# else
@@ -241,7 +274,7 @@ local_strnlen (const char *string, size_t maxlen)
241# endif 274# endif
242#endif 275#endif
243 276
244#if (((!USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF) && WIDE_CHAR_VERSION) || ((!USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || (NEED_PRINTF_DIRECTIVE_LS && !defined IN_LIBINTL)) && !WIDE_CHAR_VERSION && DCHAR_IS_TCHAR)) && HAVE_WCHAR_T 277#if ((!USE_SNPRINTF || WIDE_CHAR_VERSION || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || (PTRDIFF_MAX > INT_MAX) || !DCHAR_IS_TCHAR || NEED_WPRINTF_DIRECTIVE_LC) && WIDE_CHAR_VERSION) || ((!USE_SNPRINTF || (PTRDIFF_MAX > INT_MAX) || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || NEED_PRINTF_DIRECTIVE_LS) && !WIDE_CHAR_VERSION && DCHAR_IS_TCHAR)
245# if HAVE_WCSLEN 278# if HAVE_WCSLEN
246# define local_wcslen wcslen 279# define local_wcslen wcslen
247# else 280# else
@@ -264,8 +297,8 @@ local_wcslen (const wchar_t *s)
264# endif 297# endif
265#endif 298#endif
266 299
267#if (!USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF) && HAVE_WCHAR_T && WIDE_CHAR_VERSION 300#if (!USE_SNPRINTF || (WIDE_CHAR_VERSION && DCHAR_IS_TCHAR) || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF) && WIDE_CHAR_VERSION
268# if HAVE_WCSNLEN 301# if HAVE_WCSNLEN && HAVE_DECL_WCSNLEN
269# define local_wcsnlen wcsnlen 302# define local_wcsnlen wcsnlen
270# else 303# else
271# ifndef local_wcsnlen_defined 304# ifndef local_wcsnlen_defined
@@ -283,12 +316,12 @@ local_wcsnlen (const wchar_t *s, size_t maxlen)
283# endif 316# endif
284#endif 317#endif
285 318
286#if (((!USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || (NEED_PRINTF_DIRECTIVE_LS && !defined IN_LIBINTL) || ENABLE_WCHAR_FALLBACK) && HAVE_WCHAR_T) || (ENABLE_WCHAR_FALLBACK && HAVE_WINT_T)) && !WIDE_CHAR_VERSION 319#if ((!USE_SNPRINTF || (PTRDIFF_MAX > INT_MAX) || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || NEED_PRINTF_DIRECTIVE_LS || ENABLE_WCHAR_FALLBACK) || ((NEED_PRINTF_DIRECTIVE_LC || ENABLE_WCHAR_FALLBACK) && HAVE_WINT_T)) && !WIDE_CHAR_VERSION
287# if ENABLE_WCHAR_FALLBACK 320# if ENABLE_WCHAR_FALLBACK
288static size_t 321static size_t
289wctomb_fallback (char *s, wchar_t wc) 322wctomb_fallback (char *s, wchar_t wc)
290{ 323{
291 static char hex[16] = "0123456789ABCDEF"; 324 static char const hex[16] = "0123456789ABCDEF";
292 325
293 s[0] = '\\'; 326 s[0] = '\\';
294 if (sizeof (wchar_t) > 2 && wc > 0xffff) 327 if (sizeof (wchar_t) > 2 && wc > 0xffff)
@@ -351,7 +384,7 @@ local_wctomb (char *s, wchar_t wc)
351# endif 384# endif
352#endif 385#endif
353 386
354#if (NEED_PRINTF_DIRECTIVE_A || NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_INFINITE_LONG_DOUBLE || NEED_PRINTF_DOUBLE || NEED_PRINTF_INFINITE_DOUBLE) && !defined IN_LIBINTL 387#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)
355/* Determine the decimal-point character according to the current locale. */ 388/* Determine the decimal-point character according to the current locale. */
356# ifndef decimal_point_char_defined 389# ifndef decimal_point_char_defined
357# define decimal_point_char_defined 1 390# define decimal_point_char_defined 1
@@ -378,7 +411,218 @@ decimal_point_char (void)
378# endif 411# endif
379#endif 412#endif
380 413
381#if NEED_PRINTF_INFINITE_DOUBLE && !NEED_PRINTF_DOUBLE && !defined IN_LIBINTL 414#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))
415/* Determine the thousands-separator character according to the current
416 locale.
417 It is a single multibyte character.
418 In glibc: 35x ".", 90x ",", 23x U+202F, 1x U+2019, 1x U+066C, on other
419 systems also U+00A0. */
420# ifndef thousands_separator_char_defined
421# define thousands_separator_char_defined 1
422static const char *
423thousands_separator_char (char stackbuf[10])
424{
425 /* Determine it in a multithread-safe way.
426 We know nl_langinfo is multithread-safe on glibc systems, on Mac OS X
427 systems, and on NetBSD, but is not required to be multithread-safe by
428 POSIX.
429 localeconv() is not guaranteed to be multithread-safe by POSIX either;
430 however, on native Windows it is (cf. test-localeconv-mt).
431 sprintf(), however, is multithread-safe. */
432# if HAVE_NL_LANGINFO && (__GLIBC__ || defined __UCLIBC__ || (defined __APPLE__ && defined __MACH__) || defined __NetBSD__)
433 return nl_langinfo (THOUSEP);
434# elif defined _WIN32 && !defined __CYGWIN__
435 return localeconv () -> thousands_sep;
436# else
437 sprintf (stackbuf, "%'.0f", 1000.0);
438 /* Now stackbuf = "1<thousep>000". */
439 stackbuf[strlen (stackbuf) - 3] = '\0';
440# if defined __sun
441 /* Solaris specific hack: Replace wrong result (0xC2 means U+00A0). */
442 if (strcmp (&stackbuf[1], "\302") == 0)
443 strcpy (&stackbuf[1], MB_CUR_MAX > 1 ? "\302\240" : "\240");
444# endif
445 return &stackbuf[1];
446# endif
447}
448# endif
449#endif
450#if !WIDE_CHAR_VERSION && defined DCHAR_CONV_FROM_ENCODING && (NEED_PRINTF_DOUBLE || NEED_PRINTF_LONG_DOUBLE)
451/* Determine the thousands-separator character, as a DCHAR_T[] array,
452 according to the current locale.
453 It is a single Unicode character. */
454# ifndef thousands_separator_DCHAR_defined
455# define thousands_separator_DCHAR_defined 1
456static const DCHAR_T *
457thousands_separator_DCHAR (DCHAR_T stackbuf[10])
458{
459 /* Determine it in a multithread-safe way. */
460 char tmpbuf[10];
461 const char *tmp = thousands_separator_char (tmpbuf);
462 if (*tmp != '\0')
463 {
464 /* Convert it from char[] to DCHAR_T[]. */
465 size_t converted_len = 10;
466 DCHAR_T *converted =
467 DCHAR_CONV_FROM_ENCODING (locale_charset (),
468 iconveh_question_mark,
469 tmp, strlen (tmp) + 1,
470 NULL,
471 stackbuf, &converted_len);
472 if (converted != NULL)
473 {
474 if (converted != stackbuf)
475 /* It should not be so long. */
476 abort ();
477 return stackbuf;
478 }
479 }
480 stackbuf[0] = 0;
481 return stackbuf;
482}
483# endif
484#endif
485/* Maximum number of 'char' in the char[] or DCHAR_T[] representation of the
486 thousands separator. */
487#define THOUSEP_CHAR_MAXLEN 3
488
489#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))
490/* Determine the thousands-separator character, as a wide character, according
491 to the current locale.
492 It is a single wide character. */
493# ifndef thousands_separator_wchar_defined
494# define thousands_separator_wchar_defined 1
495static const wchar_t *
496thousands_separator_wchar (wchar_t stackbuf[10])
497{
498# if __GLIBC__ >= 2 || defined __CYGWIN__
499 /* On glibc, in the unibyte locale fr_FR, the *wprintf routines use U+202F
500 as separator, which cannot be represented in the locale encoding. */
501 stackbuf[0] =
502 (wchar_t) (unsigned long) nl_langinfo (_NL_NUMERIC_THOUSANDS_SEP_WC);
503 stackbuf[1] = L'\0';
504 return stackbuf;
505# elif defined _WIN32 && !defined __CYGWIN__
506 const char *tmp = localeconv () -> thousands_sep;
507 if (*tmp != '\0')
508 {
509 mbstate_t state;
510 mbszero (&state);
511 if ((int) mbrtowc (&stackbuf[0], tmp, strlen (tmp), &state) > 0)
512 stackbuf[1] = L'\0';
513 else
514 stackbuf[0] = L'\0';
515 }
516 else
517 stackbuf[0] = L'\0';
518 return stackbuf;
519# elif defined __sun
520 /* Use sprintf, because swprintf retrieves a wrong value for the
521 thousands-separator wide character (e.g. (wchar_t) 0xffffffa0). */
522 char tmp[10];
523 sprintf (tmp, "%'.0f", 1000.0);
524 /* Now tmp = L"1<thousep>000". */
525 tmp[strlen (tmp) - 3] = '\0';
526 /* Solaris specific hack: Replace wrong result (0xC2 means U+00A0). */
527 if (strcmp (&tmp[1], "\302") == 0)
528 strcpy (&tmp[1], MB_CUR_MAX > 1 ? "\302\240" : "\240");
529 if (tmp[1] != '\0')
530 {
531 mbstate_t state;
532 mbszero (&state);
533 if ((int) mbrtowc (&stackbuf[0], &tmp[1], strlen (&tmp[1]), &state) > 0)
534 stackbuf[1] = L'\0';
535 else
536 stackbuf[0] = L'\0';
537 }
538 else
539 stackbuf[0] = L'\0';
540 return stackbuf;
541# else
542 swprintf (stackbuf, 10, L"%'.0f", 1000.0);
543 /* Now stackbuf = L"1<thousep>000". */
544 stackbuf[local_wcslen (stackbuf) - 3] = '\0';
545 return &stackbuf[1];
546# endif
547}
548# endif
549#endif
550/* Maximum number of 'wchar_t' in the wchar_t[] representation of the thousands
551 separator. */
552#define THOUSEP_WCHAR_MAXLEN 1
553
554#if (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)
555# ifndef grouping_rule_defined
556# define grouping_rule_defined 1
557/* Determine the grouping rule.
558 * As specified in POSIX
559 * <https://pubs.opengroup.org/onlinepubs/9799919799/functions/localeconv.html>
560 * <https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/V1_chap07.html#tag_07_03_04>
561 * it is a string whose elements are 'signed char' values, where
562 * "Each integer specifies the number of digits in each group, with the initial
563 * integer defining the size of the group immediately preceding the decimal
564 * delimiter, and the following integers defining the preceding groups. If
565 * the last integer is not -1, then the size of the previous group (if any)
566 * shall be repeatedly used for the remainder of the digits. If the last
567 * integer is -1, then no further grouping shall be performed."
568 * Platforms that have locales with grouping:
569 * glibc, FreeBSD, NetBSD, AIX, Solaris, Cygwin, Haiku.
570 * Platforms that don't:
571 * musl libc, macOS, OpenBSD, Android, mingw, MSVC.
572 * Typical grouping rules on glibc:
573 * 136x 3 (fr_FR etc.)
574 * 4x 4 (cmn_TW etc.)
575 * 9x 3;2 (ta_IN etc.)
576 * 1x 2;2;2;3 (umn_US)
577 * 21x -1 (C etc.)
578 */
579static const signed char *
580grouping_rule (void)
581{
582 /* We know nl_langinfo is multithread-safe on glibc systems and on Cygwin,
583 but is not required to be multithread-safe by POSIX.
584 localeconv() is not guaranteed to be multithread-safe by POSIX either;
585 however, on all known systems it is (cf. test-localeconv-mt). */
586# if __GLIBC__ >= 2
587 return (const signed char *) nl_langinfo (GROUPING);
588# elif defined __CYGWIN__
589 return (const signed char *) nl_langinfo (_NL_NUMERIC_GROUPING);
590# else
591 return (const signed char *) localeconv () -> grouping;
592# endif
593}
594/* Determines the number of thousands-separators to be inserted in a digit
595 sequence with ndigits digits (before the decimal point). */
596static size_t
597num_thousands_separators (const signed char *grouping, size_t ndigits)
598{
599 const signed char *g = grouping;
600 int h = *g;
601 if (h <= 0 || ndigits == 0)
602 return 0;
603 size_t insert = 0;
604 for (;;)
605 {
606 /* Invariant: here h == *g, h > 0, ndigits > 0. */
607 if (g[1] == 0)
608 /* h repeats endlessly. */
609 return insert + (ndigits - 1) / h;
610 /* h does not repeat. */
611 if (ndigits <= h)
612 return insert;
613 ndigits -= h;
614 insert++;
615 g++;
616 h = *g;
617 if (h < 0)
618 /* No further grouping. */
619 return insert;
620 }
621}
622# endif
623#endif
624
625#if NEED_PRINTF_INFINITE_DOUBLE && !NEED_PRINTF_DOUBLE
382 626
383/* Equivalent to !isfinite(x) || x == 0, but does not require libm. */ 627/* Equivalent to !isfinite(x) || x == 0, but does not require libm. */
384static int 628static int
@@ -389,7 +633,7 @@ is_infinite_or_zero (double x)
389 633
390#endif 634#endif
391 635
392#if NEED_PRINTF_INFINITE_LONG_DOUBLE && !NEED_PRINTF_LONG_DOUBLE && !defined IN_LIBINTL 636#if NEED_PRINTF_INFINITE_LONG_DOUBLE && !NEED_PRINTF_LONG_DOUBLE
393 637
394/* Equivalent to !isfinite(x) || x == 0, but does not require libm. */ 638/* Equivalent to !isfinite(x) || x == 0, but does not require libm. */
395static int 639static int
@@ -400,7 +644,44 @@ is_infinite_or_zerol (long double x)
400 644
401#endif 645#endif
402 646
403#if (NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_DOUBLE) && !defined IN_LIBINTL 647#if NEED_PRINTF_LONG_DOUBLE
648
649/* Like frexpl, except that it supports even "unsupported" numbers. */
650# if (LDBL_MANT_DIG == 64 && (defined __ia64 || (defined __x86_64__ || defined __amd64__) || (defined __i386 || defined __i386__ || defined _I386 || defined _M_IX86 || defined _X86_))) && (defined __APPLE__ && defined __MACH__)
651/* Don't assume that frexpl can handle pseudo-denormals; it does not on
652 macOS 12/x86_64. Therefore test for a pseudo-denormal explicitly. */
653
654static
655long double safe_frexpl (long double x, int *exp)
656{
657 union
658 {
659 long double value;
660 struct { unsigned int mant_word[2]; unsigned short sign_exp_word; } r;
661 }
662 u;
663 u.value = x;
664 if (u.r.sign_exp_word == 0 && (u.r.mant_word[1] & 0x80000000u) != 0)
665 {
666 /* Pseudo-Denormal. */
667 *exp = LDBL_MIN_EXP;
668 u.r.sign_exp_word = 1 - LDBL_MIN_EXP;
669 return u.value;
670 }
671 else
672 return frexpl (x, exp);
673}
674
675# else
676# define safe_frexpl frexpl
677# endif
678
679#endif
680
681#if NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_DOUBLE
682
683/* An indicator for a failed memory allocation. */
684# define NOMEM_PTR ((void *) (-1))
404 685
405/* Converting 'long double' to decimal without rare rounding bugs requires 686/* Converting 'long double' to decimal without rare rounding bugs requires
406 real bignums. We use the naming conventions of GNU gmp, but vastly simpler 687 real bignums. We use the naming conventions of GNU gmp, but vastly simpler
@@ -422,8 +703,8 @@ typedef struct
422} mpn_t; 703} mpn_t;
423 704
424/* Compute the product of two bignums >= 0. 705/* Compute the product of two bignums >= 0.
425 Return the allocated memory in case of success, NULL in case of memory 706 Return the allocated memory (possibly NULL) in case of success, NOMEM_PTR
426 allocation failure. */ 707 in case of memory allocation failure. */
427static void * 708static void *
428multiply (mpn_t src1, mpn_t src2, mpn_t *dest) 709multiply (mpn_t src1, mpn_t src2, mpn_t *dest)
429{ 710{
@@ -451,7 +732,7 @@ multiply (mpn_t src1, mpn_t src2, mpn_t *dest)
451 { 732 {
452 /* src1 or src2 is zero. */ 733 /* src1 or src2 is zero. */
453 dest->nlimbs = 0; 734 dest->nlimbs = 0;
454 dest->limbs = (mp_limb_t *) malloc (1); 735 dest->limbs = NULL;
455 } 736 }
456 else 737 else
457 { 738 {
@@ -463,7 +744,7 @@ multiply (mpn_t src1, mpn_t src2, mpn_t *dest)
463 dlen = len1 + len2; 744 dlen = len1 + len2;
464 dp = (mp_limb_t *) malloc (dlen * sizeof (mp_limb_t)); 745 dp = (mp_limb_t *) malloc (dlen * sizeof (mp_limb_t));
465 if (dp == NULL) 746 if (dp == NULL)
466 return NULL; 747 return NOMEM_PTR;
467 for (k = len2; k > 0; ) 748 for (k = len2; k > 0; )
468 dp[--k] = 0; 749 dp[--k] = 0;
469 for (i = 0; i < len1; i++) 750 for (i = 0; i < len1; i++)
@@ -494,8 +775,8 @@ multiply (mpn_t src1, mpn_t src2, mpn_t *dest)
494 the remainder. 775 the remainder.
495 Finally, round-to-even is performed: If r > b/2 or if r = b/2 and q is odd, 776 Finally, round-to-even is performed: If r > b/2 or if r = b/2 and q is odd,
496 q is incremented. 777 q is incremented.
497 Return the allocated memory in case of success, NULL in case of memory 778 Return the allocated memory (possibly NULL) in case of success, NOMEM_PTR
498 allocation failure. */ 779 in case of memory allocation failure. */
499static void * 780static void *
500divide (mpn_t a, mpn_t b, mpn_t *q) 781divide (mpn_t a, mpn_t b, mpn_t *q)
501{ 782{
@@ -566,7 +847,7 @@ divide (mpn_t a, mpn_t b, mpn_t *q)
566 final rounding of q.) */ 847 final rounding of q.) */
567 roomptr = (mp_limb_t *) malloc ((a_len + 2) * sizeof (mp_limb_t)); 848 roomptr = (mp_limb_t *) malloc ((a_len + 2) * sizeof (mp_limb_t));
568 if (roomptr == NULL) 849 if (roomptr == NULL)
569 return NULL; 850 return NOMEM_PTR;
570 851
571 /* Normalise a. */ 852 /* Normalise a. */
572 while (a_len > 0 && a_ptr[a_len - 1] == 0) 853 while (a_len > 0 && a_ptr[a_len - 1] == 0)
@@ -702,7 +983,7 @@ divide (mpn_t a, mpn_t b, mpn_t *q)
702 if (tmp_roomptr == NULL) 983 if (tmp_roomptr == NULL)
703 { 984 {
704 free (roomptr); 985 free (roomptr);
705 return NULL; 986 return NOMEM_PTR;
706 } 987 }
707 { 988 {
708 const mp_limb_t *sourceptr = b_ptr; 989 const mp_limb_t *sourceptr = b_ptr;
@@ -921,6 +1202,14 @@ divide (mpn_t a, mpn_t b, mpn_t *q)
921 return roomptr; 1202 return roomptr;
922} 1203}
923 1204
1205/* Avoid pointless GCC warning "argument 1 value '18446744073709551615' exceeds
1206 maximum object size 9223372036854775807", triggered by the use of xsum as
1207 argument of malloc. */
1208# if _GL_GNUC_PREREQ (7, 0)
1209# pragma GCC diagnostic push
1210# pragma GCC diagnostic ignored "-Walloc-size-larger-than="
1211# endif
1212
924/* Convert a bignum a >= 0, multiplied with 10^extra_zeroes, to decimal 1213/* Convert a bignum a >= 0, multiplied with 10^extra_zeroes, to decimal
925 representation. 1214 representation.
926 Destroys the contents of a. 1215 Destroys the contents of a.
@@ -977,6 +1266,10 @@ convert_to_decimal (mpn_t a, size_t extra_zeroes)
977 return c_ptr; 1266 return c_ptr;
978} 1267}
979 1268
1269# if _GL_GNUC_PREREQ (7, 0)
1270# pragma GCC diagnostic pop
1271# endif
1272
980# if NEED_PRINTF_LONG_DOUBLE 1273# if NEED_PRINTF_LONG_DOUBLE
981 1274
982/* Assuming x is finite and >= 0: 1275/* Assuming x is finite and >= 0:
@@ -997,7 +1290,7 @@ decode_long_double (long double x, int *ep, mpn_t *mp)
997 if (m.limbs == NULL) 1290 if (m.limbs == NULL)
998 return NULL; 1291 return NULL;
999 /* Split into exponential part and mantissa. */ 1292 /* Split into exponential part and mantissa. */
1000 y = frexpl (x, &exp); 1293 y = safe_frexpl (x, &exp);
1001 if (!(y >= 0.0L && y < 1.0L)) 1294 if (!(y >= 0.0L && y < 1.0L))
1002 abort (); 1295 abort ();
1003 /* x = 2^exp * y = 2^(exp - LDBL_MANT_BIT) * (y * 2^LDBL_MANT_BIT), and the 1296 /* x = 2^exp * y = 2^(exp - LDBL_MANT_BIT) * (y * 2^LDBL_MANT_BIT), and the
@@ -1171,8 +1464,6 @@ scale10_round_decimal_decoded (int e, mpn_t m, void *memory, int n)
1171 void *z_memory; 1464 void *z_memory;
1172 char *digits; 1465 char *digits;
1173 1466
1174 if (memory == NULL)
1175 return NULL;
1176 /* x = 2^e * m, hence 1467 /* x = 2^e * m, hence
1177 y = round (2^e * 10^n * m) = round (2^(e+n) * 5^n * m) 1468 y = round (2^e * 10^n * m) = round (2^(e+n) * 5^n * m)
1178 = round (2^s * 5^n * m). */ 1469 = round (2^s * 5^n * m). */
@@ -1290,7 +1581,7 @@ scale10_round_decimal_decoded (int e, mpn_t m, void *memory, int n)
1290 mpn_t denominator; 1581 mpn_t denominator;
1291 void *tmp_memory; 1582 void *tmp_memory;
1292 tmp_memory = multiply (m, pow5, &numerator); 1583 tmp_memory = multiply (m, pow5, &numerator);
1293 if (tmp_memory == NULL) 1584 if (tmp_memory == NOMEM_PTR)
1294 { 1585 {
1295 free (pow5_ptr); 1586 free (pow5_ptr);
1296 free (memory); 1587 free (memory);
@@ -1363,7 +1654,7 @@ scale10_round_decimal_decoded (int e, mpn_t m, void *memory, int n)
1363 1654
1364 /* Here y = round (x * 10^n) = z * 10^extra_zeroes. */ 1655 /* Here y = round (x * 10^n) = z * 10^extra_zeroes. */
1365 1656
1366 if (z_memory == NULL) 1657 if (z_memory == NOMEM_PTR)
1367 return NULL; 1658 return NULL;
1368 digits = convert_to_decimal (z, extra_zeroes); 1659 digits = convert_to_decimal (z, extra_zeroes);
1369 free (z_memory); 1660 free (z_memory);
@@ -1380,10 +1671,13 @@ scale10_round_decimal_decoded (int e, mpn_t m, void *memory, int n)
1380static char * 1671static char *
1381scale10_round_decimal_long_double (long double x, int n) 1672scale10_round_decimal_long_double (long double x, int n)
1382{ 1673{
1383 int e IF_LINT(= 0); 1674 int e;
1384 mpn_t m; 1675 mpn_t m;
1385 void *memory = decode_long_double (x, &e, &m); 1676 void *memory = decode_long_double (x, &e, &m);
1386 return scale10_round_decimal_decoded (e, m, memory, n); 1677 if (memory != NULL)
1678 return scale10_round_decimal_decoded (e, m, memory, n);
1679 else
1680 return NULL;
1387} 1681}
1388 1682
1389# endif 1683# endif
@@ -1398,10 +1692,13 @@ scale10_round_decimal_long_double (long double x, int n)
1398static char * 1692static char *
1399scale10_round_decimal_double (double x, int n) 1693scale10_round_decimal_double (double x, int n)
1400{ 1694{
1401 int e IF_LINT(= 0); 1695 int e;
1402 mpn_t m; 1696 mpn_t m;
1403 void *memory = decode_double (x, &e, &m); 1697 void *memory = decode_double (x, &e, &m);
1404 return scale10_round_decimal_decoded (e, m, memory, n); 1698 if (memory != NULL)
1699 return scale10_round_decimal_decoded (e, m, memory, n);
1700 else
1701 return NULL;
1405} 1702}
1406 1703
1407# endif 1704# endif
@@ -1420,7 +1717,7 @@ floorlog10l (long double x)
1420 double l; 1717 double l;
1421 1718
1422 /* Split into exponential part and mantissa. */ 1719 /* Split into exponential part and mantissa. */
1423 y = frexpl (x, &exp); 1720 y = safe_frexpl (x, &exp);
1424 if (!(y >= 0.0L && y < 1.0L)) 1721 if (!(y >= 0.0L && y < 1.0L))
1425 abort (); 1722 abort ();
1426 if (y == 0.0L) 1723 if (y == 0.0L)
@@ -1604,7 +1901,7 @@ is_borderline (const char *digits, size_t precision)
1604 1901
1605#endif 1902#endif
1606 1903
1607#if !USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF 1904#if !USE_SNPRINTF || (WIDE_CHAR_VERSION && DCHAR_IS_TCHAR) || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF
1608 1905
1609/* Use a different function name, to make it possible that the 'wchar_t' 1906/* Use a different function name, to make it possible that the 'wchar_t'
1610 parametrization and the 'char' parametrization get compiled in the same 1907 parametrization and the 'char' parametrization get compiled in the same
@@ -1627,51 +1924,323 @@ MAX_ROOM_NEEDED (const arguments *ap, size_t arg_index, FCHAR_T conversion,
1627 switch (conversion) 1924 switch (conversion)
1628 { 1925 {
1629 case 'd': case 'i': case 'u': 1926 case 'd': case 'i': case 'u':
1630 if (type == TYPE_LONGLONGINT || type == TYPE_ULONGLONGINT) 1927 switch (type)
1631 tmp_length = 1928 {
1632 (unsigned int) (sizeof (unsigned long long) * CHAR_BIT 1929 default:
1633 * 0.30103 /* binary -> decimal */ 1930 tmp_length =
1634 ) 1931 (unsigned int) (sizeof (unsigned int) * CHAR_BIT
1635 + 1; /* turn floor into ceil */ 1932 * 0.30103 /* binary -> decimal */
1636 else if (type == TYPE_LONGINT || type == TYPE_ULONGINT) 1933 )
1637 tmp_length = 1934 + 1; /* turn floor into ceil */
1638 (unsigned int) (sizeof (unsigned long) * CHAR_BIT 1935 break;
1639 * 0.30103 /* binary -> decimal */ 1936 case TYPE_LONGINT:
1640 ) 1937 tmp_length =
1641 + 1; /* turn floor into ceil */ 1938 (unsigned int) (sizeof (long int) * CHAR_BIT
1642 else 1939 * 0.30103 /* binary -> decimal */
1643 tmp_length = 1940 )
1644 (unsigned int) (sizeof (unsigned int) * CHAR_BIT 1941 + 1; /* turn floor into ceil */
1645 * 0.30103 /* binary -> decimal */ 1942 break;
1646 ) 1943 case TYPE_ULONGINT:
1647 + 1; /* turn floor into ceil */ 1944 tmp_length =
1945 (unsigned int) (sizeof (unsigned long int) * CHAR_BIT
1946 * 0.30103 /* binary -> decimal */
1947 )
1948 + 1; /* turn floor into ceil */
1949 break;
1950 case TYPE_LONGLONGINT:
1951 tmp_length =
1952 (unsigned int) (sizeof (long long int) * CHAR_BIT
1953 * 0.30103 /* binary -> decimal */
1954 )
1955 + 1; /* turn floor into ceil */
1956 break;
1957 case TYPE_ULONGLONGINT:
1958 tmp_length =
1959 (unsigned int) (sizeof (unsigned long long int) * CHAR_BIT
1960 * 0.30103 /* binary -> decimal */
1961 )
1962 + 1; /* turn floor into ceil */
1963 break;
1964 case TYPE_INT8_T:
1965 tmp_length =
1966 (unsigned int) (sizeof (int8_t) * CHAR_BIT
1967 * 0.30103 /* binary -> decimal */
1968 )
1969 + 1; /* turn floor into ceil */
1970 break;
1971 case TYPE_UINT8_T:
1972 tmp_length =
1973 (unsigned int) (sizeof (uint8_t) * CHAR_BIT
1974 * 0.30103 /* binary -> decimal */
1975 )
1976 + 1; /* turn floor into ceil */
1977 break;
1978 case TYPE_INT16_T:
1979 tmp_length =
1980 (unsigned int) (sizeof (int16_t) * CHAR_BIT
1981 * 0.30103 /* binary -> decimal */
1982 )
1983 + 1; /* turn floor into ceil */
1984 break;
1985 case TYPE_UINT16_T:
1986 tmp_length =
1987 (unsigned int) (sizeof (uint16_t) * CHAR_BIT
1988 * 0.30103 /* binary -> decimal */
1989 )
1990 + 1; /* turn floor into ceil */
1991 break;
1992 case TYPE_INT32_T:
1993 tmp_length =
1994 (unsigned int) (sizeof (int32_t) * CHAR_BIT
1995 * 0.30103 /* binary -> decimal */
1996 )
1997 + 1; /* turn floor into ceil */
1998 break;
1999 case TYPE_UINT32_T:
2000 tmp_length =
2001 (unsigned int) (sizeof (uint32_t) * CHAR_BIT
2002 * 0.30103 /* binary -> decimal */
2003 )
2004 + 1; /* turn floor into ceil */
2005 break;
2006 case TYPE_INT64_T:
2007 tmp_length =
2008 (unsigned int) (sizeof (int64_t) * CHAR_BIT
2009 * 0.30103 /* binary -> decimal */
2010 )
2011 + 1; /* turn floor into ceil */
2012 break;
2013 case TYPE_UINT64_T:
2014 tmp_length =
2015 (unsigned int) (sizeof (uint64_t) * CHAR_BIT
2016 * 0.30103 /* binary -> decimal */
2017 )
2018 + 1; /* turn floor into ceil */
2019 break;
2020 case TYPE_INT_FAST8_T:
2021 tmp_length =
2022 (unsigned int) (sizeof (int_fast8_t) * CHAR_BIT
2023 * 0.30103 /* binary -> decimal */
2024 )
2025 + 1; /* turn floor into ceil */
2026 break;
2027 case TYPE_UINT_FAST8_T:
2028 tmp_length =
2029 (unsigned int) (sizeof (uint_fast8_t) * CHAR_BIT
2030 * 0.30103 /* binary -> decimal */
2031 )
2032 + 1; /* turn floor into ceil */
2033 break;
2034 case TYPE_INT_FAST16_T:
2035 tmp_length =
2036 (unsigned int) (sizeof (int_fast16_t) * CHAR_BIT
2037 * 0.30103 /* binary -> decimal */
2038 )
2039 + 1; /* turn floor into ceil */
2040 break;
2041 case TYPE_UINT_FAST16_T:
2042 tmp_length =
2043 (unsigned int) (sizeof (uint_fast16_t) * CHAR_BIT
2044 * 0.30103 /* binary -> decimal */
2045 )
2046 + 1; /* turn floor into ceil */
2047 break;
2048 case TYPE_INT_FAST32_T:
2049 tmp_length =
2050 (unsigned int) (sizeof (int_fast32_t) * CHAR_BIT
2051 * 0.30103 /* binary -> decimal */
2052 )
2053 + 1; /* turn floor into ceil */
2054 break;
2055 case TYPE_UINT_FAST32_T:
2056 tmp_length =
2057 (unsigned int) (sizeof (uint_fast32_t) * CHAR_BIT
2058 * 0.30103 /* binary -> decimal */
2059 )
2060 + 1; /* turn floor into ceil */
2061 break;
2062 case TYPE_INT_FAST64_T:
2063 tmp_length =
2064 (unsigned int) (sizeof (int_fast64_t) * CHAR_BIT
2065 * 0.30103 /* binary -> decimal */
2066 )
2067 + 1; /* turn floor into ceil */
2068 break;
2069 case TYPE_UINT_FAST64_T:
2070 tmp_length =
2071 (unsigned int) (sizeof (uint_fast64_t) * CHAR_BIT
2072 * 0.30103 /* binary -> decimal */
2073 )
2074 + 1; /* turn floor into ceil */
2075 break;
2076 }
1648 if (tmp_length < precision) 2077 if (tmp_length < precision)
1649 tmp_length = precision; 2078 tmp_length = precision;
1650 /* Multiply by 2, as an estimate for FLAG_GROUP. */ 2079 /* Account for thousands separators. */
1651 tmp_length = xsum (tmp_length, tmp_length); 2080 if (flags & FLAG_GROUP)
2081 {
2082 /* A thousands separator needs to be inserted at most every 2 digits.
2083 This is the case in the ta_IN locale. */
2084# if WIDE_CHAR_VERSION
2085 tmp_length = xsum (tmp_length, tmp_length / 2 * THOUSEP_WCHAR_MAXLEN);
2086# else
2087 tmp_length = xsum (tmp_length, tmp_length / 2 * THOUSEP_CHAR_MAXLEN);
2088# endif
2089 }
1652 /* Add 1, to account for a leading sign. */ 2090 /* Add 1, to account for a leading sign. */
1653 tmp_length = xsum (tmp_length, 1); 2091 tmp_length = xsum (tmp_length, 1);
1654 break; 2092 break;
1655 2093
2094 case 'b':
2095 #if SUPPORT_GNU_PRINTF_DIRECTIVES \
2096 || (__GLIBC__ + (__GLIBC_MINOR__ >= 35) > 2)
2097 case 'B':
2098 #endif
2099 switch (type)
2100 {
2101 default:
2102 tmp_length =
2103 (unsigned int) (sizeof (unsigned int) * CHAR_BIT)
2104 + 1; /* turn floor into ceil */
2105 break;
2106 case TYPE_ULONGINT:
2107 tmp_length =
2108 (unsigned int) (sizeof (unsigned long int) * CHAR_BIT)
2109 + 1; /* turn floor into ceil */
2110 break;
2111 case TYPE_ULONGLONGINT:
2112 tmp_length =
2113 (unsigned int) (sizeof (unsigned long long int) * CHAR_BIT)
2114 + 1; /* turn floor into ceil */
2115 break;
2116 case TYPE_UINT8_T:
2117 tmp_length =
2118 (unsigned int) (sizeof (uint8_t) * CHAR_BIT)
2119 + 1; /* turn floor into ceil */
2120 break;
2121 case TYPE_UINT16_T:
2122 tmp_length =
2123 (unsigned int) (sizeof (uint16_t) * CHAR_BIT)
2124 + 1; /* turn floor into ceil */
2125 break;
2126 case TYPE_UINT32_T:
2127 tmp_length =
2128 (unsigned int) (sizeof (uint32_t) * CHAR_BIT)
2129 + 1; /* turn floor into ceil */
2130 break;
2131 case TYPE_UINT64_T:
2132 tmp_length =
2133 (unsigned int) (sizeof (uint64_t) * CHAR_BIT)
2134 + 1; /* turn floor into ceil */
2135 break;
2136 case TYPE_UINT_FAST8_T:
2137 tmp_length =
2138 (unsigned int) (sizeof (uint_fast8_t) * CHAR_BIT)
2139 + 1; /* turn floor into ceil */
2140 break;
2141 case TYPE_UINT_FAST16_T:
2142 tmp_length =
2143 (unsigned int) (sizeof (uint_fast16_t) * CHAR_BIT)
2144 + 1; /* turn floor into ceil */
2145 break;
2146 case TYPE_UINT_FAST32_T:
2147 tmp_length =
2148 (unsigned int) (sizeof (uint_fast32_t) * CHAR_BIT)
2149 + 1; /* turn floor into ceil */
2150 break;
2151 case TYPE_UINT_FAST64_T:
2152 tmp_length =
2153 (unsigned int) (sizeof (uint_fast64_t) * CHAR_BIT)
2154 + 1; /* turn floor into ceil */
2155 break;
2156 }
2157 if (tmp_length < precision)
2158 tmp_length = precision;
2159 /* Add 2, to account for a prefix from the alternate form. */
2160 tmp_length = xsum (tmp_length, 2);
2161 break;
2162
1656 case 'o': 2163 case 'o':
1657 if (type == TYPE_LONGLONGINT || type == TYPE_ULONGLONGINT) 2164 switch (type)
1658 tmp_length = 2165 {
1659 (unsigned int) (sizeof (unsigned long long) * CHAR_BIT 2166 default:
1660 * 0.333334 /* binary -> octal */ 2167 tmp_length =
1661 ) 2168 (unsigned int) (sizeof (unsigned int) * CHAR_BIT
1662 + 1; /* turn floor into ceil */ 2169 * 0.333334 /* binary -> octal */
1663 else if (type == TYPE_LONGINT || type == TYPE_ULONGINT) 2170 )
1664 tmp_length = 2171 + 1; /* turn floor into ceil */
1665 (unsigned int) (sizeof (unsigned long) * CHAR_BIT 2172 break;
1666 * 0.333334 /* binary -> octal */ 2173 case TYPE_ULONGINT:
1667 ) 2174 tmp_length =
1668 + 1; /* turn floor into ceil */ 2175 (unsigned int) (sizeof (unsigned long int) * CHAR_BIT
1669 else 2176 * 0.333334 /* binary -> octal */
1670 tmp_length = 2177 )
1671 (unsigned int) (sizeof (unsigned int) * CHAR_BIT 2178 + 1; /* turn floor into ceil */
1672 * 0.333334 /* binary -> octal */ 2179 break;
1673 ) 2180 case TYPE_ULONGLONGINT:
1674 + 1; /* turn floor into ceil */ 2181 tmp_length =
2182 (unsigned int) (sizeof (unsigned long long int) * CHAR_BIT
2183 * 0.333334 /* binary -> octal */
2184 )
2185 + 1; /* turn floor into ceil */
2186 break;
2187 case TYPE_UINT8_T:
2188 tmp_length =
2189 (unsigned int) (sizeof (uint8_t) * CHAR_BIT
2190 * 0.333334 /* binary -> octal */
2191 )
2192 + 1; /* turn floor into ceil */
2193 break;
2194 case TYPE_UINT16_T:
2195 tmp_length =
2196 (unsigned int) (sizeof (uint16_t) * CHAR_BIT
2197 * 0.333334 /* binary -> octal */
2198 )
2199 + 1; /* turn floor into ceil */
2200 break;
2201 case TYPE_UINT32_T:
2202 tmp_length =
2203 (unsigned int) (sizeof (uint32_t) * CHAR_BIT
2204 * 0.333334 /* binary -> octal */
2205 )
2206 + 1; /* turn floor into ceil */
2207 break;
2208 case TYPE_UINT64_T:
2209 tmp_length =
2210 (unsigned int) (sizeof (uint64_t) * CHAR_BIT
2211 * 0.333334 /* binary -> octal */
2212 )
2213 + 1; /* turn floor into ceil */
2214 break;
2215 case TYPE_UINT_FAST8_T:
2216 tmp_length =
2217 (unsigned int) (sizeof (uint_fast8_t) * CHAR_BIT
2218 * 0.333334 /* binary -> octal */
2219 )
2220 + 1; /* turn floor into ceil */
2221 break;
2222 case TYPE_UINT_FAST16_T:
2223 tmp_length =
2224 (unsigned int) (sizeof (uint_fast16_t) * CHAR_BIT
2225 * 0.333334 /* binary -> octal */
2226 )
2227 + 1; /* turn floor into ceil */
2228 break;
2229 case TYPE_UINT_FAST32_T:
2230 tmp_length =
2231 (unsigned int) (sizeof (uint_fast32_t) * CHAR_BIT
2232 * 0.333334 /* binary -> octal */
2233 )
2234 + 1; /* turn floor into ceil */
2235 break;
2236 case TYPE_UINT_FAST64_T:
2237 tmp_length =
2238 (unsigned int) (sizeof (uint_fast64_t) * CHAR_BIT
2239 * 0.333334 /* binary -> octal */
2240 )
2241 + 1; /* turn floor into ceil */
2242 break;
2243 }
1675 if (tmp_length < precision) 2244 if (tmp_length < precision)
1676 tmp_length = precision; 2245 tmp_length = precision;
1677 /* Add 1, to account for a leading sign. */ 2246 /* Add 1, to account for a leading sign. */
@@ -1679,36 +2248,104 @@ MAX_ROOM_NEEDED (const arguments *ap, size_t arg_index, FCHAR_T conversion,
1679 break; 2248 break;
1680 2249
1681 case 'x': case 'X': 2250 case 'x': case 'X':
1682 if (type == TYPE_LONGLONGINT || type == TYPE_ULONGLONGINT) 2251 switch (type)
1683 tmp_length = 2252 {
1684 (unsigned int) (sizeof (unsigned long long) * CHAR_BIT 2253 default:
1685 * 0.25 /* binary -> hexadecimal */ 2254 tmp_length =
1686 ) 2255 (unsigned int) (sizeof (unsigned int) * CHAR_BIT
1687 + 1; /* turn floor into ceil */ 2256 * 0.25 /* binary -> hexadecimal */
1688 else if (type == TYPE_LONGINT || type == TYPE_ULONGINT) 2257 )
1689 tmp_length = 2258 + 1; /* turn floor into ceil */
1690 (unsigned int) (sizeof (unsigned long) * CHAR_BIT 2259 break;
1691 * 0.25 /* binary -> hexadecimal */ 2260 case TYPE_ULONGINT:
1692 ) 2261 tmp_length =
1693 + 1; /* turn floor into ceil */ 2262 (unsigned int) (sizeof (unsigned long int) * CHAR_BIT
1694 else 2263 * 0.25 /* binary -> hexadecimal */
1695 tmp_length = 2264 )
1696 (unsigned int) (sizeof (unsigned int) * CHAR_BIT 2265 + 1; /* turn floor into ceil */
1697 * 0.25 /* binary -> hexadecimal */ 2266 break;
1698 ) 2267 case TYPE_ULONGLONGINT:
1699 + 1; /* turn floor into ceil */ 2268 tmp_length =
2269 (unsigned int) (sizeof (unsigned long long int) * CHAR_BIT
2270 * 0.25 /* binary -> hexadecimal */
2271 )
2272 + 1; /* turn floor into ceil */
2273 break;
2274 case TYPE_UINT8_T:
2275 tmp_length =
2276 (unsigned int) (sizeof (uint8_t) * CHAR_BIT
2277 * 0.25 /* binary -> hexadecimal */
2278 )
2279 + 1; /* turn floor into ceil */
2280 break;
2281 case TYPE_UINT16_T:
2282 tmp_length =
2283 (unsigned int) (sizeof (uint16_t) * CHAR_BIT
2284 * 0.25 /* binary -> hexadecimal */
2285 )
2286 + 1; /* turn floor into ceil */
2287 break;
2288 case TYPE_UINT32_T:
2289 tmp_length =
2290 (unsigned int) (sizeof (uint32_t) * CHAR_BIT
2291 * 0.25 /* binary -> hexadecimal */
2292 )
2293 + 1; /* turn floor into ceil */
2294 break;
2295 case TYPE_UINT64_T:
2296 tmp_length =
2297 (unsigned int) (sizeof (uint64_t) * CHAR_BIT
2298 * 0.25 /* binary -> hexadecimal */
2299 )
2300 + 1; /* turn floor into ceil */
2301 break;
2302 case TYPE_UINT_FAST8_T:
2303 tmp_length =
2304 (unsigned int) (sizeof (uint_fast8_t) * CHAR_BIT
2305 * 0.25 /* binary -> hexadecimal */
2306 )
2307 + 1; /* turn floor into ceil */
2308 break;
2309 case TYPE_UINT_FAST16_T:
2310 tmp_length =
2311 (unsigned int) (sizeof (uint_fast16_t) * CHAR_BIT
2312 * 0.25 /* binary -> hexadecimal */
2313 )
2314 + 1; /* turn floor into ceil */
2315 break;
2316 case TYPE_UINT_FAST32_T:
2317 tmp_length =
2318 (unsigned int) (sizeof (uint_fast32_t) * CHAR_BIT
2319 * 0.25 /* binary -> hexadecimal */
2320 )
2321 + 1; /* turn floor into ceil */
2322 break;
2323 case TYPE_UINT_FAST64_T:
2324 tmp_length =
2325 (unsigned int) (sizeof (uint_fast64_t) * CHAR_BIT
2326 * 0.25 /* binary -> hexadecimal */
2327 )
2328 + 1; /* turn floor into ceil */
2329 break;
2330 }
1700 if (tmp_length < precision) 2331 if (tmp_length < precision)
1701 tmp_length = precision; 2332 tmp_length = precision;
1702 /* Add 2, to account for a leading sign or alternate form. */ 2333 /* Add 2, to account for a prefix from the alternate form. */
1703 tmp_length = xsum (tmp_length, 2); 2334 tmp_length = xsum (tmp_length, 2);
1704 break; 2335 break;
1705 2336
2337 case 'e': case 'E':
2338 tmp_length =
2339 12; /* sign, decimal point, exponent etc. */
2340 tmp_length = xsum (tmp_length, precision);
2341 break;
2342
1706 case 'f': case 'F': 2343 case 'f': case 'F':
1707 if (type == TYPE_LONGDOUBLE) 2344 if (type == TYPE_LONGDOUBLE)
1708 tmp_length = 2345 tmp_length =
1709 (unsigned int) (LDBL_MAX_EXP 2346 (unsigned int) (LDBL_MAX_EXP
1710 * 0.30103 /* binary -> decimal */ 2347 * 0.30103 /* binary -> decimal */
1711 * 2 /* estimate for FLAG_GROUP */ 2348 * 0.5 * 3 /* estimate for FLAG_GROUP */
1712 ) 2349 )
1713 + 1 /* turn floor into ceil */ 2350 + 1 /* turn floor into ceil */
1714 + 10; /* sign, decimal point etc. */ 2351 + 10; /* sign, decimal point etc. */
@@ -1716,17 +2353,20 @@ MAX_ROOM_NEEDED (const arguments *ap, size_t arg_index, FCHAR_T conversion,
1716 tmp_length = 2353 tmp_length =
1717 (unsigned int) (DBL_MAX_EXP 2354 (unsigned int) (DBL_MAX_EXP
1718 * 0.30103 /* binary -> decimal */ 2355 * 0.30103 /* binary -> decimal */
1719 * 2 /* estimate for FLAG_GROUP */ 2356 * 0.5 * 3 /* estimate for FLAG_GROUP */
1720 ) 2357 )
1721 + 1 /* turn floor into ceil */ 2358 + 1 /* turn floor into ceil */
1722 + 10; /* sign, decimal point etc. */ 2359 + 10; /* sign, decimal point etc. */
1723 tmp_length = xsum (tmp_length, precision); 2360 tmp_length = xsum (tmp_length, precision);
1724 break; 2361 break;
1725 2362
1726 case 'e': case 'E': case 'g': case 'G': 2363 case 'g': case 'G':
1727 tmp_length = 2364 tmp_length =
1728 12; /* sign, decimal point, exponent etc. */ 2365 12; /* sign, decimal point, exponent etc. */
1729 tmp_length = xsum (tmp_length, precision); 2366 tmp_length = xsum (tmp_length,
2367 precision
2368 * 0.5 * 3 /* estimate for FLAG_GROUP */
2369 );
1730 break; 2370 break;
1731 2371
1732 case 'a': case 'A': 2372 case 'a': case 'A':
@@ -1764,10 +2404,9 @@ MAX_ROOM_NEEDED (const arguments *ap, size_t arg_index, FCHAR_T conversion,
1764 break; 2404 break;
1765 2405
1766 case 's': 2406 case 's':
1767# if HAVE_WCHAR_T
1768 if (type == TYPE_WIDE_STRING) 2407 if (type == TYPE_WIDE_STRING)
1769 { 2408 {
1770# if WIDE_CHAR_VERSION 2409# if WIDE_CHAR_VERSION
1771 /* ISO C says about %ls in fwprintf: 2410 /* ISO C says about %ls in fwprintf:
1772 "If the precision is not specified or is greater than the size 2411 "If the precision is not specified or is greater than the size
1773 of the array, the array shall contain a null wide character." 2412 of the array, the array shall contain a null wide character."
@@ -1778,7 +2417,7 @@ MAX_ROOM_NEEDED (const arguments *ap, size_t arg_index, FCHAR_T conversion,
1778 tmp_length = local_wcsnlen (arg, precision); 2417 tmp_length = local_wcsnlen (arg, precision);
1779 else 2418 else
1780 tmp_length = local_wcslen (arg); 2419 tmp_length = local_wcslen (arg);
1781# else 2420# else
1782 /* ISO C says about %ls in fprintf: 2421 /* ISO C says about %ls in fprintf:
1783 "If a precision is specified, no more than that many bytes are 2422 "If a precision is specified, no more than that many bytes are
1784 written (including shift sequences, if any), and the array 2423 written (including shift sequences, if any), and the array
@@ -1789,10 +2428,9 @@ MAX_ROOM_NEEDED (const arguments *ap, size_t arg_index, FCHAR_T conversion,
1789 So if there is a precision, we must not use wcslen. */ 2428 So if there is a precision, we must not use wcslen. */
1790 /* This case has already been handled separately in VASNPRINTF. */ 2429 /* This case has already been handled separately in VASNPRINTF. */
1791 abort (); 2430 abort ();
1792# endif 2431# endif
1793 } 2432 }
1794 else 2433 else
1795# endif
1796 { 2434 {
1797# if WIDE_CHAR_VERSION 2435# if WIDE_CHAR_VERSION
1798 /* ISO C says about %s in fwprintf: 2436 /* ISO C says about %s in fwprintf:
@@ -1879,7 +2517,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
1879 TCHAR_T *buf; 2517 TCHAR_T *buf;
1880 TCHAR_T *buf_malloced; 2518 TCHAR_T *buf_malloced;
1881 const FCHAR_T *cp; 2519 const FCHAR_T *cp;
1882 size_t i; 2520 size_t di;
1883 DIRECTIVE *dp; 2521 DIRECTIVE *dp;
1884 /* Output string accumulator. */ 2522 /* Output string accumulator. */
1885 DCHAR_T *result; 2523 DCHAR_T *result;
@@ -1943,7 +2581,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
1943#define ENSURE_ALLOCATION(needed) \ 2581#define ENSURE_ALLOCATION(needed) \
1944 ENSURE_ALLOCATION_ELSE((needed), goto out_of_memory; ) 2582 ENSURE_ALLOCATION_ELSE((needed), goto out_of_memory; )
1945 2583
1946 for (cp = format, i = 0, dp = &d.dir[0]; ; cp = dp->dir_end, i++, dp++) 2584 for (cp = format, di = 0, dp = &d.dir[0]; ; cp = dp->dir_end, di++, dp++)
1947 { 2585 {
1948 if (cp != dp->dir_start) 2586 if (cp != dp->dir_start)
1949 { 2587 {
@@ -1966,7 +2604,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
1966 while (--n > 0); 2604 while (--n > 0);
1967 } 2605 }
1968 } 2606 }
1969 if (i == d.count) 2607 if (di == d.count)
1970 break; 2608 break;
1971 2609
1972 /* Execute a single directive. */ 2610 /* Execute a single directive. */
@@ -1988,6 +2626,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
1988 2626
1989 if (dp->conversion == 'n') 2627 if (dp->conversion == 'n')
1990 { 2628 {
2629#if NEED_PRINTF_WITH_N_DIRECTIVE
1991 switch (a.arg[dp->arg_index].type) 2630 switch (a.arg[dp->arg_index].type)
1992 { 2631 {
1993 case TYPE_COUNT_SCHAR_POINTER: 2632 case TYPE_COUNT_SCHAR_POINTER:
@@ -2005,9 +2644,36 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2005 case TYPE_COUNT_LONGLONGINT_POINTER: 2644 case TYPE_COUNT_LONGLONGINT_POINTER:
2006 *a.arg[dp->arg_index].a.a_count_longlongint_pointer = length; 2645 *a.arg[dp->arg_index].a.a_count_longlongint_pointer = length;
2007 break; 2646 break;
2647 case TYPE_COUNT_INT8_T_POINTER:
2648 *a.arg[dp->arg_index].a.a_count_int8_t_pointer = length;
2649 break;
2650 case TYPE_COUNT_INT16_T_POINTER:
2651 *a.arg[dp->arg_index].a.a_count_int16_t_pointer = length;
2652 break;
2653 case TYPE_COUNT_INT32_T_POINTER:
2654 *a.arg[dp->arg_index].a.a_count_int32_t_pointer = length;
2655 break;
2656 case TYPE_COUNT_INT64_T_POINTER:
2657 *a.arg[dp->arg_index].a.a_count_int64_t_pointer = length;
2658 break;
2659 case TYPE_COUNT_INT_FAST8_T_POINTER:
2660 *a.arg[dp->arg_index].a.a_count_int_fast8_t_pointer = length;
2661 break;
2662 case TYPE_COUNT_INT_FAST16_T_POINTER:
2663 *a.arg[dp->arg_index].a.a_count_int_fast16_t_pointer = length;
2664 break;
2665 case TYPE_COUNT_INT_FAST32_T_POINTER:
2666 *a.arg[dp->arg_index].a.a_count_int_fast32_t_pointer = length;
2667 break;
2668 case TYPE_COUNT_INT_FAST64_T_POINTER:
2669 *a.arg[dp->arg_index].a.a_count_int_fast64_t_pointer = length;
2670 break;
2008 default: 2671 default:
2009 abort (); 2672 abort ();
2010 } 2673 }
2674#else
2675 abort ();
2676#endif
2011 } 2677 }
2012#if ENABLE_UNISTDIO 2678#if ENABLE_UNISTDIO
2013 /* The unistdio extensions. */ 2679 /* The unistdio extensions. */
@@ -2048,6 +2714,8 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2048 width = xsum (xtimes (width, 10), *digitp++ - '0'); 2714 width = xsum (xtimes (width, 10), *digitp++ - '0');
2049 while (digitp != dp->width_end); 2715 while (digitp != dp->width_end);
2050 } 2716 }
2717 if (width > (size_t) INT_MAX)
2718 goto overflow;
2051 has_width = 1; 2719 has_width = 1;
2052 } 2720 }
2053 2721
@@ -2126,11 +2794,12 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2126 { 2794 {
2127 /* Use the entire string. */ 2795 /* Use the entire string. */
2128 arg_end = arg + u8_strlen (arg); 2796 arg_end = arg + u8_strlen (arg);
2129 /* The number of characters doesn't matter. */ 2797 /* The number of characters doesn't matter,
2798 because !has_width and therefore width==0. */
2130 characters = 0; 2799 characters = 0;
2131 } 2800 }
2132 2801
2133 if (characters < width && !(dp->flags & FLAG_LEFT)) 2802 if (characters < width && !(flags & FLAG_LEFT))
2134 { 2803 {
2135 size_t n = width - characters; 2804 size_t n = width - characters;
2136 ENSURE_ALLOCATION (xsum (length, n)); 2805 ENSURE_ALLOCATION (xsum (length, n));
@@ -2167,7 +2836,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2167 if (converted != result + length) 2836 if (converted != result + length)
2168 { 2837 {
2169 ENSURE_ALLOCATION_ELSE (xsum (length, converted_len), 2838 ENSURE_ALLOCATION_ELSE (xsum (length, converted_len),
2170 { free (converted); goto out_of_memory; }); 2839 { free (converted); goto out_of_memory; });
2171 DCHAR_CPY (result + length, converted, converted_len); 2840 DCHAR_CPY (result + length, converted, converted_len);
2172 free (converted); 2841 free (converted);
2173 } 2842 }
@@ -2175,7 +2844,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2175 } 2844 }
2176# endif 2845# endif
2177 2846
2178 if (characters < width && (dp->flags & FLAG_LEFT)) 2847 if (characters < width && (flags & FLAG_LEFT))
2179 { 2848 {
2180 size_t n = width - characters; 2849 size_t n = width - characters;
2181 ENSURE_ALLOCATION (xsum (length, n)); 2850 ENSURE_ALLOCATION (xsum (length, n));
@@ -2228,11 +2897,12 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2228 { 2897 {
2229 /* Use the entire string. */ 2898 /* Use the entire string. */
2230 arg_end = arg + u16_strlen (arg); 2899 arg_end = arg + u16_strlen (arg);
2231 /* The number of characters doesn't matter. */ 2900 /* The number of characters doesn't matter,
2901 because !has_width and therefore width==0. */
2232 characters = 0; 2902 characters = 0;
2233 } 2903 }
2234 2904
2235 if (characters < width && !(dp->flags & FLAG_LEFT)) 2905 if (characters < width && !(flags & FLAG_LEFT))
2236 { 2906 {
2237 size_t n = width - characters; 2907 size_t n = width - characters;
2238 ENSURE_ALLOCATION (xsum (length, n)); 2908 ENSURE_ALLOCATION (xsum (length, n));
@@ -2269,7 +2939,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2269 if (converted != result + length) 2939 if (converted != result + length)
2270 { 2940 {
2271 ENSURE_ALLOCATION_ELSE (xsum (length, converted_len), 2941 ENSURE_ALLOCATION_ELSE (xsum (length, converted_len),
2272 { free (converted); goto out_of_memory; }); 2942 { free (converted); goto out_of_memory; });
2273 DCHAR_CPY (result + length, converted, converted_len); 2943 DCHAR_CPY (result + length, converted, converted_len);
2274 free (converted); 2944 free (converted);
2275 } 2945 }
@@ -2277,7 +2947,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2277 } 2947 }
2278# endif 2948# endif
2279 2949
2280 if (characters < width && (dp->flags & FLAG_LEFT)) 2950 if (characters < width && (flags & FLAG_LEFT))
2281 { 2951 {
2282 size_t n = width - characters; 2952 size_t n = width - characters;
2283 ENSURE_ALLOCATION (xsum (length, n)); 2953 ENSURE_ALLOCATION (xsum (length, n));
@@ -2330,11 +3000,12 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2330 { 3000 {
2331 /* Use the entire string. */ 3001 /* Use the entire string. */
2332 arg_end = arg + u32_strlen (arg); 3002 arg_end = arg + u32_strlen (arg);
2333 /* The number of characters doesn't matter. */ 3003 /* The number of characters doesn't matter,
3004 because !has_width and therefore width==0. */
2334 characters = 0; 3005 characters = 0;
2335 } 3006 }
2336 3007
2337 if (characters < width && !(dp->flags & FLAG_LEFT)) 3008 if (characters < width && !(flags & FLAG_LEFT))
2338 { 3009 {
2339 size_t n = width - characters; 3010 size_t n = width - characters;
2340 ENSURE_ALLOCATION (xsum (length, n)); 3011 ENSURE_ALLOCATION (xsum (length, n));
@@ -2371,7 +3042,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2371 if (converted != result + length) 3042 if (converted != result + length)
2372 { 3043 {
2373 ENSURE_ALLOCATION_ELSE (xsum (length, converted_len), 3044 ENSURE_ALLOCATION_ELSE (xsum (length, converted_len),
2374 { free (converted); goto out_of_memory; }); 3045 { free (converted); goto out_of_memory; });
2375 DCHAR_CPY (result + length, converted, converted_len); 3046 DCHAR_CPY (result + length, converted, converted_len);
2376 free (converted); 3047 free (converted);
2377 } 3048 }
@@ -2379,7 +3050,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2379 } 3050 }
2380# endif 3051# endif
2381 3052
2382 if (characters < width && (dp->flags & FLAG_LEFT)) 3053 if (characters < width && (flags & FLAG_LEFT))
2383 { 3054 {
2384 size_t n = width - characters; 3055 size_t n = width - characters;
2385 ENSURE_ALLOCATION (xsum (length, n)); 3056 ENSURE_ALLOCATION (xsum (length, n));
@@ -2394,7 +3065,335 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2394 } 3065 }
2395 } 3066 }
2396#endif 3067#endif
2397#if (!USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || (NEED_PRINTF_DIRECTIVE_LS && !defined IN_LIBINTL) || ENABLE_WCHAR_FALLBACK) && HAVE_WCHAR_T 3068#if !WIDE_CHAR_VERSION && (PTRDIFF_MAX > INT_MAX)
3069 else if (dp->conversion == 's'
3070 && a.arg[dp->arg_index].type != TYPE_WIDE_STRING)
3071 {
3072 /* %s in vasnprintf. See the specification of fprintf.
3073 We handle it ourselves here, because the string may be longer
3074 than INT_MAX characters, whence snprintf or sprintf would
3075 fail to process it. */
3076 int flags = dp->flags;
3077 int has_width;
3078 size_t width;
3079 int has_precision;
3080 size_t precision;
3081
3082 has_width = 0;
3083 width = 0;
3084 if (dp->width_start != dp->width_end)
3085 {
3086 if (dp->width_arg_index != ARG_NONE)
3087 {
3088 int arg;
3089
3090 if (!(a.arg[dp->width_arg_index].type == TYPE_INT))
3091 abort ();
3092 arg = a.arg[dp->width_arg_index].a.a_int;
3093 width = arg;
3094 if (arg < 0)
3095 {
3096 /* "A negative field width is taken as a '-' flag
3097 followed by a positive field width." */
3098 flags |= FLAG_LEFT;
3099 width = -width;
3100 }
3101 }
3102 else
3103 {
3104 const FCHAR_T *digitp = dp->width_start;
3105
3106 do
3107 width = xsum (xtimes (width, 10), *digitp++ - '0');
3108 while (digitp != dp->width_end);
3109 }
3110 if (width > (size_t) INT_MAX)
3111 goto overflow;
3112 has_width = 1;
3113 }
3114
3115 has_precision = 0;
3116 precision = 6;
3117 if (dp->precision_start != dp->precision_end)
3118 {
3119 if (dp->precision_arg_index != ARG_NONE)
3120 {
3121 int arg;
3122
3123 if (!(a.arg[dp->precision_arg_index].type == TYPE_INT))
3124 abort ();
3125 arg = a.arg[dp->precision_arg_index].a.a_int;
3126 /* "A negative precision is taken as if the precision
3127 were omitted." */
3128 if (arg >= 0)
3129 {
3130 precision = arg;
3131 has_precision = 1;
3132 }
3133 }
3134 else
3135 {
3136 const FCHAR_T *digitp = dp->precision_start + 1;
3137
3138 precision = 0;
3139 while (digitp != dp->precision_end)
3140 precision = xsum (xtimes (precision, 10), *digitp++ - '0');
3141 has_precision = 1;
3142 }
3143 }
3144
3145 {
3146 const char *arg = a.arg[dp->arg_index].a.a_string;
3147 size_t bytes;
3148# if ENABLE_UNISTDIO && DCHAR_IS_TCHAR
3149 size_t characters;
3150# endif
3151# if !DCHAR_IS_TCHAR
3152 /* This code assumes that TCHAR_T is 'char'. */
3153 static_assert (sizeof (TCHAR_T) == 1);
3154 DCHAR_T *tmpdst;
3155 size_t tmpdst_len;
3156# endif
3157 size_t w;
3158
3159 if (has_precision)
3160 {
3161 /* Use only at most PRECISION bytes, from the left. */
3162 bytes = local_strnlen (arg, precision);
3163 }
3164 else
3165 {
3166 /* Use the entire string, and count the number of
3167 bytes. */
3168 bytes = strlen (arg);
3169 }
3170
3171# if ENABLE_UNISTDIO && DCHAR_IS_TCHAR
3172 if (has_width)
3173 characters = mbsnlen (arg, bytes);
3174 else
3175 {
3176 /* The number of characters doesn't matter,
3177 because !has_width and therefore width==0. */
3178 characters = 0;
3179 }
3180# endif
3181
3182# if !DCHAR_IS_TCHAR
3183 /* Convert from TCHAR_T[] to DCHAR_T[]. */
3184 tmpdst =
3185 DCHAR_CONV_FROM_ENCODING (locale_charset (),
3186 iconveh_question_mark,
3187 arg, bytes,
3188 NULL,
3189 NULL, &tmpdst_len);
3190 if (tmpdst == NULL)
3191 goto fail_with_errno;
3192# endif
3193
3194 if (has_width)
3195 {
3196# if ENABLE_UNISTDIO
3197 /* Outside POSIX, it's preferable to compare the width
3198 against the number of _characters_ of the converted
3199 value. */
3200# if DCHAR_IS_TCHAR
3201 w = characters;
3202# else
3203 w = DCHAR_MBSNLEN (tmpdst, tmpdst_len);
3204# endif
3205# else
3206 /* The width is compared against the number of _bytes_
3207 of the converted value, says POSIX. */
3208 w = bytes;
3209# endif
3210 }
3211 else
3212 /* w doesn't matter. */
3213 w = 0;
3214
3215 {
3216# if DCHAR_IS_TCHAR
3217 size_t total = bytes + (w < width ? width - w : 0);
3218 ENSURE_ALLOCATION (xsum (length, total));
3219# else
3220 size_t total = tmpdst_len + (w < width ? width - w : 0);
3221 ENSURE_ALLOCATION_ELSE (xsum (length, total),
3222 { free (tmpdst); goto out_of_memory; });
3223# endif
3224
3225 if (w < width && !(flags & FLAG_LEFT))
3226 {
3227 size_t n = width - w;
3228 DCHAR_SET (result + length, ' ', n);
3229 length += n;
3230 }
3231
3232# if DCHAR_IS_TCHAR
3233 memcpy (result + length, arg, bytes);
3234 length += bytes;
3235# else
3236 DCHAR_CPY (result + length, tmpdst, tmpdst_len);
3237 free (tmpdst);
3238 length += tmpdst_len;
3239# endif
3240
3241 if (w < width && (flags & FLAG_LEFT))
3242 {
3243 size_t n = width - w;
3244 DCHAR_SET (result + length, ' ', n);
3245 length += n;
3246 }
3247 }
3248 }
3249 }
3250#endif
3251#if WIDE_CHAR_VERSION && ((PTRDIFF_MAX > INT_MAX) || !DCHAR_IS_TCHAR || NEED_WPRINTF_DIRECTIVE_LC)
3252 else if ((dp->conversion == 's'
3253 && a.arg[dp->arg_index].type == TYPE_WIDE_STRING)
3254 || (dp->conversion == 'c'
3255 && a.arg[dp->arg_index].type == TYPE_WIDE_CHAR))
3256 {
3257 /* %ls or %lc in vasnwprintf. See the specification of
3258 fwprintf. */
3259 /* It would be silly to use snprintf ("%ls", ...) and then
3260 convert back the result from a char[] to a wchar_t[].
3261 Instead, just copy the argument wchar_t[] to the result. */
3262 int flags = dp->flags;
3263 size_t width;
3264
3265 width = 0;
3266 if (dp->width_start != dp->width_end)
3267 {
3268 if (dp->width_arg_index != ARG_NONE)
3269 {
3270 int arg;
3271
3272 if (!(a.arg[dp->width_arg_index].type == TYPE_INT))
3273 abort ();
3274 arg = a.arg[dp->width_arg_index].a.a_int;
3275 width = arg;
3276 if (arg < 0)
3277 {
3278 /* "A negative field width is taken as a '-' flag
3279 followed by a positive field width." */
3280 flags |= FLAG_LEFT;
3281 width = -width;
3282 }
3283 }
3284 else
3285 {
3286 const FCHAR_T *digitp = dp->width_start;
3287
3288 do
3289 width = xsum (xtimes (width, 10), *digitp++ - '0');
3290 while (digitp != dp->width_end);
3291 }
3292 if (width > (size_t) INT_MAX)
3293 goto overflow;
3294 }
3295
3296 {
3297 const wchar_t *ls_arg;
3298 wchar_t lc_arg[1];
3299 size_t characters;
3300
3301 if (dp->conversion == 's')
3302 {
3303 int has_precision;
3304 size_t precision;
3305
3306 has_precision = 0;
3307 precision = 6;
3308 if (dp->precision_start != dp->precision_end)
3309 {
3310 if (dp->precision_arg_index != ARG_NONE)
3311 {
3312 int arg;
3313
3314 if (!(a.arg[dp->precision_arg_index].type == TYPE_INT))
3315 abort ();
3316 arg = a.arg[dp->precision_arg_index].a.a_int;
3317 /* "A negative precision is taken as if the precision
3318 were omitted." */
3319 if (arg >= 0)
3320 {
3321 precision = arg;
3322 has_precision = 1;
3323 }
3324 }
3325 else
3326 {
3327 const FCHAR_T *digitp = dp->precision_start + 1;
3328
3329 precision = 0;
3330 while (digitp != dp->precision_end)
3331 precision = xsum (xtimes (precision, 10), *digitp++ - '0');
3332 has_precision = 1;
3333 }
3334 }
3335
3336 ls_arg = a.arg[dp->arg_index].a.a_wide_string;
3337
3338 if (has_precision)
3339 {
3340 /* Use only at most PRECISION wide characters, from
3341 the left. */
3342 const wchar_t *ls_arg_end;
3343
3344 ls_arg_end = ls_arg;
3345 characters = 0;
3346 for (; precision > 0; precision--)
3347 {
3348 if (*ls_arg_end == 0)
3349 /* Found the terminating null wide character. */
3350 break;
3351 ls_arg_end++;
3352 characters++;
3353 }
3354 }
3355 else
3356 {
3357 /* Use the entire string, and count the number of wide
3358 characters. */
3359 characters = local_wcslen (ls_arg);
3360 }
3361 }
3362 else /* dp->conversion == 'c' */
3363 {
3364 lc_arg[0] = (wchar_t) a.arg[dp->arg_index].a.a_wide_char;
3365 ls_arg = lc_arg;
3366 characters = 1;
3367 }
3368
3369 {
3370 size_t total = (characters < width ? width : characters);
3371 ENSURE_ALLOCATION (xsum (length, total));
3372
3373 if (characters < width && !(flags & FLAG_LEFT))
3374 {
3375 size_t n = width - characters;
3376 DCHAR_SET (result + length, ' ', n);
3377 length += n;
3378 }
3379
3380 if (characters > 0)
3381 {
3382 DCHAR_CPY (result + length, ls_arg, characters);
3383 length += characters;
3384 }
3385
3386 if (characters < width && (flags & FLAG_LEFT))
3387 {
3388 size_t n = width - characters;
3389 DCHAR_SET (result + length, ' ', n);
3390 length += n;
3391 }
3392 }
3393 }
3394 }
3395#endif
3396#if WIDE_CHAR_VERSION || !USE_SNPRINTF || (PTRDIFF_MAX > INT_MAX) || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || NEED_PRINTF_DIRECTIVE_LS || ENABLE_WCHAR_FALLBACK
2398 else if (dp->conversion == 's' 3397 else if (dp->conversion == 's'
2399# if WIDE_CHAR_VERSION 3398# if WIDE_CHAR_VERSION
2400 && a.arg[dp->arg_index].type != TYPE_WIDE_STRING 3399 && a.arg[dp->arg_index].type != TYPE_WIDE_STRING
@@ -2447,6 +3446,8 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2447 width = xsum (xtimes (width, 10), *digitp++ - '0'); 3446 width = xsum (xtimes (width, 10), *digitp++ - '0');
2448 while (digitp != dp->width_end); 3447 while (digitp != dp->width_end);
2449 } 3448 }
3449 if (width > (size_t) INT_MAX)
3450 goto overflow;
2450 has_width = 1; 3451 has_width = 1;
2451 } 3452 }
2452 3453
@@ -2493,7 +3494,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2493 wide characters, from the left. */ 3494 wide characters, from the left. */
2494# if HAVE_MBRTOWC 3495# if HAVE_MBRTOWC
2495 mbstate_t state; 3496 mbstate_t state;
2496 memset (&state, '\0', sizeof (mbstate_t)); 3497 mbszero (&state);
2497# endif 3498# endif
2498 arg_end = arg; 3499 arg_end = arg;
2499 characters = 0; 3500 characters = 0;
@@ -2521,7 +3522,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2521 characters. */ 3522 characters. */
2522# if HAVE_MBRTOWC 3523# if HAVE_MBRTOWC
2523 mbstate_t state; 3524 mbstate_t state;
2524 memset (&state, '\0', sizeof (mbstate_t)); 3525 mbszero (&state);
2525# endif 3526# endif
2526 arg_end = arg; 3527 arg_end = arg;
2527 characters = 0; 3528 characters = 0;
@@ -2551,7 +3552,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2551 characters = 0; 3552 characters = 0;
2552 } 3553 }
2553 3554
2554 if (characters < width && !(dp->flags & FLAG_LEFT)) 3555 if (characters < width && !(flags & FLAG_LEFT))
2555 { 3556 {
2556 size_t n = width - characters; 3557 size_t n = width - characters;
2557 ENSURE_ALLOCATION (xsum (length, n)); 3558 ENSURE_ALLOCATION (xsum (length, n));
@@ -2565,7 +3566,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2565 size_t remaining; 3566 size_t remaining;
2566# if HAVE_MBRTOWC 3567# if HAVE_MBRTOWC
2567 mbstate_t state; 3568 mbstate_t state;
2568 memset (&state, '\0', sizeof (mbstate_t)); 3569 mbszero (&state);
2569# endif 3570# endif
2570 ENSURE_ALLOCATION (xsum (length, characters)); 3571 ENSURE_ALLOCATION (xsum (length, characters));
2571 for (remaining = characters; remaining > 0; remaining--) 3572 for (remaining = characters; remaining > 0; remaining--)
@@ -2591,7 +3592,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2591 { 3592 {
2592# if HAVE_MBRTOWC 3593# if HAVE_MBRTOWC
2593 mbstate_t state; 3594 mbstate_t state;
2594 memset (&state, '\0', sizeof (mbstate_t)); 3595 mbszero (&state);
2595# endif 3596# endif
2596 while (arg < arg_end) 3597 while (arg < arg_end)
2597 { 3598 {
@@ -2602,17 +3603,19 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2602# else 3603# else
2603 count = mbtowc (&wc, arg, arg_end - arg); 3604 count = mbtowc (&wc, arg, arg_end - arg);
2604# endif 3605# endif
2605 if (count <= 0) 3606 if (count == 0)
2606 /* mbrtowc not consistent with mbrlen, or mbtowc 3607 /* mbrtowc not consistent with strlen. */
2607 not consistent with mblen. */
2608 abort (); 3608 abort ();
3609 if (count < 0)
3610 /* Invalid or incomplete multibyte character. */
3611 goto fail_with_EILSEQ;
2609 ENSURE_ALLOCATION (xsum (length, 1)); 3612 ENSURE_ALLOCATION (xsum (length, 1));
2610 result[length++] = wc; 3613 result[length++] = wc;
2611 arg += count; 3614 arg += count;
2612 } 3615 }
2613 } 3616 }
2614 3617
2615 if (characters < width && (dp->flags & FLAG_LEFT)) 3618 if (characters < width && (flags & FLAG_LEFT))
2616 { 3619 {
2617 size_t n = width - characters; 3620 size_t n = width - characters;
2618 ENSURE_ALLOCATION (xsum (length, n)); 3621 ENSURE_ALLOCATION (xsum (length, n));
@@ -2625,11 +3628,13 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2625 { 3628 {
2626 const wchar_t *arg = a.arg[dp->arg_index].a.a_wide_string; 3629 const wchar_t *arg = a.arg[dp->arg_index].a.a_wide_string;
2627 const wchar_t *arg_end; 3630 const wchar_t *arg_end;
3631 size_t bytes;
3632# if ENABLE_UNISTDIO && DCHAR_IS_TCHAR
2628 size_t characters; 3633 size_t characters;
3634# endif
2629# if !DCHAR_IS_TCHAR 3635# if !DCHAR_IS_TCHAR
2630 /* This code assumes that TCHAR_T is 'char'. */ 3636 /* This code assumes that TCHAR_T is 'char'. */
2631 static_assert (sizeof (TCHAR_T) == 1); 3637 static_assert (sizeof (TCHAR_T) == 1);
2632 TCHAR_T *tmpsrc;
2633 DCHAR_T *tmpdst; 3638 DCHAR_T *tmpdst;
2634 size_t tmpdst_len; 3639 size_t tmpdst_len;
2635# endif 3640# endif
@@ -2641,10 +3646,13 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2641 at most PRECISION bytes, from the left. */ 3646 at most PRECISION bytes, from the left. */
2642# if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t 3647# if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t
2643 mbstate_t state; 3648 mbstate_t state;
2644 memset (&state, '\0', sizeof (mbstate_t)); 3649 mbszero (&state);
2645# endif 3650# endif
2646 arg_end = arg; 3651 arg_end = arg;
3652 bytes = 0;
3653# if ENABLE_UNISTDIO && DCHAR_IS_TCHAR
2647 characters = 0; 3654 characters = 0;
3655# endif
2648 while (precision > 0) 3656 while (precision > 0)
2649 { 3657 {
2650 char cbuf[64]; /* Assume MB_CUR_MAX <= 64. */ 3658 char cbuf[64]; /* Assume MB_CUR_MAX <= 64. */
@@ -2660,7 +3668,10 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2660 if (precision < (unsigned int) count) 3668 if (precision < (unsigned int) count)
2661 break; 3669 break;
2662 arg_end++; 3670 arg_end++;
2663 characters += count; 3671 bytes += count;
3672# if ENABLE_UNISTDIO && DCHAR_IS_TCHAR
3673 characters += mbsnlen (cbuf, count);
3674# endif
2664 precision -= count; 3675 precision -= count;
2665 } 3676 }
2666 } 3677 }
@@ -2674,10 +3685,13 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2674 bytes. */ 3685 bytes. */
2675# if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t 3686# if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t
2676 mbstate_t state; 3687 mbstate_t state;
2677 memset (&state, '\0', sizeof (mbstate_t)); 3688 mbszero (&state);
2678# endif 3689# endif
2679 arg_end = arg; 3690 arg_end = arg;
3691 bytes = 0;
3692# if ENABLE_UNISTDIO && DCHAR_IS_TCHAR
2680 characters = 0; 3693 characters = 0;
3694# endif
2681 for (;;) 3695 for (;;)
2682 { 3696 {
2683 char cbuf[64]; /* Assume MB_CUR_MAX <= 64. */ 3697 char cbuf[64]; /* Assume MB_CUR_MAX <= 64. */
@@ -2691,7 +3705,10 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2691 /* Cannot convert. */ 3705 /* Cannot convert. */
2692 goto fail_with_EILSEQ; 3706 goto fail_with_EILSEQ;
2693 arg_end++; 3707 arg_end++;
2694 characters += count; 3708 bytes += count;
3709# if ENABLE_UNISTDIO && DCHAR_IS_TCHAR
3710 characters += mbsnlen (cbuf, count);
3711# endif
2695 } 3712 }
2696 } 3713 }
2697# if DCHAR_IS_TCHAR 3714# if DCHAR_IS_TCHAR
@@ -2699,56 +3716,64 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2699 { 3716 {
2700 /* Use the entire string. */ 3717 /* Use the entire string. */
2701 arg_end = arg + local_wcslen (arg); 3718 arg_end = arg + local_wcslen (arg);
2702 /* The number of bytes doesn't matter. */ 3719 /* The number of bytes and characters doesn't matter,
3720 because !has_width and therefore width==0. */
3721 bytes = 0;
3722# if ENABLE_UNISTDIO
2703 characters = 0; 3723 characters = 0;
3724# endif
2704 } 3725 }
2705# endif 3726# endif
2706 3727
2707# if !DCHAR_IS_TCHAR 3728# if !DCHAR_IS_TCHAR
2708 /* Convert the string into a piece of temporary memory. */
2709 tmpsrc = (TCHAR_T *) malloc (characters * sizeof (TCHAR_T));
2710 if (tmpsrc == NULL)
2711 goto out_of_memory;
2712 { 3729 {
2713 TCHAR_T *tmpptr = tmpsrc; 3730 TCHAR_T *tmpsrc;
2714 size_t remaining; 3731
3732 /* Convert the string into a piece of temporary memory. */
3733 tmpsrc = (TCHAR_T *) malloc (bytes * sizeof (TCHAR_T));
3734 if (tmpsrc == NULL)
3735 goto out_of_memory;
3736 {
3737 TCHAR_T *tmpptr = tmpsrc;
3738 size_t remaining;
2715# if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t 3739# if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t
2716 mbstate_t state; 3740 mbstate_t state;
2717 memset (&state, '\0', sizeof (mbstate_t)); 3741 mbszero (&state);
2718# endif 3742# endif
2719 for (remaining = characters; remaining > 0; ) 3743 for (remaining = bytes; remaining > 0; )
2720 { 3744 {
2721 char cbuf[64]; /* Assume MB_CUR_MAX <= 64. */ 3745 char cbuf[64]; /* Assume MB_CUR_MAX <= 64. */
2722 int count; 3746 int count;
2723 3747
2724 if (*arg == 0) 3748 if (*arg == 0)
2725 abort (); 3749 abort ();
2726 count = local_wcrtomb (cbuf, *arg, &state); 3750 count = local_wcrtomb (cbuf, *arg, &state);
2727 if (count <= 0) 3751 if (count <= 0)
2728 /* Inconsistency. */ 3752 /* Inconsistency. */
2729 abort (); 3753 abort ();
2730 memcpy (tmpptr, cbuf, count); 3754 memcpy (tmpptr, cbuf, count);
2731 tmpptr += count; 3755 tmpptr += count;
2732 arg++; 3756 arg++;
2733 remaining -= count; 3757 remaining -= count;
3758 }
3759 if (!(arg == arg_end))
3760 abort ();
3761 }
3762
3763 /* Convert from TCHAR_T[] to DCHAR_T[]. */
3764 tmpdst =
3765 DCHAR_CONV_FROM_ENCODING (locale_charset (),
3766 iconveh_question_mark,
3767 tmpsrc, bytes,
3768 NULL,
3769 NULL, &tmpdst_len);
3770 if (tmpdst == NULL)
3771 {
3772 free (tmpsrc);
3773 goto fail_with_errno;
2734 } 3774 }
2735 if (!(arg == arg_end)) 3775 free (tmpsrc);
2736 abort ();
2737 } 3776 }
2738
2739 /* Convert from TCHAR_T[] to DCHAR_T[]. */
2740 tmpdst =
2741 DCHAR_CONV_FROM_ENCODING (locale_charset (),
2742 iconveh_question_mark,
2743 tmpsrc, characters,
2744 NULL,
2745 NULL, &tmpdst_len);
2746 if (tmpdst == NULL)
2747 {
2748 free (tmpsrc);
2749 goto fail_with_errno;
2750 }
2751 free (tmpsrc);
2752# endif 3777# endif
2753 3778
2754 if (has_width) 3779 if (has_width)
@@ -2757,21 +3782,30 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2757 /* Outside POSIX, it's preferable to compare the width 3782 /* Outside POSIX, it's preferable to compare the width
2758 against the number of _characters_ of the converted 3783 against the number of _characters_ of the converted
2759 value. */ 3784 value. */
2760 w = DCHAR_MBSNLEN (result + length, characters); 3785# if DCHAR_IS_TCHAR
3786 w = characters;
3787# else
3788 w = DCHAR_MBSNLEN (tmpdst, tmpdst_len);
3789# endif
2761# else 3790# else
2762 /* The width is compared against the number of _bytes_ 3791 /* The width is compared against the number of _bytes_
2763 of the converted value, says POSIX. */ 3792 of the converted value, says POSIX. */
2764 w = characters; 3793 w = bytes;
2765# endif 3794# endif
2766 } 3795 }
2767 else 3796 else
2768 /* w doesn't matter. */ 3797 /* w doesn't matter. */
2769 w = 0; 3798 w = 0;
2770 3799
2771 if (w < width && !(dp->flags & FLAG_LEFT)) 3800 if (w < width && !(flags & FLAG_LEFT))
2772 { 3801 {
2773 size_t n = width - w; 3802 size_t n = width - w;
3803# if DCHAR_IS_TCHAR
2774 ENSURE_ALLOCATION (xsum (length, n)); 3804 ENSURE_ALLOCATION (xsum (length, n));
3805# else
3806 ENSURE_ALLOCATION_ELSE (xsum (length, n),
3807 { free (tmpdst); goto out_of_memory; });
3808# endif
2775 DCHAR_SET (result + length, ' ', n); 3809 DCHAR_SET (result + length, ' ', n);
2776 length += n; 3810 length += n;
2777 } 3811 }
@@ -2783,10 +3817,10 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2783 size_t remaining; 3817 size_t remaining;
2784# if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t 3818# if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t
2785 mbstate_t state; 3819 mbstate_t state;
2786 memset (&state, '\0', sizeof (mbstate_t)); 3820 mbszero (&state);
2787# endif 3821# endif
2788 ENSURE_ALLOCATION (xsum (length, characters)); 3822 ENSURE_ALLOCATION (xsum (length, bytes));
2789 for (remaining = characters; remaining > 0; ) 3823 for (remaining = bytes; remaining > 0; )
2790 { 3824 {
2791 char cbuf[64]; /* Assume MB_CUR_MAX <= 64. */ 3825 char cbuf[64]; /* Assume MB_CUR_MAX <= 64. */
2792 int count; 3826 int count;
@@ -2809,7 +3843,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2809 { 3843 {
2810# if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t 3844# if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t
2811 mbstate_t state; 3845 mbstate_t state;
2812 memset (&state, '\0', sizeof (mbstate_t)); 3846 mbszero (&state);
2813# endif 3847# endif
2814 while (arg < arg_end) 3848 while (arg < arg_end)
2815 { 3849 {
@@ -2830,13 +3864,13 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2830 } 3864 }
2831# else 3865# else
2832 ENSURE_ALLOCATION_ELSE (xsum (length, tmpdst_len), 3866 ENSURE_ALLOCATION_ELSE (xsum (length, tmpdst_len),
2833 { free (tmpdst); goto out_of_memory; }); 3867 { free (tmpdst); goto out_of_memory; });
2834 DCHAR_CPY (result + length, tmpdst, tmpdst_len); 3868 DCHAR_CPY (result + length, tmpdst, tmpdst_len);
2835 free (tmpdst); 3869 free (tmpdst);
2836 length += tmpdst_len; 3870 length += tmpdst_len;
2837# endif 3871# endif
2838 3872
2839 if (w < width && (dp->flags & FLAG_LEFT)) 3873 if (w < width && (flags & FLAG_LEFT))
2840 { 3874 {
2841 size_t n = width - w; 3875 size_t n = width - w;
2842 ENSURE_ALLOCATION (xsum (length, n)); 3876 ENSURE_ALLOCATION (xsum (length, n));
@@ -2847,12 +3881,13 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2847# endif 3881# endif
2848 } 3882 }
2849#endif 3883#endif
2850#if ENABLE_WCHAR_FALLBACK && HAVE_WINT_T && !WIDE_CHAR_VERSION 3884#if (NEED_PRINTF_DIRECTIVE_LC || ENABLE_WCHAR_FALLBACK) && HAVE_WINT_T && !WIDE_CHAR_VERSION
2851 else if (dp->conversion == 'c' 3885 else if (dp->conversion == 'c'
2852 && a.arg[dp->arg_index].type == TYPE_WIDE_CHAR) 3886 && a.arg[dp->arg_index].type == TYPE_WIDE_CHAR)
2853 { 3887 {
2854 /* Implement the 'lc' directive ourselves, in order to provide 3888 /* Implement the 'lc' directive ourselves, in order to provide
2855 the fallback that avoids EILSEQ. */ 3889 a correct behaviour for the null wint_t argument and/or the
3890 fallback that avoids EILSEQ. */
2856 int flags = dp->flags; 3891 int flags = dp->flags;
2857 int has_width; 3892 int has_width;
2858 size_t width; 3893 size_t width;
@@ -2885,17 +3920,21 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2885 width = xsum (xtimes (width, 10), *digitp++ - '0'); 3920 width = xsum (xtimes (width, 10), *digitp++ - '0');
2886 while (digitp != dp->width_end); 3921 while (digitp != dp->width_end);
2887 } 3922 }
3923 if (width > (size_t) INT_MAX)
3924 goto overflow;
2888 has_width = 1; 3925 has_width = 1;
2889 } 3926 }
2890 3927
2891 /* %lc in vasnprintf. See the specification of fprintf. */ 3928 /* %lc in vasnprintf. See the specification of fprintf. */
2892 { 3929 {
2893 wchar_t arg = (wchar_t) a.arg[dp->arg_index].a.a_wide_char; 3930 wchar_t arg = (wchar_t) a.arg[dp->arg_index].a.a_wide_char;
3931 size_t bytes;
3932# if ENABLE_UNISTDIO && DCHAR_IS_TCHAR
2894 size_t characters; 3933 size_t characters;
3934# endif
2895# if !DCHAR_IS_TCHAR 3935# if !DCHAR_IS_TCHAR
2896 /* This code assumes that TCHAR_T is 'char'. */ 3936 /* This code assumes that TCHAR_T is 'char'. */
2897 static_assert (sizeof (TCHAR_T) == 1); 3937 static_assert (sizeof (TCHAR_T) == 1);
2898 TCHAR_T tmpsrc[64]; /* Assume MB_CUR_MAX <= 64. */
2899 DCHAR_T *tmpdst; 3938 DCHAR_T *tmpdst;
2900 size_t tmpdst_len; 3939 size_t tmpdst_len;
2901# endif 3940# endif
@@ -2906,58 +3945,65 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2906# endif 3945# endif
2907 { 3946 {
2908 /* Count the number of bytes. */ 3947 /* Count the number of bytes. */
2909 characters = 0; 3948 char cbuf[64]; /* Assume MB_CUR_MAX <= 64. */
2910 if (arg != 0) 3949 int count;
2911 {
2912 char cbuf[64]; /* Assume MB_CUR_MAX <= 64. */
2913 int count;
2914# if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t 3950# if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t
2915 mbstate_t state; 3951 mbstate_t state;
2916 memset (&state, '\0', sizeof (mbstate_t)); 3952 mbszero (&state);
2917# endif 3953# endif
2918 3954
2919 count = local_wcrtomb (cbuf, arg, &state); 3955 count = local_wcrtomb (cbuf, arg, &state);
2920 if (count < 0) 3956 if (count < 0)
2921 /* Inconsistency. */ 3957 /* Cannot convert. */
2922 abort (); 3958 goto fail_with_EILSEQ;
2923 characters = count; 3959 bytes = count;
2924 } 3960# if ENABLE_UNISTDIO && DCHAR_IS_TCHAR
3961 characters = mbsnlen (cbuf, count);
3962# endif
2925 } 3963 }
2926# if DCHAR_IS_TCHAR 3964# if DCHAR_IS_TCHAR
2927 else 3965 else
2928 { 3966 {
2929 /* The number of bytes doesn't matter. */ 3967 /* The number of bytes and characters doesn't matter,
3968 because !has_width and therefore width==0. */
3969 bytes = 0;
3970# if ENABLE_UNISTDIO
2930 characters = 0; 3971 characters = 0;
3972# endif
2931 } 3973 }
2932# endif 3974# endif
2933 3975
2934# if !DCHAR_IS_TCHAR 3976# if !DCHAR_IS_TCHAR
2935 /* Convert the string into a piece of temporary memory. */ 3977 {
2936 if (characters > 0) /* implies arg != 0 */ 3978 TCHAR_T tmpsrc[64]; /* Assume MB_CUR_MAX <= 64. */
2937 { 3979
2938 char cbuf[64]; /* Assume MB_CUR_MAX <= 64. */ 3980 /* Convert the string into a piece of temporary memory. */
2939 int count; 3981 if (bytes > 0)
3982 {
3983 char cbuf[64]; /* Assume MB_CUR_MAX <= 64. */
3984 int count;
2940# if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t 3985# if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t
2941 mbstate_t state; 3986 mbstate_t state;
2942 memset (&state, '\0', sizeof (mbstate_t)); 3987 mbszero (&state);
2943# endif 3988# endif
2944 3989
2945 count = local_wcrtomb (cbuf, arg, &state); 3990 count = local_wcrtomb (cbuf, arg, &state);
2946 if (count <= 0) 3991 if (count <= 0)
2947 /* Inconsistency. */ 3992 /* Inconsistency. */
2948 abort (); 3993 abort ();
2949 memcpy (tmpsrc, cbuf, count); 3994 memcpy (tmpsrc, cbuf, count);
2950 } 3995 }
2951 3996
2952 /* Convert from TCHAR_T[] to DCHAR_T[]. */ 3997 /* Convert from TCHAR_T[] to DCHAR_T[]. */
2953 tmpdst = 3998 tmpdst =
2954 DCHAR_CONV_FROM_ENCODING (locale_charset (), 3999 DCHAR_CONV_FROM_ENCODING (locale_charset (),
2955 iconveh_question_mark, 4000 iconveh_question_mark,
2956 tmpsrc, characters, 4001 tmpsrc, bytes,
2957 NULL, 4002 NULL,
2958 NULL, &tmpdst_len); 4003 NULL, &tmpdst_len);
2959 if (tmpdst == NULL) 4004 if (tmpdst == NULL)
2960 goto fail_with_errno; 4005 goto fail_with_errno;
4006 }
2961# endif 4007# endif
2962 4008
2963 if (has_width) 4009 if (has_width)
@@ -2966,21 +4012,30 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2966 /* Outside POSIX, it's preferable to compare the width 4012 /* Outside POSIX, it's preferable to compare the width
2967 against the number of _characters_ of the converted 4013 against the number of _characters_ of the converted
2968 value. */ 4014 value. */
2969 w = DCHAR_MBSNLEN (result + length, characters); 4015# if DCHAR_IS_TCHAR
4016 w = characters;
4017# else
4018 w = DCHAR_MBSNLEN (tmpdst, tmpdst_len);
4019# endif
2970# else 4020# else
2971 /* The width is compared against the number of _bytes_ 4021 /* The width is compared against the number of _bytes_
2972 of the converted value, says POSIX. */ 4022 of the converted value, says POSIX. */
2973 w = characters; 4023 w = bytes;
2974# endif 4024# endif
2975 } 4025 }
2976 else 4026 else
2977 /* w doesn't matter. */ 4027 /* w doesn't matter. */
2978 w = 0; 4028 w = 0;
2979 4029
2980 if (w < width && !(dp->flags & FLAG_LEFT)) 4030 if (w < width && !(flags & FLAG_LEFT))
2981 { 4031 {
2982 size_t n = width - w; 4032 size_t n = width - w;
4033# if DCHAR_IS_TCHAR
2983 ENSURE_ALLOCATION (xsum (length, n)); 4034 ENSURE_ALLOCATION (xsum (length, n));
4035# else
4036 ENSURE_ALLOCATION_ELSE (xsum (length, n),
4037 { free (tmpdst); goto out_of_memory; });
4038# endif
2984 DCHAR_SET (result + length, ' ', n); 4039 DCHAR_SET (result + length, ' ', n);
2985 length += n; 4040 length += n;
2986 } 4041 }
@@ -2989,13 +4044,13 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2989 if (has_width) 4044 if (has_width)
2990 { 4045 {
2991 /* We know the number of bytes in advance. */ 4046 /* We know the number of bytes in advance. */
2992 ENSURE_ALLOCATION (xsum (length, characters)); 4047 ENSURE_ALLOCATION (xsum (length, bytes));
2993 if (characters > 0) /* implies arg != 0 */ 4048 if (bytes > 0)
2994 { 4049 {
2995 int count; 4050 int count;
2996# if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t 4051# if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t
2997 mbstate_t state; 4052 mbstate_t state;
2998 memset (&state, '\0', sizeof (mbstate_t)); 4053 mbszero (&state);
2999# endif 4054# endif
3000 4055
3001 count = local_wcrtomb (result + length, arg, &state); 4056 count = local_wcrtomb (result + length, arg, &state);
@@ -3007,33 +4062,30 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
3007 } 4062 }
3008 else 4063 else
3009 { 4064 {
3010 if (arg != 0) 4065 char cbuf[64]; /* Assume MB_CUR_MAX <= 64. */
3011 { 4066 int count;
3012 char cbuf[64]; /* Assume MB_CUR_MAX <= 64. */
3013 int count;
3014# if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t 4067# if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t
3015 mbstate_t state; 4068 mbstate_t state;
3016 memset (&state, '\0', sizeof (mbstate_t)); 4069 mbszero (&state);
3017# endif 4070# endif
3018 4071
3019 count = local_wcrtomb (cbuf, arg, &state); 4072 count = local_wcrtomb (cbuf, arg, &state);
3020 if (count <= 0) 4073 if (count < 0)
3021 /* Inconsistency. */ 4074 /* Cannot convert. */
3022 abort (); 4075 goto fail_with_EILSEQ;
3023 ENSURE_ALLOCATION (xsum (length, count)); 4076 ENSURE_ALLOCATION (xsum (length, count));
3024 memcpy (result + length, cbuf, count); 4077 memcpy (result + length, cbuf, count);
3025 length += count; 4078 length += count;
3026 }
3027 } 4079 }
3028# else 4080# else
3029 ENSURE_ALLOCATION_ELSE (xsum (length, tmpdst_len), 4081 ENSURE_ALLOCATION_ELSE (xsum (length, tmpdst_len),
3030 { free (tmpdst); goto out_of_memory; }); 4082 { free (tmpdst); goto out_of_memory; });
3031 DCHAR_CPY (result + length, tmpdst, tmpdst_len); 4083 DCHAR_CPY (result + length, tmpdst, tmpdst_len);
3032 free (tmpdst); 4084 free (tmpdst);
3033 length += tmpdst_len; 4085 length += tmpdst_len;
3034# endif 4086# endif
3035 4087
3036 if (w < width && (dp->flags & FLAG_LEFT)) 4088 if (w < width && (flags & FLAG_LEFT))
3037 { 4089 {
3038 size_t n = width - w; 4090 size_t n = width - w;
3039 ENSURE_ALLOCATION (xsum (length, n)); 4091 ENSURE_ALLOCATION (xsum (length, n));
@@ -3043,14 +4095,406 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
3043 } 4095 }
3044 } 4096 }
3045#endif 4097#endif
3046#if (NEED_PRINTF_DIRECTIVE_A || NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_DOUBLE) && !defined IN_LIBINTL 4098#if NEED_WPRINTF_DIRECTIVE_C && WIDE_CHAR_VERSION
4099 else if (dp->conversion == 'c'
4100 && a.arg[dp->arg_index].type != TYPE_WIDE_CHAR)
4101 {
4102 /* Implement the 'c' directive ourselves, in order to avoid
4103 EILSEQ in the "C" locale. */
4104 int flags = dp->flags;
4105 size_t width;
4106
4107 width = 0;
4108 if (dp->width_start != dp->width_end)
4109 {
4110 if (dp->width_arg_index != ARG_NONE)
4111 {
4112 int arg;
4113
4114 if (!(a.arg[dp->width_arg_index].type == TYPE_INT))
4115 abort ();
4116 arg = a.arg[dp->width_arg_index].a.a_int;
4117 width = arg;
4118 if (arg < 0)
4119 {
4120 /* "A negative field width is taken as a '-' flag
4121 followed by a positive field width." */
4122 flags |= FLAG_LEFT;
4123 width = -width;
4124 }
4125 }
4126 else
4127 {
4128 const FCHAR_T *digitp = dp->width_start;
4129
4130 do
4131 width = xsum (xtimes (width, 10), *digitp++ - '0');
4132 while (digitp != dp->width_end);
4133 }
4134 if (width > (size_t) INT_MAX)
4135 goto overflow;
4136 }
4137
4138 /* %c in vasnwprintf. See the specification of fwprintf. */
4139 {
4140 char arg = (char) a.arg[dp->arg_index].a.a_char;
4141 mbstate_t state;
4142 wchar_t wc;
4143
4144 mbszero (&state);
4145 int count = mbrtowc (&wc, &arg, 1, &state);
4146 if (count < 0)
4147 /* Invalid or incomplete multibyte character. */
4148 goto fail_with_EILSEQ;
4149
4150 {
4151 size_t total = (1 < width ? width : 1);
4152 ENSURE_ALLOCATION (xsum (length, total));
4153
4154 if (1 < width && !(flags & FLAG_LEFT))
4155 {
4156 size_t n = width - 1;
4157 DCHAR_SET (result + length, ' ', n);
4158 length += n;
4159 }
4160
4161 result[length++] = wc;
4162
4163 if (1 < width && (flags & FLAG_LEFT))
4164 {
4165 size_t n = width - 1;
4166 DCHAR_SET (result + length, ' ', n);
4167 length += n;
4168 }
4169 }
4170 }
4171 }
4172#endif
4173#if NEED_PRINTF_DIRECTIVE_B || NEED_PRINTF_DIRECTIVE_UPPERCASE_B
4174 else if (0
4175# if NEED_PRINTF_DIRECTIVE_B
4176 || (dp->conversion == 'b')
4177# endif
4178# if NEED_PRINTF_DIRECTIVE_UPPERCASE_B
4179 || (dp->conversion == 'B')
4180# endif
4181 )
4182 {
4183 arg_type type = a.arg[dp->arg_index].type;
4184 int flags = dp->flags;
4185 int has_width;
4186 size_t width;
4187 int has_precision;
4188 size_t precision;
4189 size_t tmp_length;
4190 size_t count;
4191 DCHAR_T tmpbuf[700];
4192 DCHAR_T *tmp;
4193 DCHAR_T *tmp_end;
4194 DCHAR_T *tmp_start;
4195 DCHAR_T *pad_ptr;
4196 DCHAR_T *p;
4197
4198 has_width = 0;
4199 width = 0;
4200 if (dp->width_start != dp->width_end)
4201 {
4202 if (dp->width_arg_index != ARG_NONE)
4203 {
4204 int arg;
4205
4206 if (!(a.arg[dp->width_arg_index].type == TYPE_INT))
4207 abort ();
4208 arg = a.arg[dp->width_arg_index].a.a_int;
4209 width = arg;
4210 if (arg < 0)
4211 {
4212 /* "A negative field width is taken as a '-' flag
4213 followed by a positive field width." */
4214 flags |= FLAG_LEFT;
4215 width = -width;
4216 }
4217 }
4218 else
4219 {
4220 const FCHAR_T *digitp = dp->width_start;
4221
4222 do
4223 width = xsum (xtimes (width, 10), *digitp++ - '0');
4224 while (digitp != dp->width_end);
4225 }
4226 if (width > (size_t) INT_MAX)
4227 goto overflow;
4228 has_width = 1;
4229 }
4230
4231 has_precision = 0;
4232 precision = 1;
4233 if (dp->precision_start != dp->precision_end)
4234 {
4235 if (dp->precision_arg_index != ARG_NONE)
4236 {
4237 int arg;
4238
4239 if (!(a.arg[dp->precision_arg_index].type == TYPE_INT))
4240 abort ();
4241 arg = a.arg[dp->precision_arg_index].a.a_int;
4242 /* "A negative precision is taken as if the precision
4243 were omitted." */
4244 if (arg >= 0)
4245 {
4246 precision = arg;
4247 has_precision = 1;
4248 }
4249 }
4250 else
4251 {
4252 const FCHAR_T *digitp = dp->precision_start + 1;
4253
4254 precision = 0;
4255 while (digitp != dp->precision_end)
4256 precision = xsum (xtimes (precision, 10), *digitp++ - '0');
4257 has_precision = 1;
4258 }
4259 }
4260
4261 /* Allocate a temporary buffer of sufficient size. */
4262 switch (type)
4263 {
4264 default:
4265 tmp_length =
4266 (unsigned int) (sizeof (unsigned int) * CHAR_BIT)
4267 + 1; /* turn floor into ceil */
4268 break;
4269 case TYPE_ULONGINT:
4270 tmp_length =
4271 (unsigned int) (sizeof (unsigned long int) * CHAR_BIT)
4272 + 1; /* turn floor into ceil */
4273 break;
4274 case TYPE_ULONGLONGINT:
4275 tmp_length =
4276 (unsigned int) (sizeof (unsigned long long int) * CHAR_BIT)
4277 + 1; /* turn floor into ceil */
4278 break;
4279 case TYPE_UINT8_T:
4280 tmp_length =
4281 (unsigned int) (sizeof (uint8_t) * CHAR_BIT)
4282 + 1; /* turn floor into ceil */
4283 break;
4284 case TYPE_UINT16_T:
4285 tmp_length =
4286 (unsigned int) (sizeof (uint16_t) * CHAR_BIT)
4287 + 1; /* turn floor into ceil */
4288 break;
4289 case TYPE_UINT32_T:
4290 tmp_length =
4291 (unsigned int) (sizeof (uint32_t) * CHAR_BIT)
4292 + 1; /* turn floor into ceil */
4293 break;
4294 case TYPE_UINT64_T:
4295 tmp_length =
4296 (unsigned int) (sizeof (uint64_t) * CHAR_BIT)
4297 + 1; /* turn floor into ceil */
4298 break;
4299 case TYPE_UINT_FAST8_T:
4300 tmp_length =
4301 (unsigned int) (sizeof (uint_fast8_t) * CHAR_BIT)
4302 + 1; /* turn floor into ceil */
4303 break;
4304 case TYPE_UINT_FAST16_T:
4305 tmp_length =
4306 (unsigned int) (sizeof (uint_fast16_t) * CHAR_BIT)
4307 + 1; /* turn floor into ceil */
4308 break;
4309 case TYPE_UINT_FAST32_T:
4310 tmp_length =
4311 (unsigned int) (sizeof (uint_fast32_t) * CHAR_BIT)
4312 + 1; /* turn floor into ceil */
4313 break;
4314 case TYPE_UINT_FAST64_T:
4315 tmp_length =
4316 (unsigned int) (sizeof (uint_fast64_t) * CHAR_BIT)
4317 + 1; /* turn floor into ceil */
4318 break;
4319 }
4320 if (tmp_length < precision)
4321 tmp_length = precision;
4322 /* Add 2, to account for a prefix from the alternate form. */
4323 tmp_length = xsum (tmp_length, 2);
4324
4325 if (tmp_length < width)
4326 tmp_length = width;
4327
4328 if (tmp_length <= sizeof (tmpbuf) / sizeof (DCHAR_T))
4329 tmp = tmpbuf;
4330 else
4331 {
4332 size_t tmp_memsize = xtimes (tmp_length, sizeof (DCHAR_T));
4333
4334 if (size_overflow_p (tmp_memsize))
4335 /* Overflow, would lead to out of memory. */
4336 goto out_of_memory;
4337 tmp = (DCHAR_T *) malloc (tmp_memsize);
4338 if (tmp == NULL)
4339 /* Out of memory. */
4340 goto out_of_memory;
4341 }
4342
4343 tmp_end = tmp + tmp_length;
4344
4345 unsigned long long arg;
4346 switch (type)
4347 {
4348 case TYPE_UCHAR:
4349 arg = a.arg[dp->arg_index].a.a_uchar;
4350 break;
4351 case TYPE_USHORT:
4352 arg = a.arg[dp->arg_index].a.a_ushort;
4353 break;
4354 case TYPE_UINT:
4355 arg = a.arg[dp->arg_index].a.a_uint;
4356 break;
4357 case TYPE_ULONGINT:
4358 arg = a.arg[dp->arg_index].a.a_ulongint;
4359 break;
4360 case TYPE_ULONGLONGINT:
4361 arg = a.arg[dp->arg_index].a.a_ulonglongint;
4362 break;
4363 case TYPE_UINT8_T:
4364 arg = a.arg[dp->arg_index].a.a_uint8_t;
4365 break;
4366 case TYPE_UINT16_T:
4367 arg = a.arg[dp->arg_index].a.a_uint16_t;
4368 break;
4369 case TYPE_UINT32_T:
4370 arg = a.arg[dp->arg_index].a.a_uint32_t;
4371 break;
4372 case TYPE_UINT64_T:
4373 arg = a.arg[dp->arg_index].a.a_uint64_t;
4374 break;
4375 case TYPE_UINT_FAST8_T:
4376 arg = a.arg[dp->arg_index].a.a_uint_fast8_t;
4377 break;
4378 case TYPE_UINT_FAST16_T:
4379 arg = a.arg[dp->arg_index].a.a_uint_fast16_t;
4380 break;
4381 case TYPE_UINT_FAST32_T:
4382 arg = a.arg[dp->arg_index].a.a_uint_fast32_t;
4383 break;
4384 case TYPE_UINT_FAST64_T:
4385 arg = a.arg[dp->arg_index].a.a_uint_fast64_t;
4386 break;
4387 default:
4388 abort ();
4389 }
4390 int need_prefix = ((flags & FLAG_ALT) && arg != 0);
4391
4392 p = tmp_end;
4393 /* "The result of converting a zero value with a precision
4394 of zero is no characters." */
4395 if (!(has_precision && precision == 0 && arg == 0))
4396 {
4397 do
4398 {
4399 *--p = '0' + (arg & 1);
4400 arg = arg >> 1;
4401 }
4402 while (arg != 0);
4403 }
4404
4405 if (has_precision)
4406 {
4407 DCHAR_T *digits_start = tmp_end - precision;
4408 while (p > digits_start)
4409 *--p = '0';
4410 }
4411
4412 pad_ptr = p;
4413
4414 if (need_prefix)
4415 {
4416# if NEED_PRINTF_DIRECTIVE_B && !NEED_PRINTF_DIRECTIVE_UPPERCASE_B
4417 *--p = 'b';
4418# elif NEED_PRINTF_DIRECTIVE_UPPERCASE_B && !NEED_PRINTF_DIRECTIVE_B
4419 *--p = 'B';
4420# else
4421 *--p = dp->conversion;
4422# endif
4423 *--p = '0';
4424 }
4425 tmp_start = p;
4426
4427 /* The generated string now extends from tmp_start to tmp_end,
4428 with the zero padding insertion point being at pad_ptr,
4429 tmp_start <= pad_ptr <= tmp_end. */
4430 count = tmp_end - tmp_start;
4431
4432 if (count < width)
4433 {
4434 size_t pad = width - count;
4435
4436 if (flags & FLAG_LEFT)
4437 {
4438 /* Pad with spaces on the right. */
4439 for (p = tmp_start; p < tmp_end; p++)
4440 *(p - pad) = *p;
4441 for (p = tmp_end - pad; p < tmp_end; p++)
4442 *p = ' ';
4443 }
4444 else if ((flags & FLAG_ZERO)
4445 /* Neither ISO C nor POSIX specify that the '0'
4446 flag is ignored when a width and a precision
4447 are both present. But most implementations
4448 do so. */
4449 && !(has_width && has_precision))
4450 {
4451 /* Pad with zeroes. */
4452 for (p = tmp_start; p < pad_ptr; p++)
4453 *(p - pad) = *p;
4454 for (p = pad_ptr - pad; p < pad_ptr; p++)
4455 *p = '0';
4456 }
4457 else
4458 {
4459 /* Pad with spaces on the left. */
4460 for (p = tmp_start - pad; p < tmp_start; p++)
4461 *p = ' ';
4462 }
4463
4464 tmp_start = tmp_start - pad;
4465 }
4466
4467 count = tmp_end - tmp_start;
4468
4469 if (count > tmp_length)
4470 /* tmp_length was incorrectly calculated - fix the
4471 code above! */
4472 abort ();
4473
4474 /* Make room for the result. */
4475 if (count >= allocated - length)
4476 {
4477 size_t n = xsum (length, count);
4478
4479 ENSURE_ALLOCATION_ELSE (n,
4480 { if (tmp != tmpbuf) free (tmp); goto out_of_memory; });
4481 }
4482
4483 /* Append the result. */
4484 memcpy (result + length, tmp_start, count * sizeof (DCHAR_T));
4485 if (tmp != tmpbuf)
4486 free (tmp);
4487 length += count;
4488 }
4489#endif
4490#if NEED_PRINTF_DIRECTIVE_A || NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_DOUBLE || (NEED_WPRINTF_DIRECTIVE_LA && WIDE_CHAR_VERSION)
3047 else if ((dp->conversion == 'a' || dp->conversion == 'A') 4491 else if ((dp->conversion == 'a' || dp->conversion == 'A')
3048# if !(NEED_PRINTF_DIRECTIVE_A || (NEED_PRINTF_LONG_DOUBLE && NEED_PRINTF_DOUBLE)) 4492# if !(NEED_PRINTF_DIRECTIVE_A || (NEED_PRINTF_LONG_DOUBLE && NEED_PRINTF_DOUBLE))
3049 && (0 4493 && (0
3050# if NEED_PRINTF_DOUBLE 4494# if NEED_PRINTF_DOUBLE
3051 || a.arg[dp->arg_index].type == TYPE_DOUBLE 4495 || a.arg[dp->arg_index].type == TYPE_DOUBLE
3052# endif 4496# endif
3053# if NEED_PRINTF_LONG_DOUBLE 4497# if NEED_PRINTF_LONG_DOUBLE || (NEED_WPRINTF_DIRECTIVE_LA && WIDE_CHAR_VERSION)
3054 || a.arg[dp->arg_index].type == TYPE_LONGDOUBLE 4498 || a.arg[dp->arg_index].type == TYPE_LONGDOUBLE
3055# endif 4499# endif
3056 ) 4500 )
@@ -3096,6 +4540,8 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
3096 width = xsum (xtimes (width, 10), *digitp++ - '0'); 4540 width = xsum (xtimes (width, 10), *digitp++ - '0');
3097 while (digitp != dp->width_end); 4541 while (digitp != dp->width_end);
3098 } 4542 }
4543 if (width > (size_t) INT_MAX)
4544 goto overflow;
3099 } 4545 }
3100 4546
3101 has_precision = 0; 4547 has_precision = 0;
@@ -3170,7 +4616,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
3170 p = tmp; 4616 p = tmp;
3171 if (type == TYPE_LONGDOUBLE) 4617 if (type == TYPE_LONGDOUBLE)
3172 { 4618 {
3173# if NEED_PRINTF_DIRECTIVE_A || NEED_PRINTF_LONG_DOUBLE 4619# if NEED_PRINTF_DIRECTIVE_A || NEED_PRINTF_LONG_DOUBLE || (NEED_WPRINTF_DIRECTIVE_LA && WIDE_CHAR_VERSION)
3174 long double arg = a.arg[dp->arg_index].a.a_longdouble; 4620 long double arg = a.arg[dp->arg_index].a.a_longdouble;
3175 4621
3176 if (isnanl (arg)) 4622 if (isnanl (arg))
@@ -3290,7 +4736,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
3290 } 4736 }
3291 } 4737 }
3292 *p++ = dp->conversion - 'A' + 'P'; 4738 *p++ = dp->conversion - 'A' + 'P';
3293# if WIDE_CHAR_VERSION 4739# if WIDE_CHAR_VERSION && DCHAR_IS_TCHAR
3294 { 4740 {
3295 static const wchar_t decimal_format[] = 4741 static const wchar_t decimal_format[] =
3296 { '%', '+', 'd', '\0' }; 4742 { '%', '+', 'd', '\0' };
@@ -3441,7 +4887,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
3441 } 4887 }
3442 } 4888 }
3443 *p++ = dp->conversion - 'A' + 'P'; 4889 *p++ = dp->conversion - 'A' + 'P';
3444# if WIDE_CHAR_VERSION 4890# if WIDE_CHAR_VERSION && DCHAR_IS_TCHAR
3445 { 4891 {
3446 static const wchar_t decimal_format[] = 4892 static const wchar_t decimal_format[] =
3447 { '%', '+', 'd', '\0' }; 4893 { '%', '+', 'd', '\0' };
@@ -3523,7 +4969,8 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
3523 { 4969 {
3524 size_t n = xsum (length, count); 4970 size_t n = xsum (length, count);
3525 4971
3526 ENSURE_ALLOCATION (n); 4972 ENSURE_ALLOCATION_ELSE (n,
4973 { if (tmp != tmpbuf) free (tmp); goto out_of_memory; });
3527 } 4974 }
3528 4975
3529 /* Append the result. */ 4976 /* Append the result. */
@@ -3533,7 +4980,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
3533 length += count; 4980 length += count;
3534 } 4981 }
3535#endif 4982#endif
3536#if (NEED_PRINTF_INFINITE_DOUBLE || NEED_PRINTF_DOUBLE || NEED_PRINTF_INFINITE_LONG_DOUBLE || NEED_PRINTF_LONG_DOUBLE) && !defined IN_LIBINTL 4983#if NEED_PRINTF_INFINITE_DOUBLE || NEED_PRINTF_DOUBLE || NEED_PRINTF_INFINITE_LONG_DOUBLE || NEED_PRINTF_LONG_DOUBLE
3537 else if ((dp->conversion == 'f' || dp->conversion == 'F' 4984 else if ((dp->conversion == 'f' || dp->conversion == 'F'
3538 || dp->conversion == 'e' || dp->conversion == 'E' 4985 || dp->conversion == 'e' || dp->conversion == 'E'
3539 || dp->conversion == 'g' || dp->conversion == 'G' 4986 || dp->conversion == 'g' || dp->conversion == 'G'
@@ -3601,6 +5048,8 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
3601 width = xsum (xtimes (width, 10), *digitp++ - '0'); 5048 width = xsum (xtimes (width, 10), *digitp++ - '0');
3602 while (digitp != dp->width_end); 5049 while (digitp != dp->width_end);
3603 } 5050 }
5051 if (width > (size_t) INT_MAX)
5052 goto overflow;
3604 } 5053 }
3605 5054
3606 has_precision = 0; 5055 has_precision = 0;
@@ -3687,6 +5136,17 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
3687 } 5136 }
3688 } 5137 }
3689# endif 5138# endif
5139 /* Account for thousands separators. */
5140 if (flags & FLAG_GROUP)
5141 {
5142 /* A thousands separator needs to be inserted at most every 2 digits.
5143 This is the case in the ta_IN locale. */
5144# if WIDE_CHAR_VERSION
5145 tmp_length = xsum (tmp_length, tmp_length / 2 * THOUSEP_WCHAR_MAXLEN);
5146# else
5147 tmp_length = xsum (tmp_length, tmp_length / 2 * THOUSEP_CHAR_MAXLEN);
5148# endif
5149 }
3690 /* Account for sign, decimal point etc. */ 5150 /* Account for sign, decimal point etc. */
3691 tmp_length = xsum (tmp_length, 12); 5151 tmp_length = xsum (tmp_length, 12);
3692 5152
@@ -3782,12 +5242,84 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
3782 ndigits = strlen (digits); 5242 ndigits = strlen (digits);
3783 5243
3784 if (ndigits > precision) 5244 if (ndigits > precision)
3785 do 5245 {
3786 { 5246 /* Number of digits before the decimal point. */
3787 --ndigits; 5247 size_t intpart_digits = ndigits - precision;
3788 *p++ = digits[ndigits]; 5248
3789 } 5249 const DCHAR_T *thousep = NULL;
3790 while (ndigits > precision); 5250 DCHAR_T thousep_buf[10];
5251# if !WIDE_CHAR_VERSION
5252 size_t thousep_len = 0;
5253# endif
5254 const signed char *grouping;
5255 size_t insert = 0;
5256
5257 if ((flags & FLAG_GROUP) && (intpart_digits > 1))
5258 {
5259 /* Determine the thousands separator and
5260 the grouping rule of the current locale. */
5261# if WIDE_CHAR_VERSION
5262 /* DCHAR_T is wchar_t. */
5263 thousep = thousands_separator_wchar (thousep_buf);
5264# define thousep_len 1
5265# elif defined DCHAR_CONV_FROM_ENCODING
5266 /* DCHAR_T is uintN_t. */
5267 thousep = thousands_separator_DCHAR (thousep_buf);
5268 thousep_len = DCHAR_STRLEN (thousep);
5269# else
5270 /* DCHAR_T is char. */
5271 thousep = thousands_separator_char (thousep_buf);
5272 thousep_len = strlen (thousep);
5273# endif
5274 if (*thousep == 0)
5275 thousep = NULL;
5276 if (thousep != NULL)
5277 {
5278 grouping = grouping_rule ();
5279 insert =
5280 num_thousands_separators (grouping, intpart_digits);
5281 }
5282 }
5283
5284 const char *digitp = digits + precision;
5285 DCHAR_T *p_before_intpart = p;
5286 p += intpart_digits + insert * thousep_len;
5287 DCHAR_T *p_after_intpart = p;
5288 if (insert > 0) /* implies (flag & FLAG_GROUP) && (thousep != NULL) */
5289 {
5290 const signed char *g = grouping;
5291 for (;;)
5292 {
5293 int h = *g;
5294 if (h <= 0)
5295 abort ();
5296 int i = h;
5297 do
5298 *--p = *digitp++;
5299 while (--i > 0);
5300# if WIDE_CHAR_VERSION
5301 *--p = thousep[0];
5302# else
5303 p -= thousep_len;
5304 DCHAR_CPY (p, thousep, thousep_len);
5305# endif
5306 insert--;
5307 if (insert == 0)
5308 break;
5309 if (g[1] != 0)
5310 g++;
5311 }
5312 }
5313 for (;;)
5314 {
5315 *--p = *digitp++;
5316 if (p == p_before_intpart)
5317 break;
5318 }
5319 p = p_after_intpart;
5320 ndigits = precision;
5321# undef thousep_len
5322 }
3791 else 5323 else
3792 *p++ = '0'; 5324 *p++ = '0';
3793 /* Here ndigits <= precision. */ 5325 /* Here ndigits <= precision. */
@@ -3901,7 +5433,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
3901 } 5433 }
3902 5434
3903 *p++ = dp->conversion; /* 'e' or 'E' */ 5435 *p++ = dp->conversion; /* 'e' or 'E' */
3904# if WIDE_CHAR_VERSION 5436# if WIDE_CHAR_VERSION && DCHAR_IS_TCHAR
3905 { 5437 {
3906 static const wchar_t decimal_format[] = 5438 static const wchar_t decimal_format[] =
3907 { '%', '+', '.', '2', 'd', '\0' }; 5439 { '%', '+', '.', '2', 'd', '\0' };
@@ -4040,10 +5572,84 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
4040 digits without trailing zeroes. */ 5572 digits without trailing zeroes. */
4041 if (exponent >= 0) 5573 if (exponent >= 0)
4042 { 5574 {
4043 size_t ecount = exponent + 1; 5575 /* Number of digits before the decimal point. */
4044 /* Note: count <= precision = ndigits. */ 5576 size_t intpart_digits = exponent + 1;
4045 for (; ecount > 0; ecount--) 5577 /* Note: intpart_digits <= precision = ndigits. */
4046 *p++ = digits[--ndigits]; 5578
5579 const DCHAR_T *thousep = NULL;
5580 DCHAR_T thousep_buf[10];
5581# if !WIDE_CHAR_VERSION
5582 size_t thousep_len = 0;
5583# endif
5584 const signed char *grouping;
5585 size_t insert = 0;
5586
5587 if ((flags & FLAG_GROUP) && (intpart_digits > 1))
5588 {
5589 /* Determine the thousands separator and
5590 the grouping rule of the current locale. */
5591# if WIDE_CHAR_VERSION
5592 /* DCHAR_T is wchar_t. */
5593 thousep = thousands_separator_wchar (thousep_buf);
5594# define thousep_len 1
5595# elif defined DCHAR_CONV_FROM_ENCODING
5596 /* DCHAR_T is uintN_t. */
5597 thousep = thousands_separator_DCHAR (thousep_buf);
5598 thousep_len = DCHAR_STRLEN (thousep);
5599# else
5600 /* DCHAR_T is char. */
5601 thousep = thousands_separator_char (thousep_buf);
5602 thousep_len = strlen (thousep);
5603# endif
5604 if (*thousep == 0)
5605 thousep = NULL;
5606 if (thousep != NULL)
5607 {
5608 grouping = grouping_rule ();
5609 insert =
5610 num_thousands_separators (grouping, intpart_digits);
5611 }
5612 }
5613
5614 const char *digitp = digits + ndigits - intpart_digits;
5615 DCHAR_T *p_before_intpart = p;
5616 p += intpart_digits + insert * thousep_len;
5617 DCHAR_T *p_after_intpart = p;
5618 if (insert > 0) /* implies (flag & FLAG_GROUP) && (thousep != NULL) */
5619 {
5620 const signed char *g = grouping;
5621 for (;;)
5622 {
5623 int h = *g;
5624 if (h <= 0)
5625 abort ();
5626 int i = h;
5627 do
5628 *--p = *digitp++;
5629 while (--i > 0);
5630# if WIDE_CHAR_VERSION
5631 *--p = thousep[0];
5632# else
5633 p -= thousep_len;
5634 DCHAR_CPY (p, thousep, thousep_len);
5635# endif
5636 insert--;
5637 if (insert == 0)
5638 break;
5639 if (g[1] != 0)
5640 g++;
5641 }
5642 }
5643 for (;;)
5644 {
5645 *--p = *digitp++;
5646 if (p == p_before_intpart)
5647 break;
5648 }
5649 p = p_after_intpart;
5650 ndigits -= intpart_digits;
5651# undef thousep_len
5652
4047 if ((flags & FLAG_ALT) || ndigits > nzeroes) 5653 if ((flags & FLAG_ALT) || ndigits > nzeroes)
4048 { 5654 {
4049 *p++ = decimal_point_char (); 5655 *p++ = decimal_point_char ();
@@ -4082,7 +5688,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
4082 } 5688 }
4083 } 5689 }
4084 *p++ = dp->conversion - 'G' + 'E'; /* 'e' or 'E' */ 5690 *p++ = dp->conversion - 'G' + 'E'; /* 'e' or 'E' */
4085# if WIDE_CHAR_VERSION 5691# if WIDE_CHAR_VERSION && DCHAR_IS_TCHAR
4086 { 5692 {
4087 static const wchar_t decimal_format[] = 5693 static const wchar_t decimal_format[] =
4088 { '%', '+', '.', '2', 'd', '\0' }; 5694 { '%', '+', '.', '2', 'd', '\0' };
@@ -4244,12 +5850,84 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
4244 ndigits = strlen (digits); 5850 ndigits = strlen (digits);
4245 5851
4246 if (ndigits > precision) 5852 if (ndigits > precision)
4247 do 5853 {
4248 { 5854 /* Number of digits before the decimal point. */
4249 --ndigits; 5855 size_t intpart_digits = ndigits - precision;
4250 *p++ = digits[ndigits]; 5856
4251 } 5857 const DCHAR_T *thousep = NULL;
4252 while (ndigits > precision); 5858 DCHAR_T thousep_buf[10];
5859# if !WIDE_CHAR_VERSION
5860 size_t thousep_len = 0;
5861# endif
5862 const signed char *grouping;
5863 size_t insert = 0;
5864
5865 if ((flags & FLAG_GROUP) && (intpart_digits > 1))
5866 {
5867 /* Determine the thousands separator and
5868 the grouping rule of the current locale. */
5869# if WIDE_CHAR_VERSION
5870 /* DCHAR_T is wchar_t. */
5871 thousep = thousands_separator_wchar (thousep_buf);
5872# define thousep_len 1
5873# elif defined DCHAR_CONV_FROM_ENCODING
5874 /* DCHAR_T is uintN_t. */
5875 thousep = thousands_separator_DCHAR (thousep_buf);
5876 thousep_len = DCHAR_STRLEN (thousep);
5877# else
5878 /* DCHAR_T is char. */
5879 thousep = thousands_separator_char (thousep_buf);
5880 thousep_len = strlen (thousep);
5881# endif
5882 if (*thousep == 0)
5883 thousep = NULL;
5884 if (thousep != NULL)
5885 {
5886 grouping = grouping_rule ();
5887 insert =
5888 num_thousands_separators (grouping, intpart_digits);
5889 }
5890 }
5891
5892 const char *digitp = digits + precision;
5893 DCHAR_T *p_before_intpart = p;
5894 p += intpart_digits + insert * thousep_len;
5895 DCHAR_T *p_after_intpart = p;
5896 if (insert > 0) /* implies (flag & FLAG_GROUP) && (thousep != NULL) */
5897 {
5898 const signed char *g = grouping;
5899 for (;;)
5900 {
5901 int h = *g;
5902 if (h <= 0)
5903 abort ();
5904 int i = h;
5905 do
5906 *--p = *digitp++;
5907 while (--i > 0);
5908# if WIDE_CHAR_VERSION
5909 *--p = thousep[0];
5910# else
5911 p -= thousep_len;
5912 DCHAR_CPY (p, thousep, thousep_len);
5913# endif
5914 insert--;
5915 if (insert == 0)
5916 break;
5917 if (g[1] != 0)
5918 g++;
5919 }
5920 }
5921 for (;;)
5922 {
5923 *--p = *digitp++;
5924 if (p == p_before_intpart)
5925 break;
5926 }
5927 p = p_after_intpart;
5928 ndigits = precision;
5929# undef thousep_len
5930 }
4253 else 5931 else
4254 *p++ = '0'; 5932 *p++ = '0';
4255 /* Here ndigits <= precision. */ 5933 /* Here ndigits <= precision. */
@@ -4359,7 +6037,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
4359 } 6037 }
4360 6038
4361 *p++ = dp->conversion; /* 'e' or 'E' */ 6039 *p++ = dp->conversion; /* 'e' or 'E' */
4362# if WIDE_CHAR_VERSION 6040# if WIDE_CHAR_VERSION && DCHAR_IS_TCHAR
4363 { 6041 {
4364 static const wchar_t decimal_format[] = 6042 static const wchar_t decimal_format[] =
4365 /* Produce the same number of exponent digits 6043 /* Produce the same number of exponent digits
@@ -4510,10 +6188,84 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
4510 digits without trailing zeroes. */ 6188 digits without trailing zeroes. */
4511 if (exponent >= 0) 6189 if (exponent >= 0)
4512 { 6190 {
4513 size_t ecount = exponent + 1; 6191 /* Number of digits before the decimal point. */
4514 /* Note: ecount <= precision = ndigits. */ 6192 size_t intpart_digits = exponent + 1;
4515 for (; ecount > 0; ecount--) 6193 /* Note: intpart_digits <= precision = ndigits. */
4516 *p++ = digits[--ndigits]; 6194
6195 const DCHAR_T *thousep = NULL;
6196 DCHAR_T thousep_buf[10];
6197# if !WIDE_CHAR_VERSION
6198 size_t thousep_len = 0;
6199# endif
6200 const signed char *grouping;
6201 size_t insert = 0;
6202
6203 if ((flags & FLAG_GROUP) && (intpart_digits > 1))
6204 {
6205 /* Determine the thousands separator and
6206 the grouping rule of the current locale. */
6207# if WIDE_CHAR_VERSION
6208 /* DCHAR_T is wchar_t. */
6209 thousep = thousands_separator_wchar (thousep_buf);
6210# define thousep_len 1
6211# elif defined DCHAR_CONV_FROM_ENCODING
6212 /* DCHAR_T is uintN_t. */
6213 thousep = thousands_separator_DCHAR (thousep_buf);
6214 thousep_len = DCHAR_STRLEN (thousep);
6215# else
6216 /* DCHAR_T is char. */
6217 thousep = thousands_separator_char (thousep_buf);
6218 thousep_len = strlen (thousep);
6219# endif
6220 if (*thousep == 0)
6221 thousep = NULL;
6222 if (thousep != NULL)
6223 {
6224 grouping = grouping_rule ();
6225 insert =
6226 num_thousands_separators (grouping, intpart_digits);
6227 }
6228 }
6229
6230 const char *digitp = digits + ndigits - intpart_digits;
6231 DCHAR_T *p_before_intpart = p;
6232 p += intpart_digits + insert * thousep_len;
6233 DCHAR_T *p_after_intpart = p;
6234 if (insert > 0) /* implies (flag & FLAG_GROUP) && (thousep != NULL) */
6235 {
6236 const signed char *g = grouping;
6237 for (;;)
6238 {
6239 int h = *g;
6240 if (h <= 0)
6241 abort ();
6242 int i = h;
6243 do
6244 *--p = *digitp++;
6245 while (--i > 0);
6246# if WIDE_CHAR_VERSION
6247 *--p = thousep[0];
6248# else
6249 p -= thousep_len;
6250 DCHAR_CPY (p, thousep, thousep_len);
6251# endif
6252 insert--;
6253 if (insert == 0)
6254 break;
6255 if (g[1] != 0)
6256 g++;
6257 }
6258 }
6259 for (;;)
6260 {
6261 *--p = *digitp++;
6262 if (p == p_before_intpart)
6263 break;
6264 }
6265 p = p_after_intpart;
6266 ndigits -= intpart_digits;
6267# undef thousep_len
6268
4517 if ((flags & FLAG_ALT) || ndigits > nzeroes) 6269 if ((flags & FLAG_ALT) || ndigits > nzeroes)
4518 { 6270 {
4519 *p++ = decimal_point_char (); 6271 *p++ = decimal_point_char ();
@@ -4552,7 +6304,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
4552 } 6304 }
4553 } 6305 }
4554 *p++ = dp->conversion - 'G' + 'E'; /* 'e' or 'E' */ 6306 *p++ = dp->conversion - 'G' + 'E'; /* 'e' or 'E' */
4555# if WIDE_CHAR_VERSION 6307# if WIDE_CHAR_VERSION && DCHAR_IS_TCHAR
4556 { 6308 {
4557 static const wchar_t decimal_format[] = 6309 static const wchar_t decimal_format[] =
4558 /* Produce the same number of exponent digits 6310 /* Produce the same number of exponent digits
@@ -4706,7 +6458,8 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
4706 { 6458 {
4707 size_t n = xsum (length, count); 6459 size_t n = xsum (length, count);
4708 6460
4709 ENSURE_ALLOCATION (n); 6461 ENSURE_ALLOCATION_ELSE (n,
6462 { if (tmp != tmpbuf) free (tmp); goto out_of_memory; });
4710 } 6463 }
4711 6464
4712 /* Append the result. */ 6465 /* Append the result. */
@@ -4720,24 +6473,29 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
4720 { 6473 {
4721 arg_type type = a.arg[dp->arg_index].type; 6474 arg_type type = a.arg[dp->arg_index].type;
4722 int flags = dp->flags; 6475 int flags = dp->flags;
4723#if !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION 6476#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
4724 int has_width; 6477 int has_width;
4725#endif 6478#endif
4726#if !USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION 6479#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
4727 size_t width; 6480 size_t width;
4728#endif 6481#endif
4729#if !USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || NEED_PRINTF_UNBOUNDED_PRECISION 6482#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
4730 int has_precision; 6483 int has_precision;
4731 size_t precision; 6484 size_t precision;
4732#endif 6485#endif
4733#if NEED_PRINTF_UNBOUNDED_PRECISION 6486#if NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION
4734 int prec_ourselves; 6487 int prec_ourselves;
4735#else 6488#else
4736# define prec_ourselves 0 6489# define prec_ourselves 0
4737#endif 6490#endif
4738#if NEED_PRINTF_FLAG_LEFTADJUST 6491#if NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION || NEED_PRINTF_FLAG_GROUPING || NEED_PRINTF_FLAG_GROUPING_INT
6492 int group_ourselves;
6493#else
6494# define group_ourselves 0
6495#endif
6496#if (WIDE_CHAR_VERSION && MUSL_LIBC) || NEED_PRINTF_FLAG_LEFTADJUST
4739# define pad_ourselves 1 6497# define pad_ourselves 1
4740#elif !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION 6498#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
4741 int pad_ourselves; 6499 int pad_ourselves;
4742#else 6500#else
4743# define pad_ourselves 0 6501# define pad_ourselves 0
@@ -4752,10 +6510,10 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
4752 TCHAR_T *tmp; 6510 TCHAR_T *tmp;
4753#endif 6511#endif
4754 6512
4755#if !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION 6513#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
4756 has_width = 0; 6514 has_width = 0;
4757#endif 6515#endif
4758#if !USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION 6516#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
4759 width = 0; 6517 width = 0;
4760 if (dp->width_start != dp->width_end) 6518 if (dp->width_start != dp->width_end)
4761 { 6519 {
@@ -4783,13 +6541,16 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
4783 width = xsum (xtimes (width, 10), *digitp++ - '0'); 6541 width = xsum (xtimes (width, 10), *digitp++ - '0');
4784 while (digitp != dp->width_end); 6542 while (digitp != dp->width_end);
4785 } 6543 }
4786#if !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION 6544 if (width > (size_t) INT_MAX)
6545 goto overflow;
6546# define WIDTH_IS_CHECKED 1
6547# 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
4787 has_width = 1; 6548 has_width = 1;
4788#endif 6549# endif
4789 } 6550 }
4790#endif 6551#endif
4791 6552
4792#if !USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || NEED_PRINTF_UNBOUNDED_PRECISION 6553#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
4793 has_precision = 0; 6554 has_precision = 0;
4794 precision = 6; 6555 precision = 6;
4795 if (dp->precision_start != dp->precision_end) 6556 if (dp->precision_start != dp->precision_end)
@@ -4822,22 +6583,69 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
4822#endif 6583#endif
4823 6584
4824 /* Decide whether to handle the precision ourselves. */ 6585 /* Decide whether to handle the precision ourselves. */
4825#if NEED_PRINTF_UNBOUNDED_PRECISION 6586#if NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION
4826 switch (dp->conversion) 6587 switch (dp->conversion)
4827 { 6588 {
6589# if NEED_PRINTF_UNBOUNDED_PRECISION
4828 case 'd': case 'i': case 'u': 6590 case 'd': case 'i': case 'u':
6591 case 'b':
6592 #if SUPPORT_GNU_PRINTF_DIRECTIVES \
6593 || (__GLIBC__ + (__GLIBC_MINOR__ >= 35) > 2)
6594 case 'B':
6595 #endif
4829 case 'o': 6596 case 'o':
4830 case 'x': case 'X': case 'p':
4831 prec_ourselves = has_precision && (precision > 0); 6597 prec_ourselves = has_precision && (precision > 0);
4832 break; 6598 break;
6599# endif
6600 case 'x': case 'X': case 'p':
6601 prec_ourselves =
6602 has_precision
6603 && (0
6604# if NEED_PRINTF_FLAG_ALT_PRECISION_ZERO
6605 || (precision == 0)
6606# endif
6607# if NEED_PRINTF_UNBOUNDED_PRECISION
6608 || (precision > 0)
6609# endif
6610 );
6611 break;
4833 default: 6612 default:
4834 prec_ourselves = 0; 6613 prec_ourselves = 0;
4835 break; 6614 break;
4836 } 6615 }
4837#endif 6616#endif
4838 6617
6618 /* Decide whether to add the thousands separators ourselves. */
6619#if NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION || NEED_PRINTF_FLAG_GROUPING || NEED_PRINTF_FLAG_GROUPING_INT
6620 if (flags & FLAG_GROUP)
6621 {
6622 switch (dp->conversion)
6623 {
6624 case 'd': case 'i': case 'u':
6625# if NEED_PRINTF_FLAG_GROUPING || NEED_PRINTF_FLAG_GROUPING_INT
6626 group_ourselves = 1;
6627# else
6628 group_ourselves = prec_ourselves;
6629# endif
6630 break;
6631 case 'f': case 'F': case 'g': case 'G':
6632# if NEED_PRINTF_FLAG_GROUPING
6633 group_ourselves = 1;
6634# else
6635 group_ourselves = prec_ourselves;
6636# endif
6637 break;
6638 default:
6639 group_ourselves = 0;
6640 break;
6641 }
6642 }
6643 else
6644 group_ourselves = 0;
6645#endif
6646
4839 /* Decide whether to perform the padding ourselves. */ 6647 /* Decide whether to perform the padding ourselves. */
4840#if !NEED_PRINTF_FLAG_LEFTADJUST && (!DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION) 6648#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)
4841 switch (dp->conversion) 6649 switch (dp->conversion)
4842 { 6650 {
4843# if !DCHAR_IS_TCHAR || ENABLE_UNISTDIO 6651# if !DCHAR_IS_TCHAR || ENABLE_UNISTDIO
@@ -4854,7 +6662,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
4854 pad_ourselves = 1; 6662 pad_ourselves = 1;
4855 break; 6663 break;
4856 default: 6664 default:
4857 pad_ourselves = prec_ourselves; 6665 pad_ourselves = prec_ourselves | group_ourselves;
4858 break; 6666 break;
4859 } 6667 }
4860#endif 6668#endif
@@ -4887,14 +6695,8 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
4887 sprintf. */ 6695 sprintf. */
4888 fbp = buf; 6696 fbp = buf;
4889 *fbp++ = '%'; 6697 *fbp++ = '%';
4890#if NEED_PRINTF_FLAG_GROUPING 6698 if ((flags & FLAG_GROUP) && !group_ourselves)
4891 /* The underlying implementation doesn't support the ' flag.
4892 Produce no grouping characters in this case; this is
4893 acceptable because the grouping is locale dependent. */
4894#else
4895 if (flags & FLAG_GROUP)
4896 *fbp++ = '\''; 6699 *fbp++ = '\'';
4897#endif
4898 if (flags & FLAG_LEFT) 6700 if (flags & FLAG_LEFT)
4899 *fbp++ = '-'; 6701 *fbp++ = '-';
4900 if (flags & FLAG_SHOWSIGN) 6702 if (flags & FLAG_SHOWSIGN)
@@ -4914,6 +6716,43 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
4914 if (dp->width_start != dp->width_end) 6716 if (dp->width_start != dp->width_end)
4915 { 6717 {
4916 size_t n = dp->width_end - dp->width_start; 6718 size_t n = dp->width_end - dp->width_start;
6719#if !WIDTH_IS_CHECKED
6720 size_t width;
6721 /* Reject an out-of-range width.
6722 The underlying SNPRINTF already does this on some
6723 platforms (glibc, musl, macOS, FreeBSD, NetBSD,
6724 OpenBSD, Cygwin, Solaris, MSVC). However, on others
6725 (AIX, mingw), it doesn't; thus this vasnprintf
6726 invocation would succeed and produce a wrong result.
6727 So, this is redundant on some platforms, but it's a
6728 quick check anyway. */
6729 if (dp->width_arg_index != ARG_NONE)
6730 {
6731 int arg;
6732
6733 if (!(a.arg[dp->width_arg_index].type == TYPE_INT))
6734 abort ();
6735 arg = a.arg[dp->width_arg_index].a.a_int;
6736 width = arg;
6737 if (arg < 0)
6738 {
6739 /* "A negative field width is taken as a '-' flag
6740 followed by a positive field width." */
6741 width = -width;
6742 }
6743 }
6744 else
6745 {
6746 const FCHAR_T *digitp = dp->width_start;
6747
6748 width = 0;
6749 do
6750 width = xsum (xtimes (width, 10), *digitp++ - '0');
6751 while (digitp != dp->width_end);
6752 }
6753 if (width > (size_t) INT_MAX)
6754 goto overflow;
6755#endif
4917 /* The width specification is known to consist only 6756 /* The width specification is known to consist only
4918 of standard ASCII characters. */ 6757 of standard ASCII characters. */
4919 if (sizeof (FCHAR_T) == sizeof (TCHAR_T)) 6758 if (sizeof (FCHAR_T) == sizeof (TCHAR_T))
@@ -4952,10 +6791,58 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
4952 } 6791 }
4953 } 6792 }
4954 6793
4955 switch (type) 6794 switch (+type)
4956 { 6795 {
4957 case TYPE_LONGLONGINT: 6796 case TYPE_LONGLONGINT:
4958 case TYPE_ULONGLONGINT: 6797 case TYPE_ULONGLONGINT:
6798 #if INT8_WIDTH > LONG_WIDTH
6799 case TYPE_INT8_T:
6800 #endif
6801 #if UINT8_WIDTH > LONG_WIDTH
6802 case TYPE_UINT8_T:
6803 #endif
6804 #if INT16_WIDTH > LONG_WIDTH
6805 case TYPE_INT16_T:
6806 #endif
6807 #if UINT16_WIDTH > LONG_WIDTH
6808 case TYPE_UINT16_T:
6809 #endif
6810 #if INT32_WIDTH > LONG_WIDTH
6811 case TYPE_INT32_T:
6812 #endif
6813 #if UINT32_WIDTH > LONG_WIDTH
6814 case TYPE_UINT32_T:
6815 #endif
6816 #if INT64_WIDTH > LONG_WIDTH
6817 case TYPE_INT64_T:
6818 #endif
6819 #if UINT64_WIDTH > LONG_WIDTH
6820 case TYPE_UINT64_T:
6821 #endif
6822 #if INT_FAST8_WIDTH > LONG_WIDTH
6823 case TYPE_INT_FAST8_T:
6824 #endif
6825 #if UINT_FAST8_WIDTH > LONG_WIDTH
6826 case TYPE_UINT_FAST8_T:
6827 #endif
6828 #if INT_FAST16_WIDTH > LONG_WIDTH
6829 case TYPE_INT_FAST16_T:
6830 #endif
6831 #if UINT_FAST16_WIDTH > LONG_WIDTH
6832 case TYPE_UINT_FAST16_T:
6833 #endif
6834 #if INT_FAST32_WIDTH > LONG_WIDTH
6835 case TYPE_INT3_FAST2_T:
6836 #endif
6837 #if UINT_FAST32_WIDTH > LONG_WIDTH
6838 case TYPE_UINT_FAST32_T:
6839 #endif
6840 #if INT_FAST64_WIDTH > LONG_WIDTH
6841 case TYPE_INT_FAST64_T:
6842 #endif
6843 #if UINT_FAST64_WIDTH > LONG_WIDTH
6844 case TYPE_UINT_FAST64_T:
6845 #endif
4959#if defined _WIN32 && ! defined __CYGWIN__ 6846#if defined _WIN32 && ! defined __CYGWIN__
4960 *fbp++ = 'I'; 6847 *fbp++ = 'I';
4961 *fbp++ = '6'; 6848 *fbp++ = '6';
@@ -4967,12 +6854,58 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
4967 FALLTHROUGH; 6854 FALLTHROUGH;
4968 case TYPE_LONGINT: 6855 case TYPE_LONGINT:
4969 case TYPE_ULONGINT: 6856 case TYPE_ULONGINT:
4970#if HAVE_WINT_T 6857 #if INT8_WIDTH > INT_WIDTH && INT8_WIDTH <= LONG_WIDTH
6858 case TYPE_INT8_T:
6859 #endif
6860 #if UINT8_WIDTH > INT_WIDTH && UINT8_WIDTH <= LONG_WIDTH
6861 case TYPE_UINT8_T:
6862 #endif
6863 #if INT16_WIDTH > INT_WIDTH && INT16_WIDTH <= LONG_WIDTH
6864 case TYPE_INT16_T:
6865 #endif
6866 #if UINT16_WIDTH > INT_WIDTH && UINT16_WIDTH <= LONG_WIDTH
6867 case TYPE_UINT16_T:
6868 #endif
6869 #if INT32_WIDTH > INT_WIDTH && INT32_WIDTH <= LONG_WIDTH
6870 case TYPE_INT32_T:
6871 #endif
6872 #if UINT32_WIDTH > INT_WIDTH && UINT32_WIDTH <= LONG_WIDTH
6873 case TYPE_UINT32_T:
6874 #endif
6875 #if INT64_WIDTH > INT_WIDTH && INT64_WIDTH <= LONG_WIDTH
6876 case TYPE_INT64_T:
6877 #endif
6878 #if UINT64_WIDTH > INT_WIDTH && UINT64_WIDTH <= LONG_WIDTH
6879 case TYPE_UINT64_T:
6880 #endif
6881 #if INT_FAST8_WIDTH > INT_WIDTH && INT_FAST8_WIDTH <= LONG_WIDTH
6882 case TYPE_INT_FAST8_T:
6883 #endif
6884 #if UINT_FAST8_WIDTH > INT_WIDTH && UINT_FAST8_WIDTH <= LONG_WIDTH
6885 case TYPE_UINT_FAST8_T:
6886 #endif
6887 #if INT_FAST16_WIDTH > INT_WIDTH && INT_FAST16_WIDTH <= LONG_WIDTH
6888 case TYPE_INT_FAST16_T:
6889 #endif
6890 #if UINT_FAST16_WIDTH > INT_WIDTH && UINT_FAST16_WIDTH <= LONG_WIDTH
6891 case TYPE_UINT_FAST16_T:
6892 #endif
6893 #if INT_FAST32_WIDTH > INT_WIDTH && INT_FAST32_WIDTH <= LONG_WIDTH
6894 case TYPE_INT_FAST32_T:
6895 #endif
6896 #if UINT_FAST32_WIDTH > INT_WIDTH && UINT_FAST32_WIDTH <= LONG_WIDTH
6897 case TYPE_UINT_FAST32_T:
6898 #endif
6899 #if INT_FAST64_WIDTH > INT_WIDTH && INT_FAST64_WIDTH <= LONG_WIDTH
6900 case TYPE_INT_FAST64_T:
6901 #endif
6902 #if UINT_FAST64_WIDTH > INT_WIDTH && UINT_FAST64_WIDTH <= LONG_WIDTH
6903 case TYPE_UINT_FAST64_T:
6904 #endif
6905 #if HAVE_WINT_T
4971 case TYPE_WIDE_CHAR: 6906 case TYPE_WIDE_CHAR:
4972#endif 6907 #endif
4973#if HAVE_WCHAR_T
4974 case TYPE_WIDE_STRING: 6908 case TYPE_WIDE_STRING:
4975#endif
4976 *fbp++ = 'l'; 6909 *fbp++ = 'l';
4977 break; 6910 break;
4978 case TYPE_LONGDOUBLE: 6911 case TYPE_LONGDOUBLE:
@@ -4988,47 +6921,74 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
4988#endif 6921#endif
4989 *fbp = dp->conversion; 6922 *fbp = dp->conversion;
4990#if USE_SNPRINTF 6923#if USE_SNPRINTF
4991# if ((HAVE_SNPRINTF_RETVAL_C99 && HAVE_SNPRINTF_TRUNCATION_C99) \ 6924 /* Decide whether to pass %n in the format string
6925 to SNPRINTF. */
6926# if (((!WIDE_CHAR_VERSION || !DCHAR_IS_TCHAR) \
6927 && (HAVE_SNPRINTF_RETVAL_C99 && HAVE_SNPRINTF_TRUNCATION_C99)) \
4992 || ((__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 3)) \ 6928 || ((__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 3)) \
4993 && !defined __UCLIBC__) \ 6929 && !defined __UCLIBC__) \
4994 || (defined __APPLE__ && defined __MACH__) \ 6930 || (defined __APPLE__ && defined __MACH__) \
6931 || defined __OpenBSD__ \
4995 || defined __ANDROID__ \ 6932 || defined __ANDROID__ \
4996 || (defined _WIN32 && ! defined __CYGWIN__)) 6933 || (defined _WIN32 && ! defined __CYGWIN__)) \
4997 /* On systems where we know that snprintf's return value 6934 || (WIDE_CHAR_VERSION && MUSL_LIBC)
4998 conforms to ISO C 99 (HAVE_SNPRINTF_RETVAL_C99) and that 6935 /* We can avoid passing %n and instead rely on SNPRINTF's
4999 snprintf always produces NUL-terminated strings 6936 return value if
5000 (HAVE_SNPRINTF_TRUNCATION_C99), it is possible to avoid 6937 - !WIDE_CHAR_VERSION || !DCHAR_IS_TCHAR, because otherwise,
5001 using %n. And it is desirable to do so, because more and 6938 when WIDE_CHAR_VERSION && DCHAR_IS_TCHAR,
5002 more platforms no longer support %n, for "security reasons". 6939 snwprintf()/_snwprintf() (Windows) and swprintf() (Unix)
5003 In particular, the following platforms: 6940 don't return the needed buffer size,
6941 and
6942 - we're compiling for a system where we know
6943 - that snprintf's return value conforms to ISO C 99
6944 (HAVE_SNPRINTF_RETVAL_C99) and
6945 - that snprintf always produces NUL-terminated strings
6946 (HAVE_SNPRINTF_TRUNCATION_C99).
6947 And it is desirable to do so, because more and more platforms
6948 no longer support %n, for "security reasons". */
6949 /* On specific platforms, listed below, we *must* avoid %n.
6950 In the case
6951 !WIDE_CHAR_VERSION && HAVE_SNPRINTF_RETVAL_C99 && !USE_MSVC__SNPRINTF
6952 we can rely on the return value of snprintf instead. Whereas
6953 in the opposite case
6954 WIDE_CHAR_VERSION || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF
6955 we need to make room based on an estimation, computed by
6956 MAX_ROOM_NEEDED. */
6957 /* The following platforms forbid %n:
5004 - On glibc2 systems from 2004-10-18 or newer, the use of 6958 - On glibc2 systems from 2004-10-18 or newer, the use of
5005 %n in format strings in writable memory may crash the 6959 %n in format strings in writable memory may crash the
5006 program (if compiled with _FORTIFY_SOURCE=2). 6960 program (if compiled with _FORTIFY_SOURCE=2).
5007 - On Mac OS X 10.13 or newer, the use of %n in format 6961 - On macOS 10.13 or newer, the use of %n in format
5008 strings in writable memory by default crashes the 6962 strings in writable memory by default crashes the
5009 program. 6963 program.
6964 - On OpenBSD, since 2021-08-30, the use of %n in format
6965 strings produces an abort (see
6966 <https://cvsweb.openbsd.org/cgi-bin/cvsweb/src/lib/libc/stdio/vfprintf.c.diff?r1=1.79&r2=1.80&f=h>,
6967 <https://cvsweb.openbsd.org/cgi-bin/cvsweb/src/lib/libc/stdio/vfwprintf.c.diff?r1=1.20&r2=1.21&f=h>).
5010 - On Android, starting on 2018-03-07, the use of %n in 6968 - On Android, starting on 2018-03-07, the use of %n in
5011 format strings produces a fatal error (see 6969 format strings produces a fatal error (see
5012 <https://android.googlesource.com/platform/bionic/+/41398d03b7e8e0dfb951660ae713e682e9fc0336>). 6970 <https://android.googlesource.com/platform/bionic/+/41398d03b7e8e0dfb951660ae713e682e9fc0336>).
5013 On these platforms, HAVE_SNPRINTF_RETVAL_C99 and 6971 - On native Windows systems (such as mingw) where the OS is
5014 HAVE_SNPRINTF_TRUNCATION_C99 are 1. We have listed them 6972 Windows Vista, the use of %n in format strings by default
5015 explicitly in the condition above, in case of cross- 6973 crashes the program. See
5016 compilation (just to be sure). */ 6974 <https://gcc.gnu.org/ml/gcc/2007-06/msg00122.html> and
5017 /* On native Windows systems (such as mingw), we can avoid using 6975 <https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/set-printf-count-output>
5018 %n because: 6976 On the first four of these platforms, if !WIDE_CHAR_VERSION,
6977 it is not a big deal to avoid %n, because on these platforms,
6978 HAVE_SNPRINTF_RETVAL_C99 and HAVE_SNPRINTF_TRUNCATION_C99 are
6979 1.
6980 On native Windows, if !WIDE_CHAR_VERSION, it's not a big deal
6981 either because:
5019 - Although the gl_SNPRINTF_TRUNCATION_C99 test fails, 6982 - Although the gl_SNPRINTF_TRUNCATION_C99 test fails,
5020 snprintf does not write more than the specified number 6983 snprintf does not write more than the specified number
5021 of bytes. (snprintf (buf, 3, "%d %d", 4567, 89) writes 6984 of bytes. (snprintf (buf, 3, "%d %d", 4567, 89) writes
5022 '4', '5', '6' into buf, not '4', '5', '\0'.) 6985 '4', '5', '6' into buf, not '4', '5', '\0'.)
5023 - Although the gl_SNPRINTF_RETVAL_C99 test fails, snprintf 6986 - Although the gl_SNPRINTF_RETVAL_C99 test fails, snprintf
5024 allows us to recognize the case of an insufficient 6987 allows us to recognize the case of an insufficient
5025 buffer size: it returns -1 in this case. 6988 buffer size: it returns -1 in this case. */
5026 On native Windows systems (such as mingw) where the OS is 6989 /* Additionally, in the WIDE_CHAR_VERSION case, we cannot use %n
5027 Windows Vista, the use of %n in format strings by default 6990 on musl libc because we would run into an swprintf() bug.
5028 crashes the program. See 6991 See <https://www.openwall.com/lists/musl/2023/03/19/1>. */
5029 <https://gcc.gnu.org/ml/gcc/2007-06/msg00122.html> and
5030 <https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/set-printf-count-output>
5031 So we should avoid %n in this situation. */
5032 fbp[1] = '\0'; 6992 fbp[1] = '\0';
5033# else /* AIX <= 5.1, HP-UX, IRIX, OSF/1, Solaris <= 9, BeOS */ 6993# else /* AIX <= 5.1, HP-UX, IRIX, OSF/1, Solaris <= 9, BeOS */
5034 fbp[1] = '%'; 6994 fbp[1] = '%';
@@ -5127,7 +7087,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
5127#endif 7087#endif
5128 7088
5129 errno = 0; 7089 errno = 0;
5130 switch (type) 7090 switch (+type)
5131 { 7091 {
5132 case TYPE_SCHAR: 7092 case TYPE_SCHAR:
5133 { 7093 {
@@ -5189,6 +7149,102 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
5189 SNPRINTF_BUF (arg); 7149 SNPRINTF_BUF (arg);
5190 } 7150 }
5191 break; 7151 break;
7152 case TYPE_INT8_T:
7153 {
7154 int8_t arg = a.arg[dp->arg_index].a.a_int8_t;
7155 SNPRINTF_BUF (arg);
7156 }
7157 break;
7158 case TYPE_UINT8_T:
7159 {
7160 uint8_t arg = a.arg[dp->arg_index].a.a_uint8_t;
7161 SNPRINTF_BUF (arg);
7162 }
7163 break;
7164 case TYPE_INT16_T:
7165 {
7166 int16_t arg = a.arg[dp->arg_index].a.a_int16_t;
7167 SNPRINTF_BUF (arg);
7168 }
7169 break;
7170 case TYPE_UINT16_T:
7171 {
7172 uint16_t arg = a.arg[dp->arg_index].a.a_uint16_t;
7173 SNPRINTF_BUF (arg);
7174 }
7175 break;
7176 case TYPE_INT32_T:
7177 {
7178 int32_t arg = a.arg[dp->arg_index].a.a_int32_t;
7179 SNPRINTF_BUF (arg);
7180 }
7181 break;
7182 case TYPE_UINT32_T:
7183 {
7184 uint32_t arg = a.arg[dp->arg_index].a.a_uint32_t;
7185 SNPRINTF_BUF (arg);
7186 }
7187 break;
7188 case TYPE_INT64_T:
7189 {
7190 int64_t arg = a.arg[dp->arg_index].a.a_int64_t;
7191 SNPRINTF_BUF (arg);
7192 }
7193 break;
7194 case TYPE_UINT64_T:
7195 {
7196 uint64_t arg = a.arg[dp->arg_index].a.a_uint64_t;
7197 SNPRINTF_BUF (arg);
7198 }
7199 break;
7200 case TYPE_INT_FAST8_T:
7201 {
7202 int_fast8_t arg = a.arg[dp->arg_index].a.a_int_fast8_t;
7203 SNPRINTF_BUF (arg);
7204 }
7205 break;
7206 case TYPE_UINT_FAST8_T:
7207 {
7208 uint_fast8_t arg = a.arg[dp->arg_index].a.a_uint_fast8_t;
7209 SNPRINTF_BUF (arg);
7210 }
7211 break;
7212 case TYPE_INT_FAST16_T:
7213 {
7214 int_fast16_t arg = a.arg[dp->arg_index].a.a_int_fast16_t;
7215 SNPRINTF_BUF (arg);
7216 }
7217 break;
7218 case TYPE_UINT_FAST16_T:
7219 {
7220 uint_fast16_t arg = a.arg[dp->arg_index].a.a_uint_fast16_t;
7221 SNPRINTF_BUF (arg);
7222 }
7223 break;
7224 case TYPE_INT_FAST32_T:
7225 {
7226 int_fast32_t arg = a.arg[dp->arg_index].a.a_int_fast32_t;
7227 SNPRINTF_BUF (arg);
7228 }
7229 break;
7230 case TYPE_UINT_FAST32_T:
7231 {
7232 uint_fast32_t arg = a.arg[dp->arg_index].a.a_uint_fast32_t;
7233 SNPRINTF_BUF (arg);
7234 }
7235 break;
7236 case TYPE_INT_FAST64_T:
7237 {
7238 int_fast64_t arg = a.arg[dp->arg_index].a.a_int_fast64_t;
7239 SNPRINTF_BUF (arg);
7240 }
7241 break;
7242 case TYPE_UINT_FAST64_T:
7243 {
7244 uint_fast64_t arg = a.arg[dp->arg_index].a.a_uint_fast64_t;
7245 SNPRINTF_BUF (arg);
7246 }
7247 break;
5192 case TYPE_DOUBLE: 7248 case TYPE_DOUBLE:
5193 { 7249 {
5194 double arg = a.arg[dp->arg_index].a.a_double; 7250 double arg = a.arg[dp->arg_index].a.a_double;
@@ -5221,14 +7277,12 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
5221 SNPRINTF_BUF (arg); 7277 SNPRINTF_BUF (arg);
5222 } 7278 }
5223 break; 7279 break;
5224#if HAVE_WCHAR_T
5225 case TYPE_WIDE_STRING: 7280 case TYPE_WIDE_STRING:
5226 { 7281 {
5227 const wchar_t *arg = a.arg[dp->arg_index].a.a_wide_string; 7282 const wchar_t *arg = a.arg[dp->arg_index].a.a_wide_string;
5228 SNPRINTF_BUF (arg); 7283 SNPRINTF_BUF (arg);
5229 } 7284 }
5230 break; 7285 break;
5231#endif
5232 case TYPE_POINTER: 7286 case TYPE_POINTER:
5233 { 7287 {
5234 void *arg = a.arg[dp->arg_index].a.a_pointer; 7288 void *arg = a.arg[dp->arg_index].a.a_pointer;
@@ -5271,12 +7325,16 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
5271 /* Look at the snprintf() return value. */ 7325 /* Look at the snprintf() return value. */
5272 if (retcount < 0) 7326 if (retcount < 0)
5273 { 7327 {
5274# if !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF 7328# if (WIDE_CHAR_VERSION && DCHAR_IS_TCHAR) || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF
5275 /* HP-UX 10.20 snprintf() is doubly deficient: 7329 /* HP-UX 10.20 snprintf() is doubly deficient:
5276 It doesn't understand the '%n' directive, 7330 It doesn't understand the '%n' directive,
5277 *and* it returns -1 (rather than the length 7331 *and* it returns -1 (rather than the length
5278 that would have been required) when the 7332 that would have been required) when the
5279 buffer is too small. 7333 buffer is too small.
7334 Likewise, in case of
7335 WIDE_CHAR_VERSION && DCHAR_IS_TCHAR, the
7336 functions snwprintf()/_snwprintf() (Windows)
7337 or swprintf() (Unix).
5280 But a failure at this point can also come 7338 But a failure at this point can also come
5281 from other reasons than a too small buffer, 7339 from other reasons than a too small buffer,
5282 such as an invalid wide string argument to 7340 such as an invalid wide string argument to
@@ -5312,7 +7370,15 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
5312# endif 7370# endif
5313 } 7371 }
5314 else 7372 else
5315 count = retcount; 7373 {
7374 count = retcount;
7375# if WIDE_CHAR_VERSION && defined __MINGW32__
7376 if (count == 0 && dp->conversion == 'c')
7377 /* snwprintf returned 0 instead of 1. But it
7378 wrote a null wide character. */
7379 count = 1;
7380# endif
7381 }
5316 } 7382 }
5317 } 7383 }
5318#endif 7384#endif
@@ -5370,7 +7436,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
5370 } 7436 }
5371#endif 7437#endif
5372 7438
5373#if NEED_PRINTF_UNBOUNDED_PRECISION 7439#if NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION
5374 if (prec_ourselves) 7440 if (prec_ourselves)
5375 { 7441 {
5376 /* Handle the precision. */ 7442 /* Handle the precision. */
@@ -5390,10 +7456,13 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
5390 || *prec_ptr == ' ')) 7456 || *prec_ptr == ' '))
5391 prefix_count = 1; 7457 prefix_count = 1;
5392 /* Put the additional zeroes after the 0x prefix if 7458 /* Put the additional zeroes after the 0x prefix if
5393 (flags & FLAG_ALT) || (dp->conversion == 'p'). */ 7459 (flags & FLAG_ALT) || (dp->conversion == 'p'), or
7460 after the 0b prefix if (flags & FLAG_ALT). */
5394 else if (count >= 2 7461 else if (count >= 2
5395 && prec_ptr[0] == '0' 7462 && prec_ptr[0] == '0'
5396 && (prec_ptr[1] == 'x' || prec_ptr[1] == 'X')) 7463 && (prec_ptr[1] == 'x' || prec_ptr[1] == 'X'
7464 || prec_ptr[1] == 'b'
7465 || prec_ptr[1] == 'B'))
5397 prefix_count = 2; 7466 prefix_count = 2;
5398 7467
5399 move = count - prefix_count; 7468 move = count - prefix_count;
@@ -5430,9 +7499,147 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
5430 7499
5431 count += insert; 7500 count += insert;
5432 } 7501 }
7502# if NEED_PRINTF_FLAG_ALT_PRECISION_ZERO
7503 else if (precision == 0
7504 && move == 1
7505 && prec_ptr[prefix_count] == '0')
7506 {
7507 /* Replace the "0" result with an empty string. */
7508 count = prefix_count;
7509 }
7510# endif
5433 } 7511 }
5434#endif 7512#endif
5435 7513
7514#if NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION || NEED_PRINTF_FLAG_GROUPING || NEED_PRINTF_FLAG_GROUPING_INT
7515 if (group_ourselves) /* implies (flags & FLAG_GROUP) */
7516 /* Handle the grouping. */
7517 switch (dp->conversion)
7518 {
7519 /* These are the only conversion to which grouping
7520 applies. */
7521 case 'd': case 'i': case 'u':
7522 case 'f': case 'F': case 'g': case 'G':
7523 {
7524 /* Determine the thousands separator of the current
7525 locale. */
7526 const TCHAR_T *thousep;
7527 TCHAR_T thousep_buf[10];
7528
7529# if WIDE_CHAR_VERSION && DCHAR_IS_TCHAR
7530 /* TCHAR_T is wchar_t. */
7531 thousep = thousands_separator_wchar (thousep_buf);
7532# else
7533 /* TCHAR_T is char. */
7534 thousep = thousands_separator_char (thousep_buf);
7535# endif
7536
7537 /* Nothing to do in locales where thousep is the empty
7538 string. */
7539 if (*thousep != 0)
7540 {
7541 /* Since FLAG_LOCALIZED is only supported on glibc
7542 systems, here we can assume that all digits are
7543 the ASCII digits '0'..'9'. */
7544 TCHAR_T *number_ptr =
7545# if USE_SNPRINTF
7546 (TCHAR_T *) (result + length);
7547# else
7548 tmp;
7549# endif
7550 TCHAR_T *end_ptr = number_ptr + count;
7551
7552 /* Find where the leading digits start. */
7553 TCHAR_T *digits_ptr = number_ptr;
7554 if (count >= 1
7555 && (*digits_ptr == '-' || *digits_ptr == '+'
7556 || *digits_ptr == ' '))
7557 digits_ptr++;
7558
7559 /* Find where the leading digits end. */
7560 TCHAR_T *digits_end_ptr;
7561 switch (dp->conversion)
7562 {
7563 case 'd': case 'i': case 'u':
7564 digits_end_ptr = end_ptr;
7565 break;
7566 case 'f': case 'F': case 'g': case 'G':
7567 {
7568 TCHAR_T decimal_point = decimal_point_char ();
7569 for (digits_end_ptr = digits_ptr;
7570 digits_end_ptr < end_ptr;
7571 digits_end_ptr++)
7572 if (*digits_end_ptr == decimal_point
7573 || *digits_end_ptr == 'e')
7574 break;
7575 }
7576 break;
7577 }
7578
7579 /* Determine the number of thousands separators
7580 to insert. */
7581 const signed char *grouping = grouping_rule ();
7582 size_t insert =
7583 num_thousands_separators (grouping, digits_end_ptr - digits_ptr);
7584 if (insert > 0)
7585 {
7586# if WIDE_CHAR_VERSION && DCHAR_IS_TCHAR
7587# define thousep_len 1
7588# else
7589 size_t thousep_len = strlen (thousep);
7590# endif
7591# if USE_SNPRINTF
7592 size_t digits_offset = digits_ptr - number_ptr;
7593 size_t digits_end_offset = digits_end_ptr - number_ptr;
7594 size_t n =
7595 xsum (length,
7596 (count + insert * thousep_len + TCHARS_PER_DCHAR - 1)
7597 / TCHARS_PER_DCHAR);
7598 length += (count + TCHARS_PER_DCHAR - 1) / TCHARS_PER_DCHAR;
7599 ENSURE_ALLOCATION (n);
7600 length -= (count + TCHARS_PER_DCHAR - 1) / TCHARS_PER_DCHAR;
7601 number_ptr = (TCHAR_T *) (result + length);
7602 end_ptr = number_ptr + count;
7603 digits_ptr = number_ptr + digits_offset;
7604 digits_end_ptr = number_ptr + digits_end_offset;
7605# endif
7606
7607 count += insert * thousep_len;
7608
7609 const TCHAR_T *p = end_ptr;
7610 TCHAR_T *q = end_ptr + insert * thousep_len;
7611 while (p > digits_end_ptr)
7612 *--q = *--p;
7613 const signed char *g = grouping;
7614 for (;;)
7615 {
7616 int h = *g;
7617 if (h <= 0)
7618 abort ();
7619 int i = h;
7620 do
7621 *--q = *--p;
7622 while (--i > 0);
7623# if WIDE_CHAR_VERSION && DCHAR_IS_TCHAR
7624 *--q = *thousep;
7625# else
7626 q -= thousep_len;
7627 memcpy (q, thousep, thousep_len);
7628# endif
7629 insert--;
7630 if (insert == 0)
7631 break;
7632 if (g[1] != 0)
7633 g++;
7634 }
7635 /* Here q == p. Done with the insertions. */
7636 }
7637 }
7638 }
7639 break;
7640 }
7641#endif
7642
5436#if !USE_SNPRINTF 7643#if !USE_SNPRINTF
5437 if (count >= tmp_length) 7644 if (count >= tmp_length)
5438 /* tmp_length was incorrectly calculated - fix the 7645 /* tmp_length was incorrectly calculated - fix the
@@ -5442,11 +7649,14 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
5442 7649
5443#if !DCHAR_IS_TCHAR 7650#if !DCHAR_IS_TCHAR
5444 /* Convert from TCHAR_T[] to DCHAR_T[]. */ 7651 /* Convert from TCHAR_T[] to DCHAR_T[]. */
5445 if (dp->conversion == 'c' || dp->conversion == 's') 7652 if (dp->conversion == 'c' || dp->conversion == 's'
7653 || (flags & FLAG_GROUP)
7654# if __GLIBC__ >= 2 && !defined __UCLIBC__
7655 || (flags & FLAG_LOCALIZED)
7656# endif
7657 )
5446 { 7658 {
5447 /* type = TYPE_CHAR or TYPE_WIDE_CHAR or TYPE_STRING 7659 /* The result string is not guaranteed to be ASCII. */
5448 TYPE_WIDE_STRING.
5449 The result string is not certainly ASCII. */
5450 const TCHAR_T *tmpsrc; 7660 const TCHAR_T *tmpsrc;
5451 DCHAR_T *tmpdst; 7661 DCHAR_T *tmpdst;
5452 size_t tmpdst_len; 7662 size_t tmpdst_len;
@@ -5457,6 +7667,56 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
5457# else 7667# else
5458 tmpsrc = tmp; 7668 tmpsrc = tmp;
5459# endif 7669# endif
7670# if WIDE_CHAR_VERSION
7671 /* Convert tmpsrc[0..count-1] to a freshly allocated
7672 wide character array. */
7673 mbstate_t state;
7674
7675 mbszero (&state);
7676 tmpdst_len = 0;
7677 {
7678 const TCHAR_T *src = tmpsrc;
7679 size_t srclen = count;
7680
7681 for (; srclen > 0; tmpdst_len++)
7682 {
7683 /* Parse the next multibyte character. */
7684 size_t ret = mbrtowc (NULL, src, srclen, &state);
7685 if (ret == (size_t)(-2) || ret == (size_t)(-1))
7686 goto fail_with_EILSEQ;
7687 if (ret == 0)
7688 ret = 1;
7689 src += ret;
7690 srclen -= ret;
7691 }
7692 }
7693
7694 tmpdst =
7695 (wchar_t *) malloc ((tmpdst_len + 1) * sizeof (wchar_t));
7696 if (tmpdst == NULL)
7697 goto out_of_memory;
7698
7699 mbszero (&state);
7700 {
7701 DCHAR_T *destptr = tmpdst;
7702 const TCHAR_T *src = tmpsrc;
7703 size_t srclen = count;
7704
7705 for (; srclen > 0; destptr++)
7706 {
7707 /* Parse the next multibyte character. */
7708 size_t ret = mbrtowc (destptr, src, srclen, &state);
7709 if (ret == (size_t)(-2) || ret == (size_t)(-1))
7710 /* Should already have been caught in the first
7711 loop, above. */
7712 abort ();
7713 if (ret == 0)
7714 ret = 1;
7715 src += ret;
7716 srclen -= ret;
7717 }
7718 }
7719# else
5460 tmpdst = 7720 tmpdst =
5461 DCHAR_CONV_FROM_ENCODING (locale_charset (), 7721 DCHAR_CONV_FROM_ENCODING (locale_charset (),
5462 iconveh_question_mark, 7722 iconveh_question_mark,
@@ -5465,8 +7725,9 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
5465 NULL, &tmpdst_len); 7725 NULL, &tmpdst_len);
5466 if (tmpdst == NULL) 7726 if (tmpdst == NULL)
5467 goto fail_with_errno; 7727 goto fail_with_errno;
7728# endif
5468 ENSURE_ALLOCATION_ELSE (xsum (length, tmpdst_len), 7729 ENSURE_ALLOCATION_ELSE (xsum (length, tmpdst_len),
5469 { free (tmpdst); goto out_of_memory; }); 7730 { free (tmpdst); goto out_of_memory; });
5470 DCHAR_CPY (result + length, tmpdst, tmpdst_len); 7731 DCHAR_CPY (result + length, tmpdst, tmpdst_len);
5471 free (tmpdst); 7732 free (tmpdst);
5472 count = tmpdst_len; 7733 count = tmpdst_len;
@@ -5531,7 +7792,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
5531 /* Here count <= allocated - length. */ 7792 /* Here count <= allocated - length. */
5532 7793
5533 /* Perform padding. */ 7794 /* Perform padding. */
5534#if !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION 7795#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
5535 if (pad_ourselves && has_width) 7796 if (pad_ourselves && has_width)
5536 { 7797 {
5537 size_t w; 7798 size_t w;
@@ -5540,6 +7801,23 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
5540 against the number of _characters_ of the converted 7801 against the number of _characters_ of the converted
5541 value. */ 7802 value. */
5542 w = DCHAR_MBSNLEN (result + length, count); 7803 w = DCHAR_MBSNLEN (result + length, count);
7804# elif __GLIBC__ >= 2
7805 /* glibc prefers to compare the width against the number
7806 of characters as well, but only for numeric conversion
7807 specifiers. See
7808 <https://sourceware.org/bugzilla/show_bug.cgi?id=28943>
7809 <https://sourceware.org/bugzilla/show_bug.cgi?id=30883>
7810 <https://sourceware.org/bugzilla/show_bug.cgi?id=31542> */
7811 switch (dp->conversion)
7812 {
7813 case 'd': case 'i': case 'u':
7814 case 'f': case 'F': case 'g': case 'G':
7815 w = DCHAR_MBSNLEN (result + length, count);
7816 break;
7817 default:
7818 w = count;
7819 break;
7820 }
5543# else 7821# else
5544 /* The width is compared against the number of _bytes_ 7822 /* The width is compared against the number of _bytes_
5545 of the converted value, says POSIX. */ 7823 of the converted value, says POSIX. */
@@ -5590,6 +7868,22 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
5590 if ((*pad_ptr >= 'A' && *pad_ptr <= 'Z') 7868 if ((*pad_ptr >= 'A' && *pad_ptr <= 'Z')
5591 || (*pad_ptr >= 'a' && *pad_ptr <= 'z')) 7869 || (*pad_ptr >= 'a' && *pad_ptr <= 'z'))
5592 pad_ptr = NULL; 7870 pad_ptr = NULL;
7871 else
7872 /* Do the zero-padding after the "0x" or
7873 "0b" prefix, not before. */
7874 if (p - rp >= 2
7875 && *rp == '0'
7876 && (((dp->conversion == 'a'
7877 || dp->conversion == 'x')
7878 && rp[1] == 'x')
7879 || ((dp->conversion == 'A'
7880 || dp->conversion == 'X')
7881 && rp[1] == 'X')
7882 || (dp->conversion == 'b'
7883 && rp[1] == 'b')
7884 || (dp->conversion == 'B'
7885 && rp[1] == 'B')))
7886 pad_ptr += 2;
5593 } 7887 }
5594 /* The generated string now extends from rp to p, 7888 /* The generated string now extends from rp to p,
5595 with the zero padding insertion point being at 7889 with the zero padding insertion point being at
@@ -5603,7 +7897,22 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
5603 for (; pad > 0; pad--) 7897 for (; pad > 0; pad--)
5604 *p++ = ' '; 7898 *p++ = ' ';
5605 } 7899 }
5606 else if ((flags & FLAG_ZERO) && pad_ptr != NULL) 7900 else if ((flags & FLAG_ZERO) && pad_ptr != NULL
7901 /* ISO C says: "For d, i, o, u, x, and X
7902 conversions, if a precision is
7903 specified, the 0 flag is ignored. */
7904 && !(has_precision
7905 && (dp->conversion == 'd'
7906 || dp->conversion == 'i'
7907 || dp->conversion == 'o'
7908 || dp->conversion == 'u'
7909 || dp->conversion == 'x'
7910 || dp->conversion == 'X'
7911 /* Although ISO C does not
7912 require it, treat 'b' and 'B'
7913 like 'x' and 'X'. */
7914 || dp->conversion == 'b'
7915 || dp->conversion == 'B')))
5607 { 7916 {
5608 /* Pad with zeroes. */ 7917 /* Pad with zeroes. */
5609 DCHAR_T *q = end; 7918 DCHAR_T *q = end;
@@ -5687,17 +7996,15 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
5687 not have this limitation. */ 7996 not have this limitation. */
5688 return result; 7997 return result;
5689 7998
5690#if USE_SNPRINTF
5691 overflow: 7999 overflow:
5692 errno = EOVERFLOW; 8000 errno = EOVERFLOW;
5693 goto fail_with_errno; 8001 goto fail_with_errno;
5694#endif
5695 8002
5696 out_of_memory: 8003 out_of_memory:
5697 errno = ENOMEM; 8004 errno = ENOMEM;
5698 goto fail_with_errno; 8005 goto fail_with_errno;
5699 8006
5700#if ENABLE_UNISTDIO || ((!USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || (NEED_PRINTF_DIRECTIVE_LS && !defined IN_LIBINTL) || ENABLE_WCHAR_FALLBACK) && HAVE_WCHAR_T) 8007#if ENABLE_UNISTDIO || (WIDE_CHAR_VERSION || !USE_SNPRINTF || (PTRDIFF_MAX > INT_MAX) || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || NEED_PRINTF_DIRECTIVE_LS || ENABLE_WCHAR_FALLBACK) || ((NEED_PRINTF_DIRECTIVE_LC || ENABLE_WCHAR_FALLBACK) && HAVE_WINT_T && !WIDE_CHAR_VERSION) || (NEED_WPRINTF_DIRECTIVE_C && WIDE_CHAR_VERSION)
5701 fail_with_EILSEQ: 8008 fail_with_EILSEQ:
5702 errno = EILSEQ; 8009 errno = EILSEQ;
5703 goto fail_with_errno; 8010 goto fail_with_errno;