Cleaned up yacc problems that shouldn't have existed in the original port
[unix-history] / gnu / usr.bin / tar / getdate.y
CommitLineData
8c4ebc23
JH
1%{
2/* $Revision: 2.1 $
3**
4** Originally written by Steven M. Bellovin <smb@research.att.com> while
5** at the University of North Carolina at Chapel Hill. Later tweaked by
6** a couple of people on Usenet. Completely overhauled by Rich $alz
7** <rsalz@bbn.com> and Jim Berets <jberets@bbn.com> in August, 1990;
8** send any email to Rich.
9**
10** This grammar has eight shift/reduce conflicts.
11**
12** This code is in the public domain and has no copyright.
13*/
14/* SUPPRESS 287 on yaccpar_sccsid *//* Unusd static variable */
15/* SUPPRESS 288 on yyerrlab *//* Label unused */
16
17#ifdef HAVE_CONFIG_H
18#include "config.h"
19#endif
20
21#ifdef __GNUC__
22#define alloca __builtin_alloca
23#else
24#ifdef HAVE_ALLOCA_H
25#include <alloca.h>
26#else
27#ifdef _AIX /* for Bison */
28 #pragma alloca
29#else
30char *alloca ();
31#endif
32#endif
33#endif
34
35#include <stdio.h>
36#include <ctype.h>
37
38/* The code at the top of get_date which figures out the offset of the
39 current time zone checks various CPP symbols to see if special
40 tricks are need, but defaults to using the gettimeofday system call.
41 Include <sys/time.h> if that will be used. */
42
43#if !defined (USG) && !defined (sgi) && !defined (__386BSD__)
44#include <sys/time.h>
45#endif
46
47#if defined(vms)
48
49#include <types.h>
50#include <time.h>
51
52#else
53
54#include <sys/types.h>
55
56#if defined(USG) || !defined(HAVE_FTIME)
57/*
58** If you need to do a tzset() call to set the
59** timezone, and don't have ftime().
60*/
61struct timeb {
62 time_t time; /* Seconds since the epoch */
63 unsigned short millitm; /* Field not used */
64 short timezone;
65 short dstflag; /* Field not used */
66};
67
68#else
69
70#include <sys/timeb.h>
71
72#endif /* defined(USG) && !defined(HAVE_FTIME) */
73
74#if defined(BSD4_2) || defined(BSD4_1C) || (defined (hp9000) && !defined (hpux))
75#include <sys/time.h>
76#else
77#if defined(_AIX)
78#include <sys/time.h>
79#endif
80#include <time.h>
81#endif /* defined(BSD4_2) */
82
83#endif /* defined(vms) */
84
85#if defined (STDC_HEADERS) || defined (USG)
86#include <string.h>
87#endif
88
89#if sgi
90#undef timezone
91#endif
92
93extern struct tm *localtime();
94
95#define yyparse getdate_yyparse
96#define yylex getdate_yylex
97#define yyerror getdate_yyerror
98
99#if !defined(lint) && !defined(SABER)
100static char RCS[] =
101 "$Header: str2date.y,v 2.1 90/09/06 08:15:06 cronan Exp $";
102#endif /* !defined(lint) && !defined(SABER) */
103
104
105#define EPOCH 1970
106#define HOUR(x) ((time_t)(x) * 60)
107#define SECSPERDAY (24L * 60L * 60L)
108
109
110/*
111** An entry in the lexical lookup table.
112*/
113typedef struct _TABLE {
114 char *name;
115 int type;
116 time_t value;
117} TABLE;
118
119
120/*
121** Daylight-savings mode: on, off, or not yet known.
122*/
123typedef enum _DSTMODE {
124 DSTon, DSToff, DSTmaybe
125} DSTMODE;
126
127/*
128** Meridian: am, pm, or 24-hour style.
129*/
130typedef enum _MERIDIAN {
131 MERam, MERpm, MER24
132} MERIDIAN;
133
134
135/*
136** Global variables. We could get rid of most of these by using a good
137** union as the yacc stack. (This routine was originally written before
138** yacc had the %union construct.) Maybe someday; right now we only use
139** the %union very rarely.
140*/
141static char *yyInput;
142static DSTMODE yyDSTmode;
143static time_t yyDayOrdinal;
144static time_t yyDayNumber;
145static int yyHaveDate;
146static int yyHaveDay;
147static int yyHaveRel;
148static int yyHaveTime;
149static int yyHaveZone;
150static time_t yyTimezone;
151static time_t yyDay;
152static time_t yyHour;
153static time_t yyMinutes;
154static time_t yyMonth;
155static time_t yySeconds;
156static time_t yyYear;
157static MERIDIAN yyMeridian;
158static time_t yyRelMonth;
159static time_t yyRelSeconds;
160
161%}
162
163%union {
164 time_t Number;
165 enum _MERIDIAN Meridian;
166}
167
168%token tAGO tDAY tDAYZONE tID tMERIDIAN tMINUTE_UNIT tMONTH tMONTH_UNIT
169%token tSEC_UNIT tSNUMBER tUNUMBER tZONE tDST
170
171%type <Number> tDAY tDAYZONE tMINUTE_UNIT tMONTH tMONTH_UNIT
172%type <Number> tSEC_UNIT tSNUMBER tUNUMBER tZONE
173%type <Meridian> tMERIDIAN o_merid
174
175%%
176
177spec : /* NULL */
178 | spec item
179 ;
180
181item : time {
182 yyHaveTime++;
183 }
184 | zone {
185 yyHaveZone++;
186 }
187 | date {
188 yyHaveDate++;
189 }
190 | day {
191 yyHaveDay++;
192 }
193 | rel {
194 yyHaveRel++;
195 }
196 | number
197 ;
198
199time : tUNUMBER tMERIDIAN {
200 yyHour = $1;
201 yyMinutes = 0;
202 yySeconds = 0;
203 yyMeridian = $2;
204 }
205 | tUNUMBER ':' tUNUMBER o_merid {
206 yyHour = $1;
207 yyMinutes = $3;
208 yySeconds = 0;
209 yyMeridian = $4;
210 }
211 | tUNUMBER ':' tUNUMBER tSNUMBER {
212 yyHour = $1;
213 yyMinutes = $3;
214 yyMeridian = MER24;
215 yyDSTmode = DSToff;
216 yyTimezone = - ($4 % 100 + ($4 / 100) * 60);
217 }
218 | tUNUMBER ':' tUNUMBER ':' tUNUMBER o_merid {
219 yyHour = $1;
220 yyMinutes = $3;
221 yySeconds = $5;
222 yyMeridian = $6;
223 }
224 | tUNUMBER ':' tUNUMBER ':' tUNUMBER tSNUMBER {
225 yyHour = $1;
226 yyMinutes = $3;
227 yySeconds = $5;
228 yyMeridian = MER24;
229 yyDSTmode = DSToff;
230 yyTimezone = - ($6 % 100 + ($6 / 100) * 60);
231 }
232 ;
233
234zone : tZONE {
235 yyTimezone = $1;
236 yyDSTmode = DSToff;
237 }
238 | tDAYZONE {
239 yyTimezone = $1;
240 yyDSTmode = DSTon;
241 }
242 |
243 tZONE tDST {
244 yyTimezone = $1;
245 yyDSTmode = DSTon;
246 }
247 ;
248
249day : tDAY {
250 yyDayOrdinal = 1;
251 yyDayNumber = $1;
252 }
253 | tDAY ',' {
254 yyDayOrdinal = 1;
255 yyDayNumber = $1;
256 }
257 | tUNUMBER tDAY {
258 yyDayOrdinal = $1;
259 yyDayNumber = $2;
260 }
261 ;
262
263date : tUNUMBER '/' tUNUMBER {
264 yyMonth = $1;
265 yyDay = $3;
266 }
267 | tUNUMBER '/' tUNUMBER '/' tUNUMBER {
268 yyMonth = $1;
269 yyDay = $3;
270 yyYear = $5;
271 }
272 | tUNUMBER tSNUMBER tSNUMBER {
273 /* ISO 8601 format. yyyy-mm-dd. */
274 yyYear = $1;
275 yyMonth = -$2;
276 yyDay = -$3;
277 }
278 | tMONTH tUNUMBER {
279 yyMonth = $1;
280 yyDay = $2;
281 }
282 | tMONTH tUNUMBER ',' tUNUMBER {
283 yyMonth = $1;
284 yyDay = $2;
285 yyYear = $4;
286 }
287 | tUNUMBER tMONTH {
288 yyMonth = $2;
289 yyDay = $1;
290 }
291 | tUNUMBER tMONTH tUNUMBER {
292 yyMonth = $2;
293 yyDay = $1;
294 yyYear = $3;
295 }
296 ;
297
298rel : relunit tAGO {
299 yyRelSeconds = -yyRelSeconds;
300 yyRelMonth = -yyRelMonth;
301 }
302 | relunit
303 ;
304
305relunit : tUNUMBER tMINUTE_UNIT {
306 yyRelSeconds += $1 * $2 * 60L;
307 }
308 | tSNUMBER tMINUTE_UNIT {
309 yyRelSeconds += $1 * $2 * 60L;
310 }
311 | tMINUTE_UNIT {
312 yyRelSeconds += $1 * 60L;
313 }
314 | tSNUMBER tSEC_UNIT {
315 yyRelSeconds += $1;
316 }
317 | tUNUMBER tSEC_UNIT {
318 yyRelSeconds += $1;
319 }
320 | tSEC_UNIT {
321 yyRelSeconds++;
322 }
323 | tSNUMBER tMONTH_UNIT {
324 yyRelMonth += $1 * $2;
325 }
326 | tUNUMBER tMONTH_UNIT {
327 yyRelMonth += $1 * $2;
328 }
329 | tMONTH_UNIT {
330 yyRelMonth += $1;
331 }
332 ;
333
334number : tUNUMBER {
335 if (yyHaveTime && yyHaveDate && !yyHaveRel)
336 yyYear = $1;
337 else {
338 if($1>10000) {
339 time_t date_part;
340
341 date_part= $1/10000;
342 yyHaveDate++;
343 yyDay= (date_part)%100;
344 yyMonth= (date_part/100)%100;
345 yyYear = date_part/10000;
346 }
347 yyHaveTime++;
348 if ($1 < 100) {
349 yyHour = $1;
350 yyMinutes = 0;
351 }
352 else {
353 yyHour = $1 / 100;
354 yyMinutes = $1 % 100;
355 }
356 yySeconds = 0;
357 yyMeridian = MER24;
358 }
359 }
360 ;
361
362o_merid : /* NULL */ {
363 $$ = MER24;
364 }
365 | tMERIDIAN {
366 $$ = $1;
367 }
368 ;
369
370%%
371
372/* Month and day table. */
373static TABLE const MonthDayTable[] = {
374 { "january", tMONTH, 1 },
375 { "february", tMONTH, 2 },
376 { "march", tMONTH, 3 },
377 { "april", tMONTH, 4 },
378 { "may", tMONTH, 5 },
379 { "june", tMONTH, 6 },
380 { "july", tMONTH, 7 },
381 { "august", tMONTH, 8 },
382 { "september", tMONTH, 9 },
383 { "sept", tMONTH, 9 },
384 { "october", tMONTH, 10 },
385 { "november", tMONTH, 11 },
386 { "december", tMONTH, 12 },
387 { "sunday", tDAY, 0 },
388 { "monday", tDAY, 1 },
389 { "tuesday", tDAY, 2 },
390 { "tues", tDAY, 2 },
391 { "wednesday", tDAY, 3 },
392 { "wednes", tDAY, 3 },
393 { "thursday", tDAY, 4 },
394 { "thur", tDAY, 4 },
395 { "thurs", tDAY, 4 },
396 { "friday", tDAY, 5 },
397 { "saturday", tDAY, 6 },
398 { NULL }
399};
400
401/* Time units table. */
402static TABLE const UnitsTable[] = {
403 { "year", tMONTH_UNIT, 12 },
404 { "month", tMONTH_UNIT, 1 },
405 { "fortnight", tMINUTE_UNIT, 14 * 24 * 60 },
406 { "week", tMINUTE_UNIT, 7 * 24 * 60 },
407 { "day", tMINUTE_UNIT, 1 * 24 * 60 },
408 { "hour", tMINUTE_UNIT, 60 },
409 { "minute", tMINUTE_UNIT, 1 },
410 { "min", tMINUTE_UNIT, 1 },
411 { "second", tSEC_UNIT, 1 },
412 { "sec", tSEC_UNIT, 1 },
413 { NULL }
414};
415
416/* Assorted relative-time words. */
417static TABLE const OtherTable[] = {
418 { "tomorrow", tMINUTE_UNIT, 1 * 24 * 60 },
419 { "yesterday", tMINUTE_UNIT, -1 * 24 * 60 },
420 { "today", tMINUTE_UNIT, 0 },
421 { "now", tMINUTE_UNIT, 0 },
422 { "last", tUNUMBER, -1 },
423 { "this", tMINUTE_UNIT, 0 },
424 { "next", tUNUMBER, 2 },
425 { "first", tUNUMBER, 1 },
426/* { "second", tUNUMBER, 2 }, */
427 { "third", tUNUMBER, 3 },
428 { "fourth", tUNUMBER, 4 },
429 { "fifth", tUNUMBER, 5 },
430 { "sixth", tUNUMBER, 6 },
431 { "seventh", tUNUMBER, 7 },
432 { "eighth", tUNUMBER, 8 },
433 { "ninth", tUNUMBER, 9 },
434 { "tenth", tUNUMBER, 10 },
435 { "eleventh", tUNUMBER, 11 },
436 { "twelfth", tUNUMBER, 12 },
437 { "ago", tAGO, 1 },
438 { NULL }
439};
440
441/* The timezone table. */
442/* Some of these are commented out because a time_t can't store a float. */
443static TABLE const TimezoneTable[] = {
444 { "gmt", tZONE, HOUR( 0) }, /* Greenwich Mean */
445 { "ut", tZONE, HOUR( 0) }, /* Universal (Coordinated) */
446 { "utc", tZONE, HOUR( 0) },
447 { "wet", tZONE, HOUR( 0) }, /* Western European */
448 { "bst", tDAYZONE, HOUR( 0) }, /* British Summer */
449 { "wat", tZONE, HOUR( 1) }, /* West Africa */
450 { "at", tZONE, HOUR( 2) }, /* Azores */
451#if 0
452 /* For completeness. BST is also British Summer, and GST is
453 * also Guam Standard. */
454 { "bst", tZONE, HOUR( 3) }, /* Brazil Standard */
455 { "gst", tZONE, HOUR( 3) }, /* Greenland Standard */
456#endif
457#if 0
458 { "nft", tZONE, HOUR(3.5) }, /* Newfoundland */
459 { "nst", tZONE, HOUR(3.5) }, /* Newfoundland Standard */
460 { "ndt", tDAYZONE, HOUR(3.5) }, /* Newfoundland Daylight */
461#endif
462 { "ast", tZONE, HOUR( 4) }, /* Atlantic Standard */
463 { "adt", tDAYZONE, HOUR( 4) }, /* Atlantic Daylight */
464 { "est", tZONE, HOUR( 5) }, /* Eastern Standard */
465 { "edt", tDAYZONE, HOUR( 5) }, /* Eastern Daylight */
466 { "cst", tZONE, HOUR( 6) }, /* Central Standard */
467 { "cdt", tDAYZONE, HOUR( 6) }, /* Central Daylight */
468 { "mst", tZONE, HOUR( 7) }, /* Mountain Standard */
469 { "mdt", tDAYZONE, HOUR( 7) }, /* Mountain Daylight */
470 { "pst", tZONE, HOUR( 8) }, /* Pacific Standard */
471 { "pdt", tDAYZONE, HOUR( 8) }, /* Pacific Daylight */
472 { "yst", tZONE, HOUR( 9) }, /* Yukon Standard */
473 { "ydt", tDAYZONE, HOUR( 9) }, /* Yukon Daylight */
474 { "hst", tZONE, HOUR(10) }, /* Hawaii Standard */
475 { "hdt", tDAYZONE, HOUR(10) }, /* Hawaii Daylight */
476 { "cat", tZONE, HOUR(10) }, /* Central Alaska */
477 { "ahst", tZONE, HOUR(10) }, /* Alaska-Hawaii Standard */
478 { "nt", tZONE, HOUR(11) }, /* Nome */
479 { "idlw", tZONE, HOUR(12) }, /* International Date Line West */
480 { "cet", tZONE, -HOUR(1) }, /* Central European */
481 { "met", tZONE, -HOUR(1) }, /* Middle European */
482 { "mewt", tZONE, -HOUR(1) }, /* Middle European Winter */
483 { "mest", tDAYZONE, -HOUR(1) }, /* Middle European Summer */
484 { "swt", tZONE, -HOUR(1) }, /* Swedish Winter */
485 { "sst", tDAYZONE, -HOUR(1) }, /* Swedish Summer */
486 { "fwt", tZONE, -HOUR(1) }, /* French Winter */
487 { "fst", tDAYZONE, -HOUR(1) }, /* French Summer */
488 { "eet", tZONE, -HOUR(2) }, /* Eastern Europe, USSR Zone 1 */
489 { "bt", tZONE, -HOUR(3) }, /* Baghdad, USSR Zone 2 */
490#if 0
491 { "it", tZONE, -HOUR(3.5) },/* Iran */
492#endif
493 { "zp4", tZONE, -HOUR(4) }, /* USSR Zone 3 */
494 { "zp5", tZONE, -HOUR(5) }, /* USSR Zone 4 */
495#if 0
496 { "ist", tZONE, -HOUR(5.5) },/* Indian Standard */
497#endif
498 { "zp6", tZONE, -HOUR(6) }, /* USSR Zone 5 */
499#if 0
500 /* For completeness. NST is also Newfoundland Stanard, and SST is
501 * also Swedish Summer. */
502 { "nst", tZONE, -HOUR(6.5) },/* North Sumatra */
503 { "sst", tZONE, -HOUR(7) }, /* South Sumatra, USSR Zone 6 */
504#endif /* 0 */
505 { "wast", tZONE, -HOUR(7) }, /* West Australian Standard */
506 { "wadt", tDAYZONE, -HOUR(7) }, /* West Australian Daylight */
507#if 0
508 { "jt", tZONE, -HOUR(7.5) },/* Java (3pm in Cronusland!) */
509#endif
510 { "cct", tZONE, -HOUR(8) }, /* China Coast, USSR Zone 7 */
511 { "jst", tZONE, -HOUR(9) }, /* Japan Standard, USSR Zone 8 */
512#if 0
513 { "cast", tZONE, -HOUR(9.5) },/* Central Australian Standard */
514 { "cadt", tDAYZONE, -HOUR(9.5) },/* Central Australian Daylight */
515#endif
516 { "east", tZONE, -HOUR(10) }, /* Eastern Australian Standard */
517 { "eadt", tDAYZONE, -HOUR(10) }, /* Eastern Australian Daylight */
518 { "gst", tZONE, -HOUR(10) }, /* Guam Standard, USSR Zone 9 */
519 { "nzt", tZONE, -HOUR(12) }, /* New Zealand */
520 { "nzst", tZONE, -HOUR(12) }, /* New Zealand Standard */
521 { "nzdt", tDAYZONE, -HOUR(12) }, /* New Zealand Daylight */
522 { "idle", tZONE, -HOUR(12) }, /* International Date Line East */
523 { NULL }
524};
525
526/* Military timezone table. */
527static TABLE const MilitaryTable[] = {
528 { "a", tZONE, HOUR( 1) },
529 { "b", tZONE, HOUR( 2) },
530 { "c", tZONE, HOUR( 3) },
531 { "d", tZONE, HOUR( 4) },
532 { "e", tZONE, HOUR( 5) },
533 { "f", tZONE, HOUR( 6) },
534 { "g", tZONE, HOUR( 7) },
535 { "h", tZONE, HOUR( 8) },
536 { "i", tZONE, HOUR( 9) },
537 { "k", tZONE, HOUR( 10) },
538 { "l", tZONE, HOUR( 11) },
539 { "m", tZONE, HOUR( 12) },
540 { "n", tZONE, HOUR(- 1) },
541 { "o", tZONE, HOUR(- 2) },
542 { "p", tZONE, HOUR(- 3) },
543 { "q", tZONE, HOUR(- 4) },
544 { "r", tZONE, HOUR(- 5) },
545 { "s", tZONE, HOUR(- 6) },
546 { "t", tZONE, HOUR(- 7) },
547 { "u", tZONE, HOUR(- 8) },
548 { "v", tZONE, HOUR(- 9) },
549 { "w", tZONE, HOUR(-10) },
550 { "x", tZONE, HOUR(-11) },
551 { "y", tZONE, HOUR(-12) },
552 { "z", tZONE, HOUR( 0) },
553 { NULL }
554};
555
556\f
557
558
559/* ARGSUSED */
560static int
561yyerror(s)
562 char *s;
563{
564 return 0;
565}
566
567
568static time_t
569ToSeconds(Hours, Minutes, Seconds, Meridian)
570 time_t Hours;
571 time_t Minutes;
572 time_t Seconds;
573 MERIDIAN Meridian;
574{
575 if (Minutes < 0 || Minutes > 59 || Seconds < 0 || Seconds > 59)
576 return -1;
577 switch (Meridian) {
578 case MER24:
579 if (Hours < 0 || Hours > 23)
580 return -1;
581 return (Hours * 60L + Minutes) * 60L + Seconds;
582 case MERam:
583 if (Hours < 1 || Hours > 12)
584 return -1;
585 return (Hours * 60L + Minutes) * 60L + Seconds;
586 case MERpm:
587 if (Hours < 1 || Hours > 12)
588 return -1;
589 return ((Hours + 12) * 60L + Minutes) * 60L + Seconds;
590 }
591 /* NOTREACHED */
592}
593
594
595static time_t
596Convert(Month, Day, Year, Hours, Minutes, Seconds, Meridian, DSTmode)
597 time_t Month;
598 time_t Day;
599 time_t Year;
600 time_t Hours;
601 time_t Minutes;
602 time_t Seconds;
603 MERIDIAN Meridian;
604 DSTMODE DSTmode;
605{
606 static int DaysInMonth[12] = {
607 31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
608 };
609 time_t tod;
610 time_t Julian;
611 int i;
612
613 if (Year < 0)
614 Year = -Year;
615 if (Year < 100)
616 Year += 1900;
617 DaysInMonth[1] = Year % 4 == 0 && (Year % 100 != 0 || Year % 400 == 0)
618 ? 29 : 28;
619 if (Year < EPOCH || Year > 1999
620 || Month < 1 || Month > 12
621 /* Lint fluff: "conversion from long may lose accuracy" */
622 || Day < 1 || Day > DaysInMonth[(int)--Month])
623 return -1;
624
625 for (Julian = Day - 1, i = 0; i < Month; i++)
626 Julian += DaysInMonth[i];
627 for (i = EPOCH; i < Year; i++)
628 Julian += 365 + (i % 4 == 0);
629 Julian *= SECSPERDAY;
630 Julian += yyTimezone * 60L;
631 if ((tod = ToSeconds(Hours, Minutes, Seconds, Meridian)) < 0)
632 return -1;
633 Julian += tod;
634 if (DSTmode == DSTon
635 || (DSTmode == DSTmaybe && localtime(&Julian)->tm_isdst))
636 Julian -= 60 * 60;
637 return Julian;
638}
639
640
641static time_t
642DSTcorrect(Start, Future)
643 time_t Start;
644 time_t Future;
645{
646 time_t StartDay;
647 time_t FutureDay;
648
649 StartDay = (localtime(&Start)->tm_hour + 1) % 24;
650 FutureDay = (localtime(&Future)->tm_hour + 1) % 24;
651 return (Future - Start) + (StartDay - FutureDay) * 60L * 60L;
652}
653
654
655static time_t
656RelativeDate(Start, DayOrdinal, DayNumber)
657 time_t Start;
658 time_t DayOrdinal;
659 time_t DayNumber;
660{
661 struct tm *tm;
662 time_t now;
663
664 now = Start;
665 tm = localtime(&now);
666 now += SECSPERDAY * ((DayNumber - tm->tm_wday + 7) % 7);
667 now += 7 * SECSPERDAY * (DayOrdinal <= 0 ? DayOrdinal : DayOrdinal - 1);
668 return DSTcorrect(Start, now);
669}
670
671
672static time_t
673RelativeMonth(Start, RelMonth)
674 time_t Start;
675 time_t RelMonth;
676{
677 struct tm *tm;
678 time_t Month;
679 time_t Year;
680
681 if (RelMonth == 0)
682 return 0;
683 tm = localtime(&Start);
684 Month = 12 * tm->tm_year + tm->tm_mon + RelMonth;
685 Year = Month / 12;
686 Month = Month % 12 + 1;
687 return DSTcorrect(Start,
688 Convert(Month, (time_t)tm->tm_mday, Year,
689 (time_t)tm->tm_hour, (time_t)tm->tm_min, (time_t)tm->tm_sec,
690 MER24, DSTmaybe));
691}
692
693
694static int
695LookupWord(buff)
696 char *buff;
697{
698 register char *p;
699 register char *q;
700 register const TABLE *tp;
701 int i;
702 int abbrev;
703
704 /* Make it lowercase. */
705 for (p = buff; *p; p++)
706 if (isupper(*p))
707 *p = tolower(*p);
708
709 if (strcmp(buff, "am") == 0 || strcmp(buff, "a.m.") == 0) {
710 yylval.Meridian = MERam;
711 return tMERIDIAN;
712 }
713 if (strcmp(buff, "pm") == 0 || strcmp(buff, "p.m.") == 0) {
714 yylval.Meridian = MERpm;
715 return tMERIDIAN;
716 }
717
718 /* See if we have an abbreviation for a month. */
719 if (strlen(buff) == 3)
720 abbrev = 1;
721 else if (strlen(buff) == 4 && buff[3] == '.') {
722 abbrev = 1;
723 buff[3] = '\0';
724 }
725 else
726 abbrev = 0;
727
728 for (tp = MonthDayTable; tp->name; tp++) {
729 if (abbrev) {
730 if (strncmp(buff, tp->name, 3) == 0) {
731 yylval.Number = tp->value;
732 return tp->type;
733 }
734 }
735 else if (strcmp(buff, tp->name) == 0) {
736 yylval.Number = tp->value;
737 return tp->type;
738 }
739 }
740
741 for (tp = TimezoneTable; tp->name; tp++)
742 if (strcmp(buff, tp->name) == 0) {
743 yylval.Number = tp->value;
744 return tp->type;
745 }
746
747 if (strcmp(buff, "dst") == 0)
748 return tDST;
749
750 for (tp = UnitsTable; tp->name; tp++)
751 if (strcmp(buff, tp->name) == 0) {
752 yylval.Number = tp->value;
753 return tp->type;
754 }
755
756 /* Strip off any plural and try the units table again. */
757 i = strlen(buff) - 1;
758 if (buff[i] == 's') {
759 buff[i] = '\0';
760 for (tp = UnitsTable; tp->name; tp++)
761 if (strcmp(buff, tp->name) == 0) {
762 yylval.Number = tp->value;
763 return tp->type;
764 }
765 buff[i] = 's'; /* Put back for "this" in OtherTable. */
766 }
767
768 for (tp = OtherTable; tp->name; tp++)
769 if (strcmp(buff, tp->name) == 0) {
770 yylval.Number = tp->value;
771 return tp->type;
772 }
773
774 /* Military timezones. */
775 if (buff[1] == '\0' && isalpha(*buff)) {
776 for (tp = MilitaryTable; tp->name; tp++)
777 if (strcmp(buff, tp->name) == 0) {
778 yylval.Number = tp->value;
779 return tp->type;
780 }
781 }
782
783 /* Drop out any periods and try the timezone table again. */
784 for (i = 0, p = q = buff; *q; q++)
785 if (*q != '.')
786 *p++ = *q;
787 else
788 i++;
789 *p = '\0';
790 if (i)
791 for (tp = TimezoneTable; tp->name; tp++)
792 if (strcmp(buff, tp->name) == 0) {
793 yylval.Number = tp->value;
794 return tp->type;
795 }
796
797 return tID;
798}
799
800
801static int
802yylex()
803{
804 register char c;
805 register char *p;
806 char buff[20];
807 int Count;
808 int sign;
809
810 for ( ; ; ) {
811 while (isspace(*yyInput))
812 yyInput++;
813
814 if (isdigit(c = *yyInput) || c == '-' || c == '+') {
815 if (c == '-' || c == '+') {
816 sign = c == '-' ? -1 : 1;
817 if (!isdigit(*++yyInput))
818 /* skip the '-' sign */
819 continue;
820 }
821 else
822 sign = 0;
823 for (yylval.Number = 0; isdigit(c = *yyInput++); )
824 yylval.Number = 10 * yylval.Number + c - '0';
825 yyInput--;
826 if (sign < 0)
827 yylval.Number = -yylval.Number;
828 return sign ? tSNUMBER : tUNUMBER;
829 }
830 if (isalpha(c)) {
831 for (p = buff; isalpha(c = *yyInput++) || c == '.'; )
832 if (p < &buff[sizeof buff - 1])
833 *p++ = c;
834 *p = '\0';
835 yyInput--;
836 return LookupWord(buff);
837 }
838 if (c != '(')
839 return *yyInput++;
840 Count = 0;
841 do {
842 c = *yyInput++;
843 if (c == '\0')
844 return c;
845 if (c == '(')
846 Count++;
847 else if (c == ')')
848 Count--;
849 } while (Count > 0);
850 }
851}
852
853
854time_t
855get_date(p, now)
856 char *p;
857 struct timeb *now;
858{
859 struct tm *tm;
860 struct timeb ftz;
861 time_t Start;
862 time_t tod;
863
864 yyInput = p;
865 if (now == NULL) {
866 now = &ftz;
867#if !defined(HAVE_FTIME)
868 (void)time(&ftz.time);
869 /* Set the timezone global. */
870 tzset();
871 {
872#if sgi
873 ftz.timezone = (int) _timezone / 60;
874#else /* not sgi */
875#ifdef __386BSD__
876 ftz.timezone = 0;
877#else /* neither sgi nor 386BSD */
878#if defined (USG)
879 extern time_t timezone;
880
881 ftz.timezone = (int) timezone / 60;
882#else /* neither sgi nor 386BSD nor USG */
883 struct timeval tv;
884 struct timezone tz;
885
886 gettimeofday (&tv, &tz);
887 ftz.timezone = (int) tz.tz_minuteswest;
888#endif /* neither sgi nor 386BSD nor USG */
889#endif /* neither sgi nor 386BSD */
890#endif /* not sgi */
891 }
892#else /* HAVE_FTIME */
893 (void)ftime(&ftz);
894#endif /* HAVE_FTIME */
895 }
896
897 tm = localtime(&now->time);
898 yyYear = tm->tm_year;
899 yyMonth = tm->tm_mon + 1;
900 yyDay = tm->tm_mday;
901 yyTimezone = now->timezone;
902 yyDSTmode = DSTmaybe;
903 yyHour = 0;
904 yyMinutes = 0;
905 yySeconds = 0;
906 yyMeridian = MER24;
907 yyRelSeconds = 0;
908 yyRelMonth = 0;
909 yyHaveDate = 0;
910 yyHaveDay = 0;
911 yyHaveRel = 0;
912 yyHaveTime = 0;
913 yyHaveZone = 0;
914
915 if (yyparse()
916 || yyHaveTime > 1 || yyHaveZone > 1 || yyHaveDate > 1 || yyHaveDay > 1)
917 return -1;
918
919 if (yyHaveDate || yyHaveTime || yyHaveDay) {
920 Start = Convert(yyMonth, yyDay, yyYear, yyHour, yyMinutes, yySeconds,
921 yyMeridian, yyDSTmode);
922 if (Start < 0)
923 return -1;
924 }
925 else {
926 Start = now->time;
927 if (!yyHaveRel)
928 Start -= ((tm->tm_hour * 60L + tm->tm_min) * 60L) + tm->tm_sec;
929 }
930
931 Start += yyRelSeconds;
932 Start += RelativeMonth(Start, yyRelMonth);
933
934 if (yyHaveDay && !yyHaveDate) {
935 tod = RelativeDate(Start, yyDayOrdinal, yyDayNumber);
936 Start += tod;
937 }
938
939 /* Have to do *something* with a legitimate -1 so it's distinguishable
940 * from the error return value. (Alternately could set errno on error.) */
941 return Start == -1 ? 0 : Start;
942}
943
944
945#if defined(TEST)
946
947/* ARGSUSED */
948main(ac, av)
949 int ac;
950 char *av[];
951{
952 char buff[128];
953 time_t d;
954
955 (void)printf("Enter date, or blank line to exit.\n\t> ");
956 (void)fflush(stdout);
957 while (gets(buff) && buff[0]) {
958 d = get_date(buff, (struct timeb *)NULL);
959 if (d == -1)
960 (void)printf("Bad format - couldn't convert.\n");
961 else
962 (void)printf("%s", ctime(&d));
963 (void)printf("\t> ");
964 (void)fflush(stdout);
965 }
966 exit(0);
967 /* NOTREACHED */
968}
969#endif /* defined(TEST) */