diff options
author | Jakob Kaivo <jkk@ung.org> | 2022-03-13 15:00:32 -0400 |
---|---|---|
committer | Jakob Kaivo <jkk@ung.org> | 2022-03-13 15:00:32 -0400 |
commit | 65cf227c67e1b293d7beb0ef3ecef50ad5223be8 (patch) | |
tree | 31d6fad4efaac74536ea7074310836c9384c529d /touch.c | |
parent | 19eb24378a5e7eec6e1022ef07f422033c6623db (diff) |
implement most of -d date parsing
Diffstat (limited to 'touch.c')
-rw-r--r-- | touch.c | 105 |
1 files changed, 70 insertions, 35 deletions
@@ -64,20 +64,19 @@ static int touch(const char *path, struct timespec times[2], int create) return 0; } -static int twodigits(const char *s) +static int twodigits(const char *s, int min, int max) { char buf[3] = { s[0], s[1], '\0' }; if (!(isdigit(buf[0]) && isdigit(buf[1]))) { - return -1; + fprintf(stderr, "touch: invalid time\n"); + exit(1); } - return atoi(buf); -} - -static struct timespec convert_date(const char *date) -{ - (void)date; - struct timespec ts = { 0 }; - return ts; + int ret = atoi(buf); + if (ret < min || ret > max) { + fprintf(stderr, "touch: invalid time\n"); + exit(1); + } + return ret; } static struct timespec convert_time(const char *date) @@ -92,53 +91,41 @@ static struct timespec convert_time(const char *date) char *dot = strchr(date, '.'); if (dot) { if (strlen(dot + 1) != 2) { - fprintf(stderr, "invalid time %s\n", date); + fprintf(stderr, "invalid time\n"); exit(1); } - /* TODO: 00 - 60 */ - tm->tm_sec = twodigits(dot + 1); + tm->tm_sec = twodigits(dot + 1, 0, 60); } else { tm->tm_sec = 0; } switch (strlen(date) - (dot ? 3 : 0)) { - case 12: - century = twodigits(date) - 19; + case 12: /* CC */ + century = twodigits(date, 0, 100) - 19; date += 2; /* FALLTHRU */ - case 10: - /* TODO: 00 - 99 */ + case 10: /* YY */ if (century == -1) { - tm->tm_year = twodigits(date); + tm->tm_year = twodigits(date, 0, 100); if (00 <= tm->tm_year && tm->tm_year <= 68) { tm->tm_year += 100; } } else { - tm->tm_year = (century * 100) + twodigits(date); + tm->tm_year = (century * 100) + twodigits(date, 0, 100); } date += 2; /* FALLTHRU */ - case 8: - /* TODO: 01 - 12 */ - tm->tm_mon = twodigits(date) - 1; + case 8: /* MM */ + tm->tm_mon = twodigits(date, 1, 12) - 1; date += 2; - /* FALLTHRU */ - case 6: - /* TODO: 01 - 31 */ - tm->tm_mday = twodigits(date); + tm->tm_mday = twodigits(date, 1, 31); date += 2; - /* FALLTHRU */ - case 4: - /* TODO: 00 - 23 */ - tm->tm_hour = twodigits(date); + tm->tm_hour = twodigits(date, 0, 23); date += 2; - /* FALLTHRU */ - case 2: - /* TODO: 00 - 59 */ - tm->tm_min = twodigits(date); + tm->tm_min = twodigits(date, 0, 59); break; default: - fprintf(stderr, "invalide time %s\n", date); + fprintf(stderr, "invalid time\n"); exit(1); } @@ -150,6 +137,54 @@ static struct timespec convert_time(const char *date) return ts; } +static int getnext(const char *current, char **next, size_t ndigits, char *term, int min, int max) +{ + char buf[ndigits + 1]; + for (size_t i = 0; i < ndigits; i++) { + if (!isdigit(current[i])) { + return -1; + } + buf[i] = current[i]; + } + buf[ndigits] = '\0'; + + char *end = NULL; + long ret = strtol(buf, &end, 10); + if (!strchr(term, *end)) { + fprintf(stderr, "touch: invalid date\n"); + exit(1); + } + if (ret < min || ret > max) { + fprintf(stderr, "touch: invalid date\n"); + exit(1); + } + + *next = (char*)current + ndigits + 1; + return ret; +} + +static struct timespec convert_date(const char *date) +{ + struct timespec ts = { 0 }; + struct tm tm = { 0 }; + char *next = (char*)date; + + tm.tm_year = getnext(next, &next, 4, "-", 0, 10000) - 1900; + tm.tm_mon = getnext(next, &next, 2, "-", 1, 12) - 1; + tm.tm_mday = getnext(next, &next, 2, "T ", 1, 31); + tm.tm_hour = getnext(next, &next, 2, ":", 0, 23); + tm.tm_min = getnext(next, &next, 2, ":", 0, 59); + tm.tm_sec = getnext(next, &next, 2, ".,", 0, 60); + + /* TODO: frac */ + /* TODO: tz */ + /* TODO: time is too large */ + + ts.tv_sec = mktime(&tm); + + return ts; +} + int main(int argc, char *argv[]) { setlocale(LC_ALL, ""); |