2 static char yysccsid[] = "@(#)yaccpar 1.9 (Berkeley) 02/21/93";
7 #define yyclearin (yychar=(-1))
8 #define yyerrok (yyerrflag=0)
9 #define YYRECOVERING (yyerrflag!=0)
14 ** Originally written by Steven M. Bellovin <smb@research.att.com> while
15 ** at the University of North Carolina at Chapel Hill. Later tweaked by
16 ** a couple of people on Usenet. Completely overhauled by Rich $alz
17 ** <rsalz@osf.org> and Jim Berets <jberets@bbn.com> in August, 1990.
18 ** Further revised (removed obsolete constructs and cleaned up timezone
19 ** names) in August, 1991, by Rich. Paul Eggert <eggert@twinsun.com>
20 ** helped in September, 1992. Art Cancro <ajc@uncnsrd.mt-kisco.ny.us> cleaned
21 ** it up for ANSI C in December, 1999.
23 ** This grammar has six shift/reduce conflicts.
25 ** This code is in the public domain and has no copyright.
27 /* SUPPRESS 530 *//* Empty body for statement */
28 /* SUPPRESS 593 on yyerrlab *//* Label was not used */
29 /* SUPPRESS 593 on yynewstate *//* Label was not used */
30 /* SUPPRESS 595 on yypvt *//* Automatic variable may be used before set */
32 #include <sys/types.h>
38 #define yyparse date_parse
39 #define yylex date_lex
40 #define yyerror date_error
43 /* See the LeapYears table in Convert. */
45 #define END_OF_TIME 2038
46 /* Constants for general time calculations. */
48 #define SECSPERDAY (24L * 60L * 60L)
49 /* Readability for TABLE stuff. */
50 #define HOUR(x) (x * 60)
54 #define IS7BIT(x) ((unsigned int)(x) < 0200)
56 #define SIZEOF(array) ((int)(sizeof array / sizeof array[0]))
57 #define ENDOF(array) (&array[SIZEOF(array)])
61 ** An entry in the lexical lookup table.
63 typedef struct _TABLE {
70 ** Daylight-savings mode: on, off, or not yet known.
72 typedef enum _DSTMODE {
73 DSTon, DSToff, DSTmaybe
77 ** Meridian: am, pm, or 24-hour style.
79 typedef enum _MERIDIAN {
85 ** Global variables. We could get rid of most of them by using a yacc
86 ** union, but this is more efficient. (This routine predates the
87 ** yacc %union construct.)
90 static DSTMODE yyDSTmode;
91 static int yyHaveDate;
93 static int yyHaveTime;
94 static time_t yyTimezone;
97 static time_t yyMinutes;
98 static time_t yyMonth;
99 static time_t yySeconds;
100 static time_t yyYear;
101 static MERIDIAN yyMeridian;
102 static time_t yyRelMonth;
103 static time_t yyRelSeconds;
106 static void date_error(char *);
107 #line 99 "parsedate.y"
110 enum _MERIDIAN Meridian;
115 #define tMERIDIAN 259
117 #define tMONTH_UNIT 261
118 #define tSEC_UNIT 262
122 #define YYERRCODE 256
123 short yylhs[] = { -1,
124 0, 0, 4, 4, 4, 4, 5, 5, 5, 5,
125 5, 2, 2, 2, 2, 1, 6, 6, 6, 6,
126 6, 6, 6, 7, 7, 7, 7, 3, 3,
129 0, 2, 1, 2, 1, 1, 2, 4, 4, 6,
130 6, 1, 1, 2, 1, 1, 3, 5, 2, 4,
131 2, 3, 5, 2, 2, 2, 2, 0, 1,
133 short yydefred[] = { 1,
134 0, 0, 0, 0, 0, 2, 0, 5, 6, 0,
135 0, 26, 24, 29, 0, 27, 25, 0, 0, 7,
136 13, 16, 0, 15, 4, 0, 0, 22, 0, 0,
137 14, 0, 20, 0, 9, 8, 0, 23, 0, 18,
140 short yydgoto[] = { 1,
141 24, 25, 20, 6, 7, 8, 9,
143 short yysindex[] = { 0,
144 -239, -36, -248, -255, -47, 0, -232, 0, 0, -247,
145 -25, 0, 0, 0, -237, 0, 0, -235, -234, 0,
146 0, 0, -231, 0, 0, -226, -229, 0, -56, -11,
147 0, -227, 0, -225, 0, 0, -224, 0, -250, 0,
150 short yyrindex[] = { 0,
151 0, 0, 0, 0, 1, 0, 22, 0, 0, 0,
152 12, 0, 0, 0, 28, 0, 0, 0, 0, 0,
153 0, 0, 23, 0, 0, 0, 0, 0, 3, 14,
154 0, 0, 0, 0, 0, 0, 0, 0, 3, 0,
157 short yygindex[] = { 0,
158 -19, 0, -24, 0, 0, 0, 0,
160 #define YYTABLESIZE 291
161 short yytable[] = { 19,
162 28, 34, 28, 31, 36, 12, 13, 10, 14, 35,
163 18, 19, 22, 17, 42, 11, 26, 2, 27, 41,
164 3, 3, 12, 4, 5, 21, 28, 21, 29, 30,
165 22, 22, 23, 32, 33, 37, 38, 0, 39, 40,
166 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
167 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
168 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
169 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
170 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
171 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
172 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
173 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
174 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
175 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
176 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
177 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
178 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
179 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
180 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
181 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
182 0, 0, 14, 0, 0, 0, 22, 0, 0, 0,
183 0, 14, 15, 16, 17, 0, 0, 0, 0, 0,
184 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
185 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
186 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
187 0, 0, 0, 0, 0, 0, 0, 28, 28, 28,
188 28, 0, 28, 28, 28, 28, 28, 28, 19, 0,
189 17, 19, 0, 17, 19, 19, 17, 17, 3, 12,
190 0, 3, 12, 0, 21, 3, 12, 21, 0, 0,
193 short yycheck[] = { 47,
194 0, 58, 0, 23, 29, 261, 262, 44, 259, 29,
195 58, 0, 263, 0, 39, 264, 264, 257, 44, 39,
196 260, 0, 0, 263, 264, 258, 264, 0, 264, 264,
197 263, 263, 265, 260, 264, 47, 264, -1, 264, 264,
198 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
199 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
200 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
201 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
202 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
203 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
204 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
205 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
206 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
207 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
208 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
209 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
210 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
211 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
212 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
213 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
214 -1, -1, 259, -1, -1, -1, 263, -1, -1, -1,
215 -1, 259, 260, 261, 262, -1, -1, -1, -1, -1,
216 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
217 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
218 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
219 -1, -1, -1, -1, -1, -1, -1, 257, 258, 257,
220 258, -1, 260, 263, 264, 265, 264, 265, 257, -1,
221 257, 260, -1, 260, 263, 264, 263, 264, 257, 257,
222 -1, 260, 260, -1, 257, 264, 264, 260, -1, -1,
229 #define YYMAXTOKEN 265
232 "end-of-file",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
233 0,0,0,0,0,0,0,0,0,0,"','",0,0,"'/'",0,0,0,0,0,0,0,0,0,0,"':'",0,0,0,0,0,0,0,0,0,
234 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
235 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
236 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
237 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
238 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"tDAY","tDAYZONE",
239 "tMERIDIAN","tMONTH","tMONTH_UNIT","tSEC_UNIT","tSNUMBER","tUNUMBER","tZONE",
249 "time : tUNUMBER o_merid",
250 "time : tUNUMBER ':' tUNUMBER o_merid",
251 "time : tUNUMBER ':' tUNUMBER numzone",
252 "time : tUNUMBER ':' tUNUMBER ':' tUNUMBER o_merid",
253 "time : tUNUMBER ':' tUNUMBER ':' tUNUMBER numzone",
256 "zone : tZONE numzone",
258 "numzone : tSNUMBER",
259 "date : tUNUMBER '/' tUNUMBER",
260 "date : tUNUMBER '/' tUNUMBER '/' tUNUMBER",
261 "date : tMONTH tUNUMBER",
262 "date : tMONTH tUNUMBER ',' tUNUMBER",
263 "date : tUNUMBER tMONTH",
264 "date : tUNUMBER tMONTH tUNUMBER",
265 "date : tDAY ',' tUNUMBER tMONTH tUNUMBER",
266 "rel : tSNUMBER tSEC_UNIT",
267 "rel : tUNUMBER tSEC_UNIT",
268 "rel : tSNUMBER tMONTH_UNIT",
269 "rel : tUNUMBER tMONTH_UNIT",
271 "o_merid : tMERIDIAN",
276 #define YYMAXDEPTH YYSTACKSIZE
279 #define YYSTACKSIZE YYMAXDEPTH
281 #define YYSTACKSIZE 500
282 #define YYMAXDEPTH 500
293 short yyss[YYSTACKSIZE];
294 YYSTYPE yyvs[YYSTACKSIZE];
295 #define yystacksize YYSTACKSIZE
296 #line 286 "parsedate.y"
298 /* Month and day table. */
299 static TABLE MonthDayTable[] = {
300 { "january", tMONTH, 1 },
301 { "february", tMONTH, 2 },
302 { "march", tMONTH, 3 },
303 { "april", tMONTH, 4 },
304 { "may", tMONTH, 5 },
305 { "june", tMONTH, 6 },
306 { "july", tMONTH, 7 },
307 { "august", tMONTH, 8 },
308 { "september", tMONTH, 9 },
309 { "october", tMONTH, 10 },
310 { "november", tMONTH, 11 },
311 { "december", tMONTH, 12 },
312 /* The value of the day isn't used... */
313 { "sunday", tDAY, 0 },
314 { "monday", tDAY, 0 },
315 { "tuesday", tDAY, 0 },
316 { "wednesday", tDAY, 0 },
317 { "thursday", tDAY, 0 },
318 { "friday", tDAY, 0 },
319 { "saturday", tDAY, 0 },
322 /* Time units table. */
323 static TABLE UnitsTable[] = {
324 { "year", tMONTH_UNIT, 12 },
325 { "month", tMONTH_UNIT, 1 },
326 { "week", tSEC_UNIT, 7L * 24 * 60 * 60 },
327 { "day", tSEC_UNIT, 1L * 24 * 60 * 60 },
328 { "hour", tSEC_UNIT, 60 * 60 },
329 { "minute", tSEC_UNIT, 60 },
330 { "min", tSEC_UNIT, 60 },
331 { "second", tSEC_UNIT, 1 },
332 { "sec", tSEC_UNIT, 1 },
335 /* Timezone table. */
336 static TABLE TimezoneTable[] = {
337 { "gmt", tZONE, HOUR( 0) }, /* Greenwich Mean */
338 { "ut", tZONE, HOUR( 0) }, /* Universal */
339 { "utc", tZONE, HOUR( 0) }, /* Universal Coordinated */
340 { "cut", tZONE, HOUR( 0) }, /* Coordinated Universal */
341 { "z", tZONE, HOUR( 0) }, /* Greenwich Mean */
342 { "wet", tZONE, HOUR( 0) }, /* Western European */
343 { "bst", tDAYZONE, HOUR( 0) }, /* British Summer */
344 { "nst", tZONE, HOUR(3)+30 }, /* Newfoundland Standard */
345 { "ndt", tDAYZONE, HOUR(3)+30 }, /* Newfoundland Daylight */
346 { "ast", tZONE, HOUR( 4) }, /* Atlantic Standard */
347 { "adt", tDAYZONE, HOUR( 4) }, /* Atlantic Daylight */
348 { "est", tZONE, HOUR( 5) }, /* Eastern Standard */
349 { "edt", tDAYZONE, HOUR( 5) }, /* Eastern Daylight */
350 { "cst", tZONE, HOUR( 6) }, /* Central Standard */
351 { "cdt", tDAYZONE, HOUR( 6) }, /* Central Daylight */
352 { "mst", tZONE, HOUR( 7) }, /* Mountain Standard */
353 { "mdt", tDAYZONE, HOUR( 7) }, /* Mountain Daylight */
354 { "pst", tZONE, HOUR( 8) }, /* Pacific Standard */
355 { "pdt", tDAYZONE, HOUR( 8) }, /* Pacific Daylight */
356 { "yst", tZONE, HOUR( 9) }, /* Yukon Standard */
357 { "ydt", tDAYZONE, HOUR( 9) }, /* Yukon Daylight */
358 { "akst", tZONE, HOUR( 9) }, /* Alaska Standard */
359 { "akdt", tDAYZONE, HOUR( 9) }, /* Alaska Daylight */
360 { "hst", tZONE, HOUR(10) }, /* Hawaii Standard */
361 { "hast", tZONE, HOUR(10) }, /* Hawaii-Aleutian Standard */
362 { "hadt", tDAYZONE, HOUR(10) }, /* Hawaii-Aleutian Daylight */
363 { "ces", tDAYZONE, -HOUR(1) }, /* Central European Summer */
364 { "cest", tDAYZONE, -HOUR(1) }, /* Central European Summer */
365 { "mez", tZONE, -HOUR(1) }, /* Middle European */
366 { "mezt", tDAYZONE, -HOUR(1) }, /* Middle European Summer */
367 { "cet", tZONE, -HOUR(1) }, /* Central European */
368 { "met", tZONE, -HOUR(1) }, /* Middle European */
369 { "eet", tZONE, -HOUR(2) }, /* Eastern Europe */
370 { "msk", tZONE, -HOUR(3) }, /* Moscow Winter */
371 { "msd", tDAYZONE, -HOUR(3) }, /* Moscow Summer */
372 { "wast", tZONE, -HOUR(8) }, /* West Australian Standard */
373 { "wadt", tDAYZONE, -HOUR(8) }, /* West Australian Daylight */
374 { "hkt", tZONE, -HOUR(8) }, /* Hong Kong */
375 { "cct", tZONE, -HOUR(8) }, /* China Coast */
376 { "jst", tZONE, -HOUR(9) }, /* Japan Standard */
377 { "kst", tZONE, -HOUR(9) }, /* Korean Standard */
378 { "kdt", tZONE, -HOUR(9) }, /* Korean Daylight */
379 { "cast", tZONE, -(HOUR(9)+30) }, /* Central Australian Standard */
380 { "cadt", tDAYZONE, -(HOUR(9)+30) }, /* Central Australian Daylight */
381 { "east", tZONE, -HOUR(10) }, /* Eastern Australian Standard */
382 { "eadt", tDAYZONE, -HOUR(10) }, /* Eastern Australian Daylight */
383 { "nzst", tZONE, -HOUR(12) }, /* New Zealand Standard */
384 { "nzdt", tDAYZONE, -HOUR(12) }, /* New Zealand Daylight */
386 /* For completeness we include the following entries. */
389 /* Duplicate names. Either they conflict with a zone listed above
390 * (which is either more likely to be seen or just been in circulation
391 * longer), or they conflict with another zone in this section and
392 * we could not reasonably choose one over the other. */
393 { "fst", tZONE, HOUR( 2) }, /* Fernando De Noronha Standard */
394 { "fdt", tDAYZONE, HOUR( 2) }, /* Fernando De Noronha Daylight */
395 { "bst", tZONE, HOUR( 3) }, /* Brazil Standard */
396 { "est", tZONE, HOUR( 3) }, /* Eastern Standard (Brazil) */
397 { "edt", tDAYZONE, HOUR( 3) }, /* Eastern Daylight (Brazil) */
398 { "wst", tZONE, HOUR( 4) }, /* Western Standard (Brazil) */
399 { "wdt", tDAYZONE, HOUR( 4) }, /* Western Daylight (Brazil) */
400 { "cst", tZONE, HOUR( 5) }, /* Chile Standard */
401 { "cdt", tDAYZONE, HOUR( 5) }, /* Chile Daylight */
402 { "ast", tZONE, HOUR( 5) }, /* Acre Standard */
403 { "adt", tDAYZONE, HOUR( 5) }, /* Acre Daylight */
404 { "cst", tZONE, HOUR( 5) }, /* Cuba Standard */
405 { "cdt", tDAYZONE, HOUR( 5) }, /* Cuba Daylight */
406 { "est", tZONE, HOUR( 6) }, /* Easter Island Standard */
407 { "edt", tDAYZONE, HOUR( 6) }, /* Easter Island Daylight */
408 { "sst", tZONE, HOUR(11) }, /* Samoa Standard */
409 { "ist", tZONE, -HOUR(2) }, /* Israel Standard */
410 { "idt", tDAYZONE, -HOUR(2) }, /* Israel Daylight */
411 { "idt", tDAYZONE, -(HOUR(3)+30) }, /* Iran Daylight */
412 { "ist", tZONE, -(HOUR(3)+30) }, /* Iran Standard */
413 { "cst", tZONE, -HOUR(8) }, /* China Standard */
414 { "cdt", tDAYZONE, -HOUR(8) }, /* China Daylight */
415 { "sst", tZONE, -HOUR(8) }, /* Singapore Standard */
417 /* Dubious (e.g., not in Olson's TIMEZONE package) or obsolete. */
418 { "gst", tZONE, HOUR( 3) }, /* Greenland Standard */
419 { "wat", tZONE, -HOUR(1) }, /* West Africa */
420 { "at", tZONE, HOUR( 2) }, /* Azores */
421 { "gst", tZONE, -HOUR(10) }, /* Guam Standard */
422 { "nft", tZONE, HOUR(3)+30 }, /* Newfoundland */
423 { "idlw", tZONE, HOUR(12) }, /* International Date Line West */
424 { "mewt", tZONE, -HOUR(1) }, /* Middle European Winter */
425 { "mest", tDAYZONE, -HOUR(1) }, /* Middle European Summer */
426 { "swt", tZONE, -HOUR(1) }, /* Swedish Winter */
427 { "sst", tDAYZONE, -HOUR(1) }, /* Swedish Summer */
428 { "fwt", tZONE, -HOUR(1) }, /* French Winter */
429 { "fst", tDAYZONE, -HOUR(1) }, /* French Summer */
430 { "bt", tZONE, -HOUR(3) }, /* Baghdad */
431 { "it", tZONE, -(HOUR(3)+30) }, /* Iran */
432 { "zp4", tZONE, -HOUR(4) }, /* USSR Zone 3 */
433 { "zp5", tZONE, -HOUR(5) }, /* USSR Zone 4 */
434 { "ist", tZONE, -(HOUR(5)+30) }, /* Indian Standard */
435 { "zp6", tZONE, -HOUR(6) }, /* USSR Zone 5 */
436 { "nst", tZONE, -HOUR(7) }, /* North Sumatra */
437 { "sst", tZONE, -HOUR(7) }, /* South Sumatra */
438 { "jt", tZONE, -(HOUR(7)+30) }, /* Java (3pm in Cronusland!) */
439 { "nzt", tZONE, -HOUR(12) }, /* New Zealand */
440 { "idle", tZONE, -HOUR(12) }, /* International Date Line East */
441 { "cat", tZONE, HOUR(10) }, /* -- expired 1967 */
442 { "nt", tZONE, HOUR(11) }, /* -- expired 1967 */
443 { "ahst", tZONE, HOUR(10) }, /* -- expired 1983 */
444 { "hdt", tDAYZONE, HOUR(10) }, /* -- expired 1986 */
459 ToSeconds(time_t Hours, time_t Minutes, time_t Seconds, MERIDIAN Meridian)
461 if (Minutes < 0 || Minutes > 59 || Seconds < 0 || Seconds > 61)
463 if (Meridian == MER24) {
464 if (Hours < 0 || Hours > 23)
468 if (Hours < 1 || Hours > 12)
472 if (Meridian == MERpm)
475 return (Hours * 60L + Minutes) * 60L + Seconds;
480 Convert(time_t Month, time_t Day, time_t Year,
481 time_t Hours, time_t Minutes, time_t Seconds,
482 MERIDIAN Meridian, DSTMODE dst)
484 static int DaysNormal[13] = {
485 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
487 static int DaysLeap[13] = {
488 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
490 static int LeapYears[] = {
491 1972, 1976, 1980, 1984, 1988, 1992, 1996,
492 2000, 2004, 2008, 2012, 2016, 2020, 2024, 2028, 2032, 2036
496 register time_t Julian;
506 for (mp = DaysNormal, yp = LeapYears; yp < ENDOF(LeapYears); yp++)
511 if (Year < EPOCH || Year > END_OF_TIME
512 || Month < 1 || Month > 12
513 /* NOSTRICT *//* conversion from long may lose accuracy */
514 || Day < 1 || Day > mp[(int)Month])
517 Julian = Day - 1 + (Year - EPOCH) * 365;
518 for (yp = LeapYears; yp < ENDOF(LeapYears); yp++, Julian++)
521 for (i = 1; i < Month; i++)
523 Julian *= SECSPERDAY;
524 Julian += yyTimezone * 60L;
525 if ((tod = ToSeconds(Hours, Minutes, Seconds, Meridian)) < 0)
529 if (dst == DSTon || (dst == DSTmaybe && localtime(&tod)->tm_isdst))
530 Julian -= DST_OFFSET * 60L * 60L;
536 DSTcorrect(time_t Start, time_t Future)
541 StartDay = (localtime(&Start)->tm_hour + 1) % 24;
542 FutureDay = (localtime(&Future)->tm_hour + 1) % 24;
543 return (Future - Start) + (StartDay - FutureDay) * DST_OFFSET * 60L * 60L;
548 RelativeMonth(time_t Start, time_t RelMonth)
554 tm = localtime(&Start);
555 Month = 12 * tm->tm_year + tm->tm_mon + RelMonth;
557 Month = Month % 12 + 1;
558 return DSTcorrect(Start,
559 Convert(Month, (time_t)tm->tm_mday, Year,
560 (time_t)tm->tm_hour, (time_t)tm->tm_min, (time_t)tm->tm_sec,
566 LookupWord(char *buff, register int length)
576 /* See if we have an abbreviation for a month. */
577 if (length == 3 || (length == 4 && p[3] == '.'))
578 for (tp = MonthDayTable; tp < ENDOF(MonthDayTable); tp++) {
580 if (c == q[0] && p[1] == q[1] && p[2] == q[2]) {
581 yylval.Number = tp->value;
586 for (tp = MonthDayTable; tp < ENDOF(MonthDayTable); tp++)
587 if (c == tp->name[0] && strcmp(p, tp->name) == 0) {
588 yylval.Number = tp->value;
592 /* Try for a timezone. */
593 for (tp = TimezoneTable; tp < ENDOF(TimezoneTable); tp++)
594 if (c == tp->name[0] && p[1] == tp->name[1]
595 && strcmp(p, tp->name) == 0) {
596 yylval.Number = tp->value;
600 /* Try the units table. */
601 for (tp = UnitsTable; tp < ENDOF(UnitsTable); tp++)
602 if (c == tp->name[0] && strcmp(p, tp->name) == 0) {
603 yylval.Number = tp->value;
607 /* Strip off any plural and try the units table again. */
608 if (--length > 0 && p[length] == 's') {
610 for (tp = UnitsTable; tp < ENDOF(UnitsTable); tp++)
611 if (c == tp->name[0] && strcmp(p, tp->name) == 0) {
613 yylval.Number = tp->value;
620 /* Drop out any periods. */
621 for (p = buff, q = (char*)buff; *q; q++)
626 /* Try the meridians. */
627 if (buff[1] == 'm' && buff[2] == '\0') {
628 if (buff[0] == 'a') {
629 yylval.Meridian = MERam;
632 if (buff[0] == 'p') {
633 yylval.Meridian = MERpm;
638 /* If we saw any periods, try the timezones again. */
639 if (p - buff != length) {
641 for (p = buff, tp = TimezoneTable; tp < ENDOF(TimezoneTable); tp++)
642 if (c == tp->name[0] && p[1] == tp->name[1]
643 && strcmp(p, tp->name) == 0) {
644 yylval.Number = tp->value;
649 /* Unknown word -- assume GMT timezone. */
663 register int nesting;
666 /* Get first character after the whitespace. */
668 while (isspace(*yyInput))
672 /* Ignore RFC 822 comments, typically time zone names. */
675 for (nesting = 1; (c = *++yyInput) != RPAREN || --nesting; )
678 else if (!IS7BIT(c) || c == '\0' || c == '\r'
679 || (c == '\\' && ((c = *++yyInput) == '\0' || !IS7BIT(c))))
680 /* Lexical error: bad comment. */
686 if (isdigit(c) || c == '-' || c == '+') {
687 if (c == '-' || c == '+') {
688 sign = c == '-' ? -1 : 1;
690 if (!isdigit(*yyInput))
691 /* Skip the plus or minus sign. */
696 for (i = 0; (c = *yyInput++) != '\0' && isdigit(c); )
697 i = 10 * i + c - '0';
699 yylval.Number = sign < 0 ? -i : i;
700 return sign ? tSNUMBER : tUNUMBER;
705 for (p = buff; (c = *yyInput++) == '.' || isalpha(c); )
706 if (p < &buff[sizeof buff - 1])
707 *p++ = isupper(c) ? tolower(c) : c;
710 return LookupWord(buff, p - buff);
721 extern int date_parse(void);
730 yyDSTmode = DSTmaybe;
741 if (date_parse() || yyHaveTime > 1 || yyHaveDate > 1)
744 if (yyHaveDate || yyHaveTime) {
745 Start = Convert(yyMonth, yyDay, yyYear, yyHour, yyMinutes, yySeconds,
746 yyMeridian, yyDSTmode);
753 Start += yyRelSeconds;
755 Start += RelativeMonth(Start, yyRelMonth);
757 /* Have to do *something* with a legitimate -1 so it's distinguishable
758 * from the error return value. (Alternately could set errno on error.) */
759 return Start == -1 ? 0 : Start;
771 main(int ac, char *av[])
780 (void)printf("Enter date, or blank line to exit.\n\t> ");
782 (void)printf("\t> ");
783 (void)fflush(stdout);
784 if (gets(buff) == NULL || buff[0] == '\n')
787 if (strcmp(buff, "yydebug") == 0) {
789 printf("yydebug = %s\n", yydebug ? "on" : "off");
793 d = parsedate(buff, (TIMEINFO *)NULL);
795 (void)printf("Bad format - couldn't convert.\n");
797 (void)printf("%s", ctime(&d));
805 #define YYABORT goto yyabort
806 #define YYREJECT goto yyabort
807 #define YYACCEPT goto yyaccept
808 #define YYERROR goto yyerrlab
812 register int yym, yyn, yystate;
815 extern char *getenv();
817 if (yys = getenv("YYDEBUG"))
820 if (yyn >= '0' && yyn <= '9')
831 *yyssp = yystate = 0;
834 if (yyn = yydefred[yystate]) goto yyreduce;
837 if ((yychar = yylex()) < 0) yychar = 0;
842 if (yychar <= YYMAXTOKEN) yys = yyname[yychar];
843 if (!yys) yys = "illegal-symbol";
844 printf("%sdebug: state %d, reading %d (%s)\n",
845 YYPREFIX, yystate, yychar, yys);
849 if ((yyn = yysindex[yystate]) && (yyn += yychar) >= 0 &&
850 yyn <= YYTABLESIZE && yycheck[yyn] == yychar)
854 printf("%sdebug: state %d, shifting to state %d\n",
855 YYPREFIX, yystate, yytable[yyn]);
857 if (yyssp >= yyss + yystacksize - 1)
861 *++yyssp = yystate = yytable[yyn];
864 if (yyerrflag > 0) --yyerrflag;
867 if ((yyn = yyrindex[yystate]) && (yyn += yychar) >= 0 &&
868 yyn <= YYTABLESIZE && yycheck[yyn] == yychar)
873 if (yyerrflag) goto yyinrecovery;
878 yyerror("syntax error");
890 if ((yyn = yysindex[*yyssp]) && (yyn += YYERRCODE) >= 0 &&
891 yyn <= YYTABLESIZE && yycheck[yyn] == YYERRCODE)
895 printf("%sdebug: state %d, error recovery shifting\
896 to state %d\n", YYPREFIX, *yyssp, yytable[yyn]);
898 if (yyssp >= yyss + yystacksize - 1)
902 *++yyssp = yystate = yytable[yyn];
910 printf("%sdebug: error recovery discarding state %d\n",
913 if (yyssp <= yyss) goto yyabort;
921 if (yychar == 0) goto yyabort;
926 if (yychar <= YYMAXTOKEN) yys = yyname[yychar];
927 if (!yys) yys = "illegal-symbol";
928 printf("%sdebug: state %d, error recovery discards token %d (%s)\n",
929 YYPREFIX, yystate, yychar, yys);
938 printf("%sdebug: state %d, reducing by rule %d (%s)\n",
939 YYPREFIX, yystate, yyn, yyrule[yyn]);
942 yyval = yyvsp[1-yym];
946 #line 117 "parsedate.y"
950 /* I am compulsive about lint natterings... */
951 if (yyHaveTime == -1) {
958 #line 126 "parsedate.y"
961 yyTimezone = yyvsp[0].Number;
965 #line 130 "parsedate.y"
971 #line 133 "parsedate.y"
977 #line 138 "parsedate.y"
979 if (yyvsp[-1].Number < 100) {
980 yyHour = yyvsp[-1].Number;
984 yyHour = yyvsp[-1].Number / 100;
985 yyMinutes = yyvsp[-1].Number % 100;
988 yyMeridian = yyvsp[0].Meridian;
992 #line 150 "parsedate.y"
994 yyHour = yyvsp[-3].Number;
995 yyMinutes = yyvsp[-1].Number;
997 yyMeridian = yyvsp[0].Meridian;
1001 #line 156 "parsedate.y"
1003 yyHour = yyvsp[-3].Number;
1004 yyMinutes = yyvsp[-1].Number;
1005 yyTimezone = yyvsp[0].Number;
1011 #line 163 "parsedate.y"
1013 yyHour = yyvsp[-5].Number;
1014 yyMinutes = yyvsp[-3].Number;
1015 yySeconds = yyvsp[-1].Number;
1016 yyMeridian = yyvsp[0].Meridian;
1020 #line 169 "parsedate.y"
1022 yyHour = yyvsp[-5].Number;
1023 yyMinutes = yyvsp[-3].Number;
1024 yySeconds = yyvsp[-1].Number;
1025 yyTimezone = yyvsp[0].Number;
1031 #line 179 "parsedate.y"
1033 yyval.Number = yyvsp[0].Number;
1038 #line 183 "parsedate.y"
1040 yyval.Number = yyvsp[0].Number;
1045 #line 187 "parsedate.y"
1047 /* Only allow "GMT+300" and "GMT-0800" */
1048 if (yyvsp[-1].Number != 0) {
1051 yyval.Number = yyvsp[0].Number;
1056 #line 195 "parsedate.y"
1058 yyval.Number = yyvsp[0].Number;
1063 #line 201 "parsedate.y"
1067 /* Unix and GMT and numeric timezones -- a little confusing. */
1068 if (yyvsp[0].Number < 0) {
1069 /* Don't work with negative modulus. */
1070 yyvsp[0].Number = -yyvsp[0].Number;
1071 if (yyvsp[0].Number > 9999 || (i = yyvsp[0].Number % 100) >= 60) {
1074 yyval.Number = (yyvsp[0].Number / 100) * 60 + i;
1077 if (yyvsp[0].Number > 9999 || (i = yyvsp[0].Number % 100) >= 60) {
1080 yyval.Number = -((yyvsp[0].Number / 100) * 60 + i);
1085 #line 222 "parsedate.y"
1087 yyMonth = yyvsp[-2].Number;
1088 yyDay = yyvsp[0].Number;
1092 #line 226 "parsedate.y"
1094 if (yyvsp[-4].Number > 100) {
1095 yyYear = yyvsp[-4].Number;
1096 yyMonth = yyvsp[-2].Number;
1097 yyDay = yyvsp[0].Number;
1100 yyMonth = yyvsp[-4].Number;
1101 yyDay = yyvsp[-2].Number;
1102 yyYear = yyvsp[0].Number;
1107 #line 238 "parsedate.y"
1109 yyMonth = yyvsp[-1].Number;
1110 yyDay = yyvsp[0].Number;
1114 #line 242 "parsedate.y"
1116 yyMonth = yyvsp[-3].Number;
1117 yyDay = yyvsp[-2].Number;
1118 yyYear = yyvsp[0].Number;
1122 #line 247 "parsedate.y"
1124 yyDay = yyvsp[-1].Number;
1125 yyMonth = yyvsp[0].Number;
1129 #line 251 "parsedate.y"
1131 yyDay = yyvsp[-2].Number;
1132 yyMonth = yyvsp[-1].Number;
1133 yyYear = yyvsp[0].Number;
1137 #line 256 "parsedate.y"
1139 yyDay = yyvsp[-2].Number;
1140 yyMonth = yyvsp[-1].Number;
1141 yyYear = yyvsp[0].Number;
1145 #line 263 "parsedate.y"
1147 yyRelSeconds += yyvsp[-1].Number * yyvsp[0].Number;
1151 #line 266 "parsedate.y"
1153 yyRelSeconds += yyvsp[-1].Number * yyvsp[0].Number;
1157 #line 269 "parsedate.y"
1159 yyRelMonth += yyvsp[-1].Number * yyvsp[0].Number;
1163 #line 272 "parsedate.y"
1165 yyRelMonth += yyvsp[-1].Number * yyvsp[0].Number;
1169 #line 277 "parsedate.y"
1171 yyval.Meridian = MER24;
1175 #line 280 "parsedate.y"
1177 yyval.Meridian = yyvsp[0].Meridian;
1180 #line 1181 "y.tab.c"
1186 if (yystate == 0 && yym == 0)
1190 printf("%sdebug: after reduction, shifting from state 0 to\
1191 state %d\n", YYPREFIX, YYFINAL);
1198 if ((yychar = yylex()) < 0) yychar = 0;
1203 if (yychar <= YYMAXTOKEN) yys = yyname[yychar];
1204 if (!yys) yys = "illegal-symbol";
1205 printf("%sdebug: state %d, reading %d (%s)\n",
1206 YYPREFIX, YYFINAL, yychar, yys);
1210 if (yychar == 0) goto yyaccept;
1213 if ((yyn = yygindex[yym]) && (yyn += yystate) >= 0 &&
1214 yyn <= YYTABLESIZE && yycheck[yyn] == yystate)
1215 yystate = yytable[yyn];
1217 yystate = yydgoto[yym];
1220 printf("%sdebug: after reduction, shifting from state %d \
1221 to state %d\n", YYPREFIX, *yyssp, yystate);
1223 if (yyssp >= yyss + yystacksize - 1)
1231 yyerror("yacc stack overflow");