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

Telnet服务器

开发平台:

Unix_Linux

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