2 /* $Id: parsedate.y,v 1.9.2.1 2000/12/26 08:39:49 kondou Exp $
5 ** Originally written by Steven M. Bellovin <smb@research.att.com> while
6 ** at the University of North Carolina at Chapel Hill. Later tweaked by
7 ** a couple of people on Usenet. Completely overhauled by Rich $alz
8 ** <rsalz@osf.org> and Jim Berets <jberets@bbn.com> in August, 1990.
9 ** Further revised (removed obsolete constructs and cleaned up timezone
10 ** names) in August, 1991, by Rich. Paul Eggert <eggert@twinsun.com>
11 ** helped in September, 1992.
13 ** This grammar has six shift/reduce conflicts.
15 ** This code is in the public domain and has no copyright.
17 /* SUPPRESS 530 *//* Empty body for statement */
18 /* SUPPRESS 593 on yyerrlab *//* Label was not used */
19 /* SUPPRESS 593 on yynewstate *//* Label was not used */
20 /* SUPPRESS 595 on yypvt *//* Automatic variable may be used before set */
22 #include <sys/types.h>
24 #include <sys/timeb.h>
32 #define CTYPE(isXXXXX, c) (isXXXXX((c)))
33 #define SIZEOF(array) (sizeof array / sizeof array[0])
34 #define ENDOF(array) (&array[SIZEOF(array)])
36 typedef const char *STRING;
37 typedef struct timeb TIMEINFO;
39 #define yylhs date_yylhs
40 #define yylen date_yylen
41 #define yydefred date_yydefred
42 #define yydgoto date_yydgoto
43 #define yysindex date_yysindex
44 #define yyrindex date_yyrindex
45 #define yygindex date_yygindex
46 #define yytable date_yytable
47 #define yycheck date_yycheck
48 #define yyparse date_parse
49 #define yylex date_lex
50 #define yyerror date_error
53 static int date_lex(void);
56 /* See the LeapYears table in Convert. */
58 #define END_OF_TIME 2038
59 /* Constants for general time calculations. */
61 #define SECSPERDAY (24L * 60L * 60L)
62 /* Readability for TABLE stuff. */
63 #define HOUR(x) (x * 60)
67 #define IS7BIT(x) ((unsigned int)(x) < 0200)
71 ** An entry in the lexical lookup table.
73 typedef struct _TABLE {
80 ** Daylight-savings mode: on, off, or not yet known.
82 typedef enum _DSTMODE {
83 DSTon, DSToff, DSTmaybe
87 ** Meridian: am, pm, or 24-hour style.
89 typedef enum _MERIDIAN {
95 ** Global variables. We could get rid of most of them by using a yacc
96 ** union, but this is more efficient. (This routine predates the
97 ** yacc %union construct.)
100 static DSTMODE yyDSTmode;
101 static int yyHaveDate;
102 static int yyHaveRel;
103 static int yyHaveTime;
104 static time_t yyTimezone;
106 static time_t yyHour;
107 static time_t yyMinutes;
108 static time_t yyMonth;
109 static time_t yySeconds;
110 static time_t yyYear;
111 static MERIDIAN yyMeridian;
112 static time_t yyRelMonth;
113 static time_t yyRelSeconds;
115 static void date_error(const char *);
120 enum _MERIDIAN Meridian;
123 %token tDAY tDAYZONE tMERIDIAN tMONTH tMONTH_UNIT tSEC_UNIT tSNUMBER
124 %token tUNUMBER tZONE
126 %type <Number> tDAYZONE tMONTH tMONTH_UNIT tSEC_UNIT
127 %type <Number> tSNUMBER tUNUMBER tZONE numzone zone
128 %type <Meridian> tMERIDIAN o_merid
139 /* I am compulsive about lint natterings... */
140 if (yyHaveTime == -1) {
143 #endif /* defined(lint) */
157 time : tUNUMBER o_merid {
164 yyMinutes = $1 % 100;
169 | tUNUMBER ':' tUNUMBER o_merid {
175 | tUNUMBER ':' tUNUMBER numzone {
182 | tUNUMBER ':' tUNUMBER ':' tUNUMBER o_merid {
188 | tUNUMBER ':' tUNUMBER ':' tUNUMBER numzone {
207 /* Only allow "GMT+300" and "GMT-0800" */
223 /* Unix and GMT and numeric timezones -- a little confusing. */
225 /* Don't work with negative modulus. */
227 if ($1 > 9999 || (i = $1 % 100) >= 60) {
230 $$ = ($1 / 100) * 60 + i;
233 if ($1 > 9999 || (i = $1 % 100) >= 60) {
236 $$ = -(($1 / 100) * 60 + i);
241 date : tUNUMBER '/' tUNUMBER {
245 | tUNUMBER '/' tUNUMBER '/' tUNUMBER {
247 /* assume YYYY/MM/DD format, so need not to add 1900 */
257 /* assume MM/DD/YY* format */
261 /* assume year is YYYY format, so need not to add 1900 */
263 } else if ($5 < 100) {
264 /* assume year is YY format, so need to add 1900 */
265 yyYear = $5 + (yyYear / 100 + (yyYear % 100 - $5) / 50) * 100;
275 | tMONTH tUNUMBER ',' tUNUMBER {
279 /* assume year is YYYY format, so need not to add 1900 */
281 } else if ($4 < 100) {
282 /* assume year is YY format, so need to add 1900 */
283 yyYear = $4 + (yyYear / 100 + (yyYear % 100 - $4) / 50) * 100;
292 | tUNUMBER tMONTH tUNUMBER {
296 /* assume year is YYYY format, so need not to add 1900 */
298 } else if ($3 < 100) {
299 /* assume year is YY format, so need to add 1900 */
300 yyYear = $3 + (yyYear / 100 + (yyYear % 100 - $3) / 50) * 100;
305 | tDAY ',' tUNUMBER tMONTH tUNUMBER {
309 /* assume year is YYYY format, so need not to add 1900 */
311 } else if ($5 < 100) {
312 /* assume year is YY format, so need to add 1900 */
313 yyYear = $5 + (yyYear / 100 + (yyYear % 100 - $5) / 50) * 100;
320 rel : tSNUMBER tSEC_UNIT {
321 yyRelSeconds += $1 * $2;
323 | tUNUMBER tSEC_UNIT {
324 yyRelSeconds += $1 * $2;
326 | tSNUMBER tMONTH_UNIT {
327 yyRelMonth += $1 * $2;
329 | tUNUMBER tMONTH_UNIT {
330 yyRelMonth += $1 * $2;
334 o_merid : /* NULL */ {
344 /* Month and day table. */
345 static TABLE MonthDayTable[] = {
346 { "january", tMONTH, 1 },
347 { "february", tMONTH, 2 },
348 { "march", tMONTH, 3 },
349 { "april", tMONTH, 4 },
350 { "may", tMONTH, 5 },
351 { "june", tMONTH, 6 },
352 { "july", tMONTH, 7 },
353 { "august", tMONTH, 8 },
354 { "september", tMONTH, 9 },
355 { "october", tMONTH, 10 },
356 { "november", tMONTH, 11 },
357 { "december", tMONTH, 12 },
358 /* The value of the day isn't used... */
359 { "sunday", tDAY, 0 },
360 { "monday", tDAY, 0 },
361 { "tuesday", tDAY, 0 },
362 { "wednesday", tDAY, 0 },
363 { "thursday", tDAY, 0 },
364 { "friday", tDAY, 0 },
365 { "saturday", tDAY, 0 },
368 /* Time units table. */
369 static TABLE UnitsTable[] = {
370 { "year", tMONTH_UNIT, 12 },
371 { "month", tMONTH_UNIT, 1 },
372 { "week", tSEC_UNIT, 7 * 24 * 60 * 60 },
373 { "day", tSEC_UNIT, 1 * 24 * 60 * 60 },
374 { "hour", tSEC_UNIT, 60 * 60 },
375 { "minute", tSEC_UNIT, 60 },
376 { "min", tSEC_UNIT, 60 },
377 { "second", tSEC_UNIT, 1 },
378 { "sec", tSEC_UNIT, 1 },
381 /* Timezone table. */
382 static TABLE TimezoneTable[] = {
383 { "gmt", tZONE, HOUR( 0) }, /* Greenwich Mean */
384 { "ut", tZONE, HOUR( 0) }, /* Universal */
385 { "utc", tZONE, HOUR( 0) }, /* Universal Coordinated */
386 { "cut", tZONE, HOUR( 0) }, /* Coordinated Universal */
387 { "z", tZONE, HOUR( 0) }, /* Greenwich Mean */
388 { "wet", tZONE, HOUR( 0) }, /* Western European */
389 { "bst", tDAYZONE, HOUR( 0) }, /* British Summer */
390 { "nst", tZONE, HOUR(3)+30 }, /* Newfoundland Standard */
391 { "ndt", tDAYZONE, HOUR(3)+30 }, /* Newfoundland Daylight */
392 { "ast", tZONE, HOUR( 4) }, /* Atlantic Standard */
393 { "adt", tDAYZONE, HOUR( 4) }, /* Atlantic Daylight */
394 { "est", tZONE, HOUR( 5) }, /* Eastern Standard */
395 { "edt", tDAYZONE, HOUR( 5) }, /* Eastern Daylight */
396 { "cst", tZONE, HOUR( 6) }, /* Central Standard */
397 { "cdt", tDAYZONE, HOUR( 6) }, /* Central Daylight */
398 { "mst", tZONE, HOUR( 7) }, /* Mountain Standard */
399 { "mdt", tDAYZONE, HOUR( 7) }, /* Mountain Daylight */
400 { "pst", tZONE, HOUR( 8) }, /* Pacific Standard */
401 { "pdt", tDAYZONE, HOUR( 8) }, /* Pacific Daylight */
402 { "yst", tZONE, HOUR( 9) }, /* Yukon Standard */
403 { "ydt", tDAYZONE, HOUR( 9) }, /* Yukon Daylight */
404 { "akst", tZONE, HOUR( 9) }, /* Alaska Standard */
405 { "akdt", tDAYZONE, HOUR( 9) }, /* Alaska Daylight */
406 { "hst", tZONE, HOUR(10) }, /* Hawaii Standard */
407 { "hast", tZONE, HOUR(10) }, /* Hawaii-Aleutian Standard */
408 { "hadt", tDAYZONE, HOUR(10) }, /* Hawaii-Aleutian Daylight */
409 { "ces", tDAYZONE, -HOUR(1) }, /* Central European Summer */
410 { "cest", tDAYZONE, -HOUR(1) }, /* Central European Summer */
411 { "mez", tZONE, -HOUR(1) }, /* Middle European */
412 { "mezt", tDAYZONE, -HOUR(1) }, /* Middle European Summer */
413 { "cet", tZONE, -HOUR(1) }, /* Central European */
414 { "met", tZONE, -HOUR(1) }, /* Middle European */
415 { "eet", tZONE, -HOUR(2) }, /* Eastern Europe */
416 { "msk", tZONE, -HOUR(3) }, /* Moscow Winter */
417 { "msd", tDAYZONE, -HOUR(3) }, /* Moscow Summer */
418 { "wast", tZONE, -HOUR(8) }, /* West Australian Standard */
419 { "wadt", tDAYZONE, -HOUR(8) }, /* West Australian Daylight */
420 { "hkt", tZONE, -HOUR(8) }, /* Hong Kong */
421 { "cct", tZONE, -HOUR(8) }, /* China Coast */
422 { "jst", tZONE, -HOUR(9) }, /* Japan Standard */
423 { "kst", tZONE, -HOUR(9) }, /* Korean Standard */
424 { "kdt", tZONE, -HOUR(9) }, /* Korean Daylight */
425 { "cast", tZONE, -(HOUR(9)+30) }, /* Central Australian Standard */
426 { "cadt", tDAYZONE, -(HOUR(9)+30) }, /* Central Australian Daylight */
427 { "east", tZONE, -HOUR(10) }, /* Eastern Australian Standard */
428 { "eadt", tDAYZONE, -HOUR(10) }, /* Eastern Australian Daylight */
429 { "nzst", tZONE, -HOUR(12) }, /* New Zealand Standard */
430 { "nzdt", tDAYZONE, -HOUR(12) }, /* New Zealand Daylight */
432 /* For completeness we include the following entries. */
435 /* Duplicate names. Either they conflict with a zone listed above
436 * (which is either more likely to be seen or just been in circulation
437 * longer), or they conflict with another zone in this section and
438 * we could not reasonably choose one over the other. */
439 { "fst", tZONE, HOUR( 2) }, /* Fernando De Noronha Standard */
440 { "fdt", tDAYZONE, HOUR( 2) }, /* Fernando De Noronha Daylight */
441 { "bst", tZONE, HOUR( 3) }, /* Brazil Standard */
442 { "est", tZONE, HOUR( 3) }, /* Eastern Standard (Brazil) */
443 { "edt", tDAYZONE, HOUR( 3) }, /* Eastern Daylight (Brazil) */
444 { "wst", tZONE, HOUR( 4) }, /* Western Standard (Brazil) */
445 { "wdt", tDAYZONE, HOUR( 4) }, /* Western Daylight (Brazil) */
446 { "cst", tZONE, HOUR( 5) }, /* Chile Standard */
447 { "cdt", tDAYZONE, HOUR( 5) }, /* Chile Daylight */
448 { "ast", tZONE, HOUR( 5) }, /* Acre Standard */
449 { "adt", tDAYZONE, HOUR( 5) }, /* Acre Daylight */
450 { "cst", tZONE, HOUR( 5) }, /* Cuba Standard */
451 { "cdt", tDAYZONE, HOUR( 5) }, /* Cuba Daylight */
452 { "est", tZONE, HOUR( 6) }, /* Easter Island Standard */
453 { "edt", tDAYZONE, HOUR( 6) }, /* Easter Island Daylight */
454 { "sst", tZONE, HOUR(11) }, /* Samoa Standard */
455 { "ist", tZONE, -HOUR(2) }, /* Israel Standard */
456 { "idt", tDAYZONE, -HOUR(2) }, /* Israel Daylight */
457 { "idt", tDAYZONE, -(HOUR(3)+30) }, /* Iran Daylight */
458 { "ist", tZONE, -(HOUR(3)+30) }, /* Iran Standard */
459 { "cst", tZONE, -HOUR(8) }, /* China Standard */
460 { "cdt", tDAYZONE, -HOUR(8) }, /* China Daylight */
461 { "sst", tZONE, -HOUR(8) }, /* Singapore Standard */
463 /* Dubious (e.g., not in Olson's TIMEZONE package) or obsolete. */
464 { "gst", tZONE, HOUR( 3) }, /* Greenland Standard */
465 { "wat", tZONE, -HOUR(1) }, /* West Africa */
466 { "at", tZONE, HOUR( 2) }, /* Azores */
467 { "gst", tZONE, -HOUR(10) }, /* Guam Standard */
468 { "nft", tZONE, HOUR(3)+30 }, /* Newfoundland */
469 { "idlw", tZONE, HOUR(12) }, /* International Date Line West */
470 { "mewt", tZONE, -HOUR(1) }, /* Middle European Winter */
471 { "mest", tDAYZONE, -HOUR(1) }, /* Middle European Summer */
472 { "swt", tZONE, -HOUR(1) }, /* Swedish Winter */
473 { "sst", tDAYZONE, -HOUR(1) }, /* Swedish Summer */
474 { "fwt", tZONE, -HOUR(1) }, /* French Winter */
475 { "fst", tDAYZONE, -HOUR(1) }, /* French Summer */
476 { "bt", tZONE, -HOUR(3) }, /* Baghdad */
477 { "it", tZONE, -(HOUR(3)+30) }, /* Iran */
478 { "zp4", tZONE, -HOUR(4) }, /* USSR Zone 3 */
479 { "zp5", tZONE, -HOUR(5) }, /* USSR Zone 4 */
480 { "ist", tZONE, -(HOUR(5)+30) }, /* Indian Standard */
481 { "zp6", tZONE, -HOUR(6) }, /* USSR Zone 5 */
482 { "nst", tZONE, -HOUR(7) }, /* North Sumatra */
483 { "sst", tZONE, -HOUR(7) }, /* South Sumatra */
484 { "jt", tZONE, -(HOUR(7)+30) }, /* Java (3pm in Cronusland!) */
485 { "nzt", tZONE, -HOUR(12) }, /* New Zealand */
486 { "idle", tZONE, -HOUR(12) }, /* International Date Line East */
487 { "cat", tZONE, HOUR(10) }, /* -- expired 1967 */
488 { "nt", tZONE, HOUR(11) }, /* -- expired 1967 */
489 { "ahst", tZONE, HOUR(10) }, /* -- expired 1983 */
490 { "hdt", tDAYZONE, HOUR(10) }, /* -- expired 1986 */
497 GetTimeInfo(TIMEINFO *Now)
499 static time_t NextHour;
500 static long LastTzone;
502 int secondsUntilNextHour;
505 /* Get the basic time. */
506 if (gettimeofday(&tv, (struct timezone *) 0) == -1)
508 Now->time = tv.tv_sec;
509 Now->millitm = tv.tv_usec;
511 /* Now get the timezone if the last time < HH:00:00 <= now for some HH. */
512 if (NextHour <= Now->time) {
513 tm = localtime(&Now->time);
516 secondsUntilNextHour = 60 * (60 - tm->tm_min) - tm->tm_sec;
517 LastTzone = (0 - tm->tm_gmtoff) / 60;
518 NextHour = Now->time + secondsUntilNextHour;
520 Now->timezone = LastTzone;
527 date_error(const char *s __unused)
534 ToSeconds(time_t Hours, time_t Minutes, time_t Seconds, MERIDIAN Meridian)
536 if (Minutes < 0 || Minutes > 59 || Seconds < 0 || Seconds > 61)
538 if (Meridian == MER24) {
539 if (Hours < 0 || Hours > 23)
543 if (Hours < 1 || Hours > 12)
547 if (Meridian == MERpm)
550 return (Hours * 60L + Minutes) * 60L + Seconds;
555 Convert(time_t Month, time_t Day, time_t Year, time_t Hours, time_t Minutes, time_t Seconds, MERIDIAN Meridian, DSTMODE dst)
557 static int DaysNormal[13] = {
558 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
560 static int DaysLeap[13] = {
561 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
563 static int LeapYears[] = {
564 1972, 1976, 1980, 1984, 1988, 1992, 1996,
565 2000, 2004, 2008, 2012, 2016, 2020, 2024, 2028, 2032, 2036
573 /* Year should not be passed as a relative value, but absolute one.
574 so this should not happen, but just ensure it */
582 for (mp = DaysNormal, yp = LeapYears; yp < ENDOF(LeapYears); yp++)
587 if (Year < EPOCH || Year > END_OF_TIME
588 || Month < 1 || Month > 12
589 /* NOSTRICT *//* conversion from long may lose accuracy */
590 || Day < 1 || Day > mp[(int)Month])
593 Julian = Day - 1 + (Year - EPOCH) * 365;
594 for (yp = LeapYears; yp < ENDOF(LeapYears); yp++, Julian++)
597 for (i = 1; i < Month; i++)
599 Julian *= SECSPERDAY;
600 Julian += yyTimezone * 60L;
601 if ((tod = ToSeconds(Hours, Minutes, Seconds, Meridian)) < 0)
605 if (dst == DSTon || (dst == DSTmaybe && localtime(&tod)->tm_isdst))
606 Julian -= DST_OFFSET * 60 * 60;
612 DSTcorrect(time_t Start, time_t Future)
617 StartDay = (localtime(&Start)->tm_hour + 1) % 24;
618 FutureDay = (localtime(&Future)->tm_hour + 1) % 24;
619 return (Future - Start) + (StartDay - FutureDay) * DST_OFFSET * 60 * 60;
624 RelativeMonth(time_t Start, time_t RelMonth)
630 tm = localtime(&Start);
631 Month = 12 * tm->tm_year + tm->tm_mon + RelMonth;
634 Month = Month % 12 + 1;
635 return DSTcorrect(Start,
636 Convert(Month, (time_t)tm->tm_mday, Year,
637 (time_t)tm->tm_hour, (time_t)tm->tm_min, (time_t)tm->tm_sec,
642 static int LookupWord(char *buff, int length)
652 /* See if we have an abbreviation for a month. */
653 if (length == 3 || (length == 4 && p[3] == '.'))
654 for (tp = MonthDayTable; tp < ENDOF(MonthDayTable); tp++) {
656 if (c == q[0] && p[1] == q[1] && p[2] == q[2]) {
657 yylval.Number = tp->value;
662 for (tp = MonthDayTable; tp < ENDOF(MonthDayTable); tp++)
663 if (c == tp->name[0] && strcmp(p, tp->name) == 0) {
664 yylval.Number = tp->value;
668 /* Try for a timezone. */
669 for (tp = TimezoneTable; tp < ENDOF(TimezoneTable); tp++)
670 if (c == tp->name[0] && p[1] == tp->name[1]
671 && strcmp(p, tp->name) == 0) {
672 yylval.Number = tp->value;
676 /* Try the units table. */
677 for (tp = UnitsTable; tp < ENDOF(UnitsTable); tp++)
678 if (c == tp->name[0] && strcmp(p, tp->name) == 0) {
679 yylval.Number = tp->value;
683 /* Strip off any plural and try the units table again. */
684 if (--length > 0 && p[length] == 's') {
686 for (tp = UnitsTable; tp < ENDOF(UnitsTable); tp++)
687 if (c == tp->name[0] && strcmp(p, tp->name) == 0) {
689 yylval.Number = tp->value;
696 /* Drop out any periods. */
697 for (p = buff, q = (STRING)buff; *q; q++)
702 /* Try the meridians. */
703 if (buff[1] == 'm' && buff[2] == '\0') {
704 if (buff[0] == 'a') {
705 yylval.Meridian = MERam;
708 if (buff[0] == 'p') {
709 yylval.Meridian = MERpm;
714 /* If we saw any periods, try the timezones again. */
715 if (p - buff != length) {
717 for (p = buff, tp = TimezoneTable; tp < ENDOF(TimezoneTable); tp++)
718 if (c == tp->name[0] && p[1] == tp->name[1]
719 && strcmp(p, tp->name) == 0) {
720 yylval.Number = tp->value;
725 /* Unknown word -- assume GMT timezone. */
731 static int date_lex(void)
741 /* Get first character after the whitespace. */
743 while (CTYPE(isspace, (int)*yyInput))
747 /* Ignore RFC 822 comments, typically time zone names. */
750 for (nesting = 1; (c = *++yyInput) != RPAREN || --nesting; )
753 else if (!IS7BIT(c) || c == '\0' || c == '\r'
754 || (c == '\\' && ((c = *++yyInput) == '\0' || !IS7BIT(c))))
755 /* Lexical error: bad comment. */
761 if (CTYPE(isdigit, (int)c) || c == '-' || c == '+') {
762 if (c == '-' || c == '+') {
763 sign = c == '-' ? -1 : 1;
765 if (!CTYPE(isdigit, (int)*yyInput))
766 /* Skip the plus or minus sign. */
771 for (i = 0; (c = *yyInput++) != '\0' && CTYPE(isdigit, (int)c); )
772 i = 10 * i + c - '0';
774 yylval.Number = sign < 0 ? -i : i;
775 return sign ? tSNUMBER : tUNUMBER;
779 if (CTYPE(isalpha, (int)c)) {
780 for (p = buff; (c = *yyInput++) == '.' || CTYPE(isalpha, (int)c); )
781 if (p < &buff[sizeof buff - 1])
782 *p++ = CTYPE(isupper, (int)c) ? tolower(c) : c;
785 return LookupWord(buff, p - buff);
793 time_t parsedate(char *p, TIMEINFO *now)
802 (void)GetTimeInfo(&ti);
805 tm = localtime(&now->time);
806 yyYear = tm->tm_year + 1900;
807 yyMonth = tm->tm_mon + 1;
809 yyTimezone = now->timezone;
810 yyDSTmode = DSTmaybe;
821 if (date_parse() || yyHaveTime > 1 || yyHaveDate > 1)
824 if (yyHaveDate || yyHaveTime) {
825 Start = Convert(yyMonth, yyDay, yyYear, yyHour, yyMinutes, yySeconds,
826 yyMeridian, yyDSTmode);
833 Start -= (tm->tm_hour * 60L + tm->tm_min) * 60L + tm->tm_sec;
836 Start += yyRelSeconds;
838 Start += RelativeMonth(Start, yyRelMonth);
840 /* Have to do *something* with a legitimate -1 so it's distinguishable
841 * from the error return value. (Alternately could set errno on error.) */
842 return Start == -1 ? 0 : Start;
865 (void)printf("Enter date, or blank line to exit.\n\t> ");
867 (void)printf("\t> ");
868 (void)fflush(stdout);
869 if (gets(buff) == NULL || buff[0] == '\n')
872 if (strcmp(buff, "yydebug") == 0) {
874 printf("yydebug = %s\n", yydebug ? "on" : "off");
878 d = parsedate(buff, (TIMEINFO *)NULL);
880 (void)printf("Bad format - couldn't convert.\n");
882 (void)printf("%s", ctime(&d));
888 #endif /* defined(TEST) */