1
2 /* A Bison parser, made from parsedate.y
3 by GNU Bison version 1.28 */
4
5 #define YYBISON 1 /* Identify Bison output. */
6
7 #define tDAY 257
8 #define tDAYZONE 258
9 #define tMERIDIAN 259
10 #define tMONTH 260
11 #define tMONTH_UNIT 261
12 #define tSEC_UNIT 262
13 #define tSNUMBER 263
14 #define tUNUMBER 264
15 #define tZONE 265
16 #define tDST 266
17
18 #line 1 "parsedate.y"
19
20 /*:ts=8*/
21 /*****************************************************************************
22 * FIDOGATE --- Gateway UNIX Mail/News <-> FIDO NetMail/EchoMail
23 *
24 * $Id: parsedate.c,v 4.3 2000/10/18 21:53:57 mj Exp $
25 *
26 * parsedate() date/time parser. Taken from ifmail 1.7 / inn 1.4 and
27 * adopted for FIDOGATE. Added DST from old getdate.y.
28 *
29 *****************************************************************************/
30 /* Original %Revision: 1.13 %
31 **
32 ** Originally written by Steven M. Bellovin <smb@research.att.com> while
33 ** at the University of North Carolina at Chapel Hill. Later tweaked by
34 ** a couple of people on Usenet. Completely overhauled by Rich $alz
35 ** <rsalz@osf.org> and Jim Berets <jberets@bbn.com> in August, 1990.
36 ** Further revised (removed obsolete constructs and cleaned up timezone
37 ** names) in August, 1991, by Rich. Paul Eggert <eggert@twinsun.com>
38 ** helped in September, 1992.
39 **
40 ** This grammar has six shift/reduce conflicts.
41 **
42 ** This code is in the public domain and has no copyright.
43 */
44 /* SUPPRESS 530 *//* Empty body for statement */
45 /* SUPPRESS 593 on yyerrlab *//* Label was not used */
46 /* SUPPRESS 593 on yynewstate *//* Label was not used */
47 /* SUPPRESS 595 on yypvt *//* Automatic variable may be used before set */
48
49 #include "fidogate.h"
50
51 #include <sys/time.h>
52
53 /* Stuff from inn configdata.h */
54 #if defined(__STDC__)
55 typedef char const *STRING;
56 typedef char * const CSTRING;
57 #else
58 typedef char *STRING;
59 typedef char *CSTRING;
60 #endif /* defined(__STDC__) */
61
62 #define CTYPE(isXXXXX, c) ((isascii((c)) && isXXXXX((c))))
63
64 /* Stuff from inn macros.h */
65 #define SIZEOF(array) ((int)(sizeof array / sizeof array[0]))
66 #define ENDOF(array) (&array[SIZEOF(array)])
67
68
69
70 #define yyparse date_parse
71 #define yylex date_lex
72 #define yyerror date_error
73
74 static int date_lex(void);
75
76
77
78 /* See the LeapYears table in Convert. */
79 #define EPOCH 1970
80 #define END_OF_TIME 2038
81 /* Constants for general time calculations. */
82 #define DST_OFFSET 1
83 #define SECSPERDAY (24L * 60L * 60L)
84 /* Readability for TABLE stuff. */
85 #define HOUR(x) (x * 60)
86
87 #define LPAREN '('
88 #define RPAREN ')'
89 #define IS7BIT(x) ((unsigned int)(x) < 0200)
90
91
92 /*
93 ** An entry in the lexical lookup table.
94 */
95 typedef struct _TABLE {
96 STRING name;
97 int type;
98 time_t value;
99 } TABLE;
100
101 /*
102 ** Daylight-savings mode: on, off, or not yet known.
103 */
104 typedef enum _DSTMODE {
105 DSTon, DSToff, DSTmaybe
106 } DSTMODE;
107
108 /*
109 ** Meridian: am, pm, or 24-hour style.
110 */
111 typedef enum _MERIDIAN {
112 MERam, MERpm, MER24
113 } MERIDIAN;
114
115
116 /*
117 ** Global variables. We could get rid of most of them by using a yacc
118 ** union, but this is more efficient. (This routine predates the
119 ** yacc %union construct.)
120 */
121 static char *yyInput;
122 static DSTMODE yyDSTmode;
123 static int yyHaveDate;
124 static int yyHaveRel;
125 static int yyHaveTime;
126 static time_t yyTimezone;
127 static time_t yyDay;
128 static time_t yyHour;
129 static time_t yyMinutes;
130 static time_t yyMonth;
131 static time_t yySeconds;
132 static time_t yyYear;
133 static MERIDIAN yyMeridian;
134 static time_t yyRelMonth;
135 static time_t yyRelSeconds;
136
137
138 extern struct tm *localtime(const time_t *);
139
140 static void date_error(char *s);
141
142 #line 125 "parsedate.y"
143 typedef union {
144 time_t Number;
145 enum _MERIDIAN Meridian;
146 } YYSTYPE;
147 #include <stdio.h>
148
149 #ifndef __cplusplus
150 #ifndef __STDC__
151 #define const
152 #endif
153 #endif
154
155
156
157 #define YYFINAL 48
158 #define YYFLAG -32768
159 #define YYNTBASE 16
160
161 #define YYTRANSLATE(x) ((unsigned)(x) <= 266 ? yytranslate[x] : 24)
162
163 static const char yytranslate[] = { 0,
164 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
165 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
166 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
167 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
168 2, 2, 2, 15, 2, 2, 14, 2, 2, 2,
169 2, 2, 2, 2, 2, 2, 2, 13, 2, 2,
170 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
171 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
172 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
173 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
174 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
175 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
176 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
177 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
178 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
179 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
180 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
181 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
182 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
183 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
184 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
185 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
186 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
187 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
188 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
189 2, 2, 2, 2, 2, 1, 3, 4, 5, 6,
190 7, 8, 9, 10, 11, 12
191 };
192
193 #if YYDEBUG != 0
194 static const short yyprhs[] = { 0,
195 0, 1, 4, 6, 9, 11, 13, 16, 21, 26,
196 33, 40, 42, 44, 47, 50, 52, 54, 58, 64,
197 67, 72, 75, 79, 85, 90, 93, 96, 99, 102,
198 103
199 };
200
201 static const short yyrhs[] = { -1,
202 16, 17, 0, 18, 0, 18, 19, 0, 21, 0,
203 22, 0, 10, 23, 0, 10, 13, 10, 23, 0,
204 10, 13, 10, 20, 0, 10, 13, 10, 13, 10,
205 23, 0, 10, 13, 10, 13, 10, 20, 0, 11,
206 0, 4, 0, 11, 12, 0, 11, 20, 0, 20,
207 0, 9, 0, 10, 14, 10, 0, 10, 14, 10,
208 14, 10, 0, 6, 10, 0, 6, 10, 15, 10,
209 0, 10, 6, 0, 10, 6, 10, 0, 3, 15,
210 10, 6, 10, 0, 3, 10, 6, 10, 0, 9,
211 8, 0, 10, 8, 0, 9, 7, 0, 10, 7,
212 0, 0, 5, 0
213 };
214
215 #endif
216
217 #if YYDEBUG != 0
218 static const short yyrline[] = { 0,
219 139, 140, 143, 152, 156, 159, 164, 176, 182, 189,
220 195, 205, 209, 213, 217, 225, 231, 252, 256, 268,
221 272, 277, 281, 286, 291, 298, 301, 304, 307, 312,
222 315
223 };
224 #endif
225
226
227 #if YYDEBUG != 0 || defined (YYERROR_VERBOSE)
228
229 static const char * const yytname[] = { "$","error","$undefined.","tDAY","tDAYZONE",
230 "tMERIDIAN","tMONTH","tMONTH_UNIT","tSEC_UNIT","tSNUMBER","tUNUMBER","tZONE",
231 "tDST","':'","'/'","','","spec","item","time","zone","numzone","date","rel",
232 "o_merid", NULL
233 };
234 #endif
235
236 static const short yyr1[] = { 0,
237 16, 16, 17, 17, 17, 17, 18, 18, 18, 18,
238 18, 19, 19, 19, 19, 19, 20, 21, 21, 21,
239 21, 21, 21, 21, 21, 22, 22, 22, 22, 23,
240 23
241 };
242
243 static const short yyr2[] = { 0,
244 0, 2, 1, 2, 1, 1, 2, 4, 4, 6,
245 6, 1, 1, 2, 2, 1, 1, 3, 5, 2,
246 4, 2, 3, 5, 4, 2, 2, 2, 2, 0,
247 1
248 };
249
250 static const short yydefact[] = { 1,
251 0, 0, 0, 0, 30, 2, 3, 5, 6, 0,
252 0, 20, 28, 26, 31, 22, 29, 27, 0, 0,
253 7, 13, 17, 12, 4, 16, 0, 0, 0, 23,
254 30, 18, 14, 15, 25, 0, 21, 0, 9, 8,
255 0, 24, 30, 19, 11, 10, 0, 0
256 };
257
258 static const short yydefgoto[] = { 1,
259 6, 7, 25, 26, 8, 9, 21
260 };
261
262 static const short yypact[] = {-32768,
263 2, -6, -7, 26, 9,-32768, 21,-32768,-32768, 12,
264 11, 16,-32768,-32768,-32768, 25,-32768,-32768, 27, 28,
265 -32768,-32768,-32768, 17,-32768,-32768, 29, 30, 31,-32768,
266 15, 13,-32768,-32768,-32768, 32,-32768, 33,-32768,-32768,
267 34,-32768, 1,-32768,-32768,-32768, 40,-32768
268 };
269
270 static const short yypgoto[] = {-32768,
271 -32768,-32768,-32768, -24,-32768,-32768, -30
272 };
273
274
275 #define YYLAST 44
276
277
278 static const short yytable[] = { 34,
279 40, 47, 12, 10, 2, 15, 39, 3, 11, 23,
280 4, 5, 46, 15, 16, 17, 18, 27, 45, 15,
281 28, 19, 20, 23, 22, 23, 41, 38, 33, 23,
282 29, 24, 13, 14, 30, 36, 31, 32, 35, 48,
283 37, 42, 43, 44
284 };
285
286 static const short yycheck[] = { 24,
287 31, 0, 10, 10, 3, 5, 31, 6, 15, 9,
288 9, 10, 43, 5, 6, 7, 8, 6, 43, 5,
289 10, 13, 14, 9, 4, 9, 14, 13, 12, 9,
290 15, 11, 7, 8, 10, 6, 10, 10, 10, 0,
291 10, 10, 10, 10
292 };
293 /* -*-C-*- Note some compilers choke on comments on `#line' lines. */
294 #line 3 "/usr/lib/bison.simple"
295 /* This file comes from bison-1.28. */
296
297 /* Skeleton output parser for bison,
298 Copyright (C) 1984, 1989, 1990 Free Software Foundation, Inc.
299
300 This program is free software; you can redistribute it and/or modify
301 it under the terms of the GNU General Public License as published by
302 the Free Software Foundation; either version 2, or (at your option)
303 any later version.
304
305 This program is distributed in the hope that it will be useful,
306 but WITHOUT ANY WARRANTY; without even the implied warranty of
307 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
308 GNU General Public License for more details.
309
310 You should have received a copy of the GNU General Public License
311 along with this program; if not, write to the Free Software
312 Foundation, Inc., 59 Temple Place - Suite 330,
313 Boston, MA 02111-1307, USA. */
314
315 /* As a special exception, when this file is copied by Bison into a
316 Bison output file, you may use that output file without restriction.
317 This special exception was added by the Free Software Foundation
318 in version 1.24 of Bison. */
319
320 /* This is the parser code that is written into each bison parser
321 when the %semantic_parser declaration is not specified in the grammar.
322 It was written by Richard Stallman by simplifying the hairy parser
323 used when %semantic_parser is specified. */
324
325 #ifndef YYSTACK_USE_ALLOCA
326 #ifdef alloca
327 #define YYSTACK_USE_ALLOCA
328 #else /* alloca not defined */
329 #ifdef __GNUC__
330 #define YYSTACK_USE_ALLOCA
331 #define alloca __builtin_alloca
332 #else /* not GNU C. */
333 #if (!defined (__STDC__) && defined (sparc)) || defined (__sparc__) || defined (__sparc) || defined (__sgi) || (defined (__sun) && defined (__i386))
334 #define YYSTACK_USE_ALLOCA
335 #include <alloca.h>
336 #else /* not sparc */
337 /* We think this test detects Watcom and Microsoft C. */
338 /* This used to test MSDOS, but that is a bad idea
339 since that symbol is in the user namespace. */
340 #if (defined (_MSDOS) || defined (_MSDOS_)) && !defined (__TURBOC__)
341 #if 0 /* No need for malloc.h, which pollutes the namespace;
342 instead, just don't use alloca. */
343 #include <malloc.h>
344 #endif
345 #else /* not MSDOS, or __TURBOC__ */
346 #if defined(_AIX)
347 /* I don't know what this was needed for, but it pollutes the namespace.
348 So I turned it off. rms, 2 May 1997. */
349 /* #include <malloc.h> */
350 #pragma alloca
351 #define YYSTACK_USE_ALLOCA
352 #else /* not MSDOS, or __TURBOC__, or _AIX */
353 #if 0
354 #ifdef __hpux /* haible@ilog.fr says this works for HPUX 9.05 and up,
355 and on HPUX 10. Eventually we can turn this on. */
356 #define YYSTACK_USE_ALLOCA
357 #define alloca __builtin_alloca
358 #endif /* __hpux */
359 #endif
360 #endif /* not _AIX */
361 #endif /* not MSDOS, or __TURBOC__ */
362 #endif /* not sparc */
363 #endif /* not GNU C */
364 #endif /* alloca not defined */
365 #endif /* YYSTACK_USE_ALLOCA not defined */
366
367 #ifdef YYSTACK_USE_ALLOCA
368 #define YYSTACK_ALLOC alloca
369 #else
370 #define YYSTACK_ALLOC malloc
371 #endif
372
373 /* Note: there must be only one dollar sign in this file.
374 It is replaced by the list of actions, each action
375 as one case of the switch. */
376
377 #define yyerrok (yyerrstatus = 0)
378 #define yyclearin (yychar = YYEMPTY)
379 #define YYEMPTY -2
380 #define YYEOF 0
381 #define YYACCEPT goto yyacceptlab
382 #define YYABORT goto yyabortlab
383 #define YYERROR goto yyerrlab1
384 /* Like YYERROR except do call yyerror.
385 This remains here temporarily to ease the
386 transition to the new meaning of YYERROR, for GCC.
387 Once GCC version 2 has supplanted version 1, this can go. */
388 #define YYFAIL goto yyerrlab
389 #define YYRECOVERING() (!!yyerrstatus)
390 #define YYBACKUP(token, value) \
391 do \
392 if (yychar == YYEMPTY && yylen == 1) \
393 { yychar = (token), yylval = (value); \
394 yychar1 = YYTRANSLATE (yychar); \
395 YYPOPSTACK; \
396 goto yybackup; \
397 } \
398 else \
399 { yyerror ("syntax error: cannot back up"); YYERROR; } \
400 while (0)
401
402 #define YYTERROR 1
403 #define YYERRCODE 256
404
405 #ifndef YYPURE
406 #define YYLEX yylex()
407 #endif
408
409 #ifdef YYPURE
410 #ifdef YYLSP_NEEDED
411 #ifdef YYLEX_PARAM
412 #define YYLEX yylex(&yylval, &yylloc, YYLEX_PARAM)
413 #else
414 #define YYLEX yylex(&yylval, &yylloc)
415 #endif
416 #else /* not YYLSP_NEEDED */
417 #ifdef YYLEX_PARAM
418 #define YYLEX yylex(&yylval, YYLEX_PARAM)
419 #else
420 #define YYLEX yylex(&yylval)
421 #endif
422 #endif /* not YYLSP_NEEDED */
423 #endif
424
425 /* If nonreentrant, generate the variables here */
426
427 #ifndef YYPURE
428
429 int yychar; /* the lookahead symbol */
430 YYSTYPE yylval; /* the semantic value of the */
431 /* lookahead symbol */
432
433 #ifdef YYLSP_NEEDED
434 YYLTYPE yylloc; /* location data for the lookahead */
435 /* symbol */
436 #endif
437
438 int yynerrs; /* number of parse errors so far */
439 #endif /* not YYPURE */
440
441 #if YYDEBUG != 0
442 int yydebug; /* nonzero means print parse trace */
443 /* Since this is uninitialized, it does not stop multiple parsers
444 from coexisting. */
445 #endif
446
447 /* YYINITDEPTH indicates the initial size of the parser's stacks */
448
449 #ifndef YYINITDEPTH
450 #define YYINITDEPTH 200
451 #endif
452
453 /* YYMAXDEPTH is the maximum size the stacks can grow to
454 (effective only if the built-in stack extension method is used). */
455
456 #if YYMAXDEPTH == 0
457 #undef YYMAXDEPTH
458 #endif
459
460 #ifndef YYMAXDEPTH
461 #define YYMAXDEPTH 10000
462 #endif
463
464 /* Define __yy_memcpy. Note that the size argument
465 should be passed with type unsigned int, because that is what the non-GCC
466 definitions require. With GCC, __builtin_memcpy takes an arg
467 of type size_t, but it can handle unsigned int. */
468
469 #if __GNUC__ > 1 /* GNU C and GNU C++ define this. */
470 #define __yy_memcpy(TO,FROM,COUNT) __builtin_memcpy(TO,FROM,COUNT)
471 #else /* not GNU C or C++ */
472 #ifndef __cplusplus
473
474 /* This is the most reliable way to avoid incompatibilities
475 in available built-in functions on various systems. */
476 static void
__yy_memcpy(to,from,count)477 __yy_memcpy (to, from, count)
478 char *to;
479 char *from;
480 unsigned int count;
481 {
482 register char *f = from;
483 register char *t = to;
484 register int i = count;
485
486 while (i-- > 0)
487 *t++ = *f++;
488 }
489
490 #else /* __cplusplus */
491
492 /* This is the most reliable way to avoid incompatibilities
493 in available built-in functions on various systems. */
494 static void
__yy_memcpy(char * to,char * from,unsigned int count)495 __yy_memcpy (char *to, char *from, unsigned int count)
496 {
497 register char *t = to;
498 register char *f = from;
499 register int i = count;
500
501 while (i-- > 0)
502 *t++ = *f++;
503 }
504
505 #endif
506 #endif
507
508 #line 217 "/usr/lib/bison.simple"
509
510 /* The user can define YYPARSE_PARAM as the name of an argument to be passed
511 into yyparse. The argument should have type void *.
512 It should actually point to an object.
513 Grammar actions can access the variable by casting it
514 to the proper pointer type. */
515
516 #ifdef YYPARSE_PARAM
517 #ifdef __cplusplus
518 #define YYPARSE_PARAM_ARG void *YYPARSE_PARAM
519 #define YYPARSE_PARAM_DECL
520 #else /* not __cplusplus */
521 #define YYPARSE_PARAM_ARG YYPARSE_PARAM
522 #define YYPARSE_PARAM_DECL void *YYPARSE_PARAM;
523 #endif /* not __cplusplus */
524 #else /* not YYPARSE_PARAM */
525 #define YYPARSE_PARAM_ARG
526 #define YYPARSE_PARAM_DECL
527 #endif /* not YYPARSE_PARAM */
528
529 /* Prevent warning if -Wstrict-prototypes. */
530 #ifdef __GNUC__
531 #ifdef YYPARSE_PARAM
532 int yyparse (void *);
533 #else
534 int yyparse (void);
535 #endif
536 #endif
537
538 int
yyparse(YYPARSE_PARAM_ARG)539 yyparse(YYPARSE_PARAM_ARG)
540 YYPARSE_PARAM_DECL
541 {
542 register int yystate;
543 register int yyn;
544 register short *yyssp;
545 register YYSTYPE *yyvsp;
546 int yyerrstatus; /* number of tokens to shift before error messages enabled */
547 int yychar1 = 0; /* lookahead token as an internal (translated) token number */
548
549 short yyssa[YYINITDEPTH]; /* the state stack */
550 YYSTYPE yyvsa[YYINITDEPTH]; /* the semantic value stack */
551
552 short *yyss = yyssa; /* refer to the stacks thru separate pointers */
553 YYSTYPE *yyvs = yyvsa; /* to allow yyoverflow to reallocate them elsewhere */
554
555 #ifdef YYLSP_NEEDED
556 YYLTYPE yylsa[YYINITDEPTH]; /* the location stack */
557 YYLTYPE *yyls = yylsa;
558 YYLTYPE *yylsp;
559
560 #define YYPOPSTACK (yyvsp--, yyssp--, yylsp--)
561 #else
562 #define YYPOPSTACK (yyvsp--, yyssp--)
563 #endif
564
565 int yystacksize = YYINITDEPTH;
566 int yyfree_stacks = 0;
567
568 #ifdef YYPURE
569 int yychar;
570 YYSTYPE yylval;
571 int yynerrs;
572 #ifdef YYLSP_NEEDED
573 YYLTYPE yylloc;
574 #endif
575 #endif
576
577 YYSTYPE yyval; /* the variable used to return */
578 /* semantic values from the action */
579 /* routines */
580
581 int yylen;
582
583 #if YYDEBUG != 0
584 if (yydebug)
585 fprintf(stderr, "Starting parse\n");
586 #endif
587
588 yystate = 0;
589 yyerrstatus = 0;
590 yynerrs = 0;
591 yychar = YYEMPTY; /* Cause a token to be read. */
592
593 /* Initialize stack pointers.
594 Waste one element of value and location stack
595 so that they stay on the same level as the state stack.
596 The wasted elements are never initialized. */
597
598 yyssp = yyss - 1;
599 yyvsp = yyvs;
600 #ifdef YYLSP_NEEDED
601 yylsp = yyls;
602 #endif
603
604 /* Push a new state, which is found in yystate . */
605 /* In all cases, when you get here, the value and location stacks
606 have just been pushed. so pushing a state here evens the stacks. */
607 yynewstate:
608
609 *++yyssp = yystate;
610
611 if (yyssp >= yyss + yystacksize - 1)
612 {
613 /* Give user a chance to reallocate the stack */
614 /* Use copies of these so that the &'s don't force the real ones into memory. */
615 YYSTYPE *yyvs1 = yyvs;
616 short *yyss1 = yyss;
617 #ifdef YYLSP_NEEDED
618 YYLTYPE *yyls1 = yyls;
619 #endif
620
621 /* Get the current used size of the three stacks, in elements. */
622 int size = yyssp - yyss + 1;
623
624 #ifdef yyoverflow
625 /* Each stack pointer address is followed by the size of
626 the data in use in that stack, in bytes. */
627 #ifdef YYLSP_NEEDED
628 /* This used to be a conditional around just the two extra args,
629 but that might be undefined if yyoverflow is a macro. */
630 yyoverflow("parser stack overflow",
631 &yyss1, size * sizeof (*yyssp),
632 &yyvs1, size * sizeof (*yyvsp),
633 &yyls1, size * sizeof (*yylsp),
634 &yystacksize);
635 #else
636 yyoverflow("parser stack overflow",
637 &yyss1, size * sizeof (*yyssp),
638 &yyvs1, size * sizeof (*yyvsp),
639 &yystacksize);
640 #endif
641
642 yyss = yyss1; yyvs = yyvs1;
643 #ifdef YYLSP_NEEDED
644 yyls = yyls1;
645 #endif
646 #else /* no yyoverflow */
647 /* Extend the stack our own way. */
648 if (yystacksize >= YYMAXDEPTH)
649 {
650 yyerror("parser stack overflow");
651 if (yyfree_stacks)
652 {
653 free (yyss);
654 free (yyvs);
655 #ifdef YYLSP_NEEDED
656 free (yyls);
657 #endif
658 }
659 return 2;
660 }
661 yystacksize *= 2;
662 if (yystacksize > YYMAXDEPTH)
663 yystacksize = YYMAXDEPTH;
664 #ifndef YYSTACK_USE_ALLOCA
665 yyfree_stacks = 1;
666 #endif
667 yyss = (short *) YYSTACK_ALLOC (yystacksize * sizeof (*yyssp));
668 __yy_memcpy ((char *)yyss, (char *)yyss1,
669 size * (unsigned int) sizeof (*yyssp));
670 yyvs = (YYSTYPE *) YYSTACK_ALLOC (yystacksize * sizeof (*yyvsp));
671 __yy_memcpy ((char *)yyvs, (char *)yyvs1,
672 size * (unsigned int) sizeof (*yyvsp));
673 #ifdef YYLSP_NEEDED
674 yyls = (YYLTYPE *) YYSTACK_ALLOC (yystacksize * sizeof (*yylsp));
675 __yy_memcpy ((char *)yyls, (char *)yyls1,
676 size * (unsigned int) sizeof (*yylsp));
677 #endif
678 #endif /* no yyoverflow */
679
680 yyssp = yyss + size - 1;
681 yyvsp = yyvs + size - 1;
682 #ifdef YYLSP_NEEDED
683 yylsp = yyls + size - 1;
684 #endif
685
686 #if YYDEBUG != 0
687 if (yydebug)
688 fprintf(stderr, "Stack size increased to %d\n", yystacksize);
689 #endif
690
691 if (yyssp >= yyss + yystacksize - 1)
692 YYABORT;
693 }
694
695 #if YYDEBUG != 0
696 if (yydebug)
697 fprintf(stderr, "Entering state %d\n", yystate);
698 #endif
699
700 goto yybackup;
701 yybackup:
702
703 /* Do appropriate processing given the current state. */
704 /* Read a lookahead token if we need one and don't already have one. */
705 /* yyresume: */
706
707 /* First try to decide what to do without reference to lookahead token. */
708
709 yyn = yypact[yystate];
710 if (yyn == YYFLAG)
711 goto yydefault;
712
713 /* Not known => get a lookahead token if don't already have one. */
714
715 /* yychar is either YYEMPTY or YYEOF
716 or a valid token in external form. */
717
718 if (yychar == YYEMPTY)
719 {
720 #if YYDEBUG != 0
721 if (yydebug)
722 fprintf(stderr, "Reading a token: ");
723 #endif
724 yychar = YYLEX;
725 }
726
727 /* Convert token to internal form (in yychar1) for indexing tables with */
728
729 if (yychar <= 0) /* This means end of input. */
730 {
731 yychar1 = 0;
732 yychar = YYEOF; /* Don't call YYLEX any more */
733
734 #if YYDEBUG != 0
735 if (yydebug)
736 fprintf(stderr, "Now at end of input.\n");
737 #endif
738 }
739 else
740 {
741 yychar1 = YYTRANSLATE(yychar);
742
743 #if YYDEBUG != 0
744 if (yydebug)
745 {
746 fprintf (stderr, "Next token is %d (%s", yychar, yytname[yychar1]);
747 /* Give the individual parser a way to print the precise meaning
748 of a token, for further debugging info. */
749 #ifdef YYPRINT
750 YYPRINT (stderr, yychar, yylval);
751 #endif
752 fprintf (stderr, ")\n");
753 }
754 #endif
755 }
756
757 yyn += yychar1;
758 if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != yychar1)
759 goto yydefault;
760
761 yyn = yytable[yyn];
762
763 /* yyn is what to do for this token type in this state.
764 Negative => reduce, -yyn is rule number.
765 Positive => shift, yyn is new state.
766 New state is final state => don't bother to shift,
767 just return success.
768 0, or most negative number => error. */
769
770 if (yyn < 0)
771 {
772 if (yyn == YYFLAG)
773 goto yyerrlab;
774 yyn = -yyn;
775 goto yyreduce;
776 }
777 else if (yyn == 0)
778 goto yyerrlab;
779
780 if (yyn == YYFINAL)
781 YYACCEPT;
782
783 /* Shift the lookahead token. */
784
785 #if YYDEBUG != 0
786 if (yydebug)
787 fprintf(stderr, "Shifting token %d (%s), ", yychar, yytname[yychar1]);
788 #endif
789
790 /* Discard the token being shifted unless it is eof. */
791 if (yychar != YYEOF)
792 yychar = YYEMPTY;
793
794 *++yyvsp = yylval;
795 #ifdef YYLSP_NEEDED
796 *++yylsp = yylloc;
797 #endif
798
799 /* count tokens shifted since error; after three, turn off error status. */
800 if (yyerrstatus) yyerrstatus--;
801
802 yystate = yyn;
803 goto yynewstate;
804
805 /* Do the default action for the current state. */
806 yydefault:
807
808 yyn = yydefact[yystate];
809 if (yyn == 0)
810 goto yyerrlab;
811
812 /* Do a reduction. yyn is the number of a rule to reduce with. */
813 yyreduce:
814 yylen = yyr2[yyn];
815 if (yylen > 0)
816 yyval = yyvsp[1-yylen]; /* implement default value of the action */
817
818 #if YYDEBUG != 0
819 if (yydebug)
820 {
821 int i;
822
823 fprintf (stderr, "Reducing via rule %d (line %d), ",
824 yyn, yyrline[yyn]);
825
826 /* Print the symbols being reduced, and their result. */
827 for (i = yyprhs[yyn]; yyrhs[i] > 0; i++)
828 fprintf (stderr, "%s ", yytname[yyrhs[i]]);
829 fprintf (stderr, " -> %s\n", yytname[yyr1[yyn]]);
830 }
831 #endif
832
833
834 switch (yyn) {
835
836 case 3:
837 #line 143 "parsedate.y"
838 {
839 yyHaveTime++;
840 #if defined(lint)
841 /* I am compulsive about lint natterings... */
842 if (yyHaveTime == -1) {
843 YYERROR;
844 }
845 #endif /* defined(lint) */
846 ;
847 break;}
848 case 4:
849 #line 152 "parsedate.y"
850 {
851 yyHaveTime++;
852 yyTimezone = yyvsp[0].Number;
853 ;
854 break;}
855 case 5:
856 #line 156 "parsedate.y"
857 {
858 yyHaveDate++;
859 ;
860 break;}
861 case 6:
862 #line 159 "parsedate.y"
863 {
864 yyHaveRel = 1;
865 ;
866 break;}
867 case 7:
868 #line 164 "parsedate.y"
869 {
870 if (yyvsp[-1].Number < 100) {
871 yyHour = yyvsp[-1].Number;
872 yyMinutes = 0;
873 }
874 else {
875 yyHour = yyvsp[-1].Number / 100;
876 yyMinutes = yyvsp[-1].Number % 100;
877 }
878 yySeconds = 0;
879 yyMeridian = yyvsp[0].Meridian;
880 ;
881 break;}
882 case 8:
883 #line 176 "parsedate.y"
884 {
885 yyHour = yyvsp[-3].Number;
886 yyMinutes = yyvsp[-1].Number;
887 yySeconds = 0;
888 yyMeridian = yyvsp[0].Meridian;
889 ;
890 break;}
891 case 9:
892 #line 182 "parsedate.y"
893 {
894 yyHour = yyvsp[-3].Number;
895 yyMinutes = yyvsp[-1].Number;
896 yyTimezone = yyvsp[0].Number;
897 yyMeridian = MER24;
898 yyDSTmode = DSToff;
899 ;
900 break;}
901 case 10:
902 #line 189 "parsedate.y"
903 {
904 yyHour = yyvsp[-5].Number;
905 yyMinutes = yyvsp[-3].Number;
906 yySeconds = yyvsp[-1].Number;
907 yyMeridian = yyvsp[0].Meridian;
908 ;
909 break;}
910 case 11:
911 #line 195 "parsedate.y"
912 {
913 yyHour = yyvsp[-5].Number;
914 yyMinutes = yyvsp[-3].Number;
915 yySeconds = yyvsp[-1].Number;
916 yyTimezone = yyvsp[0].Number;
917 yyMeridian = MER24;
918 yyDSTmode = DSToff;
919 ;
920 break;}
921 case 12:
922 #line 205 "parsedate.y"
923 {
924 yyval.Number = yyvsp[0].Number;
925 yyDSTmode = DSToff;
926 ;
927 break;}
928 case 13:
929 #line 209 "parsedate.y"
930 {
931 yyval.Number = yyvsp[0].Number;
932 yyDSTmode = DSTon;
933 ;
934 break;}
935 case 14:
936 #line 213 "parsedate.y"
937 {
938 yyTimezone = yyvsp[-1].Number;
939 yyDSTmode = DSTon;
940 ;
941 break;}
942 case 15:
943 #line 217 "parsedate.y"
944 {
945 /* Only allow "GMT+300" and "GMT-0800" */
946 if (yyvsp[-1].Number != 0) {
947 YYABORT;
948 }
949 yyval.Number = yyvsp[0].Number;
950 yyDSTmode = DSToff;
951 ;
952 break;}
953 case 16:
954 #line 225 "parsedate.y"
955 {
956 yyval.Number = yyvsp[0].Number;
957 yyDSTmode = DSToff;
958 ;
959 break;}
960 case 17:
961 #line 231 "parsedate.y"
962 {
963 int i;
964
965 /* Unix and GMT and numeric timezones -- a little confusing. */
966 if (yyvsp[0].Number < 0) {
967 /* Don't work with negative modulus. */
968 yyvsp[0].Number = -yyvsp[0].Number;
969 if (yyvsp[0].Number > 9999 || (i = yyvsp[0].Number % 100) >= 60) {
970 YYABORT;
971 }
972 yyval.Number = (yyvsp[0].Number / 100) * 60 + i;
973 }
974 else {
975 if (yyvsp[0].Number > 9999 || (i = yyvsp[0].Number % 100) >= 60) {
976 YYABORT;
977 }
978 yyval.Number = -((yyvsp[0].Number / 100) * 60 + i);
979 }
980 ;
981 break;}
982 case 18:
983 #line 252 "parsedate.y"
984 {
985 yyMonth = yyvsp[-2].Number;
986 yyDay = yyvsp[0].Number;
987 ;
988 break;}
989 case 19:
990 #line 256 "parsedate.y"
991 {
992 if (yyvsp[-4].Number > 100) {
993 yyYear = yyvsp[-4].Number;
994 yyMonth = yyvsp[-2].Number;
995 yyDay = yyvsp[0].Number;
996 }
997 else {
998 yyMonth = yyvsp[-4].Number;
999 yyDay = yyvsp[-2].Number;
1000 yyYear = yyvsp[0].Number;
1001 }
1002 ;
1003 break;}
1004 case 20:
1005 #line 268 "parsedate.y"
1006 {
1007 yyMonth = yyvsp[-1].Number;
1008 yyDay = yyvsp[0].Number;
1009 ;
1010 break;}
1011 case 21:
1012 #line 272 "parsedate.y"
1013 {
1014 yyMonth = yyvsp[-3].Number;
1015 yyDay = yyvsp[-2].Number;
1016 yyYear = yyvsp[0].Number;
1017 ;
1018 break;}
1019 case 22:
1020 #line 277 "parsedate.y"
1021 {
1022 yyDay = yyvsp[-1].Number;
1023 yyMonth = yyvsp[0].Number;
1024 ;
1025 break;}
1026 case 23:
1027 #line 281 "parsedate.y"
1028 {
1029 yyDay = yyvsp[-2].Number;
1030 yyMonth = yyvsp[-1].Number;
1031 yyYear = yyvsp[0].Number;
1032 ;
1033 break;}
1034 case 24:
1035 #line 286 "parsedate.y"
1036 {
1037 yyDay = yyvsp[-2].Number;
1038 yyMonth = yyvsp[-1].Number;
1039 yyYear = yyvsp[0].Number;
1040 ;
1041 break;}
1042 case 25:
1043 #line 291 "parsedate.y"
1044 {
1045 yyDay = yyvsp[-2].Number;
1046 yyMonth = yyvsp[-1].Number;
1047 yyYear = yyvsp[0].Number;
1048 ;
1049 break;}
1050 case 26:
1051 #line 298 "parsedate.y"
1052 {
1053 yyRelSeconds += yyvsp[-1].Number * yyvsp[0].Number;
1054 ;
1055 break;}
1056 case 27:
1057 #line 301 "parsedate.y"
1058 {
1059 yyRelSeconds += yyvsp[-1].Number * yyvsp[0].Number;
1060 ;
1061 break;}
1062 case 28:
1063 #line 304 "parsedate.y"
1064 {
1065 yyRelMonth += yyvsp[-1].Number * yyvsp[0].Number;
1066 ;
1067 break;}
1068 case 29:
1069 #line 307 "parsedate.y"
1070 {
1071 yyRelMonth += yyvsp[-1].Number * yyvsp[0].Number;
1072 ;
1073 break;}
1074 case 30:
1075 #line 312 "parsedate.y"
1076 {
1077 yyval.Meridian = MER24;
1078 ;
1079 break;}
1080 case 31:
1081 #line 315 "parsedate.y"
1082 {
1083 yyval.Meridian = yyvsp[0].Meridian;
1084 ;
1085 break;}
1086 }
1087 /* the action file gets copied in in place of this dollarsign */
1088 #line 543 "/usr/lib/bison.simple"
1089
1090 yyvsp -= yylen;
1091 yyssp -= yylen;
1092 #ifdef YYLSP_NEEDED
1093 yylsp -= yylen;
1094 #endif
1095
1096 #if YYDEBUG != 0
1097 if (yydebug)
1098 {
1099 short *ssp1 = yyss - 1;
1100 fprintf (stderr, "state stack now");
1101 while (ssp1 != yyssp)
1102 fprintf (stderr, " %d", *++ssp1);
1103 fprintf (stderr, "\n");
1104 }
1105 #endif
1106
1107 *++yyvsp = yyval;
1108
1109 #ifdef YYLSP_NEEDED
1110 yylsp++;
1111 if (yylen == 0)
1112 {
1113 yylsp->first_line = yylloc.first_line;
1114 yylsp->first_column = yylloc.first_column;
1115 yylsp->last_line = (yylsp-1)->last_line;
1116 yylsp->last_column = (yylsp-1)->last_column;
1117 yylsp->text = 0;
1118 }
1119 else
1120 {
1121 yylsp->last_line = (yylsp+yylen-1)->last_line;
1122 yylsp->last_column = (yylsp+yylen-1)->last_column;
1123 }
1124 #endif
1125
1126 /* Now "shift" the result of the reduction.
1127 Determine what state that goes to,
1128 based on the state we popped back to
1129 and the rule number reduced by. */
1130
1131 yyn = yyr1[yyn];
1132
1133 yystate = yypgoto[yyn - YYNTBASE] + *yyssp;
1134 if (yystate >= 0 && yystate <= YYLAST && yycheck[yystate] == *yyssp)
1135 yystate = yytable[yystate];
1136 else
1137 yystate = yydefgoto[yyn - YYNTBASE];
1138
1139 goto yynewstate;
1140
1141 yyerrlab: /* here on detecting error */
1142
1143 if (! yyerrstatus)
1144 /* If not already recovering from an error, report this error. */
1145 {
1146 ++yynerrs;
1147
1148 #ifdef YYERROR_VERBOSE
1149 yyn = yypact[yystate];
1150
1151 if (yyn > YYFLAG && yyn < YYLAST)
1152 {
1153 int size = 0;
1154 char *msg;
1155 int x, count;
1156
1157 count = 0;
1158 /* Start X at -yyn if nec to avoid negative indexes in yycheck. */
1159 for (x = (yyn < 0 ? -yyn : 0);
1160 x < (sizeof(yytname) / sizeof(char *)); x++)
1161 if (yycheck[x + yyn] == x)
1162 size += strlen(yytname[x]) + 15, count++;
1163 msg = (char *) malloc(size + 15);
1164 if (msg != 0)
1165 {
1166 strcpy(msg, "parse error");
1167
1168 if (count < 5)
1169 {
1170 count = 0;
1171 for (x = (yyn < 0 ? -yyn : 0);
1172 x < (sizeof(yytname) / sizeof(char *)); x++)
1173 if (yycheck[x + yyn] == x)
1174 {
1175 strcat(msg, count == 0 ? ", expecting `" : " or `");
1176 strcat(msg, yytname[x]);
1177 strcat(msg, "'");
1178 count++;
1179 }
1180 }
1181 yyerror(msg);
1182 free(msg);
1183 }
1184 else
1185 yyerror ("parse error; also virtual memory exceeded");
1186 }
1187 else
1188 #endif /* YYERROR_VERBOSE */
1189 yyerror("parse error");
1190 }
1191
1192 goto yyerrlab1;
1193 yyerrlab1: /* here on error raised explicitly by an action */
1194
1195 if (yyerrstatus == 3)
1196 {
1197 /* if just tried and failed to reuse lookahead token after an error, discard it. */
1198
1199 /* return failure if at end of input */
1200 if (yychar == YYEOF)
1201 YYABORT;
1202
1203 #if YYDEBUG != 0
1204 if (yydebug)
1205 fprintf(stderr, "Discarding token %d (%s).\n", yychar, yytname[yychar1]);
1206 #endif
1207
1208 yychar = YYEMPTY;
1209 }
1210
1211 /* Else will try to reuse lookahead token
1212 after shifting the error token. */
1213
1214 yyerrstatus = 3; /* Each real token shifted decrements this */
1215
1216 goto yyerrhandle;
1217
1218 yyerrdefault: /* current state does not do anything special for the error token. */
1219
1220 #if 0
1221 /* This is wrong; only states that explicitly want error tokens
1222 should shift them. */
1223 yyn = yydefact[yystate]; /* If its default is to accept any token, ok. Otherwise pop it.*/
1224 if (yyn) goto yydefault;
1225 #endif
1226
1227 yyerrpop: /* pop the current state because it cannot handle the error token */
1228
1229 if (yyssp == yyss) YYABORT;
1230 yyvsp--;
1231 yystate = *--yyssp;
1232 #ifdef YYLSP_NEEDED
1233 yylsp--;
1234 #endif
1235
1236 #if YYDEBUG != 0
1237 if (yydebug)
1238 {
1239 short *ssp1 = yyss - 1;
1240 fprintf (stderr, "Error: state stack now");
1241 while (ssp1 != yyssp)
1242 fprintf (stderr, " %d", *++ssp1);
1243 fprintf (stderr, "\n");
1244 }
1245 #endif
1246
1247 yyerrhandle:
1248
1249 yyn = yypact[yystate];
1250 if (yyn == YYFLAG)
1251 goto yyerrdefault;
1252
1253 yyn += YYTERROR;
1254 if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != YYTERROR)
1255 goto yyerrdefault;
1256
1257 yyn = yytable[yyn];
1258 if (yyn < 0)
1259 {
1260 if (yyn == YYFLAG)
1261 goto yyerrpop;
1262 yyn = -yyn;
1263 goto yyreduce;
1264 }
1265 else if (yyn == 0)
1266 goto yyerrpop;
1267
1268 if (yyn == YYFINAL)
1269 YYACCEPT;
1270
1271 #if YYDEBUG != 0
1272 if (yydebug)
1273 fprintf(stderr, "Shifting error token, ");
1274 #endif
1275
1276 *++yyvsp = yylval;
1277 #ifdef YYLSP_NEEDED
1278 *++yylsp = yylloc;
1279 #endif
1280
1281 yystate = yyn;
1282 goto yynewstate;
1283
1284 yyacceptlab:
1285 /* YYACCEPT comes here. */
1286 if (yyfree_stacks)
1287 {
1288 free (yyss);
1289 free (yyvs);
1290 #ifdef YYLSP_NEEDED
1291 free (yyls);
1292 #endif
1293 }
1294 return 0;
1295
1296 yyabortlab:
1297 /* YYABORT comes here. */
1298 if (yyfree_stacks)
1299 {
1300 free (yyss);
1301 free (yyvs);
1302 #ifdef YYLSP_NEEDED
1303 free (yyls);
1304 #endif
1305 }
1306 return 1;
1307 }
1308 #line 320 "parsedate.y"
1309
1310
1311 /* Month and day table. */
1312 static TABLE MonthDayTable[] = {
1313 { "january", tMONTH, 1 },
1314 { "february", tMONTH, 2 },
1315 { "march", tMONTH, 3 },
1316 { "april", tMONTH, 4 },
1317 { "may", tMONTH, 5 },
1318 { "june", tMONTH, 6 },
1319 { "july", tMONTH, 7 },
1320 { "august", tMONTH, 8 },
1321 { "september", tMONTH, 9 },
1322 { "october", tMONTH, 10 },
1323 { "november", tMONTH, 11 },
1324 { "december", tMONTH, 12 },
1325 /* The value of the day isn't used... */
1326 { "sunday", tDAY, 0 },
1327 { "monday", tDAY, 0 },
1328 { "tuesday", tDAY, 0 },
1329 { "wednesday", tDAY, 0 },
1330 { "thursday", tDAY, 0 },
1331 { "friday", tDAY, 0 },
1332 { "saturday", tDAY, 0 },
1333 };
1334
1335 /* Time units table. */
1336 static TABLE UnitsTable[] = {
1337 { "year", tMONTH_UNIT, 12 },
1338 { "month", tMONTH_UNIT, 1 },
1339 { "week", tSEC_UNIT, 7 * 24 * 60 * 60 },
1340 { "day", tSEC_UNIT, 1 * 24 * 60 * 60 },
1341 { "hour", tSEC_UNIT, 60 * 60 },
1342 { "minute", tSEC_UNIT, 60 },
1343 { "min", tSEC_UNIT, 60 },
1344 { "second", tSEC_UNIT, 1 },
1345 { "sec", tSEC_UNIT, 1 },
1346 };
1347
1348 /* Timezone table. */
1349 static TABLE TimezoneTable[] = {
1350 { "gmt", tZONE, HOUR( 0) }, /* Greenwich Mean */
1351 { "ut", tZONE, HOUR( 0) }, /* Universal */
1352 { "utc", tZONE, HOUR( 0) }, /* Universal Coordinated */
1353 { "cut", tZONE, HOUR( 0) }, /* Coordinated Universal */
1354 { "z", tZONE, HOUR( 0) }, /* Greenwich Mean */
1355 { "wet", tZONE, HOUR( 0) }, /* Western European */
1356 { "bst", tDAYZONE, HOUR( 0) }, /* British Summer */
1357 { "nst", tZONE, HOUR(3)+30 }, /* Newfoundland Standard */
1358 { "ndt", tDAYZONE, HOUR(3)+30 }, /* Newfoundland Daylight */
1359 { "ast", tZONE, HOUR( 4) }, /* Atlantic Standard */
1360 { "adt", tDAYZONE, HOUR( 4) }, /* Atlantic Daylight */
1361 { "est", tZONE, HOUR( 5) }, /* Eastern Standard */
1362 { "edt", tDAYZONE, HOUR( 5) }, /* Eastern Daylight */
1363 { "cst", tZONE, HOUR( 6) }, /* Central Standard */
1364 { "cdt", tDAYZONE, HOUR( 6) }, /* Central Daylight */
1365 { "mst", tZONE, HOUR( 7) }, /* Mountain Standard */
1366 { "mdt", tDAYZONE, HOUR( 7) }, /* Mountain Daylight */
1367 { "pst", tZONE, HOUR( 8) }, /* Pacific Standard */
1368 { "pdt", tDAYZONE, HOUR( 8) }, /* Pacific Daylight */
1369 { "yst", tZONE, HOUR( 9) }, /* Yukon Standard */
1370 { "ydt", tDAYZONE, HOUR( 9) }, /* Yukon Daylight */
1371 { "akst", tZONE, HOUR( 9) }, /* Alaska Standard */
1372 { "akdt", tDAYZONE, HOUR( 9) }, /* Alaska Daylight */
1373 { "hst", tZONE, HOUR(10) }, /* Hawaii Standard */
1374 { "hast", tZONE, HOUR(10) }, /* Hawaii-Aleutian Standard */
1375 { "hadt", tDAYZONE, HOUR(10) }, /* Hawaii-Aleutian Daylight */
1376 { "ces", tDAYZONE, -HOUR(1) }, /* Central European Summer */
1377 { "cest", tDAYZONE, -HOUR(1) }, /* Central European Summer */
1378 { "mez", tZONE, -HOUR(1) }, /* Middle European */
1379 { "mezt", tDAYZONE, -HOUR(1) }, /* Middle European Summer */
1380 { "cet", tZONE, -HOUR(1) }, /* Central European */
1381 { "met", tZONE, -HOUR(1) }, /* Middle European */
1382 /* Additional aliases for MET / MET DST *************************************/
1383 { "mez", tZONE, -HOUR(1) }, /* Middle European */
1384 { "mewt", tZONE, -HOUR(1) }, /* Middle European Winter */
1385 { "mest", tDAYZONE, -HOUR(1) }, /* Middle European Summer */
1386 { "mes", tDAYZONE, -HOUR(1) }, /* Middle European Summer */
1387 { "mesz", tDAYZONE, -HOUR(1) }, /* Middle European Summer */
1388 { "msz", tDAYZONE, -HOUR(1) }, /* Middle European Summer */
1389 { "metdst", tDAYZONE, -HOUR(1) }, /* Middle European Summer */
1390 /****************************************************************************/
1391 { "eet", tZONE, -HOUR(2) }, /* Eastern Europe */
1392 { "msk", tZONE, -HOUR(3) }, /* Moscow Winter */
1393 { "msd", tDAYZONE, -HOUR(3) }, /* Moscow Summer */
1394 { "wast", tZONE, -HOUR(8) }, /* West Australian Standard */
1395 { "wadt", tDAYZONE, -HOUR(8) }, /* West Australian Daylight */
1396 { "hkt", tZONE, -HOUR(8) }, /* Hong Kong */
1397 { "cct", tZONE, -HOUR(8) }, /* China Coast */
1398 { "jst", tZONE, -HOUR(9) }, /* Japan Standard */
1399 { "kst", tZONE, -HOUR(9) }, /* Korean Standard */
1400 { "kdt", tZONE, -HOUR(9) }, /* Korean Daylight */
1401 { "cast", tZONE, -(HOUR(9)+30) }, /* Central Australian Standard */
1402 { "cadt", tDAYZONE, -(HOUR(9)+30) }, /* Central Australian Daylight */
1403 { "east", tZONE, -HOUR(10) }, /* Eastern Australian Standard */
1404 { "eadt", tDAYZONE, -HOUR(10) }, /* Eastern Australian Daylight */
1405 { "nzst", tZONE, -HOUR(12) }, /* New Zealand Standard */
1406 { "nzdt", tDAYZONE, -HOUR(12) }, /* New Zealand Daylight */
1407
1408 /* For completeness we include the following entries. */
1409 #if 0
1410
1411 /* Duplicate names. Either they conflict with a zone listed above
1412 * (which is either more likely to be seen or just been in circulation
1413 * longer), or they conflict with another zone in this section and
1414 * we could not reasonably choose one over the other. */
1415 { "fst", tZONE, HOUR( 2) }, /* Fernando De Noronha Standard */
1416 { "fdt", tDAYZONE, HOUR( 2) }, /* Fernando De Noronha Daylight */
1417 { "bst", tZONE, HOUR( 3) }, /* Brazil Standard */
1418 { "est", tZONE, HOUR( 3) }, /* Eastern Standard (Brazil) */
1419 { "edt", tDAYZONE, HOUR( 3) }, /* Eastern Daylight (Brazil) */
1420 { "wst", tZONE, HOUR( 4) }, /* Western Standard (Brazil) */
1421 { "wdt", tDAYZONE, HOUR( 4) }, /* Western Daylight (Brazil) */
1422 { "cst", tZONE, HOUR( 5) }, /* Chile Standard */
1423 { "cdt", tDAYZONE, HOUR( 5) }, /* Chile Daylight */
1424 { "ast", tZONE, HOUR( 5) }, /* Acre Standard */
1425 { "adt", tDAYZONE, HOUR( 5) }, /* Acre Daylight */
1426 { "cst", tZONE, HOUR( 5) }, /* Cuba Standard */
1427 { "cdt", tDAYZONE, HOUR( 5) }, /* Cuba Daylight */
1428 { "est", tZONE, HOUR( 6) }, /* Easter Island Standard */
1429 { "edt", tDAYZONE, HOUR( 6) }, /* Easter Island Daylight */
1430 { "sst", tZONE, HOUR(11) }, /* Samoa Standard */
1431 { "ist", tZONE, -HOUR(2) }, /* Israel Standard */
1432 { "idt", tDAYZONE, -HOUR(2) }, /* Israel Daylight */
1433 { "idt", tDAYZONE, -(HOUR(3)+30) }, /* Iran Daylight */
1434 { "ist", tZONE, -(HOUR(3)+30) }, /* Iran Standard */
1435 { "cst", tZONE, -HOUR(8) }, /* China Standard */
1436 { "cdt", tDAYZONE, -HOUR(8) }, /* China Daylight */
1437 { "sst", tZONE, -HOUR(8) }, /* Singapore Standard */
1438
1439 /* Dubious (e.g., not in Olson's TIMEZONE package) or obsolete. */
1440 { "gst", tZONE, HOUR( 3) }, /* Greenland Standard */
1441 { "wat", tZONE, -HOUR(1) }, /* West Africa */
1442 { "at", tZONE, HOUR( 2) }, /* Azores */
1443 { "gst", tZONE, -HOUR(10) }, /* Guam Standard */
1444 { "nft", tZONE, HOUR(3)+30 }, /* Newfoundland */
1445 { "idlw", tZONE, HOUR(12) }, /* International Date Line West */
1446 { "mewt", tZONE, -HOUR(1) }, /* Middle European Winter */
1447 { "mest", tDAYZONE, -HOUR(1) }, /* Middle European Summer */
1448 { "swt", tZONE, -HOUR(1) }, /* Swedish Winter */
1449 { "sst", tDAYZONE, -HOUR(1) }, /* Swedish Summer */
1450 { "fwt", tZONE, -HOUR(1) }, /* French Winter */
1451 { "fst", tDAYZONE, -HOUR(1) }, /* French Summer */
1452 { "bt", tZONE, -HOUR(3) }, /* Baghdad */
1453 { "it", tZONE, -(HOUR(3)+30) }, /* Iran */
1454 { "zp4", tZONE, -HOUR(4) }, /* USSR Zone 3 */
1455 { "zp5", tZONE, -HOUR(5) }, /* USSR Zone 4 */
1456 { "ist", tZONE, -(HOUR(5)+30) }, /* Indian Standard */
1457 { "zp6", tZONE, -HOUR(6) }, /* USSR Zone 5 */
1458 { "nst", tZONE, -HOUR(7) }, /* North Sumatra */
1459 { "sst", tZONE, -HOUR(7) }, /* South Sumatra */
1460 { "jt", tZONE, -(HOUR(7)+30) }, /* Java (3pm in Cronusland!) */
1461 { "nzt", tZONE, -HOUR(12) }, /* New Zealand */
1462 { "idle", tZONE, -HOUR(12) }, /* International Date Line East */
1463 { "cat", tZONE, HOUR(10) }, /* -- expired 1967 */
1464 { "nt", tZONE, HOUR(11) }, /* -- expired 1967 */
1465 { "ahst", tZONE, HOUR(10) }, /* -- expired 1983 */
1466 { "hdt", tDAYZONE, HOUR(10) }, /* -- expired 1986 */
1467 #endif /* 0 */
1468 };
1469
1470
1471
1472 /* ARGSUSED */
1473 static void
date_error(char * s)1474 date_error(char *s)
1475 {
1476 /* NOTREACHED */
1477 }
1478
1479
1480 static time_t
ToSeconds(time_t Hours,time_t Minutes,time_t Seconds,MERIDIAN Meridian)1481 ToSeconds(time_t Hours, time_t Minutes, time_t Seconds, MERIDIAN Meridian)
1482 {
1483 if (Minutes < 0 || Minutes > 59 || Seconds < 0 || Seconds > 61)
1484 return -1;
1485 if (Meridian == MER24) {
1486 if (Hours < 0 || Hours > 23)
1487 return -1;
1488 }
1489 else {
1490 if (Hours < 1 || Hours > 12)
1491 return -1;
1492 if (Hours == 12)
1493 Hours = 0;
1494 if (Meridian == MERpm)
1495 Hours += 12;
1496 }
1497 return (Hours * 60L + Minutes) * 60L + Seconds;
1498 }
1499
1500
1501 static time_t
Convert(time_t Month,time_t Day,time_t Year,time_t Hours,time_t Minutes,time_t Seconds,MERIDIAN Meridian,DSTMODE dst)1502 Convert(time_t Month, time_t Day, time_t Year, time_t Hours, time_t Minutes, time_t Seconds, MERIDIAN Meridian, DSTMODE dst)
1503 {
1504 static int DaysNormal[13] = {
1505 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
1506 };
1507 static int DaysLeap[13] = {
1508 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
1509 };
1510 static int LeapYears[] = {
1511 1972, 1976, 1980, 1984, 1988, 1992, 1996,
1512 2000, 2004, 2008, 2012, 2016, 2020, 2024, 2028, 2032, 2036
1513 };
1514 register int *yp;
1515 register int *mp;
1516 register time_t Julian;
1517 register int i;
1518 time_t tod;
1519
1520 if (Year < 0)
1521 Year = -Year;
1522 if (Year < 100)
1523 Year += 1900;
1524 if (Year < EPOCH)
1525 Year += 100;
1526 for (mp = DaysNormal, yp = LeapYears; yp < ENDOF(LeapYears); yp++)
1527 if (Year == *yp) {
1528 mp = DaysLeap;
1529 break;
1530 }
1531 if (Year < EPOCH || Year > END_OF_TIME
1532 || Month < 1 || Month > 12
1533 /* NOSTRICT *//* conversion from long may lose accuracy */
1534 || Day < 1 || Day > mp[(int)Month])
1535 return -1;
1536
1537 Julian = Day - 1 + (Year - EPOCH) * 365;
1538 for (yp = LeapYears; yp < ENDOF(LeapYears); yp++, Julian++)
1539 if (Year <= *yp)
1540 break;
1541 for (i = 1; i < Month; i++)
1542 Julian += *++mp;
1543 Julian *= SECSPERDAY;
1544 Julian += yyTimezone * 60L;
1545 if ((tod = ToSeconds(Hours, Minutes, Seconds, Meridian)) < 0)
1546 return -1;
1547 Julian += tod;
1548 tod = Julian;
1549 if (dst == DSTon || (dst == DSTmaybe && localtime(&tod)->tm_isdst))
1550 Julian -= DST_OFFSET * 60 * 60;
1551 return Julian;
1552 }
1553
1554
1555 static time_t
DSTcorrect(time_t Start,time_t Future)1556 DSTcorrect(time_t Start, time_t Future)
1557 {
1558 time_t StartDay;
1559 time_t FutureDay;
1560
1561 StartDay = (localtime(&Start)->tm_hour + 1) % 24;
1562 FutureDay = (localtime(&Future)->tm_hour + 1) % 24;
1563 return (Future - Start) + (StartDay - FutureDay) * DST_OFFSET * 60 * 60;
1564 }
1565
1566
1567 static time_t
RelativeMonth(time_t Start,time_t RelMonth)1568 RelativeMonth(time_t Start, time_t RelMonth)
1569 {
1570 struct tm *tm;
1571 time_t Month;
1572 time_t Year;
1573
1574 tm = localtime(&Start);
1575 Month = 12 * tm->tm_year + tm->tm_mon + RelMonth;
1576 Year = Month / 12;
1577 Month = Month % 12 + 1;
1578 return DSTcorrect(Start,
1579 Convert(Month, (time_t)tm->tm_mday, Year,
1580 (time_t)tm->tm_hour, (time_t)tm->tm_min, (time_t)tm->tm_sec,
1581 MER24, DSTmaybe));
1582 }
1583
1584
1585 static int
LookupWord(char * buff,register int length)1586 LookupWord(char *buff, register int length)
1587 {
1588 register char *p;
1589 register STRING q;
1590 register TABLE *tp;
1591 register int c;
1592
1593 p = buff;
1594 c = p[0];
1595
1596 /* See if we have an abbreviation for a month. */
1597 if (length == 3 || (length == 4 && p[3] == '.'))
1598 for (tp = MonthDayTable; tp < ENDOF(MonthDayTable); tp++) {
1599 q = tp->name;
1600 if (c == q[0] && p[1] == q[1] && p[2] == q[2]) {
1601 yylval.Number = tp->value;
1602 return tp->type;
1603 }
1604 }
1605 else
1606 for (tp = MonthDayTable; tp < ENDOF(MonthDayTable); tp++)
1607 if (c == tp->name[0] && strcmp(p, tp->name) == 0) {
1608 yylval.Number = tp->value;
1609 return tp->type;
1610 }
1611
1612 /* Try for a timezone. */
1613 for (tp = TimezoneTable; tp < ENDOF(TimezoneTable); tp++)
1614 if (c == tp->name[0] && p[1] == tp->name[1]
1615 && strcmp(p, tp->name) == 0) {
1616 yylval.Number = tp->value;
1617 return tp->type;
1618 }
1619
1620 if (strcmp(buff, "dst") == 0)
1621 return tDST;
1622
1623 /* Try the units table. */
1624 for (tp = UnitsTable; tp < ENDOF(UnitsTable); tp++)
1625 if (c == tp->name[0] && strcmp(p, tp->name) == 0) {
1626 yylval.Number = tp->value;
1627 return tp->type;
1628 }
1629
1630 /* Strip off any plural and try the units table again. */
1631 if (--length > 0 && p[length] == 's') {
1632 p[length] = '\0';
1633 for (tp = UnitsTable; tp < ENDOF(UnitsTable); tp++)
1634 if (c == tp->name[0] && strcmp(p, tp->name) == 0) {
1635 p[length] = 's';
1636 yylval.Number = tp->value;
1637 return tp->type;
1638 }
1639 p[length] = 's';
1640 }
1641 length++;
1642
1643 /* Drop out any periods. */
1644 for (p = buff, q = (STRING)buff; *q; q++)
1645 if (*q != '.')
1646 *p++ = *q;
1647 *p = '\0';
1648
1649 /* Try the meridians. */
1650 if (buff[1] == 'm' && buff[2] == '\0') {
1651 if (buff[0] == 'a') {
1652 yylval.Meridian = MERam;
1653 return tMERIDIAN;
1654 }
1655 if (buff[0] == 'p') {
1656 yylval.Meridian = MERpm;
1657 return tMERIDIAN;
1658 }
1659 }
1660
1661 /* If we saw any periods, try the timezones again. */
1662 if (p - buff != length) {
1663 c = buff[0];
1664 for (p = buff, tp = TimezoneTable; tp < ENDOF(TimezoneTable); tp++)
1665 if (c == tp->name[0] && p[1] == tp->name[1]
1666 && strcmp(p, tp->name) == 0) {
1667 yylval.Number = tp->value;
1668 return tp->type;
1669 }
1670 }
1671
1672 /* Unknown word -- assume GMT timezone. */
1673 yylval.Number = 0;
1674 return tZONE;
1675 }
1676
1677
1678 static int
date_lex(void)1679 date_lex(void)
1680 {
1681 register char c;
1682 register char *p;
1683 char buff[20];
1684 register int sign;
1685 register int i;
1686 register int nesting;
1687
1688 for ( ; ; ) {
1689 /* Get first character after the whitespace. */
1690 for ( ; ; ) {
1691 while (CTYPE(isspace, *yyInput))
1692 yyInput++;
1693 c = *yyInput;
1694
1695 /* Ignore RFC 822 comments, typically time zone names. */
1696 if (c != LPAREN)
1697 break;
1698 for (nesting = 1; (c = *++yyInput) != RPAREN || --nesting; )
1699 if (c == LPAREN)
1700 nesting++;
1701 else if (!IS7BIT(c) || c == '\0' || c == '\r'
1702 || (c == '\\' && ((c = *++yyInput) == '\0' || !IS7BIT(c))))
1703 /* Lexical error: bad comment. */
1704 return '?';
1705 yyInput++;
1706 }
1707
1708 /* A number? */
1709 if (CTYPE(isdigit, c) || c == '-' || c == '+') {
1710 if (c == '-' || c == '+') {
1711 sign = c == '-' ? -1 : 1;
1712 yyInput++;
1713 if (!CTYPE(isdigit, *yyInput))
1714 /* Skip the plus or minus sign. */
1715 continue;
1716 }
1717 else
1718 sign = 0;
1719 for (i = 0; (c = *yyInput++) != '\0' && CTYPE(isdigit, c); )
1720 i = 10 * i + c - '0';
1721 yyInput--;
1722 yylval.Number = sign < 0 ? -i : i;
1723 return sign ? tSNUMBER : tUNUMBER;
1724 }
1725
1726 /* A word? */
1727 if (CTYPE(isalpha, c)) {
1728 for (p = buff; (c = *yyInput++) == '.' || CTYPE(isalpha, c); )
1729 if (p < &buff[sizeof buff - 1])
1730 *p++ = CTYPE(isupper, c) ? tolower(c) : c;
1731 *p = '\0';
1732 yyInput--;
1733 return LookupWord(buff, p - buff);
1734 }
1735
1736 return *yyInput++;
1737 }
1738 }
1739
1740
1741 time_t
parsedate(char * p,TIMEINFO * now)1742 parsedate(char *p, TIMEINFO *now)
1743 {
1744 extern int date_parse(void);
1745 struct tm *tm;
1746 TIMEINFO ti;
1747 time_t Start;
1748
1749 yyInput = p;
1750 if (now == NULL) {
1751 now = &ti;
1752 (void)GetTimeInfo(&ti);
1753 }
1754
1755 tm = localtime(&now->time);
1756 yyYear = tm->tm_year;
1757 yyMonth = tm->tm_mon + 1;
1758 yyDay = tm->tm_mday;
1759 yyTimezone = now->tzone;
1760 if(tm->tm_isdst) /* Correct timezone offset for DST */
1761 yyTimezone += DST_OFFSET * 60;
1762 yyDSTmode = DSTmaybe;
1763 yyHour = 0;
1764 yyMinutes = 0;
1765 yySeconds = 0;
1766 yyMeridian = MER24;
1767 yyRelSeconds = 0;
1768 yyRelMonth = 0;
1769 yyHaveDate = 0;
1770 yyHaveRel = 0;
1771 yyHaveTime = 0;
1772
1773 if (date_parse() || yyHaveTime > 1 || yyHaveDate > 1)
1774 return -1;
1775
1776 if (yyHaveDate || yyHaveTime) {
1777 Start = Convert(yyMonth, yyDay, yyYear, yyHour, yyMinutes, yySeconds,
1778 yyMeridian, yyDSTmode);
1779 if (Start < 0)
1780 return -1;
1781 }
1782 else {
1783 Start = now->time;
1784 if (!yyHaveRel)
1785 Start -= (tm->tm_hour * 60L + tm->tm_min) * 60L + tm->tm_sec;
1786 }
1787
1788 Start += yyRelSeconds;
1789 if (yyRelMonth)
1790 Start += RelativeMonth(Start, yyRelMonth);
1791
1792 /* Have to do *something* with a legitimate -1 so it's distinguishable
1793 * from the error return value. (Alternately could set errno on error.) */
1794 return Start == -1 ? 0 : Start;
1795 }
1796
1797
1798
1799 /***** TEST main ************************************************************/
1800 #ifdef TEST
1801
1802 /*
1803 * Parser test
1804 */
main(int argc,char * argv[])1805 int main(int argc, char *argv[])
1806 {
1807 time_t t;
1808
1809 if(argc != 2)
1810 {
1811 fprintf(stderr, "usage: testdate DATE-STRING\n");
1812 exit(1);
1813 }
1814
1815 t = parsedate(argv[1], NULL);
1816
1817 printf("parsedate(%s) = %ld\n", argv[1], t);
1818 if(t != ERROR)
1819 {
1820 printf("date() = %s\n",
1821 date("%Y-%m-%d %X", &t));
1822
1823 printf(" %s\n",
1824 date("%a %b %d %H %j %m %M %S %w %x %X %y %Y %Z %O", &t) );
1825 }
1826
1827 exit(0);
1828
1829 /**NOT REACHED**/
1830 return 0;
1831 }
1832
1833 #endif /**TEST**/
1834