Add GNU LGPL headers to all .c .C and .h files
[oweals/cde.git] / cde / programs / dtdocbook / tcl / tclDate.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /* $XConsortium: tclDate.c /main/2 1996/08/08 14:43:30 cde-hp $ */
24 /* 
25  * tclGetdate.c --
26  *
27  *      This file is generated from a yacc grammar defined in
28  *      the file tclGetdate.y
29  *
30  * Copyright (c) 1992-1995 Karl Lehenbauer and Mark Diekhans.
31  * Copyright (c) 1995-1996 Sun Microsystems, Inc.
32  *
33  * See the file "license.terms" for information on usage and redistribution
34  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
35  *
36  * @(#) tclDate.c 1.24 96/04/18 16:53:56
37  */
38
39 #include "tclInt.h"
40 #include "tclPort.h"
41
42 #ifdef MAC_TCL
43 #   define EPOCH           1904
44 #   define START_OF_TIME   1904
45 #   define END_OF_TIME     2039
46 #else
47 #   define EPOCH           1970
48 #   define START_OF_TIME   1902
49 #   define END_OF_TIME     2037
50
51 extern struct tm  *localtime();
52 #endif
53
54 #define HOUR(x)         ((int) (60 * x))
55 #define SECSPERDAY      (24L * 60L * 60L)
56
57
58 /*
59  *  An entry in the lexical lookup table.
60  */
61 typedef struct _TABLE {
62     char        *name;
63     int         type;
64     time_t      value;
65 } TABLE;
66
67
68 /*
69  *  Daylight-savings mode:  on, off, or not yet known.
70  */
71 typedef enum _DSTMODE {
72     DSTon, DSToff, DSTmaybe
73 } DSTMODE;
74
75 /*
76  *  Meridian:  am, pm, or 24-hour style.
77  */
78 typedef enum _MERIDIAN {
79     MERam, MERpm, MER24
80 } MERIDIAN;
81
82
83 /*
84  *  Global variables.  We could get rid of most of these by using a good
85  *  union as the yacc stack.  (This routine was originally written before
86  *  yacc had the %union construct.)  Maybe someday; right now we only use
87  *  the %union very rarely.
88  */
89 static char     *TclDateInput;
90 static DSTMODE  TclDateDSTmode;
91 static time_t   TclDateDayOrdinal;
92 static time_t   TclDateDayNumber;
93 static int      TclDateHaveDate;
94 static int      TclDateHaveDay;
95 static int      TclDateHaveRel;
96 static int      TclDateHaveTime;
97 static int      TclDateHaveZone;
98 static time_t   TclDateTimezone;
99 static time_t   TclDateDay;
100 static time_t   TclDateHour;
101 static time_t   TclDateMinutes;
102 static time_t   TclDateMonth;
103 static time_t   TclDateSeconds;
104 static time_t   TclDateYear;
105 static MERIDIAN TclDateMeridian;
106 static time_t   TclDateRelMonth;
107 static time_t   TclDateRelSeconds;
108
109
110 /*
111  * Prototypes of internal functions.
112  */
113 static void
114 TclDateerror _ANSI_ARGS_((char *s));
115
116 static time_t
117 ToSeconds _ANSI_ARGS_((time_t      Hours,
118                        time_t      Minutes,
119                        time_t      Seconds,
120                        MERIDIAN    Meridian));
121
122 static int
123 Convert _ANSI_ARGS_((time_t      Month,
124                      time_t      Day,
125                      time_t      Year,
126                      time_t      Hours,
127                      time_t      Minutes,
128                      time_t      Seconds,
129                      MERIDIAN    Meridia,
130                      DSTMODE     DSTmode,
131                      time_t     *TimePtr));
132
133 static time_t
134 DSTcorrect _ANSI_ARGS_((time_t      Start,
135                         time_t      Future));
136
137 static time_t
138 RelativeDate _ANSI_ARGS_((time_t      Start,
139                           time_t      DayOrdinal,
140                           time_t      DayNumber));
141
142 static int
143 RelativeMonth _ANSI_ARGS_((time_t      Start,
144                            time_t      RelMonth,
145                            time_t     *TimePtr));
146 static int
147 LookupWord _ANSI_ARGS_((char  *buff));
148
149 static int
150 TclDatelex _ANSI_ARGS_((void));
151
152 int
153 TclDateparse _ANSI_ARGS_((void));
154 typedef union
155 #ifdef __cplusplus
156         YYSTYPE
157 #endif
158  {
159     time_t              Number;
160     enum _MERIDIAN      Meridian;
161 } YYSTYPE;
162 # define tAGO 257
163 # define tDAY 258
164 # define tDAYZONE 259
165 # define tID 260
166 # define tMERIDIAN 261
167 # define tMINUTE_UNIT 262
168 # define tMONTH 263
169 # define tMONTH_UNIT 264
170 # define tSEC_UNIT 265
171 # define tSNUMBER 266
172 # define tUNUMBER 267
173 # define tZONE 268
174 # define tEPOCH 269
175 # define tDST 270
176
177
178
179 #ifdef __cplusplus
180
181 #ifndef TclDateerror
182         void TclDateerror(const char *);
183 #endif
184
185 #ifndef TclDatelex
186 #ifdef __EXTERN_C__
187         extern "C" { int TclDatelex(void); }
188 #else
189         int TclDatelex(void);
190 #endif
191 #endif
192         int TclDateparse(void);
193
194 #endif
195 #define TclDateclearin TclDatechar = -1
196 #define TclDateerrok TclDateerrflag = 0
197 extern int TclDatechar;
198 extern int TclDateerrflag;
199 YYSTYPE TclDatelval;
200 YYSTYPE TclDateval;
201 typedef int TclDatetabelem;
202 #ifndef YYMAXDEPTH
203 #define YYMAXDEPTH 150
204 #endif
205 #if YYMAXDEPTH > 0
206 int TclDate_TclDates[YYMAXDEPTH], *TclDates = TclDate_TclDates;
207 YYSTYPE TclDate_TclDatev[YYMAXDEPTH], *TclDatev = TclDate_TclDatev;
208 #else   /* user does initial allocation */
209 int *TclDates;
210 YYSTYPE *TclDatev;
211 #endif
212 static int TclDatemaxdepth = YYMAXDEPTH;
213 # define YYERRCODE 256
214
215
216 /*
217  * Month and day table.
218  */
219 static TABLE    MonthDayTable[] = {
220     { "january",        tMONTH,  1 },
221     { "february",       tMONTH,  2 },
222     { "march",          tMONTH,  3 },
223     { "april",          tMONTH,  4 },
224     { "may",            tMONTH,  5 },
225     { "june",           tMONTH,  6 },
226     { "july",           tMONTH,  7 },
227     { "august",         tMONTH,  8 },
228     { "september",      tMONTH,  9 },
229     { "sept",           tMONTH,  9 },
230     { "october",        tMONTH, 10 },
231     { "november",       tMONTH, 11 },
232     { "december",       tMONTH, 12 },
233     { "sunday",         tDAY, 0 },
234     { "monday",         tDAY, 1 },
235     { "tuesday",        tDAY, 2 },
236     { "tues",           tDAY, 2 },
237     { "wednesday",      tDAY, 3 },
238     { "wednes",         tDAY, 3 },
239     { "thursday",       tDAY, 4 },
240     { "thur",           tDAY, 4 },
241     { "thurs",          tDAY, 4 },
242     { "friday",         tDAY, 5 },
243     { "saturday",       tDAY, 6 },
244     { NULL }
245 };
246
247 /*
248  * Time units table.
249  */
250 static TABLE    UnitsTable[] = {
251     { "year",           tMONTH_UNIT,    12 },
252     { "month",          tMONTH_UNIT,    1 },
253     { "fortnight",      tMINUTE_UNIT,   14 * 24 * 60 },
254     { "week",           tMINUTE_UNIT,   7 * 24 * 60 },
255     { "day",            tMINUTE_UNIT,   1 * 24 * 60 },
256     { "hour",           tMINUTE_UNIT,   60 },
257     { "minute",         tMINUTE_UNIT,   1 },
258     { "min",            tMINUTE_UNIT,   1 },
259     { "second",         tSEC_UNIT,      1 },
260     { "sec",            tSEC_UNIT,      1 },
261     { NULL }
262 };
263
264 /*
265  * Assorted relative-time words.
266  */
267 static TABLE    OtherTable[] = {
268     { "tomorrow",       tMINUTE_UNIT,   1 * 24 * 60 },
269     { "yesterday",      tMINUTE_UNIT,   -1 * 24 * 60 },
270     { "today",          tMINUTE_UNIT,   0 },
271     { "now",            tMINUTE_UNIT,   0 },
272     { "last",           tUNUMBER,       -1 },
273     { "this",           tMINUTE_UNIT,   0 },
274     { "next",           tUNUMBER,       2 },
275 #if 0
276     { "first",          tUNUMBER,       1 },
277 /*  { "second",         tUNUMBER,       2 }, */
278     { "third",          tUNUMBER,       3 },
279     { "fourth",         tUNUMBER,       4 },
280     { "fifth",          tUNUMBER,       5 },
281     { "sixth",          tUNUMBER,       6 },
282     { "seventh",        tUNUMBER,       7 },
283     { "eighth",         tUNUMBER,       8 },
284     { "ninth",          tUNUMBER,       9 },
285     { "tenth",          tUNUMBER,       10 },
286     { "eleventh",       tUNUMBER,       11 },
287     { "twelfth",        tUNUMBER,       12 },
288 #endif
289     { "ago",            tAGO,   1 },
290     { "epoch",          tEPOCH,   0 },
291     { NULL }
292 };
293
294 /*
295  * The timezone table.  (Note: This table was modified to not use any floating
296  * point constants to work around an SGI compiler bug).
297  */
298 static TABLE    TimezoneTable[] = {
299     { "gmt",    tZONE,     HOUR( 0) },      /* Greenwich Mean */
300     { "ut",     tZONE,     HOUR( 0) },      /* Universal (Coordinated) */
301     { "utc",    tZONE,     HOUR( 0) },
302     { "wet",    tZONE,     HOUR( 0) } ,     /* Western European */
303     { "bst",    tDAYZONE,  HOUR( 0) },      /* British Summer */
304     { "wat",    tZONE,     HOUR( 1) },      /* West Africa */
305     { "at",     tZONE,     HOUR( 2) },      /* Azores */
306 #if     0
307     /* For completeness.  BST is also British Summer, and GST is
308      * also Guam Standard. */
309     { "bst",    tZONE,     HOUR( 3) },      /* Brazil Standard */
310     { "gst",    tZONE,     HOUR( 3) },      /* Greenland Standard */
311 #endif
312     { "nft",    tZONE,     HOUR( 7/2) },    /* Newfoundland */
313     { "nst",    tZONE,     HOUR( 7/2) },    /* Newfoundland Standard */
314     { "ndt",    tDAYZONE,  HOUR( 7/2) },    /* Newfoundland Daylight */
315     { "ast",    tZONE,     HOUR( 4) },      /* Atlantic Standard */
316     { "adt",    tDAYZONE,  HOUR( 4) },      /* Atlantic Daylight */
317     { "est",    tZONE,     HOUR( 5) },      /* Eastern Standard */
318     { "edt",    tDAYZONE,  HOUR( 5) },      /* Eastern Daylight */
319     { "cst",    tZONE,     HOUR( 6) },      /* Central Standard */
320     { "cdt",    tDAYZONE,  HOUR( 6) },      /* Central Daylight */
321     { "mst",    tZONE,     HOUR( 7) },      /* Mountain Standard */
322     { "mdt",    tDAYZONE,  HOUR( 7) },      /* Mountain Daylight */
323     { "pst",    tZONE,     HOUR( 8) },      /* Pacific Standard */
324     { "pdt",    tDAYZONE,  HOUR( 8) },      /* Pacific Daylight */
325     { "yst",    tZONE,     HOUR( 9) },      /* Yukon Standard */
326     { "ydt",    tDAYZONE,  HOUR( 9) },      /* Yukon Daylight */
327     { "hst",    tZONE,     HOUR(10) },      /* Hawaii Standard */
328     { "hdt",    tDAYZONE,  HOUR(10) },      /* Hawaii Daylight */
329     { "cat",    tZONE,     HOUR(10) },      /* Central Alaska */
330     { "ahst",   tZONE,     HOUR(10) },      /* Alaska-Hawaii Standard */
331     { "nt",     tZONE,     HOUR(11) },      /* Nome */
332     { "idlw",   tZONE,     HOUR(12) },      /* International Date Line West */
333     { "cet",    tZONE,    -HOUR( 1) },      /* Central European */
334     { "met",    tZONE,    -HOUR( 1) },      /* Middle European */
335     { "mewt",   tZONE,    -HOUR( 1) },      /* Middle European Winter */
336     { "mest",   tDAYZONE, -HOUR( 1) },      /* Middle European Summer */
337     { "swt",    tZONE,    -HOUR( 1) },      /* Swedish Winter */
338     { "sst",    tDAYZONE, -HOUR( 1) },      /* Swedish Summer */
339     { "fwt",    tZONE,    -HOUR( 1) },      /* French Winter */
340     { "fst",    tDAYZONE, -HOUR( 1) },      /* French Summer */
341     { "eet",    tZONE,    -HOUR( 2) },      /* Eastern Europe, USSR Zone 1 */
342     { "bt",     tZONE,    -HOUR( 3) },      /* Baghdad, USSR Zone 2 */
343     { "it",     tZONE,    -HOUR( 7/2) },    /* Iran */
344     { "zp4",    tZONE,    -HOUR( 4) },      /* USSR Zone 3 */
345     { "zp5",    tZONE,    -HOUR( 5) },      /* USSR Zone 4 */
346     { "ist",    tZONE,    -HOUR(11/2) },    /* Indian Standard */
347     { "zp6",    tZONE,    -HOUR( 6) },      /* USSR Zone 5 */
348 #if     0
349     /* For completeness.  NST is also Newfoundland Stanard, nad SST is
350      * also Swedish Summer. */
351     { "nst",    tZONE,    -HOUR(13/2) },    /* North Sumatra */
352     { "sst",    tZONE,    -HOUR( 7) },      /* South Sumatra, USSR Zone 6 */
353 #endif  /* 0 */
354     { "wast",   tZONE,    -HOUR( 7) },      /* West Australian Standard */
355     { "wadt",   tDAYZONE, -HOUR( 7) },      /* West Australian Daylight */
356     { "jt",     tZONE,    -HOUR(15/2) },    /* Java (3pm in Cronusland!) */
357     { "cct",    tZONE,    -HOUR( 8) },      /* China Coast, USSR Zone 7 */
358     { "jst",    tZONE,    -HOUR( 9) },      /* Japan Standard, USSR Zone 8 */
359     { "cast",   tZONE,    -HOUR(19/2) },    /* Central Australian Standard */
360     { "cadt",   tDAYZONE, -HOUR(19/2) },    /* Central Australian Daylight */
361     { "east",   tZONE,    -HOUR(10) },      /* Eastern Australian Standard */
362     { "eadt",   tDAYZONE, -HOUR(10) },      /* Eastern Australian Daylight */
363     { "gst",    tZONE,    -HOUR(10) },      /* Guam Standard, USSR Zone 9 */
364     { "nzt",    tZONE,    -HOUR(12) },      /* New Zealand */
365     { "nzst",   tZONE,    -HOUR(12) },      /* New Zealand Standard */
366     { "nzdt",   tDAYZONE, -HOUR(12) },      /* New Zealand Daylight */
367     { "idle",   tZONE,    -HOUR(12) },      /* International Date Line East */
368     /* ADDED BY Marco Nijdam */
369     { "dst",    tDST,     HOUR( 0) },       /* DST on (hour is ignored) */
370     /* End ADDED */
371     {  NULL  }
372 };
373
374 /*
375  * Military timezone table.
376  */
377 static TABLE    MilitaryTable[] = {
378     { "a",      tZONE,  HOUR(  1) },
379     { "b",      tZONE,  HOUR(  2) },
380     { "c",      tZONE,  HOUR(  3) },
381     { "d",      tZONE,  HOUR(  4) },
382     { "e",      tZONE,  HOUR(  5) },
383     { "f",      tZONE,  HOUR(  6) },
384     { "g",      tZONE,  HOUR(  7) },
385     { "h",      tZONE,  HOUR(  8) },
386     { "i",      tZONE,  HOUR(  9) },
387     { "k",      tZONE,  HOUR( 10) },
388     { "l",      tZONE,  HOUR( 11) },
389     { "m",      tZONE,  HOUR( 12) },
390     { "n",      tZONE,  HOUR(- 1) },
391     { "o",      tZONE,  HOUR(- 2) },
392     { "p",      tZONE,  HOUR(- 3) },
393     { "q",      tZONE,  HOUR(- 4) },
394     { "r",      tZONE,  HOUR(- 5) },
395     { "s",      tZONE,  HOUR(- 6) },
396     { "t",      tZONE,  HOUR(- 7) },
397     { "u",      tZONE,  HOUR(- 8) },
398     { "v",      tZONE,  HOUR(- 9) },
399     { "w",      tZONE,  HOUR(-10) },
400     { "x",      tZONE,  HOUR(-11) },
401     { "y",      tZONE,  HOUR(-12) },
402     { "z",      tZONE,  HOUR(  0) },
403     { NULL }
404 };
405
406
407 /*
408  * Dump error messages in the bit bucket.
409  */
410 static void
411 TclDateerror(s)
412     char  *s;
413 {
414 }
415
416
417 static time_t
418 ToSeconds(Hours, Minutes, Seconds, Meridian)
419     time_t      Hours;
420     time_t      Minutes;
421     time_t      Seconds;
422     MERIDIAN    Meridian;
423 {
424     if (Minutes < 0 || Minutes > 59 || Seconds < 0 || Seconds > 59)
425         return -1;
426     switch (Meridian) {
427     case MER24:
428         if (Hours < 0 || Hours > 23)
429             return -1;
430         return (Hours * 60L + Minutes) * 60L + Seconds;
431     case MERam:
432         if (Hours < 1 || Hours > 12)
433             return -1;
434         return ((Hours % 12) * 60L + Minutes) * 60L + Seconds;
435     case MERpm:
436         if (Hours < 1 || Hours > 12)
437             return -1;
438         return (((Hours % 12) + 12) * 60L + Minutes) * 60L + Seconds;
439     }
440     return -1;  /* Should never be reached */
441 }
442
443
444 static int
445 Convert(Month, Day, Year, Hours, Minutes, Seconds, Meridian, DSTmode, TimePtr)
446     time_t      Month;
447     time_t      Day;
448     time_t      Year;
449     time_t      Hours;
450     time_t      Minutes;
451     time_t      Seconds;
452     MERIDIAN    Meridian;
453     DSTMODE     DSTmode;
454     time_t     *TimePtr;
455 {
456     static int  DaysInMonth[12] = {
457         31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
458     };
459     time_t      tod;
460     time_t      Julian;
461     int         i;
462
463     if (Year < 0)
464         Year = -Year;
465     if (Year < 100)
466         Year += 1900;
467     DaysInMonth[1] = Year % 4 == 0 && (Year % 100 != 0 || Year % 400 == 0)
468                     ? 29 : 28;
469     if (Month < 1 || Month > 12
470      || Year < START_OF_TIME || Year > END_OF_TIME
471      || Day < 1 || Day > DaysInMonth[(int)--Month])
472         return -1;
473
474     for (Julian = Day - 1, i = 0; i < Month; i++)
475         Julian += DaysInMonth[i];
476     if (Year >= EPOCH) {
477         for (i = EPOCH; i < Year; i++)
478             Julian += 365 + (i % 4 == 0);
479     } else {
480         for (i = Year; i < EPOCH; i++)
481             Julian -= 365 + (i % 4 == 0);
482     }
483     Julian *= SECSPERDAY;
484     Julian += TclDateTimezone * 60L;
485     if ((tod = ToSeconds(Hours, Minutes, Seconds, Meridian)) < 0)
486         return -1;
487     Julian += tod;
488     if (DSTmode == DSTon
489      || (DSTmode == DSTmaybe && localtime(&Julian)->tm_isdst))
490         Julian -= 60 * 60;
491     *TimePtr = Julian;
492     return 0;
493 }
494
495
496 static time_t
497 DSTcorrect(Start, Future)
498     time_t      Start;
499     time_t      Future;
500 {
501     time_t      StartDay;
502     time_t      FutureDay;
503
504     StartDay = (localtime(&Start)->tm_hour + 1) % 24;
505     FutureDay = (localtime(&Future)->tm_hour + 1) % 24;
506     return (Future - Start) + (StartDay - FutureDay) * 60L * 60L;
507 }
508
509
510 static time_t
511 RelativeDate(Start, DayOrdinal, DayNumber)
512     time_t      Start;
513     time_t      DayOrdinal;
514     time_t      DayNumber;
515 {
516     struct tm   *tm;
517     time_t      now;
518
519     now = Start;
520     tm = localtime(&now);
521     now += SECSPERDAY * ((DayNumber - tm->tm_wday + 7) % 7);
522     now += 7 * SECSPERDAY * (DayOrdinal <= 0 ? DayOrdinal : DayOrdinal - 1);
523     return DSTcorrect(Start, now);
524 }
525
526
527 static int
528 RelativeMonth(Start, RelMonth, TimePtr)
529     time_t      Start;
530     time_t      RelMonth;
531     time_t     *TimePtr;
532 {
533     struct tm   *tm;
534     time_t      Month;
535     time_t      Year;
536     time_t      Julian;
537
538     if (RelMonth == 0) {
539         *TimePtr = 0;
540         return 0;
541     }
542     tm = localtime(&Start);
543     Month = 12 * tm->tm_year + tm->tm_mon + RelMonth;
544     Year = Month / 12;
545     Month = Month % 12 + 1;
546     if (Convert(Month, (time_t)tm->tm_mday, Year,
547                 (time_t)tm->tm_hour, (time_t)tm->tm_min, (time_t)tm->tm_sec,
548                 MER24, DSTmaybe, &Julian) < 0)
549         return -1;
550     *TimePtr = DSTcorrect(Start, Julian);
551     return 0;
552 }
553
554
555 static int
556 LookupWord(buff)
557     char                *buff;
558 {
559     register char       *p;
560     register char       *q;
561     register TABLE      *tp;
562     int                 i;
563     int                 abbrev;
564
565     /*
566      * Make it lowercase.
567      */
568     for (p = buff; *p; p++) {
569         if (isupper(*p)) {
570             *p = (char) tolower(*p);
571         }
572     }
573
574     if (strcmp(buff, "am") == 0 || strcmp(buff, "a.m.") == 0) {
575         TclDatelval.Meridian = MERam;
576         return tMERIDIAN;
577     }
578     if (strcmp(buff, "pm") == 0 || strcmp(buff, "p.m.") == 0) {
579         TclDatelval.Meridian = MERpm;
580         return tMERIDIAN;
581     }
582
583     /*
584      * See if we have an abbreviation for a month.
585      */
586     if (strlen(buff) == 3) {
587         abbrev = 1;
588     } else if (strlen(buff) == 4 && buff[3] == '.') {
589         abbrev = 1;
590         buff[3] = '\0';
591     } else {
592         abbrev = 0;
593     }
594
595     for (tp = MonthDayTable; tp->name; tp++) {
596         if (abbrev) {
597             if (strncmp(buff, tp->name, 3) == 0) {
598                 TclDatelval.Number = tp->value;
599                 return tp->type;
600             }
601         } else if (strcmp(buff, tp->name) == 0) {
602             TclDatelval.Number = tp->value;
603             return tp->type;
604         }
605     }
606
607     for (tp = TimezoneTable; tp->name; tp++) {
608         if (strcmp(buff, tp->name) == 0) {
609             TclDatelval.Number = tp->value;
610             return tp->type;
611         }
612     }
613
614     for (tp = UnitsTable; tp->name; tp++) {
615         if (strcmp(buff, tp->name) == 0) {
616             TclDatelval.Number = tp->value;
617             return tp->type;
618         }
619     }
620
621     /*
622      * Strip off any plural and try the units table again.
623      */
624     i = strlen(buff) - 1;
625     if (buff[i] == 's') {
626         buff[i] = '\0';
627         for (tp = UnitsTable; tp->name; tp++) {
628             if (strcmp(buff, tp->name) == 0) {
629                 TclDatelval.Number = tp->value;
630                 return tp->type;
631             }
632         }
633     }
634
635     for (tp = OtherTable; tp->name; tp++) {
636         if (strcmp(buff, tp->name) == 0) {
637             TclDatelval.Number = tp->value;
638             return tp->type;
639         }
640     }
641
642     /*
643      * Military timezones.
644      */
645     if (buff[1] == '\0' && isalpha(*buff)) {
646         for (tp = MilitaryTable; tp->name; tp++) {
647             if (strcmp(buff, tp->name) == 0) {
648                 TclDatelval.Number = tp->value;
649                 return tp->type;
650             }
651         }
652     }
653
654     /*
655      * Drop out any periods and try the timezone table again.
656      */
657     for (i = 0, p = q = buff; *q; q++)
658         if (*q != '.')
659             *p++ = *q;
660         else
661             i++;
662     *p = '\0';
663     if (i)
664         for (tp = TimezoneTable; tp->name; tp++) {
665             if (strcmp(buff, tp->name) == 0) {
666                 TclDatelval.Number = tp->value;
667                 return tp->type;
668             }
669         }
670
671     return tID;
672 }
673
674
675 static int
676 TclDatelex()
677 {
678     register char       c;
679     register char       *p;
680     char                buff[20];
681     int                 Count;
682     int                 sign;
683
684     for ( ; ; ) {
685         while (isspace((unsigned char) (*TclDateInput))) {
686             TclDateInput++;
687         }
688
689         if (isdigit(c = *TclDateInput) || c == '-' || c == '+') {
690             if (c == '-' || c == '+') {
691                 sign = c == '-' ? -1 : 1;
692                 if (!isdigit(*++TclDateInput)) {
693                     /*
694                      * skip the '-' sign
695                      */
696                     continue;
697                 }
698             } else {
699                 sign = 0;
700             }
701             for (TclDatelval.Number = 0; isdigit(c = *TclDateInput++); ) {
702                 TclDatelval.Number = 10 * TclDatelval.Number + c - '0';
703             }
704             TclDateInput--;
705             if (sign < 0) {
706                 TclDatelval.Number = -TclDatelval.Number;
707             }
708             return sign ? tSNUMBER : tUNUMBER;
709         }
710         if (isalpha(c)) {
711             for (p = buff; isalpha(c = *TclDateInput++) || c == '.'; ) {
712                 if (p < &buff[sizeof buff - 1]) {
713                     *p++ = c;
714                 }
715             }
716             *p = '\0';
717             TclDateInput--;
718             return LookupWord(buff);
719         }
720         if (c != '(') {
721             return *TclDateInput++;
722         }
723         Count = 0;
724         do {
725             c = *TclDateInput++;
726             if (c == '\0') {
727                 return c;
728             } else if (c == '(') {
729                 Count++;
730             } else if (c == ')') {
731                 Count--;
732             }
733         } while (Count > 0);
734     }
735 }
736
737 /*
738  * Specify zone is of -50000 to force GMT.  (This allows BST to work).
739  */
740
741 int
742 TclGetDate(p, now, zone, timePtr)
743     char          *p;
744     unsigned long  now;
745     long           zone;
746     unsigned long *timePtr;
747 {
748     struct tm           *tm;
749     time_t              Start;
750     time_t              Time;
751     time_t              tod;
752
753     TclDateInput = p;
754     tm = localtime((time_t *) &now);
755     TclDateYear = tm->tm_year;
756     TclDateMonth = tm->tm_mon + 1;
757     TclDateDay = tm->tm_mday;
758     TclDateTimezone = zone;
759     if (zone == -50000) {
760         TclDateDSTmode = DSToff;  /* assume GMT */
761         TclDateTimezone = 0;
762     } else {
763         TclDateDSTmode = DSTmaybe;
764     }
765     TclDateHour = 0;
766     TclDateMinutes = 0;
767     TclDateSeconds = 0;
768     TclDateMeridian = MER24;
769     TclDateRelSeconds = 0;
770     TclDateRelMonth = 0;
771     TclDateHaveDate = 0;
772     TclDateHaveDay = 0;
773     TclDateHaveRel = 0;
774     TclDateHaveTime = 0;
775     TclDateHaveZone = 0;
776
777     if (TclDateparse() || TclDateHaveTime > 1 || TclDateHaveZone > 1 || TclDateHaveDate > 1 ||
778             TclDateHaveDay > 1) {
779         return -1;
780     }
781     
782     if (TclDateHaveDate || TclDateHaveTime || TclDateHaveDay) {
783         if (Convert(TclDateMonth, TclDateDay, TclDateYear, TclDateHour, TclDateMinutes, TclDateSeconds,
784                     TclDateMeridian, TclDateDSTmode, &Start) < 0)
785             return -1;
786     }
787     else {
788         Start = now;
789         if (!TclDateHaveRel)
790             Start -= ((tm->tm_hour * 60L) + tm->tm_min * 60L) + tm->tm_sec;
791     }
792
793     Start += TclDateRelSeconds;
794     if (RelativeMonth(Start, TclDateRelMonth, &Time) < 0) {
795         return -1;
796     }
797     Start += Time;
798
799     if (TclDateHaveDay && !TclDateHaveDate) {
800         tod = RelativeDate(Start, TclDateDayOrdinal, TclDateDayNumber);
801         Start += tod;
802     }
803
804     *timePtr = Start;
805     return 0;
806 }
807 TclDatetabelem TclDateexca[] ={
808 -1, 1,
809         0, -1,
810         -2, 0,
811         };
812 # define YYNPROD 41
813 # define YYLAST 227
814 TclDatetabelem TclDateact[]={
815
816     14,    11,    23,    28,    17,    12,    19,    18,    16,     9,
817     10,    13,    42,    21,    46,    45,    44,    48,    41,    37,
818     36,    35,    32,    29,    34,    33,    31,    43,    39,    38,
819     30,    15,     8,     7,     6,     5,     4,     3,     2,     1,
820      0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
821      0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
822      0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
823      0,     0,     0,     0,    47,     0,     0,     0,     0,     0,
824      0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
825      0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
826      0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
827      0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
828      0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
829      0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
830      0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
831      0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
832      0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
833      0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
834      0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
835      0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
836      0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
837      0,     0,     0,    22,     0,     0,    20,    25,    24,    27,
838     26,    42,     0,     0,     0,     0,    40 };
839 TclDatetabelem TclDatepact[]={
840
841 -10000000,  -258,-10000000,-10000000,-10000000,-10000000,-10000000,-10000000,-10000000,   -45,
842   -267,-10000000,  -244,-10000000,   -14,  -231,  -240,-10000000,-10000000,-10000000,
843 -10000000,  -246,-10000000,  -247,  -248,-10000000,-10000000,-10000000,-10000000,   -15,
844 -10000000,-10000000,-10000000,-10000000,-10000000,   -40,   -20,-10000000,  -251,-10000000,
845 -10000000,  -252,-10000000,  -253,-10000000,  -249,-10000000,-10000000,-10000000 };
846 TclDatetabelem TclDatepgo[]={
847
848      0,    28,    39,    38,    37,    36,    35,    34,    33,    32,
849     31 };
850 TclDatetabelem TclDater1[]={
851
852      0,     2,     2,     3,     3,     3,     3,     3,     3,     4,
853      4,     4,     4,     4,     5,     5,     5,     7,     7,     7,
854      6,     6,     6,     6,     6,     6,     6,     8,     8,    10,
855     10,    10,    10,    10,    10,    10,    10,    10,     9,     1,
856      1 };
857 TclDatetabelem TclDater2[]={
858
859      0,     0,     4,     3,     3,     3,     3,     3,     2,     5,
860      9,     9,    13,    13,     5,     3,     3,     3,     5,     5,
861      7,    11,     5,     9,     5,     3,     7,     5,     2,     5,
862      5,     3,     5,     5,     3,     5,     5,     3,     3,     1,
863      3 };
864 TclDatetabelem TclDatechk[]={
865
866 -10000000,    -2,    -3,    -4,    -5,    -6,    -7,    -8,    -9,   267,
867    268,   259,   263,   269,   258,   -10,   266,   262,   265,   264,
868    261,    58,   258,    47,   263,   262,   265,   264,   270,   267,
869     44,   257,   262,   265,   264,   267,   267,   267,    44,    -1,
870    266,    58,   261,    47,   267,   267,   267,    -1,   266 };
871 TclDatetabelem TclDatedef[]={
872
873      1,    -2,     2,     3,     4,     5,     6,     7,     8,    38,
874     15,    16,     0,    25,    17,    28,     0,    31,    34,    37,
875      9,     0,    19,     0,    24,    29,    33,    36,    14,    22,
876     18,    27,    30,    32,    35,    39,    20,    26,     0,    10,
877     11,     0,    40,     0,    23,    39,    21,    12,    13 };
878 typedef struct
879 #ifdef __cplusplus
880         TclDatetoktype
881 #endif
882 { char *t_name; int t_val; } TclDatetoktype;
883 #ifndef YYDEBUG
884 #       define YYDEBUG  0       /* don't allow debugging */
885 #endif
886
887 #if YYDEBUG
888
889 TclDatetoktype TclDatetoks[] =
890 {
891         "tAGO", 257,
892         "tDAY", 258,
893         "tDAYZONE",     259,
894         "tID",  260,
895         "tMERIDIAN",    261,
896         "tMINUTE_UNIT", 262,
897         "tMONTH",       263,
898         "tMONTH_UNIT",  264,
899         "tSEC_UNIT",    265,
900         "tSNUMBER",     266,
901         "tUNUMBER",     267,
902         "tZONE",        268,
903         "tEPOCH",       269,
904         "tDST", 270,
905         "-unknown-",    -1      /* ends search */
906 };
907
908 char * TclDatereds[] =
909 {
910         "-no such reduction-",
911         "spec : /* empty */",
912         "spec : spec item",
913         "item : time",
914         "item : zone",
915         "item : date",
916         "item : day",
917         "item : rel",
918         "item : number",
919         "time : tUNUMBER tMERIDIAN",
920         "time : tUNUMBER ':' tUNUMBER o_merid",
921         "time : tUNUMBER ':' tUNUMBER tSNUMBER",
922         "time : tUNUMBER ':' tUNUMBER ':' tUNUMBER o_merid",
923         "time : tUNUMBER ':' tUNUMBER ':' tUNUMBER tSNUMBER",
924         "zone : tZONE tDST",
925         "zone : tZONE",
926         "zone : tDAYZONE",
927         "day : tDAY",
928         "day : tDAY ','",
929         "day : tUNUMBER tDAY",
930         "date : tUNUMBER '/' tUNUMBER",
931         "date : tUNUMBER '/' tUNUMBER '/' tUNUMBER",
932         "date : tMONTH tUNUMBER",
933         "date : tMONTH tUNUMBER ',' tUNUMBER",
934         "date : tUNUMBER tMONTH",
935         "date : tEPOCH",
936         "date : tUNUMBER tMONTH tUNUMBER",
937         "rel : relunit tAGO",
938         "rel : relunit",
939         "relunit : tUNUMBER tMINUTE_UNIT",
940         "relunit : tSNUMBER tMINUTE_UNIT",
941         "relunit : tMINUTE_UNIT",
942         "relunit : tSNUMBER tSEC_UNIT",
943         "relunit : tUNUMBER tSEC_UNIT",
944         "relunit : tSEC_UNIT",
945         "relunit : tSNUMBER tMONTH_UNIT",
946         "relunit : tUNUMBER tMONTH_UNIT",
947         "relunit : tMONTH_UNIT",
948         "number : tUNUMBER",
949         "o_merid : /* empty */",
950         "o_merid : tMERIDIAN",
951 };
952 #endif /* YYDEBUG */
953 /*
954  * Copyright (c) 1993 by Sun Microsystems, Inc.
955  */
956
957
958 /*
959 ** Skeleton parser driver for yacc output
960 */
961
962 /*
963 ** yacc user known macros and defines
964 */
965 #define YYERROR         goto TclDateerrlab
966 #define YYACCEPT        return(0)
967 #define YYABORT         return(1)
968 #define YYBACKUP( newtoken, newvalue )\
969 {\
970         if ( TclDatechar >= 0 || ( TclDater2[ TclDatetmp ] >> 1 ) != 1 )\
971         {\
972                 TclDateerror( "syntax error - cannot backup" );\
973                 goto TclDateerrlab;\
974         }\
975         TclDatechar = newtoken;\
976         TclDatestate = *TclDateps;\
977         TclDatelval = newvalue;\
978         goto TclDatenewstate;\
979 }
980 #define YYRECOVERING()  (!!TclDateerrflag)
981 #define YYNEW(type)     malloc(sizeof(type) * TclDatenewmax)
982 #define YYCOPY(to, from, type) \
983         (type *) memcpy(to, (char *) from, TclDatenewmax * sizeof(type))
984 #define YYENLARGE( from, type) \
985         (type *) realloc((char *) from, TclDatenewmax * sizeof(type))
986 #ifndef YYDEBUG
987 #       define YYDEBUG  1       /* make debugging available */
988 #endif
989
990 /*
991 ** user known globals
992 */
993 int TclDatedebug;                       /* set to 1 to get debugging */
994
995 /*
996 ** driver internal defines
997 */
998 #define YYFLAG          (-10000000)
999
1000 /*
1001 ** global variables used by the parser
1002 */
1003 YYSTYPE *TclDatepv;                     /* top of value stack */
1004 int *TclDateps;                 /* top of state stack */
1005
1006 int TclDatestate;                       /* current state */
1007 int TclDatetmp;                 /* extra var (lasts between blocks) */
1008
1009 int TclDatenerrs;                       /* number of errors */
1010 int TclDateerrflag;                     /* error recovery flag */
1011 int TclDatechar;                        /* current input token number */
1012
1013
1014
1015 #ifdef YYNMBCHARS
1016 #define YYLEX()         TclDatecvtok(TclDatelex())
1017 /*
1018 ** TclDatecvtok - return a token if i is a wchar_t value that exceeds 255.
1019 **      If i<255, i itself is the token.  If i>255 but the neither 
1020 **      of the 30th or 31st bit is on, i is already a token.
1021 */
1022 #if defined(__STDC__) || defined(__cplusplus)
1023 int TclDatecvtok(int i)
1024 #else
1025 int TclDatecvtok(i) int i;
1026 #endif
1027 {
1028         int first = 0;
1029         int last = YYNMBCHARS - 1;
1030         int mid;
1031         wchar_t j;
1032
1033         if(i&0x60000000){/*Must convert to a token. */
1034                 if( TclDatembchars[last].character < i ){
1035                         return i;/*Giving up*/
1036                 }
1037                 while ((last>=first)&&(first>=0)) {/*Binary search loop*/
1038                         mid = (first+last)/2;
1039                         j = TclDatembchars[mid].character;
1040                         if( j==i ){/*Found*/ 
1041                                 return TclDatembchars[mid].tvalue;
1042                         }else if( j<i ){
1043                                 first = mid + 1;
1044                         }else{
1045                                 last = mid -1;
1046                         }
1047                 }
1048                 /*No entry in the table.*/
1049                 return i;/* Giving up.*/
1050         }else{/* i is already a token. */
1051                 return i;
1052         }
1053 }
1054 #else/*!YYNMBCHARS*/
1055 #define YYLEX()         TclDatelex()
1056 #endif/*!YYNMBCHARS*/
1057
1058 /*
1059 ** TclDateparse - return 0 if worked, 1 if syntax error not recovered from
1060 */
1061 #if defined(__STDC__) || defined(__cplusplus)
1062 int TclDateparse(void)
1063 #else
1064 int TclDateparse()
1065 #endif
1066 {
1067         register YYSTYPE *TclDatepvt;   /* top of value stack for $vars */
1068
1069 #if defined(__cplusplus) || defined(lint)
1070 /*
1071         hacks to please C++ and lint - goto's inside switch should never be
1072         executed; TclDatepvt is set to 0 to avoid "used before set" warning.
1073 */
1074         static int __yaccpar_lint_hack__ = 0;
1075         switch (__yaccpar_lint_hack__)
1076         {
1077                 case 1: goto TclDateerrlab;
1078                 case 2: goto TclDatenewstate;
1079         }
1080         TclDatepvt = 0;
1081 #endif
1082
1083         /*
1084         ** Initialize externals - TclDateparse may be called more than once
1085         */
1086         TclDatepv = &TclDatev[-1];
1087         TclDateps = &TclDates[-1];
1088         TclDatestate = 0;
1089         TclDatetmp = 0;
1090         TclDatenerrs = 0;
1091         TclDateerrflag = 0;
1092         TclDatechar = -1;
1093
1094 #if YYMAXDEPTH <= 0
1095         if (TclDatemaxdepth <= 0)
1096         {
1097                 if ((TclDatemaxdepth = YYEXPAND(0)) <= 0)
1098                 {
1099                         TclDateerror("yacc initialization error");
1100                         YYABORT;
1101                 }
1102         }
1103 #endif
1104
1105         {
1106                 register YYSTYPE *TclDate_pv;   /* top of value stack */
1107                 register int *TclDate_ps;               /* top of state stack */
1108                 register int TclDate_state;             /* current state */
1109                 register int  TclDate_n;                /* internal state number info */
1110         goto TclDatestack;      /* moved from 6 lines above to here to please C++ */
1111
1112                 /*
1113                 ** get globals into registers.
1114                 ** branch to here only if YYBACKUP was called.
1115                 */
1116                 TclDate_pv = TclDatepv;
1117                 TclDate_ps = TclDateps;
1118                 TclDate_state = TclDatestate;
1119                 goto TclDate_newstate;
1120
1121                 /*
1122                 ** get globals into registers.
1123                 ** either we just started, or we just finished a reduction
1124                 */
1125         TclDatestack:
1126                 TclDate_pv = TclDatepv;
1127                 TclDate_ps = TclDateps;
1128                 TclDate_state = TclDatestate;
1129
1130                 /*
1131                 ** top of for (;;) loop while no reductions done
1132                 */
1133         TclDate_stack:
1134                 /*
1135                 ** put a state and value onto the stacks
1136                 */
1137 #if YYDEBUG
1138                 /*
1139                 ** if debugging, look up token value in list of value vs.
1140                 ** name pairs.  0 and negative (-1) are special values.
1141                 ** Note: linear search is used since time is not a real
1142                 ** consideration while debugging.
1143                 */
1144                 if ( TclDatedebug )
1145                 {
1146                         register int TclDate_i;
1147
1148                         printf( "State %d, token ", TclDate_state );
1149                         if ( TclDatechar == 0 )
1150                                 printf( "end-of-file\n" );
1151                         else if ( TclDatechar < 0 )
1152                                 printf( "-none-\n" );
1153                         else
1154                         {
1155                                 for ( TclDate_i = 0; TclDatetoks[TclDate_i].t_val >= 0;
1156                                         TclDate_i++ )
1157                                 {
1158                                         if ( TclDatetoks[TclDate_i].t_val == TclDatechar )
1159                                                 break;
1160                                 }
1161                                 printf( "%s\n", TclDatetoks[TclDate_i].t_name );
1162                         }
1163                 }
1164 #endif /* YYDEBUG */
1165                 if ( ++TclDate_ps >= &TclDates[ TclDatemaxdepth ] )     /* room on stack? */
1166                 {
1167                         /*
1168                         ** reallocate and recover.  Note that pointers
1169                         ** have to be reset, or bad things will happen
1170                         */
1171                         int TclDateps_index = (TclDate_ps - TclDates);
1172                         int TclDatepv_index = (TclDate_pv - TclDatev);
1173                         int TclDatepvt_index = (TclDatepvt - TclDatev);
1174                         int TclDatenewmax;
1175 #ifdef YYEXPAND
1176                         TclDatenewmax = YYEXPAND(TclDatemaxdepth);
1177 #else
1178                         TclDatenewmax = 2 * TclDatemaxdepth;    /* double table size */
1179                         if (TclDatemaxdepth == YYMAXDEPTH)      /* first time growth */
1180                         {
1181                                 char *newTclDates = (char *)YYNEW(int);
1182                                 char *newTclDatev = (char *)YYNEW(YYSTYPE);
1183                                 if (newTclDates != 0 && newTclDatev != 0)
1184                                 {
1185                                         TclDates = YYCOPY(newTclDates, TclDates, int);
1186                                         TclDatev = YYCOPY(newTclDatev, TclDatev, YYSTYPE);
1187                                 }
1188                                 else
1189                                         TclDatenewmax = 0;      /* failed */
1190                         }
1191                         else                            /* not first time */
1192                         {
1193                                 TclDates = YYENLARGE(TclDates, int);
1194                                 TclDatev = YYENLARGE(TclDatev, YYSTYPE);
1195                                 if (TclDates == 0 || TclDatev == 0)
1196                                         TclDatenewmax = 0;      /* failed */
1197                         }
1198 #endif
1199                         if (TclDatenewmax <= TclDatemaxdepth)   /* tables not expanded */
1200                         {
1201                                 TclDateerror( "yacc stack overflow" );
1202                                 YYABORT;
1203                         }
1204                         TclDatemaxdepth = TclDatenewmax;
1205
1206                         TclDate_ps = TclDates + TclDateps_index;
1207                         TclDate_pv = TclDatev + TclDatepv_index;
1208                         TclDatepvt = TclDatev + TclDatepvt_index;
1209                 }
1210                 *TclDate_ps = TclDate_state;
1211                 *++TclDate_pv = TclDateval;
1212
1213                 /*
1214                 ** we have a new state - find out what to do
1215                 */
1216         TclDate_newstate:
1217                 if ( ( TclDate_n = TclDatepact[ TclDate_state ] ) <= YYFLAG )
1218                         goto TclDatedefault;            /* simple state */
1219 #if YYDEBUG
1220                 /*
1221                 ** if debugging, need to mark whether new token grabbed
1222                 */
1223                 TclDatetmp = TclDatechar < 0;
1224 #endif
1225                 if ( ( TclDatechar < 0 ) && ( ( TclDatechar = YYLEX() ) < 0 ) )
1226                         TclDatechar = 0;                /* reached EOF */
1227 #if YYDEBUG
1228                 if ( TclDatedebug && TclDatetmp )
1229                 {
1230                         register int TclDate_i;
1231
1232                         printf( "Received token " );
1233                         if ( TclDatechar == 0 )
1234                                 printf( "end-of-file\n" );
1235                         else if ( TclDatechar < 0 )
1236                                 printf( "-none-\n" );
1237                         else
1238                         {
1239                                 for ( TclDate_i = 0; TclDatetoks[TclDate_i].t_val >= 0;
1240                                         TclDate_i++ )
1241                                 {
1242                                         if ( TclDatetoks[TclDate_i].t_val == TclDatechar )
1243                                                 break;
1244                                 }
1245                                 printf( "%s\n", TclDatetoks[TclDate_i].t_name );
1246                         }
1247                 }
1248 #endif /* YYDEBUG */
1249                 if ( ( ( TclDate_n += TclDatechar ) < 0 ) || ( TclDate_n >= YYLAST ) )
1250                         goto TclDatedefault;
1251                 if ( TclDatechk[ TclDate_n = TclDateact[ TclDate_n ] ] == TclDatechar ) /*valid shift*/
1252                 {
1253                         TclDatechar = -1;
1254                         TclDateval = TclDatelval;
1255                         TclDate_state = TclDate_n;
1256                         if ( TclDateerrflag > 0 )
1257                                 TclDateerrflag--;
1258                         goto TclDate_stack;
1259                 }
1260
1261         TclDatedefault:
1262                 if ( ( TclDate_n = TclDatedef[ TclDate_state ] ) == -2 )
1263                 {
1264 #if YYDEBUG
1265                         TclDatetmp = TclDatechar < 0;
1266 #endif
1267                         if ( ( TclDatechar < 0 ) && ( ( TclDatechar = YYLEX() ) < 0 ) )
1268                                 TclDatechar = 0;                /* reached EOF */
1269 #if YYDEBUG
1270                         if ( TclDatedebug && TclDatetmp )
1271                         {
1272                                 register int TclDate_i;
1273
1274                                 printf( "Received token " );
1275                                 if ( TclDatechar == 0 )
1276                                         printf( "end-of-file\n" );
1277                                 else if ( TclDatechar < 0 )
1278                                         printf( "-none-\n" );
1279                                 else
1280                                 {
1281                                         for ( TclDate_i = 0;
1282                                                 TclDatetoks[TclDate_i].t_val >= 0;
1283                                                 TclDate_i++ )
1284                                         {
1285                                                 if ( TclDatetoks[TclDate_i].t_val
1286                                                         == TclDatechar )
1287                                                 {
1288                                                         break;
1289                                                 }
1290                                         }
1291                                         printf( "%s\n", TclDatetoks[TclDate_i].t_name );
1292                                 }
1293                         }
1294 #endif /* YYDEBUG */
1295                         /*
1296                         ** look through exception table
1297                         */
1298                         {
1299                                 register int *TclDatexi = TclDateexca;
1300
1301                                 while ( ( *TclDatexi != -1 ) ||
1302                                         ( TclDatexi[1] != TclDate_state ) )
1303                                 {
1304                                         TclDatexi += 2;
1305                                 }
1306                                 while ( ( *(TclDatexi += 2) >= 0 ) &&
1307                                         ( *TclDatexi != TclDatechar ) )
1308                                         ;
1309                                 if ( ( TclDate_n = TclDatexi[1] ) < 0 )
1310                                         YYACCEPT;
1311                         }
1312                 }
1313
1314                 /*
1315                 ** check for syntax error
1316                 */
1317                 if ( TclDate_n == 0 )   /* have an error */
1318                 {
1319                         /* no worry about speed here! */
1320                         switch ( TclDateerrflag )
1321                         {
1322                         case 0:         /* new error */
1323                                 TclDateerror( "syntax error" );
1324                                 goto skip_init;
1325                                 /*
1326                                 ** get globals into registers.
1327                                 ** we have a user generated syntax type error
1328                                 */
1329                                 TclDate_pv = TclDatepv;
1330                                 TclDate_ps = TclDateps;
1331                                 TclDate_state = TclDatestate;
1332                         skip_init:
1333                                 TclDatenerrs++;
1334                                 /* FALLTHRU */
1335                         case 1:
1336                         case 2:         /* incompletely recovered error */
1337                                         /* try again... */
1338                                 TclDateerrflag = 3;
1339                                 /*
1340                                 ** find state where "error" is a legal
1341                                 ** shift action
1342                                 */
1343                                 while ( TclDate_ps >= TclDates )
1344                                 {
1345                                         TclDate_n = TclDatepact[ *TclDate_ps ] + YYERRCODE;
1346                                         if ( TclDate_n >= 0 && TclDate_n < YYLAST &&
1347                                                 TclDatechk[TclDateact[TclDate_n]] == YYERRCODE)                                 {
1348                                                 /*
1349                                                 ** simulate shift of "error"
1350                                                 */
1351                                                 TclDate_state = TclDateact[ TclDate_n ];
1352                                                 goto TclDate_stack;
1353                                         }
1354                                         /*
1355                                         ** current state has no shift on
1356                                         ** "error", pop stack
1357                                         */
1358 #if YYDEBUG
1359 #       define _POP_ "Error recovery pops state %d, uncovers state %d\n"
1360                                         if ( TclDatedebug )
1361                                                 printf( _POP_, *TclDate_ps,
1362                                                         TclDate_ps[-1] );
1363 #       undef _POP_
1364 #endif
1365                                         TclDate_ps--;
1366                                         TclDate_pv--;
1367                                 }
1368                                 /*
1369                                 ** there is no state on stack with "error" as
1370                                 ** a valid shift.  give up.
1371                                 */
1372                                 YYABORT;
1373                         case 3:         /* no shift yet; eat a token */
1374 #if YYDEBUG
1375                                 /*
1376                                 ** if debugging, look up token in list of
1377                                 ** pairs.  0 and negative shouldn't occur,
1378                                 ** but since timing doesn't matter when
1379                                 ** debugging, it doesn't hurt to leave the
1380                                 ** tests here.
1381                                 */
1382                                 if ( TclDatedebug )
1383                                 {
1384                                         register int TclDate_i;
1385
1386                                         printf( "Error recovery discards " );
1387                                         if ( TclDatechar == 0 )
1388                                                 printf( "token end-of-file\n" );
1389                                         else if ( TclDatechar < 0 )
1390                                                 printf( "token -none-\n" );
1391                                         else
1392                                         {
1393                                                 for ( TclDate_i = 0;
1394                                                         TclDatetoks[TclDate_i].t_val >= 0;
1395                                                         TclDate_i++ )
1396                                                 {
1397                                                         if ( TclDatetoks[TclDate_i].t_val
1398                                                                 == TclDatechar )
1399                                                         {
1400                                                                 break;
1401                                                         }
1402                                                 }
1403                                                 printf( "token %s\n",
1404                                                         TclDatetoks[TclDate_i].t_name );
1405                                         }
1406                                 }
1407 #endif /* YYDEBUG */
1408                                 if ( TclDatechar == 0 ) /* reached EOF. quit */
1409                                         YYABORT;
1410                                 TclDatechar = -1;
1411                                 goto TclDate_newstate;
1412                         }
1413                 }/* end if ( TclDate_n == 0 ) */
1414                 /*
1415                 ** reduction by production TclDate_n
1416                 ** put stack tops, etc. so things right after switch
1417                 */
1418 #if YYDEBUG
1419                 /*
1420                 ** if debugging, print the string that is the user's
1421                 ** specification of the reduction which is just about
1422                 ** to be done.
1423                 */
1424                 if ( TclDatedebug )
1425                         printf( "Reduce by (%d) \"%s\"\n",
1426                                 TclDate_n, TclDatereds[ TclDate_n ] );
1427 #endif
1428                 TclDatetmp = TclDate_n;                 /* value to switch over */
1429                 TclDatepvt = TclDate_pv;                        /* $vars top of value stack */
1430                 /*
1431                 ** Look in goto table for next state
1432                 ** Sorry about using TclDate_state here as temporary
1433                 ** register variable, but why not, if it works...
1434                 ** If TclDater2[ TclDate_n ] doesn't have the low order bit
1435                 ** set, then there is no action to be done for
1436                 ** this reduction.  So, no saving & unsaving of
1437                 ** registers done.  The only difference between the
1438                 ** code just after the if and the body of the if is
1439                 ** the goto TclDate_stack in the body.  This way the test
1440                 ** can be made before the choice of what to do is needed.
1441                 */
1442                 {
1443                         /* length of production doubled with extra bit */
1444                         register int TclDate_len = TclDater2[ TclDate_n ];
1445
1446                         if ( !( TclDate_len & 01 ) )
1447                         {
1448                                 TclDate_len >>= 1;
1449                                 TclDateval = ( TclDate_pv -= TclDate_len )[1];  /* $$ = $1 */
1450                                 TclDate_state = TclDatepgo[ TclDate_n = TclDater1[ TclDate_n ] ] +
1451                                         *( TclDate_ps -= TclDate_len ) + 1;
1452                                 if ( TclDate_state >= YYLAST ||
1453                                         TclDatechk[ TclDate_state =
1454                                         TclDateact[ TclDate_state ] ] != -TclDate_n )
1455                                 {
1456                                         TclDate_state = TclDateact[ TclDatepgo[ TclDate_n ] ];
1457                                 }
1458                                 goto TclDate_stack;
1459                         }
1460                         TclDate_len >>= 1;
1461                         TclDateval = ( TclDate_pv -= TclDate_len )[1];  /* $$ = $1 */
1462                         TclDate_state = TclDatepgo[ TclDate_n = TclDater1[ TclDate_n ] ] +
1463                                 *( TclDate_ps -= TclDate_len ) + 1;
1464                         if ( TclDate_state >= YYLAST ||
1465                                 TclDatechk[ TclDate_state = TclDateact[ TclDate_state ] ] != -TclDate_n )
1466                         {
1467                                 TclDate_state = TclDateact[ TclDatepgo[ TclDate_n ] ];
1468                         }
1469                 }
1470                                         /* save until reenter driver code */
1471                 TclDatestate = TclDate_state;
1472                 TclDateps = TclDate_ps;
1473                 TclDatepv = TclDate_pv;
1474         }
1475         /*
1476         ** code supplied by user is placed in this switch
1477         */
1478         switch( TclDatetmp )
1479         {
1480                 
1481 case 3:{
1482             TclDateHaveTime++;
1483         } break;
1484 case 4:{
1485             TclDateHaveZone++;
1486         } break;
1487 case 5:{
1488             TclDateHaveDate++;
1489         } break;
1490 case 6:{
1491             TclDateHaveDay++;
1492         } break;
1493 case 7:{
1494             TclDateHaveRel++;
1495         } break;
1496 case 9:{
1497             TclDateHour = TclDatepvt[-1].Number;
1498             TclDateMinutes = 0;
1499             TclDateSeconds = 0;
1500             TclDateMeridian = TclDatepvt[-0].Meridian;
1501         } break;
1502 case 10:{
1503             TclDateHour = TclDatepvt[-3].Number;
1504             TclDateMinutes = TclDatepvt[-1].Number;
1505             TclDateSeconds = 0;
1506             TclDateMeridian = TclDatepvt[-0].Meridian;
1507         } break;
1508 case 11:{
1509             TclDateHour = TclDatepvt[-3].Number;
1510             TclDateMinutes = TclDatepvt[-1].Number;
1511             TclDateMeridian = MER24;
1512             TclDateDSTmode = DSToff;
1513             TclDateTimezone = - (TclDatepvt[-0].Number % 100 + (TclDatepvt[-0].Number / 100) * 60);
1514         } break;
1515 case 12:{
1516             TclDateHour = TclDatepvt[-5].Number;
1517             TclDateMinutes = TclDatepvt[-3].Number;
1518             TclDateSeconds = TclDatepvt[-1].Number;
1519             TclDateMeridian = TclDatepvt[-0].Meridian;
1520         } break;
1521 case 13:{
1522             TclDateHour = TclDatepvt[-5].Number;
1523             TclDateMinutes = TclDatepvt[-3].Number;
1524             TclDateSeconds = TclDatepvt[-1].Number;
1525             TclDateMeridian = MER24;
1526             TclDateDSTmode = DSToff;
1527             TclDateTimezone = - (TclDatepvt[-0].Number % 100 + (TclDatepvt[-0].Number / 100) * 60);
1528         } break;
1529 case 14:{
1530             TclDateTimezone = TclDatepvt[-1].Number;
1531             TclDateDSTmode = DSTon;
1532         } break;
1533 case 15:{
1534             TclDateTimezone = TclDatepvt[-0].Number;
1535             TclDateDSTmode = DSToff;
1536         } break;
1537 case 16:{
1538             TclDateTimezone = TclDatepvt[-0].Number;
1539             TclDateDSTmode = DSTon;
1540         } break;
1541 case 17:{
1542             TclDateDayOrdinal = 1;
1543             TclDateDayNumber = TclDatepvt[-0].Number;
1544         } break;
1545 case 18:{
1546             TclDateDayOrdinal = 1;
1547             TclDateDayNumber = TclDatepvt[-1].Number;
1548         } break;
1549 case 19:{
1550             TclDateDayOrdinal = TclDatepvt[-1].Number;
1551             TclDateDayNumber = TclDatepvt[-0].Number;
1552         } break;
1553 case 20:{
1554             TclDateMonth = TclDatepvt[-2].Number;
1555             TclDateDay = TclDatepvt[-0].Number;
1556         } break;
1557 case 21:{
1558             TclDateMonth = TclDatepvt[-4].Number;
1559             TclDateDay = TclDatepvt[-2].Number;
1560             TclDateYear = TclDatepvt[-0].Number;
1561         } break;
1562 case 22:{
1563             TclDateMonth = TclDatepvt[-1].Number;
1564             TclDateDay = TclDatepvt[-0].Number;
1565         } break;
1566 case 23:{
1567             TclDateMonth = TclDatepvt[-3].Number;
1568             TclDateDay = TclDatepvt[-2].Number;
1569             TclDateYear = TclDatepvt[-0].Number;
1570         } break;
1571 case 24:{
1572             TclDateMonth = TclDatepvt[-0].Number;
1573             TclDateDay = TclDatepvt[-1].Number;
1574         } break;
1575 case 25:{
1576                                 TclDateMonth = 1;
1577                                 TclDateDay = 1;
1578                                 TclDateYear = EPOCH;
1579                   } break;
1580 case 26:{
1581             TclDateMonth = TclDatepvt[-1].Number;
1582             TclDateDay = TclDatepvt[-2].Number;
1583             TclDateYear = TclDatepvt[-0].Number;
1584         } break;
1585 case 27:{
1586             TclDateRelSeconds = -TclDateRelSeconds;
1587             TclDateRelMonth = -TclDateRelMonth;
1588         } break;
1589 case 29:{
1590             TclDateRelSeconds += TclDatepvt[-1].Number * TclDatepvt[-0].Number * 60L;
1591         } break;
1592 case 30:{
1593             TclDateRelSeconds += TclDatepvt[-1].Number * TclDatepvt[-0].Number * 60L;
1594         } break;
1595 case 31:{
1596             TclDateRelSeconds += TclDatepvt[-0].Number * 60L;
1597         } break;
1598 case 32:{
1599             TclDateRelSeconds += TclDatepvt[-1].Number;
1600         } break;
1601 case 33:{
1602             TclDateRelSeconds += TclDatepvt[-1].Number;
1603         } break;
1604 case 34:{
1605             TclDateRelSeconds++;
1606         } break;
1607 case 35:{
1608             TclDateRelMonth += TclDatepvt[-1].Number * TclDatepvt[-0].Number;
1609         } break;
1610 case 36:{
1611             TclDateRelMonth += TclDatepvt[-1].Number * TclDatepvt[-0].Number;
1612         } break;
1613 case 37:{
1614             TclDateRelMonth += TclDatepvt[-0].Number;
1615         } break;
1616 case 38:{
1617             if (TclDateHaveTime && TclDateHaveDate && !TclDateHaveRel)
1618                 TclDateYear = TclDatepvt[-0].Number;
1619             else {
1620                 TclDateHaveTime++;
1621                 if (TclDatepvt[-0].Number < 100) {
1622                     TclDateHour = TclDatepvt[-0].Number;
1623                     TclDateMinutes = 0;
1624                 }
1625                 else {
1626                     TclDateHour = TclDatepvt[-0].Number / 100;
1627                     TclDateMinutes = TclDatepvt[-0].Number % 100;
1628                 }
1629                 TclDateSeconds = 0;
1630                 TclDateMeridian = MER24;
1631             }
1632         } break;
1633 case 39:{
1634             TclDateval.Meridian = MER24;
1635         } break;
1636 case 40:{
1637             TclDateval.Meridian = TclDatepvt[-0].Meridian;
1638         } break;
1639         }
1640         goto TclDatestack;              /* reset registers in driver code */
1641 }
1642