284dbac836b29bca7afcbd3e567db0a8cb56df23
[citadel.git] / citadel / parsedate.c
1
2 # line 2 "parsedate.y"
3 /* $Revision$
4 **
5 **  Originally written by Steven M. Bellovin <smb@research.att.com> while
6 **  at the University of North Carolina at Chapel Hill.  Later tweaked by
7 **  a couple of people on Usenet.  Completely overhauled by Rich $alz
8 **  <rsalz@osf.org> and Jim Berets <jberets@bbn.com> in August, 1990.
9 **  Further revised (removed obsolete constructs and cleaned up timezone
10 **  names) in August, 1991, by Rich.  Paul Eggert <eggert@twinsun.com>
11 **  helped in September, 1992.  Art Cancro <ajc@uncnsrd.mt-kisco.ny.us> cleaned
12 **  it up for ANSI C in December, 1999.
13 **
14 **  This grammar has six shift/reduce conflicts.
15 **
16 **  This code is in the public domain and has no copyright.
17 */
18 /* SUPPRESS 530 *//* Empty body for statement */
19 /* SUPPRESS 593 on yyerrlab *//* Label was not used */
20 /* SUPPRESS 593 on yynewstate *//* Label was not used */
21 /* SUPPRESS 595 on yypvt *//* Automatic variable may be used before set */
22 #include <stdio.h>
23 #include <sys/types.h>
24 #include <ctype.h>
25 #include <time.h>
26 #include "parsedate.h"
27
28 int date_lex(void);
29
30 #define yyparse         date_parse
31 #define yylex           date_lex
32 #define yyerror         date_error
33
34
35     /* See the LeapYears table in Convert. */
36 #define EPOCH           1970
37 #define END_OF_TIME     2038
38     /* Constants for general time calculations. */
39 #define DST_OFFSET      1
40 #define SECSPERDAY      (24L * 60L * 60L)
41     /* Readability for TABLE stuff. */
42 #define HOUR(x)         (x * 60)
43
44 #define LPAREN          '('
45 #define RPAREN          ')'
46 #define IS7BIT(x)       ((unsigned int)(x) < 0200)
47
48 #define SIZEOF(array)   ((int)(sizeof array / sizeof array[0]))
49 #define ENDOF(array)    (&array[SIZEOF(array)])
50
51
52 /*
53 **  An entry in the lexical lookup table.
54 */
55 typedef struct _TABLE {
56     char        *name;
57     int         type;
58     time_t      value;
59 } TABLE;
60
61 /*
62 **  Daylight-savings mode:  on, off, or not yet known.
63 */
64 typedef enum _DSTMODE {
65     DSTon, DSToff, DSTmaybe
66 } DSTMODE;
67
68 /*
69 **  Meridian:  am, pm, or 24-hour style.
70 */
71 typedef enum _MERIDIAN {
72     MERam, MERpm, MER24
73 } MERIDIAN;
74
75
76 /*
77 **  Global variables.  We could get rid of most of them by using a yacc
78 **  union, but this is more efficient.  (This routine predates the
79 **  yacc %union construct.)
80 */
81 static char     *yyInput;
82 static DSTMODE  yyDSTmode;
83 static int      yyHaveDate;
84 static int      yyHaveRel;
85 static int      yyHaveTime;
86 static time_t   yyTimezone;
87 static time_t   yyDay;
88 static time_t   yyHour;
89 static time_t   yyMinutes;
90 static time_t   yyMonth;
91 static time_t   yySeconds;
92 static time_t   yyYear;
93 static MERIDIAN yyMeridian;
94 static time_t   yyRelMonth;
95 static time_t   yyRelSeconds;
96
97
98 static void             date_error(char *);
99
100 # line 100 "parsedate.y"
101 typedef union
102 #ifdef __cplusplus
103         YYSTYPE
104 #endif
105  {
106     time_t              Number;
107     enum _MERIDIAN      Meridian;
108 } YYSTYPE;
109 # define tDAY 257
110 # define tDAYZONE 258
111 # define tMERIDIAN 259
112 # define tMONTH 260
113 # define tMONTH_UNIT 261
114 # define tSEC_UNIT 262
115 # define tSNUMBER 263
116 # define tUNUMBER 264
117 # define tZONE 265
118
119 #include <inttypes.h>
120
121 #ifdef __STDC__
122 #include <stdlib.h>
123 #include <string.h>
124 #else
125 #include <malloc.h>
126 #include <memory.h>
127 #endif
128
129 #include <values.h>
130
131 #if defined(__cplusplus) || defined(__STDC__)
132
133 #if defined(__cplusplus) && defined(__EXTERN_C__)
134 extern "C" {
135 #endif
136 #ifndef yyerror
137 #if defined(__cplusplus)
138         void yyerror(const char *);
139 #endif
140 #endif
141 #ifndef yylex
142         int yylex(void);
143 #endif
144         int yyparse(void);
145 #if defined(__cplusplus) && defined(__EXTERN_C__)
146 }
147 #endif
148
149 #endif
150
151 #define yyclearin yychar = -1
152 #define yyerrok yyerrflag = 0
153 extern int yychar;
154 extern int yyerrflag;
155 YYSTYPE yylval;
156 YYSTYPE yyval;
157 typedef int yytabelem;
158 #ifndef YYMAXDEPTH
159 #define YYMAXDEPTH 150
160 #endif
161 #if YYMAXDEPTH > 0
162 int yy_yys[YYMAXDEPTH], *yys = yy_yys;
163 YYSTYPE yy_yyv[YYMAXDEPTH], *yyv = yy_yyv;
164 #else   /* user does initial allocation */
165 int *yys;
166 YYSTYPE *yyv;
167 #endif
168 static int yymaxdepth = YYMAXDEPTH;
169 # define YYERRCODE 256
170
171 # line 286 "parsedate.y"
172
173
174 /* Month and day table. */
175 static TABLE    MonthDayTable[] = {
176     { "january",        tMONTH,  1 },
177     { "february",       tMONTH,  2 },
178     { "march",          tMONTH,  3 },
179     { "april",          tMONTH,  4 },
180     { "may",            tMONTH,  5 },
181     { "june",           tMONTH,  6 },
182     { "july",           tMONTH,  7 },
183     { "august",         tMONTH,  8 },
184     { "september",      tMONTH,  9 },
185     { "october",        tMONTH, 10 },
186     { "november",       tMONTH, 11 },
187     { "december",       tMONTH, 12 },
188         /* The value of the day isn't used... */
189     { "sunday",         tDAY, 0 },
190     { "monday",         tDAY, 0 },
191     { "tuesday",        tDAY, 0 },
192     { "wednesday",      tDAY, 0 },
193     { "thursday",       tDAY, 0 },
194     { "friday",         tDAY, 0 },
195     { "saturday",       tDAY, 0 },
196 };
197
198 /* Time units table. */
199 static TABLE    UnitsTable[] = {
200     { "year",           tMONTH_UNIT,    12 },
201     { "month",          tMONTH_UNIT,    1 },
202     { "week",           tSEC_UNIT,      7L * 24 * 60 * 60 },
203     { "day",            tSEC_UNIT,      1L * 24 * 60 * 60 },
204     { "hour",           tSEC_UNIT,      60 * 60 },
205     { "minute",         tSEC_UNIT,      60 },
206     { "min",            tSEC_UNIT,      60 },
207     { "second",         tSEC_UNIT,      1 },
208     { "sec",            tSEC_UNIT,      1 },
209 };
210
211 /* Timezone table. */
212 static TABLE    TimezoneTable[] = {
213     { "gmt",    tZONE,     HOUR( 0) },  /* Greenwich Mean */
214     { "ut",     tZONE,     HOUR( 0) },  /* Universal */
215     { "utc",    tZONE,     HOUR( 0) },  /* Universal Coordinated */
216     { "cut",    tZONE,     HOUR( 0) },  /* Coordinated Universal */
217     { "z",      tZONE,     HOUR( 0) },  /* Greenwich Mean */
218     { "wet",    tZONE,     HOUR( 0) },  /* Western European */
219     { "bst",    tDAYZONE,  HOUR( 0) },  /* British Summer */
220     { "nst",    tZONE,     HOUR(3)+30 }, /* Newfoundland Standard */
221     { "ndt",    tDAYZONE,  HOUR(3)+30 }, /* Newfoundland Daylight */
222     { "ast",    tZONE,     HOUR( 4) },  /* Atlantic Standard */
223     { "adt",    tDAYZONE,  HOUR( 4) },  /* Atlantic Daylight */
224     { "est",    tZONE,     HOUR( 5) },  /* Eastern Standard */
225     { "edt",    tDAYZONE,  HOUR( 5) },  /* Eastern Daylight */
226     { "cst",    tZONE,     HOUR( 6) },  /* Central Standard */
227     { "cdt",    tDAYZONE,  HOUR( 6) },  /* Central Daylight */
228     { "mst",    tZONE,     HOUR( 7) },  /* Mountain Standard */
229     { "mdt",    tDAYZONE,  HOUR( 7) },  /* Mountain Daylight */
230     { "pst",    tZONE,     HOUR( 8) },  /* Pacific Standard */
231     { "pdt",    tDAYZONE,  HOUR( 8) },  /* Pacific Daylight */
232     { "yst",    tZONE,     HOUR( 9) },  /* Yukon Standard */
233     { "ydt",    tDAYZONE,  HOUR( 9) },  /* Yukon Daylight */
234     { "akst",   tZONE,     HOUR( 9) },  /* Alaska Standard */
235     { "akdt",   tDAYZONE,  HOUR( 9) },  /* Alaska Daylight */
236     { "hst",    tZONE,     HOUR(10) },  /* Hawaii Standard */
237     { "hast",   tZONE,     HOUR(10) },  /* Hawaii-Aleutian Standard */
238     { "hadt",   tDAYZONE,  HOUR(10) },  /* Hawaii-Aleutian Daylight */
239     { "ces",    tDAYZONE,  -HOUR(1) },  /* Central European Summer */
240     { "cest",   tDAYZONE,  -HOUR(1) },  /* Central European Summer */
241     { "mez",    tZONE,     -HOUR(1) },  /* Middle European */
242     { "mezt",   tDAYZONE,  -HOUR(1) },  /* Middle European Summer */
243     { "cet",    tZONE,     -HOUR(1) },  /* Central European */
244     { "met",    tZONE,     -HOUR(1) },  /* Middle European */
245     { "eet",    tZONE,     -HOUR(2) },  /* Eastern Europe */
246     { "msk",    tZONE,     -HOUR(3) },  /* Moscow Winter */
247     { "msd",    tDAYZONE,  -HOUR(3) },  /* Moscow Summer */
248     { "wast",   tZONE,     -HOUR(8) },  /* West Australian Standard */
249     { "wadt",   tDAYZONE,  -HOUR(8) },  /* West Australian Daylight */
250     { "hkt",    tZONE,     -HOUR(8) },  /* Hong Kong */
251     { "cct",    tZONE,     -HOUR(8) },  /* China Coast */
252     { "jst",    tZONE,     -HOUR(9) },  /* Japan Standard */
253     { "kst",    tZONE,     -HOUR(9) },  /* Korean Standard */
254     { "kdt",    tZONE,     -HOUR(9) },  /* Korean Daylight */
255     { "cast",   tZONE,     -(HOUR(9)+30) }, /* Central Australian Standard */
256     { "cadt",   tDAYZONE,  -(HOUR(9)+30) }, /* Central Australian Daylight */
257     { "east",   tZONE,     -HOUR(10) }, /* Eastern Australian Standard */
258     { "eadt",   tDAYZONE,  -HOUR(10) }, /* Eastern Australian Daylight */
259     { "nzst",   tZONE,     -HOUR(12) }, /* New Zealand Standard */
260     { "nzdt",   tDAYZONE,  -HOUR(12) }, /* New Zealand Daylight */
261
262     /* For completeness we include the following entries. */
263 #if 0
264
265     /* Duplicate names.  Either they conflict with a zone listed above
266      * (which is either more likely to be seen or just been in circulation
267      * longer), or they conflict with another zone in this section and
268      * we could not reasonably choose one over the other. */
269     { "fst",    tZONE,     HOUR( 2) },  /* Fernando De Noronha Standard */
270     { "fdt",    tDAYZONE,  HOUR( 2) },  /* Fernando De Noronha Daylight */
271     { "bst",    tZONE,     HOUR( 3) },  /* Brazil Standard */
272     { "est",    tZONE,     HOUR( 3) },  /* Eastern Standard (Brazil) */
273     { "edt",    tDAYZONE,  HOUR( 3) },  /* Eastern Daylight (Brazil) */
274     { "wst",    tZONE,     HOUR( 4) },  /* Western Standard (Brazil) */
275     { "wdt",    tDAYZONE,  HOUR( 4) },  /* Western Daylight (Brazil) */
276     { "cst",    tZONE,     HOUR( 5) },  /* Chile Standard */
277     { "cdt",    tDAYZONE,  HOUR( 5) },  /* Chile Daylight */
278     { "ast",    tZONE,     HOUR( 5) },  /* Acre Standard */
279     { "adt",    tDAYZONE,  HOUR( 5) },  /* Acre Daylight */
280     { "cst",    tZONE,     HOUR( 5) },  /* Cuba Standard */
281     { "cdt",    tDAYZONE,  HOUR( 5) },  /* Cuba Daylight */
282     { "est",    tZONE,     HOUR( 6) },  /* Easter Island Standard */
283     { "edt",    tDAYZONE,  HOUR( 6) },  /* Easter Island Daylight */
284     { "sst",    tZONE,     HOUR(11) },  /* Samoa Standard */
285     { "ist",    tZONE,     -HOUR(2) },  /* Israel Standard */
286     { "idt",    tDAYZONE,  -HOUR(2) },  /* Israel Daylight */
287     { "idt",    tDAYZONE,  -(HOUR(3)+30) }, /* Iran Daylight */
288     { "ist",    tZONE,     -(HOUR(3)+30) }, /* Iran Standard */
289     { "cst",     tZONE,     -HOUR(8) }, /* China Standard */
290     { "cdt",     tDAYZONE,  -HOUR(8) }, /* China Daylight */
291     { "sst",     tZONE,     -HOUR(8) }, /* Singapore Standard */
292
293     /* Dubious (e.g., not in Olson's TIMEZONE package) or obsolete. */
294     { "gst",    tZONE,     HOUR( 3) },  /* Greenland Standard */
295     { "wat",    tZONE,     -HOUR(1) },  /* West Africa */
296     { "at",     tZONE,     HOUR( 2) },  /* Azores */
297     { "gst",    tZONE,     -HOUR(10) }, /* Guam Standard */
298     { "nft",    tZONE,     HOUR(3)+30 }, /* Newfoundland */
299     { "idlw",   tZONE,     HOUR(12) },  /* International Date Line West */
300     { "mewt",   tZONE,     -HOUR(1) },  /* Middle European Winter */
301     { "mest",   tDAYZONE,  -HOUR(1) },  /* Middle European Summer */
302     { "swt",    tZONE,     -HOUR(1) },  /* Swedish Winter */
303     { "sst",    tDAYZONE,  -HOUR(1) },  /* Swedish Summer */
304     { "fwt",    tZONE,     -HOUR(1) },  /* French Winter */
305     { "fst",    tDAYZONE,  -HOUR(1) },  /* French Summer */
306     { "bt",     tZONE,     -HOUR(3) },  /* Baghdad */
307     { "it",     tZONE,     -(HOUR(3)+30) }, /* Iran */
308     { "zp4",    tZONE,     -HOUR(4) },  /* USSR Zone 3 */
309     { "zp5",    tZONE,     -HOUR(5) },  /* USSR Zone 4 */
310     { "ist",    tZONE,     -(HOUR(5)+30) }, /* Indian Standard */
311     { "zp6",    tZONE,     -HOUR(6) },  /* USSR Zone 5 */
312     { "nst",    tZONE,     -HOUR(7) },  /* North Sumatra */
313     { "sst",    tZONE,     -HOUR(7) },  /* South Sumatra */
314     { "jt",     tZONE,     -(HOUR(7)+30) }, /* Java (3pm in Cronusland!) */
315     { "nzt",    tZONE,     -HOUR(12) }, /* New Zealand */
316     { "idle",   tZONE,     -HOUR(12) }, /* International Date Line East */
317     { "cat",    tZONE,     HOUR(10) },  /* -- expired 1967 */
318     { "nt",     tZONE,     HOUR(11) },  /* -- expired 1967 */
319     { "ahst",   tZONE,     HOUR(10) },  /* -- expired 1983 */
320     { "hdt",    tDAYZONE,  HOUR(10) },  /* -- expired 1986 */
321 #endif /* 0 */
322 };
323
324
325 /* ARGSUSED */
326 static void
327 date_error(char *s)
328 {
329     /* NOTREACHED */
330 }
331
332
333 static time_t
334 ToSeconds(time_t Hours, time_t Minutes, time_t Seconds, MERIDIAN Meridian)
335 {
336     if (Minutes < 0 || Minutes > 59 || Seconds < 0 || Seconds > 61)
337         return -1;
338     if (Meridian == MER24) {
339         if (Hours < 0 || Hours > 23)
340             return -1;
341     }
342     else {
343         if (Hours < 1 || Hours > 12)
344             return -1;
345         if (Hours == 12)
346             Hours = 0;
347         if (Meridian == MERpm)
348             Hours += 12;
349     }
350     return (Hours * 60L + Minutes) * 60L + Seconds;
351 }
352
353
354 static time_t
355 Convert(time_t Month, time_t Day, time_t Year,
356         time_t Hours, time_t Minutes, time_t Seconds,
357         MERIDIAN Meridian, DSTMODE dst)
358 {
359     static int  DaysNormal[13] = {
360         0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
361     };
362     static int  DaysLeap[13] = {
363         0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
364     };
365     static int  LeapYears[] = {
366         1972, 1976, 1980, 1984, 1988, 1992, 1996,
367         2000, 2004, 2008, 2012, 2016, 2020, 2024, 2028, 2032, 2036
368     };
369     register int        *yp;
370     register int        *mp;
371     register time_t     Julian;
372     register int        i;
373     time_t              tod;
374
375     if (Year < 0)
376         Year = -Year;
377     if (Year < 100)
378         Year += 1900;
379     if (Year < EPOCH)
380         Year += 100;
381     for (mp = DaysNormal, yp = LeapYears; yp < ENDOF(LeapYears); yp++)
382         if (Year == *yp) {
383             mp = DaysLeap;
384             break;
385         }
386     if (Year < EPOCH || Year > END_OF_TIME
387      || Month < 1 || Month > 12
388      /* NOSTRICT *//* conversion from long may lose accuracy */
389      || Day < 1 || Day > mp[(int)Month])
390         return -1;
391
392     Julian = Day - 1 + (Year - EPOCH) * 365;
393     for (yp = LeapYears; yp < ENDOF(LeapYears); yp++, Julian++)
394         if (Year <= *yp)
395             break;
396     for (i = 1; i < Month; i++)
397         Julian += *++mp;
398     Julian *= SECSPERDAY;
399     Julian += yyTimezone * 60L;
400     if ((tod = ToSeconds(Hours, Minutes, Seconds, Meridian)) < 0)
401         return -1;
402     Julian += tod;
403     tod = Julian;
404     if (dst == DSTon || (dst == DSTmaybe && localtime(&tod)->tm_isdst))
405         Julian -= DST_OFFSET * 60L * 60L;
406     return Julian;
407 }
408
409
410 static time_t
411 DSTcorrect(time_t Start, time_t Future)
412 {
413     time_t      StartDay;
414     time_t      FutureDay;
415
416     StartDay = (localtime(&Start)->tm_hour + 1) % 24;
417     FutureDay = (localtime(&Future)->tm_hour + 1) % 24;
418     return (Future - Start) + (StartDay - FutureDay) * DST_OFFSET * 60L * 60L;
419 }
420
421
422 static time_t
423 RelativeMonth(time_t Start, time_t RelMonth)
424 {
425     struct tm   *tm;
426     time_t      Month;
427     time_t      Year;
428
429     tm = localtime(&Start);
430     Month = 12 * tm->tm_year + tm->tm_mon + RelMonth;
431     Year = Month / 12;
432     Month = Month % 12 + 1;
433     return DSTcorrect(Start,
434             Convert(Month, (time_t)tm->tm_mday, Year,
435                 (time_t)tm->tm_hour, (time_t)tm->tm_min, (time_t)tm->tm_sec,
436                 MER24, DSTmaybe));
437 }
438
439
440 static int
441 LookupWord(char *buff, register int length)
442 {
443     register char       *p;
444     register char       *q;
445     register TABLE      *tp;
446     register int        c;
447
448     p = buff;
449     c = p[0];
450
451     /* See if we have an abbreviation for a month. */
452     if (length == 3 || (length == 4 && p[3] == '.'))
453         for (tp = MonthDayTable; tp < ENDOF(MonthDayTable); tp++) {
454             q = tp->name;
455             if (c == q[0] && p[1] == q[1] && p[2] == q[2]) {
456                 yylval.Number = tp->value;
457                 return tp->type;
458             }
459         }
460     else
461         for (tp = MonthDayTable; tp < ENDOF(MonthDayTable); tp++)
462             if (c == tp->name[0] && strcmp(p, tp->name) == 0) {
463                 yylval.Number = tp->value;
464                 return tp->type;
465             }
466
467     /* Try for a timezone. */
468     for (tp = TimezoneTable; tp < ENDOF(TimezoneTable); tp++)
469         if (c == tp->name[0] && p[1] == tp->name[1]
470          && strcmp(p, tp->name) == 0) {
471             yylval.Number = tp->value;
472             return tp->type;
473         }
474
475     /* Try the units table. */
476     for (tp = UnitsTable; tp < ENDOF(UnitsTable); tp++)
477         if (c == tp->name[0] && strcmp(p, tp->name) == 0) {
478             yylval.Number = tp->value;
479             return tp->type;
480         }
481
482     /* Strip off any plural and try the units table again. */
483     if (--length > 0 && p[length] == 's') {
484         p[length] = '\0';
485         for (tp = UnitsTable; tp < ENDOF(UnitsTable); tp++)
486             if (c == tp->name[0] && strcmp(p, tp->name) == 0) {
487                 p[length] = 's';
488                 yylval.Number = tp->value;
489                 return tp->type;
490             }
491         p[length] = 's';
492     }
493     length++;
494
495     /* Drop out any periods. */
496     for (p = buff, q = (char*)buff; *q; q++)
497         if (*q != '.')
498             *p++ = *q;
499     *p = '\0';
500
501     /* Try the meridians. */
502     if (buff[1] == 'm' && buff[2] == '\0') {
503         if (buff[0] == 'a') {
504             yylval.Meridian = MERam;
505             return tMERIDIAN;
506         }
507         if (buff[0] == 'p') {
508             yylval.Meridian = MERpm;
509             return tMERIDIAN;
510         }
511     }
512
513     /* If we saw any periods, try the timezones again. */
514     if (p - buff != length) {
515         c = buff[0];
516         for (p = buff, tp = TimezoneTable; tp < ENDOF(TimezoneTable); tp++)
517             if (c == tp->name[0] && p[1] == tp->name[1]
518             && strcmp(p, tp->name) == 0) {
519                 yylval.Number = tp->value;
520                 return tp->type;
521             }
522     }
523
524     /* Unknown word -- assume GMT timezone. */
525     yylval.Number = 0;
526     return tZONE;
527 }
528
529
530 int
531 date_lex(void)
532 {
533     register char       c;
534     register char       *p;
535     char                buff[20];
536     register int        sign;
537     register int        i;
538     register int        nesting;
539
540     for ( ; ; ) {
541         /* Get first character after the whitespace. */
542         for ( ; ; ) {
543             while (isspace(*yyInput))
544                 yyInput++;
545             c = *yyInput;
546
547             /* Ignore RFC 822 comments, typically time zone names. */
548             if (c != LPAREN)
549                 break;
550             for (nesting = 1; (c = *++yyInput) != RPAREN || --nesting; )
551                 if (c == LPAREN)
552                     nesting++;
553                 else if (!IS7BIT(c) || c == '\0' || c == '\r'
554                      || (c == '\\' && ((c = *++yyInput) == '\0' || !IS7BIT(c))))
555                     /* Lexical error: bad comment. */
556                     return '?';
557             yyInput++;
558         }
559
560         /* A number? */
561         if (isdigit(c) || c == '-' || c == '+') {
562             if (c == '-' || c == '+') {
563                 sign = c == '-' ? -1 : 1;
564                 yyInput++;
565                 if (!isdigit(*yyInput))
566                     /* Skip the plus or minus sign. */
567                     continue;
568             }
569             else
570                 sign = 0;
571             for (i = 0; (c = *yyInput++) != '\0' && isdigit(c); )
572                 i = 10 * i + c - '0';
573             yyInput--;
574             yylval.Number = sign < 0 ? -i : i;
575             return sign ? tSNUMBER : tUNUMBER;
576         }
577
578         /* A word? */
579         if (isalpha(c)) {
580             for (p = buff; (c = *yyInput++) == '.' || isalpha(c); )
581                 if (p < &buff[sizeof buff - 1])
582                     *p++ = isupper(c) ? tolower(c) : c;
583             *p = '\0';
584             yyInput--;
585             return LookupWord(buff, p - buff);
586         }
587
588         return *yyInput++;
589     }
590 }
591
592
593 time_t
594 parsedate(char *p)
595 {
596     extern int          date_parse(void);
597     time_t              Start;
598
599     yyInput = p;
600
601     yyYear = 0;
602     yyMonth = 0;
603     yyDay = 0;
604     yyTimezone = 0;
605     yyDSTmode = DSTmaybe;
606     yyHour = 0;
607     yyMinutes = 0;
608     yySeconds = 0;
609     yyMeridian = MER24;
610     yyRelSeconds = 0;
611     yyRelMonth = 0;
612     yyHaveDate = 0;
613     yyHaveRel = 0;
614     yyHaveTime = 0;
615
616     if (date_parse() || yyHaveTime > 1 || yyHaveDate > 1)
617         return -1;
618
619     if (yyHaveDate || yyHaveTime) {
620         Start = Convert(yyMonth, yyDay, yyYear, yyHour, yyMinutes, yySeconds,
621                     yyMeridian, yyDSTmode);
622         if (Start < 0)
623             return -1;
624     }
625     else
626         return -1;
627
628     Start += yyRelSeconds;
629     if (yyRelMonth)
630         Start += RelativeMonth(Start, yyRelMonth);
631
632     /* Have to do *something* with a legitimate -1 so it's distinguishable
633      * from the error return value.  (Alternately could set errno on error.) */
634     return Start == -1 ? 0 : Start;
635 }
636
637
638 #ifdef TEST
639
640 #if YYDEBUG
641 extern int      yydebug;
642 #endif /* YYDEBUG */
643
644 /* ARGSUSED */
645 int
646 main(int ac, char *av[])
647 {
648     char        buff[128];
649     time_t      d;
650
651 #if YYDEBUG
652     yydebug = 1;
653 #endif /* YYDEBUG */
654
655     (void)printf("Enter date, or blank line to exit.\n\t> ");
656     for ( ; ; ) {
657         (void)printf("\t> ");
658         (void)fflush(stdout);
659         if (gets(buff) == NULL || buff[0] == '\n')
660             break;
661 #if YYDEBUG
662         if (strcmp(buff, "yydebug") == 0) {
663             yydebug = !yydebug;
664             printf("yydebug = %s\n", yydebug ? "on" : "off");
665             continue;
666         }
667 #endif /* YYDEBUG */
668         d = parsedate(buff, (TIMEINFO *)NULL);
669         if (d == -1)
670             (void)printf("Bad format - couldn't convert.\n");
671         else
672             (void)printf("%s", ctime(&d));
673     }
674
675     exit(0);
676     /* NOTREACHED */
677 }
678 #endif /* TEST */
679 static const yytabelem yyexca[] ={
680 -1, 1,
681         0, -1,
682         -2, 0,
683         };
684 # define YYNPROD 30
685 # define YYLAST 216
686 static const yytabelem yyact[]={
687
688     17,    12,    34,    40,    39,    21,    14,     8,    11,    14,
689      7,    16,    38,     9,     6,    36,    31,    29,    28,    27,
690     22,    14,    25,    24,    37,    35,    30,    23,    13,    15,
691      5,     4,     3,     2,     1,    10,     0,     0,     0,     0,
692     26,     0,     0,     0,     0,     0,     0,     0,     0,     0,
693      0,     0,     0,     0,     0,     0,    33,    32,     0,     0,
694      0,     0,     0,     0,     0,     0,     0,    42,    41,     0,
695      0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
696      0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
697      0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
698      0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
699      0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
700      0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
701      0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
702      0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
703      0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
704      0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
705      0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
706      0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
707      0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
708      0,     0,     0,    21,     0,     0,     0,    14,     0,     0,
709      0,     0,    21,    18,    20,    19 };
710 static const yytabelem yypact[]={
711
712 -10000000,  -250,-10000000,  -257,-10000000,-10000000,   -47,  -244,   -17,  -239,
713 -10000000,  -242,-10000000,-10000000,-10000000,-10000000,  -245,  -246,  -247,-10000000,
714 -10000000,-10000000,   -18,  -248,-10000000,-10000000,-10000000,   -56,   -22,-10000000,
715   -249,  -236,-10000000,-10000000,  -252,  -260,-10000000,  -261,  -254,-10000000,
716 -10000000,-10000000,-10000000 };
717 static const yytabelem yypgo[]={
718
719      0,    28,    35,    29,    34,    33,    32,    31,    30 };
720 static const yytabelem yyr1[]={
721
722      0,     4,     4,     5,     5,     5,     5,     6,     6,     6,
723      6,     6,     2,     2,     2,     2,     1,     7,     7,     7,
724      7,     7,     7,     7,     8,     8,     8,     8,     3,     3 };
725 static const yytabelem yyr2[]={
726
727      0,     0,     4,     3,     5,     3,     3,     5,     9,     9,
728     13,    13,     3,     3,     5,     3,     3,     7,    11,     5,
729      9,     5,     7,    11,     5,     5,     5,     5,     1,     3 };
730 static const yytabelem yychk[]={
731
732 -10000000,    -4,    -5,    -6,    -7,    -8,   264,   260,   257,   263,
733     -2,   265,   258,    -1,   263,    -3,    58,    47,   260,   262,
734    261,   259,   264,    44,   262,   261,    -1,   264,   264,   264,
735     44,   264,    -3,    -1,    58,    47,   264,   260,   264,   264,
736    264,    -3,    -1 };
737 static const yytabelem yydef[]={
738
739      1,    -2,     2,     3,     5,     6,    28,     0,     0,     0,
740      4,    12,    13,    15,    16,     7,     0,     0,    21,    25,
741     27,    29,    19,     0,    24,    26,    14,    28,    17,    22,
742      0,     0,     8,     9,     0,     0,    20,     0,    28,    18,
743     23,    10,    11 };
744 typedef struct
745 #ifdef __cplusplus
746         yytoktype
747 #endif
748 { char *t_name; int t_val; } yytoktype;
749 #ifndef YYDEBUG
750 #       define YYDEBUG  0       /* don't allow debugging */
751 #endif
752
753 #if YYDEBUG
754
755 yytoktype yytoks[] =
756 {
757         "tDAY", 257,
758         "tDAYZONE",     258,
759         "tMERIDIAN",    259,
760         "tMONTH",       260,
761         "tMONTH_UNIT",  261,
762         "tSEC_UNIT",    262,
763         "tSNUMBER",     263,
764         "tUNUMBER",     264,
765         "tZONE",        265,
766         "-unknown-",    -1      /* ends search */
767 };
768
769 char * yyreds[] =
770 {
771         "-no such reduction-",
772         "spec : /* empty */",
773         "spec : spec item",
774         "item : time",
775         "item : time zone",
776         "item : date",
777         "item : rel",
778         "time : tUNUMBER o_merid",
779         "time : tUNUMBER ':' tUNUMBER o_merid",
780         "time : tUNUMBER ':' tUNUMBER numzone",
781         "time : tUNUMBER ':' tUNUMBER ':' tUNUMBER o_merid",
782         "time : tUNUMBER ':' tUNUMBER ':' tUNUMBER numzone",
783         "zone : tZONE",
784         "zone : tDAYZONE",
785         "zone : tZONE numzone",
786         "zone : numzone",
787         "numzone : tSNUMBER",
788         "date : tUNUMBER '/' tUNUMBER",
789         "date : tUNUMBER '/' tUNUMBER '/' tUNUMBER",
790         "date : tMONTH tUNUMBER",
791         "date : tMONTH tUNUMBER ',' tUNUMBER",
792         "date : tUNUMBER tMONTH",
793         "date : tUNUMBER tMONTH tUNUMBER",
794         "date : tDAY ',' tUNUMBER tMONTH tUNUMBER",
795         "rel : tSNUMBER tSEC_UNIT",
796         "rel : tUNUMBER tSEC_UNIT",
797         "rel : tSNUMBER tMONTH_UNIT",
798         "rel : tUNUMBER tMONTH_UNIT",
799         "o_merid : /* empty */",
800         "o_merid : tMERIDIAN",
801 };
802 #endif /* YYDEBUG */
803 # line  1 "/usr/ccs/bin/yaccpar"
804 /*
805  * Copyright (c) 1993 by Sun Microsystems, Inc.
806  */
807
808 #pragma ident   "@(#)yaccpar    6.15    97/12/08 SMI"
809
810 /*
811 ** Skeleton parser driver for yacc output
812 */
813
814 /*
815 ** yacc user known macros and defines
816 */
817 #define YYERROR         goto yyerrlab
818 #define YYACCEPT        return(0)
819 #define YYABORT         return(1)
820 #define YYBACKUP( newtoken, newvalue )\
821 {\
822         if ( yychar >= 0 || ( yyr2[ yytmp ] >> 1 ) != 1 )\
823         {\
824                 yyerror( "syntax error - cannot backup" );\
825                 goto yyerrlab;\
826         }\
827         yychar = newtoken;\
828         yystate = *yyps;\
829         yylval = newvalue;\
830         goto yynewstate;\
831 }
832 #define YYRECOVERING()  (!!yyerrflag)
833 #define YYNEW(type)     malloc(sizeof(type) * yynewmax)
834 #define YYCOPY(to, from, type) \
835         (type *) memcpy(to, (char *) from, yymaxdepth * sizeof (type))
836 #define YYENLARGE( from, type) \
837         (type *) realloc((char *) from, yynewmax * sizeof(type))
838 #ifndef YYDEBUG
839 #       define YYDEBUG  1       /* make debugging available */
840 #endif
841
842 /*
843 ** user known globals
844 */
845 int yydebug;                    /* set to 1 to get debugging */
846
847 /*
848 ** driver internal defines
849 */
850 #define YYFLAG          (-10000000)
851
852 /*
853 ** global variables used by the parser
854 */
855 YYSTYPE *yypv;                  /* top of value stack */
856 int *yyps;                      /* top of state stack */
857
858 int yystate;                    /* current state */
859 int yytmp;                      /* extra var (lasts between blocks) */
860
861 int yynerrs;                    /* number of errors */
862 int yyerrflag;                  /* error recovery flag */
863 int yychar;                     /* current input token number */
864
865
866
867 #ifdef YYNMBCHARS
868 #define YYLEX()         yycvtok(yylex())
869 /*
870 ** yycvtok - return a token if i is a wchar_t value that exceeds 255.
871 **      If i<255, i itself is the token.  If i>255 but the neither 
872 **      of the 30th or 31st bit is on, i is already a token.
873 */
874 #if defined(__STDC__) || defined(__cplusplus)
875 int yycvtok(int i)
876 #else
877 int yycvtok(i) int i;
878 #endif
879 {
880         int first = 0;
881         int last = YYNMBCHARS - 1;
882         int mid;
883         wchar_t j;
884
885         if(i&0x60000000){/*Must convert to a token. */
886                 if( yymbchars[last].character < i ){
887                         return i;/*Giving up*/
888                 }
889                 while ((last>=first)&&(first>=0)) {/*Binary search loop*/
890                         mid = (first+last)/2;
891                         j = yymbchars[mid].character;
892                         if( j==i ){/*Found*/ 
893                                 return yymbchars[mid].tvalue;
894                         }else if( j<i ){
895                                 first = mid + 1;
896                         }else{
897                                 last = mid -1;
898                         }
899                 }
900                 /*No entry in the table.*/
901                 return i;/* Giving up.*/
902         }else{/* i is already a token. */
903                 return i;
904         }
905 }
906 #else/*!YYNMBCHARS*/
907 #define YYLEX()         yylex()
908 #endif/*!YYNMBCHARS*/
909
910 /*
911 ** yyparse - return 0 if worked, 1 if syntax error not recovered from
912 */
913 #if defined(__STDC__) || defined(__cplusplus)
914 int yyparse(void)
915 #else
916 int yyparse()
917 #endif
918 {
919         register YYSTYPE *yypvt = 0;    /* top of value stack for $vars */
920
921 #if defined(__cplusplus) || defined(lint)
922 /*
923         hacks to please C++ and lint - goto's inside
924         switch should never be executed
925 */
926         static int __yaccpar_lint_hack__ = 0;
927         switch (__yaccpar_lint_hack__)
928         {
929                 case 1: goto yyerrlab;
930                 case 2: goto yynewstate;
931         }
932 #endif
933
934         /*
935         ** Initialize externals - yyparse may be called more than once
936         */
937         yypv = &yyv[-1];
938         yyps = &yys[-1];
939         yystate = 0;
940         yytmp = 0;
941         yynerrs = 0;
942         yyerrflag = 0;
943         yychar = -1;
944
945 #if YYMAXDEPTH <= 0
946         if (yymaxdepth <= 0)
947         {
948                 if ((yymaxdepth = YYEXPAND(0)) <= 0)
949                 {
950                         yyerror("yacc initialization error");
951                         YYABORT;
952                 }
953         }
954 #endif
955
956         {
957                 register YYSTYPE *yy_pv;        /* top of value stack */
958                 register int *yy_ps;            /* top of state stack */
959                 register int yy_state;          /* current state */
960                 register int  yy_n;             /* internal state number info */
961         goto yystack;   /* moved from 6 lines above to here to please C++ */
962
963                 /*
964                 ** get globals into registers.
965                 ** branch to here only if YYBACKUP was called.
966                 */
967         yynewstate:
968                 yy_pv = yypv;
969                 yy_ps = yyps;
970                 yy_state = yystate;
971                 goto yy_newstate;
972
973                 /*
974                 ** get globals into registers.
975                 ** either we just started, or we just finished a reduction
976                 */
977         yystack:
978                 yy_pv = yypv;
979                 yy_ps = yyps;
980                 yy_state = yystate;
981
982                 /*
983                 ** top of for (;;) loop while no reductions done
984                 */
985         yy_stack:
986                 /*
987                 ** put a state and value onto the stacks
988                 */
989 #if YYDEBUG
990                 /*
991                 ** if debugging, look up token value in list of value vs.
992                 ** name pairs.  0 and negative (-1) are special values.
993                 ** Note: linear search is used since time is not a real
994                 ** consideration while debugging.
995                 */
996                 if ( yydebug )
997                 {
998                         register int yy_i;
999
1000                         printf( "State %d, token ", yy_state );
1001                         if ( yychar == 0 )
1002                                 printf( "end-of-file\n" );
1003                         else if ( yychar < 0 )
1004                                 printf( "-none-\n" );
1005                         else
1006                         {
1007                                 for ( yy_i = 0; yytoks[yy_i].t_val >= 0;
1008                                         yy_i++ )
1009                                 {
1010                                         if ( yytoks[yy_i].t_val == yychar )
1011                                                 break;
1012                                 }
1013                                 printf( "%s\n", yytoks[yy_i].t_name );
1014                         }
1015                 }
1016 #endif /* YYDEBUG */
1017                 if ( ++yy_ps >= &yys[ yymaxdepth ] )    /* room on stack? */
1018                 {
1019                         /*
1020                         ** reallocate and recover.  Note that pointers
1021                         ** have to be reset, or bad things will happen
1022                         */
1023                         long yyps_index = (yy_ps - yys);
1024                         long yypv_index = (yy_pv - yyv);
1025                         long yypvt_index = (yypvt - yyv);
1026                         int yynewmax;
1027 #ifdef YYEXPAND
1028                         yynewmax = YYEXPAND(yymaxdepth);
1029 #else
1030                         yynewmax = 2 * yymaxdepth;      /* double table size */
1031                         if (yymaxdepth == YYMAXDEPTH)   /* first time growth */
1032                         {
1033                                 char *newyys = (char *)YYNEW(int);
1034                                 char *newyyv = (char *)YYNEW(YYSTYPE);
1035                                 if (newyys != 0 && newyyv != 0)
1036                                 {
1037                                         yys = YYCOPY(newyys, yys, int);
1038                                         yyv = YYCOPY(newyyv, yyv, YYSTYPE);
1039                                 }
1040                                 else
1041                                         yynewmax = 0;   /* failed */
1042                         }
1043                         else                            /* not first time */
1044                         {
1045                                 yys = YYENLARGE(yys, int);
1046                                 yyv = YYENLARGE(yyv, YYSTYPE);
1047                                 if (yys == 0 || yyv == 0)
1048                                         yynewmax = 0;   /* failed */
1049                         }
1050 #endif
1051                         if (yynewmax <= yymaxdepth)     /* tables not expanded */
1052                         {
1053                                 yyerror( "yacc stack overflow" );
1054                                 YYABORT;
1055                         }
1056                         yymaxdepth = yynewmax;
1057
1058                         yy_ps = yys + yyps_index;
1059                         yy_pv = yyv + yypv_index;
1060                         yypvt = yyv + yypvt_index;
1061                 }
1062                 *yy_ps = yy_state;
1063                 *++yy_pv = yyval;
1064
1065                 /*
1066                 ** we have a new state - find out what to do
1067                 */
1068         yy_newstate:
1069                 if ( ( yy_n = yypact[ yy_state ] ) <= YYFLAG )
1070                         goto yydefault;         /* simple state */
1071 #if YYDEBUG
1072                 /*
1073                 ** if debugging, need to mark whether new token grabbed
1074                 */
1075                 yytmp = yychar < 0;
1076 #endif
1077                 if ( ( yychar < 0 ) && ( ( yychar = YYLEX() ) < 0 ) )
1078                         yychar = 0;             /* reached EOF */
1079 #if YYDEBUG
1080                 if ( yydebug && yytmp )
1081                 {
1082                         register int yy_i;
1083
1084                         printf( "Received token " );
1085                         if ( yychar == 0 )
1086                                 printf( "end-of-file\n" );
1087                         else if ( yychar < 0 )
1088                                 printf( "-none-\n" );
1089                         else
1090                         {
1091                                 for ( yy_i = 0; yytoks[yy_i].t_val >= 0;
1092                                         yy_i++ )
1093                                 {
1094                                         if ( yytoks[yy_i].t_val == yychar )
1095                                                 break;
1096                                 }
1097                                 printf( "%s\n", yytoks[yy_i].t_name );
1098                         }
1099                 }
1100 #endif /* YYDEBUG */
1101                 if ( ( ( yy_n += yychar ) < 0 ) || ( yy_n >= YYLAST ) )
1102                         goto yydefault;
1103                 if ( yychk[ yy_n = yyact[ yy_n ] ] == yychar )  /*valid shift*/
1104                 {
1105                         yychar = -1;
1106                         yyval = yylval;
1107                         yy_state = yy_n;
1108                         if ( yyerrflag > 0 )
1109                                 yyerrflag--;
1110                         goto yy_stack;
1111                 }
1112
1113         yydefault:
1114                 if ( ( yy_n = yydef[ yy_state ] ) == -2 )
1115                 {
1116 #if YYDEBUG
1117                         yytmp = yychar < 0;
1118 #endif
1119                         if ( ( yychar < 0 ) && ( ( yychar = YYLEX() ) < 0 ) )
1120                                 yychar = 0;             /* reached EOF */
1121 #if YYDEBUG
1122                         if ( yydebug && yytmp )
1123                         {
1124                                 register int yy_i;
1125
1126                                 printf( "Received token " );
1127                                 if ( yychar == 0 )
1128                                         printf( "end-of-file\n" );
1129                                 else if ( yychar < 0 )
1130                                         printf( "-none-\n" );
1131                                 else
1132                                 {
1133                                         for ( yy_i = 0;
1134                                                 yytoks[yy_i].t_val >= 0;
1135                                                 yy_i++ )
1136                                         {
1137                                                 if ( yytoks[yy_i].t_val
1138                                                         == yychar )
1139                                                 {
1140                                                         break;
1141                                                 }
1142                                         }
1143                                         printf( "%s\n", yytoks[yy_i].t_name );
1144                                 }
1145                         }
1146 #endif /* YYDEBUG */
1147                         /*
1148                         ** look through exception table
1149                         */
1150                         {
1151                                 register const int *yyxi = yyexca;
1152
1153                                 while ( ( *yyxi != -1 ) ||
1154                                         ( yyxi[1] != yy_state ) )
1155                                 {
1156                                         yyxi += 2;
1157                                 }
1158                                 while ( ( *(yyxi += 2) >= 0 ) &&
1159                                         ( *yyxi != yychar ) )
1160                                         ;
1161                                 if ( ( yy_n = yyxi[1] ) < 0 )
1162                                         YYACCEPT;
1163                         }
1164                 }
1165
1166                 /*
1167                 ** check for syntax error
1168                 */
1169                 if ( yy_n == 0 )        /* have an error */
1170                 {
1171                         /* no worry about speed here! */
1172                         switch ( yyerrflag )
1173                         {
1174                         case 0:         /* new error */
1175                                 yyerror( "syntax error" );
1176                                 goto skip_init;
1177                         yyerrlab:
1178                                 /*
1179                                 ** get globals into registers.
1180                                 ** we have a user generated syntax type error
1181                                 */
1182                                 yy_pv = yypv;
1183                                 yy_ps = yyps;
1184                                 yy_state = yystate;
1185                         skip_init:
1186                                 yynerrs++;
1187                                 /* FALLTHRU */
1188                         case 1:
1189                         case 2:         /* incompletely recovered error */
1190                                         /* try again... */
1191                                 yyerrflag = 3;
1192                                 /*
1193                                 ** find state where "error" is a legal
1194                                 ** shift action
1195                                 */
1196                                 while ( yy_ps >= yys )
1197                                 {
1198                                         yy_n = yypact[ *yy_ps ] + YYERRCODE;
1199                                         if ( yy_n >= 0 && yy_n < YYLAST &&
1200                                                 yychk[yyact[yy_n]] == YYERRCODE)                                        {
1201                                                 /*
1202                                                 ** simulate shift of "error"
1203                                                 */
1204                                                 yy_state = yyact[ yy_n ];
1205                                                 goto yy_stack;
1206                                         }
1207                                         /*
1208                                         ** current state has no shift on
1209                                         ** "error", pop stack
1210                                         */
1211 #if YYDEBUG
1212 #       define _POP_ "Error recovery pops state %d, uncovers state %d\n"
1213                                         if ( yydebug )
1214                                                 printf( _POP_, *yy_ps,
1215                                                         yy_ps[-1] );
1216 #       undef _POP_
1217 #endif
1218                                         yy_ps--;
1219                                         yy_pv--;
1220                                 }
1221                                 /*
1222                                 ** there is no state on stack with "error" as
1223                                 ** a valid shift.  give up.
1224                                 */
1225                                 YYABORT;
1226                         case 3:         /* no shift yet; eat a token */
1227 #if YYDEBUG
1228                                 /*
1229                                 ** if debugging, look up token in list of
1230                                 ** pairs.  0 and negative shouldn't occur,
1231                                 ** but since timing doesn't matter when
1232                                 ** debugging, it doesn't hurt to leave the
1233                                 ** tests here.
1234                                 */
1235                                 if ( yydebug )
1236                                 {
1237                                         register int yy_i;
1238
1239                                         printf( "Error recovery discards " );
1240                                         if ( yychar == 0 )
1241                                                 printf( "token end-of-file\n" );
1242                                         else if ( yychar < 0 )
1243                                                 printf( "token -none-\n" );
1244                                         else
1245                                         {
1246                                                 for ( yy_i = 0;
1247                                                         yytoks[yy_i].t_val >= 0;
1248                                                         yy_i++ )
1249                                                 {
1250                                                         if ( yytoks[yy_i].t_val
1251                                                                 == yychar )
1252                                                         {
1253                                                                 break;
1254                                                         }
1255                                                 }
1256                                                 printf( "token %s\n",
1257                                                         yytoks[yy_i].t_name );
1258                                         }
1259                                 }
1260 #endif /* YYDEBUG */
1261                                 if ( yychar == 0 )      /* reached EOF. quit */
1262                                         YYABORT;
1263                                 yychar = -1;
1264                                 goto yy_newstate;
1265                         }
1266                 }/* end if ( yy_n == 0 ) */
1267                 /*
1268                 ** reduction by production yy_n
1269                 ** put stack tops, etc. so things right after switch
1270                 */
1271 #if YYDEBUG
1272                 /*
1273                 ** if debugging, print the string that is the user's
1274                 ** specification of the reduction which is just about
1275                 ** to be done.
1276                 */
1277                 if ( yydebug )
1278                         printf( "Reduce by (%d) \"%s\"\n",
1279                                 yy_n, yyreds[ yy_n ] );
1280 #endif
1281                 yytmp = yy_n;                   /* value to switch over */
1282                 yypvt = yy_pv;                  /* $vars top of value stack */
1283                 /*
1284                 ** Look in goto table for next state
1285                 ** Sorry about using yy_state here as temporary
1286                 ** register variable, but why not, if it works...
1287                 ** If yyr2[ yy_n ] doesn't have the low order bit
1288                 ** set, then there is no action to be done for
1289                 ** this reduction.  So, no saving & unsaving of
1290                 ** registers done.  The only difference between the
1291                 ** code just after the if and the body of the if is
1292                 ** the goto yy_stack in the body.  This way the test
1293                 ** can be made before the choice of what to do is needed.
1294                 */
1295                 {
1296                         /* length of production doubled with extra bit */
1297                         register int yy_len = yyr2[ yy_n ];
1298
1299                         if ( !( yy_len & 01 ) )
1300                         {
1301                                 yy_len >>= 1;
1302                                 yyval = ( yy_pv -= yy_len )[1]; /* $$ = $1 */
1303                                 yy_state = yypgo[ yy_n = yyr1[ yy_n ] ] +
1304                                         *( yy_ps -= yy_len ) + 1;
1305                                 if ( yy_state >= YYLAST ||
1306                                         yychk[ yy_state =
1307                                         yyact[ yy_state ] ] != -yy_n )
1308                                 {
1309                                         yy_state = yyact[ yypgo[ yy_n ] ];
1310                                 }
1311                                 goto yy_stack;
1312                         }
1313                         yy_len >>= 1;
1314                         yyval = ( yy_pv -= yy_len )[1]; /* $$ = $1 */
1315                         yy_state = yypgo[ yy_n = yyr1[ yy_n ] ] +
1316                                 *( yy_ps -= yy_len ) + 1;
1317                         if ( yy_state >= YYLAST ||
1318                                 yychk[ yy_state = yyact[ yy_state ] ] != -yy_n )
1319                         {
1320                                 yy_state = yyact[ yypgo[ yy_n ] ];
1321                         }
1322                 }
1323                                         /* save until reenter driver code */
1324                 yystate = yy_state;
1325                 yyps = yy_ps;
1326                 yypv = yy_pv;
1327         }
1328         /*
1329         ** code supplied by user is placed in this switch
1330         */
1331         switch( yytmp )
1332         {
1333                 
1334 case 3:
1335 # line 118 "parsedate.y"
1336 {
1337             yyHaveTime++;
1338 #ifdef lint
1339             /* I am compulsive about lint natterings... */
1340             if (yyHaveTime == -1) {
1341                 YYERROR;
1342             }
1343 #endif /* lint */
1344         } break;
1345 case 4:
1346 # line 127 "parsedate.y"
1347 {
1348             yyHaveTime++;
1349             yyTimezone = yypvt[-0].Number;
1350         } break;
1351 case 5:
1352 # line 131 "parsedate.y"
1353 {
1354             yyHaveDate++;
1355         } break;
1356 case 6:
1357 # line 134 "parsedate.y"
1358 {
1359             yyHaveRel = 1;
1360         } break;
1361 case 7:
1362 # line 139 "parsedate.y"
1363 {
1364             if (yypvt[-1].Number < 100) {
1365                 yyHour = yypvt[-1].Number;
1366                 yyMinutes = 0;
1367             }
1368             else {
1369                 yyHour = yypvt[-1].Number / 100;
1370                 yyMinutes = yypvt[-1].Number % 100;
1371             }
1372             yySeconds = 0;
1373             yyMeridian = yypvt[-0].Meridian;
1374         } break;
1375 case 8:
1376 # line 151 "parsedate.y"
1377 {
1378             yyHour = yypvt[-3].Number;
1379             yyMinutes = yypvt[-1].Number;
1380             yySeconds = 0;
1381             yyMeridian = yypvt[-0].Meridian;
1382         } break;
1383 case 9:
1384 # line 157 "parsedate.y"
1385 {
1386             yyHour = yypvt[-3].Number;
1387             yyMinutes = yypvt[-1].Number;
1388             yyTimezone = yypvt[-0].Number;
1389             yyMeridian = MER24;
1390             yyDSTmode = DSToff;
1391         } break;
1392 case 10:
1393 # line 164 "parsedate.y"
1394 {
1395             yyHour = yypvt[-5].Number;
1396             yyMinutes = yypvt[-3].Number;
1397             yySeconds = yypvt[-1].Number;
1398             yyMeridian = yypvt[-0].Meridian;
1399         } break;
1400 case 11:
1401 # line 170 "parsedate.y"
1402 {
1403             yyHour = yypvt[-5].Number;
1404             yyMinutes = yypvt[-3].Number;
1405             yySeconds = yypvt[-1].Number;
1406             yyTimezone = yypvt[-0].Number;
1407             yyMeridian = MER24;
1408             yyDSTmode = DSToff;
1409         } break;
1410 case 12:
1411 # line 180 "parsedate.y"
1412 {
1413             yyval.Number = yypvt[-0].Number;
1414             yyDSTmode = DSToff;
1415         } break;
1416 case 13:
1417 # line 184 "parsedate.y"
1418 {
1419             yyval.Number = yypvt[-0].Number;
1420             yyDSTmode = DSTon;
1421         } break;
1422 case 14:
1423 # line 188 "parsedate.y"
1424 {
1425             /* Only allow "GMT+300" and "GMT-0800" */
1426             if (yypvt[-1].Number != 0) {
1427                 YYABORT;
1428             }
1429             yyval.Number = yypvt[-0].Number;
1430             yyDSTmode = DSToff;
1431         } break;
1432 case 15:
1433 # line 196 "parsedate.y"
1434 {
1435             yyval.Number = yypvt[-0].Number;
1436             yyDSTmode = DSToff;
1437         } break;
1438 case 16:
1439 # line 202 "parsedate.y"
1440 {
1441             int         i;
1442
1443             /* Unix and GMT and numeric timezones -- a little confusing. */
1444             if (yypvt[-0].Number < 0) {
1445                 /* Don't work with negative modulus. */
1446                 yypvt[-0].Number = -yypvt[-0].Number;
1447                 if (yypvt[-0].Number > 9999 || (i = yypvt[-0].Number % 100) >= 60) {
1448                     YYABORT;
1449                 }
1450                 yyval.Number = (yypvt[-0].Number / 100) * 60 + i;
1451             }
1452             else {
1453                 if (yypvt[-0].Number > 9999 || (i = yypvt[-0].Number % 100) >= 60) {
1454                     YYABORT;
1455                 }
1456                 yyval.Number = -((yypvt[-0].Number / 100) * 60 + i);
1457             }
1458         } break;
1459 case 17:
1460 # line 223 "parsedate.y"
1461 {
1462             yyMonth = yypvt[-2].Number;
1463             yyDay = yypvt[-0].Number;
1464         } break;
1465 case 18:
1466 # line 227 "parsedate.y"
1467 {
1468             if (yypvt[-4].Number > 100) {
1469                 yyYear = yypvt[-4].Number;
1470                 yyMonth = yypvt[-2].Number;
1471                 yyDay = yypvt[-0].Number;
1472             }
1473             else {
1474                 yyMonth = yypvt[-4].Number;
1475                 yyDay = yypvt[-2].Number;
1476                 yyYear = yypvt[-0].Number;
1477             }
1478         } break;
1479 case 19:
1480 # line 239 "parsedate.y"
1481 {
1482             yyMonth = yypvt[-1].Number;
1483             yyDay = yypvt[-0].Number;
1484         } break;
1485 case 20:
1486 # line 243 "parsedate.y"
1487 {
1488             yyMonth = yypvt[-3].Number;
1489             yyDay = yypvt[-2].Number;
1490             yyYear = yypvt[-0].Number;
1491         } break;
1492 case 21:
1493 # line 248 "parsedate.y"
1494 {
1495             yyDay = yypvt[-1].Number;
1496             yyMonth = yypvt[-0].Number;
1497         } break;
1498 case 22:
1499 # line 252 "parsedate.y"
1500 {
1501             yyDay = yypvt[-2].Number;
1502             yyMonth = yypvt[-1].Number;
1503             yyYear = yypvt[-0].Number;
1504         } break;
1505 case 23:
1506 # line 257 "parsedate.y"
1507 {
1508             yyDay = yypvt[-2].Number;
1509             yyMonth = yypvt[-1].Number;
1510             yyYear = yypvt[-0].Number;
1511         } break;
1512 case 24:
1513 # line 264 "parsedate.y"
1514 {
1515             yyRelSeconds += yypvt[-1].Number * yypvt[-0].Number;
1516         } break;
1517 case 25:
1518 # line 267 "parsedate.y"
1519 {
1520             yyRelSeconds += yypvt[-1].Number * yypvt[-0].Number;
1521         } break;
1522 case 26:
1523 # line 270 "parsedate.y"
1524 {
1525             yyRelMonth += yypvt[-1].Number * yypvt[-0].Number;
1526         } break;
1527 case 27:
1528 # line 273 "parsedate.y"
1529 {
1530             yyRelMonth += yypvt[-1].Number * yypvt[-0].Number;
1531         } break;
1532 case 28:
1533 # line 278 "parsedate.y"
1534 {
1535             yyval.Meridian = MER24;
1536         } break;
1537 case 29:
1538 # line 281 "parsedate.y"
1539 {
1540             yyval.Meridian = yypvt[-0].Meridian;
1541         } break;
1542 # line  531 "/usr/ccs/bin/yaccpar"
1543         }
1544         goto yystack;           /* reset registers in driver code */
1545 }
1546