]> git.ipfire.org Git - thirdparty/coreutils.git/commitdiff
numfmt: support reading numbers with grouping characters
authorPádraig Brady <P@draigBrady.com>
Tue, 14 Oct 2025 20:06:03 +0000 (21:06 +0100)
committerPádraig Brady <P@draigBrady.com>
Fri, 17 Oct 2025 16:26:30 +0000 (17:26 +0100)
This does not validate grouping character placement,
and currently just ignores grouping characters.

* src/numfmt.c (simple_strtod_int): Skip grouping chars
that are part of a number.
* tests/misc/numfmt.pl: Add test cases.
* NEWS: Mention the improvement.

NEWS
src/numfmt.c
tests/misc/numfmt.pl

diff --git a/NEWS b/NEWS
index 40d443942e4c6b7667ade95d48e58d3c46c3be2a..a07fe298cdb4ca71845d284b9b1a449e43498152 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -35,7 +35,8 @@ GNU coreutils NEWS                                    -*- outline -*-
 
 ** Improvements
 
-  numfmt now parses numbers with a non-breaking space character before a unit.
+  numfmt now parses numbers with a non-breaking space character before a unit,
+  and numbers containing grouping characters from the current locale.
 
   wc -l now operates 10% faster on hosts that support AVX512 instructions.
 
index fbf104b5119dc044552bb74ad240a13592938757..1a744770faed32bbc78cfb193956d4dbbdcfe98c 100644 (file)
@@ -207,6 +207,8 @@ static bool debug;
 /* will be set according to the current locale.  */
 static char const *decimal_point;
 static int decimal_point_length;
+static char const *thousands_sep;
+static int thousands_sep_length;
 
 /* debugging for developers.  Enables devmsg().  */
 static bool dev_debug = false;
@@ -520,6 +522,11 @@ simple_strtod_int (char const *input_str,
       val += digit;
 
       ++(*endptr);
+
+      if (thousands_sep_length > 0
+          && STREQ_LEN (*endptr, thousands_sep, thousands_sep_length)
+          && c_isdigit ((*endptr)[thousands_sep_length]))
+        (*endptr) += thousands_sep_length;
     }
   if (! found_digit
       && ! STREQ_LEN (*endptr, decimal_point, decimal_point_length))
@@ -1474,6 +1481,11 @@ main (int argc, char **argv)
     decimal_point = ".";
   decimal_point_length = strlen (decimal_point);
 
+  thousands_sep = nl_langinfo (THOUSEP);
+  if (thousands_sep == nullptr)
+    thousands_sep = "";
+  thousands_sep_length = strlen (thousands_sep);
+
   atexit (close_stdout);
 
   while (true)
@@ -1602,7 +1614,7 @@ main (int argc, char **argv)
     {
       if (scale_to != scale_none)
         error (EXIT_FAILURE, 0, _("grouping cannot be combined with --to"));
-      if (debug && (strlen (nl_langinfo (THOUSEP)) == 0))
+      if (debug && thousands_sep_length == 0)
         error (0, 0, _("grouping has no effect in this locale"));
     }
 
index 85c888cd8e3954cccf535d1bed5904ab80a21e16..1d3c4202c76597069633573e50954bbf36c48a48 100755 (executable)
@@ -1050,8 +1050,20 @@ my @Locale_Tests =
              {OUT=>"7${lg}000${lg}000"},
              {ENV=>"LC_ALL=$locale"}],
 
-     # Input with locale'd decimal-point
-     ['lcl-stdtod-1', '--from=si 12,2K', {OUT=>"12200"},
+     # Input with locale's grouping
+     ['lcl-strtod-1', '--from=si 1${lg}234K', {OUT=>"1234000"},
+             {ENV=>"LC_ALL=$locale"}],
+
+     # Input with locale's grouping.  Note position not validated.
+     ['lcl-strtod-2', '--from=si 12${lg}34K', {OUT=>"1234000"},
+             {ENV=>"LC_ALL=$locale"}],
+
+     # Input with locale's decimal-point
+     ['lcl-strtod-3', '--from=si 12,2K', {OUT=>"12200"},
+             {ENV=>"LC_ALL=$locale"}],
+
+     # Input with locale's grouping and decimal-point
+     ['lcl-strtod-4', '--from=si 1${lg}23,4K', {OUT=>"123400"},
              {ENV=>"LC_ALL=$locale"}],
 
      ['lcl-dbl-to-human-1', '--to=si 1100', {OUT=>"1,1k"},