home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 35 Internet / 35-Internet.zip / daytime.zip / getdate.y < prev    next >
Text File  |  1998-10-18  |  26KB  |  1,031 lines

  1. %{
  2. /*
  3. **  Originally written by Steven M. Bellovin <smb@research.att.com> while
  4. **  at the University of North Carolina at Chapel Hill.  Later tweaked by
  5. **  a couple of people on Usenet.  Completely overhauled by Rich $alz
  6. **  <rsalz@bbn.com> and Jim Berets <jberets@bbn.com> in August, 1990;
  7. **  send any email to Rich.
  8. **
  9. **  This grammar has nine shift/reduce conflicts.
  10. **
  11. **  This code is in the public domain and has no copyright.
  12. */
  13. /* SUPPRESS 287 on yaccpar_sccsid *//* Unusd static variable */
  14. /* SUPPRESS 288 on yyerrlab *//* Label unused */
  15.  
  16. #ifdef HAVE_CONFIG_H
  17. #if defined (emacs) || defined (CONFIG_BROKETS)
  18. #include <config.h>
  19. #else
  20. #include "config.h"
  21. #endif
  22. #endif
  23.  
  24. /* Since the code of getdate.y is not included in the Emacs executable
  25.    itself, there is no need to #define static in this file.  Even if
  26.    the code were included in the Emacs executable, it probably
  27.    wouldn't do any harm to #undef it here; this will only cause
  28.    problems if we try to write to a static variable, which I don't
  29.    think this code needs to do.  */
  30. #ifdef emacs
  31. #undef static
  32. #endif
  33.  
  34. /* The following block of alloca-related preprocessor directives is here
  35.    solely to allow compilation by non GNU-C compilers of the C parser
  36.    produced from this file by old versions of bison.  Newer versions of
  37.    bison include a block similar to this one in bison.simple.  */
  38.    
  39. #ifdef __GNUC__
  40. #define alloca __builtin_alloca
  41. #else
  42. #ifdef HAVE_ALLOCA_H
  43. #include <alloca.h>
  44. #else
  45. #ifdef _AIX
  46.  #pragma alloca
  47. #else
  48. void *alloca ();
  49. #endif
  50. #endif
  51. #endif
  52.  
  53. #ifdef __GNUC__
  54. #undef alloca
  55. #define alloca __builtin_alloca
  56. #else
  57. #ifdef HAVE_ALLOCA_H
  58. #include <alloca.h>
  59. #else
  60. #ifdef _AIX /* for Bison */
  61.  #pragma alloca
  62. #else
  63. void *alloca ();
  64. #endif
  65. #endif
  66. #endif
  67.  
  68. #ifdef __IBMC__
  69. #include <malloc.h>
  70. #endif
  71.  
  72. #include <stdio.h>
  73. #include <ctype.h>
  74. #include <stdlib.h>
  75. #include <string.h>
  76.  
  77. /* The code at the top of get_date which figures out the offset of the
  78.    current time zone checks various CPP symbols to see if special
  79.    tricks are need, but defaults to using the gettimeofday system call.
  80.    Include <sys/time.h> if that will be used.  */
  81.  
  82. #if    defined(vms)
  83.  
  84. #include <types.h>
  85. #include <time.h>
  86.  
  87. #else
  88.  
  89. #include <sys/types.h>
  90.  
  91. #ifdef TIME_WITH_SYS_TIME
  92. #include <sys/time.h>
  93. #include <time.h>
  94. #else
  95. #ifdef HAVE_SYS_TIME_H
  96. #include <sys/time.h>
  97. #else
  98. #include <time.h>
  99. #endif
  100. #endif
  101.  
  102. #ifdef timezone
  103. #undef timezone /* needed for sgi */
  104. #endif
  105.  
  106. #if defined(__IBMC__) || defined(__GNUC__)
  107. typedef long long xtime_t;
  108. #else
  109. typedef long xtime_t;
  110. #endif
  111.  
  112. #if defined(HAVE_SYS_TIMEB_H)
  113. #include <sys/timeb.h>
  114. #else
  115. /*
  116. ** We use the obsolete `struct timeb' as part of our interface!
  117. ** Since the system doesn't have it, we define it here;
  118. ** our callers must do likewise.
  119. */
  120. struct timeb {
  121.     time_t        time;        /* Seconds since the epoch    */
  122.     unsigned short    millitm;    /* Field not used        */
  123.     short        timezone;    /* Minutes west of GMT        */
  124.     short        dstflag;    /* Field not used        */
  125. };
  126. #endif /* defined(HAVE_SYS_TIMEB_H) */
  127.  
  128. #endif    /* defined(vms) */
  129.  
  130. #if defined (STDC_HEADERS) || defined (USG)
  131. #include <string.h>
  132. #endif
  133.  
  134. /* Some old versions of bison generate parsers that use bcopy.
  135.    That loses on systems that don't provide the function, so we have
  136.    to redefine it here.  */
  137. #if !defined (HAVE_BCOPY) && defined (HAVE_MEMCPY) && !defined (bcopy)
  138. #define bcopy(from, to, len) memcpy ((to), (from), (len))
  139. #endif
  140.  
  141. extern struct tm    *gmtime();
  142. extern struct tm    *localtime();
  143.  
  144. #define yyparse getdate_yyparse
  145. #define yylex getdate_yylex
  146. #define yyerror getdate_yyerror
  147.  
  148. static int yylex (void);
  149. static int yyerror (char *);
  150.  
  151. #if    !defined(lint) && !defined(SABER)
  152. static char RCS[] =
  153.     "$Id: getdate.y,v 1.5 1998/10/18 17:33:43 rommel Exp rommel $";
  154. #endif    /* !defined(lint) && !defined(SABER) */
  155.  
  156.  
  157. #define EPOCH        1970
  158. #define HOUR(x)        ((xtime_t)(x) * 60)
  159. #define SECSPERDAY    (24L * 60L * 60L)
  160.  
  161.  
  162. /*
  163. **  An entry in the lexical lookup table.
  164. */
  165. typedef struct _TABLE {
  166.     char    *name;
  167.     int        type;
  168.     xtime_t    value;
  169. } TABLE;
  170.  
  171.  
  172. /*
  173. **  Daylight-savings mode:  on, off, or not yet known.
  174. */
  175. typedef enum _DSTMODE {
  176.     DSTon, DSToff, DSTmaybe
  177. } DSTMODE;
  178.  
  179. /*
  180. **  Meridian:  am, pm, or 24-hour style.
  181. */
  182. typedef enum _MERIDIAN {
  183.     MERam, MERpm, MER24
  184. } MERIDIAN;
  185.  
  186.  
  187. /*
  188. **  Global variables.  We could get rid of most of these by using a good
  189. **  union as the yacc stack.  (This routine was originally written before
  190. **  yacc had the %union construct.)  Maybe someday; right now we only use
  191. **  the %union very rarely.
  192. */
  193. static char    *yyInput;
  194. static DSTMODE    yyDSTmode;
  195. static xtime_t    yyDayOrdinal;
  196. static xtime_t    yyDayNumber;
  197. static int    yyHaveDate;
  198. static int    yyHaveDay;
  199. static int    yyHaveRel;
  200. static int    yyHaveTime;
  201. static int    yyHaveZone;
  202. static xtime_t    yyTimezone;
  203. static xtime_t    yyDay;
  204. static xtime_t    yyHour;
  205. static xtime_t    yyMinutes;
  206. static xtime_t    yyMonth;
  207. static xtime_t    yySeconds;
  208. static xtime_t    yyYear;
  209. static MERIDIAN    yyMeridian;
  210. static xtime_t    yyRelMonth;
  211. static xtime_t    yyRelSeconds;
  212.  
  213. %}
  214.  
  215. %union {
  216.     xtime_t        Number;
  217.     enum _MERIDIAN    Meridian;
  218. }
  219.  
  220. %token    tAGO tDAY tDAYZONE tID tMERIDIAN tMINUTE_UNIT tMONTH tMONTH_UNIT
  221. %token    tSEC_UNIT tSNUMBER tUNUMBER tZONE tDST
  222.  
  223. %type    <Number>    tDAY tDAYZONE tMINUTE_UNIT tMONTH tMONTH_UNIT
  224. %type    <Number>    tSEC_UNIT tSNUMBER tUNUMBER tZONE
  225. %type    <Meridian>    tMERIDIAN o_merid
  226.  
  227. %%
  228.  
  229. spec    : /* NULL */
  230.     | spec item
  231.     ;
  232.  
  233. item    : time {
  234.         yyHaveTime++;
  235.     }
  236.     | zone {
  237.         yyHaveZone++;
  238.     }
  239.     | date {
  240.         yyHaveDate++;
  241.     }
  242.     | day {
  243.         yyHaveDay++;
  244.     }
  245.     | rel {
  246.         yyHaveRel++;
  247.     }
  248.     | number
  249.     ;
  250.  
  251. time    : tUNUMBER tMERIDIAN {
  252.         yyHour = $1;
  253.         yyMinutes = 0;
  254.         yySeconds = 0;
  255.         yyMeridian = $2;
  256.     }
  257.     | tUNUMBER ':' tUNUMBER o_merid {
  258.         yyHour = $1;
  259.         yyMinutes = $3;
  260.         yySeconds = 0;
  261.         yyMeridian = $4;
  262.     }
  263.     | tUNUMBER ':' tUNUMBER tSNUMBER {
  264.         yyHour = $1;
  265.         yyMinutes = $3;
  266.         yyMeridian = MER24;
  267.         yyDSTmode = DSToff;
  268.         yyTimezone = - ($4 % 100 + ($4 / 100) * 60);
  269.     }
  270.     | tUNUMBER ':' tUNUMBER ':' tUNUMBER o_merid {
  271.         yyHour = $1;
  272.         yyMinutes = $3;
  273.         yySeconds = $5;
  274.         yyMeridian = $6;
  275.     }
  276.     | tUNUMBER ':' tUNUMBER ':' tUNUMBER tSNUMBER {
  277.         yyHour = $1;
  278.         yyMinutes = $3;
  279.         yySeconds = $5;
  280.         yyMeridian = MER24;
  281.         yyDSTmode = DSToff;
  282.         yyTimezone = - ($6 % 100 + ($6 / 100) * 60);
  283.     }
  284.     ;
  285.  
  286. zone    : tZONE {
  287.         yyTimezone = $1;
  288.         yyDSTmode = DSToff;
  289.     }
  290.     | tDAYZONE {
  291.         yyTimezone = $1;
  292.         yyDSTmode = DSTon;
  293.     }
  294.     |
  295.       tZONE tDST {
  296.         yyTimezone = $1;
  297.         yyDSTmode = DSTon;
  298.     }
  299.     ;
  300.  
  301. day    : tDAY {
  302.         yyDayOrdinal = 1;
  303.         yyDayNumber = $1;
  304.     }
  305.     | tDAY ',' {
  306.         yyDayOrdinal = 1;
  307.         yyDayNumber = $1;
  308.     }
  309.     | tUNUMBER tDAY {
  310.         yyDayOrdinal = $1;
  311.         yyDayNumber = $2;
  312.     }
  313.     ;
  314.  
  315. date    : tUNUMBER '/' tUNUMBER {
  316.         yyMonth = $1;
  317.         yyDay = $3;
  318.     }
  319.     | tUNUMBER '/' tUNUMBER '/' tUNUMBER {
  320.         yyMonth = $1;
  321.         yyDay = $3;
  322.         yyYear = $5;
  323.     }
  324.     | tUNUMBER tSNUMBER tSNUMBER {
  325.         /* ISO 8601 format.  yyyy-mm-dd.  */
  326.         yyYear = $1;
  327.         yyMonth = -$2;
  328.         yyDay = -$3;
  329.     }
  330.     | tMONTH tUNUMBER {
  331.         yyMonth = $1;
  332.         yyDay = $2;
  333.     }
  334.     | tMONTH tUNUMBER ',' tUNUMBER {
  335.         yyMonth = $1;
  336.         yyDay = $2;
  337.         yyYear = $4;
  338.     }
  339.     | tUNUMBER tMONTH {
  340.         yyMonth = $2;
  341.         yyDay = $1;
  342.     }
  343.     | tUNUMBER tMONTH tUNUMBER {
  344.         yyMonth = $2;
  345.         yyDay = $1;
  346.         yyYear = $3;
  347.     }
  348.     ;
  349.  
  350. rel    : relunit tAGO {
  351.         yyRelSeconds = -yyRelSeconds;
  352.         yyRelMonth = -yyRelMonth;
  353.     }
  354.     | relunit
  355.     ;
  356.  
  357. relunit    : tUNUMBER tMINUTE_UNIT {
  358.         yyRelSeconds += $1 * $2 * 60L;
  359.     }
  360.     | tSNUMBER tMINUTE_UNIT {
  361.         yyRelSeconds += $1 * $2 * 60L;
  362.     }
  363.     | tMINUTE_UNIT {
  364.         yyRelSeconds += $1 * 60L;
  365.     }
  366.     | tSNUMBER tSEC_UNIT {
  367.         yyRelSeconds += $1;
  368.     }
  369.     | tUNUMBER tSEC_UNIT {
  370.         yyRelSeconds += $1;
  371.     }
  372.     | tSEC_UNIT {
  373.         yyRelSeconds++;
  374.     }
  375.     | tSNUMBER tMONTH_UNIT {
  376.         yyRelMonth += $1 * $2;
  377.     }
  378.     | tUNUMBER tMONTH_UNIT {
  379.         yyRelMonth += $1 * $2;
  380.     }
  381.     | tMONTH_UNIT {
  382.         yyRelMonth += $1;
  383.     }
  384.     ;
  385.  
  386. number    : tUNUMBER {
  387.         if (yyHaveTime && yyHaveDate && !yyHaveRel)
  388.         yyYear = $1;
  389.         else {
  390.         if($1>10000) {
  391.             xtime_t date_part;
  392.  
  393.             date_part= $1/10000;
  394.             yyHaveDate++;
  395.             yyDay= (date_part)%100;
  396.             yyMonth= (date_part/100)%100;
  397.             yyYear = date_part/10000;
  398.         } 
  399.             yyHaveTime++;
  400.         if ($1 < 100) {
  401.             yyHour = $1;
  402.             yyMinutes = 0;
  403.         }
  404.         else {
  405.             yyHour = $1 / 100;
  406.             yyMinutes = $1 % 100;
  407.         }
  408.         yySeconds = 0;
  409.         yyMeridian = MER24;
  410.         }
  411.     }
  412.     ;
  413.  
  414. o_merid    : /* NULL */ {
  415.         $$ = MER24;
  416.     }
  417.     | tMERIDIAN {
  418.         $$ = $1;
  419.     }
  420.     ;
  421.  
  422. %%
  423.  
  424. /* Month and day table. */
  425. static TABLE const MonthDayTable[] = {
  426.     { "january",    tMONTH,  1 },
  427.     { "february",    tMONTH,  2 },
  428.     { "march",        tMONTH,  3 },
  429.     { "april",        tMONTH,  4 },
  430.     { "may",        tMONTH,  5 },
  431.     { "june",        tMONTH,  6 },
  432.     { "july",        tMONTH,  7 },
  433.     { "august",        tMONTH,  8 },
  434.     { "september",    tMONTH,  9 },
  435.     { "sept",        tMONTH,  9 },
  436.     { "october",    tMONTH, 10 },
  437.     { "november",    tMONTH, 11 },
  438.     { "december",    tMONTH, 12 },
  439.     { "sunday",        tDAY, 0 },
  440.     { "monday",        tDAY, 1 },
  441.     { "tuesday",    tDAY, 2 },
  442.     { "tues",        tDAY, 2 },
  443.     { "wednesday",    tDAY, 3 },
  444.     { "wednes",        tDAY, 3 },
  445.     { "thursday",    tDAY, 4 },
  446.     { "thur",        tDAY, 4 },
  447.     { "thurs",        tDAY, 4 },
  448.     { "friday",        tDAY, 5 },
  449.     { "saturday",    tDAY, 6 },
  450.     { NULL }
  451. };
  452.  
  453. /* Time units table. */
  454. static TABLE const UnitsTable[] = {
  455.     { "year",        tMONTH_UNIT,    12 },
  456.     { "month",        tMONTH_UNIT,    1 },
  457.     { "fortnight",    tMINUTE_UNIT,    14 * 24 * 60 },
  458.     { "week",        tMINUTE_UNIT,    7 * 24 * 60 },
  459.     { "day",        tMINUTE_UNIT,    1 * 24 * 60 },
  460.     { "hour",        tMINUTE_UNIT,    60 },
  461.     { "minute",        tMINUTE_UNIT,    1 },
  462.     { "min",        tMINUTE_UNIT,    1 },
  463.     { "second",        tSEC_UNIT,    1 },
  464.     { "sec",        tSEC_UNIT,    1 },
  465.     { NULL }
  466. };
  467.  
  468. /* Assorted relative-time words. */
  469. static TABLE const OtherTable[] = {
  470.     { "tomorrow",    tMINUTE_UNIT,    1 * 24 * 60 },
  471.     { "yesterday",    tMINUTE_UNIT,    -1 * 24 * 60 },
  472.     { "today",        tMINUTE_UNIT,    0 },
  473.     { "now",        tMINUTE_UNIT,    0 },
  474.     { "last",        tUNUMBER,    -1 },
  475.     { "this",        tMINUTE_UNIT,    0 },
  476.     { "next",        tUNUMBER,    2 },
  477.     { "first",        tUNUMBER,    1 },
  478. /*  { "second",        tUNUMBER,    2 }, */
  479.     { "third",        tUNUMBER,    3 },
  480.     { "fourth",        tUNUMBER,    4 },
  481.     { "fifth",        tUNUMBER,    5 },
  482.     { "sixth",        tUNUMBER,    6 },
  483.     { "seventh",    tUNUMBER,    7 },
  484.     { "eighth",        tUNUMBER,    8 },
  485.     { "ninth",        tUNUMBER,    9 },
  486.     { "tenth",        tUNUMBER,    10 },
  487.     { "eleventh",    tUNUMBER,    11 },
  488.     { "twelfth",    tUNUMBER,    12 },
  489.     { "ago",        tAGO,    1 },
  490.     { NULL }
  491. };
  492.  
  493. /* The timezone table. */
  494. /* Some of these are commented out because a time_t can't store a float. */
  495. static TABLE const TimezoneTable[] = {
  496.     { "gmt",    tZONE,     HOUR( 0) },    /* Greenwich Mean */
  497.     { "ut",    tZONE,     HOUR( 0) },    /* Universal (Coordinated) */
  498.     { "utc",    tZONE,     HOUR( 0) },
  499.     { "wet",    tZONE,     HOUR( 0) },    /* Western European */
  500.     { "bst",    tDAYZONE,  HOUR( 0) },    /* British Summer */
  501.     { "wat",    tZONE,     HOUR( 1) },    /* West Africa */
  502.     { "at",    tZONE,     HOUR( 2) },    /* Azores */
  503. #if 0
  504.     /* For completeness.  BST is also British Summer, and GST is
  505.      * also Guam Standard. */
  506.     { "bst",    tZONE,     HOUR( 3) },    /* Brazil Standard */
  507.     { "gst",    tZONE,     HOUR( 3) },    /* Greenland Standard */
  508. #endif
  509. #if 1
  510.     { "nft",    tZONE,     HOUR(3.5) },    /* Newfoundland */
  511.     { "nst",    tZONE,     HOUR(3.5) },    /* Newfoundland Standard */
  512.     { "ndt",    tDAYZONE,  HOUR(3.5) },    /* Newfoundland Daylight */
  513. #endif
  514.     { "ast",    tZONE,     HOUR( 4) },    /* Atlantic Standard */
  515.     { "adt",    tDAYZONE,  HOUR( 4) },    /* Atlantic Daylight */
  516.     { "est",    tZONE,     HOUR( 5) },    /* Eastern Standard */
  517.     { "edt",    tDAYZONE,  HOUR( 5) },    /* Eastern Daylight */
  518.     { "cst",    tZONE,     HOUR( 6) },    /* Central Standard */
  519.     { "cdt",    tDAYZONE,  HOUR( 6) },    /* Central Daylight */
  520.     { "mst",    tZONE,     HOUR( 7) },    /* Mountain Standard */
  521.     { "mdt",    tDAYZONE,  HOUR( 7) },    /* Mountain Daylight */
  522.     { "pst",    tZONE,     HOUR( 8) },    /* Pacific Standard */
  523.     { "pdt",    tDAYZONE,  HOUR( 8) },    /* Pacific Daylight */
  524.     { "yst",    tZONE,     HOUR( 9) },    /* Yukon Standard */
  525.     { "ydt",    tDAYZONE,  HOUR( 9) },    /* Yukon Daylight */
  526.     { "hst",    tZONE,     HOUR(10) },    /* Hawaii Standard */
  527.     { "hdt",    tDAYZONE,  HOUR(10) },    /* Hawaii Daylight */
  528.     { "cat",    tZONE,     HOUR(10) },    /* Central Alaska */
  529.     { "ahst",    tZONE,     HOUR(10) },    /* Alaska-Hawaii Standard */
  530.     { "nt",    tZONE,     HOUR(11) },    /* Nome */
  531.     { "idlw",    tZONE,     HOUR(12) },    /* International Date Line West */
  532.     { "cet",    tZONE,     -HOUR(1) },    /* Central European */
  533.     { "met",    tZONE,     -HOUR(1) },    /* Middle European */
  534.     { "mewt",    tZONE,     -HOUR(1) },    /* Middle European Winter */
  535.     { "mest",    tDAYZONE,  -HOUR(1) },    /* Middle European Summer */
  536.     { "swt",    tZONE,     -HOUR(1) },    /* Swedish Winter */
  537.     { "sst",    tDAYZONE,  -HOUR(1) },    /* Swedish Summer */
  538.     { "fwt",    tZONE,     -HOUR(1) },    /* French Winter */
  539.     { "fst",    tDAYZONE,  -HOUR(1) },    /* French Summer */
  540.     { "eet",    tZONE,     -HOUR(2) },    /* Eastern Europe, USSR Zone 1 */
  541.     { "bt",    tZONE,     -HOUR(3) },    /* Baghdad, USSR Zone 2 */
  542. #if 0
  543.     { "it",    tZONE,     -HOUR(3.5) },/* Iran */
  544. #endif
  545.     { "zp4",    tZONE,     -HOUR(4) },    /* USSR Zone 3 */
  546.     { "zp5",    tZONE,     -HOUR(5) },    /* USSR Zone 4 */
  547. #if 0
  548.     { "ist",    tZONE,     -HOUR(5.5) },/* Indian Standard */
  549. #endif
  550.     { "zp6",    tZONE,     -HOUR(6) },    /* USSR Zone 5 */
  551. #if    0
  552.     /* For completeness.  NST is also Newfoundland Stanard, and SST is
  553.      * also Swedish Summer. */
  554.     { "nst",    tZONE,     -HOUR(6.5) },/* North Sumatra */
  555.     { "sst",    tZONE,     -HOUR(7) },    /* South Sumatra, USSR Zone 6 */
  556. #endif    /* 0 */
  557.     { "wast",    tZONE,     -HOUR(7) },    /* West Australian Standard */
  558.     { "wadt",    tDAYZONE,  -HOUR(7) },    /* West Australian Daylight */
  559. #if 0
  560.     { "jt",    tZONE,     -HOUR(7.5) },/* Java (3pm in Cronusland!) */
  561. #endif
  562.     { "cct",    tZONE,     -HOUR(8) },    /* China Coast, USSR Zone 7 */
  563.     { "jst",    tZONE,     -HOUR(9) },    /* Japan Standard, USSR Zone 8 */
  564. #if 0
  565.     { "cast",    tZONE,     -HOUR(9.5) },/* Central Australian Standard */
  566.     { "cadt",    tDAYZONE,  -HOUR(9.5) },/* Central Australian Daylight */
  567. #endif
  568.     { "east",    tZONE,     -HOUR(10) },    /* Eastern Australian Standard */
  569.     { "eadt",    tDAYZONE,  -HOUR(10) },    /* Eastern Australian Daylight */
  570.     { "gst",    tZONE,     -HOUR(10) },    /* Guam Standard, USSR Zone 9 */
  571.     { "nzt",    tZONE,     -HOUR(12) },    /* New Zealand */
  572.     { "nzst",    tZONE,     -HOUR(12) },    /* New Zealand Standard */
  573.     { "nzdt",    tDAYZONE,  -HOUR(12) },    /* New Zealand Daylight */
  574.     { "idle",    tZONE,     -HOUR(12) },    /* International Date Line East */
  575.     {  NULL  }
  576. };
  577.  
  578. /* Military timezone table. */
  579. static TABLE const MilitaryTable[] = {
  580.     { "a",    tZONE,    HOUR(  1) },
  581.     { "b",    tZONE,    HOUR(  2) },
  582.     { "c",    tZONE,    HOUR(  3) },
  583.     { "d",    tZONE,    HOUR(  4) },
  584.     { "e",    tZONE,    HOUR(  5) },
  585.     { "f",    tZONE,    HOUR(  6) },
  586.     { "g",    tZONE,    HOUR(  7) },
  587.     { "h",    tZONE,    HOUR(  8) },
  588.     { "i",    tZONE,    HOUR(  9) },
  589.     { "k",    tZONE,    HOUR( 10) },
  590.     { "l",    tZONE,    HOUR( 11) },
  591.     { "m",    tZONE,    HOUR( 12) },
  592.     { "n",    tZONE,    HOUR(- 1) },
  593.     { "o",    tZONE,    HOUR(- 2) },
  594.     { "p",    tZONE,    HOUR(- 3) },
  595.     { "q",    tZONE,    HOUR(- 4) },
  596.     { "r",    tZONE,    HOUR(- 5) },
  597.     { "s",    tZONE,    HOUR(- 6) },
  598.     { "t",    tZONE,    HOUR(- 7) },
  599.     { "u",    tZONE,    HOUR(- 8) },
  600.     { "v",    tZONE,    HOUR(- 9) },
  601.     { "w",    tZONE,    HOUR(-10) },
  602.     { "x",    tZONE,    HOUR(-11) },
  603.     { "y",    tZONE,    HOUR(-12) },
  604.     { "z",    tZONE,    HOUR(  0) },
  605.     { NULL }
  606. };
  607.  
  608.  
  609.  
  610.  
  611. /* ARGSUSED */
  612. static int
  613. yyerror(char *s)
  614. {
  615.   return 0;
  616. }
  617.  
  618.  
  619. static xtime_t
  620. ToSeconds(
  621.     xtime_t    Hours,
  622.     xtime_t    Minutes,
  623.     xtime_t    Seconds,
  624.     MERIDIAN    Meridian)
  625. {
  626.     if (Minutes < 0 || Minutes > 59 || Seconds < 0 || Seconds > 59)
  627.     return -1;
  628.     switch (Meridian) {
  629.     case MER24:
  630.     if (Hours < 0 || Hours > 23)
  631.         return -1;
  632.     return (Hours * 60L + Minutes) * 60L + Seconds;
  633.     case MERam:
  634.     if (Hours < 1 || Hours > 12)
  635.         return -1;
  636.     return (Hours * 60L + Minutes) * 60L + Seconds;
  637.     case MERpm:
  638.     if (Hours < 1 || Hours > 12)
  639.         return -1;
  640.     return ((Hours + 12) * 60L + Minutes) * 60L + Seconds;
  641.     default:
  642.     abort ();
  643.     }
  644.     return -1;
  645. }
  646.  
  647.  
  648. static xtime_t
  649. Convert(
  650.     xtime_t    Month,
  651.     xtime_t    Day,
  652.     xtime_t    Year,
  653.     xtime_t    Hours,
  654.     xtime_t    Minutes,
  655.     xtime_t    Seconds,
  656.     MERIDIAN    Meridian,
  657.     DSTMODE    DSTmode)
  658. {
  659.     static int DaysInMonth[12] = {
  660.     31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
  661.     };
  662.     xtime_t    tod;
  663.     xtime_t    Julian;
  664.     time_t    xJulian;
  665.     int        i;
  666.  
  667.     if (Year < 0)
  668.     Year = -Year;
  669.     if (Year < 100)
  670.     Year += 1900;
  671.     DaysInMonth[1] = Year % 4 == 0 && (Year % 100 != 0 || Year % 400 == 0)
  672.             ? 29 : 28;
  673.     if (Year < EPOCH || Year > 2099 /* was: 1999 ! */
  674.      || Month < 1 || Month > 12
  675.      /* Lint fluff:  "conversion from long may lose accuracy" */
  676.      || Day < 1 || Day > DaysInMonth[(int)--Month])
  677.     return -1;
  678.  
  679.     for (Julian = Day - 1, i = 0; i < Month; i++)
  680.     Julian += DaysInMonth[i];
  681.     for (i = EPOCH; i < Year; i++)
  682.     Julian += 365 + (i % 4 == 0);
  683.     Julian *= SECSPERDAY;
  684.     Julian += yyTimezone * 60L;
  685.     if ((tod = ToSeconds(Hours, Minutes, Seconds, Meridian)) < 0)
  686.     return -1;
  687.     Julian += tod;
  688.     xJulian = (time_t) Julian;
  689.     if (DSTmode == DSTon
  690.      || (DSTmode == DSTmaybe && localtime(&xJulian)->tm_isdst))
  691.     Julian -= 60 * 60;
  692.     return Julian;
  693. }
  694.  
  695.  
  696. static xtime_t
  697. DSTcorrect(
  698.     xtime_t    Start,
  699.     xtime_t    Future)
  700. {
  701.     xtime_t    StartDay;
  702.     xtime_t    FutureDay;
  703.     time_t    xStart = (time_t) Start, xFuture = (time_t) Future;
  704.  
  705.     StartDay = (localtime(&xStart)->tm_hour + 1) % 24;
  706.     FutureDay = (localtime(&xFuture)->tm_hour + 1) % 24;
  707.     return (Future - Start) + (StartDay - FutureDay) * 60L * 60L;
  708. }
  709.  
  710.  
  711. static xtime_t
  712. RelativeDate(
  713.     xtime_t    Start,
  714.     xtime_t    DayOrdinal,
  715.     xtime_t    DayNumber)
  716. {
  717.     struct tm    *tm;
  718.     time_t    now;
  719.     xtime_t    xnow;
  720.  
  721.     now = (time_t) Start;
  722.     tm = localtime(&now);
  723.     xnow = Start + SECSPERDAY * ((DayNumber - tm->tm_wday + 7) % 7);
  724.     xnow += 7 * SECSPERDAY * (DayOrdinal <= 0 ? DayOrdinal : DayOrdinal - 1);
  725.     return DSTcorrect(Start, xnow);
  726. }
  727.  
  728.  
  729. static xtime_t
  730. RelativeMonth(
  731.     xtime_t    Start,
  732.     xtime_t    RelMonth)
  733. {
  734.     struct tm    *tm;
  735.     xtime_t    Month;
  736.     xtime_t    Year;
  737.     time_t    xStart = (time_t) Start;
  738.  
  739.     if (RelMonth == 0)
  740.     return 0;
  741.     tm = localtime(&xStart);
  742.     Month = 12 * tm->tm_year + tm->tm_mon + RelMonth;
  743.     Year = Month / 12;
  744.     Month = Month % 12 + 1;
  745.     return DSTcorrect(Start,
  746.         Convert(Month, tm->tm_mday, Year,
  747.         tm->tm_hour, tm->tm_min, tm->tm_sec,
  748.         MER24, DSTmaybe));
  749. }
  750.  
  751.  
  752. static int
  753. LookupWord(char *buff)
  754. {
  755.     register char    *p;
  756.     register char    *q;
  757.     register const TABLE    *tp;
  758.     int            i;
  759.     int            abbrev;
  760.  
  761.     /* Make it lowercase. */
  762.     for (p = buff; *p; p++)
  763.     if (isupper(*p))
  764.         *p = tolower(*p);
  765.  
  766.     if (strcmp(buff, "am") == 0 || strcmp(buff, "a.m.") == 0) {
  767.     yylval.Meridian = MERam;
  768.     return tMERIDIAN;
  769.     }
  770.     if (strcmp(buff, "pm") == 0 || strcmp(buff, "p.m.") == 0) {
  771.     yylval.Meridian = MERpm;
  772.     return tMERIDIAN;
  773.     }
  774.  
  775.     /* See if we have an abbreviation for a month. */
  776.     if (strlen(buff) == 3)
  777.     abbrev = 1;
  778.     else if (strlen(buff) == 4 && buff[3] == '.') {
  779.     abbrev = 1;
  780.     buff[3] = '\0';
  781.     }
  782.     else
  783.     abbrev = 0;
  784.  
  785.     for (tp = MonthDayTable; tp->name; tp++) {
  786.     if (abbrev) {
  787.         if (strncmp(buff, tp->name, 3) == 0) {
  788.         yylval.Number = tp->value;
  789.         return tp->type;
  790.         }
  791.     }
  792.     else if (strcmp(buff, tp->name) == 0) {
  793.         yylval.Number = tp->value;
  794.         return tp->type;
  795.     }
  796.     }
  797.  
  798.     for (tp = TimezoneTable; tp->name; tp++)
  799.     if (strcmp(buff, tp->name) == 0) {
  800.         yylval.Number = tp->value;
  801.         return tp->type;
  802.     }
  803.  
  804.     if (strcmp(buff, "dst") == 0) 
  805.     return tDST;
  806.  
  807.     for (tp = UnitsTable; tp->name; tp++)
  808.     if (strcmp(buff, tp->name) == 0) {
  809.         yylval.Number = tp->value;
  810.         return tp->type;
  811.     }
  812.  
  813.     /* Strip off any plural and try the units table again. */
  814.     i = strlen(buff) - 1;
  815.     if (buff[i] == 's') {
  816.     buff[i] = '\0';
  817.     for (tp = UnitsTable; tp->name; tp++)
  818.         if (strcmp(buff, tp->name) == 0) {
  819.         yylval.Number = tp->value;
  820.         return tp->type;
  821.         }
  822.     buff[i] = 's';        /* Put back for "this" in OtherTable. */
  823.     }
  824.  
  825.     for (tp = OtherTable; tp->name; tp++)
  826.     if (strcmp(buff, tp->name) == 0) {
  827.         yylval.Number = tp->value;
  828.         return tp->type;
  829.     }
  830.  
  831.     /* Military timezones. */
  832.     if (buff[1] == '\0' && isalpha(*buff)) {
  833.     for (tp = MilitaryTable; tp->name; tp++)
  834.         if (strcmp(buff, tp->name) == 0) {
  835.         yylval.Number = tp->value;
  836.         return tp->type;
  837.         }
  838.     }
  839.  
  840.     /* Drop out any periods and try the timezone table again. */
  841.     for (i = 0, p = q = buff; *q; q++)
  842.     if (*q != '.')
  843.         *p++ = *q;
  844.     else
  845.         i++;
  846.     *p = '\0';
  847.     if (i)
  848.     for (tp = TimezoneTable; tp->name; tp++)
  849.         if (strcmp(buff, tp->name) == 0) {
  850.         yylval.Number = tp->value;
  851.         return tp->type;
  852.         }
  853.  
  854.     return tID;
  855. }
  856.  
  857.  
  858. static int
  859. yylex(void)
  860. {
  861.     register char    c;
  862.     register char    *p;
  863.     char        buff[20];
  864.     int            Count;
  865.     int            sign;
  866.  
  867.     for ( ; ; ) {
  868.     while (isspace(*yyInput))
  869.         yyInput++;
  870.  
  871.     if (isdigit(c = *yyInput) || c == '-' || c == '+') {
  872.         if (c == '-' || c == '+') {
  873.         sign = c == '-' ? -1 : 1;
  874.         if (!isdigit(*++yyInput))
  875.             /* skip the '-' sign */
  876.             continue;
  877.         }
  878.         else
  879.         sign = 0;
  880.         for (yylval.Number = 0; isdigit(c = *yyInput++); )
  881.         yylval.Number = 10 * yylval.Number + c - '0';
  882.         yyInput--;
  883.         if (sign < 0)
  884.         yylval.Number = -yylval.Number;
  885.         return sign ? tSNUMBER : tUNUMBER;
  886.     }
  887.     if (isalpha(c)) {
  888.         for (p = buff; isalpha(c = *yyInput++) || c == '.'; )
  889.         if (p < &buff[sizeof buff - 1])
  890.             *p++ = c;
  891.         *p = '\0';
  892.         yyInput--;
  893.         return LookupWord(buff);
  894.     }
  895.     if (c != '(')
  896.         return *yyInput++;
  897.     Count = 0;
  898.     do {
  899.         c = *yyInput++;
  900.         if (c == '\0')
  901.         return c;
  902.         if (c == '(')
  903.         Count++;
  904.         else if (c == ')')
  905.         Count--;
  906.     } while (Count > 0);
  907.     }
  908. }
  909.  
  910.  
  911. #define TM_YEAR_ORIGIN 1900
  912.  
  913. /* Yield A - B, measured in seconds.  */
  914. static xtime_t
  915. difftm(struct tm *a, struct tm *b)
  916. {
  917.   int ay = a->tm_year + (TM_YEAR_ORIGIN - 1);
  918.   int by = b->tm_year + (TM_YEAR_ORIGIN - 1);
  919.   return
  920.     (
  921.      (
  922.       (
  923.        /* difference in day of year */
  924.        a->tm_yday - b->tm_yday
  925.        /* + intervening leap days */
  926.        +  ((ay >> 2) - (by >> 2))
  927.        -  (ay/100 - by/100)
  928.        +  ((ay/100 >> 2) - (by/100 >> 2))
  929.        /* + difference in years * 365 */
  930.        +  (time_t)(ay-by) * 365
  931.        )*24 + (a->tm_hour - b->tm_hour)
  932.       )*60 + (a->tm_min - b->tm_min)
  933.      )*60 + (a->tm_sec - b->tm_sec);
  934. }
  935.  
  936. time_t
  937. get_date(
  938.     char        *p,
  939.     struct timeb    *now)
  940. {
  941.     struct tm        *tm, gmt;
  942.     struct timeb    ftz;
  943.     xtime_t        Start;
  944.     xtime_t        tod;
  945.  
  946.     yyInput = p;
  947.     if (now == NULL) {
  948.         now = &ftz;
  949.     (void)time(&ftz.time);
  950.  
  951.     if (! (tm = gmtime (&ftz.time)))
  952.         return -1;
  953.     gmt = *tm;    /* Make a copy, in case localtime modifies *tm.  */
  954.     ftz.timezone = (long) difftm (&gmt, localtime (&ftz.time)) / 60;
  955.  
  956.     if (localtime(&ftz.time)->tm_isdst)
  957.       ftz.timezone += 60;
  958.     }
  959.  
  960.     tm = localtime(&now->time);
  961.     yyYear = tm->tm_year;
  962.     yyMonth = tm->tm_mon + 1;
  963.     yyDay = tm->tm_mday;
  964.     yyTimezone = now->timezone;
  965.     yyDSTmode = DSTmaybe;
  966.     yyHour = 0;
  967.     yyMinutes = 0;
  968.     yySeconds = 0;
  969.     yyMeridian = MER24;
  970.     yyRelSeconds = 0;
  971.     yyRelMonth = 0;
  972.     yyHaveDate = 0;
  973.     yyHaveDay = 0;
  974.     yyHaveRel = 0;
  975.     yyHaveTime = 0;
  976.     yyHaveZone = 0;
  977.  
  978.     if (yyparse()
  979.      || yyHaveTime > 1 || yyHaveZone > 1 || yyHaveDate > 1 || yyHaveDay > 1)
  980.     return -1;
  981.  
  982.     if (yyHaveDate || yyHaveTime || yyHaveDay) {
  983.     Start = Convert(yyMonth, yyDay, yyYear, yyHour, yyMinutes, yySeconds,
  984.             yyMeridian, yyDSTmode);
  985.     if (Start < 0)
  986.         return -1;
  987.     }
  988.     else {
  989.     Start = now->time;
  990.     if (!yyHaveRel)
  991.         Start -= ((tm->tm_hour * 60L + tm->tm_min) * 60L) + tm->tm_sec;
  992.     }
  993.  
  994.     Start += yyRelSeconds;
  995.     Start += RelativeMonth(Start, yyRelMonth);
  996.  
  997.     if (yyHaveDay && !yyHaveDate) {
  998.     tod = RelativeDate(Start, yyDayOrdinal, yyDayNumber);
  999.     Start += tod;
  1000.     }
  1001.  
  1002.     /* Have to do *something* with a legitimate -1 so it's distinguishable
  1003.      * from the error return value.  (Alternately could set errno on error.) */
  1004.     return Start == -1 ? 0 : Start;
  1005. }
  1006.  
  1007.  
  1008. #if    defined(TEST)
  1009.  
  1010. /* ARGSUSED */
  1011. int main(int ac, char *av[])
  1012. {
  1013.     char    buff[128];
  1014.     time_t    d;
  1015.  
  1016.     (void)printf("Enter date, or blank line to exit.\n\t> ");
  1017.     (void)fflush(stdout);
  1018.     while (gets(buff) && buff[0]) {
  1019.     d = get_date(buff, (struct timeb *)NULL);
  1020.     if (d == -1)
  1021.         (void)printf("Bad format - couldn't convert.\n");
  1022.     else
  1023.         (void)printf("%s", ctime(&d));
  1024.     (void)printf("\t> ");
  1025.     (void)fflush(stdout);
  1026.     }
  1027.  
  1028.     return 0;
  1029. }
  1030. #endif    /* defined(TEST) */
  1031.