home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / C / Applications / Tcl-Tk 8.0 / Pre-installed version / tcl8.0 / generic / tclDate.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-08-15  |  46.4 KB  |  1,639 lines  |  [TEXT/CWIE]

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