Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/bin/sleep Allow the decimal radix character '.' to work, reg...



details:   https://anonhg.NetBSD.org/src/rev/f6e79244221e
branches:  trunk
changeset: 447624:f6e79244221e
user:      kre <kre%NetBSD.org@localhost>
date:      Sat Jan 19 13:27:12 2019 +0000

description:
Allow the decimal radix character '.' to work, regardless of
what the current locale's radix character happens to be,
while still allowing locale specific entry of fractional
seconds (ie: if you're in locale where the radix character
is ',' you san use "sleep 2.5" or "sleep 2,5" and they
accomplish the same thing).

This avoids issues with the "sleep 0.05" in rc.subr which
generated usage messages when a locale that does not use
'.' as its radix character was in use.

Reported on netbsd-users by Dima Veselov, with the problem
diagnosed by Martin Husemann

While here, tighten the arg validity checking (3+4 is
no longer permitted as a synonym of 3) and allow 0.0
to mean the same thing as 0 rather than being an error.

Also, make the SIGINFO reports a little nicer (IMO).

The ATF tests for sleep all pass (not that that means a lot).

diffstat:

 bin/sleep/sleep.c |  60 ++++++++++++++++++++++++++++++++++++++++++++-----------
 1 files changed, 48 insertions(+), 12 deletions(-)

diffs (108 lines):

diff -r 6eecb6e592b4 -r f6e79244221e bin/sleep/sleep.c
--- a/bin/sleep/sleep.c Sat Jan 19 13:17:32 2019 +0000
+++ b/bin/sleep/sleep.c Sat Jan 19 13:27:12 2019 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: sleep.c,v 1.24 2011/08/29 14:51:19 joerg Exp $ */
+/* $NetBSD: sleep.c,v 1.25 2019/01/19 13:27:12 kre Exp $ */
 
 /*
  * Copyright (c) 1988, 1993, 1994
@@ -39,7 +39,7 @@
 #if 0
 static char sccsid[] = "@(#)sleep.c    8.3 (Berkeley) 4/2/94";
 #else
-__RCSID("$NetBSD: sleep.c,v 1.24 2011/08/29 14:51:19 joerg Exp $");
+__RCSID("$NetBSD: sleep.c,v 1.25 2019/01/19 13:27:12 kre Exp $");
 #endif
 #endif /* not lint */
 
@@ -68,6 +68,7 @@
 main(int argc, char *argv[])
 {
        char *arg, *temp;
+       const char *msg;
        double fval, ival, val;
        struct timespec ntime;
        time_t original;
@@ -100,36 +101,71 @@
         * problem. Why use an isdigit() check instead of checking for
         * a period? Because doing it this way means locales will be
         * handled transparently by the atof code.
+        *
+        * Since fracflag is set for any non-digit, we also fall
+        * into the floating point conversion path if the input
+        * is hex (the 'x' in 0xA is not a digit).  Then if
+        * strtod() handles hex (on NetBSD it does) so will we.
         */
        fracflag = 0;
        arg = *argv;
        for (temp = arg; *temp != '\0'; temp++)
-               if (!isdigit((unsigned char)*temp))
+               if (!isdigit((unsigned char)*temp)) {
+                       ch = *temp;
                        fracflag++;
+               }
 
        if (fracflag) {
-               val = atof(arg);
-               if (val <= 0)
+               /*
+                * If the radix char in the arg was a '.'
+                * (as is likely when used from scripts, etc)
+                * then force the C locale, so atof() works
+                * as intended, even if the user's locale
+                * expects something different, like ','
+                * (but leave the locale alone otherwise, so if
+                * the user entered 2,4 and that is correct for
+                * the locale, it will work).
+                */
+               if (ch == '.')
+                       (void)setlocale(LC_ALL, "C");
+               val = strtod(arg, &temp);
+               if (val < 0 || temp == arg || *temp != '\0')
                        usage();
                ival = floor(val);
                fval = (1000000000 * (val-ival));
                ntime.tv_sec = ival;
                ntime.tv_nsec = fval;
-       }
-       else {
-               ntime.tv_sec = atol(arg);
-               if (ntime.tv_sec <= 0)
+               if (ntime.tv_sec == 0 && ntime.tv_nsec == 0)
+                       return EXIT_SUCCESS;    /* was 0.0 or underflowed */
+       } else {
+               ntime.tv_sec = strtol(arg, &temp, 10);
+               if (ntime.tv_sec < 0 || temp == arg || *temp != '\0')
+                       usage();
+               if (ntime.tv_sec == 0)
                        return EXIT_SUCCESS;
                ntime.tv_nsec = 0;
        }
 
        original = ntime.tv_sec;
+       if (ntime.tv_nsec != 0)
+               msg = " and a bit";
+       else
+               msg = "";
+
        signal(SIGINFO, report_request);
        while ((rv = nanosleep(&ntime, &ntime)) != 0) {
                if (report_requested) {
-               /* Reporting does not bother with nanoseconds. */
-                       warnx("about %d second(s) left out of the original %d",
-                       (int)ntime.tv_sec, (int)original);
+                       /* Reporting does not bother (much) with nanoseconds. */
+                       if (ntime.tv_sec == 0)
+                           warnx("in the final moments of the original"
+                              " %ld%s second%s", (long)original, msg,
+                              original == 1 && *msg == '\0' ? "" : "s");
+                       else
+                           warnx("between %ld and %ld seconds left"
+                               " out of the original %ld%s",
+                               (long)ntime.tv_sec, (long)ntime.tv_sec + 1,
+                               (long)original, msg);
+
                        report_requested = 0;
                } else
                        break;



Home | Main Index | Thread Index | Old Index