diff options
-rw-r--r-- | src/utils.c | 79 |
1 files changed, 43 insertions, 36 deletions
diff --git a/src/utils.c b/src/utils.c index 0690d4e..4758e0f 100644 --- a/src/utils.c +++ b/src/utils.c @@ -938,6 +938,13 @@ parse_date_interactive(const char *datestr, int *year, int *month, int *day) * Convert a date duration string into a number of days. * If start is non-zero, the final end time is validated. * + * Allowed formats in lenient BNF: + * <duration> ::= <days> | <period> + * <period> ::= [ <weeks>w ][ <days>d ] + * Notes: + * <days> and <weeks> are any integer >= 0. + * <period> must have at least one non-terminal. + * * Returns 1 on success and 0 on failure. */ int parse_date_duration(const char *string, unsigned *days, time_t start) @@ -996,10 +1003,8 @@ int parse_date_duration(const char *string, unsigned *days, time_t start) denom = 1; } } - if (state == STATE_DONE && in > 0) return 0; - dur += in; if (start) { /* wanted: start = start + dur * DAYINSEC */ @@ -1013,7 +1018,6 @@ int parse_date_duration(const char *string, unsigned *days, time_t start) return 0; } *days = dur; - return 1; } @@ -1027,7 +1031,9 @@ int check_time(unsigned hours, unsigned minutes) /* * Converts a time string into hours and minutes. Short forms like "23:" - * (23:00) or ":45" (0:45) are allowed. + * (23:00) or ":45" (0:45) are allowed as well as "2345". Note: the latter + * clashes with date formats 0001 .. 0031 and must be picked up before + * dates when parsing in parse_datetime. * * Returns 1 on success and 0 on failure. */ @@ -1044,14 +1050,18 @@ int parse_time(const char *string, unsigned *hour, unsigned *minute) if (*p == ':') { if ((++n) > 1) return 0; - } else if ((*p >= '0') && (*p <= '9')) { - if ((n == 0) && (p == (string + 2)) && *(p + 1)) - n++; - in[n] = in[n] * 10 + (int)(*p - '0'); + } else if (isdigit(*p)) { + in[n] = in[n] * 10 + *p - '0'; } else { return 0; } } + /* 24-hour format without ':' (hhmm)? */ + if (n == 0 && strlen(string) == 4) { + in[1] = in[0] % 100; + in[0] = in[0] / 100; + n = 1; + } if (n != 1 || !check_time(in[0], in[1])) return 0; @@ -1065,13 +1075,15 @@ int parse_time(const char *string, unsigned *hour, unsigned *minute) * Converts a duration string into minutes. * If start time is non-zero, the final end time is validated. * - * Allowed formats (noted as regular expressions): - * - * - \d*:\d* - * - (\d*m|\d*h(|\d*m)|\d*d(|\d*m|\d*h(|\d*m))) - * - \d+ - * - * "\d" is used as a placeholder for "(0|1|2|3|4|5|6|7|8|9)". + * Allowed formats in lenient BNF: + * <duration> ::= <minutes> | <time> | <period> + * <time> ::= <hours>:<min> + * <period> ::= [ <days>d ][ <hours>h ][ <minutes>m ] + * <min> ::= integer in the range 0-59 + * Notes: + * <days>, <hours> and <minutes> are any sequence of + * the characters 1,2,..,9,0. + * <period> must have at least one non-terminal. * * Returns 1 on success and 0 on failure. */ @@ -1144,7 +1156,6 @@ int parse_duration(const char *string, unsigned *duration, time_t start) break; case STATE_HHMM_MM: return 0; - break; default: break; } @@ -1154,8 +1165,7 @@ int parse_duration(const char *string, unsigned *duration, time_t start) } } if ((state == STATE_HHMM_MM && in >= HOURINMIN) || - ((state == STATE_DDHHMM_HH || state == STATE_DDHHMM_MM) - && in > 0)) + ((state == STATE_DDHHMM_HH || state == STATE_DDHHMM_MM) && in > 0)) return 0; dur += in; if (start) { @@ -1171,7 +1181,6 @@ int parse_duration(const char *string, unsigned *duration, time_t start) return 0; } *duration = dur; - return 1; } @@ -1192,37 +1201,35 @@ int parse_duration(const char *string, unsigned *duration, time_t start) */ int parse_datetime(const char *string, time_t *ts, time_t dur) { - char *t = mem_strdup(string); - char *p = strchr(t, ' '); - - unsigned int hour, minute; + unsigned hour, minute; int year, month, day; - struct date new_date; int ret = 0; - if (p) { - *p = '\0'; - if (parse_date_interactive(t, &year, &month, &day) && - parse_time(p + 1, &hour, &minute)) { + char *d = mem_strdup(string); + /* Split into date and time, if possible. */ + char *t = strchr(d, ' '); + if (t) + *t++ = '\0'; + if (t) { + if (parse_date_interactive(d, &year, &month, &day) && + parse_time(t, &hour, &minute)) { ret |= PARSE_DATETIME_HAS_DATE | PARSE_DATETIME_HAS_TIME; } - } else if (parse_time(t, &hour, &minute)) { + /* Time before date, see comments in parse_time(). */ + } else if (parse_time(d, &hour, &minute)) { ret |= PARSE_DATETIME_HAS_TIME; - } else if (parse_date_interactive(t, &year, &month, &day)) { + } else if (parse_date_interactive(d, &year, &month, &day)) { ret |= PARSE_DATETIME_HAS_DATE; } - if (ret & PARSE_DATETIME_HAS_DATE) { - new_date.dd = day; - new_date.mm = month; - new_date.yyyy = year; - *ts = date2sec(new_date, 0, 0) + get_item_time(*ts); + struct date date = { day , month, year }; + *ts = date2sec(date, 0, 0) + get_item_time(*ts); } if (ret & PARSE_DATETIME_HAS_TIME) *ts = update_time_in_date(*ts, hour, minute); + mem_free(d); - mem_free(t); /* Is the resulting time a valid (start or end) time? */ if (!check_sec(ts)) return 0; |