4 * Contains yacc grammer for parsing date and time strings..
5 *---------------------------------------------------------------------------
6 * Copyright 1992 Karl Lehenbauer and Mark Diekhans.
8 * Permission to use, copy, modify, and distribute this software and its
9 * documentation for any purpose and without fee is hereby granted, provided
10 * that the above copyright notice appear in all copies. Karl Lehenbauer and
11 * Mark Diekhans make no representations about the suitability of this
12 * software for any purpose. It is provided "as is" without express or
14 *---------------------------------------------------------------------------
15 * This code is a slightly modified version of getdate.y by:
16 * Steven M. Bellovin (unc!smb)
17 * Dept. of Computer Science
18 * University of North Carolina at Chapel Hill
19 * getdate.y 2.13 9/16/86
20 *-----------------------------------------------------------------------------
21 * $Id: tclXgetdate.y,v 2.0 1992/10/16 04:51:34 markd Rel $
22 *-----------------------------------------------------------------------------
25 %token ID MONTH DAY MERIDIAN NUMBER UNIT MUNIT SUNIT ZONE DAYZONE AGO
29 #include <sys/types.h>
37 #define daysec (24L*60L*60L)
39 static int timeflag, zoneflag, dateflag, dayflag, relflag;
40 static time_t relsec, relmonth;
41 static int hh, mm, ss, merid, dayLight;
42 static int dayord, dayreq;
43 static int month, day, year;
47 static time_t timeconv(int hh, int mm, int ss, int mer);
48 static time_t daylcorr(time_t future, time_t now);
49 static lookup(char *id);
51 static time_t timeconv();
52 static time_t daylcorr();
63 void yyerror(const char *);
83 {if (timeflag && dateflag && !relflag) year = $1;
84 else {timeflag++;hh = $1/100;mm = $1%100;ss = 0;merid = 24;}};
86 tspec: NUMBER MERIDIAN
87 {hh = $1; mm = 0; ss = 0; merid = $2;}
89 {hh = $1; mm = $3; merid = 24;}
90 | NUMBER ':' NUMBER MERIDIAN
91 {hh = $1; mm = $3; merid = $4;}
92 | NUMBER ':' NUMBER NUMBER
93 {hh = $1; mm = $3; merid = 24;
94 dayLight = STANDARD; ourzone = -($4%100 + 60*$4/100);}
95 | NUMBER ':' NUMBER ':' NUMBER
96 {hh = $1; mm = $3; ss = $5; merid = 24;}
97 | NUMBER ':' NUMBER ':' NUMBER MERIDIAN
98 {hh = $1; mm = $3; ss = $5; merid = $6;}
99 | NUMBER ':' NUMBER ':' NUMBER NUMBER
100 {hh = $1; mm = $3; ss = $5; merid = 24;
101 dayLight = STANDARD; ourzone = -($6%100 + 60*$6/100);};
104 {ourzone = $1; dayLight = STANDARD;}
106 {ourzone = $1; dayLight = DAYLIGHT;};
109 {dayord = 1; dayreq = $1;}
111 {dayord = 1; dayreq = $1;}
113 {dayord = $1; dayreq = $2;};
115 dtspec: NUMBER '/' NUMBER
116 {month = $1; day = $3;}
117 | NUMBER '/' NUMBER '/' NUMBER
118 {month = $1; day = $3; year = $5;}
120 {month = $1; day = $2;}
121 | MONTH NUMBER ',' NUMBER
122 {month = $1; day = $2; year = $4;}
124 {month = $2; day = $1;}
125 | NUMBER MONTH NUMBER
126 {month = $2; day = $1; year = $3;};
130 {relsec += 60L * $1 * $2;}
132 {relmonth += $1 * $2;}
136 {relsec += 60L * $1;}
142 {relsec = -relsec; relmonth = -relmonth;};
145 static int mdays[12] =
146 {31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
149 extern struct tm *localtime();
152 time_t dateconv(mm, dd, yy, h, m, s, mer, zone, dayflag)
153 int mm, dd, yy, h, m, s, mer, zone, dayflag;
159 if (yy < 0) yy = -yy;
160 if (yy < 100) yy += 1900;
161 mdays[1] = 28 + (yy%4 == 0 && (yy%100 != 0 || yy%400 == 0));
162 if (yy < epoch || yy > 1999 || mm < 1 || mm > 12 ||
163 dd < 1 || dd > mdays[--mm]) return (-1);
165 for (i=0; i<mm; i++) jdate += mdays[i];
166 for (i = epoch; i < yy; i++) jdate += 365 + (i%4 == 0);
169 if ((tod = timeconv(h, m, s, mer)) < 0) return (-1);
171 if (dayflag==DAYLIGHT || (dayflag==MAYBE&&localtime(&jdate)->tm_isdst))
177 time_t dayconv(ord, day, now) int ord, day; time_t now;
179 register struct tm *loctime;
184 loctime = localtime(&tod);
185 tod += daysec * ((day - loctime->tm_wday + 7) % 7);
186 tod += 7*daysec*(ord<=0?ord:ord-1);
187 return daylcorr(tod, now);
191 time_t timeconv(hh, mm, ss, mer) register int hh, mm, ss, mer;
193 if (mm < 0 || mm > 59 || ss < 0 || ss > 59) return (-1);
195 case AM: if (hh < 1 || hh > 12) return(-1);
196 return (60L * ((hh%12)*60L + mm)+ss);
197 case PM: if (hh < 1 || hh > 12) return(-1);
198 return (60L * ((hh%12 +12)*60L + mm)+ss);
199 case 24: if (hh < 0 || hh > 23) return (-1);
200 return (60L * (hh*60L + mm)+ss);
201 default: return (-1);
206 time_t monthadd(sdate, relmonth) time_t sdate, relmonth;
213 if (relmonth == 0) return 0;
214 ltime = localtime(&sdate);
215 mm = 12*ltime->tm_year + ltime->tm_mon + relmonth;
218 return daylcorr(dateconv(mm, ltime->tm_mday, yy, ltime->tm_hour,
219 ltime->tm_min, ltime->tm_sec, 24, ourzone, MAYBE), sdate);
223 time_t daylcorr(future, now) time_t future, now;
227 nowdayl = (localtime(&now)->tm_hour+1) % 24;
228 fdayl = (localtime(&future)->tm_hour+1) % 24;
229 return (future-now) + 60L*60L*(nowdayl-fdayl);
239 //#define YYSTYPE extern int
250 while (isspace(*lptr)) lptr++;
252 if (isdigit(c = *lptr) || c == '-' || c == '+') {
253 if (c== '-' || c == '+') {
254 if (c=='-') sign = -1;
256 if (!isdigit(*++lptr)) {
257 /* yylval = sign; return (NUMBER); */
258 return yylex(); /* skip the '-' sign */
262 while (isdigit(c = *lptr++)) yylval = 10*yylval + c - '0';
267 } else if (isalpha(c)) {
269 while (isalpha(c = *lptr++) || c=='.')
270 if (p < &idbuf[sizeof(idbuf)-1])
274 return (lookup(idbuf));
281 if (c == '\0') return(c);
282 else if (c == '(') pcnt++;
283 else if (c == ')') pcnt--;
287 else return (*lptr++);
298 struct table mdtab[] = {
299 {"January", MONTH, 1},
300 {"February", MONTH, 2},
306 {"August", MONTH, 8},
307 {"September", MONTH, 9},
309 {"October", MONTH, 10},
310 {"November", MONTH, 11},
311 {"December", MONTH, 12},
317 {"Wednesday", DAY, 3},
319 {"Thursday", DAY, 4},
323 {"Saturday", DAY, 6},
329 struct table mztab[] = {
330 {"a.m.", MERIDIAN, AM},
331 {"am", MERIDIAN, AM},
332 {"p.m.", MERIDIAN, PM},
333 {"pm", MERIDIAN, PM},
334 {"nst", ZONE, 3 HRS + HALFHR}, /* Newfoundland */
335 {"n.s.t.", ZONE, 3 HRS + HALFHR},
336 {"ast", ZONE, 4 HRS}, /* Atlantic */
337 {"a.s.t.", ZONE, 4 HRS},
338 {"adt", DAYZONE, 4 HRS},
339 {"a.d.t.", DAYZONE, 4 HRS},
340 {"est", ZONE, 5 HRS}, /* Eastern */
341 {"e.s.t.", ZONE, 5 HRS},
342 {"edt", DAYZONE, 5 HRS},
343 {"e.d.t.", DAYZONE, 5 HRS},
344 {"cst", ZONE, 6 HRS}, /* Central */
345 {"c.s.t.", ZONE, 6 HRS},
346 {"cdt", DAYZONE, 6 HRS},
347 {"c.d.t.", DAYZONE, 6 HRS},
348 {"mst", ZONE, 7 HRS}, /* Mountain */
349 {"m.s.t.", ZONE, 7 HRS},
350 {"mdt", DAYZONE, 7 HRS},
351 {"m.d.t.", DAYZONE, 7 HRS},
352 {"pst", ZONE, 8 HRS}, /* Pacific */
353 {"p.s.t.", ZONE, 8 HRS},
354 {"pdt", DAYZONE, 8 HRS},
355 {"p.d.t.", DAYZONE, 8 HRS},
356 {"yst", ZONE, 9 HRS}, /* Yukon */
357 {"y.s.t.", ZONE, 9 HRS},
358 {"ydt", DAYZONE, 9 HRS},
359 {"y.d.t.", DAYZONE, 9 HRS},
360 {"hst", ZONE, 10 HRS}, /* Hawaii */
361 {"h.s.t.", ZONE, 10 HRS},
362 {"hdt", DAYZONE, 10 HRS},
363 {"h.d.t.", DAYZONE, 10 HRS},
365 {"gmt", ZONE, 0 HRS},
366 {"g.m.t.", ZONE, 0 HRS},
367 {"bst", DAYZONE, 0 HRS}, /* British Summer Time */
368 {"b.s.t.", DAYZONE, 0 HRS},
369 {"eet", ZONE, 0 HRS}, /* European Eastern Time */
370 {"e.e.t.", ZONE, 0 HRS},
371 {"eest", DAYZONE, 0 HRS}, /* European Eastern Summer Time */
372 {"e.e.s.t.", DAYZONE, 0 HRS},
373 {"met", ZONE, -1 HRS}, /* Middle European Time */
374 {"m.e.t.", ZONE, -1 HRS},
375 {"mest", DAYZONE, -1 HRS}, /* Middle European Summer Time */
376 {"m.e.s.t.", DAYZONE, -1 HRS},
377 {"wet", ZONE, -2 HRS }, /* Western European Time */
378 {"w.e.t.", ZONE, -2 HRS },
379 {"west", DAYZONE, -2 HRS}, /* Western European Summer Time */
380 {"w.e.s.t.", DAYZONE, -2 HRS},
382 {"jst", ZONE, -9 HRS}, /* Japan Standard Time */
383 {"j.s.t.", ZONE, -9 HRS}, /* Japan Standard Time */
384 /* No daylight savings time */
386 {"aest", ZONE, -10 HRS}, /* Australian Eastern Time */
387 {"a.e.s.t.", ZONE, -10 HRS},
388 {"aesst", DAYZONE, -10 HRS}, /* Australian Eastern Summer Time */
389 {"a.e.s.s.t.", DAYZONE, -10 HRS},
390 {"acst", ZONE, -(9 HRS + HALFHR)}, /* Australian Central Time */
391 {"a.c.s.t.", ZONE, -(9 HRS + HALFHR)},
392 {"acsst", DAYZONE, -(9 HRS + HALFHR)}, /* Australian Central Summer */
393 {"a.c.s.s.t.", DAYZONE, -(9 HRS + HALFHR)},
394 {"awst", ZONE, -8 HRS}, /* Australian Western Time */
395 {"a.w.s.t.", ZONE, -8 HRS}, /* (no daylight time there, I'm told */
399 struct table unittb[] = {
402 {"fortnight", UNIT, 14*24*60},
403 {"week", UNIT, 7*24*60},
404 {"day", UNIT, 1*24*60},
408 {"second", SUNIT, 1},
413 struct table othertb[] = {
414 {"tomorrow", UNIT, 1*24*60},
415 {"yesterday", UNIT, -1*24*60},
418 {"last", NUMBER, -1},
421 {"first", NUMBER, 1},
422 /* {"second", NUMBER, 2}, */
423 {"third", NUMBER, 3},
424 {"fourth", NUMBER, 4},
425 {"fifth", NUMBER, 5},
426 {"sixth", NUMBER, 6},
427 {"seventh", NUMBER, 7},
428 {"eigth", NUMBER, 8},
429 {"ninth", NUMBER, 9},
430 {"tenth", NUMBER, 10},
431 {"eleventh", NUMBER, 11},
432 {"twelfth", NUMBER, 12},
437 struct table milzone[] = {
459 {"w", ZONE, -10 HRS},
460 {"x", ZONE, -11 HRS},
461 {"y", ZONE, -12 HRS},
468 #define gotit (yylval=i->value, i->type)
469 #define getid for(j=idvar, k=id; *j++ = *k++; )
472 register char *j, *k;
473 register struct table *i;
477 if (strlen(idvar) == 3) abbrev = 1;
478 else if (strlen(idvar) == 4 && idvar[3] == '.') {
484 if (islower(*idvar)) *idvar = toupper(*idvar);
486 for (i = mdtab; i->name; i++) {
488 for (j = i->name; *j++ == *k++;) {
489 if (abbrev && j==i->name+3) return gotit;
490 if (j[-1] == 0) return gotit;
495 for (i = mztab; i->name; i++)
496 if (strcmp(i->name, idvar) == 0) return gotit;
498 for (j = idvar; *j; j++)
499 if (isupper(*j)) *j = tolower(*j);
500 for (i=mztab; i->name; i++)
501 if (strcmp(i->name, idvar) == 0) return gotit;
504 for (i=unittb; i->name; i++)
505 if (strcmp(i->name, idvar) == 0) return gotit;
507 if (idvar[strlen(idvar)-1] == 's')
508 idvar[strlen(idvar)-1] = '\0';
509 for (i=unittb; i->name; i++)
510 if (strcmp(i->name, idvar) == 0) return gotit;
513 for (i = othertb; i->name; i++)
514 if (strcmp(i->name, idvar) == 0) return gotit;
517 if (strlen(idvar) == 1 && isalpha(*idvar)) {
518 if (isupper(*idvar)) *idvar = tolower(*idvar);
519 for (i = milzone; i->name; i++)
520 if (strcmp(i->name, idvar) == 0) return gotit;
527 Tcl_GetDate (p, now, zone)
532 #define mcheck(f) if (f>1) err++
541 lt = localtime(&now);
543 month = lt->tm_mon+1;
545 relsec = 0; relmonth = 0;
546 timeflag=zoneflag=dateflag=dayflag=relflag=0;
552 if (err = yyparse()) return (-1);
559 if (err) return (-1);
560 if (dateflag || timeflag || dayflag) {
561 sdate = dateconv(month,day,year,hh,mm,ss,merid,ourzone,
563 if (sdate < 0) return -1;
568 sdate -= (lt->tm_sec + lt->tm_min*60 +
569 lt->tm_hour*(60L*60L));
573 sdate += monthadd(sdate, relmonth);
575 if (dayflag && !dateflag) {
576 tod = dayconv(dayord, dayreq, sdate);
584 * Error message are not used, so discard with dummy function.