parsdate.y
上传用户:minyiyu
上传日期:2018-12-24
资源大小:864k
文件大小:23k
源码类别:

Telnet服务器

开发平台:

Unix_Linux

  1. %{
  2. /*
  3.  *  Project   : tin - a Usenet reader
  4.  *  Module    : parsedate.y
  5.  *  Author    : S.Bellovin & R.$alz & J.Berets & P.Eggert
  6.  *  Created   : 01-08-90
  7.  *  Updated   : 04-12-92
  8.  *  Notes     : This grammar has 6 shift/reduce conflicts.
  9.  *              Originally written by Steven M. Bellovin <smb@research.att.com> 
  10.  *              while at the University of North Carolina at Chapel Hill.  
  11.  *              Later tweaked by a couple of people on Usenet.  Completely 
  12.  *              overhauled by Rich $alz <rsalz@osf.org> and Jim Berets 
  13.  *              <jberets@bbn.com> in August, 1990. 
  14.  *              Further revised (removed obsolete constructs and cleaned up 
  15.  *              timezone names) in August, 1991, by Rich.
  16.  *              Paul Eggert <eggert@twinsun.com> helped in September 1992.
  17.  *  Revision  : 1.12
  18.  *  Copyright : This code is in the public domain and has no copyright.
  19.  */
  20. /* SUPPRESS 530 *//* Empty body for statement */
  21. /* SUPPRESS 593 on yyerrlab *//* Label was not used */
  22. /* SUPPRESS 593 on yynewstate *//* Label was not used */
  23. /* SUPPRESS 595 on yypvt *//* Automatic variable may be used before set */
  24. /*#include "tin.h"*/
  25. #include "innbbsconf.h"
  26. #include <stdio.h>
  27. #include <time.h>
  28. typedef struct _TIMEINFO 
  29. {
  30.      time_t      time;
  31.      long        usec;
  32.      long        tzone;
  33. } TIMEINFO;
  34. /*
  35. **  Get the number of elements in a fixed-size array, or a pointer just
  36. **  past the end of it.
  37. */
  38. #define SIZEOF(array) ((int)(sizeof array / sizeof array[0]))
  39. #define ENDOF(array) (&array[SIZEOF(array)])
  40. #define CTYPE(isXXXXX, c) ((isascii((c)) && isXXXXX((c))))
  41. typedef char *STRING;
  42. #define yyparse date_parse
  43. #define yylex date_lex
  44. #define yyerror date_error
  45.     /* See the LeapYears table in Convert. */
  46. #define EPOCH 1970
  47. #define END_OF_TIME 2038
  48.     /* Constants for general time calculations. */
  49. #define DST_OFFSET 1
  50. #define SECSPERDAY (24L * 60L * 60L)
  51.     /* Readability for TABLE stuff. */
  52. #define HOUR(x) (x * 60)
  53. #define LPAREN '('
  54. #define RPAREN ')'
  55. #define IS7BIT(x) ((unsigned int)(x) < 0200)
  56. /*
  57. **  An entry in the lexical lookup table.
  58. */
  59. typedef struct _TABLE {
  60.     STRING name;
  61.     int type;
  62.     time_t value;
  63. } TABLE;
  64. /*
  65. **  Daylight-savings mode:  on, off, or not yet known.
  66. */
  67. typedef enum _DSTMODE {
  68.     DSTon, DSToff, DSTmaybe
  69. } DSTMODE;
  70. /*
  71. **  Meridian:  am, pm, or 24-hour style.
  72. */
  73. typedef enum _MERIDIAN {
  74.     MERam, MERpm, MER24
  75. } MERIDIAN;
  76. /*
  77. **  Global variables.  We could get rid of most of them by using a yacc
  78. **  union, but this is more efficient.  (This routine predates the
  79. **  yacc %union construct.)
  80. */
  81. static char *yyInput;
  82. static DSTMODE yyDSTmode;
  83. static int yyHaveDate;
  84. static int yyHaveRel;
  85. static int yyHaveTime;
  86. static time_t yyTimezone;
  87. static time_t yyDay;
  88. static time_t yyHour;
  89. static time_t yyMinutes;
  90. static time_t yyMonth;
  91. static time_t yySeconds;
  92. static time_t yyYear;
  93. static MERIDIAN yyMeridian;
  94. static time_t yyRelMonth;
  95. static time_t yyRelSeconds;
  96. extern struct tm *localtime();
  97. static void date_error();
  98. %}
  99. %union {
  100.     time_t Number;
  101.     enum _MERIDIAN Meridian;
  102. }
  103. %token tDAY tDAYZONE tMERIDIAN tMONTH tMONTH_UNIT tSEC_UNIT tSNUMBER
  104. %token tUNUMBER tZONE
  105. %type <Number> tDAYZONE tMONTH tMONTH_UNIT tSEC_UNIT
  106. %type <Number> tSNUMBER tUNUMBER tZONE numzone zone
  107. %type <Meridian> tMERIDIAN o_merid
  108. %%
  109. spec : /* NULL */
  110. | spec item
  111. ;
  112. item : time {
  113.     yyHaveTime++;
  114. #if defined(lint)
  115.     /* I am compulsive about lint natterings... */
  116.     if (yyHaveTime == -1) {
  117. YYERROR;
  118.     }
  119. #endif /* defined(lint) */
  120. }
  121. | time zone {
  122.     yyHaveTime++;
  123.     yyTimezone = $2;
  124. }
  125. | date {
  126.     yyHaveDate++;
  127. }
  128. | rel {
  129.     yyHaveRel = 1;
  130. }
  131. ;
  132. time : tUNUMBER o_merid {
  133.     if ($1 < 100) {
  134. yyHour = $1;
  135. yyMinutes = 0;
  136.     }
  137.     else {
  138. yyHour = $1 / 100;
  139. yyMinutes = $1 % 100;
  140.     }
  141.     yySeconds = 0;
  142.     yyMeridian = $2;
  143. }
  144. | tUNUMBER ':' tUNUMBER o_merid {
  145.     yyHour = $1;
  146.     yyMinutes = $3;
  147.     yySeconds = 0;
  148.     yyMeridian = $4;
  149. }
  150. | tUNUMBER ':' tUNUMBER numzone {
  151.     yyHour = $1;
  152.     yyMinutes = $3;
  153.     yyTimezone = $4;
  154.     yyMeridian = MER24;
  155.     yyDSTmode = DSToff;
  156. }
  157. | tUNUMBER ':' tUNUMBER ':' tUNUMBER o_merid {
  158.     yyHour = $1;
  159.     yyMinutes = $3;
  160.     yySeconds = $5;
  161.     yyMeridian = $6;
  162. }
  163. | tUNUMBER ':' tUNUMBER ':' tUNUMBER numzone {
  164.     yyHour = $1;
  165.     yyMinutes = $3;
  166.     yySeconds = $5;
  167.     yyTimezone = $6;
  168.     yyMeridian = MER24;
  169.     yyDSTmode = DSToff;
  170. }
  171. ;
  172. zone : tZONE {
  173.     $$ = $1;
  174.     yyDSTmode = DSToff;
  175. }
  176. | tDAYZONE {
  177.     $$ = $1;
  178.     yyDSTmode = DSTon;
  179. }
  180. | tZONE numzone {
  181.     /* Only allow "GMT+300" and "GMT-0800" */
  182.     if ($1 != 0) {
  183. YYABORT;
  184.     }
  185.     $$ = $2;
  186.     yyDSTmode = DSToff;
  187. }
  188. | numzone {
  189.     $$ = $1;
  190.     yyDSTmode = DSToff;
  191. }
  192. ;
  193. numzone : tSNUMBER {
  194.     int i;
  195.                 
  196.     /* Unix and GMT and numeric timezones -- a little confusing. */
  197.     if ($1 < 0) {
  198. /* Don't work with negative modulus. */
  199. $1 = -$1;
  200.   if ($1 > 9999 || (i = $1 % 100) >= 60) {
  201.   YYABORT;
  202.   }
  203. $$ = ($1 / 100) * 60 + i;
  204.     }
  205.     else {
  206.   if ($1 > 9999 || (i = $1 % 100) >= 60) {
  207.   YYABORT;
  208.   }
  209. $$ = -(($1 / 100) * 60 + i);
  210.     }
  211. }
  212. ;
  213. date : tUNUMBER '/' tUNUMBER {
  214.     yyMonth = $1;
  215.     yyDay = $3;
  216. }
  217. | tUNUMBER '/' tUNUMBER '/' tUNUMBER {
  218.     if ($1 > 100) {
  219. yyYear = $1;
  220. yyMonth = $3;
  221. yyDay = $5;
  222.     }
  223.     else {
  224. yyMonth = $1;
  225. yyDay = $3;
  226. yyYear = $5;
  227.     }
  228. }
  229. | tMONTH tUNUMBER {
  230.     yyMonth = $1;
  231.     yyDay = $2;
  232. }
  233. | tMONTH tUNUMBER ',' tUNUMBER {
  234.     yyMonth = $1;
  235.     yyDay = $2;
  236.     yyYear = $4;
  237. }
  238. | tUNUMBER tMONTH {
  239.     yyDay = $1;
  240.     yyMonth = $2;
  241. }
  242. | tUNUMBER tMONTH tUNUMBER {
  243.     yyDay = $1;
  244.     yyMonth = $2;
  245.     yyYear = $3;
  246. }
  247. | tDAY ',' tUNUMBER tMONTH tUNUMBER {
  248.     yyDay = $3;
  249.     yyMonth = $4;
  250.     yyYear = $5;
  251. }
  252. ;
  253. rel : tSNUMBER tSEC_UNIT {
  254.     yyRelSeconds += $1 * $2;
  255. }
  256. | tUNUMBER tSEC_UNIT {
  257.     yyRelSeconds += $1 * $2;
  258. }
  259. | tSNUMBER tMONTH_UNIT {
  260.     yyRelMonth += $1 * $2;
  261. }
  262. | tUNUMBER tMONTH_UNIT {
  263.     yyRelMonth += $1 * $2;
  264. }
  265. ;
  266. o_merid : /* NULL */ {
  267.     $$ = MER24;
  268. }
  269. | tMERIDIAN {
  270.     $$ = $1;
  271. }
  272. ;
  273. %%
  274. /* Month and day table. */
  275. static TABLE MonthDayTable[] = {
  276.     { "january", tMONTH,  1 },
  277.     { "february", tMONTH,  2 },
  278.     { "march", tMONTH,  3 },
  279.     { "april", tMONTH,  4 },
  280.     { "may", tMONTH,  5 },
  281.     { "june", tMONTH,  6 },
  282.     { "july", tMONTH,  7 },
  283.     { "august", tMONTH,  8 },
  284.     { "september", tMONTH,  9 },
  285.     { "october", tMONTH, 10 },
  286.     { "november", tMONTH, 11 },
  287.     { "december", tMONTH, 12 },
  288. /* The value of the day isn't used... */
  289.     { "sunday", tDAY, 0 },
  290.     { "monday", tDAY, 0 },
  291.     { "tuesday", tDAY, 0 },
  292.     { "wednesday", tDAY, 0 },
  293.     { "thursday", tDAY, 0 },
  294.     { "friday", tDAY, 0 },
  295.     { "saturday", tDAY, 0 },
  296. };
  297. /* Time units table. */
  298. static TABLE UnitsTable[] = {
  299.     { "year", tMONTH_UNIT, 12 },
  300.     { "month", tMONTH_UNIT, 1 },
  301. #ifdef QNX4
  302.     { "week", tSEC_UNIT, 604800 },
  303.     { "day", tSEC_UNIT, 86400 },
  304. #else
  305.     { "week", tSEC_UNIT, 7 * 24 * 60 * 60 },
  306.     { "day", tSEC_UNIT, 1 * 24 * 60 * 60 },
  307. #endif
  308.     { "hour", tSEC_UNIT, 60 * 60 },
  309.     { "minute", tSEC_UNIT, 60 },
  310.     { "min", tSEC_UNIT, 60 },
  311.     { "second", tSEC_UNIT, 1 },
  312.     { "sec", tSEC_UNIT, 1 },
  313. };
  314. /* Timezone table. */
  315. static TABLE TimezoneTable[] = {
  316.     { "gmt", tZONE,     HOUR( 0) }, /* Greenwich Mean */
  317.     { "ut", tZONE,     HOUR( 0) }, /* Universal */
  318.     { "utc", tZONE,     HOUR( 0) }, /* Universal Coordinated */
  319.     { "cut", tZONE,     HOUR( 0) }, /* Coordinated Universal */
  320.     { "z", tZONE,     HOUR( 0) }, /* Greenwich Mean */
  321.     { "wet", tZONE,     HOUR( 0) }, /* Western European */
  322.     { "bst", tDAYZONE,  HOUR( 0) }, /* British Summer */
  323.     { "nst", tZONE,     HOUR(3)+30 }, /* Newfoundland Standard */
  324.     { "ndt", tDAYZONE,  HOUR(3)+30 }, /* Newfoundland Daylight */
  325.     { "ast", tZONE,     HOUR( 4) }, /* Atlantic Standard */
  326.     { "adt", tDAYZONE,  HOUR( 4) }, /* Atlantic Daylight */
  327.     { "est", tZONE,     HOUR( 5) }, /* Eastern Standard */
  328.     { "edt", tDAYZONE,  HOUR( 5) }, /* Eastern Daylight */
  329.     { "cst", tZONE,     HOUR( 6) }, /* Central Standard */
  330.     { "cdt", tDAYZONE,  HOUR( 6) }, /* Central Daylight */
  331.     { "mst", tZONE,     HOUR( 7) }, /* Mountain Standard */
  332.     { "mdt", tDAYZONE,  HOUR( 7) }, /* Mountain Daylight */
  333.     { "pst", tZONE,     HOUR( 8) }, /* Pacific Standard */
  334.     { "pdt", tDAYZONE,  HOUR( 8) }, /* Pacific Daylight */
  335.     { "yst", tZONE,     HOUR( 9) }, /* Yukon Standard */
  336.     { "ydt", tDAYZONE,  HOUR( 9) }, /* Yukon Daylight */
  337.     { "akst", tZONE,     HOUR( 9) }, /* Alaska Standard */
  338.     { "akdt", tDAYZONE,  HOUR( 9) }, /* Alaska Daylight */
  339.     { "hst", tZONE,     HOUR(10) }, /* Hawaii Standard */
  340.     { "hast", tZONE,     HOUR(10) }, /* Hawaii-Aleutian Standard */
  341.     { "hadt", tDAYZONE,  HOUR(10) }, /* Hawaii-Aleutian Daylight */
  342.     { "ces", tDAYZONE,  -HOUR(1) }, /* Central European Summer */
  343.     { "cest", tDAYZONE,  -HOUR(1) }, /* Central European Summer */
  344.     { "mez", tZONE,     -HOUR(1) }, /* Middle European */
  345.     { "mezt", tDAYZONE,  -HOUR(1) }, /* Middle European Summer */
  346.     { "cet", tZONE,     -HOUR(1) }, /* Central European */
  347.     { "met", tZONE,     -HOUR(1) }, /* Middle European */
  348.     { "eet", tZONE,     -HOUR(2) }, /* Eastern Europe */
  349.     { "msk", tZONE,     -HOUR(3) }, /* Moscow Winter */
  350.     { "msd", tDAYZONE,  -HOUR(3) }, /* Moscow Summer */
  351.     { "wast", tZONE,     -HOUR(8) }, /* West Australian Standard */
  352.     { "wadt", tDAYZONE,  -HOUR(8) }, /* West Australian Daylight */
  353.     { "hkt", tZONE,     -HOUR(8) }, /* Hong Kong */
  354.     { "cct", tZONE,     -HOUR(8) }, /* China Coast */
  355.     { "jst", tZONE,     -HOUR(9) }, /* Japan Standard */
  356.     { "kst", tZONE,     -HOUR(9) }, /* Korean Standard */
  357.     { "kdt", tZONE,     -HOUR(9) }, /* Korean Daylight */
  358.     { "cast", tZONE,     -(HOUR(9)+30) }, /* Central Australian Standard */
  359.     { "cadt", tDAYZONE,  -(HOUR(9)+30) }, /* Central Australian Daylight */
  360.     { "east", tZONE,     -HOUR(10) }, /* Eastern Australian Standard */
  361.     { "eadt", tDAYZONE,  -HOUR(10) }, /* Eastern Australian Daylight */
  362.     { "nzst", tZONE,     -HOUR(12) }, /* New Zealand Standard */
  363.     { "nzdt", tDAYZONE,  -HOUR(12) }, /* New Zealand Daylight */
  364.     /* For completeness we include the following entries. */
  365. #if 0
  366.     /* Duplicate names.  Either they conflict with a zone listed above
  367.      * (which is either more likely to be seen or just been in circulation
  368.      * longer), or they conflict with another zone in this section and
  369.      * we could not reasonably choose one over the other. */
  370.     { "fst", tZONE,     HOUR( 2) }, /* Fernando De Noronha Standard */
  371.     { "fdt", tDAYZONE,  HOUR( 2) }, /* Fernando De Noronha Daylight */
  372.     { "bst", tZONE,     HOUR( 3) }, /* Brazil Standard */
  373.     { "est", tZONE,     HOUR( 3) }, /* Eastern Standard (Brazil) */
  374.     { "edt", tDAYZONE,  HOUR( 3) }, /* Eastern Daylight (Brazil) */
  375.     { "wst", tZONE,     HOUR( 4) }, /* Western Standard (Brazil) */
  376.     { "wdt", tDAYZONE,  HOUR( 4) }, /* Western Daylight (Brazil) */
  377.     { "cst", tZONE,     HOUR( 5) }, /* Chile Standard */
  378.     { "cdt", tDAYZONE,  HOUR( 5) }, /* Chile Daylight */
  379.     { "ast", tZONE,     HOUR( 5) }, /* Acre Standard */
  380.     { "adt", tDAYZONE,  HOUR( 5) }, /* Acre Daylight */
  381.     { "cst", tZONE,     HOUR( 5) }, /* Cuba Standard */
  382.     { "cdt", tDAYZONE,  HOUR( 5) }, /* Cuba Daylight */
  383.     { "est", tZONE,     HOUR( 6) }, /* Easter Island Standard */
  384.     { "edt", tDAYZONE,  HOUR( 6) }, /* Easter Island Daylight */
  385.     { "sst", tZONE,     HOUR(11) }, /* Samoa Standard */
  386.     { "ist", tZONE,     -HOUR(2) }, /* Israel Standard */
  387.     { "idt", tDAYZONE,  -HOUR(2) }, /* Israel Daylight */
  388.     { "idt", tDAYZONE,  -(HOUR(3)+30) }, /* Iran Daylight */
  389.     { "ist", tZONE,     -(HOUR(3)+30) }, /* Iran Standard */
  390.     { "cst",  tZONE,     -HOUR(8) }, /* China Standard */
  391.     { "cdt",  tDAYZONE,  -HOUR(8) }, /* China Daylight */
  392.     { "sst",  tZONE,     -HOUR(8) }, /* Singapore Standard */
  393.     /* Dubious (e.g., not in Olson's TIMEZONE package) or obsolete. */
  394.     { "gst", tZONE,     HOUR( 3) }, /* Greenland Standard */
  395.     { "wat", tZONE,     -HOUR(1) }, /* West Africa */
  396.     { "at", tZONE,     HOUR( 2) }, /* Azores */
  397.     { "gst", tZONE,     -HOUR(10) }, /* Guam Standard */
  398.     { "nft", tZONE,     HOUR(3)+30 }, /* Newfoundland */
  399.     { "idlw", tZONE,     HOUR(12) }, /* International Date Line West */
  400.     { "mewt", tZONE,     -HOUR(1) }, /* Middle European Winter */
  401.     { "mest", tDAYZONE,  -HOUR(1) }, /* Middle European Summer */
  402.     { "swt", tZONE,     -HOUR(1) }, /* Swedish Winter */
  403.     { "sst", tDAYZONE,  -HOUR(1) }, /* Swedish Summer */
  404.     { "fwt", tZONE,     -HOUR(1) }, /* French Winter */
  405.     { "fst", tDAYZONE,  -HOUR(1) }, /* French Summer */
  406.     { "bt", tZONE,     -HOUR(3) }, /* Baghdad */
  407.     { "it", tZONE,     -(HOUR(3)+30) }, /* Iran */
  408.     { "zp4", tZONE,     -HOUR(4) }, /* USSR Zone 3 */
  409.     { "zp5", tZONE,     -HOUR(5) }, /* USSR Zone 4 */
  410.     { "ist", tZONE,     -(HOUR(5)+30) }, /* Indian Standard */
  411.     { "zp6", tZONE,     -HOUR(6) }, /* USSR Zone 5 */
  412.     { "nst", tZONE,     -HOUR(7) }, /* North Sumatra */
  413.     { "sst", tZONE,     -HOUR(7) }, /* South Sumatra */
  414.     { "jt", tZONE,     -(HOUR(7)+30) }, /* Java (3pm in Cronusland!) */
  415.     { "nzt", tZONE,     -HOUR(12) }, /* New Zealand */
  416.     { "idle", tZONE,     -HOUR(12) }, /* International Date Line East */
  417.     { "cat", tZONE,     HOUR(10) }, /* -- expired 1967 */
  418.     { "nt", tZONE,     HOUR(11) }, /* -- expired 1967 */
  419.     { "ahst", tZONE,     HOUR(10) }, /* -- expired 1983 */
  420.     { "hdt", tDAYZONE,  HOUR(10) }, /* -- expired 1986 */
  421. #endif /* 0 */
  422. };
  423. /* ARGSUSED */
  424. static void
  425. date_error(s)
  426.     char *s;
  427. {
  428.     /* NOTREACHED */
  429. }
  430. static time_t
  431. ToSeconds(Hours, Minutes, Seconds, Meridian)
  432.     time_t Hours;
  433.     time_t Minutes;
  434.     time_t Seconds;
  435.     MERIDIAN Meridian;
  436. {
  437.     if (Minutes < 0 || Minutes > 59 || Seconds < 0 || Seconds > 61)
  438. return -1;
  439.     if (Meridian == MER24) {
  440. if (Hours < 0 || Hours > 23)
  441.     return -1;
  442.     }
  443.     else {
  444. if (Hours < 1 || Hours > 12)
  445.     return -1;
  446. if (Meridian == MERpm)
  447.     Hours += 12;
  448.     }
  449.     return (Hours * 60L + Minutes) * 60L + Seconds;
  450. }
  451. static time_t
  452. Convert(Month, Day, Year, Hours, Minutes, Seconds, Meridian, dst)
  453.     time_t Month;
  454.     time_t Day;
  455.     time_t Year;
  456.     time_t Hours;
  457.     time_t Minutes;
  458.     time_t Seconds;
  459.     MERIDIAN Meridian;
  460.     DSTMODE dst;
  461. {
  462.     static int DaysNormal[13] = {
  463. 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
  464.     };
  465.     static int DaysLeap[13] = {
  466. 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
  467.     };
  468.     static int LeapYears[] = {
  469. 1972, 1976, 1980, 1984, 1988, 1992, 1996,
  470. 2000, 2004, 2008, 2012, 2016, 2020, 2024, 2028, 2032, 2036
  471.     };
  472.     register int *yp;
  473.     register int *mp;
  474.     register time_t Julian;
  475.     register int i;
  476.     time_t tod;
  477.     if (Year < 0)
  478. Year = -Year;
  479.     if (Year < 100)
  480. Year += 1900;
  481.     if (Year < EPOCH)
  482. Year += 100;
  483.     for (mp = DaysNormal, yp = LeapYears; yp < ENDOF(LeapYears); yp++)
  484. if (Year == *yp) {
  485.     mp = DaysLeap;
  486.     break;
  487. }
  488.     if (Year < EPOCH || Year > END_OF_TIME
  489.      || Month < 1 || Month > 12
  490.      /* NOSTRICT *//* conversion from long may lose accuracy */
  491.      || Day < 1 || Day > mp[(int)Month])
  492. return -1;
  493.     Julian = Day - 1 + (Year - EPOCH) * 365;
  494.     for (yp = LeapYears; yp < ENDOF(LeapYears); yp++, Julian++)
  495. if (Year <= *yp)
  496.     break;
  497.     for (i = 1; i < Month; i++)
  498. Julian += *++mp;
  499.     Julian *= SECSPERDAY;
  500.     Julian += yyTimezone * 60L;
  501.     if ((tod = ToSeconds(Hours, Minutes, Seconds, Meridian)) < 0)
  502. return -1;
  503.     Julian += tod;
  504.     tod = Julian;
  505.     if (dst == DSTon || (dst == DSTmaybe && localtime(&tod)->tm_isdst))
  506. Julian -= DST_OFFSET * 60 * 60;
  507.     return Julian;
  508. }
  509. static time_t
  510. DSTcorrect(Start, Future)
  511.     time_t Start;
  512.     time_t Future;
  513. {
  514.     time_t StartDay;
  515.     time_t FutureDay;
  516.     StartDay = (localtime(&Start)->tm_hour + 1) % 24;
  517.     FutureDay = (localtime(&Future)->tm_hour + 1) % 24;
  518.     return (Future - Start) + (StartDay - FutureDay) * DST_OFFSET * 60 * 60;
  519. }
  520. static time_t
  521. RelativeMonth(Start, RelMonth)
  522.     time_t Start;
  523.     time_t RelMonth;
  524. {
  525.     struct tm *tm;
  526.     time_t Month;
  527.     time_t Year;
  528.     tm = localtime(&Start);
  529.     Month = 12 * tm->tm_year + tm->tm_mon + RelMonth;
  530.     Year = Month / 12;
  531.     Month = Month % 12 + 1;
  532.     return DSTcorrect(Start,
  533.     Convert(Month, (time_t)tm->tm_mday, Year,
  534. (time_t)tm->tm_hour, (time_t)tm->tm_min, (time_t)tm->tm_sec,
  535. MER24, DSTmaybe));
  536. }
  537. static int
  538. LookupWord(buff, length)
  539.     char *buff;
  540.     register int length;
  541. {
  542.     register char *p;
  543.     register STRING q;
  544.     register TABLE *tp;
  545.     register int c;
  546.     p = buff;
  547.     c = p[0];
  548.     
  549.     /* See if we have an abbreviation for a month. */
  550.     if (length == 3 || (length == 4 && p[3] == '.'))
  551. for (tp = MonthDayTable; tp < ENDOF(MonthDayTable); tp++) {
  552.     q = tp->name;
  553.     if (c == q[0] && p[1] == q[1] && p[2] == q[2]) {
  554. yylval.Number = tp->value;
  555. return tp->type;
  556.     }
  557. }
  558.     else
  559. for (tp = MonthDayTable; tp < ENDOF(MonthDayTable); tp++)
  560.     if (c == tp->name[0] && strcmp(p, tp->name) == 0) {
  561. yylval.Number = tp->value;
  562. return tp->type;
  563.     }
  564.     /* Try for a timezone. */
  565.     for (tp = TimezoneTable; tp < ENDOF(TimezoneTable); tp++)
  566. if (c == tp->name[0] && p[1] == tp->name[1]
  567.  && strcmp(p, tp->name) == 0) {
  568.     yylval.Number = tp->value;
  569.     return tp->type;
  570. }
  571.     /* Try the units table. */
  572.     for (tp = UnitsTable; tp < ENDOF(UnitsTable); tp++)
  573. if (c == tp->name[0] && strcmp(p, tp->name) == 0) {
  574.     yylval.Number = tp->value;
  575.     return tp->type;
  576. }
  577.     /* Strip off any plural and try the units table again. */
  578.     if (--length > 0 && p[length] == 's') {
  579. p[length] = '';
  580. for (tp = UnitsTable; tp < ENDOF(UnitsTable); tp++)
  581.     if (c == tp->name[0] && strcmp(p, tp->name) == 0) {
  582. p[length] = 's';
  583. yylval.Number = tp->value;
  584. return tp->type;
  585.     }
  586. p[length] = 's';
  587.     }
  588.     length++;
  589.     /* Drop out any periods. */
  590.     for (p = buff, q = (STRING)buff; *q; q++)
  591. if (*q != '.')
  592.     *p++ = *q;
  593.     *p = '';
  594.     /* Try the meridians. */
  595.     if (buff[1] == 'm' && buff[2] == '') {
  596. if (buff[0] == 'a') {
  597.     yylval.Meridian = MERam;
  598.     return tMERIDIAN;
  599. }
  600. if (buff[0] == 'p') {
  601.     yylval.Meridian = MERpm;
  602.     return tMERIDIAN;
  603. }
  604.     }
  605.     /* If we saw any periods, try the timezones again. */
  606.     if (p - buff != length) {
  607. c = buff[0];    
  608. for (p = buff, tp = TimezoneTable; tp < ENDOF(TimezoneTable); tp++)
  609.     if (c == tp->name[0] && p[1] == tp->name[1]
  610.     && strcmp(p, tp->name) == 0) {
  611. yylval.Number = tp->value;
  612. return tp->type;
  613.     }
  614.     }
  615.     
  616.     /* Unknown word -- assume GMT timezone. */
  617.     yylval.Number = 0;
  618.     return tZONE;
  619. }
  620. static int
  621. date_lex()
  622. {
  623.     register char c;
  624.     register char *p;
  625.     char buff[20];
  626.     register int sign;
  627.     register int i;
  628.     register int nesting;
  629.     for ( ; ; ) {
  630. /* Get first character after the whitespace. */
  631. for ( ; ; ) {
  632.     while (CTYPE(isspace, *yyInput))
  633. yyInput++;
  634.     c = *yyInput;
  635.     /* Ignore RFC 822 comments, typically time zone names. */
  636.     if (c != LPAREN)
  637. break;
  638.     for (nesting = 1; (c = *++yyInput) != RPAREN || --nesting; )
  639. if (c == LPAREN)
  640.     nesting++;
  641. else if (!IS7BIT(c) || c == '' || c == 'r'
  642.      || (c == '\' && ((c = *++yyInput) == '' || !IS7BIT(c))))
  643.     /* Lexical error: bad comment. */
  644.     return '?';
  645.     yyInput++;
  646. }
  647. /* A number? */
  648. if (CTYPE(isdigit, c) || c == '-' || c == '+') {
  649.     if (c == '-' || c == '+') {
  650. sign = c == '-' ? -1 : 1;
  651. yyInput++;
  652. if (!CTYPE(isdigit, *yyInput))
  653.     /* Skip the plus or minus sign. */
  654.     continue;
  655.     }
  656.     else
  657. sign = 0;
  658.     for (i = 0; (c = *yyInput++) != '' && CTYPE(isdigit, c); )
  659. i = 10 * i + c - '0';
  660.     yyInput--;
  661.     yylval.Number = sign < 0 ? -i : i;
  662.     return sign ? tSNUMBER : tUNUMBER;
  663. }
  664. /* A word? */
  665. if (CTYPE(isalpha, c)) {
  666.     for (p = buff; (c = *yyInput++) == '.' || CTYPE(isalpha, c); )
  667. if (p < &buff[sizeof buff - 1])
  668.     *p++ = CTYPE(isupper, c) ? tolower(c) : c;
  669.     *p = '';
  670.     yyInput--;
  671.     return LookupWord(buff, p - buff);
  672. }
  673. return *yyInput++;
  674.     }
  675. }
  676. int
  677. GetTimeInfo(Now)
  678.     TIMEINFO *Now;
  679. {
  680.     static time_t LastTime;
  681.     static long LastTzone;
  682.     struct tm *tm;
  683. #if defined(DO_HAVE_GETTIMEOFDAY)
  684.     struct timeval tv;
  685. #endif /* defined(DO_HAVE_GETTIMEOFDAY) */
  686. #if     !defined(WITH_GM_GMTOFF)
  687. # define DONT_HAVE_TM_GMTOFF
  688. #endif
  689. #if defined(DONT_HAVE_TM_GMTOFF)
  690.     struct tm local;
  691.     struct tm gmt;
  692. #endif /* !defined(DONT_HAVE_TM_GMTOFF) */
  693.     /* Get the basic time. */
  694. #if defined(DO_HAVE_GETTIMEOFDAY)
  695.     if (gettimeofday(&tv, (struct timezone *)NULL) == -1)
  696. return -1;
  697.     Now->time = tv.tv_sec;
  698.     Now->usec = tv.tv_usec;
  699. #else
  700.     /* Can't check for -1 since that might be a time, I guess. */
  701.     (void)time(&Now->time);
  702.     Now->usec = 0;
  703. #endif /* defined(DO_HAVE_GETTIMEOFDAY) */
  704.     /* Now get the timezone if it's been an hour since the last time. */
  705.     if (Now->time - LastTime > 60 * 60) {
  706. LastTime = Now->time;
  707. if ((tm = localtime(&Now->time)) == NULL)
  708.     return -1;
  709. #if defined(DONT_HAVE_TM_GMTOFF)
  710. /* To get the timezone, compare localtime with GMT. */
  711. local = *tm;
  712. if ((tm = gmtime(&Now->time)) == NULL)
  713.     return -1;
  714. gmt = *tm;
  715. /* Assume we are never more than 24 hours away. */
  716. LastTzone = gmt.tm_yday - local.tm_yday;
  717. if (LastTzone > 1)
  718.     LastTzone = -24;
  719. else if (LastTzone < -1)
  720.     LastTzone = 24;
  721. else
  722.     LastTzone *= 24;
  723. /* Scale in the hours and minutes; ignore seconds. */
  724. LastTzone += gmt.tm_hour - local.tm_hour;
  725. LastTzone *= 60;
  726. LastTzone += gmt.tm_min - local.tm_min;
  727. #else
  728. LastTzone =  (0 - tm->tm_gmtoff) / 60;
  729. #endif /* defined(DONT_HAVE_TM_GMTOFF) */
  730.     }
  731.     Now->tzone = LastTzone;
  732.     return 0;
  733. }
  734. time_t
  735. parsedate(p, now)
  736.     char *p;
  737.     TIMEINFO *now;
  738. {
  739.     extern int date_parse();
  740.     struct tm *tm;
  741.     TIMEINFO ti;
  742.     time_t Start;
  743.     yyInput = p;
  744.     if (now == NULL) {
  745. now = &ti;
  746. (void)GetTimeInfo(&ti);
  747.     }
  748.     tm = localtime(&now->time);
  749.     yyYear = tm->tm_year;
  750.     yyMonth = tm->tm_mon + 1;
  751.     yyDay = tm->tm_mday;
  752.     yyTimezone = now->tzone;
  753.     yyDSTmode = DSTmaybe;
  754.     yyHour = 0;
  755.     yyMinutes = 0;
  756.     yySeconds = 0;
  757.     yyMeridian = MER24;
  758.     yyRelSeconds = 0;
  759.     yyRelMonth = 0;
  760.     yyHaveDate = 0;
  761.     yyHaveRel = 0;
  762.     yyHaveTime = 0;
  763.     if (date_parse() || yyHaveTime > 1 || yyHaveDate > 1)
  764. return -1;
  765.     if (yyHaveDate || yyHaveTime) {
  766. Start = Convert(yyMonth, yyDay, yyYear, yyHour, yyMinutes, yySeconds,
  767.     yyMeridian, yyDSTmode);
  768. if (Start < 0)
  769.     return -1;
  770.     }
  771.     else {
  772. Start = now->time;
  773. if (!yyHaveRel)
  774.     Start -= (tm->tm_hour * 60L + tm->tm_min) * 60L + tm->tm_sec;
  775.     }
  776.     Start += yyRelSeconds;
  777.     if (yyRelMonth)
  778. Start += RelativeMonth(Start, yyRelMonth);
  779.     /* Have to do *something* with a legitimate -1 so it's distinguishable
  780.      * from the error return value.  (Alternately could set errno on error.) */
  781.     return Start == -1 ? 0 : Start;
  782. }