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