home *** CD-ROM | disk | FTP | other *** search
/ Black Box 4 / BlackBox.cdr / progc / getdate.arj / GETDATE.Y < prev   
Text File  |  1991-08-18  |  26KB  |  863 lines

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