3 ** Originally written by Steven M. Bellovin <smb@research.att.com> while
4 ** at the University of North Carolina at Chapel Hill. Later tweaked by
5 ** a couple of people on Usenet. Completely overhauled by Rich $alz
6 ** <rsalz@bbn.com> and Jim Berets <jberets@bbn.com> in August, 1990;
7 ** send any email to Rich.
9 ** This grammar has 10 shift/reduce conflicts.
11 ** This code is in the public domain and has no copyright.
13 /* SUPPRESS 287 on yaccpar_sccsid *//* Unused static variable */
14 /* SUPPRESS 288 on yyerrlab *//* Label unused */
24 /* Since the code of getdate.y is not included in the Emacs executable
25 itself, there is no need to #define static in this file. Even if
26 the code were included in the Emacs executable, it probably
27 wouldn't do any harm to #undef it here; this will only cause
28 problems if we try to write to a static variable, which I don't
29 think this code needs to do. */
37 #if defined (STDC_HEADERS) || !defined (isascii)
40 # define ISASCII(c) isascii(c)
43 #define ISSPACE(c) (ISASCII (c) && isspace (c))
44 #define ISALPHA(c) (ISASCII (c) && isalpha (c))
45 #define ISUPPER(c) (ISASCII (c) && isupper (c))
46 #define ISDIGIT(c) (ISASCII (c) && isdigit (c))
52 #include <sys/types.h>
53 #ifdef TIME_WITH_SYS_TIME
57 #ifdef HAVE_SYS_TIME_H
65 #undef timezone /* needed for sgi */
68 #if defined (HAVE_SYS_TIMEB_H)
69 #include <sys/timeb.h>
72 /* get_date uses the obsolete `struct timeb' in its interface! FIXME.
73 Since some systems don't have it, we define it here;
74 callers must do likewise. */
77 time_t time; /* Seconds since the epoch */
78 unsigned short millitm; /* Field not used */
79 short timezone; /* Minutes west of GMT */
80 short dstflag; /* Field not used */
82 #endif /* defined (HAVE_SYS_TIMEB_H) */
84 #endif /* defined (vms) */
86 #if defined (STDC_HEADERS) || defined (USG)
90 /* Some old versions of bison generate parsers that use bcopy.
91 That loses on systems that don't provide the function, so we have
92 to redefine it here. */
93 #if !defined (HAVE_BCOPY) && defined (HAVE_MEMCPY) && !defined (bcopy)
94 #define bcopy(from, to, len) memcpy ((to), (from), (len))
97 extern struct tm *gmtime ();
98 extern struct tm *localtime ();
100 /* Remap normal yacc parser interface names (yyparse, yylex, yyerror, etc),
101 as well as gratuitiously global symbol names, so we can have multiple
102 yacc generated parsers in the same program. Note that these are only
103 the variables produced by yacc. If other parser generators (bison,
104 byacc, etc) produce additional global names that conflict at link time,
105 then those parser generators need to be fixed instead of adding those
106 names to this list. */
108 #define yymaxdepth gd_maxdepth
109 #define yyparse gd_parse
111 #define yyerror gd_error
112 #define yylval gd_lval
113 #define yychar gd_char
114 #define yydebug gd_debug
115 #define yypact gd_pact
122 #define yyexca gd_exca
123 #define yyerrflag gd_errflag
124 #define yynerrs gd_nerrs
128 #define yy_yys gd_yys
129 #define yystate gd_state
132 #define yy_yyv gd_yyv
134 #define yylloc gd_lloc
135 #define yyreds gd_reds /* With YYDEBUG defined */
136 #define yytoks gd_toks /* With YYDEBUG defined */
137 #define yylhs gd_yylhs
138 #define yylen gd_yylen
139 #define yydefred gd_yydefred
140 #define yydgoto gd_yydgoto
141 #define yysindex gd_yysindex
142 #define yyrindex gd_yyrindex
143 #define yygindex gd_yygindex
144 #define yytable gd_yytable
145 #define yycheck gd_yycheck
148 static int yyerror ();
151 #define DOOMSDAY 2038
152 #define HOUR(x) ((time_t)(x) * 60)
153 #define SECSPERDAY (24L * 60L * 60L)
155 #define MAX_BUFF_LEN 128 /* size of buffer to read the date into */
158 ** An entry in the lexical lookup table.
160 typedef struct _TABLE {
168 ** Daylight-savings mode: on, off, or not yet known.
170 typedef enum _DSTMODE {
171 DSTon, DSToff, DSTmaybe
175 ** Meridian: am, pm, or 24-hour style.
177 typedef enum _MERIDIAN {
183 ** Global variables. We could get rid of most of these by using a good
184 ** union as the yacc stack. (This routine was originally written before
185 ** yacc had the %union construct.) Maybe someday; right now we only use
186 ** the %union very rarely.
188 static char *yyInput;
189 static DSTMODE yyDSTmode;
190 static time_t yyDayOrdinal;
191 static time_t yyDayNumber;
192 static int yyHaveDate;
193 static int yyHaveDay;
194 static int yyHaveRel;
195 static int yyHaveTime;
196 static int yyHaveZone;
197 static time_t yyTimezone;
199 static time_t yyHour;
200 static time_t yyMinutes;
201 static time_t yyMonth;
202 static time_t yySeconds;
203 static time_t yyYear;
204 static MERIDIAN yyMeridian;
205 static time_t yyRelMonth;
206 static time_t yyRelSeconds;
212 enum _MERIDIAN Meridian;
215 %token tAGO tDAY tDAYZONE tID tMERIDIAN tMINUTE_UNIT tMONTH tMONTH_UNIT
216 %token tSEC_UNIT tSNUMBER tUNUMBER tZONE tDST
218 %type <Number> tDAY tDAYZONE tMINUTE_UNIT tMONTH tMONTH_UNIT
219 %type <Number> tSEC_UNIT tSNUMBER tUNUMBER tZONE
220 %type <Meridian> tMERIDIAN o_merid
246 time : tUNUMBER tMERIDIAN {
252 | tUNUMBER ':' tUNUMBER o_merid {
258 | tUNUMBER ':' tUNUMBER tSNUMBER {
263 yyTimezone = - ($4 % 100 + ($4 / 100) * 60);
265 | tUNUMBER ':' tUNUMBER ':' tUNUMBER o_merid {
271 | tUNUMBER ':' tUNUMBER ':' tUNUMBER tSNUMBER {
277 yyTimezone = - ($6 % 100 + ($6 / 100) * 60);
310 date : tUNUMBER '/' tUNUMBER {
314 | tUNUMBER '/' tUNUMBER '/' tUNUMBER {
315 /* Interpret as YYYY/MM/DD if $1 >= 1000, otherwise as MM/DD/YY.
316 The goal in recognizing YYYY/MM/DD is solely to support legacy
317 machine-generated dates like those in an RCS log listing. If
318 you want portability, use the ISO 8601 format. */
332 | tUNUMBER tSNUMBER tSNUMBER {
333 /* ISO 8601 format. yyyy-mm-dd. */
338 | tUNUMBER tMONTH tSNUMBER {
339 /* e.g. 17-JUN-1992. */
348 | tMONTH tUNUMBER ',' tUNUMBER {
357 | tUNUMBER tMONTH tUNUMBER {
365 yyRelSeconds = -yyRelSeconds;
366 yyRelMonth = -yyRelMonth;
371 relunit : tUNUMBER tMINUTE_UNIT {
372 yyRelSeconds += $1 * $2 * 60L;
374 | tSNUMBER tMINUTE_UNIT {
375 yyRelSeconds += $1 * $2 * 60L;
378 yyRelSeconds += $1 * 60L;
380 | tSNUMBER tSEC_UNIT {
383 | tUNUMBER tSEC_UNIT {
389 | tSNUMBER tMONTH_UNIT {
390 yyRelMonth += $1 * $2;
392 | tUNUMBER tMONTH_UNIT {
393 yyRelMonth += $1 * $2;
401 if (yyHaveTime && yyHaveDate && !yyHaveRel)
407 yyMonth= ($1/100)%100;
418 yyMinutes = $1 % 100;
427 o_merid : /* NULL */ {
437 /* Month and day table. */
438 static TABLE const MonthDayTable[] = {
439 { "january", tMONTH, 1 },
440 { "february", tMONTH, 2 },
441 { "march", tMONTH, 3 },
442 { "april", tMONTH, 4 },
443 { "may", tMONTH, 5 },
444 { "june", tMONTH, 6 },
445 { "july", tMONTH, 7 },
446 { "august", tMONTH, 8 },
447 { "september", tMONTH, 9 },
448 { "sept", tMONTH, 9 },
449 { "october", tMONTH, 10 },
450 { "november", tMONTH, 11 },
451 { "december", tMONTH, 12 },
452 { "sunday", tDAY, 0 },
453 { "monday", tDAY, 1 },
454 { "tuesday", tDAY, 2 },
456 { "wednesday", tDAY, 3 },
457 { "wednes", tDAY, 3 },
458 { "thursday", tDAY, 4 },
460 { "thurs", tDAY, 4 },
461 { "friday", tDAY, 5 },
462 { "saturday", tDAY, 6 },
466 /* Time units table. */
467 static TABLE const UnitsTable[] = {
468 { "year", tMONTH_UNIT, 12 },
469 { "month", tMONTH_UNIT, 1 },
470 { "fortnight", tMINUTE_UNIT, 14 * 24 * 60 },
471 { "week", tMINUTE_UNIT, 7 * 24 * 60 },
472 { "day", tMINUTE_UNIT, 1 * 24 * 60 },
473 { "hour", tMINUTE_UNIT, 60 },
474 { "minute", tMINUTE_UNIT, 1 },
475 { "min", tMINUTE_UNIT, 1 },
476 { "second", tSEC_UNIT, 1 },
477 { "sec", tSEC_UNIT, 1 },
481 /* Assorted relative-time words. */
482 static TABLE const OtherTable[] = {
483 { "tomorrow", tMINUTE_UNIT, 1 * 24 * 60 },
484 { "yesterday", tMINUTE_UNIT, -1 * 24 * 60 },
485 { "today", tMINUTE_UNIT, 0 },
486 { "now", tMINUTE_UNIT, 0 },
487 { "last", tUNUMBER, -1 },
488 { "this", tMINUTE_UNIT, 0 },
489 { "next", tUNUMBER, 2 },
490 { "first", tUNUMBER, 1 },
491 /* { "second", tUNUMBER, 2 }, */
492 { "third", tUNUMBER, 3 },
493 { "fourth", tUNUMBER, 4 },
494 { "fifth", tUNUMBER, 5 },
495 { "sixth", tUNUMBER, 6 },
496 { "seventh", tUNUMBER, 7 },
497 { "eighth", tUNUMBER, 8 },
498 { "ninth", tUNUMBER, 9 },
499 { "tenth", tUNUMBER, 10 },
500 { "eleventh", tUNUMBER, 11 },
501 { "twelfth", tUNUMBER, 12 },
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 { "gmt", tZONE, HOUR ( 0) }, /* Greenwich Mean */
510 { "ut", tZONE, HOUR ( 0) }, /* Universal (Coordinated) */
511 { "utc", tZONE, HOUR ( 0) },
512 { "wet", tZONE, HOUR ( 0) }, /* Western European */
513 { "bst", tDAYZONE, HOUR ( 0) }, /* British Summer */
514 { "wat", tZONE, HOUR ( 1) }, /* West Africa */
515 { "at", tZONE, HOUR ( 2) }, /* Azores */
517 /* For completeness. BST is also British Summer, and GST is
518 * also Guam Standard. */
519 { "bst", tZONE, HOUR ( 3) }, /* Brazil Standard */
520 { "gst", tZONE, HOUR ( 3) }, /* Greenland Standard */
523 { "nft", tZONE, HOUR (3.5) }, /* Newfoundland */
524 { "nst", tZONE, HOUR (3.5) }, /* Newfoundland Standard */
525 { "ndt", tDAYZONE, HOUR (3.5) }, /* Newfoundland Daylight */
527 { "ast", tZONE, HOUR ( 4) }, /* Atlantic Standard */
528 { "adt", tDAYZONE, HOUR ( 4) }, /* Atlantic Daylight */
529 { "est", tZONE, HOUR ( 5) }, /* Eastern Standard */
530 { "edt", tDAYZONE, HOUR ( 5) }, /* Eastern Daylight */
531 { "cst", tZONE, HOUR ( 6) }, /* Central Standard */
532 { "cdt", tDAYZONE, HOUR ( 6) }, /* Central Daylight */
533 { "mst", tZONE, HOUR ( 7) }, /* Mountain Standard */
534 { "mdt", tDAYZONE, HOUR ( 7) }, /* Mountain Daylight */
535 { "pst", tZONE, HOUR ( 8) }, /* Pacific Standard */
536 { "pdt", tDAYZONE, HOUR ( 8) }, /* Pacific Daylight */
537 { "yst", tZONE, HOUR ( 9) }, /* Yukon Standard */
538 { "ydt", tDAYZONE, HOUR ( 9) }, /* Yukon Daylight */
539 { "hst", tZONE, HOUR (10) }, /* Hawaii Standard */
540 { "hdt", tDAYZONE, HOUR (10) }, /* Hawaii Daylight */
541 { "cat", tZONE, HOUR (10) }, /* Central Alaska */
542 { "ahst", tZONE, HOUR (10) }, /* Alaska-Hawaii Standard */
543 { "nt", tZONE, HOUR (11) }, /* Nome */
544 { "idlw", tZONE, HOUR (12) }, /* International Date Line West */
545 { "cet", tZONE, -HOUR (1) }, /* Central European */
546 { "met", tZONE, -HOUR (1) }, /* Middle European */
547 { "mewt", tZONE, -HOUR (1) }, /* Middle European Winter */
548 { "mest", tDAYZONE, -HOUR (1) }, /* Middle European Summer */
549 { "mesz", tDAYZONE, -HOUR (1) }, /* Middle European Summer */
550 { "swt", tZONE, -HOUR (1) }, /* Swedish Winter */
551 { "sst", tDAYZONE, -HOUR (1) }, /* Swedish Summer */
552 { "fwt", tZONE, -HOUR (1) }, /* French Winter */
553 { "fst", tDAYZONE, -HOUR (1) }, /* French Summer */
554 { "eet", tZONE, -HOUR (2) }, /* Eastern Europe, USSR Zone 1 */
555 { "bt", tZONE, -HOUR (3) }, /* Baghdad, USSR Zone 2 */
557 { "it", tZONE, -HOUR (3.5) },/* Iran */
559 { "zp4", tZONE, -HOUR (4) }, /* USSR Zone 3 */
560 { "zp5", tZONE, -HOUR (5) }, /* USSR Zone 4 */
562 { "ist", tZONE, -HOUR (5.5) },/* Indian Standard */
564 { "zp6", tZONE, -HOUR (6) }, /* USSR Zone 5 */
566 /* For completeness. NST is also Newfoundland Standard, and SST is
567 * also Swedish Summer. */
568 { "nst", tZONE, -HOUR (6.5) },/* North Sumatra */
569 { "sst", tZONE, -HOUR (7) }, /* South Sumatra, USSR Zone 6 */
571 { "wast", tZONE, -HOUR (7) }, /* West Australian Standard */
572 { "wadt", tDAYZONE, -HOUR (7) }, /* West Australian Daylight */
574 { "jt", tZONE, -HOUR (7.5) },/* Java (3pm in Cronusland!) */
576 { "cct", tZONE, -HOUR (8) }, /* China Coast, USSR Zone 7 */
577 { "jst", tZONE, -HOUR (9) }, /* Japan Standard, USSR Zone 8 */
579 { "cast", tZONE, -HOUR (9.5) },/* Central Australian Standard */
580 { "cadt", tDAYZONE, -HOUR (9.5) },/* Central Australian Daylight */
582 { "east", tZONE, -HOUR (10) }, /* Eastern Australian Standard */
583 { "eadt", tDAYZONE, -HOUR (10) }, /* Eastern Australian Daylight */
584 { "gst", tZONE, -HOUR (10) }, /* Guam Standard, USSR Zone 9 */
585 { "nzt", tZONE, -HOUR (12) }, /* New Zealand */
586 { "nzst", tZONE, -HOUR (12) }, /* New Zealand Standard */
587 { "nzdt", tDAYZONE, -HOUR (12) }, /* New Zealand Daylight */
588 { "idle", tZONE, -HOUR (12) }, /* International Date Line East */
592 /* Military timezone table. */
593 static TABLE const MilitaryTable[] = {
594 { "a", tZONE, HOUR ( 1) },
595 { "b", tZONE, HOUR ( 2) },
596 { "c", tZONE, HOUR ( 3) },
597 { "d", tZONE, HOUR ( 4) },
598 { "e", tZONE, HOUR ( 5) },
599 { "f", tZONE, HOUR ( 6) },
600 { "g", tZONE, HOUR ( 7) },
601 { "h", tZONE, HOUR ( 8) },
602 { "i", tZONE, HOUR ( 9) },
603 { "k", tZONE, HOUR ( 10) },
604 { "l", tZONE, HOUR ( 11) },
605 { "m", tZONE, HOUR ( 12) },
606 { "n", tZONE, HOUR (- 1) },
607 { "o", tZONE, HOUR (- 2) },
608 { "p", tZONE, HOUR (- 3) },
609 { "q", tZONE, HOUR (- 4) },
610 { "r", tZONE, HOUR (- 5) },
611 { "s", tZONE, HOUR (- 6) },
612 { "t", tZONE, HOUR (- 7) },
613 { "u", tZONE, HOUR (- 8) },
614 { "v", tZONE, HOUR (- 9) },
615 { "w", tZONE, HOUR (-10) },
616 { "x", tZONE, HOUR (-11) },
617 { "y", tZONE, HOUR (-12) },
618 { "z", tZONE, HOUR ( 0) },
635 ToSeconds (Hours, Minutes, Seconds, Meridian)
641 if (Minutes < 0 || Minutes > 59 || Seconds < 0 || Seconds > 59)
645 if (Hours < 0 || Hours > 23)
647 return (Hours * 60L + Minutes) * 60L + Seconds;
649 if (Hours < 1 || Hours > 12)
653 return (Hours * 60L + Minutes) * 60L + Seconds;
655 if (Hours < 1 || Hours > 12)
659 return ((Hours + 12) * 60L + Minutes) * 60L + Seconds;
668 Convert (Month, Day, Year, Hours, Minutes, Seconds, Meridian, DSTmode)
678 static int DaysInMonth[12] = {
679 31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
687 if (Year < DOOMSDAY-2000)
691 DaysInMonth[1] = Year % 4 == 0 && (Year % 100 != 0 || Year % 400 == 0)
693 if (Year < EPOCH || Year > DOOMSDAY
694 || Month < 1 || Month > 12
695 /* Lint fluff: "conversion from long may lose accuracy" */
696 || Day < 1 || Day > DaysInMonth[(int)--Month])
699 for (Julian = Day - 1, i = 0; i < Month; i++)
700 Julian += DaysInMonth[i];
701 for (i = EPOCH; i < Year; i++)
702 Julian += 365 + (i % 4 == 0);
703 Julian *= SECSPERDAY;
704 Julian += yyTimezone * 60L;
705 if ((tod = ToSeconds (Hours, Minutes, Seconds, Meridian)) < 0)
709 || (DSTmode == DSTmaybe && localtime (&Julian)->tm_isdst))
716 DSTcorrect (Start, Future)
723 StartDay = (localtime (&Start)->tm_hour + 1) % 24;
724 FutureDay = (localtime (&Future)->tm_hour + 1) % 24;
725 return (Future - Start) + (StartDay - FutureDay) * 60L * 60L;
730 RelativeDate (Start, DayOrdinal, DayNumber)
739 tm = localtime (&now);
740 now += SECSPERDAY * ((DayNumber - tm->tm_wday + 7) % 7);
741 now += 7 * SECSPERDAY * (DayOrdinal <= 0 ? DayOrdinal : DayOrdinal - 1);
742 return DSTcorrect (Start, now);
747 RelativeMonth (Start, RelMonth)
757 tm = localtime (&Start);
758 Month = 12 * (1900 + tm->tm_year) + tm->tm_mon + RelMonth;
760 Month = Month % 12 + 1;
761 return DSTcorrect (Start,
762 Convert (Month, (time_t)tm->tm_mday, Year,
763 (time_t)tm->tm_hour, (time_t)tm->tm_min, (time_t)tm->tm_sec,
774 register const TABLE *tp;
778 /* Make it lowercase. */
779 for (p = buff; *p; p++)
783 if (strcmp (buff, "am") == 0 || strcmp (buff, "a.m.") == 0) {
784 yylval.Meridian = MERam;
787 if (strcmp (buff, "pm") == 0 || strcmp (buff, "p.m.") == 0) {
788 yylval.Meridian = MERpm;
792 /* See if we have an abbreviation for a month. */
793 if (strlen (buff) == 3)
795 else if (strlen (buff) == 4 && buff[3] == '.') {
802 for (tp = MonthDayTable; tp->name; tp++) {
804 if (strncmp (buff, tp->name, 3) == 0) {
805 yylval.Number = tp->value;
809 else if (strcmp (buff, tp->name) == 0) {
810 yylval.Number = tp->value;
815 for (tp = TimezoneTable; tp->name; tp++)
816 if (strcmp (buff, tp->name) == 0) {
817 yylval.Number = tp->value;
821 if (strcmp (buff, "dst") == 0)
824 for (tp = UnitsTable; tp->name; tp++)
825 if (strcmp (buff, tp->name) == 0) {
826 yylval.Number = tp->value;
830 /* Strip off any plural and try the units table again. */
831 i = strlen (buff) - 1;
832 if (buff[i] == 's') {
834 for (tp = UnitsTable; tp->name; tp++)
835 if (strcmp (buff, tp->name) == 0) {
836 yylval.Number = tp->value;
839 buff[i] = 's'; /* Put back for "this" in OtherTable. */
842 for (tp = OtherTable; tp->name; tp++)
843 if (strcmp (buff, tp->name) == 0) {
844 yylval.Number = tp->value;
848 /* Military timezones. */
849 if (buff[1] == '\0' && ISALPHA (*buff)) {
850 for (tp = MilitaryTable; tp->name; tp++)
851 if (strcmp (buff, tp->name) == 0) {
852 yylval.Number = tp->value;
857 /* Drop out any periods and try the timezone table again. */
858 for (i = 0, p = q = buff; *q; q++)
865 for (tp = TimezoneTable; tp->name; tp++)
866 if (strcmp (buff, tp->name) == 0) {
867 yylval.Number = tp->value;
885 while (ISSPACE (*yyInput))
888 if (ISDIGIT (c = *yyInput) || c == '-' || c == '+') {
889 if (c == '-' || c == '+') {
890 sign = c == '-' ? -1 : 1;
891 if (!ISDIGIT (*++yyInput))
892 /* skip the '-' sign */
897 for (yylval.Number = 0; ISDIGIT (c = *yyInput++); )
898 yylval.Number = 10 * yylval.Number + c - '0';
901 yylval.Number = -yylval.Number;
902 return sign ? tSNUMBER : tUNUMBER;
905 for (p = buff; ISALPHA (c = *yyInput++) || c == '.'; )
906 if (p < &buff[sizeof buff - 1])
910 return LookupWord (buff);
927 #define TM_YEAR_ORIGIN 1900
929 /* Yield A - B, measured in seconds. */
934 int ay = a->tm_year + (TM_YEAR_ORIGIN - 1);
935 int by = b->tm_year + (TM_YEAR_ORIGIN - 1);
937 /* difference in day of year */
938 a->tm_yday - b->tm_yday
939 /* + intervening leap days */
940 + ((ay >> 2) - (by >> 2))
942 + ((ay/100 >> 2) - (by/100 >> 2))
943 /* + difference in years * 365 */
944 + (long)(ay-by) * 365
946 return (60*(60*(24*days + (a->tm_hour - b->tm_hour))
947 + (a->tm_min - b->tm_min))
948 + (a->tm_sec - b->tm_sec));
964 (void)time (&ftz.time);
966 if (! (tm = gmtime (&ftz.time)))
968 gmt = *tm; /* Make a copy, in case localtime modifies *tm. */
970 if (! (tm = localtime (&ftz.time)))
973 ftz.timezone = difftm (&gmt, tm) / 60;
978 tm = localtime (&now->time);
979 yyYear = tm->tm_year;
980 yyMonth = tm->tm_mon + 1;
982 yyTimezone = now->timezone;
983 yyDSTmode = DSTmaybe;
997 || yyHaveTime > 1 || yyHaveZone > 1 || yyHaveDate > 1 || yyHaveDay > 1)
1000 if (yyHaveDate || yyHaveTime || yyHaveDay) {
1001 Start = Convert (yyMonth, yyDay, yyYear, yyHour, yyMinutes, yySeconds,
1002 yyMeridian, yyDSTmode);
1009 Start -= ((tm->tm_hour * 60L + tm->tm_min) * 60L) + tm->tm_sec;
1012 Start += yyRelSeconds;
1013 Start += RelativeMonth (Start, yyRelMonth);
1015 if (yyHaveDay && !yyHaveDate) {
1016 tod = RelativeDate (Start, yyDayOrdinal, yyDayNumber);
1020 /* Have to do *something* with a legitimate -1 so it's distinguishable
1021 * from the error return value. (Alternately could set errno on error.) */
1022 return Start == -1 ? 0 : Start;
1034 char buff[MAX_BUFF_LEN + 1];
1037 (void)printf ("Enter date, or blank line to exit.\n\t> ");
1038 (void)fflush (stdout);
1040 buff[MAX_BUFF_LEN] = 0;
1041 while (fgets (buff, MAX_BUFF_LEN, stdin) && buff[0]) {
1042 d = get_date (buff, (struct timeb *)NULL);
1044 (void)printf ("Bad format - couldn't convert.\n");
1046 (void)printf ("%s", ctime (&d));
1047 (void)printf ("\t> ");
1048 (void)fflush (stdout);
1053 #endif /* defined (TEST) */