aboutsummaryrefslogtreecommitdiff
path: root/toys/posix/touch.c
diff options
context:
space:
mode:
authorRob Landley <rob@landley.net>2016-10-18 04:10:01 -0500
committerRob Landley <rob@landley.net>2016-10-18 04:10:01 -0500
commit9f3d8aa80fa4d7216106610b077b6d6e4e6dbed4 (patch)
treeb0694d1c750be7340583dcd39dbc0dd4ecf82238 /toys/posix/touch.c
parent64cbbab181749f85f3bcdb8576c5d530c453db84 (diff)
downloadtoybox-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/posix/touch.c')
-rw-r--r--toys/posix/touch.c77
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;