home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 1 / 1840 / getdate.y next >
Encoding:
Lex Description  |  1990-12-28  |  20.3 KB  |  864 lines

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