false positive “ot”
[alioth/cvs.git] / lib / getdate.y
1 %{
2 /* Parse a string into an internal time stamp.
3
4    Copyright (C) 1995, 1997, 1998, 2003, 2004, 2005
5    Free Software Foundation, Inc.
6
7    Copyright (c) 2005, 2006, 2007, 2010, 2016, 2017
8    mirabilos <m@mirbsd.org>
9
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 2, or (at your option)
13    any later version.
14
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software Foundation,
22    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
23
24 /* Originally written by Steven M. Bellovin <smb@research.att.com> while
25    at the University of North Carolina at Chapel Hill.  Later tweaked by
26    a couple of people on Usenet.  Completely overhauled by Rich $alz
27    <rsalz@bbn.com> and Jim Berets <jberets@bbn.com> in August, 1990.
28
29    Modified by Paul Eggert <eggert@twinsun.com> in August 1999 to do
30    the right thing about local DST.  Also modified by Paul Eggert
31    <eggert@cs.ucla.edu> in February 2004 to support
32    nanosecond-resolution time stamps, and in October 2004 to support
33    TZ strings in dates.  */
34
35 /* FIXME: Check for arithmetic overflow in all cases, not just
36    some of them.  */
37
38 #ifdef HAVE_CONFIG_H
39 # include <config.h>
40 #endif
41
42 #include "getdate.h"
43
44 #ifdef USE_LIBBSD
45 size_t strlcat(char *, const char *, size_t);
46 #endif
47
48 /* There's no need to extend the stack, so there's no need to involve
49    alloca.  */
50 #define YYSTACK_USE_ALLOCA 0
51
52 /* Tell Bison how much stack space is needed.  20 should be plenty for
53    this grammar, which is not right recursive.  Beware setting it too
54    high, since that might cause problems on machines whose
55    implementations have lame stack-overflow checking.  */
56 #define YYMAXDEPTH 20
57 #define YYINITDEPTH YYMAXDEPTH
58
59 /* Since the code of getdate.y is not included in the Emacs executable
60    itself, there is no need to #define static in this file.  Even if
61    the code were included in the Emacs executable, it probably
62    wouldn't do any harm to #undef it here; this will only cause
63    problems if we try to write to a static variable, which I don't
64    think this code needs to do.  */
65 #ifdef emacs
66 # undef static
67 #endif
68
69 #include <ctype.h>
70 #include <limits.h>
71 #include <stdio.h>
72 #include <stdlib.h>
73 #include <string.h>
74
75 #ifndef _STDLIB_H
76 #define _STDLIB_H 1 /* GNU bison needs this */
77 #endif
78
79 #ifndef IN_RCS
80 #include "setenv.h"
81 #include "xalloc.h"
82 #else /* IN_RCS */
83 #include <unistd.h>
84
85 #define HAVE_STRUCT_TM_TM_ZONE 1
86 #define HAVE_TM_GMTOFF  1
87
88 #define gettime(ts)     clock_gettime(CLOCK_REALTIME,(ts))
89
90 static void *
91 xmalloc(size_t s)
92 {
93         static const char xmalloc_enomem[] = "memory exhausted\n";
94         void *x;
95
96         if ((x = malloc(s)) == NULL) {
97                 write(2, xmalloc_enomem, sizeof(xmalloc_enomem) - 1);
98                 exit(1);
99         }
100
101         return (x);
102 }
103
104 static void *
105 xmemdup(void const *p, size_t s)
106 {
107         return (memcpy(xmalloc(s), p, s));
108 }
109 #endif /* IN_RCS */
110
111 #if (defined(STDC_HEADERS) && STDC_HEADERS) || \
112     (!defined(isascii) && !HAVE_ISASCII)
113 # define IN_CTYPE_DOMAIN(c) 1
114 #else
115 # define IN_CTYPE_DOMAIN(c) isascii (c)
116 #endif
117
118 #define ISSPACE(c) (IN_CTYPE_DOMAIN (c) && isspace (c))
119 #define ISALPHA(c) (IN_CTYPE_DOMAIN (c) && isalpha (c))
120 #define ISLOWER(c) (IN_CTYPE_DOMAIN (c) && islower (c))
121
122 /* ISDIGIT differs from isdigit, as follows:
123    - Its arg may be any int or unsigned int; it need not be an unsigned char.
124    - It's guaranteed to evaluate its argument exactly once.
125    - It's typically faster.
126    POSIX says that only '0' through '9' are digits.  Prefer ISDIGIT to
127    isdigit unless it's important to use the locale's definition
128    of `digit' even when the host does not conform to POSIX.  */
129 #define ISDIGIT(c) ((unsigned int) (c) - '0' <= 9)
130
131 #if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 8) || \
132     (defined(__STRICT_ANSI__) && __STRICT_ANSI__)
133 # define __attribute__(x)
134 #endif
135
136 #ifndef ATTRIBUTE_UNUSED
137 # define ATTRIBUTE_UNUSED __attribute__ ((__unused__))
138 #endif
139
140 #ifndef __IDSTRING
141 #define __IDSTRING(varname, string) \
142         static const char varname[] __attribute__((__used__)) = \
143             "@(""#)" #varname ": " string
144 #endif
145
146 __IDSTRING(rcsid_code, "$MirOS: src/gnu/usr.bin/cvs/lib/getdate.y,v 1.12 2017/03/26 15:54:06 tg Exp $");
147 /* placeholder line for __IDSTRING(rcsid_bron, "$miros: ..."); so that cpp #line directives work */
148
149 /* Shift A right by B bits portably, by dividing A by 2**B and
150    truncating towards minus infinity.  A and B should be free of side
151    effects, and B should be in the range 0 <= B <= INT_BITS - 2, where
152    INT_BITS is the number of useful bits in an int.  GNU code can
153    assume that INT_BITS is at least 32.
154
155    ISO C99 says that A >> B is implementation-defined if A < 0.  Some
156    implementations (e.g., UNICOS 9.0 on a Cray Y-MP EL) don't shift
157    right in the usual way when A < 0, so SHR falls back on division if
158    ordinary A >> B doesn't seem to be the usual signed shift.  */
159 #define SHR(a, b)       \
160   (-1 >> 1 == -1        \
161    ? (a) >> (b)         \
162    : (a) / (1 << (b)) - ((a) % (1 << (b)) < 0))
163
164 #define EPOCH_YEAR 1970
165 #define TM_YEAR_BASE 1900
166
167 #define HOUR(x) ((x) * 60)
168
169 /* An integer value, and the number of digits in its textual
170    representation.  */
171 typedef struct
172 {
173   bool negative;
174   long int value;
175   size_t digits;
176 } textint;
177
178 /* An entry in the lexical lookup table.  */
179 typedef struct
180 {
181   char const *name;
182   int type;
183   int value;
184 } table;
185
186 /* Meridian: am, pm, or 24-hour style.  */
187 enum { MERam, MERpm, MER24 };
188
189 enum { BILLION = 1000000000, LOG10_BILLION = 9 };
190
191 /* Information passed to and from the parser.  */
192 typedef struct
193 {
194   /* The input string remaining to be parsed. */
195   const char *input;
196
197   /* N, if this is the Nth Tuesday.  */
198   long int day_ordinal;
199
200   /* Day of week; Sunday is 0.  */
201   int day_number;
202
203   /* tm_isdst flag for the local zone.  */
204   int local_isdst;
205
206   /* Time zone, in minutes east of UTC.  */
207   long int time_zone;
208
209   /* Style used for time.  */
210   int meridian;
211
212   /* Gregorian year, month, day, hour, minutes, seconds, and nanoseconds.  */
213   textint year;
214   long int month;
215   long int day;
216   long int hour;
217   long int minutes;
218   struct timespec seconds; /* includes nanoseconds */
219
220   /* Relative year, month, day, hour, minutes, seconds, and nanoseconds.  */
221   long int rel_year;
222   long int rel_month;
223   long int rel_day;
224   long int rel_hour;
225   long int rel_minutes;
226   long int rel_seconds;
227   long int rel_ns;
228
229   /* Presence or counts of nonterminals of various flavors parsed so far.  */
230   bool timespec_seen;
231   bool rels_seen;
232   size_t dates_seen;
233   size_t days_seen;
234   size_t local_zones_seen;
235   size_t dsts_seen;
236   size_t times_seen;
237   size_t zones_seen;
238
239   /* Table of local time zone abbrevations, terminated by a null entry.  */
240   table local_time_zone_table[3];
241 } parser_control;
242
243 union YYSTYPE;
244 static int yylex (union YYSTYPE *, parser_control *);
245 static int yyerror (parser_control *, const char *);
246 static long int time_zone_hhmm (textint, long int);
247
248 %}
249
250 /* We want a reentrant parser, even if the TZ manipulation and the calls to
251    localtime and gmtime are not reentrant.  */
252 %pure-parser
253 %parse-param { parser_control *pc }
254 %lex-param { parser_control *pc }
255
256 /* This grammar has 20 shift/reduce conflicts. */
257 %expect 20
258
259 %union
260 {
261   long int intval;
262   textint textintval;
263   struct timespec timespec;
264 }
265
266 %token tAGO tDST
267
268 %token <intval> tDAY tDAY_UNIT tDAYZONE tHOUR_UNIT tLOCAL_ZONE tMERIDIAN
269 %token <intval> tMINUTE_UNIT tMONTH tMONTH_UNIT tORDINAL
270 %token <intval> tSEC_UNIT tYEAR_UNIT tZONE
271
272 %token <textintval> tSNUMBER tUNUMBER
273 %token <timespec> tSDECIMAL_NUMBER tUDECIMAL_NUMBER
274
275 %type <intval> o_colon_minutes o_merid
276 %type <timespec> seconds signed_seconds unsigned_seconds
277
278 %%
279
280 spec:
281     timespec
282   | items
283   ;
284
285 timespec:
286     '@' seconds
287       {
288         pc->seconds = $2;
289         pc->timespec_seen = true;
290       }
291   ;
292
293 items:
294     /* empty */
295   | items item
296   ;
297
298 item:
299     time
300       { pc->times_seen++; }
301   | local_zone
302       { pc->local_zones_seen++; }
303   | zone
304       { pc->zones_seen++; }
305   | date
306       { pc->dates_seen++; }
307   | day
308       { pc->days_seen++; }
309   | rel
310       { pc->rels_seen = true; }
311   | number
312   ;
313
314 time:
315     tUNUMBER tMERIDIAN
316       {
317         pc->hour = $1.value;
318         pc->minutes = 0;
319         pc->seconds.tv_sec = 0;
320         pc->seconds.tv_nsec = 0;
321         pc->meridian = $2;
322       }
323   | tUNUMBER ':' tUNUMBER o_merid
324       {
325         pc->hour = $1.value;
326         pc->minutes = $3.value;
327         pc->seconds.tv_sec = 0;
328         pc->seconds.tv_nsec = 0;
329         pc->meridian = $4;
330       }
331   | tUNUMBER ':' tUNUMBER tSNUMBER o_colon_minutes
332       {
333         pc->hour = $1.value;
334         pc->minutes = $3.value;
335         pc->seconds.tv_sec = 0;
336         pc->seconds.tv_nsec = 0;
337         pc->meridian = MER24;
338         pc->zones_seen++;
339         pc->time_zone = time_zone_hhmm ($4, $5);
340       }
341   | tUNUMBER ':' tUNUMBER ':' unsigned_seconds o_merid
342       {
343         pc->hour = $1.value;
344         pc->minutes = $3.value;
345         pc->seconds = $5;
346         pc->meridian = $6;
347       }
348   | tUNUMBER ':' tUNUMBER ':' unsigned_seconds tSNUMBER o_colon_minutes
349       {
350         pc->hour = $1.value;
351         pc->minutes = $3.value;
352         pc->seconds = $5;
353         pc->meridian = MER24;
354         pc->zones_seen++;
355         pc->time_zone = time_zone_hhmm ($6, $7);
356       }
357   ;
358
359 local_zone:
360     tLOCAL_ZONE
361       {
362         pc->local_isdst = $1;
363         pc->dsts_seen += (0 < $1);
364       }
365   | tLOCAL_ZONE tDST
366       {
367         pc->local_isdst = 1;
368         pc->dsts_seen += (0 < $1) + 1;
369       }
370   ;
371
372 zone:
373     tZONE
374       { pc->time_zone = $1; }
375   | tZONE relunit_snumber
376       { pc->time_zone = $1; pc->rels_seen = true; }
377   | tZONE tSNUMBER o_colon_minutes
378       { pc->time_zone = $1 + time_zone_hhmm ($2, $3); }
379   | tDAYZONE
380       { pc->time_zone = $1 + 60; }
381   | tZONE tDST
382       { pc->time_zone = $1 + 60; }
383   ;
384
385 day:
386     tDAY
387       {
388         pc->day_ordinal = 1;
389         pc->day_number = $1;
390       }
391   | tDAY ','
392       {
393         pc->day_ordinal = 1;
394         pc->day_number = $1;
395       }
396   | tORDINAL tDAY
397       {
398         pc->day_ordinal = $1;
399         pc->day_number = $2;
400       }
401   | tUNUMBER tDAY
402       {
403         pc->day_ordinal = $1.value;
404         pc->day_number = $2;
405       }
406   ;
407
408 date:
409     tUNUMBER '/' tUNUMBER
410       {
411         pc->month = $1.value;
412         pc->day = $3.value;
413       }
414   | tUNUMBER '/' tUNUMBER '/' tUNUMBER
415       {
416         /* Interpret as YYYY/MM/DD if the first value has 4 or more digits,
417            otherwise as MM/DD/YY.
418            The goal in recognizing YYYY/MM/DD is solely to support legacy
419            machine-generated dates like those in an RCS log listing.  If
420            you want portability, use the ISO 8601 format.  */
421         if (4 <= $1.digits)
422           {
423             pc->year = $1;
424             pc->month = $3.value;
425             pc->day = $5.value;
426           }
427         else
428           {
429             pc->month = $1.value;
430             pc->day = $3.value;
431             pc->year = $5;
432           }
433       }
434   | tUNUMBER tSNUMBER tSNUMBER
435       {
436         /* ISO 8601 format.  YYYY-MM-DD.  */
437         pc->year = $1;
438         pc->month = -$2.value;
439         pc->day = -$3.value;
440       }
441   | tUNUMBER tMONTH tSNUMBER
442       {
443         /* e.g. 17-JUN-1992.  */
444         pc->day = $1.value;
445         pc->month = $2;
446         pc->year.value = -$3.value;
447         pc->year.digits = $3.digits;
448       }
449   | tMONTH tSNUMBER tSNUMBER
450       {
451         /* e.g. JUN-17-1992.  */
452         pc->month = $1;
453         pc->day = -$2.value;
454         pc->year.value = -$3.value;
455         pc->year.digits = $3.digits;
456       }
457   | tMONTH tUNUMBER
458       {
459         pc->month = $1;
460         pc->day = $2.value;
461       }
462   | tMONTH tUNUMBER ',' tUNUMBER
463       {
464         pc->month = $1;
465         pc->day = $2.value;
466         pc->year = $4;
467       }
468   | tUNUMBER tMONTH
469       {
470         pc->day = $1.value;
471         pc->month = $2;
472       }
473   | tUNUMBER tMONTH tUNUMBER
474       {
475         pc->day = $1.value;
476         pc->month = $2;
477         pc->year = $3;
478       }
479   ;
480
481 rel:
482     relunit tAGO
483       {
484         pc->rel_ns = -pc->rel_ns;
485         pc->rel_seconds = -pc->rel_seconds;
486         pc->rel_minutes = -pc->rel_minutes;
487         pc->rel_hour = -pc->rel_hour;
488         pc->rel_day = -pc->rel_day;
489         pc->rel_month = -pc->rel_month;
490         pc->rel_year = -pc->rel_year;
491       }
492   | relunit
493   ;
494
495 relunit:
496     tORDINAL tYEAR_UNIT
497       { pc->rel_year += $1 * $2; }
498   | tUNUMBER tYEAR_UNIT
499       { pc->rel_year += $1.value * $2; }
500   | tYEAR_UNIT
501       { pc->rel_year += $1; }
502   | tORDINAL tMONTH_UNIT
503       { pc->rel_month += $1 * $2; }
504   | tUNUMBER tMONTH_UNIT
505       { pc->rel_month += $1.value * $2; }
506   | tMONTH_UNIT
507       { pc->rel_month += $1; }
508   | tORDINAL tDAY_UNIT
509       { pc->rel_day += $1 * $2; }
510   | tUNUMBER tDAY_UNIT
511       { pc->rel_day += $1.value * $2; }
512   | tDAY_UNIT
513       { pc->rel_day += $1; }
514   | tORDINAL tHOUR_UNIT
515       { pc->rel_hour += $1 * $2; }
516   | tUNUMBER tHOUR_UNIT
517       { pc->rel_hour += $1.value * $2; }
518   | tHOUR_UNIT
519       { pc->rel_hour += $1; }
520   | tORDINAL tMINUTE_UNIT
521       { pc->rel_minutes += $1 * $2; }
522   | tUNUMBER tMINUTE_UNIT
523       { pc->rel_minutes += $1.value * $2; }
524   | tMINUTE_UNIT
525       { pc->rel_minutes += $1; }
526   | tORDINAL tSEC_UNIT
527       { pc->rel_seconds += $1 * $2; }
528   | tUNUMBER tSEC_UNIT
529       { pc->rel_seconds += $1.value * $2; }
530   | tSDECIMAL_NUMBER tSEC_UNIT
531       { pc->rel_seconds += $1.tv_sec * $2; pc->rel_ns += $1.tv_nsec * $2; }
532   | tUDECIMAL_NUMBER tSEC_UNIT
533       { pc->rel_seconds += $1.tv_sec * $2; pc->rel_ns += $1.tv_nsec * $2; }
534   | tSEC_UNIT
535       { pc->rel_seconds += $1; }
536   | relunit_snumber
537   ;
538
539 relunit_snumber:
540     tSNUMBER tYEAR_UNIT
541       { pc->rel_year += $1.value * $2; }
542   | tSNUMBER tMONTH_UNIT
543       { pc->rel_month += $1.value * $2; }
544   | tSNUMBER tDAY_UNIT
545       { pc->rel_day += $1.value * $2; }
546   | tSNUMBER tHOUR_UNIT
547       { pc->rel_hour += $1.value * $2; }
548   | tSNUMBER tMINUTE_UNIT
549       { pc->rel_minutes += $1.value * $2; }
550   | tSNUMBER tSEC_UNIT
551       { pc->rel_seconds += $1.value * $2; }
552   ;
553
554 seconds: signed_seconds | unsigned_seconds;
555
556 signed_seconds:
557     tSDECIMAL_NUMBER
558   | tSNUMBER
559       { $$.tv_sec = $1.value; $$.tv_nsec = 0; }
560   ;
561
562 unsigned_seconds:
563     tUDECIMAL_NUMBER
564   | tUNUMBER
565       { $$.tv_sec = $1.value; $$.tv_nsec = 0; }
566   ;
567
568 number:
569     tUNUMBER
570       {
571         if (pc->dates_seen && ! pc->year.digits
572             && ! pc->rels_seen && (pc->times_seen || 2 < $1.digits))
573           pc->year = $1;
574         else
575           {
576             if (4 < $1.digits)
577               {
578                 pc->dates_seen++;
579                 pc->day = $1.value % 100;
580                 pc->month = ($1.value / 100) % 100;
581                 pc->year.value = $1.value / 10000;
582                 pc->year.digits = $1.digits - 4;
583               }
584             else
585               {
586                 pc->times_seen++;
587                 if ($1.digits <= 2)
588                   {
589                     pc->hour = $1.value;
590                     pc->minutes = 0;
591                   }
592                 else
593                   {
594                     pc->hour = $1.value / 100;
595                     pc->minutes = $1.value % 100;
596                   }
597                 pc->seconds.tv_sec = 0;
598                 pc->seconds.tv_nsec = 0;
599                 pc->meridian = MER24;
600               }
601           }
602       }
603   ;
604
605 o_colon_minutes:
606     /* empty */
607       { $$ = -1; }
608   | ':' tUNUMBER
609       { $$ = $2.value; }
610   ;
611
612 o_merid:
613     /* empty */
614       { $$ = MER24; }
615   | tMERIDIAN
616       { $$ = $1; }
617   ;
618
619 %%
620
621 static table const meridian_table[] =
622 {
623   { "AM",   tMERIDIAN, MERam },
624   { "A.M.", tMERIDIAN, MERam },
625   { "PM",   tMERIDIAN, MERpm },
626   { "P.M.", tMERIDIAN, MERpm },
627   { NULL, 0, 0 }
628 };
629
630 static table const dst_table[] =
631 {
632   { "DST", tDST, 0 }
633 };
634
635 static table const month_and_day_table[] =
636 {
637   { "JANUARY",  tMONTH,  1 },
638   { "FEBRUARY", tMONTH,  2 },
639   { "MARCH",    tMONTH,  3 },
640   { "APRIL",    tMONTH,  4 },
641   { "MAY",      tMONTH,  5 },
642   { "JUNE",     tMONTH,  6 },
643   { "JULY",     tMONTH,  7 },
644   { "AUGUST",   tMONTH,  8 },
645   { "SEPTEMBER",tMONTH,  9 },
646   { "SEPT",     tMONTH,  9 },
647   { "OCTOBER",  tMONTH, 10 },
648   { "NOVEMBER", tMONTH, 11 },
649   { "DECEMBER", tMONTH, 12 },
650   { "SUNDAY",   tDAY,    0 },
651   { "MONDAY",   tDAY,    1 },
652   { "TUESDAY",  tDAY,    2 },
653   { "TUES",     tDAY,    2 },
654   { "WEDNESDAY",tDAY,    3 },
655   { "WEDNES",   tDAY,    3 },
656   { "THURSDAY", tDAY,    4 },
657   { "THUR",     tDAY,    4 },
658   { "THURS",    tDAY,    4 },
659   { "FRIDAY",   tDAY,    5 },
660   { "SATURDAY", tDAY,    6 },
661   { NULL, 0, 0 }
662 };
663
664 static table const time_units_table[] =
665 {
666   { "YEAR",     tYEAR_UNIT,      1 },
667   { "MONTH",    tMONTH_UNIT,     1 },
668   { "FORTNIGHT",tDAY_UNIT,      14 },
669   { "WEEK",     tDAY_UNIT,       7 },
670   { "DAY",      tDAY_UNIT,       1 },
671   { "HOUR",     tHOUR_UNIT,      1 },
672   { "MINUTE",   tMINUTE_UNIT,    1 },
673   { "MIN",      tMINUTE_UNIT,    1 },
674   { "SECOND",   tSEC_UNIT,       1 },
675   { "SEC",      tSEC_UNIT,       1 },
676   { NULL, 0, 0 }
677 };
678
679 /* Assorted relative-time words. */
680 static table const relative_time_table[] =
681 {
682   { "TOMORROW", tDAY_UNIT,       1 },
683   { "YESTERDAY",tDAY_UNIT,      -1 },
684   { "TODAY",    tDAY_UNIT,       0 },
685   { "NOW",      tDAY_UNIT,       0 },
686   { "LAST",     tORDINAL,       -1 },
687   { "THIS",     tORDINAL,        0 },
688   { "NEXT",     tORDINAL,        1 },
689   { "FIRST",    tORDINAL,        1 },
690 /*{ "SECOND",   tORDINAL,        2 }, */
691   { "THIRD",    tORDINAL,        3 },
692   { "FOURTH",   tORDINAL,        4 },
693   { "FIFTH",    tORDINAL,        5 },
694   { "SIXTH",    tORDINAL,        6 },
695   { "SEVENTH",  tORDINAL,        7 },
696   { "EIGHTH",   tORDINAL,        8 },
697   { "NINTH",    tORDINAL,        9 },
698   { "TENTH",    tORDINAL,       10 },
699   { "ELEVENTH", tORDINAL,       11 },
700   { "TWELFTH",  tORDINAL,       12 },
701   { "AGO",      tAGO,            1 },
702   { NULL, 0, 0 }
703 };
704
705 /* The universal time zone table.  These labels can be used even for
706    time stamps that would not otherwise be valid, e.g., GMT time
707    stamps in London during summer.  */
708 static table const universal_time_zone_table[] =
709 {
710   { "GMT",      tZONE,     HOUR ( 0) }, /* Greenwich Mean */
711   { "UT",       tZONE,     HOUR ( 0) }, /* Universal (Coordinated) */
712   { "UTC",      tZONE,     HOUR ( 0) },
713   { NULL, 0, 0 }
714 };
715
716 /* The time zone table.  This table is necessarily incomplete, as time
717    zone abbreviations are ambiguous; e.g. Australians interpret "EST"
718    as Eastern time in Australia, not as US Eastern Standard Time.
719    You cannot rely on getdate to handle arbitrary time zone
720    abbreviations; use numeric abbreviations like `-0500' instead.  */
721 static table const time_zone_table[] =
722 {
723   { "WET",      tZONE,     HOUR ( 0) }, /* Western European */
724   { "WEST",     tDAYZONE,  HOUR ( 0) }, /* Western European Summer */
725   { "BST",      tDAYZONE,  HOUR ( 0) }, /* British Summer */
726   { "ART",      tZONE,    -HOUR ( 3) }, /* Argentina */
727   { "BRT",      tZONE,    -HOUR ( 3) }, /* Brazil */
728   { "BRST",     tDAYZONE, -HOUR ( 3) }, /* Brazil Summer */
729   { "NST",      tZONE,   -(HOUR ( 3) + 30) },   /* Newfoundland Standard */
730   { "NDT",      tDAYZONE,-(HOUR ( 3) + 30) },   /* Newfoundland Daylight */
731   { "AST",      tZONE,    -HOUR ( 4) }, /* Atlantic Standard */
732   { "ADT",      tDAYZONE, -HOUR ( 4) }, /* Atlantic Daylight */
733   { "CLT",      tZONE,    -HOUR ( 4) }, /* Chile */
734   { "CLST",     tDAYZONE, -HOUR ( 4) }, /* Chile Summer */
735   { "EST",      tZONE,    -HOUR ( 5) }, /* Eastern Standard */
736   { "EDT",      tDAYZONE, -HOUR ( 5) }, /* Eastern Daylight */
737   { "CST",      tZONE,    -HOUR ( 6) }, /* Central Standard */
738   { "CDT",      tDAYZONE, -HOUR ( 6) }, /* Central Daylight */
739   { "MST",      tZONE,    -HOUR ( 7) }, /* Mountain Standard */
740   { "MDT",      tDAYZONE, -HOUR ( 7) }, /* Mountain Daylight */
741   { "PST",      tZONE,    -HOUR ( 8) }, /* Pacific Standard */
742   { "PDT",      tDAYZONE, -HOUR ( 8) }, /* Pacific Daylight */
743   { "AKST",     tZONE,    -HOUR ( 9) }, /* Alaska Standard */
744   { "AKDT",     tDAYZONE, -HOUR ( 9) }, /* Alaska Daylight */
745   { "HST",      tZONE,    -HOUR (10) }, /* Hawaii Standard */
746   { "HAST",     tZONE,    -HOUR (10) }, /* Hawaii-Aleutian Standard */
747   { "HADT",     tDAYZONE, -HOUR (10) }, /* Hawaii-Aleutian Daylight */
748   { "SST",      tZONE,    -HOUR (12) }, /* Samoa Standard */
749   { "WAT",      tZONE,     HOUR ( 1) }, /* West Africa */
750   { "CET",      tZONE,     HOUR ( 1) }, /* Central European */
751   { "CEST",     tDAYZONE,  HOUR ( 1) }, /* Central European Summer */
752   { "MET",      tZONE,     HOUR ( 1) }, /* Middle European */
753   { "MEZ",      tZONE,     HOUR ( 1) }, /* Middle European */
754   { "MEST",     tDAYZONE,  HOUR ( 1) }, /* Middle European Summer */
755   { "MESZ",     tDAYZONE,  HOUR ( 1) }, /* Middle European Summer */
756   { "EET",      tZONE,     HOUR ( 2) }, /* Eastern European */
757   { "EEST",     tDAYZONE,  HOUR ( 2) }, /* Eastern European Summer */
758   { "CAT",      tZONE,     HOUR ( 2) }, /* Central Africa */
759   { "SAST",     tZONE,     HOUR ( 2) }, /* South Africa Standard */
760   { "EAT",      tZONE,     HOUR ( 3) }, /* East Africa */
761   { "MSK",      tZONE,     HOUR ( 3) }, /* Moscow */
762   { "MSD",      tDAYZONE,  HOUR ( 3) }, /* Moscow Daylight */
763   { "IST",      tZONE,    (HOUR ( 5) + 30) },   /* India Standard */
764   { "SGT",      tZONE,     HOUR ( 8) }, /* Singapore */
765   { "KST",      tZONE,     HOUR ( 9) }, /* Korea Standard */
766   { "JST",      tZONE,     HOUR ( 9) }, /* Japan Standard */
767   { "GST",      tZONE,     HOUR (10) }, /* Guam Standard */
768   { "NZST",     tZONE,     HOUR (12) }, /* New Zealand Standard */
769   { "NZDT",     tDAYZONE,  HOUR (12) }, /* New Zealand Daylight */
770   { NULL, 0, 0 }
771 };
772
773 /* Military time zone table. */
774 static table const military_table[] =
775 {
776   { "A", tZONE, -HOUR ( 1) },
777   { "B", tZONE, -HOUR ( 2) },
778   { "C", tZONE, -HOUR ( 3) },
779   { "D", tZONE, -HOUR ( 4) },
780   { "E", tZONE, -HOUR ( 5) },
781   { "F", tZONE, -HOUR ( 6) },
782   { "G", tZONE, -HOUR ( 7) },
783   { "H", tZONE, -HOUR ( 8) },
784   { "I", tZONE, -HOUR ( 9) },
785   { "K", tZONE, -HOUR (10) },
786   { "L", tZONE, -HOUR (11) },
787   { "M", tZONE, -HOUR (12) },
788   { "N", tZONE,  HOUR ( 1) },
789   { "O", tZONE,  HOUR ( 2) },
790   { "P", tZONE,  HOUR ( 3) },
791   { "Q", tZONE,  HOUR ( 4) },
792   { "R", tZONE,  HOUR ( 5) },
793   { "S", tZONE,  HOUR ( 6) },
794   { "T", tZONE,  HOUR ( 7) },
795   { "U", tZONE,  HOUR ( 8) },
796   { "V", tZONE,  HOUR ( 9) },
797   { "W", tZONE,  HOUR (10) },
798   { "X", tZONE,  HOUR (11) },
799   { "Y", tZONE,  HOUR (12) },
800   { "Z", tZONE,  HOUR ( 0) },
801   { NULL, 0, 0 }
802 };
803
804 \f
805
806 /* Convert a time zone expressed as HH:MM into an integer count of
807    minutes.  If MM is negative, then S is of the form HHMM and needs
808    to be picked apart; otherwise, S is of the form HH.  */
809
810 static long int
811 time_zone_hhmm (textint s, long int mm)
812 {
813   if (mm < 0)
814     return (s.value / 100) * 60 + s.value % 100;
815   else
816     return s.value * 60 + (s.negative ? -mm : mm);
817 }
818
819 static int
820 to_hour (long int hours, int meridian)
821 {
822   switch (meridian)
823     {
824     default: /* Pacify GCC.  */
825     case MER24:
826       return 0 <= hours && hours < 24 ? hours : -1;
827     case MERam:
828       return 0 < hours && hours < 12 ? hours : hours == 12 ? 0 : -1;
829     case MERpm:
830       return 0 < hours && hours < 12 ? hours + 12 : hours == 12 ? 12 : -1;
831     }
832 }
833
834 static long int
835 to_year (textint textyear)
836 {
837   long int year = textyear.value;
838
839   if (year < 0)
840     year = -year;
841
842   /* XPG4 suggests that years 00-68 map to 2000-2068, and
843      years 69-99 map to 1969-1999.  */
844   else if (textyear.digits == 2)
845     year += year < 69 ? 2000 : 1900;
846
847   return year;
848 }
849
850 static table const *
851 lookup_zone (parser_control const *pc, char const *name)
852 {
853   table const *tp;
854
855   for (tp = universal_time_zone_table; tp->name; tp++)
856     if (strcmp (name, tp->name) == 0)
857       return tp;
858
859   /* Try local zone abbreviations before those in time_zone_table, as
860      the local ones are more likely to be right.  */
861   for (tp = pc->local_time_zone_table; tp->name; tp++)
862     if (strcmp (name, tp->name) == 0)
863       return tp;
864
865   for (tp = time_zone_table; tp->name; tp++)
866     if (strcmp (name, tp->name) == 0)
867       return tp;
868
869   return NULL;
870 }
871
872 #if ! HAVE_TM_GMTOFF
873 /* Yield the difference between *A and *B,
874    measured in seconds, ignoring leap seconds.
875    The body of this function is taken directly from the GNU C Library;
876    see src/strftime.c.  */
877 static long int
878 tm_diff (struct tm const *a, struct tm const *b)
879 {
880   /* Compute intervening leap days correctly even if year is negative.
881      Take care to avoid int overflow in leap day calculations.  */
882   int a4 = SHR (a->tm_year, 2) + SHR (TM_YEAR_BASE, 2) - ! (a->tm_year & 3);
883   int b4 = SHR (b->tm_year, 2) + SHR (TM_YEAR_BASE, 2) - ! (b->tm_year & 3);
884   int a100 = a4 / 25 - (a4 % 25 < 0);
885   int b100 = b4 / 25 - (b4 % 25 < 0);
886   int a400 = SHR (a100, 2);
887   int b400 = SHR (b100, 2);
888   int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400);
889   long int ayear = a->tm_year;
890   long int years = ayear - b->tm_year;
891   long int days = (365 * years + intervening_leap_days
892                    + (a->tm_yday - b->tm_yday));
893   return (60 * (60 * (24 * days + (a->tm_hour - b->tm_hour))
894                 + (a->tm_min - b->tm_min))
895           + (a->tm_sec - b->tm_sec));
896 }
897 #endif /* ! HAVE_TM_GMTOFF */
898
899 static table const *
900 lookup_word (parser_control const *pc, char *word)
901 {
902   char *p;
903   char *q;
904   size_t wordlen;
905   table const *tp;
906   bool period_found;
907   bool abbrev;
908
909   /* Make it uppercase.  */
910   for (p = word; *p; p++)
911     {
912       unsigned char ch = *p;
913       if (ISLOWER (ch))
914         *p = toupper (ch);
915     }
916
917   for (tp = meridian_table; tp->name; tp++)
918     if (strcmp (word, tp->name) == 0)
919       return tp;
920
921   /* See if we have an abbreviation for a month. */
922   wordlen = strlen (word);
923   abbrev = wordlen == 3 || (wordlen == 4 && word[3] == '.');
924
925   for (tp = month_and_day_table; tp->name; tp++)
926     if ((abbrev ? strncmp (word, tp->name, 3) : strcmp (word, tp->name)) == 0)
927       return tp;
928
929   if ((tp = lookup_zone (pc, word)))
930     return tp;
931
932   if (strcmp (word, dst_table[0].name) == 0)
933     return dst_table;
934
935   for (tp = time_units_table; tp->name; tp++)
936     if (strcmp (word, tp->name) == 0)
937       return tp;
938
939   /* Strip off any plural and try the units table again. */
940   if (word[wordlen - 1] == 'S')
941     {
942       word[wordlen - 1] = '\0';
943       for (tp = time_units_table; tp->name; tp++)
944         if (strcmp (word, tp->name) == 0)
945           return tp;
946       word[wordlen - 1] = 'S';  /* For "this" in relative_time_table.  */
947     }
948
949   for (tp = relative_time_table; tp->name; tp++)
950     if (strcmp (word, tp->name) == 0)
951       return tp;
952
953   /* Military time zones. */
954   if (wordlen == 1)
955     for (tp = military_table; tp->name; tp++)
956       if (word[0] == tp->name[0])
957         return tp;
958
959   /* Drop out any periods and try the time zone table again. */
960   for (period_found = false, p = q = word; (*p = *q); q++)
961     if (*q == '.')
962       period_found = true;
963     else
964       p++;
965   if (period_found && (tp = lookup_zone (pc, word)))
966     return tp;
967
968   return NULL;
969 }
970
971 static int
972 yylex (YYSTYPE *lvalp, parser_control *pc)
973 {
974   unsigned char c;
975   size_t count;
976
977   for (;;)
978     {
979       while (c = *pc->input, ISSPACE (c))
980         pc->input++;
981
982       if (ISDIGIT (c) || c == '-' || c == '+')
983         {
984           char const *p;
985           int sign;
986           unsigned long int value;
987           if (c == '-' || c == '+')
988             {
989               sign = c == '-' ? -1 : 1;
990               while (c = *++pc->input, ISSPACE (c))
991                 continue;
992               if (! ISDIGIT (c))
993                 /* skip the '-' sign */
994                 continue;
995             }
996           else
997             sign = 0;
998           p = pc->input;
999           for (value = 0; ; value *= 10)
1000             {
1001               unsigned long int value1 = value + (c - '0');
1002               if (value1 < value)
1003                 return '?';
1004               value = value1;
1005               c = *++p;
1006               if (! ISDIGIT (c))
1007                 break;
1008               if (ULONG_MAX / 10 < value)
1009                 return '?';
1010             }
1011           if ((c == '.' || c == ',') && ISDIGIT (p[1]))
1012             {
1013               time_t s;
1014               int ns;
1015               int digits;
1016               unsigned long int value1;
1017
1018               /* Check for overflow when converting value to time_t.  */
1019               if (sign < 0)
1020                 {
1021                   s = - value;
1022                   if (0 < s)
1023                     return '?';
1024                   value1 = -s;
1025                 }
1026               else
1027                 {
1028                   s = value;
1029                   if (s < 0)
1030                     return '?';
1031                   value1 = s;
1032                 }
1033               if (value != value1)
1034                 return '?';
1035
1036               /* Accumulate fraction, to ns precision.  */
1037               p++;
1038               ns = *p++ - '0';
1039               for (digits = 2; digits <= LOG10_BILLION; digits++)
1040                 {
1041                   ns *= 10;
1042                   if (ISDIGIT (*p))
1043                     ns += *p++ - '0';
1044                 }
1045
1046               /* Skip excess digits, truncating toward -Infinity.  */
1047               if (sign < 0)
1048                 for (; ISDIGIT (*p); p++)
1049                   if (*p != '0')
1050                     {
1051                       ns++;
1052                       break;
1053                     }
1054               while (ISDIGIT (*p))
1055                 p++;
1056
1057               /* Adjust to the timespec convention, which is that
1058                  tv_nsec is always a positive offset even if tv_sec is
1059                  negative.  */
1060               if (sign < 0 && ns)
1061                 {
1062                   s--;
1063                   if (! (s < 0))
1064                     return '?';
1065                   ns = BILLION - ns;
1066                 }
1067
1068               lvalp->timespec.tv_sec = s;
1069               lvalp->timespec.tv_nsec = ns;
1070               pc->input = p;
1071               return sign ? tSDECIMAL_NUMBER : tUDECIMAL_NUMBER;
1072             }
1073           else
1074             {
1075               lvalp->textintval.negative = sign < 0;
1076               if (sign < 0)
1077                 {
1078                   lvalp->textintval.value = - value;
1079                   if (0 < lvalp->textintval.value)
1080                     return '?';
1081                 }
1082               else
1083                 {
1084                   lvalp->textintval.value = value;
1085                   if (lvalp->textintval.value < 0)
1086                     return '?';
1087                 }
1088               lvalp->textintval.digits = p - pc->input;
1089               pc->input = p;
1090               return sign ? tSNUMBER : tUNUMBER;
1091             }
1092         }
1093
1094       if (ISALPHA (c))
1095         {
1096           char buff[20];
1097           char *p = buff;
1098           table const *tp;
1099
1100           do
1101             {
1102               if (p < buff + sizeof buff - 1)
1103                 *p++ = c;
1104               c = *++pc->input;
1105             }
1106           while (ISALPHA (c) || c == '.');
1107
1108           *p = '\0';
1109           tp = lookup_word (pc, buff);
1110           if (! tp)
1111             return '?';
1112           lvalp->intval = tp->value;
1113           return tp->type;
1114         }
1115
1116       if (c != '(')
1117         return *pc->input++;
1118       count = 0;
1119       do
1120         {
1121           c = *pc->input++;
1122           if (c == '\0')
1123             return c;
1124           if (c == '(')
1125             count++;
1126           else if (c == ')')
1127             count--;
1128         }
1129       while (count != 0);
1130     }
1131 }
1132
1133 /* Do nothing if the parser reports an error.  */
1134 static int
1135 yyerror (parser_control *pc ATTRIBUTE_UNUSED, const char *s ATTRIBUTE_UNUSED)
1136 {
1137   return 0;
1138 }
1139
1140 /* If *TM0 is the old and *TM1 is the new value of a struct tm after
1141    passing it to mktime, return true if it's OK that mktime returned T.
1142    It's not OK if *TM0 has out-of-range members.  */
1143
1144 static bool
1145 mktime_ok (struct tm const *tm0, struct tm const *tm1, time_t t)
1146 {
1147   if (t == (time_t) -1)
1148     {
1149       /* Guard against falsely reporting an error when parsing a time
1150          stamp that happens to equal (time_t) -1, on a host that
1151          supports such a time stamp.  */
1152       tm1 = localtime (&t);
1153       if (!tm1)
1154         return false;
1155     }
1156
1157   return ! ((tm0->tm_sec ^ tm1->tm_sec)
1158             | (tm0->tm_min ^ tm1->tm_min)
1159             | (tm0->tm_hour ^ tm1->tm_hour)
1160             | (tm0->tm_mday ^ tm1->tm_mday)
1161             | (tm0->tm_mon ^ tm1->tm_mon)
1162             | (tm0->tm_year ^ tm1->tm_year));
1163 }
1164
1165 /* A reasonable upper bound for the size of ordinary TZ strings.
1166    Use heap allocation if TZ's length exceeds this.  */
1167 enum { TZBUFSIZE = 100 };
1168
1169 /* Return a copy of TZ, stored in TZBUF if it fits, and heap-allocated
1170    otherwise.  */
1171 static char *
1172 get_tz (char tzbuf[TZBUFSIZE])
1173 {
1174   char *tz = getenv ("TZ");
1175   if (tz)
1176     {
1177       size_t tzsize = strlen (tz) + 1;
1178       tz = (tzsize == 1 ? NULL : (tzsize <= TZBUFSIZE
1179             ? memcpy (tzbuf, tz, tzsize)
1180             : xmemdup (tz, tzsize)));
1181     }
1182   return tz;
1183 }
1184
1185 /* Parse a date/time string, storing the resulting time value into *RESULT.
1186    The string itself is pointed to by P.  Return true if successful.
1187    P can be an incomplete or relative time specification; if so, use
1188    *NOW as the basis for the returned time.  */
1189 bool
1190 get_date (struct timespec *result, char const *p, struct timespec const *now)
1191 {
1192   time_t Start;
1193   long int Start_ns;
1194   struct tm const *tmp;
1195   struct tm tm;
1196   struct tm tm0;
1197   parser_control pc;
1198   struct timespec gettime_buffer;
1199   unsigned char c;
1200   bool tz_was_altered = false;
1201   char *tz0 = NULL;
1202   char tz0buf[TZBUFSIZE];
1203   bool ok = true;
1204
1205   if (! now)
1206     {
1207       gettime (&gettime_buffer);
1208       now = &gettime_buffer;
1209     }
1210
1211   Start = now->tv_sec;
1212   Start_ns = now->tv_nsec;
1213
1214   tmp = localtime (&now->tv_sec);
1215   if (! tmp)
1216     return false;
1217
1218   while (c = *p, ISSPACE (c))
1219     p++;
1220
1221   if (strncmp (p, "TZ=\"", 4) == 0)
1222     {
1223       char const *tzbase = p + 4;
1224       size_t tzsize = 1;
1225       char const *s;
1226
1227       for (s = tzbase; *s; s++, tzsize++)
1228         if (*s == '\\')
1229           {
1230             s++;
1231             if (! (*s == '\\' || *s == '"'))
1232               break;
1233           }
1234         else if (*s == '"')
1235           {
1236             char *z;
1237             char *tz1;
1238             char tz1buf[TZBUFSIZE];
1239             bool large_tz = TZBUFSIZE < tzsize;
1240             bool setenv_ok;
1241             tz0 = get_tz (tz0buf);
1242             z = tz1 = large_tz ? xmalloc (tzsize) : tz1buf;
1243             for (s = tzbase; *s != '"'; s++)
1244               *z++ = *(s += *s == '\\');
1245             *z = '\0';
1246             setenv_ok = setenv ("TZ", tz1, 1) == 0;
1247             if (large_tz)
1248               free (tz1);
1249             if (!setenv_ok)
1250               goto fail;
1251             tz_was_altered = true;
1252             p = s + 1;
1253           }
1254     }
1255
1256   pc.input = p;
1257   pc.year.value = tmp->tm_year;
1258   pc.year.value += TM_YEAR_BASE;
1259   pc.year.digits = 0;
1260   pc.month = tmp->tm_mon + 1;
1261   pc.day = tmp->tm_mday;
1262   pc.hour = tmp->tm_hour;
1263   pc.minutes = tmp->tm_min;
1264   pc.seconds.tv_sec = tmp->tm_sec;
1265   pc.seconds.tv_nsec = Start_ns;
1266   tm.tm_isdst = tmp->tm_isdst;
1267
1268   pc.meridian = MER24;
1269   pc.rel_ns = 0;
1270   pc.rel_seconds = 0;
1271   pc.rel_minutes = 0;
1272   pc.rel_hour = 0;
1273   pc.rel_day = 0;
1274   pc.rel_month = 0;
1275   pc.rel_year = 0;
1276   pc.timespec_seen = false;
1277   pc.rels_seen = false;
1278   pc.dates_seen = 0;
1279   pc.days_seen = 0;
1280   pc.times_seen = 0;
1281   pc.local_zones_seen = 0;
1282   pc.dsts_seen = 0;
1283   pc.zones_seen = 0;
1284
1285 #if HAVE_STRUCT_TM_TM_ZONE
1286   pc.local_time_zone_table[0].name = tmp->tm_zone;
1287   pc.local_time_zone_table[0].type = tLOCAL_ZONE;
1288   pc.local_time_zone_table[0].value = tmp->tm_isdst;
1289   pc.local_time_zone_table[1].name = NULL;
1290
1291   /* Probe the names used in the next three calendar quarters, looking
1292      for a tm_isdst different from the one we already have.  */
1293   {
1294     int quarter;
1295     for (quarter = 1; quarter <= 3; quarter++)
1296       {
1297         time_t probe = Start + quarter * (90 * 24 * 60 * 60);
1298         struct tm const *probe_tm = localtime (&probe);
1299         if (probe_tm && probe_tm->tm_zone
1300             && probe_tm->tm_isdst != pc.local_time_zone_table[0].value)
1301           {
1302               {
1303                 pc.local_time_zone_table[1].name = probe_tm->tm_zone;
1304                 pc.local_time_zone_table[1].type = tLOCAL_ZONE;
1305                 pc.local_time_zone_table[1].value = probe_tm->tm_isdst;
1306                 pc.local_time_zone_table[2].name = NULL;
1307               }
1308             break;
1309           }
1310       }
1311   }
1312 #else
1313 #if HAVE_TZNAME
1314   {
1315 # ifndef tzname
1316     extern char *tzname[];
1317 # endif
1318     int i;
1319     for (i = 0; i < 2; i++)
1320       {
1321         pc.local_time_zone_table[i].name = tzname[i];
1322         pc.local_time_zone_table[i].type = tLOCAL_ZONE;
1323         pc.local_time_zone_table[i].value = i;
1324       }
1325     pc.local_time_zone_table[i].name = NULL;
1326   }
1327 #else
1328   pc.local_time_zone_table[0].name = NULL;
1329 #endif
1330 #endif
1331
1332   if (pc.local_time_zone_table[0].name && pc.local_time_zone_table[1].name
1333       && ! strcmp (pc.local_time_zone_table[0].name,
1334                    pc.local_time_zone_table[1].name))
1335     {
1336       /* This locale uses the same abbrevation for standard and
1337          daylight times.  So if we see that abbreviation, we don't
1338          know whether it's daylight time.  */
1339       pc.local_time_zone_table[0].value = -1;
1340       pc.local_time_zone_table[1].name = NULL;
1341     }
1342
1343   if (yyparse (&pc) != 0)
1344     goto fail;
1345
1346   if (pc.timespec_seen)
1347     *result = pc.seconds;
1348   else
1349     {
1350       if (1 < (pc.times_seen | pc.dates_seen | pc.days_seen | pc.dsts_seen
1351                | (pc.local_zones_seen + pc.zones_seen)))
1352         goto fail;
1353
1354       tm.tm_year = to_year (pc.year) - TM_YEAR_BASE;
1355       tm.tm_mon = pc.month - 1;
1356       tm.tm_mday = pc.day;
1357       if (pc.times_seen || (pc.rels_seen && ! pc.dates_seen && ! pc.days_seen))
1358         {
1359           tm.tm_hour = to_hour (pc.hour, pc.meridian);
1360           if (tm.tm_hour < 0)
1361             goto fail;
1362           tm.tm_min = pc.minutes;
1363           tm.tm_sec = pc.seconds.tv_sec;
1364         }
1365       else
1366         {
1367           tm.tm_hour = tm.tm_min = tm.tm_sec = 0;
1368           pc.seconds.tv_nsec = 0;
1369         }
1370
1371       /* Let mktime deduce tm_isdst if we have an absolute time stamp.  */
1372       if (!pc.rels_seen)
1373         tm.tm_isdst = -1;
1374
1375       /* But if the input explicitly specifies local time with or without
1376          DST, give mktime that information.  */
1377       if (pc.local_zones_seen)
1378         tm.tm_isdst = pc.local_isdst;
1379
1380       tm0 = tm;
1381
1382       Start = mktime (&tm);
1383
1384       if (! mktime_ok (&tm0, &tm, Start))
1385         {
1386           if (! pc.zones_seen)
1387             goto fail;
1388           else
1389             {
1390               /* Guard against falsely reporting errors near the time_t
1391                  boundaries when parsing times in other time zones.  For
1392                  example, suppose the input string "1969-12-31 23:00:00 -0100",
1393                  the current time zone is 8 hours ahead of UTC, and the min
1394                  time_t value is 1970-01-01 00:00:00 UTC.  Then the min
1395                  localtime value is 1970-01-01 08:00:00, and mktime will
1396                  therefore fail on 1969-12-31 23:00:00.  To work around the
1397                  problem, set the time zone to 1 hour behind UTC temporarily
1398                  by setting TZ="XXX1:00" and try mktime again.  */
1399
1400               long int time_zone = pc.time_zone;
1401               long int abs_time_zone = time_zone < 0 ? - time_zone : time_zone;
1402               long int abs_time_zone_hour = abs_time_zone / 60;
1403               int abs_time_zone_min = abs_time_zone % 60;
1404               char tz1buf[sizeof "XXX+0:00"
1405                           + sizeof pc.time_zone * CHAR_BIT / 3];
1406               if (!tz_was_altered)
1407                 tz0 = get_tz (tz0buf);
1408               snprintf(tz1buf, sizeof(tz1buf),
1409                        "XXX%s%ld:%02d", "-" + (time_zone < 0),
1410                        abs_time_zone_hour, abs_time_zone_min);
1411               if (setenv ("TZ", tz1buf, 1) != 0)
1412                 goto fail;
1413               tz_was_altered = true;
1414               tm = tm0;
1415               Start = mktime (&tm);
1416               if (! mktime_ok (&tm0, &tm, Start))
1417                 goto fail;
1418             }
1419         }
1420
1421       if (pc.days_seen && ! pc.dates_seen)
1422         {
1423           tm.tm_mday += ((pc.day_number - tm.tm_wday + 7) % 7
1424                          + 7 * (pc.day_ordinal - (0 < pc.day_ordinal)));
1425           tm.tm_isdst = -1;
1426           Start = mktime (&tm);
1427           if (Start == (time_t) -1)
1428             goto fail;
1429         }
1430
1431       if (pc.zones_seen)
1432         {
1433           long int delta = pc.time_zone * 60;
1434           time_t t1;
1435 #ifdef HAVE_TM_GMTOFF
1436           delta -= tm.tm_gmtoff;
1437 #else
1438           time_t t = Start;
1439           struct tm const *gmt = gmtime (&t);
1440           if (! gmt)
1441             goto fail;
1442           delta -= tm_diff (&tm, gmt);
1443 #endif
1444           t1 = Start - delta;
1445           if ((Start < t1) != (delta < 0))
1446             goto fail;  /* time_t overflow */
1447           Start = t1;
1448         }
1449
1450       /* Add relative date.  */
1451       if (pc.rel_year | pc.rel_month | pc.rel_day)
1452         {
1453           int year = tm.tm_year + pc.rel_year;
1454           int month = tm.tm_mon + pc.rel_month;
1455           int day = tm.tm_mday + pc.rel_day;
1456           if (((year < tm.tm_year) ^ (pc.rel_year < 0))
1457               | ((month < tm.tm_mon) ^ (pc.rel_month < 0))
1458               | ((day < tm.tm_mday) ^ (pc.rel_day < 0)))
1459             goto fail;
1460           tm.tm_year = year;
1461           tm.tm_mon = month;
1462           tm.tm_mday = day;
1463           Start = mktime (&tm);
1464           if (Start == (time_t) -1)
1465             goto fail;
1466         }
1467
1468       /* Add relative hours, minutes, and seconds.  On hosts that support
1469          leap seconds, ignore the possibility of leap seconds; e.g.,
1470          "+ 10 minutes" adds 600 seconds, even if one of them is a
1471          leap second.  Typically this is not what the user wants, but it's
1472          too hard to do it the other way, because the time zone indicator
1473          must be applied before relative times, and if mktime is applied
1474          again the time zone will be lost.  */
1475       {
1476         long int sum_ns = pc.seconds.tv_nsec + pc.rel_ns;
1477         long int normalized_ns = (sum_ns % BILLION + BILLION) % BILLION;
1478         time_t t0 = Start;
1479         long int d1 = 60 * 60 * pc.rel_hour;
1480         time_t t1 = t0 + d1;
1481         long int d2 = 60 * pc.rel_minutes;
1482         time_t t2 = t1 + d2;
1483         long int d3 = pc.rel_seconds;
1484         time_t t3 = t2 + d3;
1485         long int d4 = (sum_ns - normalized_ns) / BILLION;
1486         time_t t4 = t3 + d4;
1487
1488         if ((d1 / (60 * 60) ^ pc.rel_hour)
1489             | (d2 / 60 ^ pc.rel_minutes)
1490             | ((t1 < t0) ^ (d1 < 0))
1491             | ((t2 < t1) ^ (d2 < 0))
1492             | ((t3 < t2) ^ (d3 < 0))
1493             | ((t4 < t3) ^ (d4 < 0)))
1494           goto fail;
1495
1496         result->tv_sec = t4;
1497         result->tv_nsec = normalized_ns;
1498       }
1499     }
1500
1501   goto done;
1502
1503  fail:
1504   ok = false;
1505  done:
1506   if (tz_was_altered)
1507     ok &= (tz0 ? setenv("TZ", tz0, 1) : (unsetenv("TZ"), 0)) == 0;
1508   if (tz0 != tz0buf)
1509     free (tz0);
1510   return ok;
1511 }
1512
1513 #if TEST
1514
1515 int
1516 main(int argc, char **argv)
1517 {
1518   char buff[BUFSIZ];
1519   int cmd = 0;
1520
1521   if (argc > 1) {
1522     int i = 1;
1523     buff[0] = '\0';
1524     while (i < argc) {
1525       if (i > 1)
1526         strlcat(buff, " ", BUFSIZ);
1527       strlcat(buff, argv[i++], BUFSIZ);
1528     }
1529     cmd++;
1530     goto once;
1531   }
1532
1533   printf("Enter date, or blank line to exit.\n> ");
1534   fflush (stdout);
1535
1536   buff[BUFSIZ - 1] = '\0';
1537   while (fgets(buff, BUFSIZ - 1, stdin) && buff[0] &&
1538          buff[0] != '\r' && buff[0] != '\n')
1539     {
1540       struct timespec d;
1541       struct tm const *tm;
1542  once:
1543       if (! get_date (&d, buff, NULL))
1544         printf ("Bad format - couldn't convert.\n");
1545       else if (! (tm = localtime (&d.tv_sec)))
1546         {
1547           printf ("localtime (%lld) failed\n", (long long)d.tv_sec);
1548         }
1549       else
1550         {
1551           int ns = d.tv_nsec;
1552           printf ("%13lld =\t%04ld-%02d-%02d %02d:%02d:%02d.%09d\n",
1553                   (long long)d.tv_sec, (long)tm->tm_year + 1900,
1554                   tm->tm_mon + 1, tm->tm_mday,
1555                   tm->tm_hour, tm->tm_min, tm->tm_sec, ns);
1556         }
1557       if (cmd)
1558         return 0;
1559       printf ("> ");
1560       fflush (stdout);
1561     }
1562   return 0;
1563 }
1564 #endif /* TEST */