diff options
| author | Lorenz Kästle <12514511+RincewindsHat@users.noreply.github.com> | 2025-12-28 12:13:40 +0100 |
|---|---|---|
| committer | Lorenz Kästle <12514511+RincewindsHat@users.noreply.github.com> | 2025-12-28 12:13:40 +0100 |
| commit | b0afb8fe0ff1d87165af9df61501197a06240dda (patch) | |
| tree | 274ac6a96c53ef4c19ab4974ce24a06a233128c5 /gl/vasnprintf.c | |
| parent | 68fc05381ee5fa0aee1413118fbb3d81ca888b09 (diff) | |
| download | monitoring-plugins-b0afb8fe0ff1d87165af9df61501197a06240dda.tar.gz | |
Sync with Gnulib stable-202507 code (a8ac9f9ce5)
Diffstat (limited to 'gl/vasnprintf.c')
| -rw-r--r-- | gl/vasnprintf.c | 1451 |
1 files changed, 1258 insertions, 193 deletions
diff --git a/gl/vasnprintf.c b/gl/vasnprintf.c index de204458..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-2024 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(), mbszero() */ | 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, INT_WIDTH, LONG_WIDTH */ | 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 |
| @@ -182,6 +184,20 @@ | |||
| 182 | # define TCHAR_T char | 184 | # define TCHAR_T char |
| 183 | # endif | 185 | # endif |
| 184 | #endif | 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 | ||
| 185 | #if !WIDE_CHAR_VERSION || !DCHAR_IS_TCHAR | 201 | #if !WIDE_CHAR_VERSION || !DCHAR_IS_TCHAR |
| 186 | /* TCHAR_T is char. */ | 202 | /* TCHAR_T is char. */ |
| 187 | /* Use snprintf if it exists under the name 'snprintf' or '_snprintf'. | 203 | /* Use snprintf if it exists under the name 'snprintf' or '_snprintf'. |
| @@ -216,6 +232,12 @@ | |||
| 216 | /* Here we need to call the native sprintf, not rpl_sprintf. */ | 232 | /* Here we need to call the native sprintf, not rpl_sprintf. */ |
| 217 | #undef sprintf | 233 | #undef sprintf |
| 218 | 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 | |||
| 219 | /* GCC >= 4.0 with -Wall emits unjustified "... may be used uninitialized" | 241 | /* GCC >= 4.0 with -Wall emits unjustified "... may be used uninitialized" |
| 220 | warnings in this file. Use -Dlint to suppress them. */ | 242 | warnings in this file. Use -Dlint to suppress them. */ |
| 221 | #if defined GCC_LINT || defined lint | 243 | #if defined GCC_LINT || defined lint |
| @@ -224,6 +246,11 @@ | |||
| 224 | # define IF_LINT(Code) /* empty */ | 246 | # define IF_LINT(Code) /* empty */ |
| 225 | #endif | 247 | #endif |
| 226 | 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 | |||
| 227 | /* Avoid some warnings from "gcc -Wshadow". | 254 | /* Avoid some warnings from "gcc -Wshadow". |
| 228 | This file doesn't use the exp() and remainder() functions. */ | 255 | This file doesn't use the exp() and remainder() functions. */ |
| 229 | #undef exp | 256 | #undef exp |
| @@ -231,7 +258,7 @@ | |||
| 231 | #undef remainder | 258 | #undef remainder |
| 232 | #define remainder rem | 259 | #define remainder rem |
| 233 | 260 | ||
| 234 | #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 |
| 235 | # if (HAVE_STRNLEN && !defined _AIX) | 262 | # if (HAVE_STRNLEN && !defined _AIX) |
| 236 | # define local_strnlen strnlen | 263 | # define local_strnlen strnlen |
| 237 | # else | 264 | # else |
| @@ -247,7 +274,7 @@ local_strnlen (const char *string, size_t maxlen) | |||
| 247 | # endif | 274 | # endif |
| 248 | #endif | 275 | #endif |
| 249 | 276 | ||
| 250 | #if (((!USE_SNPRINTF || WIDE_CHAR_VERSION || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || NEED_WPRINTF_DIRECTIVE_LC) && WIDE_CHAR_VERSION) || ((!USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || NEED_PRINTF_DIRECTIVE_LS) && !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) |
| 251 | # if HAVE_WCSLEN | 278 | # if HAVE_WCSLEN |
| 252 | # define local_wcslen wcslen | 279 | # define local_wcslen wcslen |
| 253 | # else | 280 | # else |
| @@ -270,7 +297,7 @@ local_wcslen (const wchar_t *s) | |||
| 270 | # endif | 297 | # endif |
| 271 | #endif | 298 | #endif |
| 272 | 299 | ||
| 273 | #if (!USE_SNPRINTF || (WIDE_CHAR_VERSION && DCHAR_IS_TCHAR) || !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 |
| 274 | # if HAVE_WCSNLEN && HAVE_DECL_WCSNLEN | 301 | # if HAVE_WCSNLEN && HAVE_DECL_WCSNLEN |
| 275 | # define local_wcsnlen wcsnlen | 302 | # define local_wcsnlen wcsnlen |
| 276 | # else | 303 | # else |
| @@ -289,7 +316,7 @@ local_wcsnlen (const wchar_t *s, size_t maxlen) | |||
| 289 | # endif | 316 | # endif |
| 290 | #endif | 317 | #endif |
| 291 | 318 | ||
| 292 | #if (((!USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || NEED_PRINTF_DIRECTIVE_LS || ENABLE_WCHAR_FALLBACK) && HAVE_WCHAR_T) || ((NEED_PRINTF_DIRECTIVE_LC || 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 |
| 293 | # if ENABLE_WCHAR_FALLBACK | 320 | # if ENABLE_WCHAR_FALLBACK |
| 294 | static size_t | 321 | static size_t |
| 295 | wctomb_fallback (char *s, wchar_t wc) | 322 | wctomb_fallback (char *s, wchar_t wc) |
| @@ -357,7 +384,7 @@ local_wctomb (char *s, wchar_t wc) | |||
| 357 | # endif | 384 | # endif |
| 358 | #endif | 385 | #endif |
| 359 | 386 | ||
| 360 | #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) | 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) |
| 361 | /* Determine the decimal-point character according to the current locale. */ | 388 | /* Determine the decimal-point character according to the current locale. */ |
| 362 | # ifndef decimal_point_char_defined | 389 | # ifndef decimal_point_char_defined |
| 363 | # define decimal_point_char_defined 1 | 390 | # define decimal_point_char_defined 1 |
| @@ -384,6 +411,217 @@ decimal_point_char (void) | |||
| 384 | # endif | 411 | # endif |
| 385 | #endif | 412 | #endif |
| 386 | 413 | ||
| 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 | |||
| 387 | #if NEED_PRINTF_INFINITE_DOUBLE && !NEED_PRINTF_DOUBLE | 625 | #if NEED_PRINTF_INFINITE_DOUBLE && !NEED_PRINTF_DOUBLE |
| 388 | 626 | ||
| 389 | /* Equivalent to !isfinite(x) || x == 0, but does not require libm. */ | 627 | /* Equivalent to !isfinite(x) || x == 0, but does not require libm. */ |
| @@ -406,8 +644,45 @@ is_infinite_or_zerol (long double x) | |||
| 406 | 644 | ||
| 407 | #endif | 645 | #endif |
| 408 | 646 | ||
| 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 | |||
| 409 | #if NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_DOUBLE | 681 | #if NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_DOUBLE |
| 410 | 682 | ||
| 683 | /* An indicator for a failed memory allocation. */ | ||
| 684 | # define NOMEM_PTR ((void *) (-1)) | ||
| 685 | |||
| 411 | /* Converting 'long double' to decimal without rare rounding bugs requires | 686 | /* Converting 'long double' to decimal without rare rounding bugs requires |
| 412 | 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 |
| 413 | (and slower) algorithms. */ | 688 | (and slower) algorithms. */ |
| @@ -428,8 +703,8 @@ typedef struct | |||
| 428 | } mpn_t; | 703 | } mpn_t; |
| 429 | 704 | ||
| 430 | /* Compute the product of two bignums >= 0. | 705 | /* Compute the product of two bignums >= 0. |
| 431 | 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 |
| 432 | allocation failure. */ | 707 | in case of memory allocation failure. */ |
| 433 | static void * | 708 | static void * |
| 434 | multiply (mpn_t src1, mpn_t src2, mpn_t *dest) | 709 | multiply (mpn_t src1, mpn_t src2, mpn_t *dest) |
| 435 | { | 710 | { |
| @@ -457,7 +732,7 @@ multiply (mpn_t src1, mpn_t src2, mpn_t *dest) | |||
| 457 | { | 732 | { |
| 458 | /* src1 or src2 is zero. */ | 733 | /* src1 or src2 is zero. */ |
| 459 | dest->nlimbs = 0; | 734 | dest->nlimbs = 0; |
| 460 | dest->limbs = (mp_limb_t *) malloc (1); | 735 | dest->limbs = NULL; |
| 461 | } | 736 | } |
| 462 | else | 737 | else |
| 463 | { | 738 | { |
| @@ -469,7 +744,7 @@ multiply (mpn_t src1, mpn_t src2, mpn_t *dest) | |||
| 469 | dlen = len1 + len2; | 744 | dlen = len1 + len2; |
| 470 | dp = (mp_limb_t *) malloc (dlen * sizeof (mp_limb_t)); | 745 | dp = (mp_limb_t *) malloc (dlen * sizeof (mp_limb_t)); |
| 471 | if (dp == NULL) | 746 | if (dp == NULL) |
| 472 | return NULL; | 747 | return NOMEM_PTR; |
| 473 | for (k = len2; k > 0; ) | 748 | for (k = len2; k > 0; ) |
| 474 | dp[--k] = 0; | 749 | dp[--k] = 0; |
| 475 | for (i = 0; i < len1; i++) | 750 | for (i = 0; i < len1; i++) |
| @@ -500,8 +775,8 @@ multiply (mpn_t src1, mpn_t src2, mpn_t *dest) | |||
| 500 | the remainder. | 775 | the remainder. |
| 501 | 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, |
| 502 | q is incremented. | 777 | q is incremented. |
| 503 | 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 |
| 504 | allocation failure. */ | 779 | in case of memory allocation failure. */ |
| 505 | static void * | 780 | static void * |
| 506 | divide (mpn_t a, mpn_t b, mpn_t *q) | 781 | divide (mpn_t a, mpn_t b, mpn_t *q) |
| 507 | { | 782 | { |
| @@ -572,7 +847,7 @@ divide (mpn_t a, mpn_t b, mpn_t *q) | |||
| 572 | final rounding of q.) */ | 847 | final rounding of q.) */ |
| 573 | 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)); |
| 574 | if (roomptr == NULL) | 849 | if (roomptr == NULL) |
| 575 | return NULL; | 850 | return NOMEM_PTR; |
| 576 | 851 | ||
| 577 | /* Normalise a. */ | 852 | /* Normalise a. */ |
| 578 | while (a_len > 0 && a_ptr[a_len - 1] == 0) | 853 | while (a_len > 0 && a_ptr[a_len - 1] == 0) |
| @@ -708,7 +983,7 @@ divide (mpn_t a, mpn_t b, mpn_t *q) | |||
| 708 | if (tmp_roomptr == NULL) | 983 | if (tmp_roomptr == NULL) |
| 709 | { | 984 | { |
| 710 | free (roomptr); | 985 | free (roomptr); |
| 711 | return NULL; | 986 | return NOMEM_PTR; |
| 712 | } | 987 | } |
| 713 | { | 988 | { |
| 714 | const mp_limb_t *sourceptr = b_ptr; | 989 | const mp_limb_t *sourceptr = b_ptr; |
| @@ -930,7 +1205,7 @@ divide (mpn_t a, mpn_t b, mpn_t *q) | |||
| 930 | /* Avoid pointless GCC warning "argument 1 value '18446744073709551615' exceeds | 1205 | /* Avoid pointless GCC warning "argument 1 value '18446744073709551615' exceeds |
| 931 | maximum object size 9223372036854775807", triggered by the use of xsum as | 1206 | maximum object size 9223372036854775807", triggered by the use of xsum as |
| 932 | argument of malloc. */ | 1207 | argument of malloc. */ |
| 933 | # if __GNUC__ >= 7 | 1208 | # if _GL_GNUC_PREREQ (7, 0) |
| 934 | # pragma GCC diagnostic push | 1209 | # pragma GCC diagnostic push |
| 935 | # pragma GCC diagnostic ignored "-Walloc-size-larger-than=" | 1210 | # pragma GCC diagnostic ignored "-Walloc-size-larger-than=" |
| 936 | # endif | 1211 | # endif |
| @@ -991,7 +1266,7 @@ convert_to_decimal (mpn_t a, size_t extra_zeroes) | |||
| 991 | return c_ptr; | 1266 | return c_ptr; |
| 992 | } | 1267 | } |
| 993 | 1268 | ||
| 994 | # if __GNUC__ >= 7 | 1269 | # if _GL_GNUC_PREREQ (7, 0) |
| 995 | # pragma GCC diagnostic pop | 1270 | # pragma GCC diagnostic pop |
| 996 | # endif | 1271 | # endif |
| 997 | 1272 | ||
| @@ -1015,7 +1290,7 @@ decode_long_double (long double x, int *ep, mpn_t *mp) | |||
| 1015 | if (m.limbs == NULL) | 1290 | if (m.limbs == NULL) |
| 1016 | return NULL; | 1291 | return NULL; |
| 1017 | /* Split into exponential part and mantissa. */ | 1292 | /* Split into exponential part and mantissa. */ |
| 1018 | y = frexpl (x, &exp); | 1293 | y = safe_frexpl (x, &exp); |
| 1019 | if (!(y >= 0.0L && y < 1.0L)) | 1294 | if (!(y >= 0.0L && y < 1.0L)) |
| 1020 | abort (); | 1295 | abort (); |
| 1021 | /* 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 |
| @@ -1306,7 +1581,7 @@ scale10_round_decimal_decoded (int e, mpn_t m, void *memory, int n) | |||
| 1306 | mpn_t denominator; | 1581 | mpn_t denominator; |
| 1307 | void *tmp_memory; | 1582 | void *tmp_memory; |
| 1308 | tmp_memory = multiply (m, pow5, &numerator); | 1583 | tmp_memory = multiply (m, pow5, &numerator); |
| 1309 | if (tmp_memory == NULL) | 1584 | if (tmp_memory == NOMEM_PTR) |
| 1310 | { | 1585 | { |
| 1311 | free (pow5_ptr); | 1586 | free (pow5_ptr); |
| 1312 | free (memory); | 1587 | free (memory); |
| @@ -1379,7 +1654,7 @@ scale10_round_decimal_decoded (int e, mpn_t m, void *memory, int n) | |||
| 1379 | 1654 | ||
| 1380 | /* Here y = round (x * 10^n) = z * 10^extra_zeroes. */ | 1655 | /* Here y = round (x * 10^n) = z * 10^extra_zeroes. */ |
| 1381 | 1656 | ||
| 1382 | if (z_memory == NULL) | 1657 | if (z_memory == NOMEM_PTR) |
| 1383 | return NULL; | 1658 | return NULL; |
| 1384 | digits = convert_to_decimal (z, extra_zeroes); | 1659 | digits = convert_to_decimal (z, extra_zeroes); |
| 1385 | free (z_memory); | 1660 | free (z_memory); |
| @@ -1442,7 +1717,7 @@ floorlog10l (long double x) | |||
| 1442 | double l; | 1717 | double l; |
| 1443 | 1718 | ||
| 1444 | /* Split into exponential part and mantissa. */ | 1719 | /* Split into exponential part and mantissa. */ |
| 1445 | y = frexpl (x, &exp); | 1720 | y = safe_frexpl (x, &exp); |
| 1446 | if (!(y >= 0.0L && y < 1.0L)) | 1721 | if (!(y >= 0.0L && y < 1.0L)) |
| 1447 | abort (); | 1722 | abort (); |
| 1448 | if (y == 0.0L) | 1723 | if (y == 0.0L) |
| @@ -1801,8 +2076,17 @@ MAX_ROOM_NEEDED (const arguments *ap, size_t arg_index, FCHAR_T conversion, | |||
| 1801 | } | 2076 | } |
| 1802 | if (tmp_length < precision) | 2077 | if (tmp_length < precision) |
| 1803 | tmp_length = precision; | 2078 | tmp_length = precision; |
| 1804 | /* Multiply by 2, as an estimate for FLAG_GROUP. */ | 2079 | /* Account for thousands separators. */ |
| 1805 | 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 | } | ||
| 1806 | /* Add 1, to account for a leading sign. */ | 2090 | /* Add 1, to account for a leading sign. */ |
| 1807 | tmp_length = xsum (tmp_length, 1); | 2091 | tmp_length = xsum (tmp_length, 1); |
| 1808 | break; | 2092 | break; |
| @@ -2050,12 +2334,18 @@ MAX_ROOM_NEEDED (const arguments *ap, size_t arg_index, FCHAR_T conversion, | |||
| 2050 | tmp_length = xsum (tmp_length, 2); | 2334 | tmp_length = xsum (tmp_length, 2); |
| 2051 | break; | 2335 | break; |
| 2052 | 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 | |||
| 2053 | case 'f': case 'F': | 2343 | case 'f': case 'F': |
| 2054 | if (type == TYPE_LONGDOUBLE) | 2344 | if (type == TYPE_LONGDOUBLE) |
| 2055 | tmp_length = | 2345 | tmp_length = |
| 2056 | (unsigned int) (LDBL_MAX_EXP | 2346 | (unsigned int) (LDBL_MAX_EXP |
| 2057 | * 0.30103 /* binary -> decimal */ | 2347 | * 0.30103 /* binary -> decimal */ |
| 2058 | * 2 /* estimate for FLAG_GROUP */ | 2348 | * 0.5 * 3 /* estimate for FLAG_GROUP */ |
| 2059 | ) | 2349 | ) |
| 2060 | + 1 /* turn floor into ceil */ | 2350 | + 1 /* turn floor into ceil */ |
| 2061 | + 10; /* sign, decimal point etc. */ | 2351 | + 10; /* sign, decimal point etc. */ |
| @@ -2063,17 +2353,20 @@ MAX_ROOM_NEEDED (const arguments *ap, size_t arg_index, FCHAR_T conversion, | |||
| 2063 | tmp_length = | 2353 | tmp_length = |
| 2064 | (unsigned int) (DBL_MAX_EXP | 2354 | (unsigned int) (DBL_MAX_EXP |
| 2065 | * 0.30103 /* binary -> decimal */ | 2355 | * 0.30103 /* binary -> decimal */ |
| 2066 | * 2 /* estimate for FLAG_GROUP */ | 2356 | * 0.5 * 3 /* estimate for FLAG_GROUP */ |
| 2067 | ) | 2357 | ) |
| 2068 | + 1 /* turn floor into ceil */ | 2358 | + 1 /* turn floor into ceil */ |
| 2069 | + 10; /* sign, decimal point etc. */ | 2359 | + 10; /* sign, decimal point etc. */ |
| 2070 | tmp_length = xsum (tmp_length, precision); | 2360 | tmp_length = xsum (tmp_length, precision); |
| 2071 | break; | 2361 | break; |
| 2072 | 2362 | ||
| 2073 | case 'e': case 'E': case 'g': case 'G': | 2363 | case 'g': case 'G': |
| 2074 | tmp_length = | 2364 | tmp_length = |
| 2075 | 12; /* sign, decimal point, exponent etc. */ | 2365 | 12; /* sign, decimal point, exponent etc. */ |
| 2076 | tmp_length = xsum (tmp_length, precision); | 2366 | tmp_length = xsum (tmp_length, |
| 2367 | precision | ||
| 2368 | * 0.5 * 3 /* estimate for FLAG_GROUP */ | ||
| 2369 | ); | ||
| 2077 | break; | 2370 | break; |
| 2078 | 2371 | ||
| 2079 | case 'a': case 'A': | 2372 | case 'a': case 'A': |
| @@ -2111,10 +2404,9 @@ MAX_ROOM_NEEDED (const arguments *ap, size_t arg_index, FCHAR_T conversion, | |||
| 2111 | break; | 2404 | break; |
| 2112 | 2405 | ||
| 2113 | case 's': | 2406 | case 's': |
| 2114 | # if HAVE_WCHAR_T | ||
| 2115 | if (type == TYPE_WIDE_STRING) | 2407 | if (type == TYPE_WIDE_STRING) |
| 2116 | { | 2408 | { |
| 2117 | # if WIDE_CHAR_VERSION | 2409 | # if WIDE_CHAR_VERSION |
| 2118 | /* ISO C says about %ls in fwprintf: | 2410 | /* ISO C says about %ls in fwprintf: |
| 2119 | "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 |
| 2120 | of the array, the array shall contain a null wide character." | 2412 | of the array, the array shall contain a null wide character." |
| @@ -2125,7 +2417,7 @@ MAX_ROOM_NEEDED (const arguments *ap, size_t arg_index, FCHAR_T conversion, | |||
| 2125 | tmp_length = local_wcsnlen (arg, precision); | 2417 | tmp_length = local_wcsnlen (arg, precision); |
| 2126 | else | 2418 | else |
| 2127 | tmp_length = local_wcslen (arg); | 2419 | tmp_length = local_wcslen (arg); |
| 2128 | # else | 2420 | # else |
| 2129 | /* ISO C says about %ls in fprintf: | 2421 | /* ISO C says about %ls in fprintf: |
| 2130 | "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 |
| 2131 | written (including shift sequences, if any), and the array | 2423 | written (including shift sequences, if any), and the array |
| @@ -2136,10 +2428,9 @@ MAX_ROOM_NEEDED (const arguments *ap, size_t arg_index, FCHAR_T conversion, | |||
| 2136 | So if there is a precision, we must not use wcslen. */ | 2428 | So if there is a precision, we must not use wcslen. */ |
| 2137 | /* This case has already been handled separately in VASNPRINTF. */ | 2429 | /* This case has already been handled separately in VASNPRINTF. */ |
| 2138 | abort (); | 2430 | abort (); |
| 2139 | # endif | 2431 | # endif |
| 2140 | } | 2432 | } |
| 2141 | else | 2433 | else |
| 2142 | # endif | ||
| 2143 | { | 2434 | { |
| 2144 | # if WIDE_CHAR_VERSION | 2435 | # if WIDE_CHAR_VERSION |
| 2145 | /* ISO C says about %s in fwprintf: | 2436 | /* ISO C says about %s in fwprintf: |
| @@ -2226,7 +2517,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, | |||
| 2226 | TCHAR_T *buf; | 2517 | TCHAR_T *buf; |
| 2227 | TCHAR_T *buf_malloced; | 2518 | TCHAR_T *buf_malloced; |
| 2228 | const FCHAR_T *cp; | 2519 | const FCHAR_T *cp; |
| 2229 | size_t i; | 2520 | size_t di; |
| 2230 | DIRECTIVE *dp; | 2521 | DIRECTIVE *dp; |
| 2231 | /* Output string accumulator. */ | 2522 | /* Output string accumulator. */ |
| 2232 | DCHAR_T *result; | 2523 | DCHAR_T *result; |
| @@ -2290,7 +2581,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, | |||
| 2290 | #define ENSURE_ALLOCATION(needed) \ | 2581 | #define ENSURE_ALLOCATION(needed) \ |
| 2291 | ENSURE_ALLOCATION_ELSE((needed), goto out_of_memory; ) | 2582 | ENSURE_ALLOCATION_ELSE((needed), goto out_of_memory; ) |
| 2292 | 2583 | ||
| 2293 | 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++) |
| 2294 | { | 2585 | { |
| 2295 | if (cp != dp->dir_start) | 2586 | if (cp != dp->dir_start) |
| 2296 | { | 2587 | { |
| @@ -2313,7 +2604,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, | |||
| 2313 | while (--n > 0); | 2604 | while (--n > 0); |
| 2314 | } | 2605 | } |
| 2315 | } | 2606 | } |
| 2316 | if (i == d.count) | 2607 | if (di == d.count) |
| 2317 | break; | 2608 | break; |
| 2318 | 2609 | ||
| 2319 | /* Execute a single directive. */ | 2610 | /* Execute a single directive. */ |
| @@ -2423,6 +2714,8 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, | |||
| 2423 | width = xsum (xtimes (width, 10), *digitp++ - '0'); | 2714 | width = xsum (xtimes (width, 10), *digitp++ - '0'); |
| 2424 | while (digitp != dp->width_end); | 2715 | while (digitp != dp->width_end); |
| 2425 | } | 2716 | } |
| 2717 | if (width > (size_t) INT_MAX) | ||
| 2718 | goto overflow; | ||
| 2426 | has_width = 1; | 2719 | has_width = 1; |
| 2427 | } | 2720 | } |
| 2428 | 2721 | ||
| @@ -2501,7 +2794,8 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, | |||
| 2501 | { | 2794 | { |
| 2502 | /* Use the entire string. */ | 2795 | /* Use the entire string. */ |
| 2503 | arg_end = arg + u8_strlen (arg); | 2796 | arg_end = arg + u8_strlen (arg); |
| 2504 | /* The number of characters doesn't matter. */ | 2797 | /* The number of characters doesn't matter, |
| 2798 | because !has_width and therefore width==0. */ | ||
| 2505 | characters = 0; | 2799 | characters = 0; |
| 2506 | } | 2800 | } |
| 2507 | 2801 | ||
| @@ -2542,7 +2836,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, | |||
| 2542 | if (converted != result + length) | 2836 | if (converted != result + length) |
| 2543 | { | 2837 | { |
| 2544 | ENSURE_ALLOCATION_ELSE (xsum (length, converted_len), | 2838 | ENSURE_ALLOCATION_ELSE (xsum (length, converted_len), |
| 2545 | { free (converted); goto out_of_memory; }); | 2839 | { free (converted); goto out_of_memory; }); |
| 2546 | DCHAR_CPY (result + length, converted, converted_len); | 2840 | DCHAR_CPY (result + length, converted, converted_len); |
| 2547 | free (converted); | 2841 | free (converted); |
| 2548 | } | 2842 | } |
| @@ -2603,7 +2897,8 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, | |||
| 2603 | { | 2897 | { |
| 2604 | /* Use the entire string. */ | 2898 | /* Use the entire string. */ |
| 2605 | arg_end = arg + u16_strlen (arg); | 2899 | arg_end = arg + u16_strlen (arg); |
| 2606 | /* The number of characters doesn't matter. */ | 2900 | /* The number of characters doesn't matter, |
| 2901 | because !has_width and therefore width==0. */ | ||
| 2607 | characters = 0; | 2902 | characters = 0; |
| 2608 | } | 2903 | } |
| 2609 | 2904 | ||
| @@ -2644,7 +2939,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, | |||
| 2644 | if (converted != result + length) | 2939 | if (converted != result + length) |
| 2645 | { | 2940 | { |
| 2646 | ENSURE_ALLOCATION_ELSE (xsum (length, converted_len), | 2941 | ENSURE_ALLOCATION_ELSE (xsum (length, converted_len), |
| 2647 | { free (converted); goto out_of_memory; }); | 2942 | { free (converted); goto out_of_memory; }); |
| 2648 | DCHAR_CPY (result + length, converted, converted_len); | 2943 | DCHAR_CPY (result + length, converted, converted_len); |
| 2649 | free (converted); | 2944 | free (converted); |
| 2650 | } | 2945 | } |
| @@ -2705,7 +3000,8 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, | |||
| 2705 | { | 3000 | { |
| 2706 | /* Use the entire string. */ | 3001 | /* Use the entire string. */ |
| 2707 | arg_end = arg + u32_strlen (arg); | 3002 | arg_end = arg + u32_strlen (arg); |
| 2708 | /* The number of characters doesn't matter. */ | 3003 | /* The number of characters doesn't matter, |
| 3004 | because !has_width and therefore width==0. */ | ||
| 2709 | characters = 0; | 3005 | characters = 0; |
| 2710 | } | 3006 | } |
| 2711 | 3007 | ||
| @@ -2746,7 +3042,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, | |||
| 2746 | if (converted != result + length) | 3042 | if (converted != result + length) |
| 2747 | { | 3043 | { |
| 2748 | ENSURE_ALLOCATION_ELSE (xsum (length, converted_len), | 3044 | ENSURE_ALLOCATION_ELSE (xsum (length, converted_len), |
| 2749 | { free (converted); goto out_of_memory; }); | 3045 | { free (converted); goto out_of_memory; }); |
| 2750 | DCHAR_CPY (result + length, converted, converted_len); | 3046 | DCHAR_CPY (result + length, converted, converted_len); |
| 2751 | free (converted); | 3047 | free (converted); |
| 2752 | } | 3048 | } |
| @@ -2769,7 +3065,190 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, | |||
| 2769 | } | 3065 | } |
| 2770 | } | 3066 | } |
| 2771 | #endif | 3067 | #endif |
| 2772 | #if WIDE_CHAR_VERSION && (!DCHAR_IS_TCHAR || NEED_WPRINTF_DIRECTIVE_LC) | 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) | ||
| 2773 | else if ((dp->conversion == 's' | 3252 | else if ((dp->conversion == 's' |
| 2774 | && a.arg[dp->arg_index].type == TYPE_WIDE_STRING) | 3253 | && a.arg[dp->arg_index].type == TYPE_WIDE_STRING) |
| 2775 | || (dp->conversion == 'c' | 3254 | || (dp->conversion == 'c' |
| @@ -2810,6 +3289,8 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, | |||
| 2810 | width = xsum (xtimes (width, 10), *digitp++ - '0'); | 3289 | width = xsum (xtimes (width, 10), *digitp++ - '0'); |
| 2811 | while (digitp != dp->width_end); | 3290 | while (digitp != dp->width_end); |
| 2812 | } | 3291 | } |
| 3292 | if (width > (size_t) INT_MAX) | ||
| 3293 | goto overflow; | ||
| 2813 | } | 3294 | } |
| 2814 | 3295 | ||
| 2815 | { | 3296 | { |
| @@ -2912,7 +3393,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, | |||
| 2912 | } | 3393 | } |
| 2913 | } | 3394 | } |
| 2914 | #endif | 3395 | #endif |
| 2915 | #if (!USE_SNPRINTF || WIDE_CHAR_VERSION || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || NEED_PRINTF_DIRECTIVE_LS || ENABLE_WCHAR_FALLBACK) && HAVE_WCHAR_T | 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 |
| 2916 | else if (dp->conversion == 's' | 3397 | else if (dp->conversion == 's' |
| 2917 | # if WIDE_CHAR_VERSION | 3398 | # if WIDE_CHAR_VERSION |
| 2918 | && a.arg[dp->arg_index].type != TYPE_WIDE_STRING | 3399 | && a.arg[dp->arg_index].type != TYPE_WIDE_STRING |
| @@ -2965,6 +3446,8 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, | |||
| 2965 | width = xsum (xtimes (width, 10), *digitp++ - '0'); | 3446 | width = xsum (xtimes (width, 10), *digitp++ - '0'); |
| 2966 | while (digitp != dp->width_end); | 3447 | while (digitp != dp->width_end); |
| 2967 | } | 3448 | } |
| 3449 | if (width > (size_t) INT_MAX) | ||
| 3450 | goto overflow; | ||
| 2968 | has_width = 1; | 3451 | has_width = 1; |
| 2969 | } | 3452 | } |
| 2970 | 3453 | ||
| @@ -3145,11 +3628,13 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, | |||
| 3145 | { | 3628 | { |
| 3146 | 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; |
| 3147 | const wchar_t *arg_end; | 3630 | const wchar_t *arg_end; |
| 3631 | size_t bytes; | ||
| 3632 | # if ENABLE_UNISTDIO && DCHAR_IS_TCHAR | ||
| 3148 | size_t characters; | 3633 | size_t characters; |
| 3634 | # endif | ||
| 3149 | # if !DCHAR_IS_TCHAR | 3635 | # if !DCHAR_IS_TCHAR |
| 3150 | /* This code assumes that TCHAR_T is 'char'. */ | 3636 | /* This code assumes that TCHAR_T is 'char'. */ |
| 3151 | static_assert (sizeof (TCHAR_T) == 1); | 3637 | static_assert (sizeof (TCHAR_T) == 1); |
| 3152 | TCHAR_T *tmpsrc; | ||
| 3153 | DCHAR_T *tmpdst; | 3638 | DCHAR_T *tmpdst; |
| 3154 | size_t tmpdst_len; | 3639 | size_t tmpdst_len; |
| 3155 | # endif | 3640 | # endif |
| @@ -3164,7 +3649,10 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, | |||
| 3164 | mbszero (&state); | 3649 | mbszero (&state); |
| 3165 | # endif | 3650 | # endif |
| 3166 | arg_end = arg; | 3651 | arg_end = arg; |
| 3652 | bytes = 0; | ||
| 3653 | # if ENABLE_UNISTDIO && DCHAR_IS_TCHAR | ||
| 3167 | characters = 0; | 3654 | characters = 0; |
| 3655 | # endif | ||
| 3168 | while (precision > 0) | 3656 | while (precision > 0) |
| 3169 | { | 3657 | { |
| 3170 | char cbuf[64]; /* Assume MB_CUR_MAX <= 64. */ | 3658 | char cbuf[64]; /* Assume MB_CUR_MAX <= 64. */ |
| @@ -3180,7 +3668,10 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, | |||
| 3180 | if (precision < (unsigned int) count) | 3668 | if (precision < (unsigned int) count) |
| 3181 | break; | 3669 | break; |
| 3182 | arg_end++; | 3670 | arg_end++; |
| 3183 | characters += count; | 3671 | bytes += count; |
| 3672 | # if ENABLE_UNISTDIO && DCHAR_IS_TCHAR | ||
| 3673 | characters += mbsnlen (cbuf, count); | ||
| 3674 | # endif | ||
| 3184 | precision -= count; | 3675 | precision -= count; |
| 3185 | } | 3676 | } |
| 3186 | } | 3677 | } |
| @@ -3197,7 +3688,10 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, | |||
| 3197 | mbszero (&state); | 3688 | mbszero (&state); |
| 3198 | # endif | 3689 | # endif |
| 3199 | arg_end = arg; | 3690 | arg_end = arg; |
| 3691 | bytes = 0; | ||
| 3692 | # if ENABLE_UNISTDIO && DCHAR_IS_TCHAR | ||
| 3200 | characters = 0; | 3693 | characters = 0; |
| 3694 | # endif | ||
| 3201 | for (;;) | 3695 | for (;;) |
| 3202 | { | 3696 | { |
| 3203 | char cbuf[64]; /* Assume MB_CUR_MAX <= 64. */ | 3697 | char cbuf[64]; /* Assume MB_CUR_MAX <= 64. */ |
| @@ -3211,7 +3705,10 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, | |||
| 3211 | /* Cannot convert. */ | 3705 | /* Cannot convert. */ |
| 3212 | goto fail_with_EILSEQ; | 3706 | goto fail_with_EILSEQ; |
| 3213 | arg_end++; | 3707 | arg_end++; |
| 3214 | characters += count; | 3708 | bytes += count; |
| 3709 | # if ENABLE_UNISTDIO && DCHAR_IS_TCHAR | ||
| 3710 | characters += mbsnlen (cbuf, count); | ||
| 3711 | # endif | ||
| 3215 | } | 3712 | } |
| 3216 | } | 3713 | } |
| 3217 | # if DCHAR_IS_TCHAR | 3714 | # if DCHAR_IS_TCHAR |
| @@ -3219,56 +3716,64 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, | |||
| 3219 | { | 3716 | { |
| 3220 | /* Use the entire string. */ | 3717 | /* Use the entire string. */ |
| 3221 | arg_end = arg + local_wcslen (arg); | 3718 | arg_end = arg + local_wcslen (arg); |
| 3222 | /* 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 | ||
| 3223 | characters = 0; | 3723 | characters = 0; |
| 3724 | # endif | ||
| 3224 | } | 3725 | } |
| 3225 | # endif | 3726 | # endif |
| 3226 | 3727 | ||
| 3227 | # if !DCHAR_IS_TCHAR | 3728 | # if !DCHAR_IS_TCHAR |
| 3228 | /* Convert the string into a piece of temporary memory. */ | ||
| 3229 | tmpsrc = (TCHAR_T *) malloc (characters * sizeof (TCHAR_T)); | ||
| 3230 | if (tmpsrc == NULL) | ||
| 3231 | goto out_of_memory; | ||
| 3232 | { | 3729 | { |
| 3233 | TCHAR_T *tmpptr = tmpsrc; | 3730 | TCHAR_T *tmpsrc; |
| 3234 | 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; | ||
| 3235 | # if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t | 3739 | # if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t |
| 3236 | mbstate_t state; | 3740 | mbstate_t state; |
| 3237 | mbszero (&state); | 3741 | mbszero (&state); |
| 3238 | # endif | 3742 | # endif |
| 3239 | for (remaining = characters; remaining > 0; ) | 3743 | for (remaining = bytes; remaining > 0; ) |
| 3240 | { | 3744 | { |
| 3241 | char cbuf[64]; /* Assume MB_CUR_MAX <= 64. */ | 3745 | char cbuf[64]; /* Assume MB_CUR_MAX <= 64. */ |
| 3242 | int count; | 3746 | int count; |
| 3243 | 3747 | ||
| 3244 | if (*arg == 0) | 3748 | if (*arg == 0) |
| 3245 | abort (); | 3749 | abort (); |
| 3246 | count = local_wcrtomb (cbuf, *arg, &state); | 3750 | count = local_wcrtomb (cbuf, *arg, &state); |
| 3247 | if (count <= 0) | 3751 | if (count <= 0) |
| 3248 | /* Inconsistency. */ | 3752 | /* Inconsistency. */ |
| 3249 | abort (); | 3753 | abort (); |
| 3250 | memcpy (tmpptr, cbuf, count); | 3754 | memcpy (tmpptr, cbuf, count); |
| 3251 | tmpptr += count; | 3755 | tmpptr += count; |
| 3252 | arg++; | 3756 | arg++; |
| 3253 | 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; | ||
| 3254 | } | 3774 | } |
| 3255 | if (!(arg == arg_end)) | 3775 | free (tmpsrc); |
| 3256 | abort (); | ||
| 3257 | } | 3776 | } |
| 3258 | |||
| 3259 | /* Convert from TCHAR_T[] to DCHAR_T[]. */ | ||
| 3260 | tmpdst = | ||
| 3261 | DCHAR_CONV_FROM_ENCODING (locale_charset (), | ||
| 3262 | iconveh_question_mark, | ||
| 3263 | tmpsrc, characters, | ||
| 3264 | NULL, | ||
| 3265 | NULL, &tmpdst_len); | ||
| 3266 | if (tmpdst == NULL) | ||
| 3267 | { | ||
| 3268 | free (tmpsrc); | ||
| 3269 | goto fail_with_errno; | ||
| 3270 | } | ||
| 3271 | free (tmpsrc); | ||
| 3272 | # endif | 3777 | # endif |
| 3273 | 3778 | ||
| 3274 | if (has_width) | 3779 | if (has_width) |
| @@ -3277,11 +3782,15 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, | |||
| 3277 | /* Outside POSIX, it's preferable to compare the width | 3782 | /* Outside POSIX, it's preferable to compare the width |
| 3278 | against the number of _characters_ of the converted | 3783 | against the number of _characters_ of the converted |
| 3279 | value. */ | 3784 | value. */ |
| 3280 | 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 | ||
| 3281 | # else | 3790 | # else |
| 3282 | /* The width is compared against the number of _bytes_ | 3791 | /* The width is compared against the number of _bytes_ |
| 3283 | of the converted value, says POSIX. */ | 3792 | of the converted value, says POSIX. */ |
| 3284 | w = characters; | 3793 | w = bytes; |
| 3285 | # endif | 3794 | # endif |
| 3286 | } | 3795 | } |
| 3287 | else | 3796 | else |
| @@ -3291,7 +3800,12 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, | |||
| 3291 | if (w < width && !(flags & FLAG_LEFT)) | 3800 | if (w < width && !(flags & FLAG_LEFT)) |
| 3292 | { | 3801 | { |
| 3293 | size_t n = width - w; | 3802 | size_t n = width - w; |
| 3803 | # if DCHAR_IS_TCHAR | ||
| 3294 | 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 | ||
| 3295 | DCHAR_SET (result + length, ' ', n); | 3809 | DCHAR_SET (result + length, ' ', n); |
| 3296 | length += n; | 3810 | length += n; |
| 3297 | } | 3811 | } |
| @@ -3305,8 +3819,8 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, | |||
| 3305 | mbstate_t state; | 3819 | mbstate_t state; |
| 3306 | mbszero (&state); | 3820 | mbszero (&state); |
| 3307 | # endif | 3821 | # endif |
| 3308 | ENSURE_ALLOCATION (xsum (length, characters)); | 3822 | ENSURE_ALLOCATION (xsum (length, bytes)); |
| 3309 | for (remaining = characters; remaining > 0; ) | 3823 | for (remaining = bytes; remaining > 0; ) |
| 3310 | { | 3824 | { |
| 3311 | char cbuf[64]; /* Assume MB_CUR_MAX <= 64. */ | 3825 | char cbuf[64]; /* Assume MB_CUR_MAX <= 64. */ |
| 3312 | int count; | 3826 | int count; |
| @@ -3350,7 +3864,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, | |||
| 3350 | } | 3864 | } |
| 3351 | # else | 3865 | # else |
| 3352 | ENSURE_ALLOCATION_ELSE (xsum (length, tmpdst_len), | 3866 | ENSURE_ALLOCATION_ELSE (xsum (length, tmpdst_len), |
| 3353 | { free (tmpdst); goto out_of_memory; }); | 3867 | { free (tmpdst); goto out_of_memory; }); |
| 3354 | DCHAR_CPY (result + length, tmpdst, tmpdst_len); | 3868 | DCHAR_CPY (result + length, tmpdst, tmpdst_len); |
| 3355 | free (tmpdst); | 3869 | free (tmpdst); |
| 3356 | length += tmpdst_len; | 3870 | length += tmpdst_len; |
| @@ -3406,17 +3920,21 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, | |||
| 3406 | width = xsum (xtimes (width, 10), *digitp++ - '0'); | 3920 | width = xsum (xtimes (width, 10), *digitp++ - '0'); |
| 3407 | while (digitp != dp->width_end); | 3921 | while (digitp != dp->width_end); |
| 3408 | } | 3922 | } |
| 3923 | if (width > (size_t) INT_MAX) | ||
| 3924 | goto overflow; | ||
| 3409 | has_width = 1; | 3925 | has_width = 1; |
| 3410 | } | 3926 | } |
| 3411 | 3927 | ||
| 3412 | /* %lc in vasnprintf. See the specification of fprintf. */ | 3928 | /* %lc in vasnprintf. See the specification of fprintf. */ |
| 3413 | { | 3929 | { |
| 3414 | 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 | ||
| 3415 | size_t characters; | 3933 | size_t characters; |
| 3934 | # endif | ||
| 3416 | # if !DCHAR_IS_TCHAR | 3935 | # if !DCHAR_IS_TCHAR |
| 3417 | /* This code assumes that TCHAR_T is 'char'. */ | 3936 | /* This code assumes that TCHAR_T is 'char'. */ |
| 3418 | static_assert (sizeof (TCHAR_T) == 1); | 3937 | static_assert (sizeof (TCHAR_T) == 1); |
| 3419 | TCHAR_T tmpsrc[64]; /* Assume MB_CUR_MAX <= 64. */ | ||
| 3420 | DCHAR_T *tmpdst; | 3938 | DCHAR_T *tmpdst; |
| 3421 | size_t tmpdst_len; | 3939 | size_t tmpdst_len; |
| 3422 | # endif | 3940 | # endif |
| @@ -3427,7 +3945,6 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, | |||
| 3427 | # endif | 3945 | # endif |
| 3428 | { | 3946 | { |
| 3429 | /* Count the number of bytes. */ | 3947 | /* Count the number of bytes. */ |
| 3430 | characters = 0; | ||
| 3431 | char cbuf[64]; /* Assume MB_CUR_MAX <= 64. */ | 3948 | char cbuf[64]; /* Assume MB_CUR_MAX <= 64. */ |
| 3432 | int count; | 3949 | int count; |
| 3433 | # if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t | 3950 | # if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t |
| @@ -3439,43 +3956,54 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, | |||
| 3439 | if (count < 0) | 3956 | if (count < 0) |
| 3440 | /* Cannot convert. */ | 3957 | /* Cannot convert. */ |
| 3441 | goto fail_with_EILSEQ; | 3958 | goto fail_with_EILSEQ; |
| 3442 | characters = count; | 3959 | bytes = count; |
| 3960 | # if ENABLE_UNISTDIO && DCHAR_IS_TCHAR | ||
| 3961 | characters = mbsnlen (cbuf, count); | ||
| 3962 | # endif | ||
| 3443 | } | 3963 | } |
| 3444 | # if DCHAR_IS_TCHAR | 3964 | # if DCHAR_IS_TCHAR |
| 3445 | else | 3965 | else |
| 3446 | { | 3966 | { |
| 3447 | /* 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 | ||
| 3448 | characters = 0; | 3971 | characters = 0; |
| 3972 | # endif | ||
| 3449 | } | 3973 | } |
| 3450 | # endif | 3974 | # endif |
| 3451 | 3975 | ||
| 3452 | # if !DCHAR_IS_TCHAR | 3976 | # if !DCHAR_IS_TCHAR |
| 3453 | /* Convert the string into a piece of temporary memory. */ | 3977 | { |
| 3454 | if (characters > 0) | 3978 | TCHAR_T tmpsrc[64]; /* Assume MB_CUR_MAX <= 64. */ |
| 3455 | { | 3979 | |
| 3456 | char cbuf[64]; /* Assume MB_CUR_MAX <= 64. */ | 3980 | /* Convert the string into a piece of temporary memory. */ |
| 3457 | int count; | 3981 | if (bytes > 0) |
| 3982 | { | ||
| 3983 | char cbuf[64]; /* Assume MB_CUR_MAX <= 64. */ | ||
| 3984 | int count; | ||
| 3458 | # if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t | 3985 | # if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t |
| 3459 | mbstate_t state; | 3986 | mbstate_t state; |
| 3460 | mbszero (&state); | 3987 | mbszero (&state); |
| 3461 | # endif | 3988 | # endif |
| 3462 | 3989 | ||
| 3463 | count = local_wcrtomb (cbuf, arg, &state); | 3990 | count = local_wcrtomb (cbuf, arg, &state); |
| 3464 | if (count <= 0) | 3991 | if (count <= 0) |
| 3465 | /* Inconsistency. */ | 3992 | /* Inconsistency. */ |
| 3466 | abort (); | 3993 | abort (); |
| 3467 | memcpy (tmpsrc, cbuf, count); | 3994 | memcpy (tmpsrc, cbuf, count); |
| 3468 | } | 3995 | } |
| 3469 | 3996 | ||
| 3470 | /* Convert from TCHAR_T[] to DCHAR_T[]. */ | 3997 | /* Convert from TCHAR_T[] to DCHAR_T[]. */ |
| 3471 | tmpdst = | 3998 | tmpdst = |
| 3472 | DCHAR_CONV_FROM_ENCODING (locale_charset (), | 3999 | DCHAR_CONV_FROM_ENCODING (locale_charset (), |
| 3473 | iconveh_question_mark, | 4000 | iconveh_question_mark, |
| 3474 | tmpsrc, characters, | 4001 | tmpsrc, bytes, |
| 3475 | NULL, | 4002 | NULL, |
| 3476 | NULL, &tmpdst_len); | 4003 | NULL, &tmpdst_len); |
| 3477 | if (tmpdst == NULL) | 4004 | if (tmpdst == NULL) |
| 3478 | goto fail_with_errno; | 4005 | goto fail_with_errno; |
| 4006 | } | ||
| 3479 | # endif | 4007 | # endif |
| 3480 | 4008 | ||
| 3481 | if (has_width) | 4009 | if (has_width) |
| @@ -3484,11 +4012,15 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, | |||
| 3484 | /* Outside POSIX, it's preferable to compare the width | 4012 | /* Outside POSIX, it's preferable to compare the width |
| 3485 | against the number of _characters_ of the converted | 4013 | against the number of _characters_ of the converted |
| 3486 | value. */ | 4014 | value. */ |
| 3487 | 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 | ||
| 3488 | # else | 4020 | # else |
| 3489 | /* The width is compared against the number of _bytes_ | 4021 | /* The width is compared against the number of _bytes_ |
| 3490 | of the converted value, says POSIX. */ | 4022 | of the converted value, says POSIX. */ |
| 3491 | w = characters; | 4023 | w = bytes; |
| 3492 | # endif | 4024 | # endif |
| 3493 | } | 4025 | } |
| 3494 | else | 4026 | else |
| @@ -3498,7 +4030,12 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, | |||
| 3498 | if (w < width && !(flags & FLAG_LEFT)) | 4030 | if (w < width && !(flags & FLAG_LEFT)) |
| 3499 | { | 4031 | { |
| 3500 | size_t n = width - w; | 4032 | size_t n = width - w; |
| 4033 | # if DCHAR_IS_TCHAR | ||
| 3501 | 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 | ||
| 3502 | DCHAR_SET (result + length, ' ', n); | 4039 | DCHAR_SET (result + length, ' ', n); |
| 3503 | length += n; | 4040 | length += n; |
| 3504 | } | 4041 | } |
| @@ -3507,8 +4044,8 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, | |||
| 3507 | if (has_width) | 4044 | if (has_width) |
| 3508 | { | 4045 | { |
| 3509 | /* We know the number of bytes in advance. */ | 4046 | /* We know the number of bytes in advance. */ |
| 3510 | ENSURE_ALLOCATION (xsum (length, characters)); | 4047 | ENSURE_ALLOCATION (xsum (length, bytes)); |
| 3511 | if (characters > 0) | 4048 | if (bytes > 0) |
| 3512 | { | 4049 | { |
| 3513 | int count; | 4050 | int count; |
| 3514 | # if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t | 4051 | # if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t |
| @@ -3542,7 +4079,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, | |||
| 3542 | } | 4079 | } |
| 3543 | # else | 4080 | # else |
| 3544 | ENSURE_ALLOCATION_ELSE (xsum (length, tmpdst_len), | 4081 | ENSURE_ALLOCATION_ELSE (xsum (length, tmpdst_len), |
| 3545 | { free (tmpdst); goto out_of_memory; }); | 4082 | { free (tmpdst); goto out_of_memory; }); |
| 3546 | DCHAR_CPY (result + length, tmpdst, tmpdst_len); | 4083 | DCHAR_CPY (result + length, tmpdst, tmpdst_len); |
| 3547 | free (tmpdst); | 4084 | free (tmpdst); |
| 3548 | length += tmpdst_len; | 4085 | length += tmpdst_len; |
| @@ -3594,6 +4131,8 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, | |||
| 3594 | width = xsum (xtimes (width, 10), *digitp++ - '0'); | 4131 | width = xsum (xtimes (width, 10), *digitp++ - '0'); |
| 3595 | while (digitp != dp->width_end); | 4132 | while (digitp != dp->width_end); |
| 3596 | } | 4133 | } |
| 4134 | if (width > (size_t) INT_MAX) | ||
| 4135 | goto overflow; | ||
| 3597 | } | 4136 | } |
| 3598 | 4137 | ||
| 3599 | /* %c in vasnwprintf. See the specification of fwprintf. */ | 4138 | /* %c in vasnwprintf. See the specification of fwprintf. */ |
| @@ -3608,24 +4147,26 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, | |||
| 3608 | /* Invalid or incomplete multibyte character. */ | 4147 | /* Invalid or incomplete multibyte character. */ |
| 3609 | goto fail_with_EILSEQ; | 4148 | goto fail_with_EILSEQ; |
| 3610 | 4149 | ||
| 3611 | if (1 < width && !(flags & FLAG_LEFT)) | 4150 | { |
| 3612 | { | 4151 | size_t total = (1 < width ? width : 1); |
| 3613 | size_t n = width - 1; | 4152 | ENSURE_ALLOCATION (xsum (length, total)); |
| 3614 | ENSURE_ALLOCATION (xsum (length, n)); | 4153 | |
| 3615 | DCHAR_SET (result + length, ' ', n); | 4154 | if (1 < width && !(flags & FLAG_LEFT)) |
| 3616 | length += n; | 4155 | { |
| 3617 | } | 4156 | size_t n = width - 1; |
| 4157 | DCHAR_SET (result + length, ' ', n); | ||
| 4158 | length += n; | ||
| 4159 | } | ||
| 3618 | 4160 | ||
| 3619 | ENSURE_ALLOCATION (xsum (length, 1)); | 4161 | result[length++] = wc; |
| 3620 | result[length++] = wc; | ||
| 3621 | 4162 | ||
| 3622 | if (1 < width && (flags & FLAG_LEFT)) | 4163 | if (1 < width && (flags & FLAG_LEFT)) |
| 3623 | { | 4164 | { |
| 3624 | size_t n = width - 1; | 4165 | size_t n = width - 1; |
| 3625 | ENSURE_ALLOCATION (xsum (length, n)); | 4166 | DCHAR_SET (result + length, ' ', n); |
| 3626 | DCHAR_SET (result + length, ' ', n); | 4167 | length += n; |
| 3627 | length += n; | 4168 | } |
| 3628 | } | 4169 | } |
| 3629 | } | 4170 | } |
| 3630 | } | 4171 | } |
| 3631 | #endif | 4172 | #endif |
| @@ -3682,6 +4223,8 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, | |||
| 3682 | width = xsum (xtimes (width, 10), *digitp++ - '0'); | 4223 | width = xsum (xtimes (width, 10), *digitp++ - '0'); |
| 3683 | while (digitp != dp->width_end); | 4224 | while (digitp != dp->width_end); |
| 3684 | } | 4225 | } |
| 4226 | if (width > (size_t) INT_MAX) | ||
| 4227 | goto overflow; | ||
| 3685 | has_width = 1; | 4228 | has_width = 1; |
| 3686 | } | 4229 | } |
| 3687 | 4230 | ||
| @@ -3933,7 +4476,8 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, | |||
| 3933 | { | 4476 | { |
| 3934 | size_t n = xsum (length, count); | 4477 | size_t n = xsum (length, count); |
| 3935 | 4478 | ||
| 3936 | ENSURE_ALLOCATION (n); | 4479 | ENSURE_ALLOCATION_ELSE (n, |
| 4480 | { if (tmp != tmpbuf) free (tmp); goto out_of_memory; }); | ||
| 3937 | } | 4481 | } |
| 3938 | 4482 | ||
| 3939 | /* Append the result. */ | 4483 | /* Append the result. */ |
| @@ -3996,6 +4540,8 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, | |||
| 3996 | width = xsum (xtimes (width, 10), *digitp++ - '0'); | 4540 | width = xsum (xtimes (width, 10), *digitp++ - '0'); |
| 3997 | while (digitp != dp->width_end); | 4541 | while (digitp != dp->width_end); |
| 3998 | } | 4542 | } |
| 4543 | if (width > (size_t) INT_MAX) | ||
| 4544 | goto overflow; | ||
| 3999 | } | 4545 | } |
| 4000 | 4546 | ||
| 4001 | has_precision = 0; | 4547 | has_precision = 0; |
| @@ -4423,7 +4969,8 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, | |||
| 4423 | { | 4969 | { |
| 4424 | size_t n = xsum (length, count); | 4970 | size_t n = xsum (length, count); |
| 4425 | 4971 | ||
| 4426 | ENSURE_ALLOCATION (n); | 4972 | ENSURE_ALLOCATION_ELSE (n, |
| 4973 | { if (tmp != tmpbuf) free (tmp); goto out_of_memory; }); | ||
| 4427 | } | 4974 | } |
| 4428 | 4975 | ||
| 4429 | /* Append the result. */ | 4976 | /* Append the result. */ |
| @@ -4501,6 +5048,8 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, | |||
| 4501 | width = xsum (xtimes (width, 10), *digitp++ - '0'); | 5048 | width = xsum (xtimes (width, 10), *digitp++ - '0'); |
| 4502 | while (digitp != dp->width_end); | 5049 | while (digitp != dp->width_end); |
| 4503 | } | 5050 | } |
| 5051 | if (width > (size_t) INT_MAX) | ||
| 5052 | goto overflow; | ||
| 4504 | } | 5053 | } |
| 4505 | 5054 | ||
| 4506 | has_precision = 0; | 5055 | has_precision = 0; |
| @@ -4587,6 +5136,17 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, | |||
| 4587 | } | 5136 | } |
| 4588 | } | 5137 | } |
| 4589 | # 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 | } | ||
| 4590 | /* Account for sign, decimal point etc. */ | 5150 | /* Account for sign, decimal point etc. */ |
| 4591 | tmp_length = xsum (tmp_length, 12); | 5151 | tmp_length = xsum (tmp_length, 12); |
| 4592 | 5152 | ||
| @@ -4682,12 +5242,84 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, | |||
| 4682 | ndigits = strlen (digits); | 5242 | ndigits = strlen (digits); |
| 4683 | 5243 | ||
| 4684 | if (ndigits > precision) | 5244 | if (ndigits > precision) |
| 4685 | do | 5245 | { |
| 4686 | { | 5246 | /* Number of digits before the decimal point. */ |
| 4687 | --ndigits; | 5247 | size_t intpart_digits = ndigits - precision; |
| 4688 | *p++ = digits[ndigits]; | 5248 | |
| 4689 | } | 5249 | const DCHAR_T *thousep = NULL; |
| 4690 | 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 | } | ||
| 4691 | else | 5323 | else |
| 4692 | *p++ = '0'; | 5324 | *p++ = '0'; |
| 4693 | /* Here ndigits <= precision. */ | 5325 | /* Here ndigits <= precision. */ |
| @@ -4940,10 +5572,84 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, | |||
| 4940 | digits without trailing zeroes. */ | 5572 | digits without trailing zeroes. */ |
| 4941 | if (exponent >= 0) | 5573 | if (exponent >= 0) |
| 4942 | { | 5574 | { |
| 4943 | size_t ecount = exponent + 1; | 5575 | /* Number of digits before the decimal point. */ |
| 4944 | /* Note: count <= precision = ndigits. */ | 5576 | size_t intpart_digits = exponent + 1; |
| 4945 | for (; ecount > 0; ecount--) | 5577 | /* Note: intpart_digits <= precision = ndigits. */ |
| 4946 | *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 | |||
| 4947 | if ((flags & FLAG_ALT) || ndigits > nzeroes) | 5653 | if ((flags & FLAG_ALT) || ndigits > nzeroes) |
| 4948 | { | 5654 | { |
| 4949 | *p++ = decimal_point_char (); | 5655 | *p++ = decimal_point_char (); |
| @@ -5144,12 +5850,84 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, | |||
| 5144 | ndigits = strlen (digits); | 5850 | ndigits = strlen (digits); |
| 5145 | 5851 | ||
| 5146 | if (ndigits > precision) | 5852 | if (ndigits > precision) |
| 5147 | do | 5853 | { |
| 5148 | { | 5854 | /* Number of digits before the decimal point. */ |
| 5149 | --ndigits; | 5855 | size_t intpart_digits = ndigits - precision; |
| 5150 | *p++ = digits[ndigits]; | 5856 | |
| 5151 | } | 5857 | const DCHAR_T *thousep = NULL; |
| 5152 | 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 | } | ||
| 5153 | else | 5931 | else |
| 5154 | *p++ = '0'; | 5932 | *p++ = '0'; |
| 5155 | /* Here ndigits <= precision. */ | 5933 | /* Here ndigits <= precision. */ |
| @@ -5410,10 +6188,84 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, | |||
| 5410 | digits without trailing zeroes. */ | 6188 | digits without trailing zeroes. */ |
| 5411 | if (exponent >= 0) | 6189 | if (exponent >= 0) |
| 5412 | { | 6190 | { |
| 5413 | size_t ecount = exponent + 1; | 6191 | /* Number of digits before the decimal point. */ |
| 5414 | /* Note: ecount <= precision = ndigits. */ | 6192 | size_t intpart_digits = exponent + 1; |
| 5415 | for (; ecount > 0; ecount--) | 6193 | /* Note: intpart_digits <= precision = ndigits. */ |
| 5416 | *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 | |||
| 5417 | if ((flags & FLAG_ALT) || ndigits > nzeroes) | 6269 | if ((flags & FLAG_ALT) || ndigits > nzeroes) |
| 5418 | { | 6270 | { |
| 5419 | *p++ = decimal_point_char (); | 6271 | *p++ = decimal_point_char (); |
| @@ -5606,7 +6458,8 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, | |||
| 5606 | { | 6458 | { |
| 5607 | size_t n = xsum (length, count); | 6459 | size_t n = xsum (length, count); |
| 5608 | 6460 | ||
| 5609 | ENSURE_ALLOCATION (n); | 6461 | ENSURE_ALLOCATION_ELSE (n, |
| 6462 | { if (tmp != tmpbuf) free (tmp); goto out_of_memory; }); | ||
| 5610 | } | 6463 | } |
| 5611 | 6464 | ||
| 5612 | /* Append the result. */ | 6465 | /* Append the result. */ |
| @@ -5620,13 +6473,13 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, | |||
| 5620 | { | 6473 | { |
| 5621 | arg_type type = a.arg[dp->arg_index].type; | 6474 | arg_type type = a.arg[dp->arg_index].type; |
| 5622 | int flags = dp->flags; | 6475 | int flags = dp->flags; |
| 5623 | #if (WIDE_CHAR_VERSION && MUSL_LIBC) || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION | 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 |
| 5624 | int has_width; | 6477 | int has_width; |
| 5625 | #endif | 6478 | #endif |
| 5626 | #if !USE_SNPRINTF || WIDE_CHAR_VERSION || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION | 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 |
| 5627 | size_t width; | 6480 | size_t width; |
| 5628 | #endif | 6481 | #endif |
| 5629 | #if !USE_SNPRINTF || (WIDE_CHAR_VERSION && DCHAR_IS_TCHAR) || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || (WIDE_CHAR_VERSION && MUSL_LIBC) || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION | 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 |
| 5630 | int has_precision; | 6483 | int has_precision; |
| 5631 | size_t precision; | 6484 | size_t precision; |
| 5632 | #endif | 6485 | #endif |
| @@ -5635,9 +6488,14 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, | |||
| 5635 | #else | 6488 | #else |
| 5636 | # define prec_ourselves 0 | 6489 | # define prec_ourselves 0 |
| 5637 | #endif | 6490 | #endif |
| 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 | ||
| 5638 | #if (WIDE_CHAR_VERSION && MUSL_LIBC) || NEED_PRINTF_FLAG_LEFTADJUST | 6496 | #if (WIDE_CHAR_VERSION && MUSL_LIBC) || NEED_PRINTF_FLAG_LEFTADJUST |
| 5639 | # define pad_ourselves 1 | 6497 | # define pad_ourselves 1 |
| 5640 | #elif !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_FLAG_ALT_PRECISION_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 |
| 5641 | int pad_ourselves; | 6499 | int pad_ourselves; |
| 5642 | #else | 6500 | #else |
| 5643 | # define pad_ourselves 0 | 6501 | # define pad_ourselves 0 |
| @@ -5652,10 +6510,10 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, | |||
| 5652 | TCHAR_T *tmp; | 6510 | TCHAR_T *tmp; |
| 5653 | #endif | 6511 | #endif |
| 5654 | 6512 | ||
| 5655 | #if (WIDE_CHAR_VERSION && MUSL_LIBC) || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION | 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 |
| 5656 | has_width = 0; | 6514 | has_width = 0; |
| 5657 | #endif | 6515 | #endif |
| 5658 | #if !USE_SNPRINTF || WIDE_CHAR_VERSION || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION | 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 |
| 5659 | width = 0; | 6517 | width = 0; |
| 5660 | if (dp->width_start != dp->width_end) | 6518 | if (dp->width_start != dp->width_end) |
| 5661 | { | 6519 | { |
| @@ -5683,13 +6541,16 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, | |||
| 5683 | width = xsum (xtimes (width, 10), *digitp++ - '0'); | 6541 | width = xsum (xtimes (width, 10), *digitp++ - '0'); |
| 5684 | while (digitp != dp->width_end); | 6542 | while (digitp != dp->width_end); |
| 5685 | } | 6543 | } |
| 5686 | # if (WIDE_CHAR_VERSION && MUSL_LIBC) || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION | 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 | ||
| 5687 | has_width = 1; | 6548 | has_width = 1; |
| 5688 | # endif | 6549 | # endif |
| 5689 | } | 6550 | } |
| 5690 | #endif | 6551 | #endif |
| 5691 | 6552 | ||
| 5692 | #if !USE_SNPRINTF || (WIDE_CHAR_VERSION && DCHAR_IS_TCHAR) || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || (WIDE_CHAR_VERSION && MUSL_LIBC) || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION | 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 |
| 5693 | has_precision = 0; | 6554 | has_precision = 0; |
| 5694 | precision = 6; | 6555 | precision = 6; |
| 5695 | if (dp->precision_start != dp->precision_end) | 6556 | if (dp->precision_start != dp->precision_end) |
| @@ -5754,8 +6615,37 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, | |||
| 5754 | } | 6615 | } |
| 5755 | #endif | 6616 | #endif |
| 5756 | 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 | |||
| 5757 | /* Decide whether to perform the padding ourselves. */ | 6647 | /* Decide whether to perform the padding ourselves. */ |
| 5758 | #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) | 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) |
| 5759 | switch (dp->conversion) | 6649 | switch (dp->conversion) |
| 5760 | { | 6650 | { |
| 5761 | # if !DCHAR_IS_TCHAR || ENABLE_UNISTDIO | 6651 | # if !DCHAR_IS_TCHAR || ENABLE_UNISTDIO |
| @@ -5772,7 +6662,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, | |||
| 5772 | pad_ourselves = 1; | 6662 | pad_ourselves = 1; |
| 5773 | break; | 6663 | break; |
| 5774 | default: | 6664 | default: |
| 5775 | pad_ourselves = prec_ourselves; | 6665 | pad_ourselves = prec_ourselves | group_ourselves; |
| 5776 | break; | 6666 | break; |
| 5777 | } | 6667 | } |
| 5778 | #endif | 6668 | #endif |
| @@ -5805,14 +6695,8 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, | |||
| 5805 | sprintf. */ | 6695 | sprintf. */ |
| 5806 | fbp = buf; | 6696 | fbp = buf; |
| 5807 | *fbp++ = '%'; | 6697 | *fbp++ = '%'; |
| 5808 | #if NEED_PRINTF_FLAG_GROUPING | 6698 | if ((flags & FLAG_GROUP) && !group_ourselves) |
| 5809 | /* The underlying implementation doesn't support the ' flag. | ||
| 5810 | Produce no grouping characters in this case; this is | ||
| 5811 | acceptable because the grouping is locale dependent. */ | ||
| 5812 | #else | ||
| 5813 | if (flags & FLAG_GROUP) | ||
| 5814 | *fbp++ = '\''; | 6699 | *fbp++ = '\''; |
| 5815 | #endif | ||
| 5816 | if (flags & FLAG_LEFT) | 6700 | if (flags & FLAG_LEFT) |
| 5817 | *fbp++ = '-'; | 6701 | *fbp++ = '-'; |
| 5818 | if (flags & FLAG_SHOWSIGN) | 6702 | if (flags & FLAG_SHOWSIGN) |
| @@ -5832,6 +6716,43 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, | |||
| 5832 | if (dp->width_start != dp->width_end) | 6716 | if (dp->width_start != dp->width_end) |
| 5833 | { | 6717 | { |
| 5834 | 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 | ||
| 5835 | /* The width specification is known to consist only | 6756 | /* The width specification is known to consist only |
| 5836 | of standard ASCII characters. */ | 6757 | of standard ASCII characters. */ |
| 5837 | if (sizeof (FCHAR_T) == sizeof (TCHAR_T)) | 6758 | if (sizeof (FCHAR_T) == sizeof (TCHAR_T)) |
| @@ -5870,7 +6791,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, | |||
| 5870 | } | 6791 | } |
| 5871 | } | 6792 | } |
| 5872 | 6793 | ||
| 5873 | switch (type) | 6794 | switch (+type) |
| 5874 | { | 6795 | { |
| 5875 | case TYPE_LONGLONGINT: | 6796 | case TYPE_LONGLONGINT: |
| 5876 | case TYPE_ULONGLONGINT: | 6797 | case TYPE_ULONGLONGINT: |
| @@ -5984,9 +6905,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, | |||
| 5984 | #if HAVE_WINT_T | 6905 | #if HAVE_WINT_T |
| 5985 | case TYPE_WIDE_CHAR: | 6906 | case TYPE_WIDE_CHAR: |
| 5986 | #endif | 6907 | #endif |
| 5987 | #if HAVE_WCHAR_T | ||
| 5988 | case TYPE_WIDE_STRING: | 6908 | case TYPE_WIDE_STRING: |
| 5989 | #endif | ||
| 5990 | *fbp++ = 'l'; | 6909 | *fbp++ = 'l'; |
| 5991 | break; | 6910 | break; |
| 5992 | case TYPE_LONGDOUBLE: | 6911 | case TYPE_LONGDOUBLE: |
| @@ -6168,7 +7087,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, | |||
| 6168 | #endif | 7087 | #endif |
| 6169 | 7088 | ||
| 6170 | errno = 0; | 7089 | errno = 0; |
| 6171 | switch (type) | 7090 | switch (+type) |
| 6172 | { | 7091 | { |
| 6173 | case TYPE_SCHAR: | 7092 | case TYPE_SCHAR: |
| 6174 | { | 7093 | { |
| @@ -6358,14 +7277,12 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, | |||
| 6358 | SNPRINTF_BUF (arg); | 7277 | SNPRINTF_BUF (arg); |
| 6359 | } | 7278 | } |
| 6360 | break; | 7279 | break; |
| 6361 | #if HAVE_WCHAR_T | ||
| 6362 | case TYPE_WIDE_STRING: | 7280 | case TYPE_WIDE_STRING: |
| 6363 | { | 7281 | { |
| 6364 | 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; |
| 6365 | SNPRINTF_BUF (arg); | 7283 | SNPRINTF_BUF (arg); |
| 6366 | } | 7284 | } |
| 6367 | break; | 7285 | break; |
| 6368 | #endif | ||
| 6369 | case TYPE_POINTER: | 7286 | case TYPE_POINTER: |
| 6370 | { | 7287 | { |
| 6371 | void *arg = a.arg[dp->arg_index].a.a_pointer; | 7288 | void *arg = a.arg[dp->arg_index].a.a_pointer; |
| @@ -6539,10 +7456,13 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, | |||
| 6539 | || *prec_ptr == ' ')) | 7456 | || *prec_ptr == ' ')) |
| 6540 | prefix_count = 1; | 7457 | prefix_count = 1; |
| 6541 | /* Put the additional zeroes after the 0x prefix if | 7458 | /* Put the additional zeroes after the 0x prefix if |
| 6542 | (flags & FLAG_ALT) || (dp->conversion == 'p'). */ | 7459 | (flags & FLAG_ALT) || (dp->conversion == 'p'), or |
| 7460 | after the 0b prefix if (flags & FLAG_ALT). */ | ||
| 6543 | else if (count >= 2 | 7461 | else if (count >= 2 |
| 6544 | && prec_ptr[0] == '0' | 7462 | && prec_ptr[0] == '0' |
| 6545 | && (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')) | ||
| 6546 | prefix_count = 2; | 7466 | prefix_count = 2; |
| 6547 | 7467 | ||
| 6548 | move = count - prefix_count; | 7468 | move = count - prefix_count; |
| @@ -6591,6 +7511,135 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, | |||
| 6591 | } | 7511 | } |
| 6592 | #endif | 7512 | #endif |
| 6593 | 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 | |||
| 6594 | #if !USE_SNPRINTF | 7643 | #if !USE_SNPRINTF |
| 6595 | if (count >= tmp_length) | 7644 | if (count >= tmp_length) |
| 6596 | /* tmp_length was incorrectly calculated - fix the | 7645 | /* tmp_length was incorrectly calculated - fix the |
| @@ -6601,6 +7650,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, | |||
| 6601 | #if !DCHAR_IS_TCHAR | 7650 | #if !DCHAR_IS_TCHAR |
| 6602 | /* Convert from TCHAR_T[] to DCHAR_T[]. */ | 7651 | /* Convert from TCHAR_T[] to DCHAR_T[]. */ |
| 6603 | if (dp->conversion == 'c' || dp->conversion == 's' | 7652 | if (dp->conversion == 'c' || dp->conversion == 's' |
| 7653 | || (flags & FLAG_GROUP) | ||
| 6604 | # if __GLIBC__ >= 2 && !defined __UCLIBC__ | 7654 | # if __GLIBC__ >= 2 && !defined __UCLIBC__ |
| 6605 | || (flags & FLAG_LOCALIZED) | 7655 | || (flags & FLAG_LOCALIZED) |
| 6606 | # endif | 7656 | # endif |
| @@ -6677,7 +7727,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, | |||
| 6677 | goto fail_with_errno; | 7727 | goto fail_with_errno; |
| 6678 | # endif | 7728 | # endif |
| 6679 | ENSURE_ALLOCATION_ELSE (xsum (length, tmpdst_len), | 7729 | ENSURE_ALLOCATION_ELSE (xsum (length, tmpdst_len), |
| 6680 | { free (tmpdst); goto out_of_memory; }); | 7730 | { free (tmpdst); goto out_of_memory; }); |
| 6681 | DCHAR_CPY (result + length, tmpdst, tmpdst_len); | 7731 | DCHAR_CPY (result + length, tmpdst, tmpdst_len); |
| 6682 | free (tmpdst); | 7732 | free (tmpdst); |
| 6683 | count = tmpdst_len; | 7733 | count = tmpdst_len; |
| @@ -6742,7 +7792,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, | |||
| 6742 | /* Here count <= allocated - length. */ | 7792 | /* Here count <= allocated - length. */ |
| 6743 | 7793 | ||
| 6744 | /* Perform padding. */ | 7794 | /* Perform padding. */ |
| 6745 | #if (WIDE_CHAR_VERSION && MUSL_LIBC) || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION | 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 |
| 6746 | if (pad_ourselves && has_width) | 7796 | if (pad_ourselves && has_width) |
| 6747 | { | 7797 | { |
| 6748 | size_t w; | 7798 | size_t w; |
| @@ -6751,6 +7801,23 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, | |||
| 6751 | against the number of _characters_ of the converted | 7801 | against the number of _characters_ of the converted |
| 6752 | value. */ | 7802 | value. */ |
| 6753 | 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 | } | ||
| 6754 | # else | 7821 | # else |
| 6755 | /* The width is compared against the number of _bytes_ | 7822 | /* The width is compared against the number of _bytes_ |
| 6756 | of the converted value, says POSIX. */ | 7823 | of the converted value, says POSIX. */ |
| @@ -6929,17 +7996,15 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, | |||
| 6929 | not have this limitation. */ | 7996 | not have this limitation. */ |
| 6930 | return result; | 7997 | return result; |
| 6931 | 7998 | ||
| 6932 | #if USE_SNPRINTF | ||
| 6933 | overflow: | 7999 | overflow: |
| 6934 | errno = EOVERFLOW; | 8000 | errno = EOVERFLOW; |
| 6935 | goto fail_with_errno; | 8001 | goto fail_with_errno; |
| 6936 | #endif | ||
| 6937 | 8002 | ||
| 6938 | out_of_memory: | 8003 | out_of_memory: |
| 6939 | errno = ENOMEM; | 8004 | errno = ENOMEM; |
| 6940 | goto fail_with_errno; | 8005 | goto fail_with_errno; |
| 6941 | 8006 | ||
| 6942 | #if ENABLE_UNISTDIO || ((!USE_SNPRINTF || WIDE_CHAR_VERSION || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || NEED_PRINTF_DIRECTIVE_LS || ENABLE_WCHAR_FALLBACK) && HAVE_WCHAR_T) || ((NEED_PRINTF_DIRECTIVE_LC || ENABLE_WCHAR_FALLBACK) && HAVE_WINT_T && !WIDE_CHAR_VERSION) || (NEED_WPRINTF_DIRECTIVE_C && WIDE_CHAR_VERSION) | 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) |
| 6943 | fail_with_EILSEQ: | 8008 | fail_with_EILSEQ: |
| 6944 | errno = EILSEQ; | 8009 | errno = EILSEQ; |
| 6945 | goto fail_with_errno; | 8010 | goto fail_with_errno; |
