From 4b7a0e138d6b067cdcceaab1e703d60008653d9b Mon Sep 17 00:00:00 2001 From: P. J. McDermott Date: Mon, 30 Aug 2021 20:48:00 -0400 Subject: datetime: Replace goto with function calls goto is fine, but this splits up a function that had grown a little long. --- diff --git a/src/datetime.c b/src/datetime.c index 6fecb82..d1a720d 100644 --- a/src/datetime.c +++ b/src/datetime.c @@ -115,6 +115,69 @@ _datetime_reset_tm(struct tm *tm) tm->tm_isdst = INT_MIN; } +static void +_datetime_normalize(struct tm *arg_tm, time_t *arg_sec) +{ + time_t now_sec; + struct tm *now_tm; + int wday; + + if (arg_tm->tm_sec == INT_MIN) { + arg_tm->tm_sec = 0; + } + if (arg_tm->tm_mday == INT_MIN && arg_tm->tm_wday == INT_MIN) { + /* No date specified; try today. */ + now_sec = time(NULL); + now_tm = localtime(&now_sec); + arg_tm->tm_year = now_tm->tm_year; + arg_tm->tm_mon = now_tm->tm_mon; + arg_tm->tm_mday = now_tm->tm_mday; + arg_tm->tm_wday = now_tm->tm_wday; + *arg_sec = mktime(arg_tm); + if (*arg_sec <= mktime(now_tm)) { + /* Specified time already happened today; use tomorrow. + * Adding the number of seconds in a day is a shortcut + * that ignores leap seconds. One better method would + * be to increment tm_mday % days in tm_mon, etc. */ + *arg_sec += 60 * 60 * 24; + now_tm = localtime(arg_sec); + arg_tm->tm_year = now_tm->tm_year; + arg_tm->tm_mon = now_tm->tm_mon; + arg_tm->tm_mday = now_tm->tm_mday; + *arg_sec = mktime(arg_tm); + } + } else if (arg_tm->tm_mday == INT_MIN) { + /* Only a weekday specified; try tomorrow or next week. Uses + * same shortcut as above. */ + wday = arg_tm->tm_wday; + now_sec = time(NULL); + now_tm = localtime(&now_sec); + arg_tm->tm_year = now_tm->tm_year; + arg_tm->tm_mon = now_tm->tm_mon; + arg_tm->tm_mday = now_tm->tm_mday; + arg_tm->tm_wday = now_tm->tm_wday; + if (wday <= now_tm->tm_wday) { + wday += 7; + } + *arg_sec = mktime(arg_tm); + *arg_sec += (60 * 60 * 24) * (wday - now_tm->tm_wday); + } else if (arg_tm->tm_year == INT_MIN) { + /* No year specified; try this year. */ + now_sec = time(NULL); + now_tm = localtime(&now_sec); + arg_tm->tm_year = now_tm->tm_year; + *arg_sec = mktime(arg_tm); + if (*arg_sec <= mktime(now_tm)) { + /* Specified time already happened this year; use next + * year. */ + ++arg_tm->tm_year; + *arg_sec = mktime(arg_tm); + } + } else { + *arg_sec = mktime(arg_tm); + } +} + int datetime_parse(const char *input, time_t *arg_sec) { @@ -125,9 +188,6 @@ datetime_parse(const char *input, time_t *arg_sec) int t; char *end; struct tm arg_tm; - time_t now_sec; - struct tm *now_tm; - int wday; date_fmt_len = strlen(DATETIME_DATE_FMTS_[0]); time_fmt_len = strlen(DATETIME_TIME_FMTS_[0]); @@ -146,7 +206,9 @@ datetime_parse(const char *input, time_t *arg_sec) _datetime_reset_tm(&arg_tm); end = strptime(input, fmt_buf, &arg_tm); if (end != NULL && *end == '\0') { - goto found; + free(fmt_buf); + _datetime_normalize(&arg_tm, arg_sec); + return 0; } } } @@ -158,7 +220,9 @@ datetime_parse(const char *input, time_t *arg_sec) _datetime_reset_tm(&arg_tm); end = strptime(input, fmt_buf, &arg_tm); if (end != NULL && *end == '\0') { - goto found; + free(fmt_buf); + _datetime_normalize(&arg_tm, arg_sec); + return 0; } } } @@ -166,71 +230,13 @@ datetime_parse(const char *input, time_t *arg_sec) _datetime_reset_tm(&arg_tm); end = strptime(input, DATETIME_MISC_FMTS_[d], &arg_tm); if (end != NULL && *end == '\0') { - goto found; + free(fmt_buf); + _datetime_normalize(&arg_tm, arg_sec); + return 0; } } free(fmt_buf); fputs("Unknown date format\n", stderr); return -1; - - found: - free(fmt_buf); - - if (arg_tm.tm_sec == INT_MIN) { - arg_tm.tm_sec = 0; - } - if (arg_tm.tm_mday == INT_MIN && arg_tm.tm_wday == INT_MIN) { - /* No date specified; try today. */ - now_sec = time(NULL); - now_tm = localtime(&now_sec); - arg_tm.tm_year = now_tm->tm_year; - arg_tm.tm_mon = now_tm->tm_mon; - arg_tm.tm_mday = now_tm->tm_mday; - arg_tm.tm_wday = now_tm->tm_wday; - *arg_sec = mktime(&arg_tm); - if (*arg_sec <= mktime(now_tm)) { - /* Specified time already happened today; use tomorrow. - * Adding the number of seconds in a day is a shortcut - * that ignores leap seconds. One better method would - * be to increment tm_mday % days in tm_mon, etc. */ - *arg_sec += 60 * 60 * 24; - now_tm = localtime(arg_sec); - arg_tm.tm_year = now_tm->tm_year; - arg_tm.tm_mon = now_tm->tm_mon; - arg_tm.tm_mday = now_tm->tm_mday; - *arg_sec = mktime(&arg_tm); - } - } else if (arg_tm.tm_mday == INT_MIN) { - /* Only a weekday specified; try tomorrow or next week. Uses - * same shortcut as above. */ - wday = arg_tm.tm_wday; - now_sec = time(NULL); - now_tm = localtime(&now_sec); - arg_tm.tm_year = now_tm->tm_year; - arg_tm.tm_mon = now_tm->tm_mon; - arg_tm.tm_mday = now_tm->tm_mday; - arg_tm.tm_wday = now_tm->tm_wday; - if (wday <= now_tm->tm_wday) { - wday += 7; - } - *arg_sec = mktime(&arg_tm); - *arg_sec += (60 * 60 * 24) * (wday - now_tm->tm_wday); - } else if (arg_tm.tm_year == INT_MIN) { - /* No year specified; try this year. */ - now_sec = time(NULL); - now_tm = localtime(&now_sec); - arg_tm.tm_year = now_tm->tm_year; - *arg_sec = mktime(&arg_tm); - if (*arg_sec <= mktime(now_tm)) { - /* Specified time already happened this year; use next - * year. */ - ++arg_tm.tm_year; - *arg_sec = mktime(&arg_tm); - } - } else { - *arg_sec = mktime(&arg_tm); - } - - return 0; } -- cgit v0.9.1