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 {
319 | tUNUMBER tSNUMBER tSNUMBER {
320 /* ISO 8601 format. yyyy-mm-dd. */
325 | tUNUMBER tMONTH tSNUMBER {
326 /* e.g. 17-JUN-1992. */
335 | tMONTH tUNUMBER ',' tUNUMBER {
344 | tUNUMBER tMONTH tUNUMBER {
352 yyRelSeconds = -yyRelSeconds;
353 yyRelMonth = -yyRelMonth;
358 relunit : tUNUMBER tMINUTE_UNIT {
359 yyRelSeconds += $1 * $2 * 60L;
361 | tSNUMBER tMINUTE_UNIT {
362 yyRelSeconds += $1 * $2 * 60L;
365 yyRelSeconds += $1 * 60L;
367 | tSNUMBER tSEC_UNIT {
370 | tUNUMBER tSEC_UNIT {
376 | tSNUMBER tMONTH_UNIT {
377 yyRelMonth += $1 * $2;
379 | tUNUMBER tMONTH_UNIT {
380 yyRelMonth += $1 * $2;
388 if (yyHaveTime && yyHaveDate && !yyHaveRel)
394 yyMonth= ($1/100)%100;
405 yyMinutes = $1 % 100;
414 o_merid : /* NULL */ {
424 /* Month and day table. */
425 static TABLE const MonthDayTable[] = {
426 { "january", tMONTH, 1 },
427 { "february", tMONTH, 2 },
428 { "march", tMONTH, 3 },
429 { "april", tMONTH, 4 },
430 { "may", tMONTH, 5 },
431 { "june", tMONTH, 6 },
432 { "july", tMONTH, 7 },
433 { "august", tMONTH, 8 },
434 { "september", tMONTH, 9 },
435 { "sept", tMONTH, 9 },
436 { "october", tMONTH, 10 },
437 { "november", tMONTH, 11 },
438 { "december", tMONTH, 12 },
439 { "sunday", tDAY, 0 },
440 { "monday", tDAY, 1 },
441 { "tuesday", tDAY, 2 },
443 { "wednesday", tDAY, 3 },
444 { "wednes", tDAY, 3 },
445 { "thursday", tDAY, 4 },
447 { "thurs", tDAY, 4 },
448 { "friday", tDAY, 5 },
449 { "saturday", tDAY, 6 },
453 /* Time units table. */
454 static TABLE const UnitsTable[] = {
455 { "year", tMONTH_UNIT, 12 },
456 { "month", tMONTH_UNIT, 1 },
457 { "fortnight", tMINUTE_UNIT, 14 * 24 * 60 },
458 { "week", tMINUTE_UNIT, 7 * 24 * 60 },
459 { "day", tMINUTE_UNIT, 1 * 24 * 60 },
460 { "hour", tMINUTE_UNIT, 60 },
461 { "minute", tMINUTE_UNIT, 1 },
462 { "min", tMINUTE_UNIT, 1 },
463 { "second", tSEC_UNIT, 1 },
464 { "sec", tSEC_UNIT, 1 },
468 /* Assorted relative-time words. */
469 static TABLE const OtherTable[] = {
470 { "tomorrow", tMINUTE_UNIT, 1 * 24 * 60 },
471 { "yesterday", tMINUTE_UNIT, -1 * 24 * 60 },
472 { "today", tMINUTE_UNIT, 0 },
473 { "now", tMINUTE_UNIT, 0 },
474 { "last", tUNUMBER, -1 },
475 { "this", tMINUTE_UNIT, 0 },
476 { "next", tUNUMBER, 2 },
477 { "first", tUNUMBER, 1 },
478 /* { "second", tUNUMBER, 2 }, */
479 { "third", tUNUMBER, 3 },
480 { "fourth", tUNUMBER, 4 },
481 { "fifth", tUNUMBER, 5 },
482 { "sixth", tUNUMBER, 6 },
483 { "seventh", tUNUMBER, 7 },
484 { "eighth", tUNUMBER, 8 },
485 { "ninth", tUNUMBER, 9 },
486 { "tenth", tUNUMBER, 10 },
487 { "eleventh", tUNUMBER, 11 },
488 { "twelfth", tUNUMBER, 12 },
493 /* The timezone table. */
494 /* Some of these are commented out because a time_t can't store a float. */
495 static TABLE const TimezoneTable[] = {
496 { "gmt", tZONE, HOUR ( 0) }, /* Greenwich Mean */
497 { "ut", tZONE, HOUR ( 0) }, /* Universal (Coordinated) */
498 { "utc", tZONE, HOUR ( 0) },
499 { "wet", tZONE, HOUR ( 0) }, /* Western European */
500 { "bst", tDAYZONE, HOUR ( 0) }, /* British Summer */
501 { "wat", tZONE, HOUR ( 1) }, /* West Africa */
502 { "at", tZONE, HOUR ( 2) }, /* Azores */
504 /* For completeness. BST is also British Summer, and GST is
505 * also Guam Standard. */
506 { "bst", tZONE, HOUR ( 3) }, /* Brazil Standard */
507 { "gst", tZONE, HOUR ( 3) }, /* Greenland Standard */
510 { "nft", tZONE, HOUR (3.5) }, /* Newfoundland */
511 { "nst", tZONE, HOUR (3.5) }, /* Newfoundland Standard */
512 { "ndt", tDAYZONE, HOUR (3.5) }, /* Newfoundland Daylight */
514 { "ast", tZONE, HOUR ( 4) }, /* Atlantic Standard */
515 { "adt", tDAYZONE, HOUR ( 4) }, /* Atlantic Daylight */
516 { "est", tZONE, HOUR ( 5) }, /* Eastern Standard */
517 { "edt", tDAYZONE, HOUR ( 5) }, /* Eastern Daylight */
518 { "cst", tZONE, HOUR ( 6) }, /* Central Standard */
519 { "cdt", tDAYZONE, HOUR ( 6) }, /* Central Daylight */
520 { "mst", tZONE, HOUR ( 7) }, /* Mountain Standard */
521 { "mdt", tDAYZONE, HOUR ( 7) }, /* Mountain Daylight */
522 { "pst", tZONE, HOUR ( 8) }, /* Pacific Standard */
523 { "pdt", tDAYZONE, HOUR ( 8) }, /* Pacific Daylight */
524 { "yst", tZONE, HOUR ( 9) }, /* Yukon Standard */
525 { "ydt", tDAYZONE, HOUR ( 9) }, /* Yukon Daylight */
526 { "hst", tZONE, HOUR (10) }, /* Hawaii Standard */
527 { "hdt", tDAYZONE, HOUR (10) }, /* Hawaii Daylight */
528 { "cat", tZONE, HOUR (10) }, /* Central Alaska */
529 { "ahst", tZONE, HOUR (10) }, /* Alaska-Hawaii Standard */
530 { "nt", tZONE, HOUR (11) }, /* Nome */
531 { "idlw", tZONE, HOUR (12) }, /* International Date Line West */
532 { "cet", tZONE, -HOUR (1) }, /* Central European */
533 { "met", tZONE, -HOUR (1) }, /* Middle European */
534 { "mewt", tZONE, -HOUR (1) }, /* Middle European Winter */
535 { "mest", tDAYZONE, -HOUR (1) }, /* Middle European Summer */
536 { "mesz", tDAYZONE, -HOUR (1) }, /* Middle European Summer */
537 { "swt", tZONE, -HOUR (1) }, /* Swedish Winter */
538 { "sst", tDAYZONE, -HOUR (1) }, /* Swedish Summer */
539 { "fwt", tZONE, -HOUR (1) }, /* French Winter */
540 { "fst", tDAYZONE, -HOUR (1) }, /* French Summer */
541 { "eet", tZONE, -HOUR (2) }, /* Eastern Europe, USSR Zone 1 */
542 { "bt", tZONE, -HOUR (3) }, /* Baghdad, USSR Zone 2 */
544 { "it", tZONE, -HOUR (3.5) },/* Iran */
546 { "zp4", tZONE, -HOUR (4) }, /* USSR Zone 3 */
547 { "zp5", tZONE, -HOUR (5) }, /* USSR Zone 4 */
549 { "ist", tZONE, -HOUR (5.5) },/* Indian Standard */
551 { "zp6", tZONE, -HOUR (6) }, /* USSR Zone 5 */
553 /* For completeness. NST is also Newfoundland Standard, and SST is
554 * also Swedish Summer. */
555 { "nst", tZONE, -HOUR (6.5) },/* North Sumatra */
556 { "sst", tZONE, -HOUR (7) }, /* South Sumatra, USSR Zone 6 */
558 { "wast", tZONE, -HOUR (7) }, /* West Australian Standard */
559 { "wadt", tDAYZONE, -HOUR (7) }, /* West Australian Daylight */
561 { "jt", tZONE, -HOUR (7.5) },/* Java (3pm in Cronusland!) */
563 { "cct", tZONE, -HOUR (8) }, /* China Coast, USSR Zone 7 */
564 { "jst", tZONE, -HOUR (9) }, /* Japan Standard, USSR Zone 8 */
566 { "cast", tZONE, -HOUR (9.5) },/* Central Australian Standard */
567 { "cadt", tDAYZONE, -HOUR (9.5) },/* Central Australian Daylight */
569 { "east", tZONE, -HOUR (10) }, /* Eastern Australian Standard */
570 { "eadt", tDAYZONE, -HOUR (10) }, /* Eastern Australian Daylight */
571 { "gst", tZONE, -HOUR (10) }, /* Guam Standard, USSR Zone 9 */
572 { "nzt", tZONE, -HOUR (12) }, /* New Zealand */
573 { "nzst", tZONE, -HOUR (12) }, /* New Zealand Standard */
574 { "nzdt", tDAYZONE, -HOUR (12) }, /* New Zealand Daylight */
575 { "idle", tZONE, -HOUR (12) }, /* International Date Line East */
579 /* Military timezone table. */
580 static TABLE const MilitaryTable[] = {
581 { "a", tZONE, HOUR ( 1) },
582 { "b", tZONE, HOUR ( 2) },
583 { "c", tZONE, HOUR ( 3) },
584 { "d", tZONE, HOUR ( 4) },
585 { "e", tZONE, HOUR ( 5) },
586 { "f", tZONE, HOUR ( 6) },
587 { "g", tZONE, HOUR ( 7) },
588 { "h", tZONE, HOUR ( 8) },
589 { "i", tZONE, HOUR ( 9) },
590 { "k", tZONE, HOUR ( 10) },
591 { "l", tZONE, HOUR ( 11) },
592 { "m", tZONE, HOUR ( 12) },
593 { "n", tZONE, HOUR (- 1) },
594 { "o", tZONE, HOUR (- 2) },
595 { "p", tZONE, HOUR (- 3) },
596 { "q", tZONE, HOUR (- 4) },
597 { "r", tZONE, HOUR (- 5) },
598 { "s", tZONE, HOUR (- 6) },
599 { "t", tZONE, HOUR (- 7) },
600 { "u", tZONE, HOUR (- 8) },
601 { "v", tZONE, HOUR (- 9) },
602 { "w", tZONE, HOUR (-10) },
603 { "x", tZONE, HOUR (-11) },
604 { "y", tZONE, HOUR (-12) },
605 { "z", tZONE, HOUR ( 0) },
622 ToSeconds (Hours, Minutes, Seconds, Meridian)
628 if (Minutes < 0 || Minutes > 59 || Seconds < 0 || Seconds > 59)
632 if (Hours < 0 || Hours > 23)
634 return (Hours * 60L + Minutes) * 60L + Seconds;
636 if (Hours < 1 || Hours > 12)
640 return (Hours * 60L + Minutes) * 60L + Seconds;
642 if (Hours < 1 || Hours > 12)
646 return ((Hours + 12) * 60L + Minutes) * 60L + Seconds;
655 Convert (Month, Day, Year, Hours, Minutes, Seconds, Meridian, DSTmode)
665 static int DaysInMonth[12] = {
666 31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
674 if (Year < DOOMSDAY-2000)
678 DaysInMonth[1] = Year % 4 == 0 && (Year % 100 != 0 || Year % 400 == 0)
680 if (Year < EPOCH || Year >= DOOMSDAY
681 || Month < 1 || Month > 12
682 /* Lint fluff: "conversion from long may lose accuracy" */
683 || Day < 1 || Day > DaysInMonth[(int)--Month])
686 for (Julian = Day - 1, i = 0; i < Month; i++)
687 Julian += DaysInMonth[i];
688 for (i = EPOCH; i < Year; i++)
689 Julian += 365 + (i % 4 == 0);
690 Julian *= SECSPERDAY;
691 Julian += yyTimezone * 60L;
692 if ((tod = ToSeconds (Hours, Minutes, Seconds, Meridian)) < 0)
696 || (DSTmode == DSTmaybe && localtime (&Julian)->tm_isdst))
703 DSTcorrect (Start, Future)
710 StartDay = (localtime (&Start)->tm_hour + 1) % 24;
711 FutureDay = (localtime (&Future)->tm_hour + 1) % 24;
712 return (Future - Start) + (StartDay - FutureDay) * 60L * 60L;
717 RelativeDate (Start, DayOrdinal, DayNumber)
726 tm = localtime (&now);
727 now += SECSPERDAY * ((DayNumber - tm->tm_wday + 7) % 7);
728 now += 7 * SECSPERDAY * (DayOrdinal <= 0 ? DayOrdinal : DayOrdinal - 1);
729 return DSTcorrect (Start, now);
734 RelativeMonth (Start, RelMonth)
744 tm = localtime (&Start);
745 Month = 12 * (1900 + tm->tm_year) + tm->tm_mon + RelMonth;
747 Month = Month % 12 + 1;
748 return DSTcorrect (Start,
749 Convert (Month, (time_t)tm->tm_mday, Year,
750 (time_t)tm->tm_hour, (time_t)tm->tm_min, (time_t)tm->tm_sec,
761 register const TABLE *tp;
765 /* Make it lowercase. */
766 for (p = buff; *p; p++)
770 if (strcmp (buff, "am") == 0 || strcmp (buff, "a.m.") == 0) {
771 yylval.Meridian = MERam;
774 if (strcmp (buff, "pm") == 0 || strcmp (buff, "p.m.") == 0) {
775 yylval.Meridian = MERpm;
779 /* See if we have an abbreviation for a month. */
780 if (strlen (buff) == 3)
782 else if (strlen (buff) == 4 && buff[3] == '.') {
789 for (tp = MonthDayTable; tp->name; tp++) {
791 if (strncmp (buff, tp->name, 3) == 0) {
792 yylval.Number = tp->value;
796 else if (strcmp (buff, tp->name) == 0) {
797 yylval.Number = tp->value;
802 for (tp = TimezoneTable; tp->name; tp++)
803 if (strcmp (buff, tp->name) == 0) {
804 yylval.Number = tp->value;
808 if (strcmp (buff, "dst") == 0)
811 for (tp = UnitsTable; tp->name; tp++)
812 if (strcmp (buff, tp->name) == 0) {
813 yylval.Number = tp->value;
817 /* Strip off any plural and try the units table again. */
818 i = strlen (buff) - 1;
819 if (buff[i] == 's') {
821 for (tp = UnitsTable; tp->name; tp++)
822 if (strcmp (buff, tp->name) == 0) {
823 yylval.Number = tp->value;
826 buff[i] = 's'; /* Put back for "this" in OtherTable. */
829 for (tp = OtherTable; tp->name; tp++)
830 if (strcmp (buff, tp->name) == 0) {
831 yylval.Number = tp->value;
835 /* Military timezones. */
836 if (buff[1] == '\0' && ISALPHA (*buff)) {
837 for (tp = MilitaryTable; tp->name; tp++)
838 if (strcmp (buff, tp->name) == 0) {
839 yylval.Number = tp->value;
844 /* Drop out any periods and try the timezone table again. */
845 for (i = 0, p = q = buff; *q; q++)
852 for (tp = TimezoneTable; tp->name; tp++)
853 if (strcmp (buff, tp->name) == 0) {
854 yylval.Number = tp->value;
872 while (ISSPACE (*yyInput))
875 if (ISDIGIT (c = *yyInput) || c == '-' || c == '+') {
876 if (c == '-' || c == '+') {
877 sign = c == '-' ? -1 : 1;
878 if (!ISDIGIT (*++yyInput))
879 /* skip the '-' sign */
884 for (yylval.Number = 0; ISDIGIT (c = *yyInput++); )
885 yylval.Number = 10 * yylval.Number + c - '0';
888 yylval.Number = -yylval.Number;
889 return sign ? tSNUMBER : tUNUMBER;
892 for (p = buff; ISALPHA (c = *yyInput++) || c == '.'; )
893 if (p < &buff[sizeof buff - 1])
897 return LookupWord (buff);
914 #define TM_YEAR_ORIGIN 1900
916 /* Yield A - B, measured in seconds. */
921 int ay = a->tm_year + (TM_YEAR_ORIGIN - 1);
922 int by = b->tm_year + (TM_YEAR_ORIGIN - 1);
924 /* difference in day of year */
925 a->tm_yday - b->tm_yday
926 /* + intervening leap days */
927 + ((ay >> 2) - (by >> 2))
929 + ((ay/100 >> 2) - (by/100 >> 2))
930 /* + difference in years * 365 */
931 + (long)(ay-by) * 365
933 return (60*(60*(24*days + (a->tm_hour - b->tm_hour))
934 + (a->tm_min - b->tm_min))
935 + (a->tm_sec - b->tm_sec));
951 (void)time (&ftz.time);
953 if (! (tm = gmtime (&ftz.time)))
955 gmt = *tm; /* Make a copy, in case localtime modifies *tm. */
957 if (! (tm = localtime (&ftz.time)))
960 ftz.timezone = difftm (&gmt, tm) / 60;
965 tm = localtime (&now->time);
966 yyYear = tm->tm_year;
967 yyMonth = tm->tm_mon + 1;
969 yyTimezone = now->timezone;
970 yyDSTmode = DSTmaybe;
984 || yyHaveTime > 1 || yyHaveZone > 1 || yyHaveDate > 1 || yyHaveDay > 1)
987 if (yyHaveDate || yyHaveTime || yyHaveDay) {
988 Start = Convert (yyMonth, yyDay, yyYear, yyHour, yyMinutes, yySeconds,
989 yyMeridian, yyDSTmode);
996 Start -= ((tm->tm_hour * 60L + tm->tm_min) * 60L) + tm->tm_sec;
999 Start += yyRelSeconds;
1000 Start += RelativeMonth (Start, yyRelMonth);
1002 if (yyHaveDay && !yyHaveDate) {
1003 tod = RelativeDate (Start, yyDayOrdinal, yyDayNumber);
1007 /* Have to do *something* with a legitimate -1 so it's distinguishable
1008 * from the error return value. (Alternately could set errno on error.) */
1009 return Start == -1 ? 0 : Start;
1021 char buff[MAX_BUFF_LEN + 1];
1024 (void)printf ("Enter date, or blank line to exit.\n\t> ");
1025 (void)fflush (stdout);
1027 buff[MAX_BUFF_LEN] = 0;
1028 while (fgets (buff, MAX_BUFF_LEN, stdin) && buff[0]) {
1029 d = get_date (buff, (struct timeb *)NULL);
1031 (void)printf ("Bad format - couldn't convert.\n");
1033 (void)printf ("%s", ctime (&d));
1034 (void)printf ("\t> ");
1035 (void)fflush (stdout);
1040 #endif /* defined (TEST) */