summaryrefslogtreecommitdiff
path: root/lib/vasnprintf.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/vasnprintf.c')
-rw-r--r--lib/vasnprintf.c1508
1 files changed, 1026 insertions, 482 deletions
diff --git a/lib/vasnprintf.c b/lib/vasnprintf.c
index 6ae95ca5..12bdd45b 100644
--- a/lib/vasnprintf.c
+++ b/lib/vasnprintf.c
@@ -1,5 +1,5 @@
/* vsprintf with automatic memory allocation.
- Copyright (C) 1999, 2002-2024 Free Software Foundation, Inc.
+ Copyright (C) 1999, 2002-2026 Free Software Foundation, Inc.
This file is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
@@ -29,6 +29,7 @@
Depends on FCHAR_T.
DCHAR_CPY memcpy like function for DCHAR_T[] arrays.
DCHAR_SET memset like function for DCHAR_T[] arrays.
+ DCHAR_STRLEN strlen like function for DCHAR_T[] arrays.
DCHAR_MBSNLEN mbsnlen like function for DCHAR_T[] arrays.
SNPRINTF The system's snprintf (or similar) function.
This may be either snprintf or swprintf.
@@ -88,7 +89,7 @@
#include <errno.h> /* errno */
#include <limits.h> /* CHAR_BIT, INT_MAX, INT_WIDTH, LONG_WIDTH */
#include <float.h> /* DBL_MAX_EXP, LDBL_MAX_EXP, LDBL_MANT_DIG */
-#if HAVE_NL_LANGINFO
+#if HAVE_NL_LANGINFO || __GLIBC__ >= 2 || defined __CYGWIN__
# include <langinfo.h>
#endif
#ifndef VASNPRINTF
@@ -133,6 +134,16 @@
# include "fpucw.h"
#endif
+#if HAVE_SAME_LONG_DOUBLE_AS_DOUBLE
+/* Override macros from fpucw.h. */
+# undef DECL_LONG_DOUBLE_ROUNDING
+# define DECL_LONG_DOUBLE_ROUNDING
+# undef BEGIN_LONG_DOUBLE_ROUNDING
+# define BEGIN_LONG_DOUBLE_ROUNDING()
+# undef END_LONG_DOUBLE_ROUNDING
+# define END_LONG_DOUBLE_ROUNDING()
+#endif
+
/* Default parameters. */
#ifndef VASNPRINTF
# if WIDE_CHAR_VERSION
@@ -179,10 +190,24 @@
# define SNPRINTF swprintf
# endif
# else
- /* Old platforms such as NetBSD 3.0, OpenBSD 3.8, HP-UX 11.00, IRIX 6.5. */
+ /* Old platforms such as NetBSD 3.0, OpenBSD 3.8, HP-UX 11.00. */
# define TCHAR_T char
# endif
#endif
+#ifndef DCHAR_STRLEN
+# if WIDE_CHAR_VERSION
+# define DCHAR_STRLEN local_wcslen
+# else
+# define DCHAR_STRLEN strlen
+# endif
+#endif
+#ifndef DCHAR_MBSNLEN
+# if WIDE_CHAR_VERSION
+# define DCHAR_MBSNLEN wcsnlen
+# else
+# define DCHAR_MBSNLEN mbsnlen
+# endif
+#endif
#if !WIDE_CHAR_VERSION || !DCHAR_IS_TCHAR
/* TCHAR_T is char. */
/* Use snprintf if it exists under the name 'snprintf' or '_snprintf'.
@@ -217,6 +242,12 @@
/* Here we need to call the native sprintf, not rpl_sprintf. */
#undef sprintf
+/* macOS 12's "warning: 'sprintf' is deprecated" is pointless,
+ as sprintf is used safely here. */
+#if defined __APPLE__ && defined __MACH__ && _GL_GNUC_PREREQ (4, 2)
+# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+#endif
+
/* GCC >= 4.0 with -Wall emits unjustified "... may be used uninitialized"
warnings in this file. Use -Dlint to suppress them. */
#if defined GCC_LINT || defined lint
@@ -225,6 +256,11 @@
# define IF_LINT(Code) /* empty */
#endif
+/* Here we need only the most basic fields of 'struct lconv', and can
+ therefore use the system's localeconv() function, without needing a
+ dependency on module 'localeconv'. */
+#undef localeconv
+
/* Avoid some warnings from "gcc -Wshadow".
This file doesn't use the exp() and remainder() functions. */
#undef exp
@@ -358,7 +394,7 @@ local_wctomb (char *s, wchar_t wc)
# endif
#endif
-#if NEED_PRINTF_DIRECTIVE_A || NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_INFINITE_LONG_DOUBLE || NEED_PRINTF_DOUBLE || NEED_PRINTF_INFINITE_DOUBLE || (NEED_WPRINTF_DIRECTIVE_LA && WIDE_CHAR_VERSION)
+#if NEED_PRINTF_DIRECTIVE_A || NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_INFINITE_LONG_DOUBLE || NEED_PRINTF_DOUBLE || NEED_PRINTF_INFINITE_DOUBLE || (NEED_WPRINTF_DIRECTIVE_LA && WIDE_CHAR_VERSION) || (NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION || NEED_PRINTF_FLAG_GROUPING || NEED_PRINTF_FLAG_GROUPING_INT)
/* Determine the decimal-point character according to the current locale. */
# ifndef decimal_point_char_defined
# define decimal_point_char_defined 1
@@ -385,6 +421,217 @@ decimal_point_char (void)
# endif
#endif
+#if (!WIDE_CHAR_VERSION && (NEED_PRINTF_DOUBLE || NEED_PRINTF_LONG_DOUBLE)) || ((!WIDE_CHAR_VERSION || !DCHAR_IS_TCHAR) && (NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION || NEED_PRINTF_FLAG_GROUPING || NEED_PRINTF_FLAG_GROUPING_INT))
+/* Determine the thousands-separator character according to the current
+ locale.
+ It is a single multibyte character.
+ In glibc: 35x ".", 90x ",", 23x U+202F, 1x U+2019, 1x U+066C, on other
+ systems also U+00A0. */
+# ifndef thousands_separator_char_defined
+# define thousands_separator_char_defined 1
+static const char *
+thousands_separator_char (char stackbuf[10])
+{
+ /* Determine it in a multithread-safe way.
+ We know nl_langinfo is multithread-safe on glibc systems, on Mac OS X
+ systems, and on NetBSD, but is not required to be multithread-safe by
+ POSIX.
+ localeconv() is not guaranteed to be multithread-safe by POSIX either;
+ however, on native Windows it is (cf. test-localeconv-mt).
+ sprintf(), however, is multithread-safe. */
+# if HAVE_NL_LANGINFO && (__GLIBC__ || defined __UCLIBC__ || (defined __APPLE__ && defined __MACH__) || defined __NetBSD__)
+ return nl_langinfo (THOUSEP);
+# elif defined _WIN32 && !defined __CYGWIN__
+ return localeconv () -> thousands_sep;
+# else
+ sprintf (stackbuf, "%'.0f", 1000.0);
+ /* Now stackbuf = "1<thousep>000". */
+ stackbuf[strlen (stackbuf) - 3] = '\0';
+# if defined __sun
+ /* Solaris specific hack: Replace wrong result (0xC2 means U+00A0). */
+ if (streq (&stackbuf[1], "\302"))
+ strcpy (&stackbuf[1], MB_CUR_MAX > 1 ? "\302\240" : "\240");
+# endif
+ return &stackbuf[1];
+# endif
+}
+# endif
+#endif
+#if !WIDE_CHAR_VERSION && defined DCHAR_CONV_FROM_ENCODING && (NEED_PRINTF_DOUBLE || NEED_PRINTF_LONG_DOUBLE)
+/* Determine the thousands-separator character, as a DCHAR_T[] array,
+ according to the current locale.
+ It is a single Unicode character. */
+# ifndef thousands_separator_DCHAR_defined
+# define thousands_separator_DCHAR_defined 1
+static const DCHAR_T *
+thousands_separator_DCHAR (DCHAR_T stackbuf[10])
+{
+ /* Determine it in a multithread-safe way. */
+ char tmpbuf[10];
+ const char *tmp = thousands_separator_char (tmpbuf);
+ if (*tmp != '\0')
+ {
+ /* Convert it from char[] to DCHAR_T[]. */
+ size_t converted_len = 10;
+ DCHAR_T *converted =
+ DCHAR_CONV_FROM_ENCODING (locale_charset (),
+ iconveh_question_mark,
+ tmp, strlen (tmp) + 1,
+ NULL,
+ stackbuf, &converted_len);
+ if (converted != NULL)
+ {
+ if (converted != stackbuf)
+ /* It should not be so long. */
+ abort ();
+ return stackbuf;
+ }
+ }
+ stackbuf[0] = 0;
+ return stackbuf;
+}
+# endif
+#endif
+/* Maximum number of 'char' in the char[] or DCHAR_T[] representation of the
+ thousands separator. */
+#define THOUSEP_CHAR_MAXLEN 3
+
+#if WIDE_CHAR_VERSION && ((NEED_PRINTF_DOUBLE || NEED_PRINTF_LONG_DOUBLE) || ((NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION || NEED_PRINTF_FLAG_GROUPING || NEED_PRINTF_FLAG_GROUPING_INT) && DCHAR_IS_TCHAR))
+/* Determine the thousands-separator character, as a wide character, according
+ to the current locale.
+ It is a single wide character. */
+# ifndef thousands_separator_wchar_defined
+# define thousands_separator_wchar_defined 1
+static const wchar_t *
+thousands_separator_wchar (wchar_t stackbuf[10])
+{
+# if __GLIBC__ >= 2 || defined __CYGWIN__
+ /* On glibc, in the unibyte locale fr_FR, the *wprintf routines use U+202F
+ as separator, which cannot be represented in the locale encoding. */
+ stackbuf[0] =
+ (wchar_t) (unsigned long) nl_langinfo (_NL_NUMERIC_THOUSANDS_SEP_WC);
+ stackbuf[1] = L'\0';
+ return stackbuf;
+# elif defined _WIN32 && !defined __CYGWIN__
+ const char *tmp = localeconv () -> thousands_sep;
+ if (*tmp != '\0')
+ {
+ mbstate_t state;
+ mbszero (&state);
+ if ((int) mbrtowc (&stackbuf[0], tmp, strlen (tmp), &state) > 0)
+ stackbuf[1] = L'\0';
+ else
+ stackbuf[0] = L'\0';
+ }
+ else
+ stackbuf[0] = L'\0';
+ return stackbuf;
+# elif defined __sun
+ /* Use sprintf, because swprintf retrieves a wrong value for the
+ thousands-separator wide character (e.g. (wchar_t) 0xffffffa0). */
+ char tmp[10];
+ sprintf (tmp, "%'.0f", 1000.0);
+ /* Now tmp = L"1<thousep>000". */
+ tmp[strlen (tmp) - 3] = '\0';
+ /* Solaris specific hack: Replace wrong result (0xC2 means U+00A0). */
+ if (streq (&tmp[1], "\302"))
+ strcpy (&tmp[1], MB_CUR_MAX > 1 ? "\302\240" : "\240");
+ if (tmp[1] != '\0')
+ {
+ mbstate_t state;
+ mbszero (&state);
+ if ((int) mbrtowc (&stackbuf[0], &tmp[1], strlen (&tmp[1]), &state) > 0)
+ stackbuf[1] = L'\0';
+ else
+ stackbuf[0] = L'\0';
+ }
+ else
+ stackbuf[0] = L'\0';
+ return stackbuf;
+# else
+ swprintf (stackbuf, 10, L"%'.0f", 1000.0);
+ /* Now stackbuf = L"1<thousep>000". */
+ stackbuf[local_wcslen (stackbuf) - 3] = '\0';
+ return &stackbuf[1];
+# endif
+}
+# endif
+#endif
+/* Maximum number of 'wchar_t' in the wchar_t[] representation of the thousands
+ separator. */
+#define THOUSEP_WCHAR_MAXLEN 1
+
+#if (NEED_PRINTF_DOUBLE || NEED_PRINTF_LONG_DOUBLE) || (NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION || NEED_PRINTF_FLAG_GROUPING || NEED_PRINTF_FLAG_GROUPING_INT)
+# ifndef grouping_rule_defined
+# define grouping_rule_defined 1
+/* Determine the grouping rule.
+ * As specified in POSIX
+ * <https://pubs.opengroup.org/onlinepubs/9799919799/functions/localeconv.html>
+ * <https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/V1_chap07.html#tag_07_03_04>
+ * it is a string whose elements are 'signed char' values, where
+ * "Each integer specifies the number of digits in each group, with the initial
+ * integer defining the size of the group immediately preceding the decimal
+ * delimiter, and the following integers defining the preceding groups. If
+ * the last integer is not -1, then the size of the previous group (if any)
+ * shall be repeatedly used for the remainder of the digits. If the last
+ * integer is -1, then no further grouping shall be performed."
+ * Platforms that have locales with grouping:
+ * glibc, FreeBSD, NetBSD, AIX, Solaris, Cygwin, Haiku.
+ * Platforms that don't:
+ * musl libc, macOS, OpenBSD, Android, mingw, MSVC.
+ * Typical grouping rules on glibc:
+ * 136x 3 (fr_FR etc.)
+ * 4x 4 (cmn_TW etc.)
+ * 9x 3;2 (ta_IN etc.)
+ * 1x 2;2;2;3 (umn_US)
+ * 21x -1 (C etc.)
+ */
+static const signed char *
+grouping_rule (void)
+{
+ /* We know nl_langinfo is multithread-safe on glibc systems and on Cygwin,
+ but is not required to be multithread-safe by POSIX.
+ localeconv() is not guaranteed to be multithread-safe by POSIX either;
+ however, on all known systems it is (cf. test-localeconv-mt). */
+# if __GLIBC__ >= 2
+ return (const signed char *) nl_langinfo (GROUPING);
+# elif defined __CYGWIN__
+ return (const signed char *) nl_langinfo (_NL_NUMERIC_GROUPING);
+# else
+ return (const signed char *) localeconv () -> grouping;
+# endif
+}
+/* Determines the number of thousands-separators to be inserted in a digit
+ sequence with ndigits digits (before the decimal point). */
+static size_t
+num_thousands_separators (const signed char *grouping, size_t ndigits)
+{
+ const signed char *g = grouping;
+ int h = *g;
+ if (h <= 0 || ndigits == 0)
+ return 0;
+ size_t insert = 0;
+ for (;;)
+ {
+ /* Invariant: here h == *g, h > 0, ndigits > 0. */
+ if (g[1] == 0)
+ /* h repeats endlessly. */
+ return insert + (ndigits - 1) / h;
+ /* h does not repeat. */
+ if (ndigits <= h)
+ return insert;
+ ndigits -= h;
+ insert++;
+ g++;
+ h = *g;
+ if (h < 0)
+ /* No further grouping. */
+ return insert;
+ }
+}
+# endif
+#endif
+
#if NEED_PRINTF_INFINITE_DOUBLE && !NEED_PRINTF_DOUBLE
/* Equivalent to !isfinite(x) || x == 0, but does not require libm. */
@@ -502,19 +749,18 @@ multiply (mpn_t src1, mpn_t src2, mpn_t *dest)
/* Here 1 <= len1 <= len2. */
size_t dlen;
mp_limb_t *dp;
- size_t k, i, j;
dlen = len1 + len2;
dp = (mp_limb_t *) malloc (dlen * sizeof (mp_limb_t));
if (dp == NULL)
return NOMEM_PTR;
- for (k = len2; k > 0; )
+ for (size_t k = len2; k > 0; )
dp[--k] = 0;
- for (i = 0; i < len1; i++)
+ for (size_t i = 0; i < len1; i++)
{
mp_limb_t digit1 = p1[i];
mp_twolimb_t carry = 0;
- for (j = 0; j < len2; j++)
+ for (size_t j = 0; j < len2; j++)
{
mp_limb_t digit2 = p2[j];
carry += (mp_twolimb_t) digit1 * (mp_twolimb_t) digit2;
@@ -598,7 +844,6 @@ divide (mpn_t a, mpn_t b, mpn_t *q)
size_t a_len = a.nlimbs;
const mp_limb_t *b_ptr = b.limbs;
size_t b_len = b.nlimbs;
- mp_limb_t *roomptr;
mp_limb_t *tmp_roomptr = NULL;
mp_limb_t *q_ptr;
size_t q_len;
@@ -608,7 +853,7 @@ divide (mpn_t a, mpn_t b, mpn_t *q)
/* Allocate room for a_len+2 digits.
(Need a_len+1 digits for the real division and 1 more digit for the
final rounding of q.) */
- roomptr = (mp_limb_t *) malloc ((a_len + 2) * sizeof (mp_limb_t));
+ mp_limb_t *roomptr = (mp_limb_t *) malloc ((a_len + 2) * sizeof (mp_limb_t));
if (roomptr == NULL)
return NOMEM_PTR;
@@ -650,8 +895,7 @@ divide (mpn_t a, mpn_t b, mpn_t *q)
mp_limb_t remainder = 0;
const mp_limb_t *sourceptr = a_ptr + a_len;
mp_limb_t *destptr = q_ptr + a_len;
- size_t count;
- for (count = a_len; count > 0; count--)
+ for (size_t count = a_len; count > 0; count--)
{
mp_twolimb_t num =
((mp_twolimb_t) remainder << GMP_LIMB_BITS) | *--sourceptr;
@@ -752,8 +996,7 @@ divide (mpn_t a, mpn_t b, mpn_t *q)
const mp_limb_t *sourceptr = b_ptr;
mp_limb_t *destptr = tmp_roomptr;
mp_twolimb_t accu = 0;
- size_t count;
- for (count = b_len; count > 0; count--)
+ for (size_t count = b_len; count > 0; count--)
{
accu += (mp_twolimb_t) *sourceptr++ << s;
*destptr++ = (mp_limb_t) accu;
@@ -780,8 +1023,7 @@ divide (mpn_t a, mpn_t b, mpn_t *q)
const mp_limb_t *sourceptr = a_ptr;
mp_limb_t *destptr = r_ptr;
mp_twolimb_t accu = 0;
- size_t count;
- for (count = a_len; count > 0; count--)
+ for (size_t count = a_len; count > 0; count--)
{
accu += (mp_twolimb_t) *sourceptr++ << s;
*destptr++ = (mp_limb_t) accu;
@@ -857,8 +1099,7 @@ divide (mpn_t a, mpn_t b, mpn_t *q)
const mp_limb_t *sourceptr = b_ptr;
mp_limb_t *destptr = r_ptr + j;
mp_twolimb_t carry = 0;
- size_t count;
- for (count = b_len; count > 0; count--)
+ for (size_t count = b_len; count > 0; count--)
{
/* Here 0 <= carry <= q*. */
carry =
@@ -882,8 +1123,7 @@ divide (mpn_t a, mpn_t b, mpn_t *q)
const mp_limb_t *sourceptr = b_ptr;
mp_limb_t *destptr = r_ptr + j;
mp_limb_t carry = 0;
- size_t count;
- for (count = b_len; count > 0; count--)
+ for (size_t count = b_len; count > 0; count--)
{
mp_limb_t source1 = *sourceptr++;
mp_limb_t source2 = *destptr;
@@ -915,8 +1155,7 @@ divide (mpn_t a, mpn_t b, mpn_t *q)
{
mp_limb_t ptr = r_ptr + r_len;
mp_twolimb_t accu = 0;
- size_t count;
- for (count = r_len; count > 0; count--)
+ for (size_t count = r_len; count > 0; count--)
{
accu = (mp_twolimb_t) (mp_limb_t) accu << GMP_LIMB_BITS;
accu += (mp_twolimb_t) *--ptr << (GMP_LIMB_BITS - s);
@@ -931,29 +1170,25 @@ divide (mpn_t a, mpn_t b, mpn_t *q)
/* Compare r << 1 with b. */
if (r_len > b_len)
goto increment_q;
- {
- size_t i;
- for (i = b_len;;)
- {
- mp_limb_t r_i =
- (i <= r_len && i > 0 ? r_ptr[i - 1] >> (GMP_LIMB_BITS - 1) : 0)
- | (i < r_len ? r_ptr[i] << 1 : 0);
- mp_limb_t b_i = (i < b_len ? b_ptr[i] : 0);
- if (r_i > b_i)
- goto increment_q;
- if (r_i < b_i)
- goto keep_q;
- if (i == 0)
- break;
- i--;
- }
- }
+ for (size_t i = b_len;;)
+ {
+ mp_limb_t r_i =
+ (i <= r_len && i > 0 ? r_ptr[i - 1] >> (GMP_LIMB_BITS - 1) : 0)
+ | (i < r_len ? r_ptr[i] << 1 : 0);
+ mp_limb_t b_i = (i < b_len ? b_ptr[i] : 0);
+ if (r_i > b_i)
+ goto increment_q;
+ if (r_i < b_i)
+ goto keep_q;
+ if (i == 0)
+ break;
+ i--;
+ }
if (q_len > 0 && ((q_ptr[0] & 1) != 0))
/* q is odd. */
increment_q:
{
- size_t i;
- for (i = 0; i < q_len; i++)
+ for (size_t i = 0; i < q_len; i++)
if (++(q_ptr[i]) != 0)
goto keep_q;
q_ptr[q_len++] = 1;
@@ -999,8 +1234,7 @@ convert_to_decimal (mpn_t a, size_t extra_zeroes)
/* Divide a by 10^9, in-place. */
mp_limb_t remainder = 0;
mp_limb_t *ptr = a_ptr + a_len;
- size_t count;
- for (count = a_len; count > 0; count--)
+ for (size_t count = a_len; count > 0; count--)
{
mp_twolimb_t num =
((mp_twolimb_t) remainder << GMP_LIMB_BITS) | *--ptr;
@@ -1008,7 +1242,7 @@ convert_to_decimal (mpn_t a, size_t extra_zeroes)
remainder = num % 1000000000;
}
/* Store the remainder as 9 decimal digits. */
- for (count = 9; count > 0; count--)
+ for (size_t count = 9; count > 0; count--)
{
*d_ptr++ = '0' + (remainder % 10);
remainder = remainder / 10;
@@ -1042,18 +1276,15 @@ convert_to_decimal (mpn_t a, size_t extra_zeroes)
static void *
decode_long_double (long double x, int *ep, mpn_t *mp)
{
- mpn_t m;
- int exp;
- long double y;
- size_t i;
-
/* Allocate memory for result. */
+ mpn_t m;
m.nlimbs = (LDBL_MANT_BIT + GMP_LIMB_BITS - 1) / GMP_LIMB_BITS;
m.limbs = (mp_limb_t *) malloc (m.nlimbs * sizeof (mp_limb_t));
if (m.limbs == NULL)
return NULL;
/* Split into exponential part and mantissa. */
- y = safe_frexpl (x, &exp);
+ int exp;
+ long double y = safe_frexpl (x, &exp);
if (!(y >= 0.0L && y < 1.0L))
abort ();
/* x = 2^exp * y = 2^(exp - LDBL_MANT_BIT) * (y * 2^LDBL_MANT_BIT), and the
@@ -1091,7 +1322,7 @@ decode_long_double (long double x, int *ep, mpn_t *mp)
}
# endif
# endif
- for (i = LDBL_MANT_BIT / GMP_LIMB_BITS; i > 0; )
+ for (size_t i = LDBL_MANT_BIT / GMP_LIMB_BITS; i > 0; )
{
mp_limb_t hi, lo;
y *= (mp_limb_t) 1 << (GMP_LIMB_BITS / 2);
@@ -1130,18 +1361,15 @@ decode_long_double (long double x, int *ep, mpn_t *mp)
static void *
decode_double (double x, int *ep, mpn_t *mp)
{
- mpn_t m;
- int exp;
- double y;
- size_t i;
-
/* Allocate memory for result. */
+ mpn_t m;
m.nlimbs = (DBL_MANT_BIT + GMP_LIMB_BITS - 1) / GMP_LIMB_BITS;
m.limbs = (mp_limb_t *) malloc (m.nlimbs * sizeof (mp_limb_t));
if (m.limbs == NULL)
return NULL;
/* Split into exponential part and mantissa. */
- y = frexp (x, &exp);
+ int exp;
+ double y = frexp (x, &exp);
if (!(y >= 0.0 && y < 1.0))
abort ();
/* x = 2^exp * y = 2^(exp - DBL_MANT_BIT) * (y * 2^DBL_MANT_BIT), and the
@@ -1179,7 +1407,7 @@ decode_double (double x, int *ep, mpn_t *mp)
}
# endif
# endif
- for (i = DBL_MANT_BIT / GMP_LIMB_BITS; i > 0; )
+ for (size_t i = DBL_MANT_BIT / GMP_LIMB_BITS; i > 0; )
{
mp_limb_t hi, lo;
y *= (mp_limb_t) 1 << (GMP_LIMB_BITS / 2);
@@ -1214,24 +1442,11 @@ decode_double (double x, int *ep, mpn_t *mp)
static char *
scale10_round_decimal_decoded (int e, mpn_t m, void *memory, int n)
{
- int s;
- size_t extra_zeroes;
- unsigned int abs_n;
- unsigned int abs_s;
- mp_limb_t *pow5_ptr;
- size_t pow5_len;
- unsigned int s_limbs;
- unsigned int s_bits;
- mpn_t pow5;
- mpn_t z;
- void *z_memory;
- char *digits;
-
/* x = 2^e * m, hence
y = round (2^e * 10^n * m) = round (2^(e+n) * 5^n * m)
= round (2^s * 5^n * m). */
- s = e + n;
- extra_zeroes = 0;
+ int s = e + n;
+ size_t extra_zeroes = 0;
/* Factor out a common power of 10 if possible. */
if (s > 0 && n > 0)
{
@@ -1244,11 +1459,12 @@ scale10_round_decimal_decoded (int e, mpn_t m, void *memory, int n)
z = round (2^s * 5^n * m). */
/* Compute 5^|n|, possibly shifted by |s| bits if n and s have the same
sign. 2.322 is slightly larger than log(5)/log(2). */
- abs_n = (n >= 0 ? n : -n);
- abs_s = (s >= 0 ? s : -s);
- pow5_ptr = (mp_limb_t *) malloc (((int)(abs_n * (2.322f / GMP_LIMB_BITS)) + 1
- + abs_s / GMP_LIMB_BITS + 1)
- * sizeof (mp_limb_t));
+ unsigned int abs_n = (n >= 0 ? n : -n);
+ unsigned int abs_s = (s >= 0 ? s : -s);
+ mp_limb_t *pow5_ptr =
+ (mp_limb_t *) malloc (((int)(abs_n * (2.322f / GMP_LIMB_BITS)) + 1
+ + abs_s / GMP_LIMB_BITS + 1)
+ * sizeof (mp_limb_t));
if (pow5_ptr == NULL)
{
free (memory);
@@ -1256,7 +1472,7 @@ scale10_round_decimal_decoded (int e, mpn_t m, void *memory, int n)
}
/* Initialize with 1. */
pow5_ptr[0] = 1;
- pow5_len = 1;
+ size_t pow5_len = 1;
/* Multiply with 5^|n|. */
if (abs_n > 0)
{
@@ -1265,13 +1481,11 @@ scale10_round_decimal_decoded (int e, mpn_t m, void *memory, int n)
1, 5, 25, 125, 625, 3125, 15625, 78125, 390625, 1953125, 9765625,
48828125, 244140625, 1220703125
};
- unsigned int n13;
- for (n13 = 0; n13 <= abs_n; n13 += 13)
+ for (unsigned int n13 = 0; n13 <= abs_n; n13 += 13)
{
mp_limb_t digit1 = small_pow5[n13 + 13 <= abs_n ? 13 : abs_n - n13];
- size_t j;
mp_twolimb_t carry = 0;
- for (j = 0; j < pow5_len; j++)
+ for (size_t j = 0; j < pow5_len; j++)
{
mp_limb_t digit2 = pow5_ptr[j];
carry += (mp_twolimb_t) digit1 * (mp_twolimb_t) digit2;
@@ -1282,8 +1496,11 @@ scale10_round_decimal_decoded (int e, mpn_t m, void *memory, int n)
pow5_ptr[pow5_len++] = (mp_limb_t) carry;
}
}
- s_limbs = abs_s / GMP_LIMB_BITS;
- s_bits = abs_s % GMP_LIMB_BITS;
+ unsigned int s_limbs = abs_s / GMP_LIMB_BITS;
+ unsigned int s_bits = abs_s % GMP_LIMB_BITS;
+ mpn_t pow5;
+ mpn_t z;
+ void *z_memory;
if (n >= 0 ? s >= 0 : s <= 0)
{
/* Multiply with 2^|s|. */
@@ -1291,8 +1508,7 @@ scale10_round_decimal_decoded (int e, mpn_t m, void *memory, int n)
{
mp_limb_t *ptr = pow5_ptr;
mp_twolimb_t accu = 0;
- size_t count;
- for (count = pow5_len; count > 0; count--)
+ for (size_t count = pow5_len; count > 0; count--)
{
accu += (mp_twolimb_t) *ptr << s_bits;
*ptr++ = (mp_limb_t) accu;
@@ -1306,13 +1522,12 @@ scale10_round_decimal_decoded (int e, mpn_t m, void *memory, int n)
}
if (s_limbs > 0)
{
- size_t count;
- for (count = pow5_len; count > 0;)
+ for (size_t count = pow5_len; count > 0;)
{
count--;
pow5_ptr[s_limbs + count] = pow5_ptr[count];
}
- for (count = s_limbs; count > 0;)
+ for (size_t count = s_limbs; count > 0;)
{
count--;
pow5_ptr[count] = 0;
@@ -1353,8 +1568,7 @@ scale10_round_decimal_decoded (int e, mpn_t m, void *memory, int n)
/* Construct 2^|s|. */
{
mp_limb_t *ptr = pow5_ptr + pow5_len;
- size_t i;
- for (i = 0; i < s_limbs; i++)
+ for (size_t i = 0; i < s_limbs; i++)
ptr[i] = 0;
ptr[s_limbs] = (mp_limb_t) 1 << s_bits;
denominator.limbs = ptr;
@@ -1379,17 +1593,13 @@ scale10_round_decimal_decoded (int e, mpn_t m, void *memory, int n)
}
{
mp_limb_t *destptr = num_ptr;
- {
- size_t i;
- for (i = 0; i < s_limbs; i++)
- *destptr++ = 0;
- }
+ for (size_t i = 0; i < s_limbs; i++)
+ *destptr++ = 0;
if (s_bits > 0)
{
const mp_limb_t *sourceptr = m.limbs;
mp_twolimb_t accu = 0;
- size_t count;
- for (count = m.nlimbs; count > 0; count--)
+ for (size_t count = m.nlimbs; count > 0; count--)
{
accu += (mp_twolimb_t) *sourceptr++ << s_bits;
*destptr++ = (mp_limb_t) accu;
@@ -1401,8 +1611,7 @@ scale10_round_decimal_decoded (int e, mpn_t m, void *memory, int n)
else
{
const mp_limb_t *sourceptr = m.limbs;
- size_t count;
- for (count = m.nlimbs; count > 0; count--)
+ for (size_t count = m.nlimbs; count > 0; count--)
*destptr++ = *sourceptr++;
}
numerator.limbs = num_ptr;
@@ -1419,7 +1628,7 @@ scale10_round_decimal_decoded (int e, mpn_t m, void *memory, int n)
if (z_memory == NOMEM_PTR)
return NULL;
- digits = convert_to_decimal (z, extra_zeroes);
+ char *digits = convert_to_decimal (z, extra_zeroes);
free (z_memory);
return digits;
}
@@ -1474,13 +1683,9 @@ scale10_round_decimal_double (double x, int n)
static int
floorlog10l (long double x)
{
- int exp;
- long double y;
- double z;
- double l;
-
/* Split into exponential part and mantissa. */
- y = safe_frexpl (x, &exp);
+ int exp;
+ long double y = safe_frexpl (x, &exp);
if (!(y >= 0.0L && y < 1.0L))
abort ();
if (y == 0.0L)
@@ -1521,8 +1726,8 @@ floorlog10l (long double x)
if (!(y >= 0.5L && y < 1.0L))
abort ();
/* Compute an approximation for l = log2(x) = exp + log2(y). */
- l = exp;
- z = y;
+ double l = exp;
+ double z = y;
if (z < 0.70710678118654752444)
{
z *= 1.4142135623730950488;
@@ -1565,13 +1770,9 @@ floorlog10l (long double x)
static int
floorlog10 (double x)
{
- int exp;
- double y;
- double z;
- double l;
-
/* Split into exponential part and mantissa. */
- y = frexp (x, &exp);
+ int exp;
+ double y = frexp (x, &exp);
if (!(y >= 0.0 && y < 1.0))
abort ();
if (y == 0.0)
@@ -1612,8 +1813,8 @@ floorlog10 (double x)
if (!(y >= 0.5 && y < 1.0))
abort ();
/* Compute an approximation for l = log2(x) = exp + log2(y). */
- l = exp;
- z = y;
+ double l = exp;
+ double z = y;
if (z < 0.70710678118654752444)
{
z *= 1.4142135623730950488;
@@ -1839,8 +2040,17 @@ MAX_ROOM_NEEDED (const arguments *ap, size_t arg_index, FCHAR_T conversion,
}
if (tmp_length < precision)
tmp_length = precision;
- /* Multiply by 2, as an estimate for FLAG_GROUP. */
- tmp_length = xsum (tmp_length, tmp_length);
+ /* Account for thousands separators. */
+ if (flags & FLAG_GROUP)
+ {
+ /* A thousands separator needs to be inserted at most every 2 digits.
+ This is the case in the ta_IN locale. */
+# if WIDE_CHAR_VERSION
+ tmp_length = xsum (tmp_length, tmp_length / 2 * THOUSEP_WCHAR_MAXLEN);
+# else
+ tmp_length = xsum (tmp_length, tmp_length / 2 * THOUSEP_CHAR_MAXLEN);
+# endif
+ }
/* Add 1, to account for a leading sign. */
tmp_length = xsum (tmp_length, 1);
break;
@@ -2088,12 +2298,18 @@ MAX_ROOM_NEEDED (const arguments *ap, size_t arg_index, FCHAR_T conversion,
tmp_length = xsum (tmp_length, 2);
break;
+ case 'e': case 'E':
+ tmp_length =
+ 12; /* sign, decimal point, exponent etc. */
+ tmp_length = xsum (tmp_length, precision);
+ break;
+
case 'f': case 'F':
if (type == TYPE_LONGDOUBLE)
tmp_length =
(unsigned int) (LDBL_MAX_EXP
* 0.30103 /* binary -> decimal */
- * 2 /* estimate for FLAG_GROUP */
+ * 0.5 * 3 /* estimate for FLAG_GROUP */
)
+ 1 /* turn floor into ceil */
+ 10; /* sign, decimal point etc. */
@@ -2101,17 +2317,20 @@ MAX_ROOM_NEEDED (const arguments *ap, size_t arg_index, FCHAR_T conversion,
tmp_length =
(unsigned int) (DBL_MAX_EXP
* 0.30103 /* binary -> decimal */
- * 2 /* estimate for FLAG_GROUP */
+ * 0.5 * 3 /* estimate for FLAG_GROUP */
)
+ 1 /* turn floor into ceil */
+ 10; /* sign, decimal point etc. */
tmp_length = xsum (tmp_length, precision);
break;
- case 'e': case 'E': case 'g': case 'G':
+ case 'g': case 'G':
tmp_length =
12; /* sign, decimal point, exponent etc. */
- tmp_length = xsum (tmp_length, precision);
+ tmp_length = xsum (tmp_length,
+ precision
+ * 0.5 * 3 /* estimate for FLAG_GROUP */
+ );
break;
case 'a': case 'A':
@@ -2258,21 +2477,12 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
goto fail_1_with_EINVAL;
{
- size_t buf_neededlength;
- TCHAR_T *buf;
- TCHAR_T *buf_malloced;
- const FCHAR_T *cp;
- size_t i;
- DIRECTIVE *dp;
- /* Output string accumulator. */
- DCHAR_T *result;
- size_t allocated;
- size_t length;
-
/* Allocate a small buffer that will hold a directive passed to
sprintf or snprintf. */
- buf_neededlength =
+ size_t buf_neededlength =
xsum4 (7, d.max_width_length, d.max_precision_length, 6);
+ TCHAR_T *buf;
+ TCHAR_T *buf_malloced;
#if HAVE_ALLOCA
if (buf_neededlength < 4000 / sizeof (TCHAR_T))
{
@@ -2291,9 +2501,11 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
buf_malloced = buf;
}
- result = resultbuf;
- allocated = (resultbuf != NULL ? *lengthp : 0);
- length = 0;
+ /* Output string accumulator. */
+ DCHAR_T *result = resultbuf;
+ size_t allocated = (resultbuf != NULL ? *lengthp : 0);
+ size_t length = 0;
+
/* Invariants:
result is either == resultbuf or malloc-allocated.
If result == NULL, resultbuf is == NULL as well.
@@ -2304,15 +2516,13 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
#define ENSURE_ALLOCATION_ELSE(needed, oom_statement) \
if ((needed) > allocated) \
{ \
- size_t memory_size; \
- DCHAR_T *memory; \
- \
allocated = (allocated > 0 ? xtimes (allocated, 2) : 12); \
if ((needed) > allocated) \
allocated = (needed); \
- memory_size = xtimes (allocated, sizeof (DCHAR_T)); \
+ size_t memory_size = xtimes (allocated, sizeof (DCHAR_T)); \
if (size_overflow_p (memory_size)) \
oom_statement \
+ DCHAR_T *memory; \
if (result == resultbuf) \
memory = (DCHAR_T *) malloc (memory_size); \
else \
@@ -2326,7 +2536,10 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
#define ENSURE_ALLOCATION(needed) \
ENSURE_ALLOCATION_ELSE((needed), goto out_of_memory; )
- for (cp = format, i = 0, dp = &d.dir[0]; ; cp = dp->dir_end, i++, dp++)
+ const FCHAR_T *cp;
+ size_t di;
+ DIRECTIVE *dp;
+ for (cp = format, di = 0, dp = &d.dir[0]; ; cp = dp->dir_end, di++, dp++)
{
if (cp != dp->dir_start)
{
@@ -2349,7 +2562,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
while (--n > 0);
}
}
- if (i == d.count)
+ if (di == d.count)
break;
/* Execute a single directive. */
@@ -2426,22 +2639,16 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
{
arg_type type = a.arg[dp->arg_index].type;
int flags = dp->flags;
- int has_width;
- size_t width;
- int has_precision;
- size_t precision;
- has_width = 0;
- width = 0;
+ int has_width = 0;
+ size_t width = 0;
if (dp->width_start != dp->width_end)
{
if (dp->width_arg_index != ARG_NONE)
{
- int arg;
-
if (!(a.arg[dp->width_arg_index].type == TYPE_INT))
abort ();
- arg = a.arg[dp->width_arg_index].a.a_int;
+ int arg = a.arg[dp->width_arg_index].a.a_int;
width = arg;
if (arg < 0)
{
@@ -2464,17 +2671,15 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
has_width = 1;
}
- has_precision = 0;
- precision = 0;
+ int has_precision = 0;
+ size_t precision = 0;
if (dp->precision_start != dp->precision_end)
{
if (dp->precision_arg_index != ARG_NONE)
{
- int arg;
-
if (!(a.arg[dp->precision_arg_index].type == TYPE_INT))
abort ();
- arg = a.arg[dp->precision_arg_index].a.a_int;
+ int arg = a.arg[dp->precision_arg_index].a.a_int;
/* "A negative precision is taken as if the precision
were omitted." */
if (arg >= 0)
@@ -2819,22 +3024,16 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
than INT_MAX characters, whence snprintf or sprintf would
fail to process it. */
int flags = dp->flags;
- int has_width;
- size_t width;
- int has_precision;
- size_t precision;
- has_width = 0;
- width = 0;
+ int has_width = 0;
+ size_t width = 0;
if (dp->width_start != dp->width_end)
{
if (dp->width_arg_index != ARG_NONE)
{
- int arg;
-
if (!(a.arg[dp->width_arg_index].type == TYPE_INT))
abort ();
- arg = a.arg[dp->width_arg_index].a.a_int;
+ int arg = a.arg[dp->width_arg_index].a.a_int;
width = arg;
if (arg < 0)
{
@@ -2857,17 +3056,15 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
has_width = 1;
}
- has_precision = 0;
- precision = 6;
+ int has_precision = 0;
+ size_t precision = 6;
if (dp->precision_start != dp->precision_end)
{
if (dp->precision_arg_index != ARG_NONE)
{
- int arg;
-
if (!(a.arg[dp->precision_arg_index].type == TYPE_INT))
abort ();
- arg = a.arg[dp->precision_arg_index].a.a_int;
+ int arg = a.arg[dp->precision_arg_index].a.a_int;
/* "A negative precision is taken as if the precision
were omitted." */
if (arg >= 0)
@@ -2889,18 +3086,8 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
{
const char *arg = a.arg[dp->arg_index].a.a_string;
- size_t bytes;
-# if ENABLE_UNISTDIO && DCHAR_IS_TCHAR
- size_t characters;
-# endif
-# if !DCHAR_IS_TCHAR
- /* This code assumes that TCHAR_T is 'char'. */
- static_assert (sizeof (TCHAR_T) == 1);
- DCHAR_T *tmpdst;
- size_t tmpdst_len;
-# endif
- size_t w;
+ size_t bytes;
if (has_precision)
{
/* Use only at most PRECISION bytes, from the left. */
@@ -2914,6 +3101,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
}
# if ENABLE_UNISTDIO && DCHAR_IS_TCHAR
+ size_t characters;
if (has_width)
characters = mbsnlen (arg, bytes);
else
@@ -2925,6 +3113,10 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
# endif
# if !DCHAR_IS_TCHAR
+ /* This code assumes that TCHAR_T is 'char'. */
+ static_assert (sizeof (TCHAR_T) == 1);
+ DCHAR_T *tmpdst;
+ size_t tmpdst_len;
/* Convert from TCHAR_T[] to DCHAR_T[]. */
tmpdst =
DCHAR_CONV_FROM_ENCODING (locale_charset (),
@@ -2936,6 +3128,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
goto fail_with_errno;
# endif
+ size_t w;
if (has_width)
{
# if ENABLE_UNISTDIO
@@ -3005,18 +3198,15 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
convert back the result from a char[] to a wchar_t[].
Instead, just copy the argument wchar_t[] to the result. */
int flags = dp->flags;
- size_t width;
- width = 0;
+ size_t width = 0;
if (dp->width_start != dp->width_end)
{
if (dp->width_arg_index != ARG_NONE)
{
- int arg;
-
if (!(a.arg[dp->width_arg_index].type == TYPE_INT))
abort ();
- arg = a.arg[dp->width_arg_index].a.a_int;
+ int arg = a.arg[dp->width_arg_index].a.a_int;
width = arg;
if (arg < 0)
{
@@ -3045,20 +3235,15 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
if (dp->conversion == 's')
{
- int has_precision;
- size_t precision;
-
- has_precision = 0;
- precision = 6;
+ int has_precision = 0;
+ size_t precision = 6;
if (dp->precision_start != dp->precision_end)
{
if (dp->precision_arg_index != ARG_NONE)
{
- int arg;
-
if (!(a.arg[dp->precision_arg_index].type == TYPE_INT))
abort ();
- arg = a.arg[dp->precision_arg_index].a.a_int;
+ int arg = a.arg[dp->precision_arg_index].a.a_int;
/* "A negative precision is taken as if the precision
were omitted." */
if (arg >= 0)
@@ -3084,9 +3269,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
{
/* Use only at most PRECISION wide characters, from
the left. */
- const wchar_t *ls_arg_end;
-
- ls_arg_end = ls_arg;
+ const wchar_t *ls_arg_end = ls_arg;
characters = 0;
for (; precision > 0; precision--)
{
@@ -3158,22 +3341,16 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
such bugs, we implement the entire processing of the 's'
directive ourselves. */
int flags = dp->flags;
- int has_width;
- size_t width;
- int has_precision;
- size_t precision;
- has_width = 0;
- width = 0;
+ int has_width = 0;
+ size_t width = 0;
if (dp->width_start != dp->width_end)
{
if (dp->width_arg_index != ARG_NONE)
{
- int arg;
-
if (!(a.arg[dp->width_arg_index].type == TYPE_INT))
abort ();
- arg = a.arg[dp->width_arg_index].a.a_int;
+ int arg = a.arg[dp->width_arg_index].a.a_int;
width = arg;
if (arg < 0)
{
@@ -3196,17 +3373,15 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
has_width = 1;
}
- has_precision = 0;
- precision = 6;
+ int has_precision = 0;
+ size_t precision = 6;
if (dp->precision_start != dp->precision_end)
{
if (dp->precision_arg_index != ARG_NONE)
{
- int arg;
-
if (!(a.arg[dp->precision_arg_index].type == TYPE_INT))
abort ();
- arg = a.arg[dp->precision_arg_index].a.a_int;
+ int arg = a.arg[dp->precision_arg_index].a.a_int;
/* "A negative precision is taken as if the precision
were omitted." */
if (arg >= 0)
@@ -3308,13 +3483,12 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
if (has_precision || has_width)
{
/* We know the number of wide characters in advance. */
- size_t remaining;
# if HAVE_MBRTOWC
mbstate_t state;
mbszero (&state);
# endif
ENSURE_ALLOCATION (xsum (length, characters));
- for (remaining = characters; remaining > 0; remaining--)
+ for (size_t remaining = characters; remaining > 0; remaining--)
{
wchar_t wc;
int count;
@@ -3400,13 +3574,11 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
# endif
while (precision > 0)
{
- char cbuf[64]; /* Assume MB_CUR_MAX <= 64. */
- int count;
-
if (*arg_end == 0)
/* Found the terminating null wide character. */
break;
- count = local_wcrtomb (cbuf, *arg_end, &state);
+ char cbuf[64]; /* Assume MB_CUR_MAX <= 64. */
+ int count = local_wcrtomb (cbuf, *arg_end, &state);
if (count < 0)
/* Cannot convert. */
goto fail_with_EILSEQ;
@@ -3439,13 +3611,11 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
# endif
for (;;)
{
- char cbuf[64]; /* Assume MB_CUR_MAX <= 64. */
- int count;
-
if (*arg_end == 0)
/* Found the terminating null wide character. */
break;
- count = local_wcrtomb (cbuf, *arg_end, &state);
+ char cbuf[64]; /* Assume MB_CUR_MAX <= 64. */
+ int count = local_wcrtomb (cbuf, *arg_end, &state);
if (count < 0)
/* Cannot convert. */
goto fail_with_EILSEQ;
@@ -3472,27 +3642,22 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
# if !DCHAR_IS_TCHAR
{
- TCHAR_T *tmpsrc;
-
/* Convert the string into a piece of temporary memory. */
- tmpsrc = (TCHAR_T *) malloc (bytes * sizeof (TCHAR_T));
+ TCHAR_T *tmpsrc = (TCHAR_T *) malloc (bytes * sizeof (TCHAR_T));
if (tmpsrc == NULL)
goto out_of_memory;
{
TCHAR_T *tmpptr = tmpsrc;
- size_t remaining;
# if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t
mbstate_t state;
mbszero (&state);
# endif
- for (remaining = bytes; remaining > 0; )
+ for (size_t remaining = bytes; remaining > 0; )
{
- char cbuf[64]; /* Assume MB_CUR_MAX <= 64. */
- int count;
-
if (*arg == 0)
abort ();
- count = local_wcrtomb (cbuf, *arg, &state);
+ char cbuf[64]; /* Assume MB_CUR_MAX <= 64. */
+ int count = local_wcrtomb (cbuf, *arg, &state);
if (count <= 0)
/* Inconsistency. */
abort ();
@@ -3559,20 +3724,17 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
if (has_precision || has_width)
{
/* We know the number of bytes in advance. */
- size_t remaining;
# if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t
mbstate_t state;
mbszero (&state);
# endif
ENSURE_ALLOCATION (xsum (length, bytes));
- for (remaining = bytes; remaining > 0; )
+ for (size_t remaining = bytes; remaining > 0; )
{
- char cbuf[64]; /* Assume MB_CUR_MAX <= 64. */
- int count;
-
if (*arg == 0)
abort ();
- count = local_wcrtomb (cbuf, *arg, &state);
+ char cbuf[64]; /* Assume MB_CUR_MAX <= 64. */
+ int count = local_wcrtomb (cbuf, *arg, &state);
if (count <= 0)
/* Inconsistency. */
abort ();
@@ -3592,12 +3754,10 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
# endif
while (arg < arg_end)
{
- char cbuf[64]; /* Assume MB_CUR_MAX <= 64. */
- int count;
-
if (*arg == 0)
abort ();
- count = local_wcrtomb (cbuf, *arg, &state);
+ char cbuf[64]; /* Assume MB_CUR_MAX <= 64. */
+ int count = local_wcrtomb (cbuf, *arg, &state);
if (count <= 0)
/* Cannot convert. */
goto fail_with_EILSEQ;
@@ -3634,20 +3794,16 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
a correct behaviour for the null wint_t argument and/or the
fallback that avoids EILSEQ. */
int flags = dp->flags;
- int has_width;
- size_t width;
- has_width = 0;
- width = 0;
+ int has_width = 0;
+ size_t width = 0;
if (dp->width_start != dp->width_end)
{
if (dp->width_arg_index != ARG_NONE)
{
- int arg;
-
if (!(a.arg[dp->width_arg_index].type == TYPE_INT))
abort ();
- arg = a.arg[dp->width_arg_index].a.a_int;
+ int arg = a.arg[dp->width_arg_index].a.a_int;
width = arg;
if (arg < 0)
{
@@ -3690,14 +3846,13 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
# endif
{
/* Count the number of bytes. */
- char cbuf[64]; /* Assume MB_CUR_MAX <= 64. */
- int count;
# if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t
mbstate_t state;
mbszero (&state);
# endif
- count = local_wcrtomb (cbuf, arg, &state);
+ char cbuf[64]; /* Assume MB_CUR_MAX <= 64. */
+ int count = local_wcrtomb (cbuf, arg, &state);
if (count < 0)
/* Cannot convert. */
goto fail_with_EILSEQ;
@@ -3725,14 +3880,13 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
/* Convert the string into a piece of temporary memory. */
if (bytes > 0)
{
- char cbuf[64]; /* Assume MB_CUR_MAX <= 64. */
- int count;
# if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t
mbstate_t state;
mbszero (&state);
# endif
- count = local_wcrtomb (cbuf, arg, &state);
+ char cbuf[64]; /* Assume MB_CUR_MAX <= 64. */
+ int count = local_wcrtomb (cbuf, arg, &state);
if (count <= 0)
/* Inconsistency. */
abort ();
@@ -3792,13 +3946,12 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
ENSURE_ALLOCATION (xsum (length, bytes));
if (bytes > 0)
{
- int count;
# if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t
mbstate_t state;
mbszero (&state);
# endif
- count = local_wcrtomb (result + length, arg, &state);
+ int count = local_wcrtomb (result + length, arg, &state);
if (count <= 0)
/* Inconsistency. */
abort ();
@@ -3807,14 +3960,13 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
}
else
{
- char cbuf[64]; /* Assume MB_CUR_MAX <= 64. */
- int count;
# if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t
mbstate_t state;
mbszero (&state);
# endif
- count = local_wcrtomb (cbuf, arg, &state);
+ char cbuf[64]; /* Assume MB_CUR_MAX <= 64. */
+ int count = local_wcrtomb (cbuf, arg, &state);
if (count < 0)
/* Cannot convert. */
goto fail_with_EILSEQ;
@@ -3847,18 +3999,15 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
/* Implement the 'c' directive ourselves, in order to avoid
EILSEQ in the "C" locale. */
int flags = dp->flags;
- size_t width;
- width = 0;
+ size_t width = 0;
if (dp->width_start != dp->width_end)
{
if (dp->width_arg_index != ARG_NONE)
{
- int arg;
-
if (!(a.arg[dp->width_arg_index].type == TYPE_INT))
abort ();
- arg = a.arg[dp->width_arg_index].a.a_int;
+ int arg = a.arg[dp->width_arg_index].a.a_int;
width = arg;
if (arg < 0)
{
@@ -3884,9 +4033,9 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
{
char arg = (char) a.arg[dp->arg_index].a.a_char;
mbstate_t state;
- wchar_t wc;
-
mbszero (&state);
+
+ wchar_t wc;
int count = mbrtowc (&wc, &arg, 1, &state);
if (count < 0)
/* Invalid or incomplete multibyte character. */
@@ -3927,30 +4076,16 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
{
arg_type type = a.arg[dp->arg_index].type;
int flags = dp->flags;
- int has_width;
- size_t width;
- int has_precision;
- size_t precision;
- size_t tmp_length;
- size_t count;
- DCHAR_T tmpbuf[700];
- DCHAR_T *tmp;
- DCHAR_T *tmp_end;
- DCHAR_T *tmp_start;
- DCHAR_T *pad_ptr;
- DCHAR_T *p;
- has_width = 0;
- width = 0;
+ int has_width = 0;
+ size_t width = 0;
if (dp->width_start != dp->width_end)
{
if (dp->width_arg_index != ARG_NONE)
{
- int arg;
-
if (!(a.arg[dp->width_arg_index].type == TYPE_INT))
abort ();
- arg = a.arg[dp->width_arg_index].a.a_int;
+ int arg = a.arg[dp->width_arg_index].a.a_int;
width = arg;
if (arg < 0)
{
@@ -3973,17 +4108,15 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
has_width = 1;
}
- has_precision = 0;
- precision = 1;
+ int has_precision = 0;
+ size_t precision = 1;
if (dp->precision_start != dp->precision_end)
{
if (dp->precision_arg_index != ARG_NONE)
{
- int arg;
-
if (!(a.arg[dp->precision_arg_index].type == TYPE_INT))
abort ();
- arg = a.arg[dp->precision_arg_index].a.a_int;
+ int arg = a.arg[dp->precision_arg_index].a.a_int;
/* "A negative precision is taken as if the precision
were omitted." */
if (arg >= 0)
@@ -4004,6 +4137,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
}
/* Allocate a temporary buffer of sufficient size. */
+ size_t tmp_length;
switch (type)
{
default:
@@ -4070,6 +4204,8 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
if (tmp_length < width)
tmp_length = width;
+ DCHAR_T tmpbuf[700];
+ DCHAR_T *tmp;
if (tmp_length <= sizeof (tmpbuf) / sizeof (DCHAR_T))
tmp = tmpbuf;
else
@@ -4085,7 +4221,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
goto out_of_memory;
}
- tmp_end = tmp + tmp_length;
+ DCHAR_T *tmp_end = tmp + tmp_length;
unsigned long long arg;
switch (type)
@@ -4134,7 +4270,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
}
int need_prefix = ((flags & FLAG_ALT) && arg != 0);
- p = tmp_end;
+ DCHAR_T *p = tmp_end;
/* "The result of converting a zero value with a precision
of zero is no characters." */
if (!(has_precision && precision == 0 && arg == 0))
@@ -4154,7 +4290,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
*--p = '0';
}
- pad_ptr = p;
+ DCHAR_T *pad_ptr = p;
if (need_prefix)
{
@@ -4167,12 +4303,12 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
# endif
*--p = '0';
}
- tmp_start = p;
+ DCHAR_T *tmp_start = p;
/* The generated string now extends from tmp_start to tmp_end,
with the zero padding insertion point being at pad_ptr,
tmp_start <= pad_ptr <= tmp_end. */
- count = tmp_end - tmp_start;
+ size_t count = tmp_end - tmp_start;
if (count < width)
{
@@ -4248,26 +4384,15 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
{
arg_type type = a.arg[dp->arg_index].type;
int flags = dp->flags;
- size_t width;
- int has_precision;
- size_t precision;
- size_t tmp_length;
- size_t count;
- DCHAR_T tmpbuf[700];
- DCHAR_T *tmp;
- DCHAR_T *pad_ptr;
- DCHAR_T *p;
- width = 0;
+ size_t width = 0;
if (dp->width_start != dp->width_end)
{
if (dp->width_arg_index != ARG_NONE)
{
- int arg;
-
if (!(a.arg[dp->width_arg_index].type == TYPE_INT))
abort ();
- arg = a.arg[dp->width_arg_index].a.a_int;
+ int arg = a.arg[dp->width_arg_index].a.a_int;
width = arg;
if (arg < 0)
{
@@ -4289,17 +4414,15 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
goto overflow;
}
- has_precision = 0;
- precision = 0;
+ int has_precision = 0;
+ size_t precision = 0;
if (dp->precision_start != dp->precision_end)
{
if (dp->precision_arg_index != ARG_NONE)
{
- int arg;
-
if (!(a.arg[dp->precision_arg_index].type == TYPE_INT))
abort ();
- arg = a.arg[dp->precision_arg_index].a.a_int;
+ int arg = a.arg[dp->precision_arg_index].a.a_int;
/* "A negative precision is taken as if the precision
were omitted." */
if (arg >= 0)
@@ -4320,6 +4443,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
}
/* Allocate a temporary buffer of sufficient size. */
+ size_t tmp_length;
if (type == TYPE_LONGDOUBLE)
tmp_length =
(unsigned int) ((LDBL_DIG + 1)
@@ -4342,6 +4466,8 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
tmp_length = xsum (tmp_length, 1); /* account for trailing NUL */
+ DCHAR_T tmpbuf[700];
+ DCHAR_T *tmp;
if (tmp_length <= sizeof (tmpbuf) / sizeof (DCHAR_T))
tmp = tmpbuf;
else
@@ -4357,8 +4483,8 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
goto out_of_memory;
}
- pad_ptr = NULL;
- p = tmp;
+ DCHAR_T *pad_ptr = NULL;
+ DCHAR_T *p = tmp;
if (type == TYPE_LONGDOUBLE)
{
# if NEED_PRINTF_DIRECTIVE_A || NEED_PRINTF_LONG_DOUBLE || (NEED_WPRINTF_DIRECTIVE_LA && WIDE_CHAR_VERSION)
@@ -4377,11 +4503,11 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
}
else
{
- int sign = 0;
DECL_LONG_DOUBLE_ROUNDING
BEGIN_LONG_DOUBLE_ROUNDING ();
+ int sign = 0;
if (signbit (arg)) /* arg < 0.0L or negative zero */
{
sign = -1;
@@ -4410,7 +4536,6 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
{
int exponent;
long double mantissa;
-
if (arg > 0.0L)
mantissa = printf_frexpl (arg, &exponent);
else
@@ -4424,9 +4549,8 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
{
/* Round the mantissa. */
long double tail = mantissa;
- size_t q;
- for (q = precision; ; q--)
+ for (size_t q = precision; ; q--)
{
int digit = (int) tail;
tail -= digit;
@@ -4441,7 +4565,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
tail *= 16.0L;
}
if (tail != 0.0L)
- for (q = precision; q > 0; q--)
+ for (size_t q = precision; q > 0; q--)
tail *= 0.0625L;
mantissa += tail;
}
@@ -4450,9 +4574,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
*p++ = dp->conversion - 'A' + 'X';
pad_ptr = p;
{
- int digit;
-
- digit = (int) mantissa;
+ int digit = (int) mantissa;
mantissa -= digit;
*p++ = '0' + digit;
if ((flags & FLAG_ALT)
@@ -4499,9 +4621,8 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
else
{
char expbuf[6 + 1];
- const char *ep;
sprintf (expbuf, "%+d", exponent);
- for (ep = expbuf; (*p = *ep) != '\0'; ep++)
+ for (const char *ep = expbuf; (*p = *ep) != '\0'; ep++)
p++;
}
# endif
@@ -4532,7 +4653,6 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
else
{
int sign = 0;
-
if (signbit (arg)) /* arg < 0.0 or negative zero */
{
sign = -1;
@@ -4561,7 +4681,6 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
{
int exponent;
double mantissa;
-
if (arg > 0.0)
mantissa = printf_frexp (arg, &exponent);
else
@@ -4575,9 +4694,8 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
{
/* Round the mantissa. */
double tail = mantissa;
- size_t q;
- for (q = precision; ; q--)
+ for (size_t q = precision; ; q--)
{
int digit = (int) tail;
tail -= digit;
@@ -4592,7 +4710,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
tail *= 16.0;
}
if (tail != 0.0)
- for (q = precision; q > 0; q--)
+ for (size_t q = precision; q > 0; q--)
tail *= 0.0625;
mantissa += tail;
}
@@ -4601,9 +4719,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
*p++ = dp->conversion - 'A' + 'X';
pad_ptr = p;
{
- int digit;
-
- digit = (int) mantissa;
+ int digit = (int) mantissa;
mantissa -= digit;
*p++ = '0' + digit;
if ((flags & FLAG_ALT)
@@ -4650,9 +4766,8 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
else
{
char expbuf[6 + 1];
- const char *ep;
sprintf (expbuf, "%+d", exponent);
- for (ep = expbuf; (*p = *ep) != '\0'; ep++)
+ for (const char *ep = expbuf; (*p = *ep) != '\0'; ep++)
p++;
}
# endif
@@ -4665,7 +4780,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
/* The generated string now extends from tmp to p, with the
zero padding insertion point being at pad_ptr. */
- count = p - tmp;
+ size_t count = p - tmp;
if (count < width)
{
@@ -4746,8 +4861,8 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
|| (a.arg[dp->arg_index].type == TYPE_LONGDOUBLE
/* Some systems produce wrong output for Inf,
-Inf, and NaN. Some systems in this category
- (IRIX 5.3) also do so for -0.0. Therefore we
- treat this case here as well. */
+ also do so for -0.0. Therefore we treat this
+ case here as well. */
&& is_infinite_or_zerol (a.arg[dp->arg_index].a.a_longdouble))
# endif
))
@@ -4756,26 +4871,15 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
arg_type type = a.arg[dp->arg_index].type;
# endif
int flags = dp->flags;
- size_t width;
- size_t count;
- int has_precision;
- size_t precision;
- size_t tmp_length;
- DCHAR_T tmpbuf[700];
- DCHAR_T *tmp;
- DCHAR_T *pad_ptr;
- DCHAR_T *p;
- width = 0;
+ size_t width = 0;
if (dp->width_start != dp->width_end)
{
if (dp->width_arg_index != ARG_NONE)
{
- int arg;
-
if (!(a.arg[dp->width_arg_index].type == TYPE_INT))
abort ();
- arg = a.arg[dp->width_arg_index].a.a_int;
+ int arg = a.arg[dp->width_arg_index].a.a_int;
width = arg;
if (arg < 0)
{
@@ -4797,17 +4901,15 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
goto overflow;
}
- has_precision = 0;
- precision = 0;
+ int has_precision = 0;
+ size_t precision = 0;
if (dp->precision_start != dp->precision_end)
{
if (dp->precision_arg_index != ARG_NONE)
{
- int arg;
-
if (!(a.arg[dp->precision_arg_index].type == TYPE_INT))
abort ();
- arg = a.arg[dp->precision_arg_index].a.a_int;
+ int arg = a.arg[dp->precision_arg_index].a.a_int;
/* "A negative precision is taken as if the precision
were omitted." */
if (arg >= 0)
@@ -4836,6 +4938,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
precision = 6;
/* Allocate a temporary buffer of sufficient size. */
+ size_t tmp_length;
# if NEED_PRINTF_DOUBLE && NEED_PRINTF_LONG_DOUBLE
tmp_length = (type == TYPE_LONGDOUBLE ? LDBL_DIG + 1 : DBL_DIG + 1);
# elif NEED_PRINTF_INFINITE_DOUBLE && NEED_PRINTF_LONG_DOUBLE
@@ -4881,6 +4984,17 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
}
}
# endif
+ /* Account for thousands separators. */
+ if (flags & FLAG_GROUP)
+ {
+ /* A thousands separator needs to be inserted at most every 2 digits.
+ This is the case in the ta_IN locale. */
+# if WIDE_CHAR_VERSION
+ tmp_length = xsum (tmp_length, tmp_length / 2 * THOUSEP_WCHAR_MAXLEN);
+# else
+ tmp_length = xsum (tmp_length, tmp_length / 2 * THOUSEP_CHAR_MAXLEN);
+# endif
+ }
/* Account for sign, decimal point etc. */
tmp_length = xsum (tmp_length, 12);
@@ -4889,6 +5003,8 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
tmp_length = xsum (tmp_length, 1); /* account for trailing NUL */
+ DCHAR_T tmpbuf[700];
+ DCHAR_T *tmp;
if (tmp_length <= sizeof (tmpbuf) / sizeof (DCHAR_T))
tmp = tmpbuf;
else
@@ -4904,8 +5020,8 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
goto out_of_memory;
}
- pad_ptr = NULL;
- p = tmp;
+ DCHAR_T *pad_ptr = NULL;
+ DCHAR_T *p = tmp;
# if NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_INFINITE_LONG_DOUBLE
# if NEED_PRINTF_DOUBLE || NEED_PRINTF_INFINITE_DOUBLE
@@ -4927,11 +5043,11 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
}
else
{
- int sign = 0;
DECL_LONG_DOUBLE_ROUNDING
BEGIN_LONG_DOUBLE_ROUNDING ();
+ int sign = 0;
if (signbit (arg)) /* arg < 0.0L or negative zero */
{
sign = -1;
@@ -4963,25 +5079,94 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
if (dp->conversion == 'f' || dp->conversion == 'F')
{
- char *digits;
- size_t ndigits;
-
- digits =
+ char *digits =
scale10_round_decimal_long_double (arg, precision);
if (digits == NULL)
{
END_LONG_DOUBLE_ROUNDING ();
goto out_of_memory;
}
- ndigits = strlen (digits);
+ size_t ndigits = strlen (digits);
if (ndigits > precision)
- do
- {
- --ndigits;
- *p++ = digits[ndigits];
- }
- while (ndigits > precision);
+ {
+ /* Number of digits before the decimal point. */
+ size_t intpart_digits = ndigits - precision;
+
+ const DCHAR_T *thousep = NULL;
+ DCHAR_T thousep_buf[10];
+# if !WIDE_CHAR_VERSION
+ size_t thousep_len = 0;
+# endif
+ const signed char *grouping;
+ size_t insert = 0;
+
+ if ((flags & FLAG_GROUP) && (intpart_digits > 1))
+ {
+ /* Determine the thousands separator and
+ the grouping rule of the current locale. */
+# if WIDE_CHAR_VERSION
+ /* DCHAR_T is wchar_t. */
+ thousep = thousands_separator_wchar (thousep_buf);
+# define thousep_len 1
+# elif defined DCHAR_CONV_FROM_ENCODING
+ /* DCHAR_T is uintN_t. */
+ thousep = thousands_separator_DCHAR (thousep_buf);
+ thousep_len = DCHAR_STRLEN (thousep);
+# else
+ /* DCHAR_T is char. */
+ thousep = thousands_separator_char (thousep_buf);
+ thousep_len = strlen (thousep);
+# endif
+ if (*thousep == 0)
+ thousep = NULL;
+ if (thousep != NULL)
+ {
+ grouping = grouping_rule ();
+ insert =
+ num_thousands_separators (grouping, intpart_digits);
+ }
+ }
+
+ const char *digitp = digits + precision;
+ DCHAR_T *p_before_intpart = p;
+ p += intpart_digits + insert * thousep_len;
+ DCHAR_T *p_after_intpart = p;
+ if (insert > 0) /* implies (flag & FLAG_GROUP) && (thousep != NULL) */
+ {
+ const signed char *g = grouping;
+ for (;;)
+ {
+ int h = *g;
+ if (h <= 0)
+ abort ();
+ int i = h;
+ do
+ *--p = *digitp++;
+ while (--i > 0);
+# if WIDE_CHAR_VERSION
+ *--p = thousep[0];
+# else
+ p -= thousep_len;
+ DCHAR_CPY (p, thousep, thousep_len);
+# endif
+ insert--;
+ if (insert == 0)
+ break;
+ if (g[1] != 0)
+ g++;
+ }
+ }
+ for (;;)
+ {
+ *--p = *digitp++;
+ if (p == p_before_intpart)
+ break;
+ }
+ p = p_after_intpart;
+ ndigits = precision;
+# undef thousep_len
+ }
else
*p++ = '0';
/* Here ndigits <= precision. */
@@ -5017,12 +5202,10 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
else
{
/* arg > 0.0L. */
- int adjusted;
+ exponent = floorlog10l (arg);
+ int adjusted = 0;
char *digits;
size_t ndigits;
-
- exponent = floorlog10l (arg);
- adjusted = 0;
for (;;)
{
digits =
@@ -5113,9 +5296,8 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
else
{
char expbuf[6 + 1];
- const char *ep;
sprintf (expbuf, "%+.2d", exponent);
- for (ep = expbuf; (*p = *ep) != '\0'; ep++)
+ for (const char *ep = expbuf; (*p = *ep) != '\0'; ep++)
p++;
}
# endif
@@ -5151,14 +5333,10 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
else
{
/* arg > 0.0L. */
- int exponent;
- int adjusted;
+ int exponent = floorlog10l (arg);
+ int adjusted = 0;
char *digits;
size_t ndigits;
- size_t nzeroes;
-
- exponent = floorlog10l (arg);
- adjusted = 0;
for (;;)
{
digits =
@@ -5218,7 +5396,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
/* Determine the number of trailing zeroes
that have to be dropped. */
- nzeroes = 0;
+ size_t nzeroes = 0;
if ((flags & FLAG_ALT) == 0)
while (nzeroes < ndigits
&& digits[nzeroes] == '0')
@@ -5234,10 +5412,84 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
digits without trailing zeroes. */
if (exponent >= 0)
{
- size_t ecount = exponent + 1;
- /* Note: count <= precision = ndigits. */
- for (; ecount > 0; ecount--)
- *p++ = digits[--ndigits];
+ /* Number of digits before the decimal point. */
+ size_t intpart_digits = exponent + 1;
+ /* Note: intpart_digits <= precision = ndigits. */
+
+ const DCHAR_T *thousep = NULL;
+ DCHAR_T thousep_buf[10];
+# if !WIDE_CHAR_VERSION
+ size_t thousep_len = 0;
+# endif
+ const signed char *grouping;
+ size_t insert = 0;
+
+ if ((flags & FLAG_GROUP) && (intpart_digits > 1))
+ {
+ /* Determine the thousands separator and
+ the grouping rule of the current locale. */
+# if WIDE_CHAR_VERSION
+ /* DCHAR_T is wchar_t. */
+ thousep = thousands_separator_wchar (thousep_buf);
+# define thousep_len 1
+# elif defined DCHAR_CONV_FROM_ENCODING
+ /* DCHAR_T is uintN_t. */
+ thousep = thousands_separator_DCHAR (thousep_buf);
+ thousep_len = DCHAR_STRLEN (thousep);
+# else
+ /* DCHAR_T is char. */
+ thousep = thousands_separator_char (thousep_buf);
+ thousep_len = strlen (thousep);
+# endif
+ if (*thousep == 0)
+ thousep = NULL;
+ if (thousep != NULL)
+ {
+ grouping = grouping_rule ();
+ insert =
+ num_thousands_separators (grouping, intpart_digits);
+ }
+ }
+
+ const char *digitp = digits + ndigits - intpart_digits;
+ DCHAR_T *p_before_intpart = p;
+ p += intpart_digits + insert * thousep_len;
+ DCHAR_T *p_after_intpart = p;
+ if (insert > 0) /* implies (flag & FLAG_GROUP) && (thousep != NULL) */
+ {
+ const signed char *g = grouping;
+ for (;;)
+ {
+ int h = *g;
+ if (h <= 0)
+ abort ();
+ int i = h;
+ do
+ *--p = *digitp++;
+ while (--i > 0);
+# if WIDE_CHAR_VERSION
+ *--p = thousep[0];
+# else
+ p -= thousep_len;
+ DCHAR_CPY (p, thousep, thousep_len);
+# endif
+ insert--;
+ if (insert == 0)
+ break;
+ if (g[1] != 0)
+ g++;
+ }
+ }
+ for (;;)
+ {
+ *--p = *digitp++;
+ if (p == p_before_intpart)
+ break;
+ }
+ p = p_after_intpart;
+ ndigits -= intpart_digits;
+# undef thousep_len
+
if ((flags & FLAG_ALT) || ndigits > nzeroes)
{
*p++ = decimal_point_char ();
@@ -5294,9 +5546,8 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
else
{
char expbuf[6 + 1];
- const char *ep;
sprintf (expbuf, "%+.2d", exponent);
- for (ep = expbuf; (*p = *ep) != '\0'; ep++)
+ for (const char *ep = expbuf; (*p = *ep) != '\0'; ep++)
p++;
}
# endif
@@ -5396,7 +5647,6 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
else
{
int sign = 0;
-
if (signbit (arg)) /* arg < 0.0 or negative zero */
{
sign = -1;
@@ -5428,22 +5678,91 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
if (dp->conversion == 'f' || dp->conversion == 'F')
{
- char *digits;
- size_t ndigits;
-
- digits =
+ char *digits =
scale10_round_decimal_double (arg, precision);
if (digits == NULL)
goto out_of_memory;
- ndigits = strlen (digits);
+ size_t ndigits = strlen (digits);
if (ndigits > precision)
- do
- {
- --ndigits;
- *p++ = digits[ndigits];
- }
- while (ndigits > precision);
+ {
+ /* Number of digits before the decimal point. */
+ size_t intpart_digits = ndigits - precision;
+
+ const DCHAR_T *thousep = NULL;
+ DCHAR_T thousep_buf[10];
+# if !WIDE_CHAR_VERSION
+ size_t thousep_len = 0;
+# endif
+ const signed char *grouping;
+ size_t insert = 0;
+
+ if ((flags & FLAG_GROUP) && (intpart_digits > 1))
+ {
+ /* Determine the thousands separator and
+ the grouping rule of the current locale. */
+# if WIDE_CHAR_VERSION
+ /* DCHAR_T is wchar_t. */
+ thousep = thousands_separator_wchar (thousep_buf);
+# define thousep_len 1
+# elif defined DCHAR_CONV_FROM_ENCODING
+ /* DCHAR_T is uintN_t. */
+ thousep = thousands_separator_DCHAR (thousep_buf);
+ thousep_len = DCHAR_STRLEN (thousep);
+# else
+ /* DCHAR_T is char. */
+ thousep = thousands_separator_char (thousep_buf);
+ thousep_len = strlen (thousep);
+# endif
+ if (*thousep == 0)
+ thousep = NULL;
+ if (thousep != NULL)
+ {
+ grouping = grouping_rule ();
+ insert =
+ num_thousands_separators (grouping, intpart_digits);
+ }
+ }
+
+ const char *digitp = digits + precision;
+ DCHAR_T *p_before_intpart = p;
+ p += intpart_digits + insert * thousep_len;
+ DCHAR_T *p_after_intpart = p;
+ if (insert > 0) /* implies (flag & FLAG_GROUP) && (thousep != NULL) */
+ {
+ const signed char *g = grouping;
+ for (;;)
+ {
+ int h = *g;
+ if (h <= 0)
+ abort ();
+ int i = h;
+ do
+ *--p = *digitp++;
+ while (--i > 0);
+# if WIDE_CHAR_VERSION
+ *--p = thousep[0];
+# else
+ p -= thousep_len;
+ DCHAR_CPY (p, thousep, thousep_len);
+# endif
+ insert--;
+ if (insert == 0)
+ break;
+ if (g[1] != 0)
+ g++;
+ }
+ }
+ for (;;)
+ {
+ *--p = *digitp++;
+ if (p == p_before_intpart)
+ break;
+ }
+ p = p_after_intpart;
+ ndigits = precision;
+# undef thousep_len
+ }
else
*p++ = '0';
/* Here ndigits <= precision. */
@@ -5479,12 +5798,10 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
else
{
/* arg > 0.0. */
- int adjusted;
+ exponent = floorlog10 (arg);
+ int adjusted = 0;
char *digits;
size_t ndigits;
-
- exponent = floorlog10 (arg);
- adjusted = 0;
for (;;)
{
digits =
@@ -5586,9 +5903,8 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
else
{
char expbuf[6 + 1];
- const char *ep;
sprintf (expbuf, decimal_format, exponent);
- for (ep = expbuf; (*p = *ep) != '\0'; ep++)
+ for (const char *ep = expbuf; (*p = *ep) != '\0'; ep++)
p++;
}
}
@@ -5625,14 +5941,10 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
else
{
/* arg > 0.0. */
- int exponent;
- int adjusted;
+ int exponent = floorlog10 (arg);
+ int adjusted = 0;
char *digits;
size_t ndigits;
- size_t nzeroes;
-
- exponent = floorlog10 (arg);
- adjusted = 0;
for (;;)
{
digits =
@@ -5688,7 +6000,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
/* Determine the number of trailing zeroes
that have to be dropped. */
- nzeroes = 0;
+ size_t nzeroes = 0;
if ((flags & FLAG_ALT) == 0)
while (nzeroes < ndigits
&& digits[nzeroes] == '0')
@@ -5704,10 +6016,84 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
digits without trailing zeroes. */
if (exponent >= 0)
{
- size_t ecount = exponent + 1;
- /* Note: ecount <= precision = ndigits. */
- for (; ecount > 0; ecount--)
- *p++ = digits[--ndigits];
+ /* Number of digits before the decimal point. */
+ size_t intpart_digits = exponent + 1;
+ /* Note: intpart_digits <= precision = ndigits. */
+
+ const DCHAR_T *thousep = NULL;
+ DCHAR_T thousep_buf[10];
+# if !WIDE_CHAR_VERSION
+ size_t thousep_len = 0;
+# endif
+ const signed char *grouping;
+ size_t insert = 0;
+
+ if ((flags & FLAG_GROUP) && (intpart_digits > 1))
+ {
+ /* Determine the thousands separator and
+ the grouping rule of the current locale. */
+# if WIDE_CHAR_VERSION
+ /* DCHAR_T is wchar_t. */
+ thousep = thousands_separator_wchar (thousep_buf);
+# define thousep_len 1
+# elif defined DCHAR_CONV_FROM_ENCODING
+ /* DCHAR_T is uintN_t. */
+ thousep = thousands_separator_DCHAR (thousep_buf);
+ thousep_len = DCHAR_STRLEN (thousep);
+# else
+ /* DCHAR_T is char. */
+ thousep = thousands_separator_char (thousep_buf);
+ thousep_len = strlen (thousep);
+# endif
+ if (*thousep == 0)
+ thousep = NULL;
+ if (thousep != NULL)
+ {
+ grouping = grouping_rule ();
+ insert =
+ num_thousands_separators (grouping, intpart_digits);
+ }
+ }
+
+ const char *digitp = digits + ndigits - intpart_digits;
+ DCHAR_T *p_before_intpart = p;
+ p += intpart_digits + insert * thousep_len;
+ DCHAR_T *p_after_intpart = p;
+ if (insert > 0) /* implies (flag & FLAG_GROUP) && (thousep != NULL) */
+ {
+ const signed char *g = grouping;
+ for (;;)
+ {
+ int h = *g;
+ if (h <= 0)
+ abort ();
+ int i = h;
+ do
+ *--p = *digitp++;
+ while (--i > 0);
+# if WIDE_CHAR_VERSION
+ *--p = thousep[0];
+# else
+ p -= thousep_len;
+ DCHAR_CPY (p, thousep, thousep_len);
+# endif
+ insert--;
+ if (insert == 0)
+ break;
+ if (g[1] != 0)
+ g++;
+ }
+ }
+ for (;;)
+ {
+ *--p = *digitp++;
+ if (p == p_before_intpart)
+ break;
+ }
+ p = p_after_intpart;
+ ndigits -= intpart_digits;
+# undef thousep_len
+
if ((flags & FLAG_ALT) || ndigits > nzeroes)
{
*p++ = decimal_point_char ();
@@ -5779,9 +6165,8 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
else
{
char expbuf[6 + 1];
- const char *ep;
sprintf (expbuf, decimal_format, exponent);
- for (ep = expbuf; (*p = *ep) != '\0'; ep++)
+ for (const char *ep = expbuf; (*p = *ep) != '\0'; ep++)
p++;
}
}
@@ -5851,7 +6236,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
/* The generated string now extends from tmp to p, with the
zero padding insertion point being at pad_ptr. */
- count = p - tmp;
+ size_t count = p - tmp;
if (count < width)
{
@@ -5915,24 +6300,19 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
{
arg_type type = a.arg[dp->arg_index].type;
int flags = dp->flags;
-#if (WIDE_CHAR_VERSION && MUSL_LIBC) || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION
- int has_width;
-#endif
-#if !USE_SNPRINTF || WIDE_CHAR_VERSION || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION
- size_t width;
-#endif
-#if !USE_SNPRINTF || (WIDE_CHAR_VERSION && DCHAR_IS_TCHAR) || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || (WIDE_CHAR_VERSION && MUSL_LIBC) || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION
- int has_precision;
- size_t precision;
-#endif
#if NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION
int prec_ourselves;
#else
# define prec_ourselves 0
#endif
+#if NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION || NEED_PRINTF_FLAG_GROUPING || NEED_PRINTF_FLAG_GROUPING_INT
+ int group_ourselves;
+#else
+# define group_ourselves 0
+#endif
#if (WIDE_CHAR_VERSION && MUSL_LIBC) || NEED_PRINTF_FLAG_LEFTADJUST
# define pad_ourselves 1
-#elif !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION
+#elif !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION || NEED_PRINTF_FLAG_GROUPING || NEED_PRINTF_FLAG_GROUPING_INT
int pad_ourselves;
#else
# define pad_ourselves 0
@@ -5947,20 +6327,18 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
TCHAR_T *tmp;
#endif
-#if (WIDE_CHAR_VERSION && MUSL_LIBC) || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION
- has_width = 0;
+#if (WIDE_CHAR_VERSION && MUSL_LIBC) || NEED_PRINTF_FLAG_LEFTADJUST || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION || NEED_PRINTF_FLAG_GROUPING || NEED_PRINTF_FLAG_GROUPING_INT
+ int has_width = 0;
#endif
-#if !USE_SNPRINTF || WIDE_CHAR_VERSION || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION
- width = 0;
+#if !USE_SNPRINTF || WIDE_CHAR_VERSION || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || NEED_PRINTF_FLAG_LEFTADJUST || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION || NEED_PRINTF_FLAG_GROUPING || NEED_PRINTF_FLAG_GROUPING_INT
+ size_t width = 0;
if (dp->width_start != dp->width_end)
{
if (dp->width_arg_index != ARG_NONE)
{
- int arg;
-
if (!(a.arg[dp->width_arg_index].type == TYPE_INT))
abort ();
- arg = a.arg[dp->width_arg_index].a.a_int;
+ int arg = a.arg[dp->width_arg_index].a.a_int;
width = arg;
if (arg < 0)
{
@@ -5981,24 +6359,22 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
if (width > (size_t) INT_MAX)
goto overflow;
# define WIDTH_IS_CHECKED 1
-# if (WIDE_CHAR_VERSION && MUSL_LIBC) || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION
+# if (WIDE_CHAR_VERSION && MUSL_LIBC) || NEED_PRINTF_FLAG_LEFTADJUST || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION || NEED_PRINTF_FLAG_GROUPING || NEED_PRINTF_FLAG_GROUPING_INT
has_width = 1;
# endif
}
#endif
-#if !USE_SNPRINTF || (WIDE_CHAR_VERSION && DCHAR_IS_TCHAR) || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || (WIDE_CHAR_VERSION && MUSL_LIBC) || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION
- has_precision = 0;
- precision = 6;
+#if !USE_SNPRINTF || (WIDE_CHAR_VERSION && DCHAR_IS_TCHAR) || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || (WIDE_CHAR_VERSION && MUSL_LIBC) || NEED_PRINTF_FLAG_LEFTADJUST || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION || NEED_PRINTF_FLAG_GROUPING || NEED_PRINTF_FLAG_GROUPING_INT
+ int has_precision = 0;
+ size_t precision = 6;
if (dp->precision_start != dp->precision_end)
{
if (dp->precision_arg_index != ARG_NONE)
{
- int arg;
-
if (!(a.arg[dp->precision_arg_index].type == TYPE_INT))
abort ();
- arg = a.arg[dp->precision_arg_index].a.a_int;
+ int arg = a.arg[dp->precision_arg_index].a.a_int;
/* "A negative precision is taken as if the precision
were omitted." */
if (arg >= 0)
@@ -6052,25 +6428,56 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
}
#endif
+ /* Decide whether to add the thousands separators ourselves. */
+#if NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION || NEED_PRINTF_FLAG_GROUPING || NEED_PRINTF_FLAG_GROUPING_INT
+ if (flags & FLAG_GROUP)
+ {
+ switch (dp->conversion)
+ {
+ case 'd': case 'i': case 'u':
+# if NEED_PRINTF_FLAG_GROUPING || NEED_PRINTF_FLAG_GROUPING_INT
+ group_ourselves = 1;
+# else
+ group_ourselves = prec_ourselves;
+# endif
+ break;
+ case 'f': case 'F': case 'g': case 'G':
+# if NEED_PRINTF_FLAG_GROUPING
+ group_ourselves = 1;
+# else
+ group_ourselves = prec_ourselves;
+# endif
+ break;
+ default:
+ group_ourselves = 0;
+ break;
+ }
+ }
+ else
+ group_ourselves = 0;
+#endif
+
/* Decide whether to perform the padding ourselves. */
-#if !((WIDE_CHAR_VERSION && MUSL_LIBC) || NEED_PRINTF_FLAG_LEFTADJUST) && (!DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION)
+#if !((WIDE_CHAR_VERSION && MUSL_LIBC) || NEED_PRINTF_FLAG_LEFTADJUST) && (!DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION || NEED_PRINTF_FLAG_GROUPING || NEED_PRINTF_FLAG_GROUPING_INT)
switch (dp->conversion)
{
-# if !DCHAR_IS_TCHAR || ENABLE_UNISTDIO
+# if !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_ZERO
+# if !DCHAR_IS_TCHAR || ENABLE_UNISTDIO
/* If we need conversion from TCHAR_T[] to DCHAR_T[], we need
to perform the padding after this conversion. Functions
with unistdio extensions perform the padding based on
character count rather than element count. */
case 'c': case 's':
-# endif
-# if NEED_PRINTF_FLAG_ZERO
+# endif
+# if NEED_PRINTF_FLAG_ZERO
case 'f': case 'F': case 'e': case 'E': case 'g': case 'G':
case 'a': case 'A':
-# endif
+# endif
pad_ourselves = 1;
break;
+# endif
default:
- pad_ourselves = prec_ourselves;
+ pad_ourselves = prec_ourselves | group_ourselves;
break;
}
#endif
@@ -6103,14 +6510,8 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
sprintf. */
fbp = buf;
*fbp++ = '%';
-#if NEED_PRINTF_FLAG_GROUPING
- /* The underlying implementation doesn't support the ' flag.
- Produce no grouping characters in this case; this is
- acceptable because the grouping is locale dependent. */
-#else
- if (flags & FLAG_GROUP)
+ if ((flags & FLAG_GROUP) && !group_ourselves)
*fbp++ = '\'';
-#endif
if (flags & FLAG_LEFT)
*fbp++ = '-';
if (flags & FLAG_SHOWSIGN)
@@ -6142,11 +6543,9 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
quick check anyway. */
if (dp->width_arg_index != ARG_NONE)
{
- int arg;
-
if (!(a.arg[dp->width_arg_index].type == TYPE_INT))
abort ();
- arg = a.arg[dp->width_arg_index].a.a_int;
+ int arg = a.arg[dp->width_arg_index].a.a_int;
width = arg;
if (arg < 0)
{
@@ -6205,7 +6604,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
}
}
- switch (type)
+ switch (+type)
{
case TYPE_LONGLONGINT:
case TYPE_ULONGLONGINT:
@@ -6371,7 +6770,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
/* The following platforms forbid %n:
- On glibc2 systems from 2004-10-18 or newer, the use of
%n in format strings in writable memory may crash the
- program (if compiled with _FORTIFY_SOURCE=2).
+ program (if compiled with _FORTIFY_SOURCE >= 2).
- On macOS 10.13 or newer, the use of %n in format
strings in writable memory by default crashes the
program.
@@ -6404,7 +6803,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
on musl libc because we would run into an swprintf() bug.
See <https://www.openwall.com/lists/musl/2023/03/19/1>. */
fbp[1] = '\0';
-# else /* AIX <= 5.1, HP-UX, IRIX, OSF/1, Solaris <= 9, BeOS */
+# else /* AIX <= 5.1, HP-UX, Solaris <= 9, BeOS */
fbp[1] = '%';
fbp[2] = 'n';
fbp[3] = '\0';
@@ -6501,7 +6900,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
#endif
errno = 0;
- switch (type)
+ switch (+type)
{
case TYPE_SCHAR:
{
@@ -6870,10 +7269,13 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
|| *prec_ptr == ' '))
prefix_count = 1;
/* Put the additional zeroes after the 0x prefix if
- (flags & FLAG_ALT) || (dp->conversion == 'p'). */
+ (flags & FLAG_ALT) || (dp->conversion == 'p'), or
+ after the 0b prefix if (flags & FLAG_ALT). */
else if (count >= 2
&& prec_ptr[0] == '0'
- && (prec_ptr[1] == 'x' || prec_ptr[1] == 'X'))
+ && (prec_ptr[1] == 'x' || prec_ptr[1] == 'X'
+ || prec_ptr[1] == 'b'
+ || prec_ptr[1] == 'B'))
prefix_count = 2;
move = count - prefix_count;
@@ -6922,6 +7324,135 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
}
#endif
+#if NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION || NEED_PRINTF_FLAG_GROUPING || NEED_PRINTF_FLAG_GROUPING_INT
+ if (group_ourselves) /* implies (flags & FLAG_GROUP) */
+ /* Handle the grouping. */
+ switch (dp->conversion)
+ {
+ /* These are the only conversion to which grouping
+ applies. */
+ case 'd': case 'i': case 'u':
+ case 'f': case 'F': case 'g': case 'G':
+ {
+ /* Determine the thousands separator of the current
+ locale. */
+ const TCHAR_T *thousep;
+ TCHAR_T thousep_buf[10];
+
+# if WIDE_CHAR_VERSION && DCHAR_IS_TCHAR
+ /* TCHAR_T is wchar_t. */
+ thousep = thousands_separator_wchar (thousep_buf);
+# else
+ /* TCHAR_T is char. */
+ thousep = thousands_separator_char (thousep_buf);
+# endif
+
+ /* Nothing to do in locales where thousep is the empty
+ string. */
+ if (*thousep != 0)
+ {
+ /* Since FLAG_LOCALIZED is only supported on glibc
+ systems, here we can assume that all digits are
+ the ASCII digits '0'..'9'. */
+ TCHAR_T *number_ptr =
+# if USE_SNPRINTF
+ (TCHAR_T *) (result + length);
+# else
+ tmp;
+# endif
+ TCHAR_T *end_ptr = number_ptr + count;
+
+ /* Find where the leading digits start. */
+ TCHAR_T *digits_ptr = number_ptr;
+ if (count >= 1
+ && (*digits_ptr == '-' || *digits_ptr == '+'
+ || *digits_ptr == ' '))
+ digits_ptr++;
+
+ /* Find where the leading digits end. */
+ TCHAR_T *digits_end_ptr;
+ switch (dp->conversion)
+ {
+ case 'd': case 'i': case 'u':
+ digits_end_ptr = end_ptr;
+ break;
+ case 'f': case 'F': case 'g': case 'G':
+ {
+ TCHAR_T decimal_point = decimal_point_char ();
+ for (digits_end_ptr = digits_ptr;
+ digits_end_ptr < end_ptr;
+ digits_end_ptr++)
+ if (*digits_end_ptr == decimal_point
+ || *digits_end_ptr == 'e')
+ break;
+ }
+ break;
+ }
+
+ /* Determine the number of thousands separators
+ to insert. */
+ const signed char *grouping = grouping_rule ();
+ size_t insert =
+ num_thousands_separators (grouping, digits_end_ptr - digits_ptr);
+ if (insert > 0)
+ {
+# if WIDE_CHAR_VERSION && DCHAR_IS_TCHAR
+# define thousep_len 1
+# else
+ size_t thousep_len = strlen (thousep);
+# endif
+# if USE_SNPRINTF
+ size_t digits_offset = digits_ptr - number_ptr;
+ size_t digits_end_offset = digits_end_ptr - number_ptr;
+ size_t n =
+ xsum (length,
+ (count + insert * thousep_len + TCHARS_PER_DCHAR - 1)
+ / TCHARS_PER_DCHAR);
+ length += (count + TCHARS_PER_DCHAR - 1) / TCHARS_PER_DCHAR;
+ ENSURE_ALLOCATION (n);
+ length -= (count + TCHARS_PER_DCHAR - 1) / TCHARS_PER_DCHAR;
+ number_ptr = (TCHAR_T *) (result + length);
+ end_ptr = number_ptr + count;
+ digits_ptr = number_ptr + digits_offset;
+ digits_end_ptr = number_ptr + digits_end_offset;
+# endif
+
+ count += insert * thousep_len;
+
+ const TCHAR_T *p = end_ptr;
+ TCHAR_T *q = end_ptr + insert * thousep_len;
+ while (p > digits_end_ptr)
+ *--q = *--p;
+ const signed char *g = grouping;
+ for (;;)
+ {
+ int h = *g;
+ if (h <= 0)
+ abort ();
+ int i = h;
+ do
+ *--q = *--p;
+ while (--i > 0);
+# if WIDE_CHAR_VERSION && DCHAR_IS_TCHAR
+ *--q = *thousep;
+# else
+ q -= thousep_len;
+ memcpy (q, thousep, thousep_len);
+# endif
+ insert--;
+ if (insert == 0)
+ break;
+ if (g[1] != 0)
+ g++;
+ }
+ /* Here q == p. Done with the insertions. */
+ }
+ }
+ }
+ break;
+ }
+#endif
+
#if !USE_SNPRINTF
if (count >= tmp_length)
/* tmp_length was incorrectly calculated - fix the
@@ -6932,22 +7463,23 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
#if !DCHAR_IS_TCHAR
/* Convert from TCHAR_T[] to DCHAR_T[]. */
if (dp->conversion == 'c' || dp->conversion == 's'
+ || (flags & FLAG_GROUP)
# if __GLIBC__ >= 2 && !defined __UCLIBC__
|| (flags & FLAG_LOCALIZED)
# endif
)
{
/* The result string is not guaranteed to be ASCII. */
- const TCHAR_T *tmpsrc;
- DCHAR_T *tmpdst;
- size_t tmpdst_len;
/* This code assumes that TCHAR_T is 'char'. */
static_assert (sizeof (TCHAR_T) == 1);
+ const TCHAR_T *tmpsrc;
# if USE_SNPRINTF
tmpsrc = (TCHAR_T *) (result + length);
# else
tmpsrc = tmp;
# endif
+ DCHAR_T *tmpdst;
+ size_t tmpdst_len;
# if WIDE_CHAR_VERSION
/* Convert tmpsrc[0..count-1] to a freshly allocated
wide character array. */
@@ -7025,9 +7557,6 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
# endif
{
const TCHAR_T *tmpsrc;
- DCHAR_T *tmpdst;
- size_t n;
-
# if USE_SNPRINTF
if (result == resultbuf)
{
@@ -7047,11 +7576,11 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
tmpsrc = tmp;
ENSURE_ALLOCATION (xsum (length, count));
# endif
- tmpdst = result + length;
+ DCHAR_T *tmpdst = result + length;
/* Copy backwards, because of overlapping. */
tmpsrc += count;
tmpdst += count;
- for (n = count; n > 0; n--)
+ for (size_t n = count; n > 0; n--)
*--tmpdst = *--tmpsrc;
}
}
@@ -7073,7 +7602,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
/* Here count <= allocated - length. */
/* Perform padding. */
-#if (WIDE_CHAR_VERSION && MUSL_LIBC) || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION
+#if (WIDE_CHAR_VERSION && MUSL_LIBC) || NEED_PRINTF_FLAG_LEFTADJUST || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION || NEED_PRINTF_FLAG_GROUPING || NEED_PRINTF_FLAG_GROUPING_INT
if (pad_ourselves && has_width)
{
size_t w;
@@ -7082,6 +7611,23 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
against the number of _characters_ of the converted
value. */
w = DCHAR_MBSNLEN (result + length, count);
+# elif __GLIBC__ >= 2
+ /* glibc prefers to compare the width against the number
+ of characters as well, but only for numeric conversion
+ specifiers. See
+ <https://sourceware.org/PR28943>
+ <https://sourceware.org/PR30883>
+ <https://sourceware.org/PR31542> */
+ switch (dp->conversion)
+ {
+ case 'd': case 'i': case 'u':
+ case 'f': case 'F': case 'g': case 'G':
+ w = DCHAR_MBSNLEN (result + length, count);
+ break;
+ default:
+ w = count;
+ break;
+ }
# else
/* The width is compared against the number of _bytes_
of the converted value, says POSIX. */
@@ -7219,8 +7765,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
{
/* Convert the %f result to upper case for %F. */
DCHAR_T *rp = result + length;
- size_t rc;
- for (rc = count; rc > 0; rc--, rp++)
+ for (size_t rc = count; rc > 0; rc--, rp++)
if (*rp >= 'a' && *rp <= 'z')
*rp = *rp - 'a' + 'A';
}
@@ -7243,9 +7788,8 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
if (result != resultbuf && length + 1 < allocated)
{
/* Shrink the allocated memory if possible. */
- DCHAR_T *memory;
-
- memory = (DCHAR_T *) realloc (result, (length + 1) * sizeof (DCHAR_T));
+ DCHAR_T *memory =
+ (DCHAR_T *) realloc (result, (length + 1) * sizeof (DCHAR_T));
if (memory != NULL)
result = memory;
}