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 code is in the public domain and has no copyright.
13 # ifdef FORCE_ALLOCA_H
18 /* Since the code of getdate.y is not included in the Emacs executable
19 itself, there is no need to #define static in this file. Even if
20 the code were included in the Emacs executable, it probably
21 wouldn't do any harm to #undef it here; this will only cause
22 problems if we try to write to a static variable, which I don't
23 think this code needs to do. */
31 #if defined (STDC_HEADERS) || (!defined (isascii) && !defined (HAVE_ISASCII))
32 # define IN_CTYPE_DOMAIN(c) 1
34 # define IN_CTYPE_DOMAIN(c) isascii(c)
37 #define ISSPACE(c) (IN_CTYPE_DOMAIN (c) && isspace (c))
38 #define ISALPHA(c) (IN_CTYPE_DOMAIN (c) && isalpha (c))
39 #define ISUPPER(c) (IN_CTYPE_DOMAIN (c) && isupper (c))
40 #define ISDIGIT_LOCALE(c) (IN_CTYPE_DOMAIN (c) && isdigit (c))
42 /* ISDIGIT differs from ISDIGIT_LOCALE, as follows:
43 - Its arg may be any int or unsigned int; it need not be an unsigned char.
44 - It's guaranteed to evaluate its argument exactly once.
45 - It's typically faster.
46 Posix 1003.2-1992 section 2.5.2.1 page 50 lines 1556-1558 says that
47 only '0' through '9' are digits. Prefer ISDIGIT to ISDIGIT_LOCALE unless
48 it's important to use the locale's definition of `digit' even when the
49 host does not conform to Posix. */
50 #define ISDIGIT(c) ((unsigned) (c) - '0' <= 9)
52 #if defined (STDC_HEADERS) || defined (USG)
56 /* Some old versions of bison generate parsers that use bcopy.
57 That loses on systems that don't provide the function, so we have
58 to redefine it here. */
59 #if !defined (HAVE_BCOPY) && defined (HAVE_MEMCPY) && !defined (bcopy)
60 # define bcopy(from, to, len) memcpy ((to), (from), (len))
63 /* Remap normal yacc parser interface names (yyparse, yylex, yyerror, etc),
64 as well as gratuitiously global symbol names, so we can have multiple
65 yacc generated parsers in the same program. Note that these are only
66 the variables produced by yacc. If other parser generators (bison,
67 byacc, etc) produce additional global names that conflict at link time,
68 then those parser generators need to be fixed instead of adding those
69 names to this list. */
71 #define yymaxdepth gd_maxdepth
72 #define yyparse gd_parse
74 #define yyerror gd_error
75 #define yylval gd_lval
76 #define yychar gd_char
77 #define yydebug gd_debug
78 #define yypact gd_pact
85 #define yyexca gd_exca
86 #define yyerrflag gd_errflag
87 #define yynerrs gd_nerrs
92 #define yystate gd_state
97 #define yylloc gd_lloc
98 #define yyreds gd_reds /* With YYDEBUG defined */
99 #define yytoks gd_toks /* With YYDEBUG defined */
100 #define yylhs gd_yylhs
101 #define yylen gd_yylen
102 #define yydefred gd_yydefred
103 #define yydgoto gd_yydgoto
104 #define yysindex gd_yysindex
105 #define yyrindex gd_yyrindex
106 #define yygindex gd_yygindex
107 #define yytable gd_yytable
108 #define yycheck gd_yycheck
111 static int yyerror ();
114 #define HOUR(x) ((x) * 60)
116 #define MAX_BUFF_LEN 128 /* size of buffer to read the date into */
119 ** An entry in the lexical lookup table.
121 typedef
struct _TABLE
{
129 ** Meridian: am, pm, or 24-hour style.
131 typedef
enum _MERIDIAN
{
137 ** Global variables. We could get rid of most of these by using a good
138 ** union as the yacc stack. (This routine was originally written before
139 ** yacc had the %union construct.) Maybe someday; right now we only use
140 ** the %union very rarely.
142 static const char *yyInput
;
143 static int yyDayOrdinal
;
144 static int yyDayNumber
;
145 static int yyHaveDate
;
146 static int yyHaveDay
;
147 static int yyHaveRel
;
148 static int yyHaveTime
;
149 static int yyHaveZone
;
150 static int yyTimezone
;
153 static int yyMinutes
;
155 static int yySeconds
;
157 static MERIDIAN yyMeridian
;
159 static int yyRelHour
;
160 static int yyRelMinutes
;
161 static int yyRelMonth
;
162 static int yyRelSeconds
;
163 static int yyRelYear
;
167 /* This grammar has 13 shift/reduce conflicts. */
172 enum _MERIDIAN Meridian
;
175 %token tAGO tDAY tDAY_UNIT tDAYZONE tDST tHOUR_UNIT tID
176 %token tMERIDIAN tMINUTE_UNIT tMONTH tMONTH_UNIT
177 %token tSEC_UNIT tSNUMBER tUNUMBER tYEAR_UNIT tZONE
179 %type
<Number
> tDAY tDAY_UNIT tDAYZONE tHOUR_UNIT tMINUTE_UNIT
180 %type
<Number
> tMONTH tMONTH_UNIT
181 %type
<Number
> tSEC_UNIT tSNUMBER tUNUMBER tYEAR_UNIT tZONE
182 %type
<Meridian
> tMERIDIAN o_merid
208 time
: tUNUMBER tMERIDIAN
{
214 | tUNUMBER
':' tUNUMBER o_merid
{
220 | tUNUMBER
':' tUNUMBER tSNUMBER
{
226 ?
-$4 %
100 + (-$4 / 100) * 60
227 : - ($4 %
100 + ($4 / 100) * 60));
229 | tUNUMBER
':' tUNUMBER
':' tUNUMBER o_merid
{
235 | tUNUMBER
':' tUNUMBER
':' tUNUMBER tSNUMBER
{
242 ?
-$6 %
100 + (-$6 / 100) * 60
243 : - ($6 %
100 + ($6 / 100) * 60));
251 yyTimezone
= $1 - 60;
255 yyTimezone
= $1 - 60;
273 date
: tUNUMBER
'/' tUNUMBER
{
277 | tUNUMBER
'/' tUNUMBER
'/' tUNUMBER
{
278 /* Interpret as YYYY/MM/DD if $1 >= 1000, otherwise as MM/DD/YY.
279 The goal in recognizing YYYY/MM/DD is solely to support legacy
280 machine-generated dates like those in an RCS log listing. If
281 you want portability, use the ISO 8601 format. */
295 | tUNUMBER tSNUMBER tSNUMBER
{
296 /* ISO 8601 format. yyyy-mm-dd. */
301 | tUNUMBER tMONTH tSNUMBER
{
302 /* e.g. 17-JUN-1992. */
311 | tMONTH tUNUMBER
',' tUNUMBER
{
320 | tUNUMBER tMONTH tUNUMBER
{
328 yyRelSeconds
= -yyRelSeconds
;
329 yyRelMinutes
= -yyRelMinutes
;
330 yyRelHour
= -yyRelHour
;
331 yyRelDay
= -yyRelDay
;
332 yyRelMonth
= -yyRelMonth
;
333 yyRelYear
= -yyRelYear
;
338 relunit
: tUNUMBER tYEAR_UNIT
{
339 yyRelYear
+= $1 * $2;
341 | tSNUMBER tYEAR_UNIT
{
342 yyRelYear
+= $1 * $2;
347 | tUNUMBER tMONTH_UNIT
{
348 yyRelMonth
+= $1 * $2;
350 | tSNUMBER tMONTH_UNIT
{
351 yyRelMonth
+= $1 * $2;
356 | tUNUMBER tDAY_UNIT
{
359 | tSNUMBER tDAY_UNIT
{
365 | tUNUMBER tHOUR_UNIT
{
366 yyRelHour
+= $1 * $2;
368 | tSNUMBER tHOUR_UNIT
{
369 yyRelHour
+= $1 * $2;
374 | tUNUMBER tMINUTE_UNIT
{
375 yyRelMinutes
+= $1 * $2;
377 | tSNUMBER tMINUTE_UNIT
{
378 yyRelMinutes
+= $1 * $2;
383 | tUNUMBER tSEC_UNIT
{
384 yyRelSeconds
+= $1 * $2;
386 | tSNUMBER tSEC_UNIT
{
387 yyRelSeconds
+= $1 * $2;
396 if
(yyHaveTime
&& yyHaveDate
&& !yyHaveRel
)
404 yyMonth
= ($1/100)%
100;
418 yyMinutes
= $1 %
100;
439 /* Include this file down here because bison inserts code above which
440 may define-away `const'. We want the prototype for get_date to have
441 the same signature as the function definition does. */
444 extern
struct tm
*gmtime
();
445 extern
struct tm
*localtime
();
446 extern
time_t mktime
();
448 /* Month and day table. */
449 static TABLE
const MonthDayTable
[] = {
450 { "january", tMONTH
, 1 },
451 { "february", tMONTH
, 2 },
452 { "march", tMONTH
, 3 },
453 { "april", tMONTH
, 4 },
454 { "may", tMONTH
, 5 },
455 { "june", tMONTH
, 6 },
456 { "july", tMONTH
, 7 },
457 { "august", tMONTH
, 8 },
458 { "september", tMONTH
, 9 },
459 { "sept", tMONTH
, 9 },
460 { "october", tMONTH
, 10 },
461 { "november", tMONTH
, 11 },
462 { "december", tMONTH
, 12 },
463 { "sunday", tDAY
, 0 },
464 { "monday", tDAY
, 1 },
465 { "tuesday", tDAY
, 2 },
467 { "wednesday", tDAY
, 3 },
468 { "wednes", tDAY
, 3 },
469 { "thursday", tDAY
, 4 },
471 { "thurs", tDAY
, 4 },
472 { "friday", tDAY
, 5 },
473 { "saturday", tDAY
, 6 },
477 /* Time units table. */
478 static TABLE
const UnitsTable
[] = {
479 { "year", tYEAR_UNIT
, 1 },
480 { "month", tMONTH_UNIT
, 1 },
481 { "fortnight", tDAY_UNIT
, 14 },
482 { "week", tDAY_UNIT
, 7 },
483 { "day", tDAY_UNIT
, 1 },
484 { "hour", tHOUR_UNIT
, 1 },
485 { "minute", tMINUTE_UNIT
, 1 },
486 { "min", tMINUTE_UNIT
, 1 },
487 { "second", tSEC_UNIT
, 1 },
488 { "sec", tSEC_UNIT
, 1 },
492 /* Assorted relative-time words. */
493 static TABLE
const OtherTable
[] = {
494 { "tomorrow", tMINUTE_UNIT
, 1 * 24 * 60 },
495 { "yesterday", tMINUTE_UNIT
, -1 * 24 * 60 },
496 { "today", tMINUTE_UNIT
, 0 },
497 { "now", tMINUTE_UNIT
, 0 },
498 { "last", tUNUMBER
, -1 },
499 { "this", tMINUTE_UNIT
, 0 },
500 { "next", tUNUMBER
, 1 },
501 { "first", tUNUMBER
, 1 },
502 /* { "second", tUNUMBER, 2 }, */
503 { "third", tUNUMBER
, 3 },
504 { "fourth", tUNUMBER
, 4 },
505 { "fifth", tUNUMBER
, 5 },
506 { "sixth", tUNUMBER
, 6 },
507 { "seventh", tUNUMBER
, 7 },
508 { "eighth", tUNUMBER
, 8 },
509 { "ninth", tUNUMBER
, 9 },
510 { "tenth", tUNUMBER
, 10 },
511 { "eleventh", tUNUMBER
, 11 },
512 { "twelfth", tUNUMBER
, 12 },
517 /* The timezone table. */
518 static TABLE
const TimezoneTable
[] = {
519 { "gmt", tZONE
, HOUR
( 0) }, /* Greenwich Mean */
520 { "ut", tZONE
, HOUR
( 0) }, /* Universal (Coordinated) */
521 { "utc", tZONE
, HOUR
( 0) },
522 { "wet", tZONE
, HOUR
( 0) }, /* Western European */
523 { "bst", tDAYZONE
, HOUR
( 0) }, /* British Summer */
524 { "wat", tZONE
, HOUR
( 1) }, /* West Africa */
525 { "at", tZONE
, HOUR
( 2) }, /* Azores */
527 /* For completeness. BST is also British Summer, and GST is
528 * also Guam Standard. */
529 { "bst", tZONE
, HOUR
( 3) }, /* Brazil Standard */
530 { "gst", tZONE
, HOUR
( 3) }, /* Greenland Standard */
533 { "nft", tZONE
, HOUR
(3.5) }, /* Newfoundland */
534 { "nst", tZONE
, HOUR
(3.5) }, /* Newfoundland Standard */
535 { "ndt", tDAYZONE
, HOUR
(3.5) }, /* Newfoundland Daylight */
537 { "ast", tZONE
, HOUR
( 4) }, /* Atlantic Standard */
538 { "adt", tDAYZONE
, HOUR
( 4) }, /* Atlantic Daylight */
539 { "est", tZONE
, HOUR
( 5) }, /* Eastern Standard */
540 { "edt", tDAYZONE
, HOUR
( 5) }, /* Eastern Daylight */
541 { "cst", tZONE
, HOUR
( 6) }, /* Central Standard */
542 { "cdt", tDAYZONE
, HOUR
( 6) }, /* Central Daylight */
543 { "mst", tZONE
, HOUR
( 7) }, /* Mountain Standard */
544 { "mdt", tDAYZONE
, HOUR
( 7) }, /* Mountain Daylight */
545 { "pst", tZONE
, HOUR
( 8) }, /* Pacific Standard */
546 { "pdt", tDAYZONE
, HOUR
( 8) }, /* Pacific Daylight */
547 { "yst", tZONE
, HOUR
( 9) }, /* Yukon Standard */
548 { "ydt", tDAYZONE
, HOUR
( 9) }, /* Yukon Daylight */
549 { "hst", tZONE
, HOUR
(10) }, /* Hawaii Standard */
550 { "hdt", tDAYZONE
, HOUR
(10) }, /* Hawaii Daylight */
551 { "cat", tZONE
, HOUR
(10) }, /* Central Alaska */
552 { "ahst", tZONE
, HOUR
(10) }, /* Alaska-Hawaii Standard */
553 { "nt", tZONE
, HOUR
(11) }, /* Nome */
554 { "idlw", tZONE
, HOUR
(12) }, /* International Date Line West */
555 { "cet", tZONE
, -HOUR
(1) }, /* Central European */
556 { "met", tZONE
, -HOUR
(1) }, /* Middle European */
557 { "mewt", tZONE
, -HOUR
(1) }, /* Middle European Winter */
558 { "mest", tDAYZONE
, -HOUR
(1) }, /* Middle European Summer */
559 { "mesz", tDAYZONE
, -HOUR
(1) }, /* Middle European Summer */
560 { "swt", tZONE
, -HOUR
(1) }, /* Swedish Winter */
561 { "sst", tDAYZONE
, -HOUR
(1) }, /* Swedish Summer */
562 { "fwt", tZONE
, -HOUR
(1) }, /* French Winter */
563 { "fst", tDAYZONE
, -HOUR
(1) }, /* French Summer */
564 { "eet", tZONE
, -HOUR
(2) }, /* Eastern Europe, USSR Zone 1 */
565 { "bt", tZONE
, -HOUR
(3) }, /* Baghdad, USSR Zone 2 */
567 { "it", tZONE
, -HOUR
(3.5) },/* Iran */
569 { "zp4", tZONE
, -HOUR
(4) }, /* USSR Zone 3 */
570 { "zp5", tZONE
, -HOUR
(5) }, /* USSR Zone 4 */
572 { "ist", tZONE
, -HOUR
(5.5) },/* Indian Standard */
574 { "zp6", tZONE
, -HOUR
(6) }, /* USSR Zone 5 */
576 /* For completeness. NST is also Newfoundland Standard, and SST is
577 * also Swedish Summer. */
578 { "nst", tZONE
, -HOUR
(6.5) },/* North Sumatra */
579 { "sst", tZONE
, -HOUR
(7) }, /* South Sumatra, USSR Zone 6 */
581 { "wast", tZONE
, -HOUR
(7) }, /* West Australian Standard */
582 { "wadt", tDAYZONE
, -HOUR
(7) }, /* West Australian Daylight */
584 { "jt", tZONE
, -HOUR
(7.5) },/* Java (3pm in Cronusland!) */
586 { "cct", tZONE
, -HOUR
(8) }, /* China Coast, USSR Zone 7 */
587 { "jst", tZONE
, -HOUR
(9) }, /* Japan Standard, USSR Zone 8 */
589 { "cast", tZONE
, -HOUR
(9.5) },/* Central Australian Standard */
590 { "cadt", tDAYZONE
, -HOUR
(9.5) },/* Central Australian Daylight */
592 { "east", tZONE
, -HOUR
(10) }, /* Eastern Australian Standard */
593 { "eadt", tDAYZONE
, -HOUR
(10) }, /* Eastern Australian Daylight */
594 { "gst", tZONE
, -HOUR
(10) }, /* Guam Standard, USSR Zone 9 */
595 { "nzt", tZONE
, -HOUR
(12) }, /* New Zealand */
596 { "nzst", tZONE
, -HOUR
(12) }, /* New Zealand Standard */
597 { "nzdt", tDAYZONE
, -HOUR
(12) }, /* New Zealand Daylight */
598 { "idle", tZONE
, -HOUR
(12) }, /* International Date Line East */
602 /* Military timezone table. */
603 static TABLE
const MilitaryTable
[] = {
604 { "a", tZONE
, HOUR
( 1) },
605 { "b", tZONE
, HOUR
( 2) },
606 { "c", tZONE
, HOUR
( 3) },
607 { "d", tZONE
, HOUR
( 4) },
608 { "e", tZONE
, HOUR
( 5) },
609 { "f", tZONE
, HOUR
( 6) },
610 { "g", tZONE
, HOUR
( 7) },
611 { "h", tZONE
, HOUR
( 8) },
612 { "i", tZONE
, HOUR
( 9) },
613 { "k", tZONE
, HOUR
( 10) },
614 { "l", tZONE
, HOUR
( 11) },
615 { "m", tZONE
, HOUR
( 12) },
616 { "n", tZONE
, HOUR
(- 1) },
617 { "o", tZONE
, HOUR
(- 2) },
618 { "p", tZONE
, HOUR
(- 3) },
619 { "q", tZONE
, HOUR
(- 4) },
620 { "r", tZONE
, HOUR
(- 5) },
621 { "s", tZONE
, HOUR
(- 6) },
622 { "t", tZONE
, HOUR
(- 7) },
623 { "u", tZONE
, HOUR
(- 8) },
624 { "v", tZONE
, HOUR
(- 9) },
625 { "w", tZONE
, HOUR
(-10) },
626 { "x", tZONE
, HOUR
(-11) },
627 { "y", tZONE
, HOUR
(-12) },
628 { "z", tZONE
, HOUR
( 0) },
644 ToHour
(Hours
, Meridian
)
651 if
(Hours
< 0 || Hours
> 23)
655 if
(Hours
< 1 || Hours
> 12)
661 if
(Hours
< 1 || Hours
> 12)
679 /* XPG4 suggests that years 00-68 map to 2000-2068, and
680 years 69-99 map to 1969-1999. */
695 register
const TABLE
*tp
;
699 /* Make it lowercase. */
700 for
(p
= buff
; *p
; p
++)
704 if
(strcmp
(buff
, "am") == 0 || strcmp
(buff
, "a.m.") == 0)
706 yylval.Meridian
= MERam
;
709 if
(strcmp
(buff
, "pm") == 0 || strcmp
(buff
, "p.m.") == 0)
711 yylval.Meridian
= MERpm
;
715 /* See if we have an abbreviation for a month. */
716 if
(strlen
(buff
) == 3)
718 else if
(strlen
(buff
) == 4 && buff
[3] == '.')
726 for
(tp
= MonthDayTable
; tp
->name
; tp
++)
730 if
(strncmp
(buff
, tp
->name
, 3) == 0)
732 yylval.Number
= tp
->value
;
736 else if
(strcmp
(buff
, tp
->name
) == 0)
738 yylval.Number
= tp
->value
;
743 for
(tp
= TimezoneTable
; tp
->name
; tp
++)
744 if
(strcmp
(buff
, tp
->name
) == 0)
746 yylval.Number
= tp
->value
;
750 if
(strcmp
(buff
, "dst") == 0)
753 for
(tp
= UnitsTable
; tp
->name
; tp
++)
754 if
(strcmp
(buff
, tp
->name
) == 0)
756 yylval.Number
= tp
->value
;
760 /* Strip off any plural and try the units table again. */
761 i
= strlen
(buff
) - 1;
765 for
(tp
= UnitsTable
; tp
->name
; tp
++)
766 if
(strcmp
(buff
, tp
->name
) == 0)
768 yylval.Number
= tp
->value
;
771 buff
[i
] = 's'; /* Put back for "this" in OtherTable. */
774 for
(tp
= OtherTable
; tp
->name
; tp
++)
775 if
(strcmp
(buff
, tp
->name
) == 0)
777 yylval.Number
= tp
->value
;
781 /* Military timezones. */
782 if
(buff
[1] == '\0' && ISALPHA
(*buff
))
784 for
(tp
= MilitaryTable
; tp
->name
; tp
++)
785 if
(strcmp
(buff
, tp
->name
) == 0)
787 yylval.Number
= tp
->value
;
792 /* Drop out any periods and try the timezone table again. */
793 for
(i
= 0, p
= q
= buff
; *q
; q
++)
800 for
(tp
= TimezoneTable
; tp
->name
; tp
++)
801 if
(strcmp
(buff
, tp
->name
) == 0)
803 yylval.Number
= tp
->value
;
821 while
(ISSPACE
(*yyInput
))
824 if
(ISDIGIT
(c
= *yyInput
) || c
== '-' || c
== '+')
826 if
(c
== '-' || c
== '+')
828 sign
= c
== '-' ?
-1 : 1;
829 if
(!ISDIGIT
(*++yyInput
))
830 /* skip the '-' sign */
835 for
(yylval.Number
= 0; ISDIGIT
(c
= *yyInput
++);)
836 yylval.Number
= 10 * yylval.Number
+ c
- '0';
839 yylval.Number
= -yylval.Number
;
840 return sign ? tSNUMBER
: tUNUMBER
;
844 for
(p
= buff
; (c
= *yyInput
++, ISALPHA
(c
)) || c
== '.';)
845 if
(p
< &buff
[sizeof buff
- 1])
849 return LookupWord
(buff
);
868 #define TM_YEAR_ORIGIN 1900
870 /* Yield A - B, measured in seconds. */
875 int ay
= a
->tm_year
+ (TM_YEAR_ORIGIN
- 1);
876 int by
= b
->tm_year
+ (TM_YEAR_ORIGIN
- 1);
878 /* difference in day of year */
879 a
->tm_yday
- b
->tm_yday
880 /* + intervening leap days */
881 + ((ay
>> 2) - (by
>> 2))
882 - (ay
/ 100 - by
/ 100)
883 + ((ay
/ 100 >> 2) - (by
/ 100 >> 2))
884 /* + difference in years * 365 */
885 + (long) (ay
- by
) * 365
887 return
(60 * (60 * (24 * days
+ (a
->tm_hour
- b
->tm_hour
))
888 + (a
->tm_min
- b
->tm_min
))
889 + (a
->tm_sec
- b
->tm_sec
));
893 get_date
(const char *p
, const time_t *now
)
895 struct tm tm
, tm0
, *tmp
;
899 Start
= now ?
*now
: time
((time_t *) NULL
);
900 tmp
= localtime
(&Start
);
901 yyYear
= tmp
->tm_year
+ TM_YEAR_ORIGIN
;
902 yyMonth
= tmp
->tm_mon
+ 1;
903 yyDay
= tmp
->tm_mday
;
904 yyHour
= tmp
->tm_hour
;
905 yyMinutes
= tmp
->tm_min
;
906 yySeconds
= tmp
->tm_sec
;
921 || yyHaveTime
> 1 || yyHaveZone
> 1 || yyHaveDate
> 1 || yyHaveDay
> 1)
924 tm.tm_year
= ToYear
(yyYear
) - TM_YEAR_ORIGIN
+ yyRelYear
;
925 tm.tm_mon
= yyMonth
- 1 + yyRelMonth
;
926 tm.tm_mday
= yyDay
+ yyRelDay
;
927 if
(yyHaveTime ||
(yyHaveRel
&& !yyHaveDate
&& !yyHaveDay
))
929 tm.tm_hour
= ToHour
(yyHour
, yyMeridian
);
932 tm.tm_min
= yyMinutes
;
933 tm.tm_sec
= yySeconds
;
937 tm.tm_hour
= tm.tm_min
= tm.tm_sec
= 0;
939 tm.tm_hour
+= yyRelHour
;
940 tm.tm_min
+= yyRelMinutes
;
941 tm.tm_sec
+= yyRelSeconds
;
945 Start
= mktime
(&tm
);
947 if
(Start
== (time_t) -1)
950 /* Guard against falsely reporting errors near the time_t boundaries
951 when parsing times in other time zones. For example, if the min
952 time_t value is 1970-01-01 00:00:00 UTC and we are 8 hours ahead
953 of UTC, then the min localtime value is 1970-01-01 08:00:00; if
954 we apply mktime to 1970-01-01 00:00:00 we will get an error, so
955 we apply mktime to 1970-01-02 08:00:00 instead and adjust the time
956 zone by 24 hours to compensate. This algorithm assumes that
957 there is no DST transition within a day of the time_t boundaries. */
961 if
(tm.tm_year
<= EPOCH
- TM_YEAR_ORIGIN
)
964 yyTimezone
-= 24 * 60;
969 yyTimezone
+= 24 * 60;
971 Start
= mktime
(&tm
);
974 if
(Start
== (time_t) -1)
978 if
(yyHaveDay
&& !yyHaveDate
)
980 tm.tm_mday
+= ((yyDayNumber
- tm.tm_wday
+ 7) %
7
981 + 7 * (yyDayOrdinal
- (0 < yyDayOrdinal
)));
982 Start
= mktime
(&tm
);
983 if
(Start
== (time_t) -1)
989 long delta
= yyTimezone
* 60L + difftm
(&tm
, gmtime
(&Start
));
990 if
((Start
+ delta
< Start
) != (delta
< 0))
991 return
-1; /* time_t overflow */
1006 char buff
[MAX_BUFF_LEN
+ 1];
1009 (void) printf
("Enter date, or blank line to exit.\n\t> ");
1010 (void) fflush
(stdout
);
1012 buff
[MAX_BUFF_LEN
] = 0;
1013 while
(fgets
(buff
, MAX_BUFF_LEN
, stdin
) && buff
[0])
1015 d
= get_date
(buff
, (time_t *) NULL
);
1017 (void) printf
("Bad format - couldn't convert.\n");
1019 (void) printf
("%s", ctime
(&d
));
1020 (void) printf
("\t> ");
1021 (void) fflush
(stdout
);
1026 #endif /* defined (TEST) */