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>
35 #include "parsedate.h"
39 #define yyparse date_parse
40 #define yylex date_lex
41 #define yyerror date_error
44 /* See the LeapYears table in Convert. */
46 #define END_OF_TIME 2038
47 /* Constants for general time calculations. */
49 #define SECSPERDAY (24L * 60L * 60L)
50 /* Readability for TABLE stuff. */
51 #define HOUR(x) (x * 60)
55 #define IS7BIT(x) ((unsigned int)(x) < 0200)
57 #define SIZEOF(array) ((int)(sizeof array / sizeof array[0]))
58 #define ENDOF(array) (&array[SIZEOF(array)])
62 ** An entry in the lexical lookup table.
64 typedef struct _TABLE {
71 ** Daylight-savings mode: on, off, or not yet known.
73 typedef enum _DSTMODE {
74 DSTon, DSToff, DSTmaybe
78 ** Meridian: am, pm, or 24-hour style.
80 typedef enum _MERIDIAN {
86 ** Global variables. We could get rid of most of them by using a yacc
87 ** union, but this is more efficient. (This routine predates the
88 ** yacc %union construct.)
91 static DSTMODE yyDSTmode;
92 static int yyHaveDate;
94 static int yyHaveTime;
95 static time_t yyTimezone;
98 static time_t yyMinutes;
99 static time_t yyMonth;
100 static time_t yySeconds;
101 static time_t yyYear;
102 static MERIDIAN yyMeridian;
103 static time_t yyRelMonth;
104 static time_t yyRelSeconds;
107 static void date_error(char *);
108 #line 100 "parsedate.y"
111 enum _MERIDIAN Meridian;
116 #define tMERIDIAN 259
118 #define tMONTH_UNIT 261
119 #define tSEC_UNIT 262
123 #define YYERRCODE 256
124 short yylhs[] = { -1,
125 0, 0, 4, 4, 4, 4, 5, 5, 5, 5,
126 5, 2, 2, 2, 2, 1, 6, 6, 6, 6,
127 6, 6, 6, 7, 7, 7, 7, 3, 3,
130 0, 2, 1, 2, 1, 1, 2, 4, 4, 6,
131 6, 1, 1, 2, 1, 1, 3, 5, 2, 4,
132 2, 3, 5, 2, 2, 2, 2, 0, 1,
134 short yydefred[] = { 1,
135 0, 0, 0, 0, 0, 2, 0, 5, 6, 0,
136 0, 26, 24, 29, 0, 27, 25, 0, 0, 7,
137 13, 16, 0, 15, 4, 0, 0, 22, 0, 0,
138 14, 0, 20, 0, 9, 8, 0, 23, 0, 18,
141 short yydgoto[] = { 1,
142 24, 25, 20, 6, 7, 8, 9,
144 short yysindex[] = { 0,
145 -239, -36, -248, -255, -47, 0, -232, 0, 0, -247,
146 -25, 0, 0, 0, -237, 0, 0, -235, -234, 0,
147 0, 0, -231, 0, 0, -226, -229, 0, -56, -11,
148 0, -227, 0, -225, 0, 0, -224, 0, -250, 0,
151 short yyrindex[] = { 0,
152 0, 0, 0, 0, 1, 0, 22, 0, 0, 0,
153 12, 0, 0, 0, 28, 0, 0, 0, 0, 0,
154 0, 0, 23, 0, 0, 0, 0, 0, 3, 14,
155 0, 0, 0, 0, 0, 0, 0, 0, 3, 0,
158 short yygindex[] = { 0,
159 -19, 0, -24, 0, 0, 0, 0,
161 #define YYTABLESIZE 291
162 short yytable[] = { 19,
163 28, 34, 28, 31, 36, 12, 13, 10, 14, 35,
164 18, 19, 22, 17, 42, 11, 26, 2, 27, 41,
165 3, 3, 12, 4, 5, 21, 28, 21, 29, 30,
166 22, 22, 23, 32, 33, 37, 38, 0, 39, 40,
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, 0, 0, 0, 0, 0, 0, 0, 0,
183 0, 0, 14, 0, 0, 0, 22, 0, 0, 0,
184 0, 14, 15, 16, 17, 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, 0, 0, 0,
188 0, 0, 0, 0, 0, 0, 0, 28, 28, 28,
189 28, 0, 28, 28, 28, 28, 28, 28, 19, 0,
190 17, 19, 0, 17, 19, 19, 17, 17, 3, 12,
191 0, 3, 12, 0, 21, 3, 12, 21, 0, 0,
194 short yycheck[] = { 47,
195 0, 58, 0, 23, 29, 261, 262, 44, 259, 29,
196 58, 0, 263, 0, 39, 264, 264, 257, 44, 39,
197 260, 0, 0, 263, 264, 258, 264, 0, 264, 264,
198 263, 263, 265, 260, 264, 47, 264, -1, 264, 264,
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, -1, -1, -1, -1, -1, -1, -1, -1,
215 -1, -1, 259, -1, -1, -1, 263, -1, -1, -1,
216 -1, 259, 260, 261, 262, -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, -1, -1, -1,
220 -1, -1, -1, -1, -1, -1, -1, 257, 258, 257,
221 258, -1, 260, 263, 264, 265, 264, 265, 257, -1,
222 257, 260, -1, 260, 263, 264, 263, 264, 257, 257,
223 -1, 260, 260, -1, 257, 264, 264, 260, -1, -1,
230 #define YYMAXTOKEN 265
233 "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,
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,
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,0,0,0,0,0,0,0,0,0,0,0,
239 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",
240 "tMERIDIAN","tMONTH","tMONTH_UNIT","tSEC_UNIT","tSNUMBER","tUNUMBER","tZONE",
250 "time : tUNUMBER o_merid",
251 "time : tUNUMBER ':' tUNUMBER o_merid",
252 "time : tUNUMBER ':' tUNUMBER numzone",
253 "time : tUNUMBER ':' tUNUMBER ':' tUNUMBER o_merid",
254 "time : tUNUMBER ':' tUNUMBER ':' tUNUMBER numzone",
257 "zone : tZONE numzone",
259 "numzone : tSNUMBER",
260 "date : tUNUMBER '/' tUNUMBER",
261 "date : tUNUMBER '/' tUNUMBER '/' tUNUMBER",
262 "date : tMONTH tUNUMBER",
263 "date : tMONTH tUNUMBER ',' tUNUMBER",
264 "date : tUNUMBER tMONTH",
265 "date : tUNUMBER tMONTH tUNUMBER",
266 "date : tDAY ',' tUNUMBER tMONTH tUNUMBER",
267 "rel : tSNUMBER tSEC_UNIT",
268 "rel : tUNUMBER tSEC_UNIT",
269 "rel : tSNUMBER tMONTH_UNIT",
270 "rel : tUNUMBER tMONTH_UNIT",
272 "o_merid : tMERIDIAN",
277 #define YYMAXDEPTH YYSTACKSIZE
280 #define YYSTACKSIZE YYMAXDEPTH
282 #define YYSTACKSIZE 500
283 #define YYMAXDEPTH 500
294 short yyss[YYSTACKSIZE];
295 YYSTYPE yyvs[YYSTACKSIZE];
296 #define yystacksize YYSTACKSIZE
297 #line 287 "parsedate.y"
299 /* Month and day table. */
300 static TABLE MonthDayTable[] = {
301 { "january", tMONTH, 1 },
302 { "february", tMONTH, 2 },
303 { "march", tMONTH, 3 },
304 { "april", tMONTH, 4 },
305 { "may", tMONTH, 5 },
306 { "june", tMONTH, 6 },
307 { "july", tMONTH, 7 },
308 { "august", tMONTH, 8 },
309 { "september", tMONTH, 9 },
310 { "october", tMONTH, 10 },
311 { "november", tMONTH, 11 },
312 { "december", tMONTH, 12 },
313 /* The value of the day isn't used... */
314 { "sunday", tDAY, 0 },
315 { "monday", tDAY, 0 },
316 { "tuesday", tDAY, 0 },
317 { "wednesday", tDAY, 0 },
318 { "thursday", tDAY, 0 },
319 { "friday", tDAY, 0 },
320 { "saturday", tDAY, 0 },
323 /* Time units table. */
324 static TABLE UnitsTable[] = {
325 { "year", tMONTH_UNIT, 12 },
326 { "month", tMONTH_UNIT, 1 },
327 { "week", tSEC_UNIT, 7L * 24 * 60 * 60 },
328 { "day", tSEC_UNIT, 1L * 24 * 60 * 60 },
329 { "hour", tSEC_UNIT, 60 * 60 },
330 { "minute", tSEC_UNIT, 60 },
331 { "min", tSEC_UNIT, 60 },
332 { "second", tSEC_UNIT, 1 },
333 { "sec", tSEC_UNIT, 1 },
336 /* Timezone table. */
337 static TABLE TimezoneTable[] = {
338 { "gmt", tZONE, HOUR( 0) }, /* Greenwich Mean */
339 { "ut", tZONE, HOUR( 0) }, /* Universal */
340 { "utc", tZONE, HOUR( 0) }, /* Universal Coordinated */
341 { "cut", tZONE, HOUR( 0) }, /* Coordinated Universal */
342 { "z", tZONE, HOUR( 0) }, /* Greenwich Mean */
343 { "wet", tZONE, HOUR( 0) }, /* Western European */
344 { "bst", tDAYZONE, HOUR( 0) }, /* British Summer */
345 { "nst", tZONE, HOUR(3)+30 }, /* Newfoundland Standard */
346 { "ndt", tDAYZONE, HOUR(3)+30 }, /* Newfoundland Daylight */
347 { "ast", tZONE, HOUR( 4) }, /* Atlantic Standard */
348 { "adt", tDAYZONE, HOUR( 4) }, /* Atlantic Daylight */
349 { "est", tZONE, HOUR( 5) }, /* Eastern Standard */
350 { "edt", tDAYZONE, HOUR( 5) }, /* Eastern Daylight */
351 { "cst", tZONE, HOUR( 6) }, /* Central Standard */
352 { "cdt", tDAYZONE, HOUR( 6) }, /* Central Daylight */
353 { "mst", tZONE, HOUR( 7) }, /* Mountain Standard */
354 { "mdt", tDAYZONE, HOUR( 7) }, /* Mountain Daylight */
355 { "pst", tZONE, HOUR( 8) }, /* Pacific Standard */
356 { "pdt", tDAYZONE, HOUR( 8) }, /* Pacific Daylight */
357 { "yst", tZONE, HOUR( 9) }, /* Yukon Standard */
358 { "ydt", tDAYZONE, HOUR( 9) }, /* Yukon Daylight */
359 { "akst", tZONE, HOUR( 9) }, /* Alaska Standard */
360 { "akdt", tDAYZONE, HOUR( 9) }, /* Alaska Daylight */
361 { "hst", tZONE, HOUR(10) }, /* Hawaii Standard */
362 { "hast", tZONE, HOUR(10) }, /* Hawaii-Aleutian Standard */
363 { "hadt", tDAYZONE, HOUR(10) }, /* Hawaii-Aleutian Daylight */
364 { "ces", tDAYZONE, -HOUR(1) }, /* Central European Summer */
365 { "cest", tDAYZONE, -HOUR(1) }, /* Central European Summer */
366 { "mez", tZONE, -HOUR(1) }, /* Middle European */
367 { "mezt", tDAYZONE, -HOUR(1) }, /* Middle European Summer */
368 { "cet", tZONE, -HOUR(1) }, /* Central European */
369 { "met", tZONE, -HOUR(1) }, /* Middle European */
370 { "eet", tZONE, -HOUR(2) }, /* Eastern Europe */
371 { "msk", tZONE, -HOUR(3) }, /* Moscow Winter */
372 { "msd", tDAYZONE, -HOUR(3) }, /* Moscow Summer */
373 { "wast", tZONE, -HOUR(8) }, /* West Australian Standard */
374 { "wadt", tDAYZONE, -HOUR(8) }, /* West Australian Daylight */
375 { "hkt", tZONE, -HOUR(8) }, /* Hong Kong */
376 { "cct", tZONE, -HOUR(8) }, /* China Coast */
377 { "jst", tZONE, -HOUR(9) }, /* Japan Standard */
378 { "kst", tZONE, -HOUR(9) }, /* Korean Standard */
379 { "kdt", tZONE, -HOUR(9) }, /* Korean Daylight */
380 { "cast", tZONE, -(HOUR(9)+30) }, /* Central Australian Standard */
381 { "cadt", tDAYZONE, -(HOUR(9)+30) }, /* Central Australian Daylight */
382 { "east", tZONE, -HOUR(10) }, /* Eastern Australian Standard */
383 { "eadt", tDAYZONE, -HOUR(10) }, /* Eastern Australian Daylight */
384 { "nzst", tZONE, -HOUR(12) }, /* New Zealand Standard */
385 { "nzdt", tDAYZONE, -HOUR(12) }, /* New Zealand Daylight */
387 /* For completeness we include the following entries. */
390 /* Duplicate names. Either they conflict with a zone listed above
391 * (which is either more likely to be seen or just been in circulation
392 * longer), or they conflict with another zone in this section and
393 * we could not reasonably choose one over the other. */
394 { "fst", tZONE, HOUR( 2) }, /* Fernando De Noronha Standard */
395 { "fdt", tDAYZONE, HOUR( 2) }, /* Fernando De Noronha Daylight */
396 { "bst", tZONE, HOUR( 3) }, /* Brazil Standard */
397 { "est", tZONE, HOUR( 3) }, /* Eastern Standard (Brazil) */
398 { "edt", tDAYZONE, HOUR( 3) }, /* Eastern Daylight (Brazil) */
399 { "wst", tZONE, HOUR( 4) }, /* Western Standard (Brazil) */
400 { "wdt", tDAYZONE, HOUR( 4) }, /* Western Daylight (Brazil) */
401 { "cst", tZONE, HOUR( 5) }, /* Chile Standard */
402 { "cdt", tDAYZONE, HOUR( 5) }, /* Chile Daylight */
403 { "ast", tZONE, HOUR( 5) }, /* Acre Standard */
404 { "adt", tDAYZONE, HOUR( 5) }, /* Acre Daylight */
405 { "cst", tZONE, HOUR( 5) }, /* Cuba Standard */
406 { "cdt", tDAYZONE, HOUR( 5) }, /* Cuba Daylight */
407 { "est", tZONE, HOUR( 6) }, /* Easter Island Standard */
408 { "edt", tDAYZONE, HOUR( 6) }, /* Easter Island Daylight */
409 { "sst", tZONE, HOUR(11) }, /* Samoa Standard */
410 { "ist", tZONE, -HOUR(2) }, /* Israel Standard */
411 { "idt", tDAYZONE, -HOUR(2) }, /* Israel Daylight */
412 { "idt", tDAYZONE, -(HOUR(3)+30) }, /* Iran Daylight */
413 { "ist", tZONE, -(HOUR(3)+30) }, /* Iran Standard */
414 { "cst", tZONE, -HOUR(8) }, /* China Standard */
415 { "cdt", tDAYZONE, -HOUR(8) }, /* China Daylight */
416 { "sst", tZONE, -HOUR(8) }, /* Singapore Standard */
418 /* Dubious (e.g., not in Olson's TIMEZONE package) or obsolete. */
419 { "gst", tZONE, HOUR( 3) }, /* Greenland Standard */
420 { "wat", tZONE, -HOUR(1) }, /* West Africa */
421 { "at", tZONE, HOUR( 2) }, /* Azores */
422 { "gst", tZONE, -HOUR(10) }, /* Guam Standard */
423 { "nft", tZONE, HOUR(3)+30 }, /* Newfoundland */
424 { "idlw", tZONE, HOUR(12) }, /* International Date Line West */
425 { "mewt", tZONE, -HOUR(1) }, /* Middle European Winter */
426 { "mest", tDAYZONE, -HOUR(1) }, /* Middle European Summer */
427 { "swt", tZONE, -HOUR(1) }, /* Swedish Winter */
428 { "sst", tDAYZONE, -HOUR(1) }, /* Swedish Summer */
429 { "fwt", tZONE, -HOUR(1) }, /* French Winter */
430 { "fst", tDAYZONE, -HOUR(1) }, /* French Summer */
431 { "bt", tZONE, -HOUR(3) }, /* Baghdad */
432 { "it", tZONE, -(HOUR(3)+30) }, /* Iran */
433 { "zp4", tZONE, -HOUR(4) }, /* USSR Zone 3 */
434 { "zp5", tZONE, -HOUR(5) }, /* USSR Zone 4 */
435 { "ist", tZONE, -(HOUR(5)+30) }, /* Indian Standard */
436 { "zp6", tZONE, -HOUR(6) }, /* USSR Zone 5 */
437 { "nst", tZONE, -HOUR(7) }, /* North Sumatra */
438 { "sst", tZONE, -HOUR(7) }, /* South Sumatra */
439 { "jt", tZONE, -(HOUR(7)+30) }, /* Java (3pm in Cronusland!) */
440 { "nzt", tZONE, -HOUR(12) }, /* New Zealand */
441 { "idle", tZONE, -HOUR(12) }, /* International Date Line East */
442 { "cat", tZONE, HOUR(10) }, /* -- expired 1967 */
443 { "nt", tZONE, HOUR(11) }, /* -- expired 1967 */
444 { "ahst", tZONE, HOUR(10) }, /* -- expired 1983 */
445 { "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 118 "parsedate.y"
950 /* I am compulsive about lint natterings... */
951 if (yyHaveTime == -1) {
958 #line 127 "parsedate.y"
961 yyTimezone = yyvsp[0].Number;
965 #line 131 "parsedate.y"
971 #line 134 "parsedate.y"
977 #line 139 "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 151 "parsedate.y"
994 yyHour = yyvsp[-3].Number;
995 yyMinutes = yyvsp[-1].Number;
997 yyMeridian = yyvsp[0].Meridian;
1001 #line 157 "parsedate.y"
1003 yyHour = yyvsp[-3].Number;
1004 yyMinutes = yyvsp[-1].Number;
1005 yyTimezone = yyvsp[0].Number;
1011 #line 164 "parsedate.y"
1013 yyHour = yyvsp[-5].Number;
1014 yyMinutes = yyvsp[-3].Number;
1015 yySeconds = yyvsp[-1].Number;
1016 yyMeridian = yyvsp[0].Meridian;
1020 #line 170 "parsedate.y"
1022 yyHour = yyvsp[-5].Number;
1023 yyMinutes = yyvsp[-3].Number;
1024 yySeconds = yyvsp[-1].Number;
1025 yyTimezone = yyvsp[0].Number;
1031 #line 180 "parsedate.y"
1033 yyval.Number = yyvsp[0].Number;
1038 #line 184 "parsedate.y"
1040 yyval.Number = yyvsp[0].Number;
1045 #line 188 "parsedate.y"
1047 /* Only allow "GMT+300" and "GMT-0800" */
1048 if (yyvsp[-1].Number != 0) {
1051 yyval.Number = yyvsp[0].Number;
1056 #line 196 "parsedate.y"
1058 yyval.Number = yyvsp[0].Number;
1063 #line 202 "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 223 "parsedate.y"
1087 yyMonth = yyvsp[-2].Number;
1088 yyDay = yyvsp[0].Number;
1092 #line 227 "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 239 "parsedate.y"
1109 yyMonth = yyvsp[-1].Number;
1110 yyDay = yyvsp[0].Number;
1114 #line 243 "parsedate.y"
1116 yyMonth = yyvsp[-3].Number;
1117 yyDay = yyvsp[-2].Number;
1118 yyYear = yyvsp[0].Number;
1122 #line 248 "parsedate.y"
1124 yyDay = yyvsp[-1].Number;
1125 yyMonth = yyvsp[0].Number;
1129 #line 252 "parsedate.y"
1131 yyDay = yyvsp[-2].Number;
1132 yyMonth = yyvsp[-1].Number;
1133 yyYear = yyvsp[0].Number;
1137 #line 257 "parsedate.y"
1139 yyDay = yyvsp[-2].Number;
1140 yyMonth = yyvsp[-1].Number;
1141 yyYear = yyvsp[0].Number;
1145 #line 264 "parsedate.y"
1147 yyRelSeconds += yyvsp[-1].Number * yyvsp[0].Number;
1151 #line 267 "parsedate.y"
1153 yyRelSeconds += yyvsp[-1].Number * yyvsp[0].Number;
1157 #line 270 "parsedate.y"
1159 yyRelMonth += yyvsp[-1].Number * yyvsp[0].Number;
1163 #line 273 "parsedate.y"
1165 yyRelMonth += yyvsp[-1].Number * yyvsp[0].Number;
1169 #line 278 "parsedate.y"
1171 yyval.Meridian = MER24;
1175 #line 281 "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");