From 9f3d8aa80fa4d7216106610b077b6d6e4e6dbed4 Mon Sep 17 00:00:00 2001 From: Rob Landley Date: Tue, 18 Oct 2016 04:10:01 -0500 Subject: 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). --- tests/touch.test | 5 ++++ toys/posix/touch.c | 77 ++++++++++++++++++++++++------------------------------ 2 files changed, 39 insertions(+), 43 deletions(-) diff --git a/tests/touch.test b/tests/touch.test index d193d7cc..d5bef815 100755 --- a/tests/touch.test +++ b/tests/touch.test @@ -35,6 +35,11 @@ testing "-r" \ "touch -r walrus walrus2 && date -r walrus2 +%s.%N" \ "1234567890.123456789\n" "" "" +# Yes, the year could roll over while you're running this test. I do not care. +testing "-t MMDDhhmm" \ + "touch -t 01231234 input && date +%Y-%m-%d:%H-%M-%S -r input" \ + "$(date +%Y)-01-23:12-34-00\n" "" "" + #testing "-a" #testing "-m" #testing "-am" 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 * * 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; -- cgit v1.2.3