2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
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)
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
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
23 /* $XConsortium: tclDate.c /main/2 1996/08/08 14:43:30 cde-hp $ */
27 * This file is generated from a yacc grammar defined in
28 * the file tclGetdate.y
30 * Copyright (c) 1992-1995 Karl Lehenbauer and Mark Diekhans.
31 * Copyright (c) 1995-1996 Sun Microsystems, Inc.
33 * See the file "license.terms" for information on usage and redistribution
34 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
36 * @(#) tclDate.c 1.24 96/04/18 16:53:56
44 # define START_OF_TIME 1904
45 # define END_OF_TIME 2039
48 # define START_OF_TIME 1902
49 # define END_OF_TIME 2037
51 extern struct tm *localtime();
54 #define HOUR(x) ((int) (60 * x))
55 #define SECSPERDAY (24L * 60L * 60L)
59 * An entry in the lexical lookup table.
61 typedef struct _TABLE {
69 * Daylight-savings mode: on, off, or not yet known.
71 typedef enum _DSTMODE {
72 DSTon, DSToff, DSTmaybe
76 * Meridian: am, pm, or 24-hour style.
78 typedef enum _MERIDIAN {
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.
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;
111 * Prototypes of internal functions.
114 TclDateerror _ANSI_ARGS_((char *s));
117 ToSeconds _ANSI_ARGS_((time_t Hours,
123 Convert _ANSI_ARGS_((time_t Month,
134 DSTcorrect _ANSI_ARGS_((time_t Start,
138 RelativeDate _ANSI_ARGS_((time_t Start,
143 RelativeMonth _ANSI_ARGS_((time_t Start,
147 LookupWord _ANSI_ARGS_((char *buff));
150 TclDatelex _ANSI_ARGS_((void));
153 TclDateparse _ANSI_ARGS_((void));
160 enum _MERIDIAN Meridian;
164 # define tDAYZONE 259
166 # define tMERIDIAN 261
167 # define tMINUTE_UNIT 262
169 # define tMONTH_UNIT 264
170 # define tSEC_UNIT 265
171 # define tSNUMBER 266
172 # define tUNUMBER 267
182 void TclDateerror(const char *);
187 extern "C" { int TclDatelex(void); }
189 int TclDatelex(void);
192 int TclDateparse(void);
195 #define TclDateclearin TclDatechar = -1
196 #define TclDateerrok TclDateerrflag = 0
197 extern int TclDatechar;
198 extern int TclDateerrflag;
201 typedef int TclDatetabelem;
203 #define YYMAXDEPTH 150
206 int TclDate_TclDates[YYMAXDEPTH], *TclDates = TclDate_TclDates;
207 YYSTYPE TclDate_TclDatev[YYMAXDEPTH], *TclDatev = TclDate_TclDatev;
208 #else /* user does initial allocation */
212 static int TclDatemaxdepth = YYMAXDEPTH;
213 # define YYERRCODE 256
217 * Month and day table.
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 },
237 { "wednesday", tDAY, 3 },
238 { "wednes", tDAY, 3 },
239 { "thursday", tDAY, 4 },
241 { "thurs", tDAY, 4 },
242 { "friday", tDAY, 5 },
243 { "saturday", tDAY, 6 },
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 },
265 * Assorted relative-time words.
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 },
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 },
290 { "epoch", tEPOCH, 0 },
295 * The timezone table. (Note: This table was modified to not use any floating
296 * point constants to work around an SGI compiler bug).
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 */
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 */
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 */
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 */
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) */
375 * Military timezone table.
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) },
408 * Dump error messages in the bit bucket.
418 ToSeconds(Hours, Minutes, Seconds, Meridian)
424 if (Minutes < 0 || Minutes > 59 || Seconds < 0 || Seconds > 59)
428 if (Hours < 0 || Hours > 23)
430 return (Hours * 60L + Minutes) * 60L + Seconds;
432 if (Hours < 1 || Hours > 12)
434 return ((Hours % 12) * 60L + Minutes) * 60L + Seconds;
436 if (Hours < 1 || Hours > 12)
438 return (((Hours % 12) + 12) * 60L + Minutes) * 60L + Seconds;
440 return -1; /* Should never be reached */
445 Convert(Month, Day, Year, Hours, Minutes, Seconds, Meridian, DSTmode, TimePtr)
456 static int DaysInMonth[12] = {
457 31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
467 DaysInMonth[1] = Year % 4 == 0 && (Year % 100 != 0 || Year % 400 == 0)
469 if (Month < 1 || Month > 12
470 || Year < START_OF_TIME || Year > END_OF_TIME
471 || Day < 1 || Day > DaysInMonth[(int)--Month])
474 for (Julian = Day - 1, i = 0; i < Month; i++)
475 Julian += DaysInMonth[i];
477 for (i = EPOCH; i < Year; i++)
478 Julian += 365 + (i % 4 == 0);
480 for (i = Year; i < EPOCH; i++)
481 Julian -= 365 + (i % 4 == 0);
483 Julian *= SECSPERDAY;
484 Julian += TclDateTimezone * 60L;
485 if ((tod = ToSeconds(Hours, Minutes, Seconds, Meridian)) < 0)
489 || (DSTmode == DSTmaybe && localtime(&Julian)->tm_isdst))
497 DSTcorrect(Start, Future)
504 StartDay = (localtime(&Start)->tm_hour + 1) % 24;
505 FutureDay = (localtime(&Future)->tm_hour + 1) % 24;
506 return (Future - Start) + (StartDay - FutureDay) * 60L * 60L;
511 RelativeDate(Start, DayOrdinal, DayNumber)
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);
528 RelativeMonth(Start, RelMonth, TimePtr)
542 tm = localtime(&Start);
543 Month = 12 * tm->tm_year + tm->tm_mon + RelMonth;
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)
550 *TimePtr = DSTcorrect(Start, Julian);
568 for (p = buff; *p; p++) {
570 *p = (char) tolower(*p);
574 if (strcmp(buff, "am") == 0 || strcmp(buff, "a.m.") == 0) {
575 TclDatelval.Meridian = MERam;
578 if (strcmp(buff, "pm") == 0 || strcmp(buff, "p.m.") == 0) {
579 TclDatelval.Meridian = MERpm;
584 * See if we have an abbreviation for a month.
586 if (strlen(buff) == 3) {
588 } else if (strlen(buff) == 4 && buff[3] == '.') {
595 for (tp = MonthDayTable; tp->name; tp++) {
597 if (strncmp(buff, tp->name, 3) == 0) {
598 TclDatelval.Number = tp->value;
601 } else if (strcmp(buff, tp->name) == 0) {
602 TclDatelval.Number = tp->value;
607 for (tp = TimezoneTable; tp->name; tp++) {
608 if (strcmp(buff, tp->name) == 0) {
609 TclDatelval.Number = tp->value;
614 for (tp = UnitsTable; tp->name; tp++) {
615 if (strcmp(buff, tp->name) == 0) {
616 TclDatelval.Number = tp->value;
622 * Strip off any plural and try the units table again.
624 i = strlen(buff) - 1;
625 if (buff[i] == 's') {
627 for (tp = UnitsTable; tp->name; tp++) {
628 if (strcmp(buff, tp->name) == 0) {
629 TclDatelval.Number = tp->value;
635 for (tp = OtherTable; tp->name; tp++) {
636 if (strcmp(buff, tp->name) == 0) {
637 TclDatelval.Number = tp->value;
643 * Military timezones.
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;
655 * Drop out any periods and try the timezone table again.
657 for (i = 0, p = q = buff; *q; q++)
664 for (tp = TimezoneTable; tp->name; tp++) {
665 if (strcmp(buff, tp->name) == 0) {
666 TclDatelval.Number = tp->value;
685 while (isspace((unsigned char) (*TclDateInput))) {
689 if (isdigit(c = *TclDateInput) || c == '-' || c == '+') {
690 if (c == '-' || c == '+') {
691 sign = c == '-' ? -1 : 1;
692 if (!isdigit(*++TclDateInput)) {
701 for (TclDatelval.Number = 0; isdigit(c = *TclDateInput++); ) {
702 TclDatelval.Number = 10 * TclDatelval.Number + c - '0';
706 TclDatelval.Number = -TclDatelval.Number;
708 return sign ? tSNUMBER : tUNUMBER;
711 for (p = buff; isalpha(c = *TclDateInput++) || c == '.'; ) {
712 if (p < &buff[sizeof buff - 1]) {
718 return LookupWord(buff);
721 return *TclDateInput++;
728 } else if (c == '(') {
730 } else if (c == ')') {
738 * Specify zone is of -50000 to force GMT. (This allows BST to work).
742 TclGetDate(p, now, zone, timePtr)
746 unsigned long *timePtr;
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 */
763 TclDateDSTmode = DSTmaybe;
768 TclDateMeridian = MER24;
769 TclDateRelSeconds = 0;
777 if (TclDateparse() || TclDateHaveTime > 1 || TclDateHaveZone > 1 || TclDateHaveDate > 1 ||
778 TclDateHaveDay > 1) {
782 if (TclDateHaveDate || TclDateHaveTime || TclDateHaveDay) {
783 if (Convert(TclDateMonth, TclDateDay, TclDateYear, TclDateHour, TclDateMinutes, TclDateSeconds,
784 TclDateMeridian, TclDateDSTmode, &Start) < 0)
790 Start -= ((tm->tm_hour * 60L) + tm->tm_min * 60L) + tm->tm_sec;
793 Start += TclDateRelSeconds;
794 if (RelativeMonth(Start, TclDateRelMonth, &Time) < 0) {
799 if (TclDateHaveDay && !TclDateHaveDate) {
800 tod = RelativeDate(Start, TclDateDayOrdinal, TclDateDayNumber);
807 TclDatetabelem TclDateexca[] ={
814 TclDatetabelem TclDateact[]={
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[]={
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[]={
848 0, 28, 39, 38, 37, 36, 35, 34, 33, 32,
850 TclDatetabelem TclDater1[]={
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,
857 TclDatetabelem TclDater2[]={
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,
864 TclDatetabelem TclDatechk[]={
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[]={
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 };
882 { char *t_name; int t_val; } TclDatetoktype;
884 # define YYDEBUG 0 /* don't allow debugging */
889 TclDatetoktype TclDatetoks[] =
905 "-unknown-", -1 /* ends search */
908 char * TclDatereds[] =
910 "-no such reduction-",
911 "spec : /* empty */",
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",
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",
936 "date : tUNUMBER tMONTH tUNUMBER",
937 "rel : relunit tAGO",
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",
949 "o_merid : /* empty */",
950 "o_merid : tMERIDIAN",
954 * Copyright (c) 1993 by Sun Microsystems, Inc.
959 ** Skeleton parser driver for yacc output
963 ** yacc user known macros and defines
965 #define YYERROR goto TclDateerrlab
966 #define YYACCEPT return(0)
967 #define YYABORT return(1)
968 #define YYBACKUP( newtoken, newvalue )\
970 if ( TclDatechar >= 0 || ( TclDater2[ TclDatetmp ] >> 1 ) != 1 )\
972 TclDateerror( "syntax error - cannot backup" );\
975 TclDatechar = newtoken;\
976 TclDatestate = *TclDateps;\
977 TclDatelval = newvalue;\
978 goto TclDatenewstate;\
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))
987 # define YYDEBUG 1 /* make debugging available */
991 ** user known globals
993 int TclDatedebug; /* set to 1 to get debugging */
996 ** driver internal defines
998 #define YYFLAG (-10000000)
1001 ** global variables used by the parser
1003 YYSTYPE *TclDatepv; /* top of value stack */
1004 int *TclDateps; /* top of state stack */
1006 int TclDatestate; /* current state */
1007 int TclDatetmp; /* extra var (lasts between blocks) */
1009 int TclDatenerrs; /* number of errors */
1010 int TclDateerrflag; /* error recovery flag */
1011 int TclDatechar; /* current input token number */
1016 #define YYLEX() TclDatecvtok(TclDatelex())
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.
1022 #if defined(__STDC__) || defined(__cplusplus)
1023 int TclDatecvtok(int i)
1025 int TclDatecvtok(i) int i;
1029 int last = YYNMBCHARS - 1;
1033 if(i&0x60000000){/*Must convert to a token. */
1034 if( TclDatembchars[last].character < i ){
1035 return i;/*Giving up*/
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;
1048 /*No entry in the table.*/
1049 return i;/* Giving up.*/
1050 }else{/* i is already a token. */
1054 #else/*!YYNMBCHARS*/
1055 #define YYLEX() TclDatelex()
1056 #endif/*!YYNMBCHARS*/
1059 ** TclDateparse - return 0 if worked, 1 if syntax error not recovered from
1061 #if defined(__STDC__) || defined(__cplusplus)
1062 int TclDateparse(void)
1067 register YYSTYPE *TclDatepvt; /* top of value stack for $vars */
1069 #if defined(__cplusplus) || defined(lint)
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.
1074 static int __yaccpar_lint_hack__ = 0;
1075 switch (__yaccpar_lint_hack__)
1077 case 1: goto TclDateerrlab;
1078 case 2: goto TclDatenewstate;
1084 ** Initialize externals - TclDateparse may be called more than once
1086 TclDatepv = &TclDatev[-1];
1087 TclDateps = &TclDates[-1];
1095 if (TclDatemaxdepth <= 0)
1097 if ((TclDatemaxdepth = YYEXPAND(0)) <= 0)
1099 TclDateerror("yacc initialization error");
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++ */
1113 ** get globals into registers.
1114 ** branch to here only if YYBACKUP was called.
1116 TclDate_pv = TclDatepv;
1117 TclDate_ps = TclDateps;
1118 TclDate_state = TclDatestate;
1119 goto TclDate_newstate;
1122 ** get globals into registers.
1123 ** either we just started, or we just finished a reduction
1126 TclDate_pv = TclDatepv;
1127 TclDate_ps = TclDateps;
1128 TclDate_state = TclDatestate;
1131 ** top of for (;;) loop while no reductions done
1135 ** put a state and value onto the stacks
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.
1146 register int TclDate_i;
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" );
1155 for ( TclDate_i = 0; TclDatetoks[TclDate_i].t_val >= 0;
1158 if ( TclDatetoks[TclDate_i].t_val == TclDatechar )
1161 printf( "%s\n", TclDatetoks[TclDate_i].t_name );
1164 #endif /* YYDEBUG */
1165 if ( ++TclDate_ps >= &TclDates[ TclDatemaxdepth ] ) /* room on stack? */
1168 ** reallocate and recover. Note that pointers
1169 ** have to be reset, or bad things will happen
1171 int TclDateps_index = (TclDate_ps - TclDates);
1172 int TclDatepv_index = (TclDate_pv - TclDatev);
1173 int TclDatepvt_index = (TclDatepvt - TclDatev);
1176 TclDatenewmax = YYEXPAND(TclDatemaxdepth);
1178 TclDatenewmax = 2 * TclDatemaxdepth; /* double table size */
1179 if (TclDatemaxdepth == YYMAXDEPTH) /* first time growth */
1181 char *newTclDates = (char *)YYNEW(int);
1182 char *newTclDatev = (char *)YYNEW(YYSTYPE);
1183 if (newTclDates != 0 && newTclDatev != 0)
1185 TclDates = YYCOPY(newTclDates, TclDates, int);
1186 TclDatev = YYCOPY(newTclDatev, TclDatev, YYSTYPE);
1189 TclDatenewmax = 0; /* failed */
1191 else /* not first time */
1193 TclDates = YYENLARGE(TclDates, int);
1194 TclDatev = YYENLARGE(TclDatev, YYSTYPE);
1195 if (TclDates == 0 || TclDatev == 0)
1196 TclDatenewmax = 0; /* failed */
1199 if (TclDatenewmax <= TclDatemaxdepth) /* tables not expanded */
1201 TclDateerror( "yacc stack overflow" );
1204 TclDatemaxdepth = TclDatenewmax;
1206 TclDate_ps = TclDates + TclDateps_index;
1207 TclDate_pv = TclDatev + TclDatepv_index;
1208 TclDatepvt = TclDatev + TclDatepvt_index;
1210 *TclDate_ps = TclDate_state;
1211 *++TclDate_pv = TclDateval;
1214 ** we have a new state - find out what to do
1217 if ( ( TclDate_n = TclDatepact[ TclDate_state ] ) <= YYFLAG )
1218 goto TclDatedefault; /* simple state */
1221 ** if debugging, need to mark whether new token grabbed
1223 TclDatetmp = TclDatechar < 0;
1225 if ( ( TclDatechar < 0 ) && ( ( TclDatechar = YYLEX() ) < 0 ) )
1226 TclDatechar = 0; /* reached EOF */
1228 if ( TclDatedebug && TclDatetmp )
1230 register int TclDate_i;
1232 printf( "Received token " );
1233 if ( TclDatechar == 0 )
1234 printf( "end-of-file\n" );
1235 else if ( TclDatechar < 0 )
1236 printf( "-none-\n" );
1239 for ( TclDate_i = 0; TclDatetoks[TclDate_i].t_val >= 0;
1242 if ( TclDatetoks[TclDate_i].t_val == TclDatechar )
1245 printf( "%s\n", TclDatetoks[TclDate_i].t_name );
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*/
1254 TclDateval = TclDatelval;
1255 TclDate_state = TclDate_n;
1256 if ( TclDateerrflag > 0 )
1262 if ( ( TclDate_n = TclDatedef[ TclDate_state ] ) == -2 )
1265 TclDatetmp = TclDatechar < 0;
1267 if ( ( TclDatechar < 0 ) && ( ( TclDatechar = YYLEX() ) < 0 ) )
1268 TclDatechar = 0; /* reached EOF */
1270 if ( TclDatedebug && TclDatetmp )
1272 register int TclDate_i;
1274 printf( "Received token " );
1275 if ( TclDatechar == 0 )
1276 printf( "end-of-file\n" );
1277 else if ( TclDatechar < 0 )
1278 printf( "-none-\n" );
1281 for ( TclDate_i = 0;
1282 TclDatetoks[TclDate_i].t_val >= 0;
1285 if ( TclDatetoks[TclDate_i].t_val
1291 printf( "%s\n", TclDatetoks[TclDate_i].t_name );
1294 #endif /* YYDEBUG */
1296 ** look through exception table
1299 register int *TclDatexi = TclDateexca;
1301 while ( ( *TclDatexi != -1 ) ||
1302 ( TclDatexi[1] != TclDate_state ) )
1306 while ( ( *(TclDatexi += 2) >= 0 ) &&
1307 ( *TclDatexi != TclDatechar ) )
1309 if ( ( TclDate_n = TclDatexi[1] ) < 0 )
1315 ** check for syntax error
1317 if ( TclDate_n == 0 ) /* have an error */
1319 /* no worry about speed here! */
1320 switch ( TclDateerrflag )
1322 case 0: /* new error */
1323 TclDateerror( "syntax error" );
1326 ** get globals into registers.
1327 ** we have a user generated syntax type error
1329 TclDate_pv = TclDatepv;
1330 TclDate_ps = TclDateps;
1331 TclDate_state = TclDatestate;
1336 case 2: /* incompletely recovered error */
1340 ** find state where "error" is a legal
1343 while ( TclDate_ps >= TclDates )
1345 TclDate_n = TclDatepact[ *TclDate_ps ] + YYERRCODE;
1346 if ( TclDate_n >= 0 && TclDate_n < YYLAST &&
1347 TclDatechk[TclDateact[TclDate_n]] == YYERRCODE) {
1349 ** simulate shift of "error"
1351 TclDate_state = TclDateact[ TclDate_n ];
1355 ** current state has no shift on
1356 ** "error", pop stack
1359 # define _POP_ "Error recovery pops state %d, uncovers state %d\n"
1361 printf( _POP_, *TclDate_ps,
1369 ** there is no state on stack with "error" as
1370 ** a valid shift. give up.
1373 case 3: /* no shift yet; eat a token */
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
1384 register int TclDate_i;
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" );
1393 for ( TclDate_i = 0;
1394 TclDatetoks[TclDate_i].t_val >= 0;
1397 if ( TclDatetoks[TclDate_i].t_val
1403 printf( "token %s\n",
1404 TclDatetoks[TclDate_i].t_name );
1407 #endif /* YYDEBUG */
1408 if ( TclDatechar == 0 ) /* reached EOF. quit */
1411 goto TclDate_newstate;
1413 }/* end if ( TclDate_n == 0 ) */
1415 ** reduction by production TclDate_n
1416 ** put stack tops, etc. so things right after switch
1420 ** if debugging, print the string that is the user's
1421 ** specification of the reduction which is just about
1425 printf( "Reduce by (%d) \"%s\"\n",
1426 TclDate_n, TclDatereds[ TclDate_n ] );
1428 TclDatetmp = TclDate_n; /* value to switch over */
1429 TclDatepvt = TclDate_pv; /* $vars top of value stack */
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.
1443 /* length of production doubled with extra bit */
1444 register int TclDate_len = TclDater2[ TclDate_n ];
1446 if ( !( TclDate_len & 01 ) )
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 )
1456 TclDate_state = TclDateact[ TclDatepgo[ TclDate_n ] ];
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 )
1467 TclDate_state = TclDateact[ TclDatepgo[ TclDate_n ] ];
1470 /* save until reenter driver code */
1471 TclDatestate = TclDate_state;
1472 TclDateps = TclDate_ps;
1473 TclDatepv = TclDate_pv;
1476 ** code supplied by user is placed in this switch
1478 switch( TclDatetmp )
1497 TclDateHour = TclDatepvt[-1].Number;
1500 TclDateMeridian = TclDatepvt[-0].Meridian;
1503 TclDateHour = TclDatepvt[-3].Number;
1504 TclDateMinutes = TclDatepvt[-1].Number;
1506 TclDateMeridian = TclDatepvt[-0].Meridian;
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);
1516 TclDateHour = TclDatepvt[-5].Number;
1517 TclDateMinutes = TclDatepvt[-3].Number;
1518 TclDateSeconds = TclDatepvt[-1].Number;
1519 TclDateMeridian = TclDatepvt[-0].Meridian;
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);
1530 TclDateTimezone = TclDatepvt[-1].Number;
1531 TclDateDSTmode = DSTon;
1534 TclDateTimezone = TclDatepvt[-0].Number;
1535 TclDateDSTmode = DSToff;
1538 TclDateTimezone = TclDatepvt[-0].Number;
1539 TclDateDSTmode = DSTon;
1542 TclDateDayOrdinal = 1;
1543 TclDateDayNumber = TclDatepvt[-0].Number;
1546 TclDateDayOrdinal = 1;
1547 TclDateDayNumber = TclDatepvt[-1].Number;
1550 TclDateDayOrdinal = TclDatepvt[-1].Number;
1551 TclDateDayNumber = TclDatepvt[-0].Number;
1554 TclDateMonth = TclDatepvt[-2].Number;
1555 TclDateDay = TclDatepvt[-0].Number;
1558 TclDateMonth = TclDatepvt[-4].Number;
1559 TclDateDay = TclDatepvt[-2].Number;
1560 TclDateYear = TclDatepvt[-0].Number;
1563 TclDateMonth = TclDatepvt[-1].Number;
1564 TclDateDay = TclDatepvt[-0].Number;
1567 TclDateMonth = TclDatepvt[-3].Number;
1568 TclDateDay = TclDatepvt[-2].Number;
1569 TclDateYear = TclDatepvt[-0].Number;
1572 TclDateMonth = TclDatepvt[-0].Number;
1573 TclDateDay = TclDatepvt[-1].Number;
1578 TclDateYear = EPOCH;
1581 TclDateMonth = TclDatepvt[-1].Number;
1582 TclDateDay = TclDatepvt[-2].Number;
1583 TclDateYear = TclDatepvt[-0].Number;
1586 TclDateRelSeconds = -TclDateRelSeconds;
1587 TclDateRelMonth = -TclDateRelMonth;
1590 TclDateRelSeconds += TclDatepvt[-1].Number * TclDatepvt[-0].Number * 60L;
1593 TclDateRelSeconds += TclDatepvt[-1].Number * TclDatepvt[-0].Number * 60L;
1596 TclDateRelSeconds += TclDatepvt[-0].Number * 60L;
1599 TclDateRelSeconds += TclDatepvt[-1].Number;
1602 TclDateRelSeconds += TclDatepvt[-1].Number;
1605 TclDateRelSeconds++;
1608 TclDateRelMonth += TclDatepvt[-1].Number * TclDatepvt[-0].Number;
1611 TclDateRelMonth += TclDatepvt[-1].Number * TclDatepvt[-0].Number;
1614 TclDateRelMonth += TclDatepvt[-0].Number;
1617 if (TclDateHaveTime && TclDateHaveDate && !TclDateHaveRel)
1618 TclDateYear = TclDatepvt[-0].Number;
1621 if (TclDatepvt[-0].Number < 100) {
1622 TclDateHour = TclDatepvt[-0].Number;
1626 TclDateHour = TclDatepvt[-0].Number / 100;
1627 TclDateMinutes = TclDatepvt[-0].Number % 100;
1630 TclDateMeridian = MER24;
1634 TclDateval.Meridian = MER24;
1637 TclDateval.Meridian = TclDatepvt[-0].Meridian;
1640 goto TclDatestack; /* reset registers in driver code */