diff options
Diffstat (limited to 'gl/vasnprintf.c')
| -rw-r--r-- | gl/vasnprintf.c | 3029 |
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 |
| 288 | static size_t | 321 | static size_t |
| 289 | wctomb_fallback (char *s, wchar_t wc) | 322 | wctomb_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 | ||
| 422 | static const char * | ||
| 423 | thousands_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 | ||
| 456 | static const DCHAR_T * | ||
| 457 | thousands_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 | ||
| 495 | static const wchar_t * | ||
| 496 | thousands_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 | */ | ||
| 579 | static const signed char * | ||
| 580 | grouping_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). */ | ||
| 596 | static size_t | ||
| 597 | num_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. */ |
| 384 | static int | 628 | static 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. */ |
| 395 | static int | 639 | static 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 | |||
| 654 | static | ||
| 655 | long 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. */ |
| 427 | static void * | 708 | static void * |
| 428 | multiply (mpn_t src1, mpn_t src2, mpn_t *dest) | 709 | multiply (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. */ |
| 499 | static void * | 780 | static void * |
| 500 | divide (mpn_t a, mpn_t b, mpn_t *q) | 781 | divide (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) | |||
| 1380 | static char * | 1671 | static char * |
| 1381 | scale10_round_decimal_long_double (long double x, int n) | 1672 | scale10_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) | |||
| 1398 | static char * | 1692 | static char * |
| 1399 | scale10_round_decimal_double (double x, int n) | 1693 | scale10_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; |
