2cb28b2ae5497b4d8124a5aba96e4cc3b3868b40
[citadel.git] / citadel / parsedate.c
1 #include <stdlib.h>
2 #ifndef lint
3 #ifdef __unused
4 __unused
5 #endif
6 static char const 
7 yyrcsid[] = "$FreeBSD: src/usr.bin/yacc/skeleton.c,v 1.37 2003/02/12 18:03:55 davidc Exp $";
8 #endif
9 #define YYBYACC 1
10 #define YYMAJOR 1
11 #define YYMINOR 9
12 #define YYLEX yylex()
13 #define YYEMPTY -1
14 #define yyclearin (yychar=(YYEMPTY))
15 #define yyerrok (yyerrflag=0)
16 #define YYRECOVERING() (yyerrflag!=0)
17 #if defined(__cplusplus) || __STDC__
18 static int yygrowstack(void);
19 #else
20 static int yygrowstack();
21 #endif
22 #define YYPREFIX "yy"
23 #line 2 "parsedate.y"
24 /* $Revision: 4003 $
25 **
26 **  Originally written by Steven M. Bellovin <smb@research.att.com> while
27 **  at the University of North Carolina at Chapel Hill.  Later tweaked by
28 **  a couple of people on Usenet.  Completely overhauled by Rich $alz
29 **  <rsalz@osf.org> and Jim Berets <jberets@bbn.com> in August, 1990.
30 **  Further revised (removed obsolete constructs and cleaned up timezone
31 **  names) in August, 1991, by Rich.  Paul Eggert <eggert@twinsun.com>
32 **  helped in September, 1992.  Art Cancro <ajc@uncensored.citadel.org> cleaned
33 **  it up for ANSI C in December, 1999.
34 **
35 **  This grammar has six shift/reduce conflicts.
36 **
37 **  This code is in the public domain and has no copyright.
38 */
39 /* SUPPRESS 530 *//* Empty body for statement */
40 /* SUPPRESS 593 on yyerrlab *//* Label was not used */
41 /* SUPPRESS 593 on yynewstate *//* Label was not used */
42 /* SUPPRESS 595 on yypvt *//* Automatic variable may be used before set */
43
44 #include "sysdep.h"
45
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <sys/types.h>
49 #include <ctype.h>
50
51 #if TIME_WITH_SYS_TIME
52 # include <sys/time.h>
53 # include <time.h>
54 #else
55 # if HAVE_SYS_TIME_H
56 #  include <sys/time.h>
57 # else
58 #  include <time.h>
59 # endif
60 #endif
61
62 #if HAVE_STRING_H
63 # if !STDC_HEADERS && HAVE_MEMORY_H
64 #  include <memory.h>
65 # endif
66 # include <string.h>
67 #endif
68 #if HAVE_STRINGS_H
69 # include <strings.h>
70 #endif
71
72 #include "parsedate.h"
73
74 int date_lex(void);
75
76 #define yyparse         date_parse
77 #define yylex           date_lex
78 #define yyerror         date_error
79
80
81     /* See the LeapYears table in Convert. */
82 #define EPOCH           1970
83 #define END_OF_TIME     2038
84     /* Constants for general time calculations. */
85 #define DST_OFFSET      1
86 #define SECSPERDAY      (24L * 60L * 60L)
87     /* Readability for TABLE stuff. */
88 #define HOUR(x)         (x * 60)
89
90 #define LPAREN          '('
91 #define RPAREN          ')'
92 #define IS7BIT(x)       ((unsigned int)(x) < 0200)
93
94 #define SIZEOF(array)   ((int)(sizeof array / sizeof array[0]))
95 #define ENDOF(array)    (&array[SIZEOF(array)])
96
97
98 /*
99 **  An entry in the lexical lookup table.
100 */
101 typedef struct _TABLE {
102     char        *name;
103     int         type;
104     time_t      value;
105 } TABLE;
106
107 /*
108 **  Daylight-savings mode:  on, off, or not yet known.
109 */
110 typedef enum _DSTMODE {
111     DSTon, DSToff, DSTmaybe
112 } DSTMODE;
113
114 /*
115 **  Meridian:  am, pm, or 24-hour style.
116 */
117 typedef enum _MERIDIAN {
118     MERam, MERpm, MER24
119 } MERIDIAN;
120
121
122 /*
123 **  Global variables.  We could get rid of most of them by using a yacc
124 **  union, but this is more efficient.  (This routine predates the
125 **  yacc %union construct.)
126 */
127 static char     *yyInput;
128 static DSTMODE  yyDSTmode;
129 static int      yyHaveDate;
130 static int      yyHaveRel;
131 static int      yyHaveTime;
132 static time_t   yyTimezone;
133 static time_t   yyDay;
134 static time_t   yyHour;
135 static time_t   yyMinutes;
136 static time_t   yyMonth;
137 static time_t   yySeconds;
138 static time_t   yyYear;
139 static MERIDIAN yyMeridian;
140 static time_t   yyRelMonth;
141 static time_t   yyRelSeconds;
142
143
144 static void             date_error(char *);
145 #line 125 "parsedate.y"
146 typedef union {
147     time_t              Number;
148     enum _MERIDIAN      Meridian;
149 } YYSTYPE;
150 #line 151 "y.tab.c"
151 #define YYERRCODE 256
152 #define tDAY 257
153 #define tDAYZONE 258
154 #define tMERIDIAN 259
155 #define tMONTH 260
156 #define tMONTH_UNIT 261
157 #define tSEC_UNIT 262
158 #define tSNUMBER 263
159 #define tUNUMBER 264
160 #define tZONE 265
161 const short yylhs[] = {                                        -1,
162     0,    0,    4,    4,    4,    4,    5,    5,    5,    5,
163     5,    2,    2,    2,    2,    1,    6,    6,    6,    6,
164     6,    6,    6,    7,    7,    7,    7,    3,    3,
165 };
166 const short yylen[] = {                                         2,
167     0,    2,    1,    2,    1,    1,    2,    4,    4,    6,
168     6,    1,    1,    2,    1,    1,    3,    5,    2,    4,
169     2,    3,    5,    2,    2,    2,    2,    0,    1,
170 };
171 const short yydefred[] = {                                      1,
172     0,    0,    0,    0,    0,    2,    0,    5,    6,    0,
173     0,   26,   24,   29,    0,   27,   25,    0,    0,    7,
174    13,   16,    0,   15,    4,    0,    0,   22,    0,    0,
175    14,    0,   20,    0,    9,    8,    0,   23,    0,   18,
176    11,   10,
177 };
178 const short yydgoto[] = {                                       1,
179    24,   25,   20,    6,    7,    8,    9,
180 };
181 const short yysindex[] = {                                      0,
182  -239,  -36, -248, -255,  -47,    0, -232,    0,    0, -247,
183   -25,    0,    0,    0, -237,    0,    0, -235, -234,    0,
184     0,    0, -231,    0,    0, -226, -229,    0,  -56,  -11,
185     0, -227,    0, -225,    0,    0, -224,    0, -250,    0,
186     0,    0,
187 };
188 const short yyrindex[] = {                                      0,
189     0,    0,    0,    0,    1,    0,   22,    0,    0,    0,
190    12,    0,    0,    0,   28,    0,    0,    0,    0,    0,
191     0,    0,   23,    0,    0,    0,    0,    0,    3,   14,
192     0,    0,    0,    0,    0,    0,    0,    0,    3,    0,
193     0,    0,
194 };
195 const short yygindex[] = {                                      0,
196   -19,    0,  -24,    0,    0,    0,    0,
197 };
198 #define YYTABLESIZE 291
199 const short yytable[] = {                                      19,
200    28,   34,   28,   31,   36,   12,   13,   10,   14,   35,
201    18,   19,   22,   17,   42,   11,   26,    2,   27,   41,
202     3,    3,   12,    4,    5,   21,   28,   21,   29,   30,
203    22,   22,   23,   32,   33,   37,   38,    0,   39,   40,
204     0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
205     0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
206     0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
207     0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
208     0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
209     0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
210     0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
211     0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
212     0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
213     0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
214     0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
215     0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
216     0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
217     0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
218     0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
219     0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
220     0,    0,   14,    0,    0,    0,   22,    0,    0,    0,
221     0,   14,   15,   16,   17,    0,    0,    0,    0,    0,
222     0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
223     0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
224     0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
225     0,    0,    0,    0,    0,    0,    0,   28,   28,   28,
226    28,    0,   28,   28,   28,   28,   28,   28,   19,    0,
227    17,   19,    0,   17,   19,   19,   17,   17,    3,   12,
228     0,    3,   12,    0,   21,    3,   12,   21,    0,    0,
229    21,
230 };
231 const short yycheck[] = {                                      47,
232     0,   58,    0,   23,   29,  261,  262,   44,  259,   29,
233    58,    0,  263,    0,   39,  264,  264,  257,   44,   39,
234   260,    0,    0,  263,  264,  258,  264,    0,  264,  264,
235   263,  263,  265,  260,  264,   47,  264,   -1,  264,  264,
236    -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
237    -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
238    -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
239    -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
240    -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
241    -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
242    -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
243    -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
244    -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
245    -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
246    -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
247    -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
248    -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
249    -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
250    -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
251    -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
252    -1,   -1,  259,   -1,   -1,   -1,  263,   -1,   -1,   -1,
253    -1,  259,  260,  261,  262,   -1,   -1,   -1,   -1,   -1,
254    -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
255    -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
256    -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
257    -1,   -1,   -1,   -1,   -1,   -1,   -1,  257,  258,  257,
258   258,   -1,  260,  263,  264,  265,  264,  265,  257,   -1,
259   257,  260,   -1,  260,  263,  264,  263,  264,  257,  257,
260    -1,  260,  260,   -1,  257,  264,  264,  260,   -1,   -1,
261   263,
262 };
263 #define YYFINAL 1
264 #ifndef YYDEBUG
265 #define YYDEBUG 0
266 #endif
267 #define YYMAXTOKEN 265
268 #if YYDEBUG
269 const char * const yyname[] = {
270 "end-of-file",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
271 0,0,0,0,0,0,0,0,0,0,"','",0,0,"'/'",0,0,0,0,0,0,0,0,0,0,"':'",0,0,0,0,0,0,0,0,0,
272 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
273 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
274 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
275 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
276 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"tDAY","tDAYZONE",
277 "tMERIDIAN","tMONTH","tMONTH_UNIT","tSEC_UNIT","tSNUMBER","tUNUMBER","tZONE",
278 };
279 const char * const yyrule[] = {
280 "$accept : spec",
281 "spec :",
282 "spec : spec item",
283 "item : time",
284 "item : time zone",
285 "item : date",
286 "item : rel",
287 "time : tUNUMBER o_merid",
288 "time : tUNUMBER ':' tUNUMBER o_merid",
289 "time : tUNUMBER ':' tUNUMBER numzone",
290 "time : tUNUMBER ':' tUNUMBER ':' tUNUMBER o_merid",
291 "time : tUNUMBER ':' tUNUMBER ':' tUNUMBER numzone",
292 "zone : tZONE",
293 "zone : tDAYZONE",
294 "zone : tZONE numzone",
295 "zone : numzone",
296 "numzone : tSNUMBER",
297 "date : tUNUMBER '/' tUNUMBER",
298 "date : tUNUMBER '/' tUNUMBER '/' tUNUMBER",
299 "date : tMONTH tUNUMBER",
300 "date : tMONTH tUNUMBER ',' tUNUMBER",
301 "date : tUNUMBER tMONTH",
302 "date : tUNUMBER tMONTH tUNUMBER",
303 "date : tDAY ',' tUNUMBER tMONTH tUNUMBER",
304 "rel : tSNUMBER tSEC_UNIT",
305 "rel : tUNUMBER tSEC_UNIT",
306 "rel : tSNUMBER tMONTH_UNIT",
307 "rel : tUNUMBER tMONTH_UNIT",
308 "o_merid :",
309 "o_merid : tMERIDIAN",
310 };
311 #endif
312 #if YYDEBUG
313 #include <stdio.h>
314 #endif
315 #ifdef YYSTACKSIZE
316 #undef YYMAXDEPTH
317 #define YYMAXDEPTH YYSTACKSIZE
318 #else
319 #ifdef YYMAXDEPTH
320 #define YYSTACKSIZE YYMAXDEPTH
321 #else
322 #define YYSTACKSIZE 10000
323 #define YYMAXDEPTH 10000
324 #endif
325 #endif
326 #define YYINITSTACKSIZE 200
327 int yydebug;
328 int yynerrs;
329 int yyerrflag;
330 int yychar;
331 short *yyssp;
332 YYSTYPE *yyvsp;
333 YYSTYPE yyval;
334 YYSTYPE yylval;
335 short *yyss;
336 short *yysslim;
337 YYSTYPE *yyvs;
338 int yystacksize;
339 #line 312 "parsedate.y"
340
341 /* Month and day table. */
342 static TABLE    MonthDayTable[] = {
343     { "january",        tMONTH,  1 },
344     { "february",       tMONTH,  2 },
345     { "march",          tMONTH,  3 },
346     { "april",          tMONTH,  4 },
347     { "may",            tMONTH,  5 },
348     { "june",           tMONTH,  6 },
349     { "july",           tMONTH,  7 },
350     { "august",         tMONTH,  8 },
351     { "september",      tMONTH,  9 },
352     { "october",        tMONTH, 10 },
353     { "november",       tMONTH, 11 },
354     { "december",       tMONTH, 12 },
355         /* The value of the day isn't used... */
356     { "sunday",         tDAY, 0 },
357     { "monday",         tDAY, 0 },
358     { "tuesday",        tDAY, 0 },
359     { "wednesday",      tDAY, 0 },
360     { "thursday",       tDAY, 0 },
361     { "friday",         tDAY, 0 },
362     { "saturday",       tDAY, 0 },
363 };
364
365 /* Time units table. */
366 static TABLE    UnitsTable[] = {
367     { "year",           tMONTH_UNIT,    12 },
368     { "month",          tMONTH_UNIT,    1 },
369     { "week",           tSEC_UNIT,      7L * 24 * 60 * 60 },
370     { "day",            tSEC_UNIT,      1L * 24 * 60 * 60 },
371     { "hour",           tSEC_UNIT,      60 * 60 },
372     { "minute",         tSEC_UNIT,      60 },
373     { "min",            tSEC_UNIT,      60 },
374     { "second",         tSEC_UNIT,      1 },
375     { "sec",            tSEC_UNIT,      1 },
376 };
377
378 /* Timezone table. */
379 static TABLE    TimezoneTable[] = {
380     { "gmt",    tZONE,     HOUR( 0) },  /* Greenwich Mean */
381     { "ut",     tZONE,     HOUR( 0) },  /* Universal */
382     { "utc",    tZONE,     HOUR( 0) },  /* Universal Coordinated */
383     { "cut",    tZONE,     HOUR( 0) },  /* Coordinated Universal */
384     { "z",      tZONE,     HOUR( 0) },  /* Greenwich Mean */
385     { "wet",    tZONE,     HOUR( 0) },  /* Western European */
386     { "bst",    tDAYZONE,  HOUR( 0) },  /* British Summer */
387     { "nst",    tZONE,     HOUR(3)+30 }, /* Newfoundland Standard */
388     { "ndt",    tDAYZONE,  HOUR(3)+30 }, /* Newfoundland Daylight */
389     { "ast",    tZONE,     HOUR( 4) },  /* Atlantic Standard */
390     { "adt",    tDAYZONE,  HOUR( 4) },  /* Atlantic Daylight */
391     { "est",    tZONE,     HOUR( 5) },  /* Eastern Standard */
392     { "edt",    tDAYZONE,  HOUR( 5) },  /* Eastern Daylight */
393     { "cst",    tZONE,     HOUR( 6) },  /* Central Standard */
394     { "cdt",    tDAYZONE,  HOUR( 6) },  /* Central Daylight */
395     { "mst",    tZONE,     HOUR( 7) },  /* Mountain Standard */
396     { "mdt",    tDAYZONE,  HOUR( 7) },  /* Mountain Daylight */
397     { "pst",    tZONE,     HOUR( 8) },  /* Pacific Standard */
398     { "pdt",    tDAYZONE,  HOUR( 8) },  /* Pacific Daylight */
399     { "yst",    tZONE,     HOUR( 9) },  /* Yukon Standard */
400     { "ydt",    tDAYZONE,  HOUR( 9) },  /* Yukon Daylight */
401     { "akst",   tZONE,     HOUR( 9) },  /* Alaska Standard */
402     { "akdt",   tDAYZONE,  HOUR( 9) },  /* Alaska Daylight */
403     { "hst",    tZONE,     HOUR(10) },  /* Hawaii Standard */
404     { "hast",   tZONE,     HOUR(10) },  /* Hawaii-Aleutian Standard */
405     { "hadt",   tDAYZONE,  HOUR(10) },  /* Hawaii-Aleutian Daylight */
406     { "ces",    tDAYZONE,  -HOUR(1) },  /* Central European Summer */
407     { "cest",   tDAYZONE,  -HOUR(1) },  /* Central European Summer */
408     { "mez",    tZONE,     -HOUR(1) },  /* Middle European */
409     { "mezt",   tDAYZONE,  -HOUR(1) },  /* Middle European Summer */
410     { "cet",    tZONE,     -HOUR(1) },  /* Central European */
411     { "met",    tZONE,     -HOUR(1) },  /* Middle European */
412     { "eet",    tZONE,     -HOUR(2) },  /* Eastern Europe */
413     { "msk",    tZONE,     -HOUR(3) },  /* Moscow Winter */
414     { "msd",    tDAYZONE,  -HOUR(3) },  /* Moscow Summer */
415     { "wast",   tZONE,     -HOUR(8) },  /* West Australian Standard */
416     { "wadt",   tDAYZONE,  -HOUR(8) },  /* West Australian Daylight */
417     { "hkt",    tZONE,     -HOUR(8) },  /* Hong Kong */
418     { "cct",    tZONE,     -HOUR(8) },  /* China Coast */
419     { "jst",    tZONE,     -HOUR(9) },  /* Japan Standard */
420     { "kst",    tZONE,     -HOUR(9) },  /* Korean Standard */
421     { "kdt",    tZONE,     -HOUR(9) },  /* Korean Daylight */
422     { "cast",   tZONE,     -(HOUR(9)+30) }, /* Central Australian Standard */
423     { "cadt",   tDAYZONE,  -(HOUR(9)+30) }, /* Central Australian Daylight */
424     { "east",   tZONE,     -HOUR(10) }, /* Eastern Australian Standard */
425     { "eadt",   tDAYZONE,  -HOUR(10) }, /* Eastern Australian Daylight */
426     { "nzst",   tZONE,     -HOUR(12) }, /* New Zealand Standard */
427     { "nzdt",   tDAYZONE,  -HOUR(12) }, /* New Zealand Daylight */
428
429     /* For completeness we include the following entries. */
430 #if 0
431
432     /* Duplicate names.  Either they conflict with a zone listed above
433      * (which is either more likely to be seen or just been in circulation
434      * longer), or they conflict with another zone in this section and
435      * we could not reasonably choose one over the other. */
436     { "fst",    tZONE,     HOUR( 2) },  /* Fernando De Noronha Standard */
437     { "fdt",    tDAYZONE,  HOUR( 2) },  /* Fernando De Noronha Daylight */
438     { "bst",    tZONE,     HOUR( 3) },  /* Brazil Standard */
439     { "est",    tZONE,     HOUR( 3) },  /* Eastern Standard (Brazil) */
440     { "edt",    tDAYZONE,  HOUR( 3) },  /* Eastern Daylight (Brazil) */
441     { "wst",    tZONE,     HOUR( 4) },  /* Western Standard (Brazil) */
442     { "wdt",    tDAYZONE,  HOUR( 4) },  /* Western Daylight (Brazil) */
443     { "cst",    tZONE,     HOUR( 5) },  /* Chile Standard */
444     { "cdt",    tDAYZONE,  HOUR( 5) },  /* Chile Daylight */
445     { "ast",    tZONE,     HOUR( 5) },  /* Acre Standard */
446     { "adt",    tDAYZONE,  HOUR( 5) },  /* Acre Daylight */
447     { "cst",    tZONE,     HOUR( 5) },  /* Cuba Standard */
448     { "cdt",    tDAYZONE,  HOUR( 5) },  /* Cuba Daylight */
449     { "est",    tZONE,     HOUR( 6) },  /* Easter Island Standard */
450     { "edt",    tDAYZONE,  HOUR( 6) },  /* Easter Island Daylight */
451     { "sst",    tZONE,     HOUR(11) },  /* Samoa Standard */
452     { "ist",    tZONE,     -HOUR(2) },  /* Israel Standard */
453     { "idt",    tDAYZONE,  -HOUR(2) },  /* Israel Daylight */
454     { "idt",    tDAYZONE,  -(HOUR(3)+30) }, /* Iran Daylight */
455     { "ist",    tZONE,     -(HOUR(3)+30) }, /* Iran Standard */
456     { "cst",     tZONE,     -HOUR(8) }, /* China Standard */
457     { "cdt",     tDAYZONE,  -HOUR(8) }, /* China Daylight */
458     { "sst",     tZONE,     -HOUR(8) }, /* Singapore Standard */
459
460     /* Dubious (e.g., not in Olson's TIMEZONE package) or obsolete. */
461     { "gst",    tZONE,     HOUR( 3) },  /* Greenland Standard */
462     { "wat",    tZONE,     -HOUR(1) },  /* West Africa */
463     { "at",     tZONE,     HOUR( 2) },  /* Azores */
464     { "gst",    tZONE,     -HOUR(10) }, /* Guam Standard */
465     { "nft",    tZONE,     HOUR(3)+30 }, /* Newfoundland */
466     { "idlw",   tZONE,     HOUR(12) },  /* International Date Line West */
467     { "mewt",   tZONE,     -HOUR(1) },  /* Middle European Winter */
468     { "mest",   tDAYZONE,  -HOUR(1) },  /* Middle European Summer */
469     { "swt",    tZONE,     -HOUR(1) },  /* Swedish Winter */
470     { "sst",    tDAYZONE,  -HOUR(1) },  /* Swedish Summer */
471     { "fwt",    tZONE,     -HOUR(1) },  /* French Winter */
472     { "fst",    tDAYZONE,  -HOUR(1) },  /* French Summer */
473     { "bt",     tZONE,     -HOUR(3) },  /* Baghdad */
474     { "it",     tZONE,     -(HOUR(3)+30) }, /* Iran */
475     { "zp4",    tZONE,     -HOUR(4) },  /* USSR Zone 3 */
476     { "zp5",    tZONE,     -HOUR(5) },  /* USSR Zone 4 */
477     { "ist",    tZONE,     -(HOUR(5)+30) }, /* Indian Standard */
478     { "zp6",    tZONE,     -HOUR(6) },  /* USSR Zone 5 */
479     { "nst",    tZONE,     -HOUR(7) },  /* North Sumatra */
480     { "sst",    tZONE,     -HOUR(7) },  /* South Sumatra */
481     { "jt",     tZONE,     -(HOUR(7)+30) }, /* Java (3pm in Cronusland!) */
482     { "nzt",    tZONE,     -HOUR(12) }, /* New Zealand */
483     { "idle",   tZONE,     -HOUR(12) }, /* International Date Line East */
484     { "cat",    tZONE,     HOUR(10) },  /* -- expired 1967 */
485     { "nt",     tZONE,     HOUR(11) },  /* -- expired 1967 */
486     { "ahst",   tZONE,     HOUR(10) },  /* -- expired 1983 */
487     { "hdt",    tDAYZONE,  HOUR(10) },  /* -- expired 1986 */
488 #endif /* 0 */
489 };
490
491
492 /* ARGSUSED */
493 static void
494 date_error(char *s)
495 {
496     /* NOTREACHED */
497 }
498
499
500 static time_t
501 ToSeconds(time_t Hours, time_t Minutes, time_t Seconds, MERIDIAN Meridian)
502 {
503     if (Minutes < 0 || Minutes > 59 || Seconds < 0 || Seconds > 61)
504         return -1;
505     if (Meridian == MER24) {
506         if (Hours < 0 || Hours > 23)
507             return -1;
508     }
509     else {
510         if (Hours < 1 || Hours > 12)
511             return -1;
512         if (Hours == 12)
513             Hours = 0;
514         if (Meridian == MERpm)
515             Hours += 12;
516     }
517     return (Hours * 60L + Minutes) * 60L + Seconds;
518 }
519
520
521 static time_t
522 Convert(time_t Month, time_t Day, time_t Year,
523         time_t Hours, time_t Minutes, time_t Seconds,
524         MERIDIAN Meridian, DSTMODE dst)
525 {
526     static int  DaysNormal[13] = {
527         0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
528     };
529     static int  DaysLeap[13] = {
530         0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
531     };
532     static int  LeapYears[] = {
533         1972, 1976, 1980, 1984, 1988, 1992, 1996,
534         2000, 2004, 2008, 2012, 2016, 2020, 2024, 2028, 2032, 2036
535     };
536     register int        *yp;
537     register int        *mp;
538     register time_t     Julian;
539     register int        i;
540     time_t              tod;
541
542     if (Year < 0)
543         Year = -Year;
544     if (Year < 100)
545         Year += 1900;
546     if (Year < EPOCH)
547         Year += 100;
548     for (mp = DaysNormal, yp = LeapYears; yp < ENDOF(LeapYears); yp++)
549         if (Year == *yp) {
550             mp = DaysLeap;
551             break;
552         }
553     if (Year < EPOCH || Year > END_OF_TIME
554      || Month < 1 || Month > 12
555      /* NOSTRICT *//* conversion from long may lose accuracy */
556      || Day < 1 || Day > mp[(int)Month])
557         return -1;
558
559     Julian = Day - 1 + (Year - EPOCH) * 365;
560     for (yp = LeapYears; yp < ENDOF(LeapYears); yp++, Julian++)
561         if (Year <= *yp)
562             break;
563     for (i = 1; i < Month; i++)
564         Julian += *++mp;
565     Julian *= SECSPERDAY;
566     Julian += yyTimezone * 60L;
567     if ((tod = ToSeconds(Hours, Minutes, Seconds, Meridian)) < 0)
568         return -1;
569     Julian += tod;
570     tod = Julian;
571     if (dst == DSTon || (dst == DSTmaybe && localtime(&tod)->tm_isdst))
572         Julian -= DST_OFFSET * 60L * 60L;
573     return Julian;
574 }
575
576
577 static time_t
578 DSTcorrect(time_t Start, time_t Future)
579 {
580     time_t      StartDay;
581     time_t      FutureDay;
582
583     StartDay = (localtime(&Start)->tm_hour + 1) % 24;
584     FutureDay = (localtime(&Future)->tm_hour + 1) % 24;
585     return (Future - Start) + (StartDay - FutureDay) * DST_OFFSET * 60L * 60L;
586 }
587
588
589 static time_t
590 RelativeMonth(time_t Start, time_t RelMonth)
591 {
592     struct tm   *tm;
593     time_t      Month;
594     time_t      Year;
595
596     tm = localtime(&Start);
597     Month = 12 * tm->tm_year + tm->tm_mon + RelMonth;
598     Year = Month / 12;
599     Month = Month % 12 + 1;
600     return DSTcorrect(Start,
601             Convert(Month, (time_t)tm->tm_mday, Year,
602                 (time_t)tm->tm_hour, (time_t)tm->tm_min, (time_t)tm->tm_sec,
603                 MER24, DSTmaybe));
604 }
605
606
607 static int
608 LookupWord(char *buff, register int length)
609 {
610     register char       *p;
611     register char       *q;
612     register TABLE      *tp;
613     register int        c;
614
615     p = buff;
616     c = p[0];
617
618     /* See if we have an abbreviation for a month. */
619     if (length == 3 || (length == 4 && p[3] == '.'))
620         for (tp = MonthDayTable; tp < ENDOF(MonthDayTable); tp++) {
621             q = tp->name;
622             if (c == q[0] && p[1] == q[1] && p[2] == q[2]) {
623                 yylval.Number = tp->value;
624                 return tp->type;
625             }
626         }
627     else
628         for (tp = MonthDayTable; tp < ENDOF(MonthDayTable); tp++)
629             if (c == tp->name[0] && strcmp(p, tp->name) == 0) {
630                 yylval.Number = tp->value;
631                 return tp->type;
632             }
633
634     /* Try for a timezone. */
635     for (tp = TimezoneTable; tp < ENDOF(TimezoneTable); tp++)
636         if (c == tp->name[0] && p[1] == tp->name[1]
637          && strcmp(p, tp->name) == 0) {
638             yylval.Number = tp->value;
639             return tp->type;
640         }
641
642     /* Try the units table. */
643     for (tp = UnitsTable; tp < ENDOF(UnitsTable); tp++)
644         if (c == tp->name[0] && strcmp(p, tp->name) == 0) {
645             yylval.Number = tp->value;
646             return tp->type;
647         }
648
649     /* Strip off any plural and try the units table again. */
650     if (--length > 0 && p[length] == 's') {
651         p[length] = '\0';
652         for (tp = UnitsTable; tp < ENDOF(UnitsTable); tp++)
653             if (c == tp->name[0] && strcmp(p, tp->name) == 0) {
654                 p[length] = 's';
655                 yylval.Number = tp->value;
656                 return tp->type;
657             }
658         p[length] = 's';
659     }
660     length++;
661
662     /* Drop out any periods. */
663     for (p = buff, q = (char*)buff; *q; q++)
664         if (*q != '.')
665             *p++ = *q;
666     *p = '\0';
667
668     /* Try the meridians. */
669     if (buff[1] == 'm' && buff[2] == '\0') {
670         if (buff[0] == 'a') {
671             yylval.Meridian = MERam;
672             return tMERIDIAN;
673         }
674         if (buff[0] == 'p') {
675             yylval.Meridian = MERpm;
676             return tMERIDIAN;
677         }
678     }
679
680     /* If we saw any periods, try the timezones again. */
681     if (p - buff != length) {
682         c = buff[0];
683         for (p = buff, tp = TimezoneTable; tp < ENDOF(TimezoneTable); tp++)
684             if (c == tp->name[0] && p[1] == tp->name[1]
685             && strcmp(p, tp->name) == 0) {
686                 yylval.Number = tp->value;
687                 return tp->type;
688             }
689     }
690
691     /* Unknown word -- assume GMT timezone. */
692     yylval.Number = 0;
693     return tZONE;
694 }
695
696
697 int
698 date_lex(void)
699 {
700     register char       c;
701     register char       *p;
702     char                buff[20];
703     register int        sign;
704     register int        i;
705     register int        nesting;
706
707     for ( ; ; ) {
708         /* Get first character after the whitespace. */
709         for ( ; ; ) {
710             while (isspace(*yyInput))
711                 yyInput++;
712             c = *yyInput;
713
714             /* Ignore RFC 822 comments, typically time zone names. */
715             if (c != LPAREN)
716                 break;
717             for (nesting = 1; (c = *++yyInput) != RPAREN || --nesting; )
718                 if (c == LPAREN)
719                     nesting++;
720                 else if (!IS7BIT(c) || c == '\0' || c == '\r'
721                      || (c == '\\' && ((c = *++yyInput) == '\0' || !IS7BIT(c))))
722                     /* Lexical error: bad comment. */
723                     return '?';
724             yyInput++;
725         }
726
727         /* A number? */
728         if (isdigit(c) || c == '-' || c == '+') {
729             if (c == '-' || c == '+') {
730                 sign = c == '-' ? -1 : 1;
731                 yyInput++;
732                 if (!isdigit(*yyInput))
733                     /* Skip the plus or minus sign. */
734                     continue;
735             }
736             else
737                 sign = 0;
738             for (i = 0; (c = *yyInput++) != '\0' && isdigit(c); )
739                 i = 10 * i + c - '0';
740             yyInput--;
741             yylval.Number = sign < 0 ? -i : i;
742             return sign ? tSNUMBER : tUNUMBER;
743         }
744
745         /* A word? */
746         if (isalpha(c)) {
747             for (p = buff; (c = *yyInput++) == '.' || isalpha(c); )
748                 if (p < &buff[sizeof buff - 1])
749                     *p++ = isupper(c) ? tolower(c) : c;
750             *p = '\0';
751             yyInput--;
752             return LookupWord(buff, p - buff);
753         }
754
755         return *yyInput++;
756     }
757 }
758
759
760 time_t
761 parsedate(char *p)
762 {
763     extern int          date_parse(void);
764     time_t              Start;
765
766     yyInput = p;
767
768     yyYear = 0;
769     yyMonth = 0;
770     yyDay = 0;
771     yyTimezone = 0;
772     yyDSTmode = DSTmaybe;
773     yyHour = 0;
774     yyMinutes = 0;
775     yySeconds = 0;
776     yyMeridian = MER24;
777     yyRelSeconds = 0;
778     yyRelMonth = 0;
779     yyHaveDate = 0;
780     yyHaveRel = 0;
781     yyHaveTime = 0;
782
783     if (date_parse() || yyHaveTime > 1 || yyHaveDate > 1)
784         return -1;
785
786     if (yyHaveDate || yyHaveTime) {
787         Start = Convert(yyMonth, yyDay, yyYear, yyHour, yyMinutes, yySeconds,
788                     yyMeridian, yyDSTmode);
789         if (Start < 0)
790             return -1;
791     }
792     else
793         return -1;
794
795     Start += yyRelSeconds;
796     if (yyRelMonth)
797         Start += RelativeMonth(Start, yyRelMonth);
798
799     /* Have to do *something* with a legitimate -1 so it's distinguishable
800      * from the error return value.  (Alternately could set errno on error.) */
801     return Start == -1 ? 0 : Start;
802 }
803
804
805 #ifdef TEST
806
807 #if YYDEBUG
808 extern int      yydebug;
809 #endif /* YYDEBUG */
810
811 /* ARGSUSED */
812 int
813 main(int ac, char *av[])
814 {
815     char        buff[128];
816     time_t      d;
817
818 #if YYDEBUG
819     yydebug = 1;
820 #endif /* YYDEBUG */
821
822     (void)printf("Enter date, or blank line to exit.\n\t> ");
823     for ( ; ; ) {
824         (void)printf("\t> ");
825         (void)fflush(stdout);
826         if (fgets(buff, sizeof buff, stdin) == NULL || buff[0] == '\n')
827             break;
828 #if YYDEBUG
829         if (strcmp(buff, "yydebug") == 0) {
830             yydebug = !yydebug;
831             printf("yydebug = %s\n", yydebug ? "on" : "off");
832             continue;
833         }
834 #endif /* YYDEBUG */
835         d = parsedate(buff, (TIMEINFO *)NULL);
836         if (d == -1)
837             (void)printf("Bad format - couldn't convert.\n");
838         else
839             (void)printf("%s", ctime(&d));
840     }
841
842     exit(0);
843     /* NOTREACHED */
844 }
845 #endif /* TEST */
846 #line 847 "y.tab.c"
847 /* allocate initial stack or double stack size, up to YYMAXDEPTH */
848 static int yygrowstack()
849 {
850     int newsize, i;
851     short *newss;
852     YYSTYPE *newvs;
853
854     if ((newsize = yystacksize) == 0)
855         newsize = YYINITSTACKSIZE;
856     else if (newsize >= YYMAXDEPTH)
857         return -1;
858     else if ((newsize *= 2) > YYMAXDEPTH)
859         newsize = YYMAXDEPTH;
860     i = yyssp - yyss;
861     newss = yyss ? (short *)realloc(yyss, newsize * sizeof *newss) :
862       (short *)malloc(newsize * sizeof *newss);
863     if (newss == NULL)
864         return -1;
865     yyss = newss;
866     yyssp = newss + i;
867     newvs = yyvs ? (YYSTYPE *)realloc(yyvs, newsize * sizeof *newvs) :
868       (YYSTYPE *)malloc(newsize * sizeof *newvs);
869     if (newvs == NULL)
870         return -1;
871     yyvs = newvs;
872     yyvsp = newvs + i;
873     yystacksize = newsize;
874     yysslim = yyss + newsize - 1;
875     return 0;
876 }
877
878 #define YYABORT goto yyabort
879 #define YYREJECT goto yyabort
880 #define YYACCEPT goto yyaccept
881 #define YYERROR goto yyerrlab
882
883 #ifndef YYPARSE_PARAM
884 #if defined(__cplusplus) || __STDC__
885 #define YYPARSE_PARAM_ARG void
886 #define YYPARSE_PARAM_DECL
887 #else   /* ! ANSI-C/C++ */
888 #define YYPARSE_PARAM_ARG
889 #define YYPARSE_PARAM_DECL
890 #endif  /* ANSI-C/C++ */
891 #else   /* YYPARSE_PARAM */
892 #ifndef YYPARSE_PARAM_TYPE
893 #define YYPARSE_PARAM_TYPE void *
894 #endif
895 #if defined(__cplusplus) || __STDC__
896 #define YYPARSE_PARAM_ARG YYPARSE_PARAM_TYPE YYPARSE_PARAM
897 #define YYPARSE_PARAM_DECL
898 #else   /* ! ANSI-C/C++ */
899 #define YYPARSE_PARAM_ARG YYPARSE_PARAM
900 #define YYPARSE_PARAM_DECL YYPARSE_PARAM_TYPE YYPARSE_PARAM;
901 #endif  /* ANSI-C/C++ */
902 #endif  /* ! YYPARSE_PARAM */
903
904 int
905 yyparse (YYPARSE_PARAM_ARG)
906     YYPARSE_PARAM_DECL
907 {
908     int yym, yyn, yystate;
909 #if YYDEBUG
910     const char *yys;
911
912     if ((yys = getenv("YYDEBUG")))
913     {
914         yyn = *yys;
915         if (yyn >= '0' && yyn <= '9')
916             yydebug = yyn - '0';
917     }
918 #endif
919
920     yynerrs = 0;
921     yyerrflag = 0;
922     yychar = (-1);
923
924     if (yyss == NULL && yygrowstack()) goto yyoverflow;
925     yyssp = yyss;
926     yyvsp = yyvs;
927     *yyssp = yystate = 0;
928
929 yyloop:
930     if ((yyn = yydefred[yystate])) goto yyreduce;
931     if (yychar < 0)
932     {
933         if ((yychar = yylex()) < 0) yychar = 0;
934 #if YYDEBUG
935         if (yydebug)
936         {
937             yys = 0;
938             if (yychar <= YYMAXTOKEN) yys = yyname[yychar];
939             if (!yys) yys = "illegal-symbol";
940             printf("%sdebug: state %d, reading %d (%s)\n",
941                     YYPREFIX, yystate, yychar, yys);
942         }
943 #endif
944     }
945     if ((yyn = yysindex[yystate]) && (yyn += yychar) >= 0 &&
946             yyn <= YYTABLESIZE && yycheck[yyn] == yychar)
947     {
948 #if YYDEBUG
949         if (yydebug)
950             printf("%sdebug: state %d, shifting to state %d\n",
951                     YYPREFIX, yystate, yytable[yyn]);
952 #endif
953         if (yyssp >= yysslim && yygrowstack())
954         {
955             goto yyoverflow;
956         }
957         *++yyssp = yystate = yytable[yyn];
958         *++yyvsp = yylval;
959         yychar = (-1);
960         if (yyerrflag > 0)  --yyerrflag;
961         goto yyloop;
962     }
963     if ((yyn = yyrindex[yystate]) && (yyn += yychar) >= 0 &&
964             yyn <= YYTABLESIZE && yycheck[yyn] == yychar)
965     {
966         yyn = yytable[yyn];
967         goto yyreduce;
968     }
969     if (yyerrflag) goto yyinrecovery;
970 #if defined(lint) || defined(__GNUC__)
971     goto yynewerror;
972 #endif
973 yynewerror:
974     yyerror("syntax error");
975 #if defined(lint) || defined(__GNUC__)
976     goto yyerrlab;
977 #endif
978 yyerrlab:
979     ++yynerrs;
980 yyinrecovery:
981     if (yyerrflag < 3)
982     {
983         yyerrflag = 3;
984         for (;;)
985         {
986             if ((yyn = yysindex[*yyssp]) && (yyn += YYERRCODE) >= 0 &&
987                     yyn <= YYTABLESIZE && yycheck[yyn] == YYERRCODE)
988             {
989 #if YYDEBUG
990                 if (yydebug)
991                     printf("%sdebug: state %d, error recovery shifting\
992  to state %d\n", YYPREFIX, *yyssp, yytable[yyn]);
993 #endif
994                 if (yyssp >= yysslim && yygrowstack())
995                 {
996                     goto yyoverflow;
997                 }
998                 *++yyssp = yystate = yytable[yyn];
999                 *++yyvsp = yylval;
1000                 goto yyloop;
1001             }
1002             else
1003             {
1004 #if YYDEBUG
1005                 if (yydebug)
1006                     printf("%sdebug: error recovery discarding state %d\n",
1007                             YYPREFIX, *yyssp);
1008 #endif
1009                 if (yyssp <= yyss) goto yyabort;
1010                 --yyssp;
1011                 --yyvsp;
1012             }
1013         }
1014     }
1015     else
1016     {
1017         if (yychar == 0) goto yyabort;
1018 #if YYDEBUG
1019         if (yydebug)
1020         {
1021             yys = 0;
1022             if (yychar <= YYMAXTOKEN) yys = yyname[yychar];
1023             if (!yys) yys = "illegal-symbol";
1024             printf("%sdebug: state %d, error recovery discards token %d (%s)\n",
1025                     YYPREFIX, yystate, yychar, yys);
1026         }
1027 #endif
1028         yychar = (-1);
1029         goto yyloop;
1030     }
1031 yyreduce:
1032 #if YYDEBUG
1033     if (yydebug)
1034         printf("%sdebug: state %d, reducing by rule %d (%s)\n",
1035                 YYPREFIX, yystate, yyn, yyrule[yyn]);
1036 #endif
1037     yym = yylen[yyn];
1038     yyval = yyvsp[1-yym];
1039     switch (yyn)
1040     {
1041 case 3:
1042 #line 143 "parsedate.y"
1043 {
1044             yyHaveTime++;
1045 #ifdef lint
1046             /* I am compulsive about lint natterings... */
1047             if (yyHaveTime == -1) {
1048                 YYERROR;
1049             }
1050 #endif /* lint */
1051         }
1052 break;
1053 case 4:
1054 #line 152 "parsedate.y"
1055 {
1056             yyHaveTime++;
1057             yyTimezone = yyvsp[0].Number;
1058         }
1059 break;
1060 case 5:
1061 #line 156 "parsedate.y"
1062 {
1063             yyHaveDate++;
1064         }
1065 break;
1066 case 6:
1067 #line 159 "parsedate.y"
1068 {
1069             yyHaveRel = 1;
1070         }
1071 break;
1072 case 7:
1073 #line 164 "parsedate.y"
1074 {
1075             if (yyvsp[-1].Number < 100) {
1076                 yyHour = yyvsp[-1].Number;
1077                 yyMinutes = 0;
1078             }
1079             else {
1080                 yyHour = yyvsp[-1].Number / 100;
1081                 yyMinutes = yyvsp[-1].Number % 100;
1082             }
1083             yySeconds = 0;
1084             yyMeridian = yyvsp[0].Meridian;
1085         }
1086 break;
1087 case 8:
1088 #line 176 "parsedate.y"
1089 {
1090             yyHour = yyvsp[-3].Number;
1091             yyMinutes = yyvsp[-1].Number;
1092             yySeconds = 0;
1093             yyMeridian = yyvsp[0].Meridian;
1094         }
1095 break;
1096 case 9:
1097 #line 182 "parsedate.y"
1098 {
1099             yyHour = yyvsp[-3].Number;
1100             yyMinutes = yyvsp[-1].Number;
1101             yyTimezone = yyvsp[0].Number;
1102             yyMeridian = MER24;
1103             yyDSTmode = DSToff;
1104         }
1105 break;
1106 case 10:
1107 #line 189 "parsedate.y"
1108 {
1109             yyHour = yyvsp[-5].Number;
1110             yyMinutes = yyvsp[-3].Number;
1111             yySeconds = yyvsp[-1].Number;
1112             yyMeridian = yyvsp[0].Meridian;
1113         }
1114 break;
1115 case 11:
1116 #line 195 "parsedate.y"
1117 {
1118             yyHour = yyvsp[-5].Number;
1119             yyMinutes = yyvsp[-3].Number;
1120             yySeconds = yyvsp[-1].Number;
1121             yyTimezone = yyvsp[0].Number;
1122             yyMeridian = MER24;
1123             yyDSTmode = DSToff;
1124         }
1125 break;
1126 case 12:
1127 #line 205 "parsedate.y"
1128 {
1129             yyval.Number = yyvsp[0].Number;
1130             yyDSTmode = DSToff;
1131         }
1132 break;
1133 case 13:
1134 #line 209 "parsedate.y"
1135 {
1136             yyval.Number = yyvsp[0].Number;
1137             yyDSTmode = DSTon;
1138         }
1139 break;
1140 case 14:
1141 #line 213 "parsedate.y"
1142 {
1143             /* Only allow "GMT+300" and "GMT-0800" */
1144             if (yyvsp[-1].Number != 0) {
1145                 YYABORT;
1146             }
1147             yyval.Number = yyvsp[0].Number;
1148             yyDSTmode = DSToff;
1149         }
1150 break;
1151 case 15:
1152 #line 221 "parsedate.y"
1153 {
1154             yyval.Number = yyvsp[0].Number;
1155             yyDSTmode = DSToff;
1156         }
1157 break;
1158 case 16:
1159 #line 227 "parsedate.y"
1160 {
1161             int         i;
1162
1163             /* Unix and GMT and numeric timezones -- a little confusing. */
1164             if (yyvsp[0].Number < 0) {
1165                 /* Don't work with negative modulus. */
1166                 yyvsp[0].Number = -yyvsp[0].Number;
1167                 if (yyvsp[0].Number > 9999 || (i = yyvsp[0].Number % 100) >= 60) {
1168                     YYABORT;
1169                 }
1170                 yyval.Number = (yyvsp[0].Number / 100) * 60 + i;
1171             }
1172             else {
1173                 if (yyvsp[0].Number > 9999 || (i = yyvsp[0].Number % 100) >= 60) {
1174                     YYABORT;
1175                 }
1176                 yyval.Number = -((yyvsp[0].Number / 100) * 60 + i);
1177             }
1178         }
1179 break;
1180 case 17:
1181 #line 248 "parsedate.y"
1182 {
1183             yyMonth = yyvsp[-2].Number;
1184             yyDay = yyvsp[0].Number;
1185         }
1186 break;
1187 case 18:
1188 #line 252 "parsedate.y"
1189 {
1190             if (yyvsp[-4].Number > 100) {
1191                 yyYear = yyvsp[-4].Number;
1192                 yyMonth = yyvsp[-2].Number;
1193                 yyDay = yyvsp[0].Number;
1194             }
1195             else {
1196                 yyMonth = yyvsp[-4].Number;
1197                 yyDay = yyvsp[-2].Number;
1198                 yyYear = yyvsp[0].Number;
1199             }
1200         }
1201 break;
1202 case 19:
1203 #line 264 "parsedate.y"
1204 {
1205             yyMonth = yyvsp[-1].Number;
1206             yyDay = yyvsp[0].Number;
1207         }
1208 break;
1209 case 20:
1210 #line 268 "parsedate.y"
1211 {
1212             yyMonth = yyvsp[-3].Number;
1213             yyDay = yyvsp[-2].Number;
1214             yyYear = yyvsp[0].Number;
1215         }
1216 break;
1217 case 21:
1218 #line 273 "parsedate.y"
1219 {
1220             yyDay = yyvsp[-1].Number;
1221             yyMonth = yyvsp[0].Number;
1222         }
1223 break;
1224 case 22:
1225 #line 277 "parsedate.y"
1226 {
1227             yyDay = yyvsp[-2].Number;
1228             yyMonth = yyvsp[-1].Number;
1229             yyYear = yyvsp[0].Number;
1230         }
1231 break;
1232 case 23:
1233 #line 282 "parsedate.y"
1234 {
1235             yyDay = yyvsp[-2].Number;
1236             yyMonth = yyvsp[-1].Number;
1237             yyYear = yyvsp[0].Number;
1238         }
1239 break;
1240 case 24:
1241 #line 289 "parsedate.y"
1242 {
1243             yyRelSeconds += yyvsp[-1].Number * yyvsp[0].Number;
1244         }
1245 break;
1246 case 25:
1247 #line 292 "parsedate.y"
1248 {
1249             yyRelSeconds += yyvsp[-1].Number * yyvsp[0].Number;
1250         }
1251 break;
1252 case 26:
1253 #line 295 "parsedate.y"
1254 {
1255             yyRelMonth += yyvsp[-1].Number * yyvsp[0].Number;
1256         }
1257 break;
1258 case 27:
1259 #line 298 "parsedate.y"
1260 {
1261             yyRelMonth += yyvsp[-1].Number * yyvsp[0].Number;
1262         }
1263 break;
1264 case 28:
1265 #line 303 "parsedate.y"
1266 {
1267             yyval.Meridian = MER24;
1268         }
1269 break;
1270 case 29:
1271 #line 306 "parsedate.y"
1272 {
1273             yyval.Meridian = yyvsp[0].Meridian;
1274         }
1275 break;
1276 #line 1277 "y.tab.c"
1277     }
1278     yyssp -= yym;
1279     yystate = *yyssp;
1280     yyvsp -= yym;
1281     yym = yylhs[yyn];
1282     if (yystate == 0 && yym == 0)
1283     {
1284 #if YYDEBUG
1285         if (yydebug)
1286             printf("%sdebug: after reduction, shifting from state 0 to\
1287  state %d\n", YYPREFIX, YYFINAL);
1288 #endif
1289         yystate = YYFINAL;
1290         *++yyssp = YYFINAL;
1291         *++yyvsp = yyval;
1292         if (yychar < 0)
1293         {
1294             if ((yychar = yylex()) < 0) yychar = 0;
1295 #if YYDEBUG
1296             if (yydebug)
1297             {
1298                 yys = 0;
1299                 if (yychar <= YYMAXTOKEN) yys = yyname[yychar];
1300                 if (!yys) yys = "illegal-symbol";
1301                 printf("%sdebug: state %d, reading %d (%s)\n",
1302                         YYPREFIX, YYFINAL, yychar, yys);
1303             }
1304 #endif
1305         }
1306         if (yychar == 0) goto yyaccept;
1307         goto yyloop;
1308     }
1309     if ((yyn = yygindex[yym]) && (yyn += yystate) >= 0 &&
1310             yyn <= YYTABLESIZE && yycheck[yyn] == yystate)
1311         yystate = yytable[yyn];
1312     else
1313         yystate = yydgoto[yym];
1314 #if YYDEBUG
1315     if (yydebug)
1316         printf("%sdebug: after reduction, shifting from state %d \
1317 to state %d\n", YYPREFIX, *yyssp, yystate);
1318 #endif
1319     if (yyssp >= yysslim && yygrowstack())
1320     {
1321         goto yyoverflow;
1322     }
1323     *++yyssp = yystate;
1324     *++yyvsp = yyval;
1325     goto yyloop;
1326 yyoverflow:
1327     yyerror("yacc stack overflow");
1328 yyabort:
1329     return (1);
1330 yyaccept:
1331     return (0);
1332 }