]> Savannah Git Hosting - gnulib.git/commitdiff
vasnprintf: Consider the grouping rule.
authorBruno Haible <bruno@clisp.org>
Sun, 13 Apr 2025 15:58:40 +0000 (17:58 +0200)
committerBruno Haible <bruno@clisp.org>
Sun, 13 Apr 2025 15:58:40 +0000 (17:58 +0200)
Reported by Pádraig Brady.

* lib/vasnprintf.c (grouping_rule, num_thousands_separators): New
functions.
(MAX_ROOM_NEEDED): Adjust worst-case guess for FLAG_GROUP.
(VASNPRINTF): Likewise. Invoke grouping_rule, num_thousands_separators.
Use the grouping rule to determine where to insert the thousands
separators.
* modules/vasnprintf (Depends-on): Add localeconv.
* modules/vasnwprintf (Depends-on): Likewise.
* modules/c-vasnprintf (Depends-on): Likewise.
* modules/unistdio/u8-u8-vasnprintf (Depends-on): Likewise.
* modules/unistdio/u8-vasnprintf (Depends-on): Likewise.
* modules/unistdio/u16-u16-vasnprintf (Depends-on): Likewise.
* modules/unistdio/u16-vasnprintf (Depends-on): Likewise.
* modules/unistdio/u32-u32-vasnprintf (Depends-on): Likewise.
* modules/unistdio/u32-vasnprintf (Depends-on): Likewise.
* modules/unistdio/ulc-vasnprintf (Depends-on): Likewise.

12 files changed:
ChangeLog
lib/vasnprintf.c
modules/c-vasnprintf
modules/unistdio/u16-u16-vasnprintf
modules/unistdio/u16-vasnprintf
modules/unistdio/u32-u32-vasnprintf
modules/unistdio/u32-vasnprintf
modules/unistdio/u8-u8-vasnprintf
modules/unistdio/u8-vasnprintf
modules/unistdio/ulc-vasnprintf
modules/vasnprintf
modules/vasnwprintf

index 4a03f496183dd4fdeafd514d0357c626f0c714ae..3415818382a09df5b9d8614fd1f27da9b2faf6df 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,24 @@
+2025-04-13  Bruno Haible  <bruno@clisp.org>
+
+       vasnprintf: Consider the grouping rule.
+       Reported by Pádraig Brady.
+       * lib/vasnprintf.c (grouping_rule, num_thousands_separators): New
+       functions.
+       (MAX_ROOM_NEEDED): Adjust worst-case guess for FLAG_GROUP.
+       (VASNPRINTF): Likewise. Invoke grouping_rule, num_thousands_separators.
+       Use the grouping rule to determine where to insert the thousands
+       separators.
+       * modules/vasnprintf (Depends-on): Add localeconv.
+       * modules/vasnwprintf (Depends-on): Likewise.
+       * modules/c-vasnprintf (Depends-on): Likewise.
+       * modules/unistdio/u8-u8-vasnprintf (Depends-on): Likewise.
+       * modules/unistdio/u8-vasnprintf (Depends-on): Likewise.
+       * modules/unistdio/u16-u16-vasnprintf (Depends-on): Likewise.
+       * modules/unistdio/u16-vasnprintf (Depends-on): Likewise.
+       * modules/unistdio/u32-u32-vasnprintf (Depends-on): Likewise.
+       * modules/unistdio/u32-vasnprintf (Depends-on): Likewise.
+       * modules/unistdio/ulc-vasnprintf (Depends-on): Likewise.
+
 2025-04-13  Bruno Haible  <bruno@clisp.org>
 
        vasnprintf tests: Fix compilation error on MSVC (regression yesterday).
index 4152237929e41589ae0bb56d442ef069983af026..d7e96ac5a6e0782d14ad3d21ae4a490891fffe55 100644 (file)
@@ -508,6 +508,77 @@ thousands_separator_wchar (wchar_t stackbuf[10])
    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.  */
@@ -1965,10 +2036,12 @@ MAX_ROOM_NEEDED (const arguments *ap, size_t arg_index, FCHAR_T conversion,
       /* 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 / 3 * THOUSEP_WCHAR_MAXLEN);
+          tmp_length = xsum (tmp_length, tmp_length / 2 * THOUSEP_WCHAR_MAXLEN);
 # else
-          tmp_length = xsum (tmp_length, tmp_length / 3 * THOUSEP_CHAR_MAXLEN);
+          tmp_length = xsum (tmp_length, tmp_length / 2 * THOUSEP_CHAR_MAXLEN);
 # endif
         }
       /* Add 1, to account for a leading sign.  */
@@ -2229,7 +2302,7 @@ MAX_ROOM_NEEDED (const arguments *ap, size_t arg_index, FCHAR_T conversion,
         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. */
@@ -2237,7 +2310,7 @@ 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. */
@@ -2249,7 +2322,7 @@ MAX_ROOM_NEEDED (const arguments *ap, size_t arg_index, FCHAR_T conversion,
         12; /* sign, decimal point, exponent etc. */
       tmp_length = xsum (tmp_length,
                          precision
-                         * 2 /* estimate for FLAG_GROUP */
+                         * 0.5 * 3 /* estimate for FLAG_GROUP */
                         );
       break;
 
@@ -5023,11 +5096,12 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
                 /* 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 / 3 * THOUSEP_WCHAR_MAXLEN);
+                    tmp_length = xsum (tmp_length, tmp_length / 2 * THOUSEP_WCHAR_MAXLEN);
 # else
-
-                    tmp_length = xsum (tmp_length, tmp_length / 3 * THOUSEP_CHAR_MAXLEN);
+                    tmp_length = xsum (tmp_length, tmp_length / 2 * THOUSEP_CHAR_MAXLEN);
 # endif
                   }
                 /* Account for sign, decimal point etc. */
@@ -5126,20 +5200,25 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
 
                                 if (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;
 #   endif
+                                    const signed char *grouping;
+                                    size_t insert = 0;
 
-                                    if ((flags & FLAG_GROUP)
-                                        && (ndigits - precision > 3))
+                                    if ((flags & FLAG_GROUP) && (intpart_digits > 1))
                                       {
-                                        /* Determine the thousands separator of the
-                                           current locale.  */
+                                        /* 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
 #   else
                                         /* DCHAR_T is char.  */
                                         thousep = thousands_separator_char (thousep_buf);
@@ -5147,26 +5226,52 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
 #   endif
                                         if (*thousep == 0)
                                           thousep = NULL;
+                                        if (thousep != NULL)
+                                          {
+                                            grouping = grouping_rule ();
+                                            insert =
+                                              num_thousands_separators (grouping,
+                                                                        ndigits - precision);
+                                          }
                                       }
 
-                                    for (;;)
+                                    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) */
                                       {
-                                        --ndigits;
-                                        *p++ = digits[ndigits];
-                                        if (ndigits == precision)
-                                          break;
-                                        if (thousep != NULL
-                                            /* implies (flags & FLAG_GROUP) */
-                                            && ((ndigits - precision) % 3) == 0)
+                                        const signed char *g = grouping;
+                                        for (;;)
                                           {
+                                            int h = *g;
+                                            if (h <= 0)
+                                              abort ();
+                                            int i;
+                                            for (i = h; i > 0; i--)
+                                              *--p = *digitp++;
 #   if WIDE_CHAR_VERSION
-                                            *p++ = thousep[0];
+                                            *--p = thousep[0];
 #   else
+                                            p -= thousep_len;
                                             memcpy (p, thousep, thousep_len);
-                                            p += 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';
@@ -5420,22 +5525,26 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
                                            digits without trailing zeroes.  */
                                         if (exponent >= 0)
                                           {
-                                            size_t ecount = exponent + 1;
-                                            /* Note: count <= precision = 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;
 #   endif
+                                            const signed char *grouping;
+                                            size_t insert = 0;
 
-                                            if ((flags & FLAG_GROUP) && (ecount > 3))
+                                            if ((flags & FLAG_GROUP) && (intpart_digits > 1))
                                               {
-                                                /* Determine the thousands separator of the
-                                                   current locale.  */
+                                                /* 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
 #   else
                                                 /* DCHAR_T is char.  */
                                                 thousep = thousands_separator_char (thousep_buf);
@@ -5443,27 +5552,51 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
 #   endif
                                                 if (*thousep == 0)
                                                   thousep = NULL;
+                                                if (thousep != NULL)
+                                                  {
+                                                    grouping = grouping_rule ();
+                                                    insert =
+                                                      num_thousands_separators (grouping, intpart_digits);
+                                                  }
                                               }
 
-                                            if (ecount > 0)
-                                              for (;;)
-                                                {
-                                                  --ndigits;
-                                                  *p++ = digits[ndigits];
-                                                  if (--ecount == 0)
-                                                    break;
-                                                  if (thousep != NULL
-                                                      /* implies (flags & FLAG_GROUP) */
-                                                      && (ecount % 3) == 0)
-                                                    {
+                                            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;
+                                                    for (i = h; i > 0; i--)
+                                                      *--p = *digitp++;
 #   if WIDE_CHAR_VERSION
-                                                      *p++ = thousep[0];
+                                                    *--p = thousep[0];
 #   else
-                                                      memcpy (p, thousep, thousep_len);
-                                                      p += thousep_len;
+                                                    p -= thousep_len;
+                                                    memcpy (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)
                                               {
@@ -5666,20 +5799,25 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
 
                                 if (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;
 #   endif
+                                    const signed char *grouping;
+                                    size_t insert = 0;
 
-                                    if ((flags & FLAG_GROUP)
-                                        && (ndigits - precision > 3))
+                                    if ((flags & FLAG_GROUP) && (intpart_digits > 1))
                                       {
-                                        /* Determine the thousands separator of the
-                                           current locale.  */
+                                        /* 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
 #   else
                                         /* DCHAR_T is char.  */
                                         thousep = thousands_separator_char (thousep_buf);
@@ -5687,26 +5825,52 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
 #   endif
                                         if (*thousep == 0)
                                           thousep = NULL;
+                                        if (thousep != NULL)
+                                          {
+                                            grouping = grouping_rule ();
+                                            insert =
+                                              num_thousands_separators (grouping,
+                                                                        ndigits - precision);
+                                          }
                                       }
 
-                                    for (;;)
+                                    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) */
                                       {
-                                        --ndigits;
-                                        *p++ = digits[ndigits];
-                                        if (ndigits == precision)
-                                          break;
-                                        if (thousep != NULL
-                                            /* implies (flags & FLAG_GROUP) */
-                                            && ((ndigits - precision) % 3) == 0)
+                                        const signed char *g = grouping;
+                                        for (;;)
                                           {
+                                            int h = *g;
+                                            if (h <= 0)
+                                              abort ();
+                                            int i;
+                                            for (i = h; i > 0; i--)
+                                              *--p = *digitp++;
 #   if WIDE_CHAR_VERSION
-                                            *p++ = thousep[0];
+                                            *--p = thousep[0];
 #   else
+                                            p -= thousep_len;
                                             memcpy (p, thousep, thousep_len);
-                                            p += 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';
@@ -5968,22 +6132,26 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
                                            digits without trailing zeroes.  */
                                         if (exponent >= 0)
                                           {
-                                            size_t ecount = exponent + 1;
-                                            /* Note: ecount <= precision = 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;
 #   endif
+                                            const signed char *grouping;
+                                            size_t insert = 0;
 
-                                            if ((flags & FLAG_GROUP) && (ecount > 3))
+                                            if ((flags & FLAG_GROUP) && (intpart_digits > 1))
                                               {
-                                                /* Determine the thousands separator of the
-                                                   current locale.  */
+                                                /* 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
 #   else
                                                 /* DCHAR_T is char.  */
                                                 thousep = thousands_separator_char (thousep_buf);
@@ -5991,27 +6159,51 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
 #   endif
                                                 if (*thousep == 0)
                                                   thousep = NULL;
+                                                if (thousep != NULL)
+                                                  {
+                                                    grouping = grouping_rule ();
+                                                    insert =
+                                                      num_thousands_separators (grouping, intpart_digits);
+                                                  }
                                               }
 
-                                            if (ecount > 0)
-                                              for (;;)
-                                                {
-                                                  --ndigits;
-                                                  *p++ = digits[ndigits];
-                                                  if (--ecount == 0)
-                                                    break;
-                                                  if (thousep != NULL
-                                                      /* implies (flags & FLAG_GROUP) */
-                                                      && (ecount % 3) == 0)
-                                                    {
+                                            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;
+                                                    for (i = h; i > 0; i--)
+                                                      *--p = *digitp++;
 #   if WIDE_CHAR_VERSION
-                                                      *p++ = thousep[0];
+                                                    *--p = thousep[0];
 #   else
-                                                      memcpy (p, thousep, thousep_len);
-                                                      p += thousep_len;
+                                                    p -= thousep_len;
+                                                    memcpy (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)
                                               {
@@ -7325,8 +7517,9 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
 
                                 /* Determine the number of thousands separators
                                    to insert.  */
-                                size_t insert = digits_end_ptr - digits_ptr;
-                                insert = (insert > 0 ? (insert - 1) / 3 : 0);
+                                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
@@ -7356,17 +7549,26 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
                                     TCHAR_T *q = end_ptr + insert * thousep_len;
                                     while (p > digits_end_ptr)
                                       *--q = *--p;
-                                    for (; insert > 0; insert--)
+                                    const signed char *g = grouping;
+                                    for (;;)
                                       {
-                                        *--q = *--p;
-                                        *--q = *--p;
-                                        *--q = *--p;
+                                        int h = *g;
+                                        if (h <= 0)
+                                          abort ();
+                                        int i;
+                                        for (i = h; i > 0; i--)
+                                          *--q = *--p;
 # if WIDE_CHAR_VERSION && DCHAR_IS_TCHAR
-                                        *--q = *thousep;
+                                          *--q = *thousep;
 # else
-                                        q -= thousep_len;
-                                        memcpy (q, thousep, thousep_len);
+                                          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.  */
                                   }
index aaa6011809b074941a51b0c6a6f358b8b7361932..eb6ecc8144a9fe383a3d3097340b879da8664887 100644 (file)
@@ -33,6 +33,7 @@ printf-safe
 alloca-opt
 xsize
 errno-h
+localeconv
 memchr
 multiarch
 mbszero
index 568ed34269db83cdf8ce6d0c19672086826dc215..f09b4b57f7217fbcc84f5c378923f5a43ba708a5 100644 (file)
@@ -39,6 +39,7 @@ localcharset
 xsize
 errno-h
 free-posix
+localeconv
 memchr
 multiarch
 assert-h
index a2982a8d56555996edf6721cba154922e9399b45..f82fdb33905b30dfa2fd6cb3e8ba91ff3bed70ba 100644 (file)
@@ -39,6 +39,7 @@ localcharset
 xsize
 errno-h
 free-posix
+localeconv
 memchr
 multiarch
 assert-h
index 718f751394e7e547a6ac2c250155f1243465a522..b15cf7c97ce6aae9b5efaab71854b002f9823d9d 100644 (file)
@@ -39,6 +39,7 @@ localcharset
 xsize
 errno-h
 free-posix
+localeconv
 memchr
 multiarch
 assert-h
index e49e3f8c78af8920e1f0ec4c842b482f5fe8c195..07fe0ed54815a5601992e50c9fc48590bc9b7b9b 100644 (file)
@@ -39,6 +39,7 @@ localcharset
 xsize
 errno-h
 free-posix
+localeconv
 memchr
 multiarch
 assert-h
index 937017ec97e0dc4c2db1d707fe8789f5be6a08be..356e5d441a3334d1aea1b4ee39b4986065ec573a 100644 (file)
@@ -39,6 +39,7 @@ localcharset
 xsize
 errno-h
 free-posix
+localeconv
 memchr
 multiarch
 assert-h
index 0d3cb00b062bcc0f50f5f409fdfb9d7a3a896d9a..e2b0355d79ca866c7647305ca321445842d9c246 100644 (file)
@@ -39,6 +39,7 @@ localcharset
 xsize
 errno-h
 free-posix
+localeconv
 memchr
 multiarch
 assert-h
index a80c979af101034920ff9040654d376eb7db9707..2257e49c952c8d247007c3b7d26932023d21ec4f 100644 (file)
@@ -37,6 +37,7 @@ localcharset
 xsize
 errno-h
 free-posix
+localeconv
 memchr
 multiarch
 assert-h
index aa12d79139c9625e22918591a9fcb3957693755e..4418d891799880e60a0ca4a69f4186101f2b54a5 100644 (file)
@@ -29,6 +29,7 @@ limits-h
 stdint-h
 xsize
 errno-h
+localeconv
 memchr
 assert-h
 wchar-h
index 3d8015f3786f54898d8cdf5a5ea3d3d951394820..987e9fd95e9281a997821d868f70e6f6787e5337 100644 (file)
@@ -36,6 +36,7 @@ errno-h
 memchr
 assert-h
 wchar-h
+localeconv
 mbszero
 mbrtowc
 wmemcpy