printf,seq,sleep,tail,timeout: accept current-locale floats

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.
This commit is contained in:
Paul Eggert
2019-01-26 16:37:01 -08:00
parent 3cd48057c7
commit 3fe8bc09be
13 changed files with 166 additions and 27 deletions

7
NEWS
View File

@@ -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.

View File

@@ -41,7 +41,8 @@ gnulib_modules="
buffer-lcm
c-strcase
c-strtod
c-strtold
cl-strtod
cl-strtold
calloc-gnu
canon-host
canonicalize

View 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.

74
gl/lib/cl-strtod.c Normal file
View File

@@ -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;
}

2
gl/lib/cl-strtod.h Normal file
View File

@@ -0,0 +1,2 @@
double cl_strtod (char const *, char **restrict);
long double cl_strtold (char const *, char **restrict);

2
gl/lib/cl-strtold.c Normal file
View File

@@ -0,0 +1,2 @@
#define LONG 1
#include "cl-strtod.c"

24
gl/modules/cl-strtod Normal file
View File

@@ -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

23
gl/modules/cl-strtold Normal file
View File

@@ -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

View 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. */

View File

@@ -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;

View 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. */

View 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;

View 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 char* str)
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. */