4682759888f2c954fcdc3a1bb622c8fb4aebe50e
[citadel.git] / citadel / parsedate.c
1
2 /*  A Bison parser, made from parsedate.y with Bison version GNU Bison version 1.22
3   */
4
5 #define YYBISON 1  /* Identify Bison output.  */
6
7 #define tDAY    258
8 #define tDAYZONE        259
9 #define tMERIDIAN       260
10 #define tMONTH  261
11 #define tMONTH_UNIT     262
12 #define tSEC_UNIT       263
13 #define tSNUMBER        264
14 #define tUNUMBER        265
15 #define tZONE   266
16
17 #line 1 "parsedate.y"
18
19 /* $Revision$
20 **
21 **  Originally written by Steven M. Bellovin <smb@research.att.com> while
22 **  at the University of North Carolina at Chapel Hill.  Later tweaked by
23 **  a couple of people on Usenet.  Completely overhauled by Rich $alz
24 **  <rsalz@osf.org> and Jim Berets <jberets@bbn.com> in August, 1990.
25 **  Further revised (removed obsolete constructs and cleaned up timezone
26 **  names) in August, 1991, by Rich.  Paul Eggert <eggert@twinsun.com>
27 **  helped in September, 1992.
28 **
29 **  This grammar has six shift/reduce conflicts.
30 **
31 **  This code is in the public domain and has no copyright.
32 */
33 /* SUPPRESS 530 *//* Empty body for statement */
34 /* SUPPRESS 593 on yyerrlab *//* Label was not used */
35 /* SUPPRESS 593 on yynewstate *//* Label was not used */
36 /* SUPPRESS 595 on yypvt *//* Automatic variable may be used before set */
37 #include <stdio.h>
38 #include <sys/types.h>
39 #include <ctype.h>
40 #include <time.h>
41
42 int date_lex();
43
44 #define yyparse         date_parse
45 #define yylex           date_lex
46 #define yyerror         date_error
47
48
49     /* See the LeapYears table in Convert. */
50 #define EPOCH           1970
51 #define END_OF_TIME     2038
52     /* Constants for general time calculations. */
53 #define DST_OFFSET      1
54 #define SECSPERDAY      (24L * 60L * 60L)
55     /* Readability for TABLE stuff. */
56 #define HOUR(x)         (x * 60)
57
58 #define LPAREN          '('
59 #define RPAREN          ')'
60 #define IS7BIT(x)       ((unsigned int)(x) < 0200)
61
62 #define SIZEOF(array)   ((int)(sizeof array / sizeof array[0]))
63 #define ENDOF(array)    (&array[SIZEOF(array)])
64
65
66 /*
67 **  An entry in the lexical lookup table.
68 */
69 typedef struct _TABLE {
70     char        *name;
71     int         type;
72     time_t      value;
73 } TABLE;
74
75 /*
76 **  Daylight-savings mode:  on, off, or not yet known.
77 */
78 typedef enum _DSTMODE {
79     DSTon, DSToff, DSTmaybe
80 } DSTMODE;
81
82 /*
83 **  Meridian:  am, pm, or 24-hour style.
84 */
85 typedef enum _MERIDIAN {
86     MERam, MERpm, MER24
87 } MERIDIAN;
88
89
90 /*
91 **  Global variables.  We could get rid of most of them by using a yacc
92 **  union, but this is more efficient.  (This routine predates the
93 **  yacc %union construct.)
94 */
95 static char     *yyInput;
96 static DSTMODE  yyDSTmode;
97 static int      yyHaveDate;
98 static int      yyHaveRel;
99 static int      yyHaveTime;
100 static time_t   yyTimezone;
101 static time_t   yyDay;
102 static time_t   yyHour;
103 static time_t   yyMinutes;
104 static time_t   yyMonth;
105 static time_t   yySeconds;
106 static time_t   yyYear;
107 static MERIDIAN yyMeridian;
108 static time_t   yyRelMonth;
109 static time_t   yyRelSeconds;
110
111
112 extern struct tm        *localtime();
113
114 static void             date_error();
115
116 #line 100 "parsedate.y"
117 typedef union {
118     time_t              Number;
119     enum _MERIDIAN      Meridian;
120 } YYSTYPE;
121
122 #ifndef YYLTYPE
123 typedef
124   struct yyltype
125     {
126       int timestamp;
127       int first_line;
128       int first_column;
129       int last_line;
130       int last_column;
131       char *text;
132    }
133   yyltype;
134
135 #define YYLTYPE yyltype
136 #endif
137
138 #include <stdio.h>
139
140 #ifndef __cplusplus
141 #ifndef __STDC__
142 #define const
143 #endif
144 #endif
145
146
147
148 #define YYFINAL         44
149 #define YYFLAG          -32768
150 #define YYNTBASE        15
151
152 #define YYTRANSLATE(x) ((unsigned)(x) <= 266 ? yytranslate[x] : 23)
153
154 static const char yytranslate[] = {     0,
155      2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
156      2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
157      2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
158      2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
159      2,     2,     2,    14,     2,     2,    13,     2,     2,     2,
160      2,     2,     2,     2,     2,     2,     2,    12,     2,     2,
161      2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
162      2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
163      2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
164      2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
165      2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
166      2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
167      2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
168      2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
169      2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
170      2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
171      2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
172      2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
173      2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
174      2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
175      2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
176      2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
177      2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
178      2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
179      2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
180      2,     2,     2,     2,     2,     1,     2,     3,     4,     5,
181      6,     7,     8,     9,    10,    11
182 };
183
184 #if YYDEBUG != 0
185 static const short yyprhs[] = {     0,
186      0,     1,     4,     6,     9,    11,    13,    16,    21,    26,
187     33,    40,    42,    44,    47,    49,    51,    55,    61,    64,
188     69,    72,    76,    82,    85,    88,    91,    94,    95
189 };
190
191 static const short yyrhs[] = {    -1,
192     15,    16,     0,    17,     0,    17,    18,     0,    20,     0,
193     21,     0,    10,    22,     0,    10,    12,    10,    22,     0,
194     10,    12,    10,    19,     0,    10,    12,    10,    12,    10,
195     22,     0,    10,    12,    10,    12,    10,    19,     0,    11,
196      0,     4,     0,    11,    19,     0,    19,     0,     9,     0,
197     10,    13,    10,     0,    10,    13,    10,    13,    10,     0,
198      6,    10,     0,     6,    10,    14,    10,     0,    10,     6,
199      0,    10,     6,    10,     0,     3,    14,    10,     6,    10,
200      0,     9,     8,     0,    10,     8,     0,     9,     7,     0,
201     10,     7,     0,     0,     5,     0
202 };
203
204 #endif
205
206 #if YYDEBUG != 0
207 static const short yyrline[] = { 0,
208    114,   115,   118,   127,   131,   134,   139,   151,   157,   164,
209    170,   180,   184,   188,   196,   202,   223,   227,   239,   243,
210    248,   252,   257,   264,   267,   270,   273,   278,   281
211 };
212
213 static const char * const yytname[] = {   "$","error","$illegal.","tDAY","tDAYZONE",
214 "tMERIDIAN","tMONTH","tMONTH_UNIT","tSEC_UNIT","tSNUMBER","tUNUMBER","tZONE",
215 "':'","'/'","','","spec","item","time","zone","numzone","date","rel","o_merid",
216 ""
217 };
218 #endif
219
220 static const short yyr1[] = {     0,
221     15,    15,    16,    16,    16,    16,    17,    17,    17,    17,
222     17,    18,    18,    18,    18,    19,    20,    20,    20,    20,
223     20,    20,    20,    21,    21,    21,    21,    22,    22
224 };
225
226 static const short yyr2[] = {     0,
227      0,     2,     1,     2,     1,     1,     2,     4,     4,     6,
228      6,     1,     1,     2,     1,     1,     3,     5,     2,     4,
229      2,     3,     5,     2,     2,     2,     2,     0,     1
230 };
231
232 static const short yydefact[] = {     1,
233      0,     0,     0,     0,    28,     2,     3,     5,     6,     0,
234     19,    26,    24,    29,    21,    27,    25,     0,     0,     7,
235     13,    16,    12,     4,    15,     0,     0,    22,    28,    17,
236     14,     0,    20,     0,     9,     8,     0,    23,    28,    18,
237     11,    10,     0,     0
238 };
239
240 static const short yydefgoto[] = {     1,
241      6,     7,    24,    25,     8,     9,    20
242 };
243
244 static const short yypact[] = {-32768,
245      1,   -11,    11,    20,    12,-32768,     4,-32768,-32768,    13,
246     16,-32768,-32768,-32768,    21,-32768,-32768,    22,    23,-32768,
247 -32768,-32768,     5,-32768,-32768,    28,    25,-32768,    17,    24,
248 -32768,    26,-32768,    29,-32768,-32768,    30,-32768,     0,-32768,
249 -32768,-32768,    38,-32768
250 };
251
252 static const short yypgoto[] = {-32768,
253 -32768,-32768,-32768,   -23,-32768,-32768,   -27
254 };
255
256
257 #define YYLAST          40
258
259
260 static const short yytable[] = {    31,
261     43,    36,    10,     2,    14,    35,     3,    21,    22,     4,
262      5,    42,    22,    22,    23,    41,    14,    15,    16,    17,
263     11,    14,    26,    18,    19,    22,    12,    13,    34,    27,
264     28,    29,    30,    32,    33,    38,    37,    44,    39,    40
265 };
266
267 static const short yycheck[] = {    23,
268      0,    29,    14,     3,     5,    29,     6,     4,     9,     9,
269     10,    39,     9,     9,    11,    39,     5,     6,     7,     8,
270     10,     5,    10,    12,    13,     9,     7,     8,    12,    14,
271     10,    10,    10,     6,    10,    10,    13,     0,    10,    10
272 };
273 /* -*-C-*-  Note some compilers choke on comments on `#line' lines.  */
274 #line 3 "/usr/lib/bison.simple"
275
276 /* Skeleton output parser for bison,
277    Copyright (C) 1984, 1989, 1990 Bob Corbett and Richard Stallman
278
279    This program is free software; you can redistribute it and/or modify
280    it under the terms of the GNU General Public License as published by
281    the Free Software Foundation; either version 1, or (at your option)
282    any later version.
283
284    This program is distributed in the hope that it will be useful,
285    but WITHOUT ANY WARRANTY; without even the implied warranty of
286    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
287    GNU General Public License for more details.
288
289    You should have received a copy of the GNU General Public License
290    along with this program; if not, write to the Free Software
291    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
292
293
294 #ifndef alloca
295 #ifdef __GNUC__
296 #define alloca __builtin_alloca
297 #else /* not GNU C.  */
298 #if (!defined (__STDC__) && defined (sparc)) || defined (__sparc__) || defined (__sparc) || defined (__sgi)
299 #include <alloca.h>
300 #else /* not sparc */
301 #if defined (MSDOS) && !defined (__TURBOC__)
302 #include <malloc.h>
303 #else /* not MSDOS, or __TURBOC__ */
304 #if defined(_AIX)
305 #include <malloc.h>
306  #pragma alloca
307 #else /* not MSDOS, __TURBOC__, or _AIX */
308 #ifdef __hpux
309 #ifdef __cplusplus
310 extern "C" {
311 void *alloca (unsigned int);
312 };
313 #else /* not __cplusplus */
314 void *alloca ();
315 #endif /* not __cplusplus */
316 #endif /* __hpux */
317 #endif /* not _AIX */
318 #endif /* not MSDOS, or __TURBOC__ */
319 #endif /* not sparc.  */
320 #endif /* not GNU C.  */
321 #endif /* alloca not defined.  */
322
323 /* This is the parser code that is written into each bison parser
324   when the %semantic_parser declaration is not specified in the grammar.
325   It was written by Richard Stallman by simplifying the hairy parser
326   used when %semantic_parser is specified.  */
327
328 /* Note: there must be only one dollar sign in this file.
329    It is replaced by the list of actions, each action
330    as one case of the switch.  */
331
332 #define yyerrok         (yyerrstatus = 0)
333 #define yyclearin       (yychar = YYEMPTY)
334 #define YYEMPTY         -2
335 #define YYEOF           0
336 #define YYACCEPT        return(0)
337 #define YYABORT         return(1)
338 #define YYERROR         goto yyerrlab1
339 /* Like YYERROR except do call yyerror.
340    This remains here temporarily to ease the
341    transition to the new meaning of YYERROR, for GCC.
342    Once GCC version 2 has supplanted version 1, this can go.  */
343 #define YYFAIL          goto yyerrlab
344 #define YYRECOVERING()  (!!yyerrstatus)
345 #define YYBACKUP(token, value) \
346 do                                                              \
347   if (yychar == YYEMPTY && yylen == 1)                          \
348     { yychar = (token), yylval = (value);                       \
349       yychar1 = YYTRANSLATE (yychar);                           \
350       YYPOPSTACK;                                               \
351       goto yybackup;                                            \
352     }                                                           \
353   else                                                          \
354     { yyerror ("syntax error: cannot back up"); YYERROR; }      \
355 while (0)
356
357 #define YYTERROR        1
358 #define YYERRCODE       256
359
360 #ifndef YYPURE
361 #define YYLEX           yylex()
362 #endif
363
364 #ifdef YYPURE
365 #ifdef YYLSP_NEEDED
366 #define YYLEX           yylex(&yylval, &yylloc)
367 #else
368 #define YYLEX           yylex(&yylval)
369 #endif
370 #endif
371
372 /* If nonreentrant, generate the variables here */
373
374 #ifndef YYPURE
375
376 int     yychar;                 /*  the lookahead symbol                */
377 YYSTYPE yylval;                 /*  the semantic value of the           */
378                                 /*  lookahead symbol                    */
379
380 #ifdef YYLSP_NEEDED
381 YYLTYPE yylloc;                 /*  location data for the lookahead     */
382                                 /*  symbol                              */
383 #endif
384
385 int yynerrs;                    /*  number of parse errors so far       */
386 #endif  /* not YYPURE */
387
388 #if YYDEBUG != 0
389 int yydebug;                    /*  nonzero means print parse trace     */
390 /* Since this is uninitialized, it does not stop multiple parsers
391    from coexisting.  */
392 #endif
393
394 /*  YYINITDEPTH indicates the initial size of the parser's stacks       */
395
396 #ifndef YYINITDEPTH
397 #define YYINITDEPTH 200
398 #endif
399
400 /*  YYMAXDEPTH is the maximum size the stacks can grow to
401     (effective only if the built-in stack extension method is used).  */
402
403 #if YYMAXDEPTH == 0
404 #undef YYMAXDEPTH
405 #endif
406
407 #ifndef YYMAXDEPTH
408 #define YYMAXDEPTH 10000
409 #endif
410
411 /* Prevent warning if -Wstrict-prototypes.  */
412 #ifdef __GNUC__
413 int yyparse (void);
414 #endif
415 \f
416 #if __GNUC__ > 1                /* GNU C and GNU C++ define this.  */
417 #define __yy_bcopy(FROM,TO,COUNT)       __builtin_memcpy(TO,FROM,COUNT)
418 #else                           /* not GNU C or C++ */
419 #ifndef __cplusplus
420
421 /* This is the most reliable way to avoid incompatibilities
422    in available built-in functions on various systems.  */
423 static void
424 __yy_bcopy (from, to, count)
425      char *from;
426      char *to;
427      int count;
428 {
429   register char *f = from;
430   register char *t = to;
431   register int i = count;
432
433   while (i-- > 0)
434     *t++ = *f++;
435 }
436
437 #else /* __cplusplus */
438
439 /* This is the most reliable way to avoid incompatibilities
440    in available built-in functions on various systems.  */
441 static void
442 __yy_bcopy (char *from, char *to, int count)
443 {
444   register char *f = from;
445   register char *t = to;
446   register int i = count;
447
448   while (i-- > 0)
449     *t++ = *f++;
450 }
451
452 #endif
453 #endif
454 \f
455 #line 184 "/usr/lib/bison.simple"
456 int
457 yyparse()
458 {
459   register int yystate;
460   register int yyn;
461   register short *yyssp;
462   register YYSTYPE *yyvsp;
463   int yyerrstatus;      /*  number of tokens to shift before error messages enabled */
464   int yychar1 = 0;              /*  lookahead token as an internal (translated) token number */
465
466   short yyssa[YYINITDEPTH];     /*  the state stack                     */
467   YYSTYPE yyvsa[YYINITDEPTH];   /*  the semantic value stack            */
468
469   short *yyss = yyssa;          /*  refer to the stacks thru separate pointers */
470   YYSTYPE *yyvs = yyvsa;        /*  to allow yyoverflow to reallocate them elsewhere */
471
472 #ifdef YYLSP_NEEDED
473   YYLTYPE yylsa[YYINITDEPTH];   /*  the location stack                  */
474   YYLTYPE *yyls = yylsa;
475   YYLTYPE *yylsp;
476
477 #define YYPOPSTACK   (yyvsp--, yyssp--, yylsp--)
478 #else
479 #define YYPOPSTACK   (yyvsp--, yyssp--)
480 #endif
481
482   int yystacksize = YYINITDEPTH;
483
484 #ifdef YYPURE
485   int yychar;
486   YYSTYPE yylval;
487   int yynerrs;
488 #ifdef YYLSP_NEEDED
489   YYLTYPE yylloc;
490 #endif
491 #endif
492
493   YYSTYPE yyval;                /*  the variable used to return         */
494                                 /*  semantic values from the action     */
495                                 /*  routines                            */
496
497   int yylen;
498
499 #if YYDEBUG != 0
500   if (yydebug)
501     fprintf(stderr, "Starting parse\n");
502 #endif
503
504   yystate = 0;
505   yyerrstatus = 0;
506   yynerrs = 0;
507   yychar = YYEMPTY;             /* Cause a token to be read.  */
508
509   /* Initialize stack pointers.
510      Waste one element of value and location stack
511      so that they stay on the same level as the state stack.
512      The wasted elements are never initialized.  */
513
514   yyssp = yyss - 1;
515   yyvsp = yyvs;
516 #ifdef YYLSP_NEEDED
517   yylsp = yyls;
518 #endif
519
520 /* Push a new state, which is found in  yystate  .  */
521 /* In all cases, when you get here, the value and location stacks
522    have just been pushed. so pushing a state here evens the stacks.  */
523 yynewstate:
524
525   *++yyssp = yystate;
526
527   if (yyssp >= yyss + yystacksize - 1)
528     {
529       /* Give user a chance to reallocate the stack */
530       /* Use copies of these so that the &'s don't force the real ones into memory. */
531       YYSTYPE *yyvs1 = yyvs;
532       short *yyss1 = yyss;
533 #ifdef YYLSP_NEEDED
534       YYLTYPE *yyls1 = yyls;
535 #endif
536
537       /* Get the current used size of the three stacks, in elements.  */
538       int size = yyssp - yyss + 1;
539
540 #ifdef yyoverflow
541       /* Each stack pointer address is followed by the size of
542          the data in use in that stack, in bytes.  */
543 #ifdef YYLSP_NEEDED
544       /* This used to be a conditional around just the two extra args,
545          but that might be undefined if yyoverflow is a macro.  */
546       yyoverflow("parser stack overflow",
547                  &yyss1, size * sizeof (*yyssp),
548                  &yyvs1, size * sizeof (*yyvsp),
549                  &yyls1, size * sizeof (*yylsp),
550                  &yystacksize);
551 #else
552       yyoverflow("parser stack overflow",
553                  &yyss1, size * sizeof (*yyssp),
554                  &yyvs1, size * sizeof (*yyvsp),
555                  &yystacksize);
556 #endif
557
558       yyss = yyss1; yyvs = yyvs1;
559 #ifdef YYLSP_NEEDED
560       yyls = yyls1;
561 #endif
562 #else /* no yyoverflow */
563       /* Extend the stack our own way.  */
564       if (yystacksize >= YYMAXDEPTH)
565         {
566           yyerror("parser stack overflow");
567           return 2;
568         }
569       yystacksize *= 2;
570       if (yystacksize > YYMAXDEPTH)
571         yystacksize = YYMAXDEPTH;
572       yyss = (short *) alloca (yystacksize * sizeof (*yyssp));
573       __yy_bcopy ((char *)yyss1, (char *)yyss, size * sizeof (*yyssp));
574       yyvs = (YYSTYPE *) alloca (yystacksize * sizeof (*yyvsp));
575       __yy_bcopy ((char *)yyvs1, (char *)yyvs, size * sizeof (*yyvsp));
576 #ifdef YYLSP_NEEDED
577       yyls = (YYLTYPE *) alloca (yystacksize * sizeof (*yylsp));
578       __yy_bcopy ((char *)yyls1, (char *)yyls, size * sizeof (*yylsp));
579 #endif
580 #endif /* no yyoverflow */
581
582       yyssp = yyss + size - 1;
583       yyvsp = yyvs + size - 1;
584 #ifdef YYLSP_NEEDED
585       yylsp = yyls + size - 1;
586 #endif
587
588 #if YYDEBUG != 0
589       if (yydebug)
590         fprintf(stderr, "Stack size increased to %d\n", yystacksize);
591 #endif
592
593       if (yyssp >= yyss + yystacksize - 1)
594         YYABORT;
595     }
596
597 #if YYDEBUG != 0
598   if (yydebug)
599     fprintf(stderr, "Entering state %d\n", yystate);
600 #endif
601
602   goto yybackup;
603  yybackup:
604
605 /* Do appropriate processing given the current state.  */
606 /* Read a lookahead token if we need one and don't already have one.  */
607 /* yyresume: */
608
609   /* First try to decide what to do without reference to lookahead token.  */
610
611   yyn = yypact[yystate];
612   if (yyn == YYFLAG)
613     goto yydefault;
614
615   /* Not known => get a lookahead token if don't already have one.  */
616
617   /* yychar is either YYEMPTY or YYEOF
618      or a valid token in external form.  */
619
620   if (yychar == YYEMPTY)
621     {
622 #if YYDEBUG != 0
623       if (yydebug)
624         fprintf(stderr, "Reading a token: ");
625 #endif
626       yychar = YYLEX;
627     }
628
629   /* Convert token to internal form (in yychar1) for indexing tables with */
630
631   if (yychar <= 0)              /* This means end of input. */
632     {
633       yychar1 = 0;
634       yychar = YYEOF;           /* Don't call YYLEX any more */
635
636 #if YYDEBUG != 0
637       if (yydebug)
638         fprintf(stderr, "Now at end of input.\n");
639 #endif
640     }
641   else
642     {
643       yychar1 = YYTRANSLATE(yychar);
644
645 #if YYDEBUG != 0
646       if (yydebug)
647         {
648           fprintf (stderr, "Next token is %d (%s", yychar, yytname[yychar1]);
649           /* Give the individual parser a way to print the precise meaning
650              of a token, for further debugging info.  */
651 #ifdef YYPRINT
652           YYPRINT (stderr, yychar, yylval);
653 #endif
654           fprintf (stderr, ")\n");
655         }
656 #endif
657     }
658
659   yyn += yychar1;
660   if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != yychar1)
661     goto yydefault;
662
663   yyn = yytable[yyn];
664
665   /* yyn is what to do for this token type in this state.
666      Negative => reduce, -yyn is rule number.
667      Positive => shift, yyn is new state.
668        New state is final state => don't bother to shift,
669        just return success.
670      0, or most negative number => error.  */
671
672   if (yyn < 0)
673     {
674       if (yyn == YYFLAG)
675         goto yyerrlab;
676       yyn = -yyn;
677       goto yyreduce;
678     }
679   else if (yyn == 0)
680     goto yyerrlab;
681
682   if (yyn == YYFINAL)
683     YYACCEPT;
684
685   /* Shift the lookahead token.  */
686
687 #if YYDEBUG != 0
688   if (yydebug)
689     fprintf(stderr, "Shifting token %d (%s), ", yychar, yytname[yychar1]);
690 #endif
691
692   /* Discard the token being shifted unless it is eof.  */
693   if (yychar != YYEOF)
694     yychar = YYEMPTY;
695
696   *++yyvsp = yylval;
697 #ifdef YYLSP_NEEDED
698   *++yylsp = yylloc;
699 #endif
700
701   /* count tokens shifted since error; after three, turn off error status.  */
702   if (yyerrstatus) yyerrstatus--;
703
704   yystate = yyn;
705   goto yynewstate;
706
707 /* Do the default action for the current state.  */
708 yydefault:
709
710   yyn = yydefact[yystate];
711   if (yyn == 0)
712     goto yyerrlab;
713
714 /* Do a reduction.  yyn is the number of a rule to reduce with.  */
715 yyreduce:
716   yylen = yyr2[yyn];
717   if (yylen > 0)
718     yyval = yyvsp[1-yylen]; /* implement default value of the action */
719
720 #if YYDEBUG != 0
721   if (yydebug)
722     {
723       int i;
724
725       fprintf (stderr, "Reducing via rule %d (line %d), ",
726                yyn, yyrline[yyn]);
727
728       /* Print the symbols being reduced, and their result.  */
729       for (i = yyprhs[yyn]; yyrhs[i] > 0; i++)
730         fprintf (stderr, "%s ", yytname[yyrhs[i]]);
731       fprintf (stderr, " -> %s\n", yytname[yyr1[yyn]]);
732     }
733 #endif
734
735
736   switch (yyn) {
737
738 case 3:
739 #line 118 "parsedate.y"
740 {
741             yyHaveTime++;
742 #ifdef lint
743             /* I am compulsive about lint natterings... */
744             if (yyHaveTime == -1) {
745                 YYERROR;
746             }
747 #endif /* lint */
748         ;
749     break;}
750 case 4:
751 #line 127 "parsedate.y"
752 {
753             yyHaveTime++;
754             yyTimezone = yyvsp[0].Number;
755         ;
756     break;}
757 case 5:
758 #line 131 "parsedate.y"
759 {
760             yyHaveDate++;
761         ;
762     break;}
763 case 6:
764 #line 134 "parsedate.y"
765 {
766             yyHaveRel = 1;
767         ;
768     break;}
769 case 7:
770 #line 139 "parsedate.y"
771 {
772             if (yyvsp[-1].Number < 100) {
773                 yyHour = yyvsp[-1].Number;
774                 yyMinutes = 0;
775             }
776             else {
777                 yyHour = yyvsp[-1].Number / 100;
778                 yyMinutes = yyvsp[-1].Number % 100;
779             }
780             yySeconds = 0;
781             yyMeridian = yyvsp[0].Meridian;
782         ;
783     break;}
784 case 8:
785 #line 151 "parsedate.y"
786 {
787             yyHour = yyvsp[-3].Number;
788             yyMinutes = yyvsp[-1].Number;
789             yySeconds = 0;
790             yyMeridian = yyvsp[0].Meridian;
791         ;
792     break;}
793 case 9:
794 #line 157 "parsedate.y"
795 {
796             yyHour = yyvsp[-3].Number;
797             yyMinutes = yyvsp[-1].Number;
798             yyTimezone = yyvsp[0].Number;
799             yyMeridian = MER24;
800             yyDSTmode = DSToff;
801         ;
802     break;}
803 case 10:
804 #line 164 "parsedate.y"
805 {
806             yyHour = yyvsp[-5].Number;
807             yyMinutes = yyvsp[-3].Number;
808             yySeconds = yyvsp[-1].Number;
809             yyMeridian = yyvsp[0].Meridian;
810         ;
811     break;}
812 case 11:
813 #line 170 "parsedate.y"
814 {
815             yyHour = yyvsp[-5].Number;
816             yyMinutes = yyvsp[-3].Number;
817             yySeconds = yyvsp[-1].Number;
818             yyTimezone = yyvsp[0].Number;
819             yyMeridian = MER24;
820             yyDSTmode = DSToff;
821         ;
822     break;}
823 case 12:
824 #line 180 "parsedate.y"
825 {
826             yyval.Number = yyvsp[0].Number;
827             yyDSTmode = DSToff;
828         ;
829     break;}
830 case 13:
831 #line 184 "parsedate.y"
832 {
833             yyval.Number = yyvsp[0].Number;
834             yyDSTmode = DSTon;
835         ;
836     break;}
837 case 14:
838 #line 188 "parsedate.y"
839 {
840             /* Only allow "GMT+300" and "GMT-0800" */
841             if (yyvsp[-1].Number != 0) {
842                 YYABORT;
843             }
844             yyval.Number = yyvsp[0].Number;
845             yyDSTmode = DSToff;
846         ;
847     break;}
848 case 15:
849 #line 196 "parsedate.y"
850 {
851             yyval.Number = yyvsp[0].Number;
852             yyDSTmode = DSToff;
853         ;
854     break;}
855 case 16:
856 #line 202 "parsedate.y"
857 {
858             int         i;
859
860             /* Unix and GMT and numeric timezones -- a little confusing. */
861             if (yyvsp[0].Number < 0) {
862                 /* Don't work with negative modulus. */
863                 yyvsp[0].Number = -yyvsp[0].Number;
864                 if (yyvsp[0].Number > 9999 || (i = yyvsp[0].Number % 100) >= 60) {
865                     YYABORT;
866                 }
867                 yyval.Number = (yyvsp[0].Number / 100) * 60 + i;
868             }
869             else {
870                 if (yyvsp[0].Number > 9999 || (i = yyvsp[0].Number % 100) >= 60) {
871                     YYABORT;
872                 }
873                 yyval.Number = -((yyvsp[0].Number / 100) * 60 + i);
874             }
875         ;
876     break;}
877 case 17:
878 #line 223 "parsedate.y"
879 {
880             yyMonth = yyvsp[-2].Number;
881             yyDay = yyvsp[0].Number;
882         ;
883     break;}
884 case 18:
885 #line 227 "parsedate.y"
886 {
887             if (yyvsp[-4].Number > 100) {
888                 yyYear = yyvsp[-4].Number;
889                 yyMonth = yyvsp[-2].Number;
890                 yyDay = yyvsp[0].Number;
891             }
892             else {
893                 yyMonth = yyvsp[-4].Number;
894                 yyDay = yyvsp[-2].Number;
895                 yyYear = yyvsp[0].Number;
896             }
897         ;
898     break;}
899 case 19:
900 #line 239 "parsedate.y"
901 {
902             yyMonth = yyvsp[-1].Number;
903             yyDay = yyvsp[0].Number;
904         ;
905     break;}
906 case 20:
907 #line 243 "parsedate.y"
908 {
909             yyMonth = yyvsp[-3].Number;
910             yyDay = yyvsp[-2].Number;
911             yyYear = yyvsp[0].Number;
912         ;
913     break;}
914 case 21:
915 #line 248 "parsedate.y"
916 {
917             yyDay = yyvsp[-1].Number;
918             yyMonth = yyvsp[0].Number;
919         ;
920     break;}
921 case 22:
922 #line 252 "parsedate.y"
923 {
924             yyDay = yyvsp[-2].Number;
925             yyMonth = yyvsp[-1].Number;
926             yyYear = yyvsp[0].Number;
927         ;
928     break;}
929 case 23:
930 #line 257 "parsedate.y"
931 {
932             yyDay = yyvsp[-2].Number;
933             yyMonth = yyvsp[-1].Number;
934             yyYear = yyvsp[0].Number;
935         ;
936     break;}
937 case 24:
938 #line 264 "parsedate.y"
939 {
940             yyRelSeconds += yyvsp[-1].Number * yyvsp[0].Number;
941         ;
942     break;}
943 case 25:
944 #line 267 "parsedate.y"
945 {
946             yyRelSeconds += yyvsp[-1].Number * yyvsp[0].Number;
947         ;
948     break;}
949 case 26:
950 #line 270 "parsedate.y"
951 {
952             yyRelMonth += yyvsp[-1].Number * yyvsp[0].Number;
953         ;
954     break;}
955 case 27:
956 #line 273 "parsedate.y"
957 {
958             yyRelMonth += yyvsp[-1].Number * yyvsp[0].Number;
959         ;
960     break;}
961 case 28:
962 #line 278 "parsedate.y"
963 {
964             yyval.Meridian = MER24;
965         ;
966     break;}
967 case 29:
968 #line 281 "parsedate.y"
969 {
970             yyval.Meridian = yyvsp[0].Meridian;
971         ;
972     break;}
973 }
974    /* the action file gets copied in in place of this dollarsign */
975 #line 465 "/usr/lib/bison.simple"
976 \f
977   yyvsp -= yylen;
978   yyssp -= yylen;
979 #ifdef YYLSP_NEEDED
980   yylsp -= yylen;
981 #endif
982
983 #if YYDEBUG != 0
984   if (yydebug)
985     {
986       short *ssp1 = yyss - 1;
987       fprintf (stderr, "state stack now");
988       while (ssp1 != yyssp)
989         fprintf (stderr, " %d", *++ssp1);
990       fprintf (stderr, "\n");
991     }
992 #endif
993
994   *++yyvsp = yyval;
995
996 #ifdef YYLSP_NEEDED
997   yylsp++;
998   if (yylen == 0)
999     {
1000       yylsp->first_line = yylloc.first_line;
1001       yylsp->first_column = yylloc.first_column;
1002       yylsp->last_line = (yylsp-1)->last_line;
1003       yylsp->last_column = (yylsp-1)->last_column;
1004       yylsp->text = 0;
1005     }
1006   else
1007     {
1008       yylsp->last_line = (yylsp+yylen-1)->last_line;
1009       yylsp->last_column = (yylsp+yylen-1)->last_column;
1010     }
1011 #endif
1012
1013   /* Now "shift" the result of the reduction.
1014      Determine what state that goes to,
1015      based on the state we popped back to
1016      and the rule number reduced by.  */
1017
1018   yyn = yyr1[yyn];
1019
1020   yystate = yypgoto[yyn - YYNTBASE] + *yyssp;
1021   if (yystate >= 0 && yystate <= YYLAST && yycheck[yystate] == *yyssp)
1022     yystate = yytable[yystate];
1023   else
1024     yystate = yydefgoto[yyn - YYNTBASE];
1025
1026   goto yynewstate;
1027
1028 yyerrlab:   /* here on detecting error */
1029
1030   if (! yyerrstatus)
1031     /* If not already recovering from an error, report this error.  */
1032     {
1033       ++yynerrs;
1034
1035 #ifdef YYERROR_VERBOSE
1036       yyn = yypact[yystate];
1037
1038       if (yyn > YYFLAG && yyn < YYLAST)
1039         {
1040           int size = 0;
1041           char *msg;
1042           int x, count;
1043
1044           count = 0;
1045           /* Start X at -yyn if nec to avoid negative indexes in yycheck.  */
1046           for (x = (yyn < 0 ? -yyn : 0);
1047                x < (sizeof(yytname) / sizeof(char *)); x++)
1048             if (yycheck[x + yyn] == x)
1049               size += strlen(yytname[x]) + 15, count++;
1050           msg = (char *) malloc(size + 15);
1051           if (msg != 0)
1052             {
1053               strcpy(msg, "parse error");
1054
1055               if (count < 5)
1056                 {
1057                   count = 0;
1058                   for (x = (yyn < 0 ? -yyn : 0);
1059                        x < (sizeof(yytname) / sizeof(char *)); x++)
1060                     if (yycheck[x + yyn] == x)
1061                       {
1062                         strcat(msg, count == 0 ? ", expecting `" : " or `");
1063                         strcat(msg, yytname[x]);
1064                         strcat(msg, "'");
1065                         count++;
1066                       }
1067                 }
1068               yyerror(msg);
1069               free(msg);
1070             }
1071           else
1072             yyerror ("parse error; also virtual memory exceeded");
1073         }
1074       else
1075 #endif /* YYERROR_VERBOSE */
1076         yyerror("parse error");
1077     }
1078
1079   goto yyerrlab1;
1080 yyerrlab1:   /* here on error raised explicitly by an action */
1081
1082   if (yyerrstatus == 3)
1083     {
1084       /* if just tried and failed to reuse lookahead token after an error, discard it.  */
1085
1086       /* return failure if at end of input */
1087       if (yychar == YYEOF)
1088         YYABORT;
1089
1090 #if YYDEBUG != 0
1091       if (yydebug)
1092         fprintf(stderr, "Discarding token %d (%s).\n", yychar, yytname[yychar1]);
1093 #endif
1094
1095       yychar = YYEMPTY;
1096     }
1097
1098   /* Else will try to reuse lookahead token
1099      after shifting the error token.  */
1100
1101   yyerrstatus = 3;              /* Each real token shifted decrements this */
1102
1103   goto yyerrhandle;
1104
1105 yyerrdefault:  /* current state does not do anything special for the error token. */
1106
1107 #if 0
1108   /* This is wrong; only states that explicitly want error tokens
1109      should shift them.  */
1110   yyn = yydefact[yystate];  /* If its default is to accept any token, ok.  Otherwise pop it.*/
1111   if (yyn) goto yydefault;
1112 #endif
1113
1114 yyerrpop:   /* pop the current state because it cannot handle the error token */
1115
1116   if (yyssp == yyss) YYABORT;
1117   yyvsp--;
1118   yystate = *--yyssp;
1119 #ifdef YYLSP_NEEDED
1120   yylsp--;
1121 #endif
1122
1123 #if YYDEBUG != 0
1124   if (yydebug)
1125     {
1126       short *ssp1 = yyss - 1;
1127       fprintf (stderr, "Error: state stack now");
1128       while (ssp1 != yyssp)
1129         fprintf (stderr, " %d", *++ssp1);
1130       fprintf (stderr, "\n");
1131     }
1132 #endif
1133
1134 yyerrhandle:
1135
1136   yyn = yypact[yystate];
1137   if (yyn == YYFLAG)
1138     goto yyerrdefault;
1139
1140   yyn += YYTERROR;
1141   if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != YYTERROR)
1142     goto yyerrdefault;
1143
1144   yyn = yytable[yyn];
1145   if (yyn < 0)
1146     {
1147       if (yyn == YYFLAG)
1148         goto yyerrpop;
1149       yyn = -yyn;
1150       goto yyreduce;
1151     }
1152   else if (yyn == 0)
1153     goto yyerrpop;
1154
1155   if (yyn == YYFINAL)
1156     YYACCEPT;
1157
1158 #if YYDEBUG != 0
1159   if (yydebug)
1160     fprintf(stderr, "Shifting error token, ");
1161 #endif
1162
1163   *++yyvsp = yylval;
1164 #ifdef YYLSP_NEEDED
1165   *++yylsp = yylloc;
1166 #endif
1167
1168   yystate = yyn;
1169   goto yynewstate;
1170 }
1171 #line 286 "parsedate.y"
1172
1173
1174 /* Month and day table. */
1175 static TABLE    MonthDayTable[] = {
1176     { "january",        tMONTH,  1 },
1177     { "february",       tMONTH,  2 },
1178     { "march",          tMONTH,  3 },
1179     { "april",          tMONTH,  4 },
1180     { "may",            tMONTH,  5 },
1181     { "june",           tMONTH,  6 },
1182     { "july",           tMONTH,  7 },
1183     { "august",         tMONTH,  8 },
1184     { "september",      tMONTH,  9 },
1185     { "october",        tMONTH, 10 },
1186     { "november",       tMONTH, 11 },
1187     { "december",       tMONTH, 12 },
1188         /* The value of the day isn't used... */
1189     { "sunday",         tDAY, 0 },
1190     { "monday",         tDAY, 0 },
1191     { "tuesday",        tDAY, 0 },
1192     { "wednesday",      tDAY, 0 },
1193     { "thursday",       tDAY, 0 },
1194     { "friday",         tDAY, 0 },
1195     { "saturday",       tDAY, 0 },
1196 };
1197
1198 /* Time units table. */
1199 static TABLE    UnitsTable[] = {
1200     { "year",           tMONTH_UNIT,    12 },
1201     { "month",          tMONTH_UNIT,    1 },
1202     { "week",           tSEC_UNIT,      7L * 24 * 60 * 60 },
1203     { "day",            tSEC_UNIT,      1L * 24 * 60 * 60 },
1204     { "hour",           tSEC_UNIT,      60 * 60 },
1205     { "minute",         tSEC_UNIT,      60 },
1206     { "min",            tSEC_UNIT,      60 },
1207     { "second",         tSEC_UNIT,      1 },
1208     { "sec",            tSEC_UNIT,      1 },
1209 };
1210
1211 /* Timezone table. */
1212 static TABLE    TimezoneTable[] = {
1213     { "gmt",    tZONE,     HOUR( 0) },  /* Greenwich Mean */
1214     { "ut",     tZONE,     HOUR( 0) },  /* Universal */
1215     { "utc",    tZONE,     HOUR( 0) },  /* Universal Coordinated */
1216     { "cut",    tZONE,     HOUR( 0) },  /* Coordinated Universal */
1217     { "z",      tZONE,     HOUR( 0) },  /* Greenwich Mean */
1218     { "wet",    tZONE,     HOUR( 0) },  /* Western European */
1219     { "bst",    tDAYZONE,  HOUR( 0) },  /* British Summer */
1220     { "nst",    tZONE,     HOUR(3)+30 }, /* Newfoundland Standard */
1221     { "ndt",    tDAYZONE,  HOUR(3)+30 }, /* Newfoundland Daylight */
1222     { "ast",    tZONE,     HOUR( 4) },  /* Atlantic Standard */
1223     { "adt",    tDAYZONE,  HOUR( 4) },  /* Atlantic Daylight */
1224     { "est",    tZONE,     HOUR( 5) },  /* Eastern Standard */
1225     { "edt",    tDAYZONE,  HOUR( 5) },  /* Eastern Daylight */
1226     { "cst",    tZONE,     HOUR( 6) },  /* Central Standard */
1227     { "cdt",    tDAYZONE,  HOUR( 6) },  /* Central Daylight */
1228     { "mst",    tZONE,     HOUR( 7) },  /* Mountain Standard */
1229     { "mdt",    tDAYZONE,  HOUR( 7) },  /* Mountain Daylight */
1230     { "pst",    tZONE,     HOUR( 8) },  /* Pacific Standard */
1231     { "pdt",    tDAYZONE,  HOUR( 8) },  /* Pacific Daylight */
1232     { "yst",    tZONE,     HOUR( 9) },  /* Yukon Standard */
1233     { "ydt",    tDAYZONE,  HOUR( 9) },  /* Yukon Daylight */
1234     { "akst",   tZONE,     HOUR( 9) },  /* Alaska Standard */
1235     { "akdt",   tDAYZONE,  HOUR( 9) },  /* Alaska Daylight */
1236     { "hst",    tZONE,     HOUR(10) },  /* Hawaii Standard */
1237     { "hast",   tZONE,     HOUR(10) },  /* Hawaii-Aleutian Standard */
1238     { "hadt",   tDAYZONE,  HOUR(10) },  /* Hawaii-Aleutian Daylight */
1239     { "ces",    tDAYZONE,  -HOUR(1) },  /* Central European Summer */
1240     { "cest",   tDAYZONE,  -HOUR(1) },  /* Central European Summer */
1241     { "mez",    tZONE,     -HOUR(1) },  /* Middle European */
1242     { "mezt",   tDAYZONE,  -HOUR(1) },  /* Middle European Summer */
1243     { "cet",    tZONE,     -HOUR(1) },  /* Central European */
1244     { "met",    tZONE,     -HOUR(1) },  /* Middle European */
1245     { "eet",    tZONE,     -HOUR(2) },  /* Eastern Europe */
1246     { "msk",    tZONE,     -HOUR(3) },  /* Moscow Winter */
1247     { "msd",    tDAYZONE,  -HOUR(3) },  /* Moscow Summer */
1248     { "wast",   tZONE,     -HOUR(8) },  /* West Australian Standard */
1249     { "wadt",   tDAYZONE,  -HOUR(8) },  /* West Australian Daylight */
1250     { "hkt",    tZONE,     -HOUR(8) },  /* Hong Kong */
1251     { "cct",    tZONE,     -HOUR(8) },  /* China Coast */
1252     { "jst",    tZONE,     -HOUR(9) },  /* Japan Standard */
1253     { "kst",    tZONE,     -HOUR(9) },  /* Korean Standard */
1254     { "kdt",    tZONE,     -HOUR(9) },  /* Korean Daylight */
1255     { "cast",   tZONE,     -(HOUR(9)+30) }, /* Central Australian Standard */
1256     { "cadt",   tDAYZONE,  -(HOUR(9)+30) }, /* Central Australian Daylight */
1257     { "east",   tZONE,     -HOUR(10) }, /* Eastern Australian Standard */
1258     { "eadt",   tDAYZONE,  -HOUR(10) }, /* Eastern Australian Daylight */
1259     { "nzst",   tZONE,     -HOUR(12) }, /* New Zealand Standard */
1260     { "nzdt",   tDAYZONE,  -HOUR(12) }, /* New Zealand Daylight */
1261
1262     /* For completeness we include the following entries. */
1263 #if 0
1264
1265     /* Duplicate names.  Either they conflict with a zone listed above
1266      * (which is either more likely to be seen or just been in circulation
1267      * longer), or they conflict with another zone in this section and
1268      * we could not reasonably choose one over the other. */
1269     { "fst",    tZONE,     HOUR( 2) },  /* Fernando De Noronha Standard */
1270     { "fdt",    tDAYZONE,  HOUR( 2) },  /* Fernando De Noronha Daylight */
1271     { "bst",    tZONE,     HOUR( 3) },  /* Brazil Standard */
1272     { "est",    tZONE,     HOUR( 3) },  /* Eastern Standard (Brazil) */
1273     { "edt",    tDAYZONE,  HOUR( 3) },  /* Eastern Daylight (Brazil) */
1274     { "wst",    tZONE,     HOUR( 4) },  /* Western Standard (Brazil) */
1275     { "wdt",    tDAYZONE,  HOUR( 4) },  /* Western Daylight (Brazil) */
1276     { "cst",    tZONE,     HOUR( 5) },  /* Chile Standard */
1277     { "cdt",    tDAYZONE,  HOUR( 5) },  /* Chile Daylight */
1278     { "ast",    tZONE,     HOUR( 5) },  /* Acre Standard */
1279     { "adt",    tDAYZONE,  HOUR( 5) },  /* Acre Daylight */
1280     { "cst",    tZONE,     HOUR( 5) },  /* Cuba Standard */
1281     { "cdt",    tDAYZONE,  HOUR( 5) },  /* Cuba Daylight */
1282     { "est",    tZONE,     HOUR( 6) },  /* Easter Island Standard */
1283     { "edt",    tDAYZONE,  HOUR( 6) },  /* Easter Island Daylight */
1284     { "sst",    tZONE,     HOUR(11) },  /* Samoa Standard */
1285     { "ist",    tZONE,     -HOUR(2) },  /* Israel Standard */
1286     { "idt",    tDAYZONE,  -HOUR(2) },  /* Israel Daylight */
1287     { "idt",    tDAYZONE,  -(HOUR(3)+30) }, /* Iran Daylight */
1288     { "ist",    tZONE,     -(HOUR(3)+30) }, /* Iran Standard */
1289     { "cst",     tZONE,     -HOUR(8) }, /* China Standard */
1290     { "cdt",     tDAYZONE,  -HOUR(8) }, /* China Daylight */
1291     { "sst",     tZONE,     -HOUR(8) }, /* Singapore Standard */
1292
1293     /* Dubious (e.g., not in Olson's TIMEZONE package) or obsolete. */
1294     { "gst",    tZONE,     HOUR( 3) },  /* Greenland Standard */
1295     { "wat",    tZONE,     -HOUR(1) },  /* West Africa */
1296     { "at",     tZONE,     HOUR( 2) },  /* Azores */
1297     { "gst",    tZONE,     -HOUR(10) }, /* Guam Standard */
1298     { "nft",    tZONE,     HOUR(3)+30 }, /* Newfoundland */
1299     { "idlw",   tZONE,     HOUR(12) },  /* International Date Line West */
1300     { "mewt",   tZONE,     -HOUR(1) },  /* Middle European Winter */
1301     { "mest",   tDAYZONE,  -HOUR(1) },  /* Middle European Summer */
1302     { "swt",    tZONE,     -HOUR(1) },  /* Swedish Winter */
1303     { "sst",    tDAYZONE,  -HOUR(1) },  /* Swedish Summer */
1304     { "fwt",    tZONE,     -HOUR(1) },  /* French Winter */
1305     { "fst",    tDAYZONE,  -HOUR(1) },  /* French Summer */
1306     { "bt",     tZONE,     -HOUR(3) },  /* Baghdad */
1307     { "it",     tZONE,     -(HOUR(3)+30) }, /* Iran */
1308     { "zp4",    tZONE,     -HOUR(4) },  /* USSR Zone 3 */
1309     { "zp5",    tZONE,     -HOUR(5) },  /* USSR Zone 4 */
1310     { "ist",    tZONE,     -(HOUR(5)+30) }, /* Indian Standard */
1311     { "zp6",    tZONE,     -HOUR(6) },  /* USSR Zone 5 */
1312     { "nst",    tZONE,     -HOUR(7) },  /* North Sumatra */
1313     { "sst",    tZONE,     -HOUR(7) },  /* South Sumatra */
1314     { "jt",     tZONE,     -(HOUR(7)+30) }, /* Java (3pm in Cronusland!) */
1315     { "nzt",    tZONE,     -HOUR(12) }, /* New Zealand */
1316     { "idle",   tZONE,     -HOUR(12) }, /* International Date Line East */
1317     { "cat",    tZONE,     HOUR(10) },  /* -- expired 1967 */
1318     { "nt",     tZONE,     HOUR(11) },  /* -- expired 1967 */
1319     { "ahst",   tZONE,     HOUR(10) },  /* -- expired 1983 */
1320     { "hdt",    tDAYZONE,  HOUR(10) },  /* -- expired 1986 */
1321 #endif /* 0 */
1322 };
1323
1324
1325 /* ARGSUSED */
1326 static void
1327 date_error(s)
1328     char        *s;
1329 {
1330     /* NOTREACHED */
1331 }
1332
1333
1334 static time_t
1335 ToSeconds(Hours, Minutes, Seconds, Meridian)
1336     time_t      Hours;
1337     time_t      Minutes;
1338     time_t      Seconds;
1339     MERIDIAN    Meridian;
1340 {
1341     if (Minutes < 0 || Minutes > 59 || Seconds < 0 || Seconds > 61)
1342         return -1;
1343     if (Meridian == MER24) {
1344         if (Hours < 0 || Hours > 23)
1345             return -1;
1346     }
1347     else {
1348         if (Hours < 1 || Hours > 12)
1349             return -1;
1350         if (Hours == 12)
1351             Hours = 0;
1352         if (Meridian == MERpm)
1353             Hours += 12;
1354     }
1355     return (Hours * 60L + Minutes) * 60L + Seconds;
1356 }
1357
1358
1359 static time_t
1360 Convert(Month, Day, Year, Hours, Minutes, Seconds, Meridian, dst)
1361     time_t      Month;
1362     time_t      Day;
1363     time_t      Year;
1364     time_t      Hours;
1365     time_t      Minutes;
1366     time_t      Seconds;
1367     MERIDIAN    Meridian;
1368     DSTMODE     dst;
1369 {
1370     static int  DaysNormal[13] = {
1371         0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
1372     };
1373     static int  DaysLeap[13] = {
1374         0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
1375     };
1376     static int  LeapYears[] = {
1377         1972, 1976, 1980, 1984, 1988, 1992, 1996,
1378         2000, 2004, 2008, 2012, 2016, 2020, 2024, 2028, 2032, 2036
1379     };
1380     register int        *yp;
1381     register int        *mp;
1382     register time_t     Julian;
1383     register int        i;
1384     time_t              tod;
1385
1386     if (Year < 0)
1387         Year = -Year;
1388     if (Year < 100)
1389         Year += 1900;
1390     if (Year < EPOCH)
1391         Year += 100;
1392     for (mp = DaysNormal, yp = LeapYears; yp < ENDOF(LeapYears); yp++)
1393         if (Year == *yp) {
1394             mp = DaysLeap;
1395             break;
1396         }
1397     if (Year < EPOCH || Year > END_OF_TIME
1398      || Month < 1 || Month > 12
1399      /* NOSTRICT *//* conversion from long may lose accuracy */
1400      || Day < 1 || Day > mp[(int)Month])
1401         return -1;
1402
1403     Julian = Day - 1 + (Year - EPOCH) * 365;
1404     for (yp = LeapYears; yp < ENDOF(LeapYears); yp++, Julian++)
1405         if (Year <= *yp)
1406             break;
1407     for (i = 1; i < Month; i++)
1408         Julian += *++mp;
1409     Julian *= SECSPERDAY;
1410     Julian += yyTimezone * 60L;
1411     if ((tod = ToSeconds(Hours, Minutes, Seconds, Meridian)) < 0)
1412         return -1;
1413     Julian += tod;
1414     tod = Julian;
1415     if (dst == DSTon || (dst == DSTmaybe && localtime(&tod)->tm_isdst))
1416         Julian -= DST_OFFSET * 60L * 60L;
1417     return Julian;
1418 }
1419
1420
1421 static time_t
1422 DSTcorrect(Start, Future)
1423     time_t      Start;
1424     time_t      Future;
1425 {
1426     time_t      StartDay;
1427     time_t      FutureDay;
1428
1429     StartDay = (localtime(&Start)->tm_hour + 1) % 24;
1430     FutureDay = (localtime(&Future)->tm_hour + 1) % 24;
1431     return (Future - Start) + (StartDay - FutureDay) * DST_OFFSET * 60L * 60L;
1432 }
1433
1434
1435 static time_t
1436 RelativeMonth(Start, RelMonth)
1437     time_t      Start;
1438     time_t      RelMonth;
1439 {
1440     struct tm   *tm;
1441     time_t      Month;
1442     time_t      Year;
1443
1444     tm = localtime(&Start);
1445     Month = 12 * tm->tm_year + tm->tm_mon + RelMonth;
1446     Year = Month / 12;
1447     Month = Month % 12 + 1;
1448     return DSTcorrect(Start,
1449             Convert(Month, (time_t)tm->tm_mday, Year,
1450                 (time_t)tm->tm_hour, (time_t)tm->tm_min, (time_t)tm->tm_sec,
1451                 MER24, DSTmaybe));
1452 }
1453
1454
1455 static int
1456 LookupWord(buff, length)
1457     char                *buff;
1458     register int        length;
1459 {
1460     register char       *p;
1461     register char       *q;
1462     register TABLE      *tp;
1463     register int        c;
1464
1465     p = buff;
1466     c = p[0];
1467
1468     /* See if we have an abbreviation for a month. */
1469     if (length == 3 || (length == 4 && p[3] == '.'))
1470         for (tp = MonthDayTable; tp < ENDOF(MonthDayTable); tp++) {
1471             q = tp->name;
1472             if (c == q[0] && p[1] == q[1] && p[2] == q[2]) {
1473                 yylval.Number = tp->value;
1474                 return tp->type;
1475             }
1476         }
1477     else
1478         for (tp = MonthDayTable; tp < ENDOF(MonthDayTable); tp++)
1479             if (c == tp->name[0] && strcmp(p, tp->name) == 0) {
1480                 yylval.Number = tp->value;
1481                 return tp->type;
1482             }
1483
1484     /* Try for a timezone. */
1485     for (tp = TimezoneTable; tp < ENDOF(TimezoneTable); tp++)
1486         if (c == tp->name[0] && p[1] == tp->name[1]
1487          && strcmp(p, tp->name) == 0) {
1488             yylval.Number = tp->value;
1489             return tp->type;
1490         }
1491
1492     /* Try the units table. */
1493     for (tp = UnitsTable; tp < ENDOF(UnitsTable); tp++)
1494         if (c == tp->name[0] && strcmp(p, tp->name) == 0) {
1495             yylval.Number = tp->value;
1496             return tp->type;
1497         }
1498
1499     /* Strip off any plural and try the units table again. */
1500     if (--length > 0 && p[length] == 's') {
1501         p[length] = '\0';
1502         for (tp = UnitsTable; tp < ENDOF(UnitsTable); tp++)
1503             if (c == tp->name[0] && strcmp(p, tp->name) == 0) {
1504                 p[length] = 's';
1505                 yylval.Number = tp->value;
1506                 return tp->type;
1507             }
1508         p[length] = 's';
1509     }
1510     length++;
1511
1512     /* Drop out any periods. */
1513     for (p = buff, q = (char*)buff; *q; q++)
1514         if (*q != '.')
1515             *p++ = *q;
1516     *p = '\0';
1517
1518     /* Try the meridians. */
1519     if (buff[1] == 'm' && buff[2] == '\0') {
1520         if (buff[0] == 'a') {
1521             yylval.Meridian = MERam;
1522             return tMERIDIAN;
1523         }
1524         if (buff[0] == 'p') {
1525             yylval.Meridian = MERpm;
1526             return tMERIDIAN;
1527         }
1528     }
1529
1530     /* If we saw any periods, try the timezones again. */
1531     if (p - buff != length) {
1532         c = buff[0];
1533         for (p = buff, tp = TimezoneTable; tp < ENDOF(TimezoneTable); tp++)
1534             if (c == tp->name[0] && p[1] == tp->name[1]
1535             && strcmp(p, tp->name) == 0) {
1536                 yylval.Number = tp->value;
1537                 return tp->type;
1538             }
1539     }
1540
1541     /* Unknown word -- assume GMT timezone. */
1542     yylval.Number = 0;
1543     return tZONE;
1544 }
1545
1546
1547 int
1548 date_lex()
1549 {
1550     register char       c;
1551     register char       *p;
1552     char                buff[20];
1553     register int        sign;
1554     register int        i;
1555     register int        nesting;
1556
1557     for ( ; ; ) {
1558         /* Get first character after the whitespace. */
1559         for ( ; ; ) {
1560             while (isspace(*yyInput))
1561                 yyInput++;
1562             c = *yyInput;
1563
1564             /* Ignore RFC 822 comments, typically time zone names. */
1565             if (c != LPAREN)
1566                 break;
1567             for (nesting = 1; (c = *++yyInput) != RPAREN || --nesting; )
1568                 if (c == LPAREN)
1569                     nesting++;
1570                 else if (!IS7BIT(c) || c == '\0' || c == '\r'
1571                      || (c == '\\' && ((c = *++yyInput) == '\0' || !IS7BIT(c))))
1572                     /* Lexical error: bad comment. */
1573                     return '?';
1574             yyInput++;
1575         }
1576
1577         /* A number? */
1578         if (isdigit(c) || c == '-' || c == '+') {
1579             if (c == '-' || c == '+') {
1580                 sign = c == '-' ? -1 : 1;
1581                 yyInput++;
1582                 if (!isdigit(*yyInput))
1583                     /* Skip the plus or minus sign. */
1584                     continue;
1585             }
1586             else
1587                 sign = 0;
1588             for (i = 0; (c = *yyInput++) != '\0' && isdigit(c); )
1589                 i = 10 * i + c - '0';
1590             yyInput--;
1591             yylval.Number = sign < 0 ? -i : i;
1592             return sign ? tSNUMBER : tUNUMBER;
1593         }
1594
1595         /* A word? */
1596         if (isalpha(c)) {
1597             for (p = buff; (c = *yyInput++) == '.' || isalpha(c); )
1598                 if (p < &buff[sizeof buff - 1])
1599                     *p++ = isupper(c) ? tolower(c) : c;
1600             *p = '\0';
1601             yyInput--;
1602             return LookupWord(buff, p - buff);
1603         }
1604
1605         return *yyInput++;
1606     }
1607 }
1608
1609
1610 time_t
1611 parsedate(p)
1612     char                *p;
1613 {
1614     extern int          date_parse();
1615     time_t              Start;
1616
1617     yyInput = p;
1618
1619     yyYear = 0;
1620     yyMonth = 0;
1621     yyDay = 0;
1622     yyTimezone = 0;
1623     yyDSTmode = DSTmaybe;
1624     yyHour = 0;
1625     yyMinutes = 0;
1626     yySeconds = 0;
1627     yyMeridian = MER24;
1628     yyRelSeconds = 0;
1629     yyRelMonth = 0;
1630     yyHaveDate = 0;
1631     yyHaveRel = 0;
1632     yyHaveTime = 0;
1633
1634     if (date_parse() || yyHaveTime > 1 || yyHaveDate > 1)
1635         return -1;
1636
1637     if (yyHaveDate || yyHaveTime) {
1638         Start = Convert(yyMonth, yyDay, yyYear, yyHour, yyMinutes, yySeconds,
1639                     yyMeridian, yyDSTmode);
1640         if (Start < 0)
1641             return -1;
1642     }
1643     else
1644         return -1;
1645
1646     Start += yyRelSeconds;
1647     if (yyRelMonth)
1648         Start += RelativeMonth(Start, yyRelMonth);
1649
1650     /* Have to do *something* with a legitimate -1 so it's distinguishable
1651      * from the error return value.  (Alternately could set errno on error.) */
1652     return Start == -1 ? 0 : Start;
1653 }
1654
1655
1656 #ifdef TEST
1657
1658 #if YYDEBUG
1659 extern int      yydebug;
1660 #endif /* YYDEBUG */
1661
1662 /* ARGSUSED */
1663 int
1664 main(ac, av)
1665     int         ac;
1666     char        *av[];
1667 {
1668     char        buff[128];
1669     time_t      d;
1670
1671 #if YYDEBUG
1672     yydebug = 1;
1673 #endif /* YYDEBUG */
1674
1675     (void)printf("Enter date, or blank line to exit.\n\t> ");
1676     for ( ; ; ) {
1677         (void)printf("\t> ");
1678         (void)fflush(stdout);
1679         if (gets(buff) == NULL || buff[0] == '\n')
1680             break;
1681 #if YYDEBUG
1682         if (strcmp(buff, "yydebug") == 0) {
1683             yydebug = !yydebug;
1684             printf("yydebug = %s\n", yydebug ? "on" : "off");
1685             continue;
1686         }
1687 #endif /* YYDEBUG */
1688         d = parsedate(buff);
1689         if (d == -1)
1690             (void)printf("Bad format - couldn't convert.\n");
1691         else
1692             (void)printf("%s", ctime(&d));
1693     }
1694
1695     exit(0);
1696     /* NOTREACHED */
1697 }
1698 #endif /* TEST */