diff options
author | Rob Landley <rob@landley.net> | 2016-10-18 04:10:01 -0500 |
---|---|---|
committer | Rob Landley <rob@landley.net> | 2016-10-18 04:10:01 -0500 |
commit | 9f3d8aa80fa4d7216106610b077b6d6e4e6dbed4 (patch) | |
tree | b0694d1c750be7340583dcd39dbc0dd4ecf82238 /toys | |
parent | 64cbbab181749f85f3bcdb8576c5d530c453db84 (diff) | |
download | toybox-9f3d8aa80fa4d7216106610b077b6d6e4e6dbed4.tar.gz |
Unify touch -t and -d handling, allow posix's underspecified "time designator"
T to be a space instead (because the posix says so, no idea why), initialize
default values reliably including zeroing daylight savings time field (which is
handled inconsistently by libc and just screws stuff up).
Diffstat (limited to 'toys')
-rw-r--r-- | toys/posix/touch.c | 77 |
1 files changed, 34 insertions, 43 deletions
diff --git a/toys/posix/touch.c b/toys/posix/touch.c index cd7dd53d..79928cee 100644 --- a/toys/posix/touch.c +++ b/toys/posix/touch.c @@ -3,8 +3,6 @@ * Copyright 2012 Choubey Ji <warior.linux@gmail.com> * * See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/touch.html - * - * TODO: have another go at merging the -t and -d stanzas USE_TOUCH(NEWTOY(touch, "acd:mr:t:h[!dtr]", TOYFLAG_BIN)) @@ -43,56 +41,49 @@ void touch_main(void) // use current time if no -t or -d ts[0].tv_nsec = UTIME_NOW; if (toys.optflags & (FLAG_t|FLAG_d)) { - char *s, *date; + char *s, *date, **format; struct tm tm; int len = 0; - localtime_r(&(ts->tv_sec), &tm); - - // Set time from -d? + // Initialize default values for time fields + ts->tv_sec = time(0); + ts->tv_nsec = 0; + // List of search types if (toys.optflags & FLAG_d) { + format = (char *[]){"%Y-%m-%dT%T", "%Y-%m-%d %T", 0}; date = TT.date; - i = strlen(date); - if (i) { - // Trailing Z means UTC timezone, don't expect libc to know this. - if (toupper(date[i-1])=='Z') { - date[i-1] = 0; - setenv("TZ", "UTC0", 1); - localtime_r(&(ts->tv_sec), &tm); - } - s = strptime(date, "%Y-%m-%dT%T", &tm); - ts->tv_nsec = 0; - if (s && *s=='.' && isdigit(s[1])) - sscanf(s, ".%lu%n", &ts->tv_nsec, &len); - else len = 0; - } else s = 0; - - // Set time from -t? - } else { - strcpy(toybuf, "%Y%m%d%H%M"); + format = (char *[]){"%Y%m%d%H%M", "%m%d%H%M", "%y%m%d%H%M", 0}; date = TT.time; - i = ((s = strchr(date, '.'))) ? s-date : strlen(date); - if (i < 8 || i%2) error_exit("bad '%s'", date); - for (i=0;i<3;i++) { - s = strptime(date, toybuf+(i&2), &tm); - if (s) break; - toybuf[1]='y'; - } - tm.tm_sec = 0; - ts->tv_nsec = 0; - if (s && *s=='.' && sscanf(s, ".%2u%n", &(tm.tm_sec), &len) == 1) { - if (sscanf(s += len, "%lu%n", &ts->tv_nsec, &len) == 1) { - s--; - len++; - } else len = 0; - } else len = 0; } - if (len) { - s += len; - if (ts->tv_nsec > 999999999) s = 0; - else while (len++ < 10) ts->tv_nsec *= 10; + + // Trailing Z means UTC timezone, don't expect libc to know this. + i = strlen(s = date); + if (i && toupper(date[i-1])=='Z') { + date[i-1] = 0; + setenv("TZ", "UTC0", 1); + } + + while (*format) { + localtime_r(&(ts->tv_sec), &tm); + // Adjusting for daylight savings time gives the wrong answer. + tm.tm_isdst = 0; + tm.tm_sec = 0; + s = strptime(date, *format++, &tm); + + // parse nanoseconds + if (s && *s=='.' && isdigit(s[1])) { + s++; + if (toys.optflags&FLAG_t) + if (1 == sscanf(s, "%2u%n", &(tm.tm_sec), &len)) s += len; + if (1 == sscanf(s, "%lu%n", &ts->tv_nsec, &len)) { + s += len; + if (ts->tv_nsec > 999999999) s = 0; + else while (len++ < 9) ts->tv_nsec *= 10; + } + } + if (s && !*s) break; } errno = 0; |