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.
8 ** This grammar has 13 shift/reduce conflicts.
10 ** This code is in the public domain and has no copyright.
15 # ifdef FORCE_ALLOCA_H
20 /* Since the code of getdate.y is not included in the Emacs executable
21 itself, there is no need to #define static in this file. Even if
22 the code were included in the Emacs executable, it probably
23 wouldn't do any harm to #undef it here; this will only cause
24 problems if we try to write to a static variable, which I don't
25 think this code needs to do. */
33 #if defined (STDC_HEADERS) || (!defined (isascii) && !defined (HAVE_ISASCII))
34 # define IN_CTYPE_DOMAIN(c) 1
36 # define IN_CTYPE_DOMAIN(c) isascii(c)
39 #define ISSPACE(c) (IN_CTYPE_DOMAIN (c) && isspace (c))
40 #define ISALPHA(c) (IN_CTYPE_DOMAIN (c) && isalpha (c))
41 #define ISUPPER(c) (IN_CTYPE_DOMAIN (c) && isupper (c))
42 #define ISDIGIT_LOCALE(c) (IN_CTYPE_DOMAIN (c) && isdigit (c))
44 /* ISDIGIT differs from ISDIGIT_LOCALE, as follows:
45 - Its arg may be any int or unsigned int; it need not be an unsigned char.
46 - It's guaranteed to evaluate its argument exactly once.
47 - It's typically faster.
48 Posix 1003.2-1992 section 2.5.2.1 page 50 lines 1556-1558 says that
49 only '0' through '9' are digits. Prefer ISDIGIT to ISDIGIT_LOCALE unless
50 it's important to use the locale's definition of `digit' even when the
51 host does not conform to Posix. */
52 #define ISDIGIT(c) ((unsigned) (c) - '0' <= 9)
56 #if defined (STDC_HEADERS) || defined (USG)
60 /* Some old versions of bison generate parsers that use bcopy.
61 That loses on systems that don't provide the function, so we have
62 to redefine it here. */
63 #if !defined (HAVE_BCOPY) && defined (HAVE_MEMCPY) && !defined (bcopy)
64 # define bcopy(from, to, len) memcpy ((to), (from), (len))
67 extern
struct tm
*gmtime
();
68 extern
struct tm
*localtime
();
69 extern
time_t mktime
();
71 /* Remap normal yacc parser interface names (yyparse, yylex, yyerror, etc),
72 as well as gratuitiously global symbol names, so we can have multiple
73 yacc generated parsers in the same program. Note that these are only
74 the variables produced by yacc. If other parser generators (bison,
75 byacc, etc) produce additional global names that conflict at link time,
76 then those parser generators need to be fixed instead of adding those
77 names to this list. */
79 #define yymaxdepth gd_maxdepth
80 #define yyparse gd_parse
82 #define yyerror gd_error
83 #define yylval gd_lval
84 #define yychar gd_char
85 #define yydebug gd_debug
86 #define yypact gd_pact
93 #define yyexca gd_exca
94 #define yyerrflag gd_errflag
95 #define yynerrs gd_nerrs
100 #define yystate gd_state
103 #define yy_yyv gd_yyv
105 #define yylloc gd_lloc
106 #define yyreds gd_reds /* With YYDEBUG defined */
107 #define yytoks gd_toks /* With YYDEBUG defined */
108 #define yylhs gd_yylhs
109 #define yylen gd_yylen
110 #define yydefred gd_yydefred
111 #define yydgoto gd_yydgoto
112 #define yysindex gd_yysindex
113 #define yyrindex gd_yyrindex
114 #define yygindex gd_yygindex
115 #define yytable gd_yytable
116 #define yycheck gd_yycheck
119 static int yyerror ();
122 #define HOUR(x) ((x) * 60)
124 #define MAX_BUFF_LEN 128 /* size of buffer to read the date into */
127 ** An entry in the lexical lookup table.
129 typedef
struct _TABLE
{
137 ** Meridian: am, pm, or 24-hour style.
139 typedef
enum _MERIDIAN
{
145 ** Global variables. We could get rid of most of these by using a good
146 ** union as the yacc stack. (This routine was originally written before
147 ** yacc had the %union construct.) Maybe someday; right now we only use
148 ** the %union very rarely.
150 static const char *yyInput
;
151 static int yyDayOrdinal
;
152 static int yyDayNumber
;
153 static int yyHaveDate
;
154 static int yyHaveDay
;
155 static int yyHaveRel
;
156 static int yyHaveTime
;
157 static int yyHaveZone
;
158 static int yyTimezone
;
161 static int yyMinutes
;
163 static int yySeconds
;
165 static MERIDIAN yyMeridian
;
167 static int yyRelHour
;
168 static int yyRelMinutes
;
169 static int yyRelMonth
;
170 static int yyRelSeconds
;
171 static int yyRelYear
;
177 enum _MERIDIAN Meridian
;
180 %token tAGO tDAY tDAY_UNIT tDAYZONE tDST tHOUR_UNIT tID
181 %token tMERIDIAN tMINUTE_UNIT tMONTH tMONTH_UNIT
182 %token tSEC_UNIT tSNUMBER tUNUMBER tYEAR_UNIT tZONE
184 %type
<Number
> tDAY tDAY_UNIT tDAYZONE tHOUR_UNIT tMINUTE_UNIT
185 %type
<Number
> tMONTH tMONTH_UNIT
186 %type
<Number
> tSEC_UNIT tSNUMBER tUNUMBER tYEAR_UNIT tZONE
187 %type
<Meridian
> tMERIDIAN o_merid
213 time
: tUNUMBER tMERIDIAN
{
219 | tUNUMBER
':' tUNUMBER o_merid
{
225 | tUNUMBER
':' tUNUMBER tSNUMBER
{
231 ?
-$4 %
100 + (-$4 / 100) * 60
232 : - ($4 %
100 + ($4 / 100) * 60));
234 | tUNUMBER
':' tUNUMBER
':' tUNUMBER o_merid
{
240 | tUNUMBER
':' tUNUMBER
':' tUNUMBER tSNUMBER
{
247 ?
-$6 %
100 + (-$6 / 100) * 60
248 : - ($6 %
100 + ($6 / 100) * 60));
256 yyTimezone
= $1 - 60;
260 yyTimezone
= $1 - 60;
278 date
: tUNUMBER
'/' tUNUMBER
{
282 | tUNUMBER
'/' tUNUMBER
'/' tUNUMBER
{
283 /* Interpret as YYYY/MM/DD if $1 >= 1000, otherwise as MM/DD/YY.
284 The goal in recognizing YYYY/MM/DD is solely to support legacy
285 machine-generated dates like those in an RCS log listing. If
286 you want portability, use the ISO 8601 format. */
300 | tUNUMBER tSNUMBER tSNUMBER
{
301 /* ISO 8601 format. yyyy-mm-dd. */
306 | tUNUMBER tMONTH tSNUMBER
{
307 /* e.g. 17-JUN-1992. */
316 | tMONTH tUNUMBER
',' tUNUMBER
{
325 | tUNUMBER tMONTH tUNUMBER
{
333 yyRelSeconds
= -yyRelSeconds
;
334 yyRelMinutes
= -yyRelMinutes
;
335 yyRelHour
= -yyRelHour
;
336 yyRelDay
= -yyRelDay
;
337 yyRelMonth
= -yyRelMonth
;
338 yyRelYear
= -yyRelYear
;
343 relunit
: tUNUMBER tYEAR_UNIT
{
344 yyRelYear
+= $1 * $2;
346 | tSNUMBER tYEAR_UNIT
{
347 yyRelYear
+= $1 * $2;
352 | tUNUMBER tMONTH_UNIT
{
353 yyRelMonth
+= $1 * $2;
355 | tSNUMBER tMONTH_UNIT
{
356 yyRelMonth
+= $1 * $2;
361 | tUNUMBER tDAY_UNIT
{
364 | tSNUMBER tDAY_UNIT
{
370 | tUNUMBER tHOUR_UNIT
{
371 yyRelHour
+= $1 * $2;
373 | tSNUMBER tHOUR_UNIT
{
374 yyRelHour
+= $1 * $2;
379 | tUNUMBER tMINUTE_UNIT
{
380 yyRelMinutes
+= $1 * $2;
382 | tSNUMBER tMINUTE_UNIT
{
383 yyRelMinutes
+= $1 * $2;
388 | tUNUMBER tSEC_UNIT
{
389 yyRelSeconds
+= $1 * $2;
391 | tSNUMBER tSEC_UNIT
{
392 yyRelSeconds
+= $1 * $2;
401 if
(yyHaveTime
&& yyHaveDate
&& !yyHaveRel
)
409 yyMonth
= ($1/100)%
100;
423 yyMinutes
= $1 %
100;
444 /* Month and day table. */
445 static TABLE
const MonthDayTable
[] = {
446 { "january", tMONTH
, 1 },
447 { "february", tMONTH
, 2 },
448 { "march", tMONTH
, 3 },
449 { "april", tMONTH
, 4 },
450 { "may", tMONTH
, 5 },
451 { "june", tMONTH
, 6 },
452 { "july", tMONTH
, 7 },
453 { "august", tMONTH
, 8 },
454 { "september", tMONTH
, 9 },
455 { "sept", tMONTH
, 9 },
456 { "october", tMONTH
, 10 },
457 { "november", tMONTH
, 11 },
458 { "december", tMONTH
, 12 },
459 { "sunday", tDAY
, 0 },
460 { "monday", tDAY
, 1 },
461 { "tuesday", tDAY
, 2 },
463 { "wednesday", tDAY
, 3 },
464 { "wednes", tDAY
, 3 },
465 { "thursday", tDAY
, 4 },
467 { "thurs", tDAY
, 4 },
468 { "friday", tDAY
, 5 },
469 { "saturday", tDAY
, 6 },
473 /* Time units table. */
474 static TABLE
const UnitsTable
[] = {
475 { "year", tYEAR_UNIT
, 1 },
476 { "month", tMONTH_UNIT
, 1 },
477 { "fortnight", tDAY_UNIT
, 14 },
478 { "week", tDAY_UNIT
, 7 },
479 { "day", tDAY_UNIT
, 1 },
480 { "hour", tHOUR_UNIT
, 1 },
481 { "minute", tMINUTE_UNIT
, 1 },
482 { "min", tMINUTE_UNIT
, 1 },
483 { "second", tSEC_UNIT
, 1 },
484 { "sec", tSEC_UNIT
, 1 },
488 /* Assorted relative-time words. */
489 static TABLE
const OtherTable
[] = {
490 { "tomorrow", tMINUTE_UNIT
, 1 * 24 * 60 },
491 { "yesterday", tMINUTE_UNIT
, -1 * 24 * 60 },
492 { "today", tMINUTE_UNIT
, 0 },
493 { "now", tMINUTE_UNIT
, 0 },
494 { "last", tUNUMBER
, -1 },
495 { "this", tMINUTE_UNIT
, 0 },
496 { "next", tUNUMBER
, 1 },
497 { "first", tUNUMBER
, 1 },
498 /* { "second", tUNUMBER, 2 }, */
499 { "third", tUNUMBER
, 3 },
500 { "fourth", tUNUMBER
, 4 },
501 { "fifth", tUNUMBER
, 5 },
502 { "sixth", tUNUMBER
, 6 },
503 { "seventh", tUNUMBER
, 7 },
504 { "eighth", tUNUMBER
, 8 },
505 { "ninth", tUNUMBER
, 9 },
506 { "tenth", tUNUMBER
, 10 },
507 { "eleventh", tUNUMBER
, 11 },
508 { "twelfth", tUNUMBER
, 12 },
513 /* The timezone table. */
514 static TABLE
const TimezoneTable
[] = {
515 { "gmt", tZONE
, HOUR
( 0) }, /* Greenwich Mean */
516 { "ut", tZONE
, HOUR
( 0) }, /* Universal (Coordinated) */
517 { "utc", tZONE
, HOUR
( 0) },
518 { "wet", tZONE
, HOUR
( 0) }, /* Western European */
519 { "bst", tDAYZONE
, HOUR
( 0) }, /* British Summer */
520 { "wat", tZONE
, HOUR
( 1) }, /* West Africa */
521 { "at", tZONE
, HOUR
( 2) }, /* Azores */
523 /* For completeness. BST is also British Summer, and GST is
524 * also Guam Standard. */
525 { "bst", tZONE
, HOUR
( 3) }, /* Brazil Standard */
526 { "gst", tZONE
, HOUR
( 3) }, /* Greenland Standard */
529 { "nft", tZONE
, HOUR
(3.5) }, /* Newfoundland */
530 { "nst", tZONE
, HOUR
(3.5) }, /* Newfoundland Standard */
531 { "ndt", tDAYZONE
, HOUR
(3.5) }, /* Newfoundland Daylight */
533 { "ast", tZONE
, HOUR
( 4) }, /* Atlantic Standard */
534 { "adt", tDAYZONE
, HOUR
( 4) }, /* Atlantic Daylight */
535 { "est", tZONE
, HOUR
( 5) }, /* Eastern Standard */
536 { "edt", tDAYZONE
, HOUR
( 5) }, /* Eastern Daylight */
537 { "cst", tZONE
, HOUR
( 6) }, /* Central Standard */
538 { "cdt", tDAYZONE
, HOUR
( 6) }, /* Central Daylight */
539 { "mst", tZONE
, HOUR
( 7) }, /* Mountain Standard */
540 { "mdt", tDAYZONE
, HOUR
( 7) }, /* Mountain Daylight */
541 { "pst", tZONE
, HOUR
( 8) }, /* Pacific Standard */
542 { "pdt", tDAYZONE
, HOUR
( 8) }, /* Pacific Daylight */
543 { "yst", tZONE
, HOUR
( 9) }, /* Yukon Standard */
544 { "ydt", tDAYZONE
, HOUR
( 9) }, /* Yukon Daylight */
545 { "hst", tZONE
, HOUR
(10) }, /* Hawaii Standard */
546 { "hdt", tDAYZONE
, HOUR
(10) }, /* Hawaii Daylight */
547 { "cat", tZONE
, HOUR
(10) }, /* Central Alaska */
548 { "ahst", tZONE
, HOUR
(10) }, /* Alaska-Hawaii Standard */
549 { "nt", tZONE
, HOUR
(11) }, /* Nome */
550 { "idlw", tZONE
, HOUR
(12) }, /* International Date Line West */
551 { "cet", tZONE
, -HOUR
(1) }, /* Central European */
552 { "met", tZONE
, -HOUR
(1) }, /* Middle European */
553 { "mewt", tZONE
, -HOUR
(1) }, /* Middle European Winter */
554 { "mest", tDAYZONE
, -HOUR
(1) }, /* Middle European Summer */
555 { "mesz", tDAYZONE
, -HOUR
(1) }, /* Middle European Summer */
556 { "swt", tZONE
, -HOUR
(1) }, /* Swedish Winter */
557 { "sst", tDAYZONE
, -HOUR
(1) }, /* Swedish Summer */
558 { "fwt", tZONE
, -HOUR
(1) }, /* French Winter */
559 { "fst", tDAYZONE
, -HOUR
(1) }, /* French Summer */
560 { "eet", tZONE
, -HOUR
(2) }, /* Eastern Europe, USSR Zone 1 */
561 { "bt", tZONE
, -HOUR
(3) }, /* Baghdad, USSR Zone 2 */
563 { "it", tZONE
, -HOUR
(3.5) },/* Iran */
565 { "zp4", tZONE
, -HOUR
(4) }, /* USSR Zone 3 */
566 { "zp5", tZONE
, -HOUR
(5) }, /* USSR Zone 4 */
568 { "ist", tZONE
, -HOUR
(5.5) },/* Indian Standard */
570 { "zp6", tZONE
, -HOUR
(6) }, /* USSR Zone 5 */
572 /* For completeness. NST is also Newfoundland Standard, and SST is
573 * also Swedish Summer. */
574 { "nst", tZONE
, -HOUR
(6.5) },/* North Sumatra */
575 { "sst", tZONE
, -HOUR
(7) }, /* South Sumatra, USSR Zone 6 */
577 { "wast", tZONE
, -HOUR
(7) }, /* West Australian Standard */
578 { "wadt", tDAYZONE
, -HOUR
(7) }, /* West Australian Daylight */
580 { "jt", tZONE
, -HOUR
(7.5) },/* Java (3pm in Cronusland!) */
582 { "cct", tZONE
, -HOUR
(8) }, /* China Coast, USSR Zone 7 */
583 { "jst", tZONE
, -HOUR
(9) }, /* Japan Standard, USSR Zone 8 */
585 { "cast", tZONE
, -HOUR
(9.5) },/* Central Australian Standard */
586 { "cadt", tDAYZONE
, -HOUR
(9.5) },/* Central Australian Daylight */
588 { "east", tZONE
, -HOUR
(10) }, /* Eastern Australian Standard */
589 { "eadt", tDAYZONE
, -HOUR
(10) }, /* Eastern Australian Daylight */
590 { "gst", tZONE
, -HOUR
(10) }, /* Guam Standard, USSR Zone 9 */
591 { "nzt", tZONE
, -HOUR
(12) }, /* New Zealand */
592 { "nzst", tZONE
, -HOUR
(12) }, /* New Zealand Standard */
593 { "nzdt", tDAYZONE
, -HOUR
(12) }, /* New Zealand Daylight */
594 { "idle", tZONE
, -HOUR
(12) }, /* International Date Line East */
598 /* Military timezone table. */
599 static TABLE
const MilitaryTable
[] = {
600 { "a", tZONE
, HOUR
( 1) },
601 { "b", tZONE
, HOUR
( 2) },
602 { "c", tZONE
, HOUR
( 3) },
603 { "d", tZONE
, HOUR
( 4) },
604 { "e", tZONE
, HOUR
( 5) },
605 { "f", tZONE
, HOUR
( 6) },
606 { "g", tZONE
, HOUR
( 7) },
607 { "h", tZONE
, HOUR
( 8) },
608 { "i", tZONE
, HOUR
( 9) },
609 { "k", tZONE
, HOUR
( 10) },
610 { "l", tZONE
, HOUR
( 11) },
611 { "m", tZONE
, HOUR
( 12) },
612 { "n", tZONE
, HOUR
(- 1) },
613 { "o", tZONE
, HOUR
(- 2) },
614 { "p", tZONE
, HOUR
(- 3) },
615 { "q", tZONE
, HOUR
(- 4) },
616 { "r", tZONE
, HOUR
(- 5) },
617 { "s", tZONE
, HOUR
(- 6) },
618 { "t", tZONE
, HOUR
(- 7) },
619 { "u", tZONE
, HOUR
(- 8) },
620 { "v", tZONE
, HOUR
(- 9) },
621 { "w", tZONE
, HOUR
(-10) },
622 { "x", tZONE
, HOUR
(-11) },
623 { "y", tZONE
, HOUR
(-12) },
624 { "z", tZONE
, HOUR
( 0) },
640 ToHour
(Hours
, Meridian
)
647 if
(Hours
< 0 || Hours
> 23)
651 if
(Hours
< 1 || Hours
> 12)
657 if
(Hours
< 1 || Hours
> 12)
675 /* XPG4 suggests that years 00-68 map to 2000-2068, and
676 years 69-99 map to 1969-1999. */
691 register
const TABLE
*tp
;
695 /* Make it lowercase. */
696 for
(p
= buff
; *p
; p
++)
700 if
(strcmp
(buff
, "am") == 0 || strcmp
(buff
, "a.m.") == 0)
702 yylval.Meridian
= MERam
;
705 if
(strcmp
(buff
, "pm") == 0 || strcmp
(buff
, "p.m.") == 0)
707 yylval.Meridian
= MERpm
;
711 /* See if we have an abbreviation for a month. */
712 if
(strlen
(buff
) == 3)
714 else if
(strlen
(buff
) == 4 && buff
[3] == '.')
722 for
(tp
= MonthDayTable
; tp
->name
; tp
++)
726 if
(strncmp
(buff
, tp
->name
, 3) == 0)
728 yylval.Number
= tp
->value
;
732 else if
(strcmp
(buff
, tp
->name
) == 0)
734 yylval.Number
= tp
->value
;
739 for
(tp
= TimezoneTable
; tp
->name
; tp
++)
740 if
(strcmp
(buff
, tp
->name
) == 0)
742 yylval.Number
= tp
->value
;
746 if
(strcmp
(buff
, "dst") == 0)
749 for
(tp
= UnitsTable
; tp
->name
; tp
++)
750 if
(strcmp
(buff
, tp
->name
) == 0)
752 yylval.Number
= tp
->value
;
756 /* Strip off any plural and try the units table again. */
757 i
= strlen
(buff
) - 1;
761 for
(tp
= UnitsTable
; tp
->name
; tp
++)
762 if
(strcmp
(buff
, tp
->name
) == 0)
764 yylval.Number
= tp
->value
;
767 buff
[i
] = 's'; /* Put back for "this" in OtherTable. */
770 for
(tp
= OtherTable
; tp
->name
; tp
++)
771 if
(strcmp
(buff
, tp
->name
) == 0)
773 yylval.Number
= tp
->value
;
777 /* Military timezones. */
778 if
(buff
[1] == '\0' && ISALPHA
(*buff
))
780 for
(tp
= MilitaryTable
; tp
->name
; tp
++)
781 if
(strcmp
(buff
, tp
->name
) == 0)
783 yylval.Number
= tp
->value
;
788 /* Drop out any periods and try the timezone table again. */
789 for
(i
= 0, p
= q
= buff
; *q
; q
++)
796 for
(tp
= TimezoneTable
; tp
->name
; tp
++)
797 if
(strcmp
(buff
, tp
->name
) == 0)
799 yylval.Number
= tp
->value
;
817 while
(ISSPACE
(*yyInput
))
820 if
(ISDIGIT
(c
= *yyInput
) || c
== '-' || c
== '+')
822 if
(c
== '-' || c
== '+')
824 sign
= c
== '-' ?
-1 : 1;
825 if
(!ISDIGIT
(*++yyInput
))
826 /* skip the '-' sign */
831 for
(yylval.Number
= 0; ISDIGIT
(c
= *yyInput
++);)
832 yylval.Number
= 10 * yylval.Number
+ c
- '0';
835 yylval.Number
= -yylval.Number
;
836 return sign ? tSNUMBER
: tUNUMBER
;
840 for
(p
= buff
; (c
= *yyInput
++, ISALPHA
(c
)) || c
== '.';)
841 if
(p
< &buff
[sizeof buff
- 1])
845 return LookupWord
(buff
);
864 #define TM_YEAR_ORIGIN 1900
866 /* Yield A - B, measured in seconds. */
871 int ay
= a
->tm_year
+ (TM_YEAR_ORIGIN
- 1);
872 int by
= b
->tm_year
+ (TM_YEAR_ORIGIN
- 1);
874 /* difference in day of year */
875 a
->tm_yday
- b
->tm_yday
876 /* + intervening leap days */
877 + ((ay
>> 2) - (by
>> 2))
878 - (ay
/ 100 - by
/ 100)
879 + ((ay
/ 100 >> 2) - (by
/ 100 >> 2))
880 /* + difference in years * 365 */
881 + (long) (ay
- by
) * 365
883 return
(60 * (60 * (24 * days
+ (a
->tm_hour
- b
->tm_hour
))
884 + (a
->tm_min
- b
->tm_min
))
885 + (a
->tm_sec
- b
->tm_sec
));
893 struct tm tm
, tm0
, *tmp
;
897 Start
= now ?
*now
: time
((time_t *) NULL
);
898 tmp
= localtime
(&Start
);
899 yyYear
= tmp
->tm_year
+ TM_YEAR_ORIGIN
;
900 yyMonth
= tmp
->tm_mon
+ 1;
901 yyDay
= tmp
->tm_mday
;
902 yyHour
= tmp
->tm_hour
;
903 yyMinutes
= tmp
->tm_min
;
904 yySeconds
= tmp
->tm_sec
;
919 || yyHaveTime
> 1 || yyHaveZone
> 1 || yyHaveDate
> 1 || yyHaveDay
> 1)
922 tm.tm_year
= ToYear
(yyYear
) - TM_YEAR_ORIGIN
+ yyRelYear
;
923 tm.tm_mon
= yyMonth
- 1 + yyRelMonth
;
924 tm.tm_mday
= yyDay
+ yyRelDay
;
925 if
(yyHaveTime ||
(yyHaveRel
&& !yyHaveDate
&& !yyHaveDay
))
927 tm.tm_hour
= ToHour
(yyHour
, yyMeridian
);
930 tm.tm_min
= yyMinutes
;
931 tm.tm_sec
= yySeconds
;
935 tm.tm_hour
= tm.tm_min
= tm.tm_sec
= 0;
937 tm.tm_hour
+= yyRelHour
;
938 tm.tm_min
+= yyRelMinutes
;
939 tm.tm_sec
+= yyRelSeconds
;
943 Start
= mktime
(&tm
);
945 if
(Start
== (time_t) -1)
948 /* Guard against falsely reporting errors near the time_t boundaries
949 when parsing times in other time zones. For example, if the min
950 time_t value is 1970-01-01 00:00:00 UTC and we are 8 hours ahead
951 of UTC, then the min localtime value is 1970-01-01 08:00:00; if
952 we apply mktime to 1970-01-01 00:00:00 we will get an error, so
953 we apply mktime to 1970-01-02 08:00:00 instead and adjust the time
954 zone by 24 hours to compensate. This algorithm assumes that
955 there is no DST transition within a day of the time_t boundaries. */
959 if
(tm.tm_year
<= EPOCH
- TM_YEAR_ORIGIN
)
962 yyTimezone
-= 24 * 60;
967 yyTimezone
+= 24 * 60;
969 Start
= mktime
(&tm
);
972 if
(Start
== (time_t) -1)
976 if
(yyHaveDay
&& !yyHaveDate
)
978 tm.tm_mday
+= ((yyDayNumber
- tm.tm_wday
+ 7) %
7
979 + 7 * (yyDayOrdinal
- (0 < yyDayOrdinal
)));
980 Start
= mktime
(&tm
);
981 if
(Start
== (time_t) -1)
987 long delta
= yyTimezone
* 60L + difftm
(&tm
, gmtime
(&Start
));
988 if
((Start
+ delta
< Start
) != (delta
< 0))
989 return
-1; /* time_t overflow */
1004 char buff
[MAX_BUFF_LEN
+ 1];
1007 (void) printf
("Enter date, or blank line to exit.\n\t> ");
1008 (void) fflush
(stdout
);
1010 buff
[MAX_BUFF_LEN
] = 0;
1011 while
(fgets
(buff
, MAX_BUFF_LEN
, stdin
) && buff
[0])
1013 d
= get_date
(buff
, (time_t *) NULL
);
1015 (void) printf
("Bad format - couldn't convert.\n");
1017 (void) printf
("%s", ctime
(&d
));
1018 (void) printf
("\t> ");
1019 (void) fflush
(stdout
);
1024 #endif /* defined (TEST) */