Source-Changes-HG archive

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

[src/trunk]: src/bin/date Provide real error messages.



details:   https://anonhg.NetBSD.org/src/rev/4b85004f09fe
branches:  trunk
changeset: 331953:4b85004f09fe
user:      dholland <dholland%NetBSD.org@localhost>
date:      Mon Sep 01 21:42:21 2014 +0000

description:
Provide real error messages.
Inspired by PR 49169 from David H. Gutteridge, but a much broader patch :-)

diffstat:

 bin/date/date.c |  135 ++++++++++++++++++++++++++++++++-----------------------
 1 files changed, 79 insertions(+), 56 deletions(-)

diffs (262 lines):

diff -r 11ff42244edc -r 4b85004f09fe bin/date/date.c
--- a/bin/date/date.c   Mon Sep 01 19:46:55 2014 +0000
+++ b/bin/date/date.c   Mon Sep 01 21:42:21 2014 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: date.c,v 1.60 2011/08/27 12:55:09 joerg Exp $ */
+/* $NetBSD: date.c,v 1.61 2014/09/01 21:42:21 dholland Exp $ */
 
 /*
  * Copyright (c) 1985, 1987, 1988, 1993
@@ -40,7 +40,7 @@
 #if 0
 static char sccsid[] = "@(#)date.c     8.2 (Berkeley) 4/28/95";
 #else
-__RCSID("$NetBSD: date.c,v 1.60 2011/08/27 12:55:09 joerg Exp $");
+__RCSID("$NetBSD: date.c,v 1.61 2014/09/01 21:42:21 dholland Exp $");
 #endif
 #endif /* not lint */
 
@@ -66,9 +66,7 @@
 static time_t tval;
 static int aflag, jflag, rflag, nflag;
 
-__dead static void badformat(void);
-__dead static void badtime(void);
-__dead static void badvalue(const char *);
+__dead static void badcanotime(const char *, const char *, size_t);
 static void setthetime(const char *);
 __dead static void usage(void);
 
@@ -94,9 +92,10 @@
                case 'd':
                        rflag = 1;
                        tval = parsedate(optarg, NULL, NULL);
-                       if (tval == -1) 
-badarg:                                 errx(EXIT_FAILURE,
-                                   "Cannot parse `%s'", optarg);
+                       if (tval == -1) {
+                               errx(EXIT_FAILURE,
+                                   "%s: Unrecognized date format", optarg);
+                       }
                        break;
                case 'j':               /* don't set time */
                        jflag = 1;
@@ -105,13 +104,18 @@
                        nflag = 1;
                        break;
                case 'r':               /* user specified seconds */
+                       if (optarg[0] == '\0') {
+                               errx(EXIT_FAILURE, "<empty>: Invalid number");
+                       }
                        errno = 0;
                        val = strtoll(optarg, &buf, 0);
-                       if (optarg[0] == '\0' || *buf != '\0')
-                               goto badarg;
-                       if (errno == ERANGE && (val == LLONG_MAX ||
-                           val == LLONG_MIN))
-                               err(EXIT_FAILURE, "Bad number `%s'", optarg);
+                       if (errno) {
+                               err(EXIT_FAILURE, "%s", optarg);
+                       }
+                       if (optarg[0] == '\0' || *buf != '\0') {
+                               errx(EXIT_FAILURE,
+                                   "%s: Invalid number", optarg);
+                       }
                        rflag = 1;
                        tval = (time_t)val;
                        break;
@@ -148,7 +152,7 @@
                goto bad;
 
        if ((tm = localtime(&tval)) == NULL)
-               err(EXIT_FAILURE, "localtime %lld failed", (long long)tval);
+               err(EXIT_FAILURE, "%lld: localtime", (long long)tval);
 
        while (strftime(buf, bufsiz, format, tm) == 0)
                if ((buf = realloc(buf, bufsiz <<= 1)) == NULL)
@@ -162,23 +166,11 @@
 }
 
 static void
-badformat(void)
-{
-       warnx("illegal time format");
-       usage();
-}
-
-static void
-badtime(void)
+badcanotime(const char *msg, const char *val, size_t where)
 {
-       errx(EXIT_FAILURE, "illegal time");
-       /* NOTREACHED */
-}
-
-static void
-badvalue(const char *param)
-{
-       warnx("invalid %s supplied", param);
+       warnx("%s in canonical time", msg);
+       warnx("%s", val);
+       warnx("%*s", (int)where + 1, "^");
        usage();
 }
 
@@ -190,44 +182,52 @@
        struct timeval tv;
        time_t new_time;
        struct tm *lt;
-       const char *dot, *t;
+       const char *dot, *t, *op;
        size_t len;
        int yearset;
 
        for (t = p, dot = NULL; *t; ++t) {
-               if (isdigit((unsigned char)*t))
-                       continue;
-               if (*t == '.' && dot == NULL) {
-                       dot = t;
-                       continue;
+               if (*t == '.') {
+                       if (dot == NULL) {
+                               dot = t;
+                       } else {
+                               badcanotime("Unexpected dot", p, t - p);
+                       }
+               } else if (!isdigit((unsigned char)*t)) {
+                       badcanotime("Expected digit", p, t - p);
                }
-               badformat();
        }
 
        if ((lt = localtime(&tval)) == NULL)
-               err(EXIT_FAILURE, "localtime %lld failed", (long long)tval);
+               err(EXIT_FAILURE, "%lld: localtime", (long long)tval);
 
        lt->tm_isdst = -1;                      /* Divine correct DST */
 
        if (dot != NULL) {                      /* .ss */
                len = strlen(dot);
-               if (len != 3)
-                       badformat();
+               if (len > 3) {
+                       badcanotime("Unexpected digit after seconds field",
+                                   p, strlen(p) - 1);
+               } else if (len < 3) {
+                       badcanotime("Expected digit in seconds field",
+                                   p, strlen(p));
+               }
                ++dot;
                lt->tm_sec = ATOI2(dot);
                if (lt->tm_sec > 61)
-                       badvalue("seconds");
+                       badcanotime("Seconds out of range", p, strlen(p) - 1);
        } else {
                len = 0;
                lt->tm_sec = 0;
        }
 
+       op = p;
        yearset = 0;
        switch (strlen(p) - len) {
        case 12:                                /* cc */
                lt->tm_year = ATOI2(p) * 100 - TM_YEAR_BASE;
                if (lt->tm_year < 0)
-                       badtime();
+                       badcanotime("Year before 1900", op, p - op + 1);
                yearset = 1;
                /* FALLTHROUGH */
        case 10:                                /* yy */
@@ -244,7 +244,7 @@
        case 8:                                 /* mm */
                lt->tm_mon = ATOI2(p);
                if (lt->tm_mon > 12 || lt->tm_mon == 0)
-                       badvalue("month");
+                       badcanotime("Month out of range", op, p - op - 1);
                --lt->tm_mon;                   /* time struct is 0 - 11 */
                /* FALLTHROUGH */
        case 6:                                 /* dd */
@@ -258,47 +258,70 @@
                case 9:
                case 11:
                        if (lt->tm_mday > 31 || lt->tm_mday == 0)
-                               badvalue("day of month");
+                               badcanotime("Day out of range (max 31)",
+                                           op, p - op - 1);
                        break;
                case 3:
                case 5:
                case 8:
                case 10:
                        if (lt->tm_mday > 30 || lt->tm_mday == 0)
-                               badvalue("day of month");
+                               badcanotime("Day out of range (max 30)",
+                                           op, p - op - 1);
                        break;
                case 1:
-                       if (lt->tm_mday > 29 || lt->tm_mday == 0 ||
-                           (lt->tm_mday == 29 &&
-                            !isleap(lt->tm_year + TM_YEAR_BASE)))
-                               badvalue("day of month");
+                       if (isleap(lt->tm_year + TM_YEAR_BASE)) {
+                               if (lt->tm_mday > 29 || lt->tm_mday == 0) {
+                                       badcanotime("Day out of range "
+                                                   "(max 29)",
+                                                   op, p - op - 1);
+                               }
+                       } else {
+                               if (lt->tm_mday > 28 || lt->tm_mday == 0) {
+                                       badcanotime("Day out of range "
+                                                   "(max 28)",
+                                                   op, p - op - 1);
+                               }
+                       }
                        break;
                default:
-                       badvalue("month");
-                       break;
+                       /*
+                        * If the month was given, it's already been
+                        * checked.  If a bad value came back from
+                        * localtime, something's badly broken.
+                        * (make this an assertion?)
+                        */
+                       errx(EXIT_FAILURE, "localtime gave invalid month %d",
+                           lt->tm_mon);
                }
                /* FALLTHROUGH */
        case 4:                                 /* hh */
                lt->tm_hour = ATOI2(p);
                if (lt->tm_hour > 23)
-                       badvalue("hour");
+                       badcanotime("Hour out of range", op, p - op - 1);
                /* FALLTHROUGH */
        case 2:                                 /* mm */
                lt->tm_min = ATOI2(p);
                if (lt->tm_min > 59)
-                       badvalue("minute");
+                       badcanotime("Minute out of range", op, p - op - 1);
                break;
        case 0:                                 /* was just .sss */
                if (len != 0)
                        break;
                /* FALLTHROUGH */
        default:
-               badformat();
+           if (strlen(p) - len > 12) {
+                   badcanotime("Too many digits", p, 12);
+           } else {
+                   badcanotime("Not enough digits", p, strlen(p) - len);
+           }
        }
 
        /* convert broken-down time to UTC clock time */
-       if ((new_time = mktime(lt)) == -1)
-               badtime();
+       if ((new_time = mktime(lt)) == -1) {
+               /* Can this actually happen? */
+               err(EXIT_FAILURE, "%s: mktime", op);
+       }
 
        /* if jflag is set, don't actually change the time, just return */
        if (jflag) {



Home | Main Index | Thread Index | Old Index