2 * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
4 * Openvision retains the copyright to derivative works of
5 * this source code. Do *NOT* create a derivative of this
6 * source code before consulting with your legal department.
7 * Do *NOT* integrate *ANY* of this source code into another
8 * product before consulting with your legal department.
10 * For further information, read the top-level Openvision
11 * copyright which is contained in the top-level MIT Kerberos
14 * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
21 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
22 * Use is subject to license terms.
25 #pragma ident "%Z%%M% %I% %E% SMI"
28 ** Originally written by Steven M. Bellovin <smb@research.att.com> while
29 ** at the University of North Carolina at Chapel Hill. Later tweaked by
30 ** a couple of people on Usenet. Completely overhauled by Rich $alz
31 ** <rsalz@bbn.com> and Jim Berets <jberets@bbn.com> in August, 1990;
32 ** send any email to Rich.
34 ** This grammar has nine shift/reduce conflicts.
36 ** This code is in the public domain and has no copyright.
38 /* SUPPRESS 287 on yaccpar_sccsid *//* Unusd static variable */
39 /* SUPPRESS 288 on yyerrlab *//* Label unused */
42 #if defined (emacs) || defined (CONFIG_BROKETS)
50 /* Since the code of getdate.y is not included in the Emacs executable
51 itself, there is no need to #define static in this file. Even if
52 the code were included in the Emacs executable, it probably
53 wouldn't do any harm to #undef it here; this will only cause
54 problems if we try to write to a static variable, which I don't
55 think this code needs to do. */
60 /* The following block of alloca-related preprocessor directives is here
61 solely to allow compilation by non GNU-C compilers of the C parser
62 produced from this file by old versions of bison. Newer versions of
63 bison include a block similar to this one in bison.simple. */
67 #define alloca __builtin_alloca
72 #ifdef _AIX /* for Bison */
83 #if defined(HAVE_STDLIB_H)
87 /* The code at the top of get_date which figures out the offset of the
88 current time zone checks various CPP symbols to see if special
89 tricks are need, but defaults to using the gettimeofday system call.
90 Include <sys/time.h> if that will be used. */
99 #include <sys/types.h>
101 #ifdef TIME_WITH_SYS_TIME
102 #include <sys/time.h>
105 #ifdef HAVE_SYS_TIME_H
106 #include <sys/time.h>
113 #undef timezone /* needed for sgi */
117 ** We use the obsolete `struct my_timeb' as part of our interface!
118 ** Since the system doesn't have it, we define it here;
119 ** our callers must do likewise.
122 time_t time
; /* Seconds since the epoch */
123 unsigned short millitm
; /* Field not used */
124 short timezone
; /* Minutes west of GMT */
125 short dstflag
; /* Field not used */
127 #endif /* defined(vms) */
129 #if defined (STDC_HEADERS) || defined (USG)
133 /* Some old versions of bison generate parsers that use bcopy.
134 That loses on systems that don't provide the function, so we have
135 to redefine it here. */
137 #define bcopy(from, to, len) memcpy ((to), (from), (len))
141 * The following is a hack so that it is easy to internationalize
142 * statically declared strings. We define a wrapper function here that
143 * will be a replacement for gettext. We the make gettext a macro that
144 * just returns its argument, which now can be used with statically defined
145 * strings. The conquence of this is that GETTEXT must be used to translate
146 * a string at runtime and gettext must be used around string literals so
147 * that xgettext command can extract them to a portable object database file.
149 * Thus to translate a string literal that is an argument to a function foo
150 * the following will have to be performed:
152 * foo(GETTEXT(gettext("This is a test")));
154 * The inner gettext call is for xgettext command to extract the string.
155 * The C preprossesor will reduce the above to:
157 * foo(GETTEXT(("This ia a test"));
163 GETTEXT
(const char *msgid
)
165 return
(gettext
(msgid
));
168 #define gettext(s) (s)
171 extern
struct tm
*gmtime
();
172 extern
struct tm
*localtime
();
174 #define yyparse getdate_yyparse
175 #define yylex getdate_yylex
176 #define yyerror getdate_yyerror
178 static int getdate_yylex
(void);
179 static int getdate_yyerror
(char *);
183 #define EPOCH_END 2099 /* Solaris 64 bit can support this at this point */
184 #define HOUR(x) ((time_t)(x) * 60)
185 #define SECSPERDAY (24L * 60L * 60L)
189 ** An entry in the lexical lookup table.
191 typedef
struct _TABLE
{
199 ** Daylight-savings mode: on, off, or not yet known.
201 typedef
enum _DSTMODE
{
202 DSTon
, DSToff
, DSTmaybe
206 ** Meridian: am, pm, or 24-hour style.
208 typedef
enum _MERIDIAN
{
214 ** Global variables. We could get rid of most of these by using a good
215 ** union as the yacc stack. (This routine was originally written before
216 ** yacc had the %union construct.) Maybe someday; right now we only use
217 ** the %union very rarely.
219 static char *yyInput
;
220 static DSTMODE yyDSTmode
;
221 static time_t yyDayOrdinal
;
222 static time_t yyDayNumber
;
223 static int yyHaveDate
;
224 static int yyHaveDay
;
225 static int yyHaveRel
;
226 static int yyHaveTime
;
227 static int yyHaveZone
;
228 static time_t yyTimezone
;
230 static time_t yyHour
;
231 static time_t yyMinutes
;
232 static time_t yyMonth
;
233 static time_t yySeconds
;
234 static time_t yyYear
;
235 static MERIDIAN yyMeridian
;
236 static time_t yyRelMonth
;
237 static time_t yyRelSeconds
;
243 enum _MERIDIAN Meridian
;
246 %token tAGO tDAY tDAYZONE tID tMERIDIAN tMINUTE_UNIT tMONTH tMONTH_UNIT
247 %token tSEC_UNIT tSNUMBER tUNUMBER tZONE tDST tNEVER
249 %type
<Number
> tDAY tDAYZONE tMINUTE_UNIT tMONTH tMONTH_UNIT
250 %type
<Number
> tSEC_UNIT tSNUMBER tUNUMBER tZONE
251 %type
<Meridian
> tMERIDIAN o_merid
261 yyHour
= yyMinutes
= yySeconds
= 0;
263 yyTimezone
= 0; /* gmt */
285 time
: tUNUMBER tMERIDIAN
{
291 | tUNUMBER
':' tUNUMBER o_merid
{
297 | tUNUMBER
':' tUNUMBER tSNUMBER
{
302 yyTimezone
= - ($4 %
100 + ($4 / 100) * 60);
304 | tUNUMBER
':' tUNUMBER
':' tUNUMBER o_merid
{
310 | tUNUMBER
':' tUNUMBER
':' tUNUMBER tSNUMBER
{
316 yyTimezone
= - ($6 %
100 + ($6 / 100) * 60);
349 date
: tUNUMBER
'/' tUNUMBER
{
353 | tUNUMBER
'/' tUNUMBER
'/' tUNUMBER
{
358 | tUNUMBER tSNUMBER tSNUMBER
{
359 /* ISO 8601 format. yyyy-mm-dd. */
364 | tUNUMBER tMONTH tSNUMBER
{
365 /* e.g. 17-JUN-1992. */
374 | tMONTH tUNUMBER
',' tUNUMBER
{
383 | tUNUMBER tMONTH tUNUMBER
{
391 yyRelSeconds
= -yyRelSeconds
;
392 yyRelMonth
= -yyRelMonth
;
397 relunit
: tUNUMBER tMINUTE_UNIT
{
398 yyRelSeconds
+= $1 * $2 * 60L;
400 | tSNUMBER tMINUTE_UNIT
{
401 yyRelSeconds
+= $1 * $2 * 60L;
404 yyRelSeconds
+= $1 * 60L;
406 | tSNUMBER tSEC_UNIT
{
409 | tUNUMBER tSEC_UNIT
{
415 | tSNUMBER tMONTH_UNIT
{
416 yyRelMonth
+= $1 * $2;
418 | tUNUMBER tMONTH_UNIT
{
419 yyRelMonth
+= $1 * $2;
426 o_merid
: /* NULL */ {
436 /* Month and day table. */
437 static TABLE
const MonthDayTable
[] = {
438 { gettext
("january"), tMONTH
, 1 },
439 { gettext
("february"), tMONTH
, 2 },
440 { gettext
("march"), tMONTH
, 3 },
441 { gettext
("april"), tMONTH
, 4 },
442 { gettext
("may"), tMONTH
, 5 },
443 { gettext
("june"), tMONTH
, 6 },
444 { gettext
("july"), tMONTH
, 7 },
445 { gettext
("august"), tMONTH
, 8 },
446 { gettext
("september"), tMONTH
, 9 },
447 { gettext
("sept"), tMONTH
, 9 },
448 { gettext
("october"), tMONTH
, 10 },
449 { gettext
("november"), tMONTH
, 11 },
450 { gettext
("december"), tMONTH
, 12 },
451 { gettext
("sunday"), tDAY
, 0 },
452 { gettext
("monday"), tDAY
, 1 },
453 { gettext
("tuesday"), tDAY
, 2 },
454 { gettext
("tues"), tDAY
, 2 },
455 { gettext
("wednesday"), tDAY
, 3 },
456 { gettext
("wednes"), tDAY
, 3 },
457 { gettext
("thursday"), tDAY
, 4 },
458 { gettext
("thur"), tDAY
, 4 },
459 { gettext
("thurs"), tDAY
, 4 },
460 { gettext
("friday"), tDAY
, 5 },
461 { gettext
("saturday"), tDAY
, 6 },
465 /* Time units table. */
466 static TABLE
const UnitsTable
[] = {
467 { gettext
("year"), tMONTH_UNIT
, 12 },
468 { gettext
("month"), tMONTH_UNIT
, 1 },
469 { gettext
("fortnight"), tMINUTE_UNIT
, 14 * 24 * 60 },
470 { gettext
("week"), tMINUTE_UNIT
, 7 * 24 * 60 },
471 { gettext
("day"), tMINUTE_UNIT
, 1 * 24 * 60 },
472 { gettext
("hour"), tMINUTE_UNIT
, 60 },
473 { gettext
("minute"), tMINUTE_UNIT
, 1 },
474 { gettext
("min"), tMINUTE_UNIT
, 1 },
475 { gettext
("second"), tSEC_UNIT
, 1 },
476 { gettext
("sec"), tSEC_UNIT
, 1 },
480 /* Assorted relative-time words. */
481 static TABLE
const OtherTable
[] = {
482 { gettext
("tomorrow"), tMINUTE_UNIT
, 1 * 24 * 60 },
483 { gettext
("yesterday"), tMINUTE_UNIT
, -1 * 24 * 60 },
484 { gettext
("today"), tMINUTE_UNIT
, 0 },
485 { gettext
("now"), tMINUTE_UNIT
, 0 },
486 { gettext
("last"), tUNUMBER
, -1 },
487 { gettext
("this"), tMINUTE_UNIT
, 0 },
488 { gettext
("next"), tUNUMBER
, 2 },
489 { gettext
("first"), tUNUMBER
, 1 },
490 /* { gettext("second"), tUNUMBER, 2 }, */
491 { gettext
("third"), tUNUMBER
, 3 },
492 { gettext
("fourth"), tUNUMBER
, 4 },
493 { gettext
("fifth"), tUNUMBER
, 5 },
494 { gettext
("sixth"), tUNUMBER
, 6 },
495 { gettext
("seventh"), tUNUMBER
, 7 },
496 { gettext
("eighth"), tUNUMBER
, 8 },
497 { gettext
("ninth"), tUNUMBER
, 9 },
498 { gettext
("tenth"), tUNUMBER
, 10 },
499 { gettext
("eleventh"), tUNUMBER
, 11 },
500 { gettext
("twelfth"), tUNUMBER
, 12 },
501 { gettext
("ago"), tAGO
, 1 },
502 { gettext
("never"), tNEVER
, 0 },
506 /* The timezone table. */
507 /* Some of these are commented out because a time_t can't store a float. */
508 static TABLE
const TimezoneTable
[] = {
509 { gettext
("gmt"), tZONE
, HOUR
( 0) }, /* Greenwich Mean */
510 { gettext
("ut"), tZONE
, HOUR
( 0) }, /* Universal (Coordinated) */
511 { gettext
("utc"), tZONE
, HOUR
( 0) },
512 { gettext
("wet"), tZONE
, HOUR
( 0) }, /* Western European */
513 { gettext
("bst"), tDAYZONE
, HOUR
( 0) }, /* British Summer */
514 { gettext
("wat"), tZONE
, HOUR
( 1) }, /* West Africa */
515 { gettext
("at"), tZONE
, HOUR
( 2) }, /* Azores */
517 /* For completeness. BST is also British Summer, and GST is
518 * also Guam Standard. */
519 { gettext
("bst"), tZONE
, HOUR
( 3) }, /* Brazil Standard */
520 { gettext
("gst"), tZONE
, HOUR
( 3) }, /* Greenland Standard */
523 { gettext
("nft"), tZONE
, HOUR
(3.5) }, /* Newfoundland */
524 { gettext
("nst"), tZONE
, HOUR
(3.5) }, /* Newfoundland Standard */
525 { gettext
("ndt"), tDAYZONE
, HOUR
(3.5) }, /* Newfoundland Daylight */
527 { gettext
("ast"), tZONE
, HOUR
( 4) }, /* Atlantic Standard */
528 { gettext
("adt"), tDAYZONE
, HOUR
( 4) }, /* Atlantic Daylight */
529 { gettext
("est"), tZONE
, HOUR
( 5) }, /* Eastern Standard */
530 { gettext
("edt"), tDAYZONE
, HOUR
( 5) }, /* Eastern Daylight */
531 { gettext
("cst"), tZONE
, HOUR
( 6) }, /* Central Standard */
532 { gettext
("cdt"), tDAYZONE
, HOUR
( 6) }, /* Central Daylight */
533 { gettext
("mst"), tZONE
, HOUR
( 7) }, /* Mountain Standard */
534 { gettext
("mdt"), tDAYZONE
, HOUR
( 7) }, /* Mountain Daylight */
535 { gettext
("pst"), tZONE
, HOUR
( 8) }, /* Pacific Standard */
536 { gettext
("pdt"), tDAYZONE
, HOUR
( 8) }, /* Pacific Daylight */
537 { gettext
("yst"), tZONE
, HOUR
( 9) }, /* Yukon Standard */
538 { gettext
("ydt"), tDAYZONE
, HOUR
( 9) }, /* Yukon Daylight */
539 { gettext
("hst"), tZONE
, HOUR
(10) }, /* Hawaii Standard */
540 { gettext
("hdt"), tDAYZONE
, HOUR
(10) }, /* Hawaii Daylight */
541 { gettext
("cat"), tZONE
, HOUR
(10) }, /* Central Alaska */
542 { gettext
("ahst"), tZONE
, HOUR
(10) }, /* Alaska-Hawaii Standard */
543 { gettext
("nt"), tZONE
, HOUR
(11) }, /* Nome */
544 { gettext
("idlw"), tZONE
, HOUR
(12) }, /* International Date Line West */
545 { gettext
("cet"), tZONE
, -HOUR
(1) }, /* Central European */
546 { gettext
("met"), tZONE
, -HOUR
(1) }, /* Middle European */
547 { gettext
("mewt"), tZONE
, -HOUR
(1) }, /* Middle European Winter */
548 { gettext
("mest"), tDAYZONE
, -HOUR
(1) }, /* Middle European Summer */
549 { gettext
("swt"), tZONE
, -HOUR
(1) }, /* Swedish Winter */
550 { gettext
("sst"), tDAYZONE
, -HOUR
(1) }, /* Swedish Summer */
551 { gettext
("fwt"), tZONE
, -HOUR
(1) }, /* French Winter */
552 { gettext
("fst"), tDAYZONE
, -HOUR
(1) }, /* French Summer */
553 { gettext
("eet"), tZONE
, -HOUR
(2) }, /* Eastern Europe, USSR Zone 1 */
554 { gettext
("bt"), tZONE
, -HOUR
(3) }, /* Baghdad, USSR Zone 2 */
556 { gettext
("it"), tZONE
, -HOUR
(3.5) },/* Iran */
558 { gettext
("zp4"), tZONE
, -HOUR
(4) }, /* USSR Zone 3 */
559 { gettext
("zp5"), tZONE
, -HOUR
(5) }, /* USSR Zone 4 */
561 { gettext
("ist"), tZONE
, -HOUR
(5.5) },/* Indian Standard */
563 { gettext
("zp6"), tZONE
, -HOUR
(6) }, /* USSR Zone 5 */
565 /* For completeness. NST is also Newfoundland Stanard, and SST is
566 * also Swedish Summer. */
567 { gettext
("nst"), tZONE
, -HOUR
(6.5) },/* North Sumatra */
568 { gettext
("sst"), tZONE
, -HOUR
(7) }, /* South Sumatra, USSR Zone 6 */
570 { gettext
("wast"), tZONE
, -HOUR
(7) }, /* West Australian Standard */
571 { gettext
("wadt"), tDAYZONE
, -HOUR
(7) }, /* West Australian Daylight */
573 { gettext
("jt"), tZONE
, -HOUR
(7.5) },/* Java (3pm in Cronusland!) */
575 { gettext
("cct"), tZONE
, -HOUR
(8) }, /* China Coast, USSR Zone 7 */
576 { gettext
("jst"), tZONE
, -HOUR
(9) }, /* Japan Standard, USSR Zone 8 */
577 { gettext
("kst"), tZONE
, -HOUR
(9) }, /* Korean Standard */
579 { gettext
("cast"), tZONE
, -HOUR
(9.5) },/* Central Australian Standard */
580 { gettext
("cadt"), tDAYZONE
, -HOUR
(9.5) },/* Central Australian Daylight */
582 { gettext
("east"), tZONE
, -HOUR
(10) }, /* Eastern Australian Standard */
583 { gettext
("eadt"), tDAYZONE
, -HOUR
(10) }, /* Eastern Australian Daylight */
584 { gettext
("gst"), tZONE
, -HOUR
(10) }, /* Guam Standard, USSR Zone 9 */
585 { gettext
("kdt"), tZONE
, -HOUR
(10) }, /* Korean Daylight */
586 { gettext
("nzt"), tZONE
, -HOUR
(12) }, /* New Zealand */
587 { gettext
("nzst"), tZONE
, -HOUR
(12) }, /* New Zealand Standard */
588 { gettext
("nzdt"), tDAYZONE
, -HOUR
(12) }, /* New Zealand Daylight */
589 { gettext
("idle"), tZONE
, -HOUR
(12) }, /* International Date Line East */
603 ToSeconds
(Hours
, Minutes
, Seconds
, Meridian
)
609 if
(Minutes
< 0 || Minutes
> 59 || Seconds
< 0 || Seconds
> 59)
613 if
(Hours
< 0 || Hours
> 23)
615 return
(Hours
* 60L + Minutes
) * 60L + Seconds
;
617 if
(Hours
< 1 || Hours
> 12)
619 return
(Hours
* 60L + Minutes
) * 60L + Seconds
;
621 if
(Hours
< 1 || Hours
> 12)
623 return
((Hours
+ 12) * 60L + Minutes
) * 60L + Seconds
;
631 * From hh:mm:ss [am|pm] mm/dd/yy [tz], compute and return the number
632 * of seconds since 00:00:00 1/1/70 GMT.
635 Convert
(Month
, Day
, Year
, Hours
, Minutes
, Seconds
, Meridian
, DSTmode
)
645 static int DaysInMonth
[12] = {
646 31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
656 DaysInMonth
[1] = Year %
4 == 0 && (Year %
100 != 0 || Year %
400 == 0)
660 || Month
< 1 || Month
> 12
661 /* Lint fluff: "conversion from long may lose accuracy" */
662 || Day
< 1 || Day
> DaysInMonth
[(int)--Month
])
665 for
(Julian
= Day
- 1, i
= 0; i
< Month
; i
++)
666 Julian
+= DaysInMonth
[i
];
667 for
(i
= EPOCH
; i
< Year
; i
++)
668 Julian
+= 365 + ((i %
4 == 0) && ((Year %
100 != 0) ||
670 Julian
*= SECSPERDAY
;
671 Julian
+= yyTimezone
* 60L;
672 if
((tod
= ToSeconds
(Hours
, Minutes
, Seconds
, Meridian
)) < 0)
676 ||
(DSTmode
== DSTmaybe
&& localtime
(&Julian
)->tm_isdst
))
683 DSTcorrect
(Start
, Future
)
690 StartDay
= (localtime
(&Start
)->tm_hour
+ 1) %
24;
691 FutureDay
= (localtime
(&Future
)->tm_hour
+ 1) %
24;
692 return
(Future
- Start
) + (StartDay
- FutureDay
) * 60L * 60L;
697 RelativeDate
(Start
, DayOrdinal
, DayNumber
)
706 tm
= localtime
(&now
);
707 now
+= SECSPERDAY
* ((DayNumber
- tm
->tm_wday
+ 7) %
7);
708 now
+= 7 * SECSPERDAY
* (DayOrdinal
<= 0 ? DayOrdinal
: DayOrdinal
- 1);
709 return DSTcorrect
(Start
, now
);
714 RelativeMonth
(Start
, RelMonth
)
725 tm
= localtime
(&Start
);
726 Month
= 12 * tm
->tm_year
+ tm
->tm_mon
+ RelMonth
;
728 Month
= Month %
12 + 1;
729 ret
= Convert
(Month
, (time_t)tm
->tm_mday
, Year
,
730 (time_t)tm
->tm_hour
, (time_t)tm
->tm_min
, (time_t)tm
->tm_sec
,
734 return DSTcorrect
(Start
, ret
);
744 register
const TABLE
*tp
;
748 /* Make it lowercase. */
749 for
(p
= buff
; *p
; p
++)
750 if
(isupper
((int) *p
))
751 *p
= tolower
((int) *p
);
753 if
(strcmp
(buff
, gettext
("am")) == 0 || strcmp
(buff
, gettext
("a.m.")) == 0) {
754 yylval.Meridian
= MERam
;
757 if
(strcmp
(buff
, gettext
("pm")) == 0 ||
758 strcmp
(buff
, gettext
("p.m.")) == 0) {
759 yylval.Meridian
= MERpm
;
763 /* See if we have an abbreviation for a month. */
764 if
(strlen
(buff
) == 3)
766 else if
(strlen
(buff
) == 4 && buff
[3] == '.') {
773 for
(tp
= MonthDayTable
; tp
->name
; tp
++) {
775 if
(strncmp
(buff
, GETTEXT
(tp
->name
), 3) == 0) {
776 yylval.Number
= tp
->value
;
780 else if
(strcmp
(buff
, GETTEXT
(tp
->name
)) == 0) {
781 yylval.Number
= tp
->value
;
786 for
(tp
= TimezoneTable
; tp
->name
; tp
++)
787 if
(strcmp
(buff
, GETTEXT
(tp
->name
)) == 0) {
788 yylval.Number
= tp
->value
;
792 if
(strcmp
(buff
, gettext
("dst")) == 0)
795 for
(tp
= UnitsTable
; tp
->name
; tp
++)
796 if
(strcmp
(buff
, GETTEXT
(tp
->name
)) == 0) {
797 yylval.Number
= tp
->value
;
801 /* Strip off any plural and try the units table again. */
802 i
= strlen
(buff
) - 1;
803 if
(buff
[i
] == 's') {
805 for
(tp
= UnitsTable
; tp
->name
; tp
++)
806 if
(strcmp
(buff
, GETTEXT
(tp
->name
)) == 0) {
807 yylval.Number
= tp
->value
;
810 buff
[i
] = 's'; /* Put back for "this" in OtherTable. */
813 for
(tp
= OtherTable
; tp
->name
; tp
++)
814 if
(strcmp
(buff
, GETTEXT
(tp
->name
)) == 0) {
815 yylval.Number
= tp
->value
;
819 /* Drop out any periods and try the timezone table again. */
820 for
(i
= 0, p
= q
= buff
; *q
; q
++)
827 for
(tp
= TimezoneTable
; tp
->name
; tp
++)
828 if
(strcmp
(buff
, GETTEXT
(tp
->name
)) == 0) {
829 yylval.Number
= tp
->value
;
847 while
(isspace
((int) *yyInput
))
851 if
(isdigit
((int) c
) || c
== '-' || c
== '+') {
852 if
(c
== '-' || c
== '+') {
853 sign
= c
== '-' ?
-1 : 1;
854 if
(!isdigit
((int) (*++yyInput
)))
855 /* skip the '-' sign */
860 for
(yylval.Number
= 0; isdigit
((int) (c
= *yyInput
++)); )
861 yylval.Number
= 10 * yylval.Number
+ c
- '0';
864 yylval.Number
= -yylval.Number
;
865 return sign ? tSNUMBER
: tUNUMBER
;
867 if
(isalpha
((int) c
)) {
868 for
(p
= buff
; isalpha
((int) (c
= *yyInput
++)) || c
== '.'; )
869 if
(p
< &buff
[sizeof buff
- 1])
873 return LookupWord
(buff
);
891 #define TM_YEAR_ORIGIN 1900
893 /* Yield A - B, measured in seconds. */
898 int ay
= a
->tm_year
+ (TM_YEAR_ORIGIN
- 1);
899 int by
= b
->tm_year
+ (TM_YEAR_ORIGIN
- 1);
904 /* difference in day of year */
905 a
->tm_yday
- b
->tm_yday
906 /* + intervening leap days */
907 + ((ay
>> 2) - (by
>> 2))
909 + ((ay
/100 >> 2) - (by
/100 >> 2))
910 /* + difference in years * 365 */
911 + (time_t)(ay
-by
) * 365
912 )*24 + (a
->tm_hour
- b
->tm_hour
)
913 )*60 + (a
->tm_min
- b
->tm_min
)
914 )*60 + (a
->tm_sec
- b
->tm_sec
);
917 /* For get_date extern declaration compatibility check... yuck. */
925 struct my_timeb
*now
= NULL
;
936 ftz.time
= time
((time_t *) 0);
938 if
(! (tm
= gmtime
(&ftz.time
)))
940 gmt
= *tm
; /* Make a copy, in case localtime modifies *tm. */
941 ftz.timezone
= difftm
(&gmt
, localtime
(&ftz.time
)) / 60;
944 tm
= localtime
(&now
->time
);
945 yyYear
= tm
->tm_year
;
946 yyMonth
= tm
->tm_mon
+ 1;
948 yyTimezone
= now
->timezone
;
949 yyDSTmode
= DSTmaybe
;
963 * When yyparse returns, zero or more of yyHave{Time,Zone,Date,Day,Rel}
964 * will have been incremented. The value is number of items of
965 * that type that were found; for all but Rel, more than one is
968 * For each yyHave indicator, the following values are set:
971 * yyHour, yyMinutes, yySeconds: hh:mm:ss specified, initialized
973 * yyMeridian: MERam, MERpm, or MER24
974 * yyTimeZone: time zone specified in minutes
975 * yyDSTmode: DSToff if yyTimeZone is set, otherwise unchanged
976 * (initialized above to DSTmaybe)
979 * yyTimezone: as above
980 * yyDSTmode: DSToff if a non-DST zone is specified, otherwise DSTon
981 * XXX don't understand interaction with yyHaveTime zone info
984 * yyDayNumber: 0-6 for Sunday-Saturday
985 * yyDayOrdinal: val specified with day ("second monday",
986 * Ordinal=2), otherwise 1
989 * yyMonth, yyDay, yyYear: mm/dd/yy specified, initialized to
993 * yyRelSeconds: seconds specified with MINUTE_UNITs ("3 hours") or
994 * SEC_UNITs ("30 seconds")
995 * yyRelMonth: months specified with MONTH_UNITs ("3 months", "1
998 * The code following yyparse turns these values into a single
1002 || yyHaveTime
> 1 || yyHaveZone
> 1 || yyHaveDate
> 1 || yyHaveDay
> 1)
1006 * If an absolute time specified, set Start to the equivalent Unix
1007 * timestamp. Otherwise, set Start to now, and if we do not have
1008 * a relatime time (ie: only yyHaveZone), decrement Start to the
1009 * beginning of today.
1011 * By having yyHaveDay in the "absolute" list, "next Monday" means
1012 * midnight next Monday. Otherwise, "next Monday" would mean the
1013 * time right now, next Monday. It's not clear to me why the
1014 * current behavior is preferred.
1016 if
(yyHaveDate || yyHaveTime || yyHaveDay
) {
1017 Start
= Convert
(yyMonth
, yyDay
, yyYear
, yyHour
, yyMinutes
, yySeconds
,
1018 yyMeridian
, yyDSTmode
);
1025 Start
-= ((tm
->tm_hour
* 60L + tm
->tm_min
) * 60L) + tm
->tm_sec
;
1029 * Add in the relative time specified. RelativeMonth adds in the
1030 * months, accounting for the fact that the actual length of "3
1031 * months" depends on where you start counting.
1033 * XXX By having this separate from the previous block, we are
1034 * allowing dates like "10:00am 3 months", which means 3 months
1035 * from 10:00am today, or even "1/1/99 two days" which means two
1036 * days after 1/1/99.
1038 * XXX Shouldn't this only be done if yyHaveRel, just for
1041 Start
+= yyRelSeconds
;
1042 delta
= RelativeMonth
(Start
, yyRelMonth
);
1043 if
(delta
== (time_t) -1)
1048 * Now, if you specified a day of week and counter, add it in. By
1049 * disallowing Date but allowing Time, you can say "5pm next
1052 * XXX The yyHaveDay && !yyHaveDate restriction should be enforced
1053 * above and be able to cause failure.
1055 if
(yyHaveDay
&& !yyHaveDate
) {
1056 tod
= RelativeDate
(Start
, yyDayOrdinal
, yyDayNumber
);
1060 /* Have to do *something* with a legitimate -1 so it's distinguishable
1061 * from the error return value. (Alternately could set errno on error.) */
1062 return Start
== -1 ?
0 : Start
;
1076 (void)printf
(gettext
("Enter date, or blank line to exit.\n\t> "));
1077 (void)fflush
(stdout
);
1078 while
(gets
(buff
) && buff
[0]) {
1079 d
= get_date
(buff
, NULL
);
1082 gettext
("Bad format - couldn't convert.\n"));
1084 (void)printf
("%s", ctime
(&d
));
1085 (void)printf
("\t> ");
1086 (void)fflush
(stdout
);
1091 #endif /* defined(TEST) */