]> git.ipfire.org Git - thirdparty/coreutils.git/commitdiff
printf,seq,sleep,tail,timeout: accept current-locale floats
authorPaul Eggert <eggert@cs.ucla.edu>
Sun, 27 Jan 2019 00:37:01 +0000 (16:37 -0800)
committerPaul Eggert <eggert@cs.ucla.edu>
Sun, 27 Jan 2019 06:41:09 +0000 (22:41 -0800)
These commands now accept floating-point numbers in the
current locale, as well as in the C locale.
Compatibility problem reported by Robert Elz.
* NEWS: Document this.
* bootstrap.conf (gnulib_modules): Add cl-strtod, cl-strtold.
Remove c-strtold.
* doc/coreutils.texi (Floating point, tail invocation)
(printf invocation, timeout invocation, sleep invocation)
(seq invocation): Document this.
* gl/lib/cl-strtod.c, gl/lib/cl-strtod.h, gl/lib/cl-strtold.c:
* gl/modules/cl-strtod, gl/modules/cl-strtold: New files.
* src/printf.c, src/seq.c, src/sleep.c, src/tail.c, src/timeout.c:
Include cl-strtod.h instead of c-strtod.
* src/printf.c (vstrtold):
* src/seq.c (scan_arg, print_numbers):
* src/sleep.c (main):
* src/tail.c (parse_options):
* src/timeout.c (parse_duration):
Use cl_strtold instead of c_strtold.

13 files changed:
NEWS
bootstrap.conf
doc/coreutils.texi
gl/lib/cl-strtod.c [new file with mode: 0644]
gl/lib/cl-strtod.h [new file with mode: 0644]
gl/lib/cl-strtold.c [new file with mode: 0644]
gl/modules/cl-strtod [new file with mode: 0644]
gl/modules/cl-strtold [new file with mode: 0644]
src/printf.c
src/seq.c
src/sleep.c
src/tail.c
src/timeout.c

diff --git a/NEWS b/NEWS
index a6a02d8e7aebae2a55154cb976ea0295639f4c8d..4b6b8bff8d087b42847850f2c8d567024dc1dfb1 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -53,6 +53,13 @@ GNU coreutils NEWS                                    -*- outline -*-
 
   id now supports specifying multiple users.
 
+  printf, seq, sleep, tail, and timeout now accept floating point
+  numbers in either the current or the C locale.  For example, if the
+  current locale's decimal point is ',', 'sleep 0,1' and 'sleep 0.1'
+  now mean the same thing.  Previously, these commands accepted only
+  C-locale syntax with '.' as the decimal point.  The new behavior is
+  more compatible with other implementations in non-C locales.
+
   test now supports the '-N FILE' unary operator (like e.g. bash) to check
   whether FILE exists and has been modified since it was last read.
 
index 37ed49a668955ee66125fc061824034b38ba6c11..02e70b379cc6c2e0e94c4fff49dee9b9ccb5a0e5 100644 (file)
@@ -41,7 +41,8 @@ gnulib_modules="
   buffer-lcm
   c-strcase
   c-strtod
-  c-strtold
+  cl-strtod
+  cl-strtold
   calloc-gnu
   canon-host
   canonicalize
index fa82d65469ec5c0cc1e5eb67a885351a9e1bd54a..be35de49075a49bf9c6c837616246f07df736695 100644 (file)
@@ -1088,7 +1088,6 @@ information, please see David Goldberg's paper
 @uref{https://@/docs.oracle.com/@/cd/@/E19957-01/@/806-3568/@/ncg_goldberg.html,
 What Every Computer Scientist Should Know About Floating-Point Arithmetic}.
 
-@vindex LC_NUMERIC
 Commands that accept floating point numbers as options, operands or
 input use the standard C functions @code{strtod} and @code{strtold} to
 convert from text to floating point numbers.  These floating point
@@ -1098,10 +1097,16 @@ case-insensitive @code{inf}, @code{infinity}, and @code{NaN}, although
 whether such values are useful depends on the command in question.
 Modern C implementations also accept hexadecimal floating point
 numbers such as @code{-0x.ep-3}, which stands for @minus{}14/16 times
-@math{2^-3}, which equals @minus{}0.109375.  The @env{LC_NUMERIC}
-locale determines the decimal-point character.  @xref{Parsing of
+@math{2^-3}, which equals @minus{}0.109375.  @xref{Parsing of
 Floats,,, libc, The GNU C Library Reference Manual}.
 
+@vindex LC_NUMERIC
+Normally the @env{LC_NUMERIC} locale determines the decimal-point
+character.  However, some commands' descriptions specify that they
+accept numbers in either the current or the C locale; for example,
+they treat @samp{3.14} like @samp{3,14} if the current locale uses
+comma as a decimal point.
+
 @node Signal specifications
 @section Signal specifications
 @cindex signals, specifying
@@ -3187,13 +3192,12 @@ never checks it again.
 Change the number of seconds to wait between iterations (the default is 1.0).
 During one iteration, every specified file is checked to see if it has
 changed size.
-Historical implementations of @command{tail} have required that
-@var{number} be an integer.  However, GNU @command{tail} accepts
-an arbitrary floating point number.  @xref{Floating point}.
 When @command{tail} uses inotify, this polling-related option
 is usually ignored.  However, if you also specify @option{--pid=@var{p}},
 @command{tail} checks whether process @var{p} is alive at least
 every @var{number} seconds.
+The @var{number} must be non-negative and can be a floating-point number
+in either the current or the C locale.  @xref{Floating point}.
 
 @item -v
 @itemx --verbose
@@ -12829,11 +12833,11 @@ warning is printed.  For example, @samp{printf "%d" "'a"} outputs
 @end itemize
 
 @vindex LC_NUMERIC
-A floating-point argument must use a period before any fractional
-digits, but is printed according to the @env{LC_NUMERIC} category of the
-current locale.  For example, in a locale whose radix character is a
-comma, the command @samp{printf %g 3.14} outputs @samp{3,14} whereas
-the command @samp{printf %g 3,14} is an error.
+A floating point argument is interpreted according to
+the @env{LC_NUMERIC} category of either the current or the C locale,
+and is printed according to the current locale.
+For example, in a locale whose decimal point character is a comma,
+the command @samp{printf '%g %g' 2,5 2.5} outputs @samp{2,5 2,5}.
 @xref{Floating point}.
 
 @kindex \@var{ooo}
@@ -17985,7 +17989,8 @@ Diagnose to stderr, any signal sent upon timeout.
 @end table
 
 @cindex time units
-@var{duration} is a floating point number followed by an optional unit:
+@var{duration} is a floating point number in either the current or the
+C locale (@pxref{Floating point}) followed by an optional unit:
 @display
 @samp{s} for seconds (the default)
 @samp{m} for minutes
@@ -18138,7 +18143,7 @@ days
 Although portable POSIX scripts must give @command{sleep} a single
 non-negative integer argument without a suffix, GNU @command{sleep}
 also accepts two or more arguments, unit suffixes, and floating-point
-numbers.  @xref{Floating point}.
+numbers in either the current or the C locale.  @xref{Floating point}.
 
 The only options are @option{--help} and @option{--version}.  @xref{Common
 options}.
@@ -18587,7 +18592,8 @@ so @code{seq 1 10 10} only produces @samp{1}.
 @var{increment} must not be @samp{0}; use @command{yes} to get
 repeated output of a constant number.
 @var{first}, @var{increment} and @var{last} must not be @code{NaN}.
-Floating-point numbers may be specified.  @xref{Floating point}.
+Floating-point numbers may be specified in either the current or
+the C locale.  @xref{Floating point}.
 
 The program accepts the following options.  Also see @ref{Common options}.
 Options must precede operands.
diff --git a/gl/lib/cl-strtod.c b/gl/lib/cl-strtod.c
new file mode 100644 (file)
index 0000000..fa77235
--- /dev/null
@@ -0,0 +1,74 @@
+/* Convert string to double in the current locale, falling back on the C locale.
+
+   Copyright 2019 Free Software Foundation, Inc.
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
+
+/* Written by Paul Eggert.  */
+
+#include <config.h>
+
+#include "cl-strtod.h"
+
+#include <c-strtod.h>
+
+#include <errno.h>
+#include <stdlib.h>
+
+#if LONG
+# define CL_STRTOD cl_strtold
+# define DOUBLE long double
+# define C_STRTOD c_strtold
+#else
+# define CL_STRTOD cl_strtod
+# define DOUBLE double
+# define C_STRTOD c_strtod
+#endif
+
+/* This function acts like strtod or strtold, except that it falls
+   back on the C locale if the initial prefix is not parsable in
+   the current locale.  If the prefix is parsable in both locales,
+   it uses the longer parse, breaking ties in favor of the current locale.
+
+   Parse the initial prefix of NPTR as a floating-point number in the
+   current locale or in the C locale (preferring the locale that
+   yields the longer parse, or the current locale if there is a tie).
+   If ENDPTR is not NULL, set *ENDPTR to the first unused byte, or to
+   NPTR if the prefix cannot be parsed.
+
+   If successful, return a number without changing errno.
+   If the prefix cannot be parsed, return 0 and possibly set errno to EINVAL.
+   If the number overflows, return an extreme value and set errno to ERANGE.
+   If the number underflows, return a value close to 0 and set errno to ERANGE.
+   If there is some other error, return 0 and set errno.  */
+
+DOUBLE
+CL_STRTOD (char const *nptr, char **restrict endptr)
+{
+  char *end;
+  DOUBLE d = strtod (nptr, &end);
+  if (*end)
+    {
+      int strtod_errno = errno;
+      char *c_end;
+      DOUBLE c = C_STRTOD (nptr, &c_end);
+      if (end < c_end)
+        d = c, end = c_end;
+      else
+        errno = strtod_errno;
+    }
+  if (endptr)
+    *endptr = end;
+  return d;
+}
diff --git a/gl/lib/cl-strtod.h b/gl/lib/cl-strtod.h
new file mode 100644 (file)
index 0000000..51becd3
--- /dev/null
@@ -0,0 +1,2 @@
+double cl_strtod (char const *, char **restrict);
+long double cl_strtold (char const *, char **restrict);
diff --git a/gl/lib/cl-strtold.c b/gl/lib/cl-strtold.c
new file mode 100644 (file)
index 0000000..95ae46d
--- /dev/null
@@ -0,0 +1,2 @@
+#define LONG 1
+#include "cl-strtod.c"
diff --git a/gl/modules/cl-strtod b/gl/modules/cl-strtod
new file mode 100644 (file)
index 0000000..a2b43c1
--- /dev/null
@@ -0,0 +1,24 @@
+Description:
+Convert string to double in current or C locale.
+
+Files:
+lib/cl-strtod.c
+lib/cl-strtod.h
+
+Depends-on:
+c-strtod
+
+configure.ac:
+AC_REQUIRE([AC_C_RESTRICT])
+
+Makefile.am:
+lib_SOURCES += cl-strtod.c
+
+Include:
+"cl-strtod.h"
+
+License:
+GPL
+
+Maintainer:
+all
diff --git a/gl/modules/cl-strtold b/gl/modules/cl-strtold
new file mode 100644 (file)
index 0000000..61cc438
--- /dev/null
@@ -0,0 +1,23 @@
+Description:
+Convert string to long double in current or C locale.
+
+Files:
+lib/cl-strtold.c
+
+Depends-on:
+c-strtold
+cl-strtod
+
+configure.ac:
+
+Makefile.am:
+lib_SOURCES += cl-strtold.c
+
+Include:
+"cl-strtod.h"
+
+License:
+GPL
+
+Maintainer:
+all
index 28e058f503e9011cd32627e7446a3d72a3d31475..3260868cbe2359b6dab65159f565d48373a7aa77 100644 (file)
@@ -55,7 +55,7 @@
 #include <sys/types.h>
 
 #include "system.h"
-#include "c-strtod.h"
+#include "cl-strtod.h"
 #include "die.h"
 #include "error.h"
 #include "quote.h"
@@ -188,7 +188,7 @@ FUNC_NAME (char const *s)                                            \
 
 STRTOX (intmax_t,    vstrtoimax, strtoimax (s, &end, 0))
 STRTOX (uintmax_t,   vstrtoumax, strtoumax (s, &end, 0))
-STRTOX (long double, vstrtold,   c_strtold (s, &end))
+STRTOX (long double, vstrtold,   cl_strtold (s, &end))
 
 /* Output a single-character \ escape.  */
 
index 21c32096bc59c10440b05cbc6ee502540ce09cfb..61d20fe628f57db3b7bed1533cf9ec704b4b847c 100644 (file)
--- a/src/seq.c
+++ b/src/seq.c
@@ -23,7 +23,7 @@
 
 #include "system.h"
 #include "die.h"
-#include "c-strtod.h"
+#include "cl-strtod.h"
 #include "error.h"
 #include "quote.h"
 #include "xstrtod.h"
@@ -142,7 +142,7 @@ scan_arg (const char *arg)
 {
   operand ret;
 
-  if (! xstrtold (arg, NULL, &ret.value, c_strtold))
+  if (! xstrtold (arg, NULL, &ret.value, cl_strtold))
     {
       error (0, 0, _("invalid floating point argument: %s"), quote (arg));
       usage (EXIT_FAILURE);
@@ -331,7 +331,7 @@ print_numbers (char const *fmt, struct layout layout,
                 xalloc_die ();
               x_str[x_strlen - layout.suffix_len] = '\0';
 
-              if (xstrtold (x_str + layout.prefix_len, NULL, &x_val, c_strtold)
+              if (xstrtold (x_str + layout.prefix_len, NULL, &x_val, cl_strtold)
                   && x_val == last)
                 {
                   char *x0_str = NULL;
index 23a941636b04e343198d02e71946d9830bbdf918..a634f1ae65f95518f76135e47aec850ebcebe20c 100644 (file)
@@ -20,7 +20,7 @@
 #include <getopt.h>
 
 #include "system.h"
-#include "c-strtod.h"
+#include "cl-strtod.h"
 #include "die.h"
 #include "error.h"
 #include "long-options.h"
@@ -128,7 +128,7 @@ main (int argc, char **argv)
     {
       double s;
       const char *p;
-      if (! (xstrtod (argv[i], &p, &s, c_strtod) || errno == ERANGE)
+      if (! (xstrtod (argv[i], &p, &s, cl_strtod) || errno == ERANGE)
           /* Nonnegative interval.  */
           || ! (0 <= s)
           /* No extra chars after the number and an optional s,m,h,d char.  */
index b8064853fe4228892432aed3316fbcb997e88139..dee827bc8f662746dd0d2de1c95aa2eed8ae763f 100644 (file)
@@ -36,7 +36,7 @@
 
 #include "system.h"
 #include "argmatch.h"
-#include "c-strtod.h"
+#include "cl-strtod.h"
 #include "die.h"
 #include "error.h"
 #include "fcntl--.h"
@@ -2244,7 +2244,7 @@ parse_options (int argc, char **argv,
         case 's':
           {
             double s;
-            if (! (xstrtod (optarg, NULL, &s, c_strtod) && 0 <= s))
+            if (! (xstrtod (optarg, NULL, &s, cl_strtod) && 0 <= s))
               die (EXIT_FAILURE, 0,
                    _("invalid number of seconds: %s"), quote (optarg));
             *sleep_interval = s;
index 560af1a7ca749e5188dbcad652ae7b230e7d8815..748832f8ac8be83222d83f24bbd3754dadaa288b 100644 (file)
@@ -55,7 +55,7 @@
 #include <sys/wait.h>
 
 #include "system.h"
-#include "c-strtod.h"
+#include "cl-strtod.h"
 #include "xstrtod.h"
 #include "sig2str.h"
 #include "operand2sig.h"
@@ -316,12 +316,12 @@ apply_time_suffix (double *x, char suffix_char)
 }
 
 static double
-parse_duration (const charstr)
+parse_duration (const char *str)
 {
   double duration;
   const char *ep;
 
-  if (! (xstrtod (str, &ep, &duration, c_strtod) || errno == ERANGE)
+  if (! (xstrtod (str, &ep, &duration, cl_strtod) || errno == ERANGE)
       /* Nonnegative interval.  */
       || ! (0 <= duration)
       /* No extra chars after the number and an optional s,m,h,d char.  */