home *** CD-ROM | disk | FTP | other *** search
/ Nebula 1995 August / NEBULA.mdf / SourceCode / MiscKit1.2.6 / Temp / MiscTimeAdditions / getdate.y
Encoding:
Lex Description  |  1993-09-22  |  20.8 KB  |  891 lines

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