1 /*
2  * parse time string - user friendly date and time parser
3  * Copyright © 2012 Jani Nikula
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
17  *
18  * Author: Jani Nikula <jani@nikula.org>
19  */
20 
21 #include <assert.h>
22 #include <ctype.h>
23 #include <errno.h>
24 #include <limits.h>
25 #include <stdio.h>
26 #include <stdarg.h>
27 #include <stdbool.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <strings.h>
31 #include <time.h>
32 #include <sys/time.h>
33 #include <sys/types.h>
34 
35 #include "compat.h"
36 #include "parse-time-string.h"
37 
38 /*
39  * IMPLEMENTATION DETAILS
40  *
41  * At a high level, the parsing is done in two phases: 1) actual
42  * parsing of the input string and storing the parsed data into
43  * 'struct state', and 2) processing of the data in 'struct state'
44  * according to current time (or provided reference time) and
45  * rounding. This is evident in the main entry point function
46  * parse_time_string().
47  *
48  * 1) The parsing phase - parse_input()
49  *
50  * Parsing is greedy and happens from left to right. The parsing is as
51  * unambiguous as possible; only unambiguous date/time formats are
52  * accepted. Redundant or contradictory absolute date/time in the
53  * input (e.g. date specified multiple times/ways) is not
54  * accepted. Relative date/time on the other hand just accumulates if
55  * present multiple times (e.g. "5 days 5 days" just turns into 10
56  * days).
57  *
58  * Parsing decisions are made on the input format, not value. For
59  * example, "20/5/2005" fails because the recognized format here is
60  * MM/D/YYYY, even though the values would suggest DD/M/YYYY.
61  *
62  * Parsing is mostly stateless in the sense that parsing decisions are
63  * not made based on the values of previously parsed data, or whether
64  * certain data is present in the first place. (There are a few
65  * exceptions to the latter part, though, such as parsing of time zone
66  * that would otherwise look like plain time.)
67  *
68  * When the parser encounters a number that is not greedily parsed as
69  * part of a format, the interpretation is postponed until the next
70  * token is parsed. The parser for the next token may consume the
71  * previously postponed number. For example, when parsing "20 May" the
72  * meaning of "20" is not known until "May" is parsed. If the parser
73  * for the next token does not consume the postponed number, the
74  * number is handled as a "lone" number before parser for the next
75  * token finishes.
76  *
77  * 2) The processing phase - create_output()
78  *
79  * Once the parser in phase 1 has finished, 'struct state' contains
80  * all the information from the input string, and it's no longer
81  * needed. Since the parser does not even handle the concept of "now",
82  * the processing initializes the fields referring to the current
83  * date/time.
84  *
85  * If requested, the result is rounded towards past or future. The
86  * idea behind rounding is to support parsing date/time ranges in an
87  * obvious way. For example, for a range defined as two dates (without
88  * time), one would typically want to have an inclusive range from the
89  * beginning of start date to the end of the end date. The caller
90  * would use rounding towards past in the start date, and towards
91  * future in the end date.
92  *
93  * The absolute date and time is shifted by the relative date and
94  * time, and time zone adjustments are made. Daylight saving time
95  * (DST) is specifically *not* handled at all.
96  *
97  * Finally, the result is stored to time_t.
98  */
99 
100 #define unused(x) x __attribute__ ((unused))
101 
102 /* XXX: Redefine these to add i18n support. The keyword table uses
103  * N_() to mark strings to be translated; they are accessed
104  * dynamically using _(). */
105 #define _(s) (s)        /* i18n: define as gettext (s) */
106 #define N_(s) (s)       /* i18n: define as gettext_noop (s) */
107 
108 #define ARRAY_SIZE(a) (sizeof (a) / sizeof (a[0]))
109 
110 /*
111  * Field indices in the tm and set arrays of struct state.
112  *
113  * NOTE: There's some code that depends on the ordering of this enum.
114  */
115 enum field {
116     /* Keep SEC...YEAR in this order. */
117     TM_ABS_SEC,         /* seconds */
118     TM_ABS_MIN,         /* minutes */
119     TM_ABS_HOUR,        /* hours */
120     TM_ABS_MDAY,        /* day of the month */
121     TM_ABS_MON,         /* month */
122     TM_ABS_YEAR,        /* year */
123 
124     TM_WDAY,            /* day of the week. special: may be relative */
125     TM_ABS_ISDST,       /* daylight saving time */
126 
127     TM_AMPM,            /* am vs. pm */
128     TM_TZ,              /* timezone in minutes */
129 
130     /* Keep SEC...YEAR in this order. */
131     TM_REL_SEC,         /* seconds relative to absolute or reference time */
132     TM_REL_MIN,         /* minutes ... */
133     TM_REL_HOUR,        /* hours ... */
134     TM_REL_DAY,         /* days ... */
135     TM_REL_MON,         /* months ... */
136     TM_REL_YEAR,        /* years ... */
137     TM_REL_WEEK,        /* weeks ... */
138 
139     TM_NONE,            /* not a field */
140 
141     TM_SIZE		= TM_NONE,
142     TM_FIRST_ABS	= TM_ABS_SEC,
143     TM_FIRST_REL	= TM_REL_SEC,
144 };
145 
146 /* Values for the set array of struct state. */
147 enum field_set {
148     FIELD_UNSET,        /* The field has not been touched by parser. */
149     FIELD_SET,          /* The field has been set by parser. */
150     FIELD_NOW,          /* The field will be set to reference time. */
151 };
152 
153 static enum field
next_abs_field(enum field field)154 next_abs_field (enum field field)
155 {
156     /* NOTE: Depends on the enum ordering. */
157     return field < TM_ABS_YEAR ? field + 1 : TM_NONE;
158 }
159 
160 static enum field
abs_to_rel_field(enum field field)161 abs_to_rel_field (enum field field)
162 {
163     assert (field <= TM_ABS_YEAR);
164 
165     /* NOTE: Depends on the enum ordering. */
166     return field + (TM_FIRST_REL - TM_FIRST_ABS);
167 }
168 
169 /* Get the smallest acceptable value for field. */
170 static int
get_field_epoch_value(enum field field)171 get_field_epoch_value (enum field field)
172 {
173     if (field == TM_ABS_MDAY || field == TM_ABS_MON)
174 	return 1;
175     else if (field == TM_ABS_YEAR)
176 	return 1970;
177     else
178 	return 0;
179 }
180 
181 /* The parsing state. */
182 struct state {
183     int tm[TM_SIZE];                    /* parsed date and time */
184     enum field_set set[TM_SIZE];        /* set status of tm */
185 
186     enum field last_field;              /* Previously set field. */
187     char delim;
188 
189     int postponed_length;               /* Number of digits in postponed value. */
190     int postponed_value;
191     char postponed_delim;               /* The delimiter preceding postponed number. */
192 };
193 
194 /*
195  * Helpers for postponed numbers.
196  *
197  * postponed_length is the number of digits in postponed value. 0
198  * means there is no postponed number. -1 means there is a postponed
199  * number, but it comes from a keyword, and it doesn't have digits.
200  */
201 static int
get_postponed_length(struct state * state)202 get_postponed_length (struct state *state)
203 {
204     return state->postponed_length;
205 }
206 
207 /*
208  * Consume a previously postponed number. Return true if a number was
209  * in fact postponed, false otherwise. Store the postponed number's
210  * value in *v, length in the input string in *n (or -1 if the number
211  * was written out and parsed as a keyword), and the preceding
212  * delimiter to *d. If a number was not postponed, *v, *n and *d are
213  * unchanged.
214  */
215 static bool
consume_postponed_number(struct state * state,int * v,int * n,char * d)216 consume_postponed_number (struct state *state, int *v, int *n, char *d)
217 {
218     if (! state->postponed_length)
219 	return false;
220 
221     if (n)
222 	*n = state->postponed_length;
223 
224     if (v)
225 	*v = state->postponed_value;
226 
227     if (d)
228 	*d = state->postponed_delim;
229 
230     state->postponed_length = 0;
231     state->postponed_value = 0;
232     state->postponed_delim = 0;
233 
234     return true;
235 }
236 
237 static int parse_postponed_number (struct state *state, enum field next_field);
238 
239 /*
240  * Postpone a number to be handled later. If one exists already,
241  * handle it first. n may be -1 to indicate a keyword that has no
242  * number length.
243  */
244 static int
set_postponed_number(struct state * state,int v,int n)245 set_postponed_number (struct state *state, int v, int n)
246 {
247     int r;
248     char d = state->delim;
249 
250     /* Parse a previously postponed number, if any. */
251     r = parse_postponed_number (state, TM_NONE);
252     if (r)
253 	return r;
254 
255     state->postponed_length = n;
256     state->postponed_value = v;
257     state->postponed_delim = d;
258 
259     return 0;
260 }
261 
262 static void
set_delim(struct state * state,char delim)263 set_delim (struct state *state, char delim)
264 {
265     state->delim = delim;
266 }
267 
268 static void
unset_delim(struct state * state)269 unset_delim (struct state *state)
270 {
271     state->delim = 0;
272 }
273 
274 /*
275  * Field set/get/mod helpers.
276  */
277 
278 /* Return true if field has been set. */
279 static bool
is_field_set(struct state * state,enum field field)280 is_field_set (struct state *state, enum field field)
281 {
282     assert (field < ARRAY_SIZE (state->tm));
283 
284     return state->set[field] != FIELD_UNSET;
285 }
286 
287 static void
unset_field(struct state * state,enum field field)288 unset_field (struct state *state, enum field field)
289 {
290     assert (field < ARRAY_SIZE (state->tm));
291 
292     state->set[field] = FIELD_UNSET;
293     state->tm[field] = 0;
294 }
295 
296 /*
297  * Set field to value. A field can only be set once to ensure the
298  * input does not contain redundant and potentially conflicting data.
299  */
300 static int
set_field(struct state * state,enum field field,int value)301 set_field (struct state *state, enum field field, int value)
302 {
303     int r;
304 
305     /* Fields can only be set once. */
306     if (is_field_set (state, field))
307 	return -PARSE_TIME_ERR_ALREADYSET;
308 
309     state->set[field] = FIELD_SET;
310 
311     /* Parse a previously postponed number, if any. */
312     r = parse_postponed_number (state, field);
313     if (r)
314 	return r;
315 
316     unset_delim (state);
317 
318     state->tm[field] = value;
319     state->last_field = field;
320 
321     return 0;
322 }
323 
324 /*
325  * Mark n fields in fields to be set to the reference date/time in the
326  * specified time zone, or local timezone if not specified. The fields
327  * will be initialized after parsing is complete and timezone is
328  * known.
329  */
330 static int
set_fields_to_now(struct state * state,enum field * fields,size_t n)331 set_fields_to_now (struct state *state, enum field *fields, size_t n)
332 {
333     size_t i;
334     int r;
335 
336     for (i = 0; i < n; i++) {
337 	r = set_field (state, fields[i], 0);
338 	if (r)
339 	    return r;
340 	state->set[fields[i]] = FIELD_NOW;
341     }
342 
343     return 0;
344 }
345 
346 /* Modify field by adding value to it. To be used on relative fields,
347  * which can be modified multiple times (to accumulate). */
348 static int
add_to_field(struct state * state,enum field field,int value)349 add_to_field (struct state *state, enum field field, int value)
350 {
351     int r;
352 
353     assert (field < ARRAY_SIZE (state->tm));
354 
355     state->set[field] = FIELD_SET;
356 
357     /* Parse a previously postponed number, if any. */
358     r = parse_postponed_number (state, field);
359     if (r)
360 	return r;
361 
362     unset_delim (state);
363 
364     state->tm[field] += value;
365     state->last_field = field;
366 
367     return 0;
368 }
369 
370 /*
371  * Get field value. Make sure the field is set before query. It's most
372  * likely an error to call this while parsing (for example fields set
373  * as FIELD_NOW will only be set to some value after parsing).
374  */
375 static int
get_field(struct state * state,enum field field)376 get_field (struct state *state, enum field field)
377 {
378     assert (field < ARRAY_SIZE (state->tm));
379 
380     return state->tm[field];
381 }
382 
383 /*
384  * Validity checkers.
385  */
386 static bool
is_valid_12hour(int h)387 is_valid_12hour (int h)
388 {
389     return h >= 1 && h <= 12;
390 }
391 
392 static bool
is_valid_time(int h,int m,int s)393 is_valid_time (int h, int m, int s)
394 {
395     /* Allow 24:00:00 to denote end of day. */
396     if (h == 24 && m == 0 && s == 0)
397 	return true;
398 
399     return h >= 0 && h <= 23 && m >= 0 && m <= 59 && s >= 0 && s <= 59;
400 }
401 
402 static bool
is_valid_mday(int mday)403 is_valid_mday (int mday)
404 {
405     return mday >= 1 && mday <= 31;
406 }
407 
408 static bool
is_valid_mon(int mon)409 is_valid_mon (int mon)
410 {
411     return mon >= 1 && mon <= 12;
412 }
413 
414 static bool
is_valid_year(int year)415 is_valid_year (int year)
416 {
417     return year >= 1970;
418 }
419 
420 static bool
is_valid_date(int year,int mon,int mday)421 is_valid_date (int year, int mon, int mday)
422 {
423     return is_valid_year (year) && is_valid_mon (mon) && is_valid_mday (mday);
424 }
425 
426 /* Unset indicator for time and date set helpers. */
427 #define UNSET -1
428 
429 /* Time set helper. No input checking. Use UNSET (-1) to leave unset. */
430 static int
set_abs_time(struct state * state,int hour,int min,int sec)431 set_abs_time (struct state *state, int hour, int min, int sec)
432 {
433     int r;
434 
435     if (hour != UNSET) {
436 	if ((r = set_field (state, TM_ABS_HOUR, hour)))
437 	    return r;
438     }
439 
440     if (min != UNSET) {
441 	if ((r = set_field (state, TM_ABS_MIN, min)))
442 	    return r;
443     }
444 
445     if (sec != UNSET) {
446 	if ((r = set_field (state, TM_ABS_SEC, sec)))
447 	    return r;
448     }
449 
450     return 0;
451 }
452 
453 /* Date set helper. No input checking. Use UNSET (-1) to leave unset. */
454 static int
set_abs_date(struct state * state,int year,int mon,int mday)455 set_abs_date (struct state *state, int year, int mon, int mday)
456 {
457     int r;
458 
459     if (year != UNSET) {
460 	if ((r = set_field (state, TM_ABS_YEAR, year)))
461 	    return r;
462     }
463 
464     if (mon != UNSET) {
465 	if ((r = set_field (state, TM_ABS_MON, mon)))
466 	    return r;
467     }
468 
469     if (mday != UNSET) {
470 	if ((r = set_field (state, TM_ABS_MDAY, mday)))
471 	    return r;
472     }
473 
474     return 0;
475 }
476 
477 /*
478  * Keyword parsing and handling.
479  */
480 struct keyword;
481 typedef int (*setter_t)(struct state *state, struct keyword *kw);
482 
483 struct keyword {
484     const char *name;   /* keyword */
485     enum field field;   /* field to set, or FIELD_NONE if N/A */
486     int value;          /* value to set, or 0 if N/A */
487     setter_t set;       /* function to use for setting, if non-NULL */
488 };
489 
490 /*
491  * Setter callback functions for keywords.
492  */
493 static int
kw_set_rel(struct state * state,struct keyword * kw)494 kw_set_rel (struct state *state, struct keyword *kw)
495 {
496     int multiplier = 1;
497 
498     /* Get a previously set multiplier, if any. */
499     consume_postponed_number (state, &multiplier, NULL, NULL);
500 
501     /* Accumulate relative field values. */
502     return add_to_field (state, kw->field, multiplier * kw->value);
503 }
504 
505 static int
kw_set_number(struct state * state,struct keyword * kw)506 kw_set_number (struct state *state, struct keyword *kw)
507 {
508     /* -1 = no length, from keyword. */
509     return set_postponed_number (state, kw->value, -1);
510 }
511 
512 static int
kw_set_month(struct state * state,struct keyword * kw)513 kw_set_month (struct state *state, struct keyword *kw)
514 {
515     int n = get_postponed_length (state);
516 
517     /* Consume postponed number if it could be mday. This handles "20
518      * January". */
519     if (n == 1 || n == 2) {
520 	int r, v;
521 
522 	consume_postponed_number (state, &v, NULL, NULL);
523 
524 	if (! is_valid_mday (v))
525 	    return -PARSE_TIME_ERR_INVALIDDATE;
526 
527 	r = set_field (state, TM_ABS_MDAY, v);
528 	if (r)
529 	    return r;
530     }
531 
532     return set_field (state, kw->field, kw->value);
533 }
534 
535 static int
kw_set_ampm(struct state * state,struct keyword * kw)536 kw_set_ampm (struct state *state, struct keyword *kw)
537 {
538     int n = get_postponed_length (state);
539 
540     /* Consume postponed number if it could be hour. This handles
541      * "5pm". */
542     if (n == 1 || n == 2) {
543 	int r, v;
544 
545 	consume_postponed_number (state, &v, NULL, NULL);
546 
547 	if (! is_valid_12hour (v))
548 	    return -PARSE_TIME_ERR_INVALIDTIME;
549 
550 	r = set_abs_time (state, v, 0, 0);
551 	if (r)
552 	    return r;
553     }
554 
555     return set_field (state, kw->field, kw->value);
556 }
557 
558 static int
kw_set_timeofday(struct state * state,struct keyword * kw)559 kw_set_timeofday (struct state *state, struct keyword *kw)
560 {
561     return set_abs_time (state, kw->value, 0, 0);
562 }
563 
564 static int
kw_set_today(struct state * state,unused (struct keyword * kw))565 kw_set_today (struct state *state, unused (struct keyword *kw))
566 {
567     enum field fields[] = { TM_ABS_YEAR, TM_ABS_MON, TM_ABS_MDAY };
568 
569     return set_fields_to_now (state, fields, ARRAY_SIZE (fields));
570 }
571 
572 static int
kw_set_now(struct state * state,unused (struct keyword * kw))573 kw_set_now (struct state *state, unused (struct keyword *kw))
574 {
575     enum field fields[] = { TM_ABS_HOUR, TM_ABS_MIN, TM_ABS_SEC };
576 
577     return set_fields_to_now (state, fields, ARRAY_SIZE (fields));
578 }
579 
580 static int
kw_set_ordinal(struct state * state,struct keyword * kw)581 kw_set_ordinal (struct state *state, struct keyword *kw)
582 {
583     int n, v;
584 
585     /* Require a postponed number. */
586     if (! consume_postponed_number (state, &v, &n, NULL))
587 	return -PARSE_TIME_ERR_DATEFORMAT;
588 
589     /* Ordinals are mday. */
590     if (n != 1 && n != 2)
591 	return -PARSE_TIME_ERR_DATEFORMAT;
592 
593     /* Be strict about st, nd, rd, and lax about th. */
594     if (strcasecmp (kw->name, "st") == 0 && v != 1 && v != 21 && v != 31)
595 	return -PARSE_TIME_ERR_INVALIDDATE;
596     else if (strcasecmp (kw->name, "nd") == 0 && v != 2 && v != 22)
597 	return -PARSE_TIME_ERR_INVALIDDATE;
598     else if (strcasecmp (kw->name, "rd") == 0 && v != 3 && v != 23)
599 	return -PARSE_TIME_ERR_INVALIDDATE;
600     else if (strcasecmp (kw->name, "th") == 0 && ! is_valid_mday (v))
601 	return -PARSE_TIME_ERR_INVALIDDATE;
602 
603     return set_field (state, TM_ABS_MDAY, v);
604 }
605 
606 static int
kw_ignore(unused (struct state * state),unused (struct keyword * kw))607 kw_ignore (unused (struct state *state), unused (struct keyword *kw))
608 {
609     return 0;
610 }
611 
612 /*
613  * Accepted keywords.
614  *
615  * A keyword may optionally contain a '|' to indicate the minimum
616  * match length. Without one, full match is required. It's advisable
617  * to keep the minimum match parts unique across all keywords. If
618  * they're not, the first match wins.
619  *
620  * If keyword begins with '*', then the matching will be case
621  * sensitive. Otherwise the matching is case insensitive.
622  *
623  * If .set is NULL, the field specified by .field will be set to
624  * .value.
625  *
626  * Note: Observe how "m" and "mi" match minutes, "M" and "mo" and
627  * "mont" match months, but "mon" matches Monday.
628  */
629 static struct keyword keywords[] = {
630     /* Weekdays. */
631     { N_ ("sun|day"),    TM_WDAY,        0,      NULL },
632     { N_ ("mon|day"),    TM_WDAY,        1,      NULL },
633     { N_ ("tue|sday"),   TM_WDAY,        2,      NULL },
634     { N_ ("wed|nesday"), TM_WDAY,        3,      NULL },
635     { N_ ("thu|rsday"),  TM_WDAY,        4,      NULL },
636     { N_ ("fri|day"),    TM_WDAY,        5,      NULL },
637     { N_ ("sat|urday"),  TM_WDAY,        6,      NULL },
638 
639     /* Months. */
640     { N_ ("jan|uary"),   TM_ABS_MON,     1,      kw_set_month },
641     { N_ ("feb|ruary"),  TM_ABS_MON,     2,      kw_set_month },
642     { N_ ("mar|ch"),     TM_ABS_MON,     3,      kw_set_month },
643     { N_ ("apr|il"),     TM_ABS_MON,     4,      kw_set_month },
644     { N_ ("may"),        TM_ABS_MON,     5,      kw_set_month },
645     { N_ ("jun|e"),      TM_ABS_MON,     6,      kw_set_month },
646     { N_ ("jul|y"),      TM_ABS_MON,     7,      kw_set_month },
647     { N_ ("aug|ust"),    TM_ABS_MON,     8,      kw_set_month },
648     { N_ ("sep|tember"), TM_ABS_MON,     9,      kw_set_month },
649     { N_ ("oct|ober"),   TM_ABS_MON,     10,     kw_set_month },
650     { N_ ("nov|ember"),  TM_ABS_MON,     11,     kw_set_month },
651     { N_ ("dec|ember"),  TM_ABS_MON,     12,     kw_set_month },
652 
653     /* Durations. */
654     { N_ ("y|ears"),     TM_REL_YEAR,    1,      kw_set_rel },
655     { N_ ("mo|nths"),    TM_REL_MON,     1,      kw_set_rel },
656     { N_ ("*M"),         TM_REL_MON,     1,      kw_set_rel },
657     { N_ ("w|eeks"),     TM_REL_WEEK,    1,      kw_set_rel },
658     { N_ ("d|ays"),      TM_REL_DAY,     1,      kw_set_rel },
659     { N_ ("h|ours"),     TM_REL_HOUR,    1,      kw_set_rel },
660     { N_ ("hr|s"),       TM_REL_HOUR,    1,      kw_set_rel },
661     { N_ ("mi|nutes"),   TM_REL_MIN,     1,      kw_set_rel },
662     { N_ ("mins"),       TM_REL_MIN,     1,      kw_set_rel },
663     { N_ ("*m"),         TM_REL_MIN,     1,      kw_set_rel },
664     { N_ ("s|econds"),   TM_REL_SEC,     1,      kw_set_rel },
665     { N_ ("secs"),       TM_REL_SEC,     1,      kw_set_rel },
666 
667     /* Numbers. */
668     { N_ ("one"),        TM_NONE,        1,      kw_set_number },
669     { N_ ("two"),        TM_NONE,        2,      kw_set_number },
670     { N_ ("three"),      TM_NONE,        3,      kw_set_number },
671     { N_ ("four"),       TM_NONE,        4,      kw_set_number },
672     { N_ ("five"),       TM_NONE,        5,      kw_set_number },
673     { N_ ("six"),        TM_NONE,        6,      kw_set_number },
674     { N_ ("seven"),      TM_NONE,        7,      kw_set_number },
675     { N_ ("eight"),      TM_NONE,        8,      kw_set_number },
676     { N_ ("nine"),       TM_NONE,        9,      kw_set_number },
677     { N_ ("ten"),        TM_NONE,        10,     kw_set_number },
678     { N_ ("dozen"),      TM_NONE,        12,     kw_set_number },
679     { N_ ("hundred"),    TM_NONE,        100,    kw_set_number },
680 
681     /* Special number forms. */
682     { N_ ("this"),       TM_NONE,        0,      kw_set_number },
683     { N_ ("last"),       TM_NONE,        1,      kw_set_number },
684 
685     /* Other special keywords. */
686     { N_ ("yesterday"),  TM_REL_DAY,     1,      kw_set_rel },
687     { N_ ("today"),      TM_NONE,        0,      kw_set_today },
688     { N_ ("now"),        TM_NONE,        0,      kw_set_now },
689     { N_ ("noon"),       TM_NONE,        12,     kw_set_timeofday },
690     { N_ ("midnight"),   TM_NONE,        0,      kw_set_timeofday },
691     { N_ ("am"),         TM_AMPM,        0,      kw_set_ampm },
692     { N_ ("a.m."),       TM_AMPM,        0,      kw_set_ampm },
693     { N_ ("pm"),         TM_AMPM,        1,      kw_set_ampm },
694     { N_ ("p.m."),       TM_AMPM,        1,      kw_set_ampm },
695     { N_ ("st"),         TM_NONE,        0,      kw_set_ordinal },
696     { N_ ("nd"),         TM_NONE,        0,      kw_set_ordinal },
697     { N_ ("rd"),         TM_NONE,        0,      kw_set_ordinal },
698     { N_ ("th"),         TM_NONE,        0,      kw_set_ordinal },
699     { N_ ("ago"),        TM_NONE,        0,      kw_ignore },
700 
701     /* Timezone codes: offset in minutes. XXX: Add more codes. */
702     { N_ ("pst"),        TM_TZ,          -8 * 60,  NULL },
703     { N_ ("mst"),        TM_TZ,          -7 * 60,  NULL },
704     { N_ ("cst"),        TM_TZ,          -6 * 60,  NULL },
705     { N_ ("est"),        TM_TZ,          -5 * 60,  NULL },
706     { N_ ("ast"),        TM_TZ,          -4 * 60,  NULL },
707     { N_ ("nst"),        TM_TZ,          -(3 * 60 + 30),     NULL },
708 
709     { N_ ("gmt"),        TM_TZ,          0,      NULL },
710     { N_ ("utc"),        TM_TZ,          0,      NULL },
711 
712     { N_ ("wet"),        TM_TZ,          0,      NULL },
713     { N_ ("cet"),        TM_TZ,          1 * 60,   NULL },
714     { N_ ("eet"),        TM_TZ,          2 * 60,   NULL },
715     { N_ ("fet"),        TM_TZ,          3 * 60,   NULL },
716 
717     { N_ ("wat"),        TM_TZ,          1 * 60,   NULL },
718     { N_ ("cat"),        TM_TZ,          2 * 60,   NULL },
719     { N_ ("eat"),        TM_TZ,          3 * 60,   NULL },
720 };
721 
722 /*
723  * Compare strings str and keyword. Return the number of matching
724  * chars on match, 0 for no match.
725  *
726  * All of the alphabetic characters (isalpha) in str up to the first
727  * non-alpha character (or end of string) must match the
728  * keyword. Consequently, the value returned on match is the number of
729  * consecutive alphabetic characters in str.
730  *
731  * Abbreviated match is accepted if the keyword contains a '|'
732  * character, and str matches keyword up to that character. Any alpha
733  * characters after that in str must still match the keyword following
734  * the '|' character. If no '|' is present, all of keyword must match.
735  *
736  * Excessive, consecutive, and misplaced (at the beginning or end) '|'
737  * characters in keyword are handled gracefully. Only the first one
738  * matters.
739  *
740  * If match_case is true, the matching is case sensitive.
741  */
742 static size_t
match_keyword(const char * str,const char * keyword,bool match_case)743 match_keyword (const char *str, const char *keyword, bool match_case)
744 {
745     const char *s = str;
746     bool prefix_matched = false;
747 
748     for (;;) {
749 	while (*keyword == '|') {
750 	    prefix_matched = true;
751 	    keyword++;
752 	}
753 
754 	if (! *s || ! isalpha ((unsigned char) *s) || ! *keyword)
755 	    break;
756 
757 	if (match_case) {
758 	    if (*s != *keyword)
759 		return 0;
760 	} else {
761 	    if (tolower ((unsigned char) *s) !=
762 		tolower ((unsigned char) *keyword))
763 		return 0;
764 	}
765 	s++;
766 	keyword++;
767     }
768 
769     /* did not match all of the keyword in input string */
770     if (*s && isalpha ((unsigned char) *s))
771 	return 0;
772 
773     /* did not match enough of keyword */
774     if (*keyword && ! prefix_matched)
775 	return 0;
776 
777     return s - str;
778 }
779 
780 /*
781  * Parse a keyword. Return < 0 on error, number of parsed chars on
782  * success.
783  */
784 static ssize_t
parse_keyword(struct state * state,const char * s)785 parse_keyword (struct state *state, const char *s)
786 {
787     unsigned int i;
788     size_t n = 0;
789     struct keyword *kw = NULL;
790     int r;
791 
792     for (i = 0; i < ARRAY_SIZE (keywords); i++) {
793 	const char *keyword = _ (keywords[i].name);
794 	bool mcase = false;
795 
796 	/* Match case if keyword begins with '*'. */
797 	if (*keyword == '*') {
798 	    mcase = true;
799 	    keyword++;
800 	}
801 
802 	n = match_keyword (s, keyword, mcase);
803 	if (n) {
804 	    kw = &keywords[i];
805 	    break;
806 	}
807     }
808 
809     if (! kw)
810 	return -PARSE_TIME_ERR_KEYWORD;
811 
812     if (kw->set)
813 	r = kw->set (state, kw);
814     else
815 	r = set_field (state, kw->field, kw->value);
816 
817     if (r < 0)
818 	return r;
819 
820     return n;
821 }
822 
823 /*
824  * Non-keyword parsers and their helpers.
825  */
826 
827 static int
set_user_tz(struct state * state,char sign,int hour,int min)828 set_user_tz (struct state *state, char sign, int hour, int min)
829 {
830     int tz = hour * 60 + min;
831 
832     assert (sign == '+' || sign == '-');
833 
834     if (hour < 0 || hour > 14 || min < 0 || min > 59 || min % 15)
835 	return -PARSE_TIME_ERR_INVALIDTIME;
836 
837     if (sign == '-')
838 	tz = -tz;
839 
840     return set_field (state, TM_TZ, tz);
841 }
842 
843 /*
844  * Parse a previously postponed number if one exists. Independent
845  * parsing of a postponed number when it wasn't consumed during
846  * parsing of the following token.
847  */
848 static int
parse_postponed_number(struct state * state,unused (enum field next_field))849 parse_postponed_number (struct state *state, unused (enum field next_field))
850 {
851     int v, n;
852     char d;
853 
854     /* Bail out if there's no postponed number. */
855     if (! consume_postponed_number (state, &v, &n, &d))
856 	return 0;
857 
858     if (n == 1 || n == 2) {
859 	/* Notable exception: Previous field affects parsing. This
860 	 * handles "January 20". */
861 	if (state->last_field == TM_ABS_MON) {
862 	    /* D[D] */
863 	    if (! is_valid_mday (v))
864 		return -PARSE_TIME_ERR_INVALIDDATE;
865 
866 	    return set_field (state, TM_ABS_MDAY, v);
867 	} else if (n == 2) {
868 	    /* XXX: Only allow if last field is hour, min, or sec? */
869 	    if (d == '+' || d == '-') {
870 		/* +/-HH */
871 		return set_user_tz (state, d, v, 0);
872 	    }
873 	}
874     } else if (n == 4) {
875 	/* Notable exception: Value affects parsing. Time zones are
876 	 * always at most 1400 and we don't understand years before
877 	 * 1970. */
878 	if (! is_valid_year (v)) {
879 	    if (d == '+' || d == '-') {
880 		/* +/-HHMM */
881 		return set_user_tz (state, d, v / 100, v % 100);
882 	    }
883 	} else {
884 	    /* YYYY */
885 	    return set_field (state, TM_ABS_YEAR, v);
886 	}
887     } else if (n == 6) {
888 	/* HHMMSS */
889 	int hour = v / 10000;
890 	int min = (v / 100) % 100;
891 	int sec = v % 100;
892 
893 	if (! is_valid_time (hour, min, sec))
894 	    return -PARSE_TIME_ERR_INVALIDTIME;
895 
896 	return set_abs_time (state, hour, min, sec);
897     } else if (n == 8) {
898 	/* YYYYMMDD */
899 	int year = v / 10000;
900 	int mon = (v / 100) % 100;
901 	int mday = v % 100;
902 
903 	if (! is_valid_date (year, mon, mday))
904 	    return -PARSE_TIME_ERR_INVALIDDATE;
905 
906 	return set_abs_date (state, year, mon, mday);
907     }
908 
909     return -PARSE_TIME_ERR_FORMAT;
910 }
911 
912 static int tm_get_field (const struct tm *tm, enum field field);
913 
914 static int
set_timestamp(struct state * state,time_t t)915 set_timestamp (struct state *state, time_t t)
916 {
917     struct tm tm;
918     enum field f;
919     int r;
920 
921     if (gmtime_r (&t, &tm) == NULL)
922 	return -PARSE_TIME_ERR_LIB;
923 
924     for (f = TM_ABS_SEC; f != TM_NONE; f = next_abs_field (f)) {
925 	r = set_field (state, f, tm_get_field (&tm, f));
926 	if (r)
927 	    return r;
928     }
929 
930     r = set_field (state, TM_TZ, 0);
931     if (r)
932 	return r;
933 
934     /* XXX: Prevent TM_AMPM with timestamp, e.g. "@123456 pm" */
935 
936     return 0;
937 }
938 
939 /* Parse a single number. Typically postpone parsing until later. */
940 static int
parse_single_number(struct state * state,unsigned long v,unsigned long n)941 parse_single_number (struct state *state, unsigned long v,
942 		     unsigned long n)
943 {
944     assert (n);
945 
946     if (state->delim == '@')
947 	return set_timestamp (state, (time_t) v);
948 
949     if (v > INT_MAX)
950 	return -PARSE_TIME_ERR_FORMAT;
951 
952     return set_postponed_number (state, v, n);
953 }
954 
955 static bool
is_time_sep(char c)956 is_time_sep (char c)
957 {
958     return c == ':';
959 }
960 
961 static bool
is_date_sep(char c)962 is_date_sep (char c)
963 {
964     return c == '/' || c == '-' || c == '.';
965 }
966 
967 static bool
is_sep(char c)968 is_sep (char c)
969 {
970     return is_time_sep (c) || is_date_sep (c);
971 }
972 
973 /* Two-digit year: 00...69 is 2000s, 70...99 1900s, if n == 0 keep
974  * unset. */
975 static int
expand_year(unsigned long year,size_t n)976 expand_year (unsigned long year, size_t n)
977 {
978     if (n == 2) {
979 	return (year < 70 ? 2000 : 1900) + year;
980     } else if (n == 4) {
981 	return year;
982     } else {
983 	return UNSET;
984     }
985 }
986 
987 /* Parse a date number triplet. */
988 static int
parse_date(struct state * state,char sep,unsigned long v1,unsigned long v2,unsigned long v3,size_t n1,size_t n2,size_t n3)989 parse_date (struct state *state, char sep,
990 	    unsigned long v1, unsigned long v2, unsigned long v3,
991 	    size_t n1, size_t n2, size_t n3)
992 {
993     int year = UNSET, mon = UNSET, mday = UNSET;
994 
995     assert (is_date_sep (sep));
996 
997     switch (sep) {
998     case '/': /* Date: M[M]/D[D][/YY[YY]] or M[M]/YYYY */
999 	if (n1 != 1 && n1 != 2)
1000 	    return -PARSE_TIME_ERR_DATEFORMAT;
1001 
1002 	if ((n2 == 1 || n2 == 2) && (n3 == 0 || n3 == 2 || n3 == 4)) {
1003 	    /* M[M]/D[D][/YY[YY]] */
1004 	    year = expand_year (v3, n3);
1005 	    mon = v1;
1006 	    mday = v2;
1007 	} else if (n2 == 4 && n3 == 0) {
1008 	    /* M[M]/YYYY */
1009 	    year = v2;
1010 	    mon = v1;
1011 	} else {
1012 	    return -PARSE_TIME_ERR_DATEFORMAT;
1013 	}
1014 	break;
1015 
1016     case '-': /* Date: YYYY-MM[-DD] or DD-MM[-YY[YY]] or MM-YYYY */
1017 	if (n1 == 4 && n2 == 2 && (n3 == 0 || n3 == 2)) {
1018 	    /* YYYY-MM[-DD] */
1019 	    year = v1;
1020 	    mon = v2;
1021 	    if (n3)
1022 		mday = v3;
1023 	} else if (n1 == 2 && n2 == 2 && (n3 == 0 || n3 == 2 || n3 == 4)) {
1024 	    /* DD-MM[-YY[YY]] */
1025 	    year = expand_year (v3, n3);
1026 	    mon = v2;
1027 	    mday = v1;
1028 	} else if (n1 == 2 && n2 == 4 && n3 == 0) {
1029 	    /* MM-YYYY */
1030 	    year = v2;
1031 	    mon = v1;
1032 	} else {
1033 	    return -PARSE_TIME_ERR_DATEFORMAT;
1034 	}
1035 	break;
1036 
1037     case '.': /* Date: D[D].M[M][.[YY[YY]]] */
1038 	if ((n1 != 1 && n1 != 2) || (n2 != 1 && n2 != 2) ||
1039 	    (n3 != 0 && n3 != 2 && n3 != 4))
1040 	    return -PARSE_TIME_ERR_DATEFORMAT;
1041 
1042 	year = expand_year (v3, n3);
1043 	mon = v2;
1044 	mday = v1;
1045 	break;
1046     }
1047 
1048     if (year != UNSET && ! is_valid_year (year))
1049 	return -PARSE_TIME_ERR_INVALIDDATE;
1050 
1051     if (mon != UNSET && ! is_valid_mon (mon))
1052 	return -PARSE_TIME_ERR_INVALIDDATE;
1053 
1054     if (mday != UNSET && ! is_valid_mday (mday))
1055 	return -PARSE_TIME_ERR_INVALIDDATE;
1056 
1057     return set_abs_date (state, year, mon, mday);
1058 }
1059 
1060 /* Parse a time number triplet. */
1061 static int
parse_time(struct state * state,char sep,unsigned long v1,unsigned long v2,unsigned long v3,size_t n1,size_t n2,size_t n3)1062 parse_time (struct state *state, char sep,
1063 	    unsigned long v1, unsigned long v2, unsigned long v3,
1064 	    size_t n1, size_t n2, size_t n3)
1065 {
1066     assert (is_time_sep (sep));
1067 
1068     if ((n1 != 1 && n1 != 2) || n2 != 2 || (n3 != 0 && n3 != 2))
1069 	return -PARSE_TIME_ERR_TIMEFORMAT;
1070 
1071     /*
1072      * Notable exception: Previously set fields affect
1073      * parsing. Interpret (+|-)HH:MM as time zone only if hour and
1074      * minute have been set.
1075      *
1076      * XXX: This could be fixed by restricting the delimiters
1077      * preceding time. For '+' it would be justified, but for '-' it
1078      * might be inconvenient. However prefer to allow '-' as an
1079      * insignificant delimiter preceding time for convenience, and
1080      * handle '+' the same way for consistency between positive and
1081      * negative time zones.
1082      */
1083     if (is_field_set (state, TM_ABS_HOUR) &&
1084 	is_field_set (state, TM_ABS_MIN) &&
1085 	n1 == 2 && n2 == 2 && n3 == 0 &&
1086 	(state->delim == '+' || state->delim == '-')) {
1087 	return set_user_tz (state, state->delim, v1, v2);
1088     }
1089 
1090     if (! is_valid_time (v1, v2, n3 ? v3 : 0))
1091 	return -PARSE_TIME_ERR_INVALIDTIME;
1092 
1093     return set_abs_time (state, v1, v2, n3 ? (int) v3 : UNSET);
1094 }
1095 
1096 /* strtoul helper that assigns length. */
1097 static unsigned long
strtoul_len(const char * s,const char ** endp,size_t * len)1098 strtoul_len (const char *s, const char **endp, size_t *len)
1099 {
1100     unsigned long val = strtoul (s, (char **) endp, 10);
1101 
1102     *len = *endp - s;
1103     return val;
1104 }
1105 
1106 /*
1107  * Parse a (group of) number(s). Return < 0 on error, number of parsed
1108  * chars on success.
1109  */
1110 static ssize_t
parse_number(struct state * state,const char * s)1111 parse_number (struct state *state, const char *s)
1112 {
1113     int r;
1114     unsigned long v1, v2, v3 = 0;
1115     size_t n1, n2, n3 = 0;
1116     const char *p = s;
1117     char sep;
1118 
1119     v1 = strtoul_len (p, &p, &n1);
1120 
1121     if (! is_sep (*p) || ! isdigit ((unsigned char) *(p + 1))) {
1122 	/* A single number. */
1123 	r = parse_single_number (state, v1, n1);
1124 	if (r)
1125 	    return r;
1126 
1127 	return p - s;
1128     }
1129 
1130     sep = *p;
1131     v2 = strtoul_len (p + 1, &p, &n2);
1132 
1133     /* A group of two or three numbers? */
1134     if (*p == sep && isdigit ((unsigned char) *(p + 1)))
1135 	v3 = strtoul_len (p + 1, &p, &n3);
1136 
1137     if (is_time_sep (sep))
1138 	r = parse_time (state, sep, v1, v2, v3, n1, n2, n3);
1139     else
1140 	r = parse_date (state, sep, v1, v2, v3, n1, n2, n3);
1141 
1142     if (r)
1143 	return r;
1144 
1145     return p - s;
1146 }
1147 
1148 /*
1149  * Parse delimiter(s). Throw away all except the last one, which is
1150  * stored for parsing the next non-delimiter. Return < 0 on error,
1151  * number of parsed chars on success.
1152  *
1153  * XXX: We might want to be more strict here.
1154  */
1155 static ssize_t
parse_delim(struct state * state,const char * s)1156 parse_delim (struct state *state, const char *s)
1157 {
1158     const char *p = s;
1159 
1160     /*
1161      * Skip non-alpha and non-digit, and store the last for further
1162      * processing.
1163      */
1164     while (*p && ! isalnum ((unsigned char) *p)) {
1165 	set_delim (state, *p);
1166 	p++;
1167     }
1168 
1169     return p - s;
1170 }
1171 
1172 /*
1173  * Parse a date/time string. Return < 0 on error, number of parsed
1174  * chars on success.
1175  */
1176 static ssize_t
parse_input(struct state * state,const char * s)1177 parse_input (struct state *state, const char *s)
1178 {
1179     const char *p = s;
1180     ssize_t n;
1181     int r;
1182 
1183     while (*p) {
1184 	if (isalpha ((unsigned char) *p)) {
1185 	    n = parse_keyword (state, p);
1186 	} else if (isdigit ((unsigned char) *p)) {
1187 	    n = parse_number (state, p);
1188 	} else {
1189 	    n = parse_delim (state, p);
1190 	}
1191 
1192 	if (n <= 0) {
1193 	    if (n == 0)
1194 		n = -PARSE_TIME_ERR;
1195 
1196 	    return n;
1197 	}
1198 
1199 	p += n;
1200     }
1201 
1202     /* Parse a previously postponed number, if any. */
1203     r = parse_postponed_number (state, TM_NONE);
1204     if (r < 0)
1205 	return r;
1206 
1207     return p - s;
1208 }
1209 
1210 /*
1211  * Processing the parsed input.
1212  */
1213 
1214 /*
1215  * Initialize reference time to tm. Use time zone in state if
1216  * specified, otherwise local time. Use now for reference time if
1217  * non-NULL, otherwise current time.
1218  */
1219 static int
initialize_now(struct state * state,const time_t * ref,struct tm * tm)1220 initialize_now (struct state *state, const time_t *ref, struct tm *tm)
1221 {
1222     time_t t;
1223 
1224     if (ref) {
1225 	t = *ref;
1226     } else {
1227 	if (time (&t) == (time_t) -1)
1228 	    return -PARSE_TIME_ERR_LIB;
1229     }
1230 
1231     if (is_field_set (state, TM_TZ)) {
1232 	/* Some other time zone. */
1233 
1234 	/* Adjust now according to the TZ. */
1235 	t += get_field (state, TM_TZ) * 60;
1236 
1237 	/* It's not gm, but this doesn't mess with the TZ. */
1238 	if (gmtime_r (&t, tm) == NULL)
1239 	    return -PARSE_TIME_ERR_LIB;
1240     } else {
1241 	/* Local time. */
1242 	if (localtime_r (&t, tm) == NULL)
1243 	    return -PARSE_TIME_ERR_LIB;
1244     }
1245 
1246     return 0;
1247 }
1248 
1249 /*
1250  * Normalize tm according to mktime(3); if structure members are
1251  * outside their valid interval, they will be normalized (so that, for
1252  * example, 40 October is changed into 9 November), and tm_wday and
1253  * tm_yday are set to values determined from the contents of the other
1254  * fields.
1255  *
1256  * Both mktime(3) and localtime_r(3) use local time, but they cancel
1257  * each other out here, making this function agnostic to time zone.
1258  */
1259 static int
normalize_tm(struct tm * tm)1260 normalize_tm (struct tm *tm)
1261 {
1262     time_t t = mktime (tm);
1263 
1264     if (t == (time_t) -1)
1265 	return -PARSE_TIME_ERR_LIB;
1266 
1267     if (! localtime_r (&t, tm))
1268 	return -PARSE_TIME_ERR_LIB;
1269 
1270     return 0;
1271 }
1272 
1273 /* Get field out of a struct tm. */
1274 static int
tm_get_field(const struct tm * tm,enum field field)1275 tm_get_field (const struct tm *tm, enum field field)
1276 {
1277     switch (field) {
1278     case TM_ABS_SEC:    return tm->tm_sec;
1279     case TM_ABS_MIN:    return tm->tm_min;
1280     case TM_ABS_HOUR:   return tm->tm_hour;
1281     case TM_ABS_MDAY:   return tm->tm_mday;
1282     case TM_ABS_MON:    return tm->tm_mon + 1; /* 0- to 1-based */
1283     case TM_ABS_YEAR:   return 1900 + tm->tm_year;
1284     case TM_WDAY:       return tm->tm_wday;
1285     case TM_ABS_ISDST:  return tm->tm_isdst;
1286     default:
1287 	assert (false);
1288 	break;
1289     }
1290 
1291     return 0;
1292 }
1293 
1294 /* Modify hour according to am/pm setting. */
1295 static int
fixup_ampm(struct state * state)1296 fixup_ampm (struct state *state)
1297 {
1298     int hour, hdiff = 0;
1299 
1300     if (! is_field_set (state, TM_AMPM))
1301 	return 0;
1302 
1303     if (! is_field_set (state, TM_ABS_HOUR))
1304 	return -PARSE_TIME_ERR_TIMEFORMAT;
1305 
1306     hour = get_field (state, TM_ABS_HOUR);
1307     if (! is_valid_12hour (hour))
1308 	return -PARSE_TIME_ERR_INVALIDTIME;
1309 
1310     if (get_field (state, TM_AMPM)) {
1311 	/* 12pm is noon. */
1312 	if (hour != 12)
1313 	    hdiff = 12;
1314     } else {
1315 	/* 12am is midnight, beginning of day. */
1316 	if (hour == 12)
1317 	    hdiff = -12;
1318     }
1319 
1320     add_to_field (state, TM_REL_HOUR, -hdiff);
1321 
1322     return 0;
1323 }
1324 
1325 /* Combine absolute and relative fields, and round. */
1326 static int
create_output(struct state * state,time_t * t_out,const time_t * ref,int round)1327 create_output (struct state *state, time_t *t_out, const time_t *ref,
1328 	       int round)
1329 {
1330     struct tm tm = { .tm_isdst = -1 };
1331     struct tm now;
1332     time_t t;
1333     enum field f;
1334     int r;
1335     int week_round = PARSE_TIME_NO_ROUND;
1336 
1337     r = initialize_now (state, ref, &now);
1338     if (r)
1339 	return r;
1340 
1341     /* Initialize fields flagged as "now" to reference time. */
1342     for (f = TM_ABS_SEC; f != TM_NONE; f = next_abs_field (f)) {
1343 	if (state->set[f] == FIELD_NOW) {
1344 	    state->tm[f] = tm_get_field (&now, f);
1345 	    state->set[f] = FIELD_SET;
1346 	}
1347     }
1348 
1349     /*
1350      * If WDAY is set but MDAY is not, we consider WDAY relative
1351      *
1352      * XXX: This fails on stuff like "two months monday" because two
1353      * months ago wasn't the same day as today. Postpone until we know
1354      * date?
1355      */
1356     if (is_field_set (state, TM_WDAY) &&
1357 	! is_field_set (state, TM_ABS_MDAY)) {
1358 	int wday = get_field (state, TM_WDAY);
1359 	int today = tm_get_field (&now, TM_WDAY);
1360 	int rel_days;
1361 
1362 	if (today > wday)
1363 	    rel_days = today - wday;
1364 	else
1365 	    rel_days = today + 7 - wday;
1366 
1367 	/* This also prevents special week rounding from happening. */
1368 	add_to_field (state, TM_REL_DAY, rel_days);
1369 
1370 	unset_field (state, TM_WDAY);
1371     }
1372 
1373     r = fixup_ampm (state);
1374     if (r)
1375 	return r;
1376 
1377     /*
1378      * Iterate fields from most accurate to least accurate, and set
1379      * unset fields according to requested rounding.
1380      */
1381     for (f = TM_ABS_SEC; f != TM_NONE; f = next_abs_field (f)) {
1382 	if (round != PARSE_TIME_NO_ROUND) {
1383 	    enum field r = abs_to_rel_field (f);
1384 
1385 	    if (is_field_set (state, f) || is_field_set (state, r)) {
1386 		if (round >= PARSE_TIME_ROUND_UP && f != TM_ABS_SEC) {
1387 		    /*
1388 		     * This is the most accurate field
1389 		     * specified. Round up adjusting it towards
1390 		     * future.
1391 		     */
1392 		    add_to_field (state, r, -1);
1393 
1394 		    /*
1395 		     * Go back a second if the result is to be used
1396 		     * for inclusive comparisons.
1397 		     */
1398 		    if (round == PARSE_TIME_ROUND_UP_INCLUSIVE)
1399 			add_to_field (state, TM_REL_SEC, 1);
1400 		}
1401 		round = PARSE_TIME_NO_ROUND; /* No more rounding. */
1402 	    } else {
1403 		if (f == TM_ABS_MDAY &&
1404 		    is_field_set (state, TM_REL_WEEK)) {
1405 		    /* Week is most accurate. */
1406 		    week_round = round;
1407 		    round = PARSE_TIME_NO_ROUND;
1408 		} else {
1409 		    set_field (state, f, get_field_epoch_value (f));
1410 		}
1411 	    }
1412 	}
1413 
1414 	if (! is_field_set (state, f))
1415 	    set_field (state, f, tm_get_field (&now, f));
1416     }
1417 
1418     /* Special case: rounding with week accuracy. */
1419     if (week_round != PARSE_TIME_NO_ROUND) {
1420 	/* Temporarily set more accurate fields to now. */
1421 	set_field (state, TM_ABS_SEC, tm_get_field (&now, TM_ABS_SEC));
1422 	set_field (state, TM_ABS_MIN, tm_get_field (&now, TM_ABS_MIN));
1423 	set_field (state, TM_ABS_HOUR, tm_get_field (&now, TM_ABS_HOUR));
1424 	set_field (state, TM_ABS_MDAY, tm_get_field (&now, TM_ABS_MDAY));
1425     }
1426 
1427     /*
1428      * Set all fields. They may contain out of range values before
1429      * normalization by mktime(3).
1430      */
1431     tm.tm_sec = get_field (state, TM_ABS_SEC) - get_field (state, TM_REL_SEC);
1432     tm.tm_min = get_field (state, TM_ABS_MIN) - get_field (state, TM_REL_MIN);
1433     tm.tm_hour = get_field (state, TM_ABS_HOUR) - get_field (state, TM_REL_HOUR);
1434     tm.tm_mday = get_field (state, TM_ABS_MDAY) -
1435 		 get_field (state, TM_REL_DAY) - 7 * get_field (state, TM_REL_WEEK);
1436     tm.tm_mon = get_field (state, TM_ABS_MON) - get_field (state, TM_REL_MON);
1437     tm.tm_mon--; /* 1- to 0-based */
1438     tm.tm_year = get_field (state, TM_ABS_YEAR) - get_field (state, TM_REL_YEAR) - 1900;
1439 
1440     /*
1441      * It's always normal time.
1442      *
1443      * XXX: This is probably not a solution that universally
1444      * works. Just make sure DST is not taken into account. We don't
1445      * want rounding to be affected by DST.
1446      */
1447     tm.tm_isdst = -1;
1448 
1449     /* Special case: rounding with week accuracy. */
1450     if (week_round != PARSE_TIME_NO_ROUND) {
1451 	/* Normalize to get proper tm.wday. */
1452 	r = normalize_tm (&tm);
1453 	if (r < 0)
1454 	    return r;
1455 
1456 	/* Set more accurate fields back to zero. */
1457 	tm.tm_sec = 0;
1458 	tm.tm_min = 0;
1459 	tm.tm_hour = 0;
1460 	tm.tm_isdst = -1;
1461 
1462 	/* Monday is the true 1st day of week, but this is easier. */
1463 	if (week_round >= PARSE_TIME_ROUND_UP) {
1464 	    tm.tm_mday += 7 - tm.tm_wday;
1465 	    if (week_round == PARSE_TIME_ROUND_UP_INCLUSIVE)
1466 		tm.tm_sec--;
1467 	} else {
1468 	    tm.tm_mday -= tm.tm_wday;
1469 	}
1470     }
1471 
1472     if (is_field_set (state, TM_TZ)) {
1473 	/* tm is in specified TZ, convert to UTC for timegm(3). */
1474 	tm.tm_min -= get_field (state, TM_TZ);
1475 	t = timegm (&tm);
1476     } else {
1477 	/* tm is in local time. */
1478 	t = mktime (&tm);
1479     }
1480 
1481     if (t == (time_t) -1)
1482 	return -PARSE_TIME_ERR_LIB;
1483 
1484     *t_out = t;
1485 
1486     return 0;
1487 }
1488 
1489 /* Internally, all errors are < 0. parse_time_string() returns errors > 0. */
1490 #define EXTERNAL_ERR(r) (-r)
1491 
1492 int
parse_time_string(const char * s,time_t * t,const time_t * ref,int round)1493 parse_time_string (const char *s, time_t *t, const time_t *ref, int round)
1494 {
1495     struct state state = { .last_field = TM_NONE };
1496     int r;
1497 
1498     if (! s || ! t)
1499 	return EXTERNAL_ERR (-PARSE_TIME_ERR);
1500 
1501     r = parse_input (&state, s);
1502     if (r < 0)
1503 	return EXTERNAL_ERR (r);
1504 
1505     r = create_output (&state, t, ref, round);
1506     if (r < 0)
1507 	return EXTERNAL_ERR (r);
1508 
1509     return 0;
1510 }
1511