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