]>
git.proxmox.com Git - mirror_edk2.git/blob - StdLib/LibC/Time/ZoneProc.c
4 Copyright (c) 2010 - 2011, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials are licensed and made available under
6 the terms and conditions of the BSD License that accompanies this distribution.
7 The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php.
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13 Portions derived from the NIH time zone package file, localtime.c,
14 which contains the following notice:
16 This file is in the public domain, so clarified as of
17 1996-06-05 by Arthur David Olson (arthur_david_olson@nih.gov).
19 NetBSD: localtime.c,v 1.39 2006/03/22 14:01:30 christos Exp
21 #include <LibConfig.h>
35 ** Someone might make incorrect use of a time zone abbreviation:
36 ** 1. They might reference tzname[0] before calling tzset (explicitly
38 ** 2. They might reference tzname[1] before calling tzset (explicitly
40 ** 3. They might reference tzname[1] after setting to a time zone
41 ** in which Daylight Saving Time is never observed.
42 ** 4. They might reference tzname[0] after setting to a time zone
43 ** in which Standard Time is never observed.
44 ** 5. They might reference tm.TM_ZONE after calling offtime.
45 ** What's best to do in the above cases is open to debate;
46 ** for now, we just set things up so that in any of the five cases
47 ** WILDABBR is used. Another possibility: initialize tzname[0] to the
48 ** string "tzname[0] used before set", and similarly for the other cases.
49 ** And another: initialize tzname[0] to "ERA", with an explanation in the
50 ** manual page of what this "time zone abbreviation" means (doing this so
51 ** that tzname[0] has the "normal" length of three characters).
54 #endif /* !defined WILDABBR */
56 const char wildabbr
[9] = "WILDABBR";
57 const char gmt
[4] = "GMT";
59 struct state
* lclptr
= NULL
;
60 struct state
* gmtptr
= NULL
;
63 #define TZ_STRLEN_MAX 255
64 #endif /* !defined TZ_STRLEN_MAX */
66 static char lcl_TZname
[TZ_STRLEN_MAX
+ 1];
67 static int lcl_is_set
= 0;
68 //static int gmt_is_set = 0;
71 (char *)__UNCONST(wildabbr
),
72 (char *)__UNCONST(wildabbr
)
75 long int timezone
= 0;
78 #ifndef NO_ZONEINFO_FILES
79 /** Get first 4 characters of codep as a 32-bit integer.
81 The first character of codep becomes the MSB of the resultant integer.
84 detzcode(const char * const codep
)
86 register INT32 result
;
89 ** The first character must be sign extended on systems with >32bit
90 ** longs. This was solved differently in the master tzcode sources
91 ** (the fix first appeared in tzcode95c.tar.gz). But I believe
92 ** that this implementation is superior.
94 #define SIGN_EXTEND_CHAR(x) ((signed char) x)
96 result
= (SIGN_EXTEND_CHAR(codep
[0]) << 24) \
97 | (codep
[1] & 0xff) << 16 \
98 | (codep
[2] & 0xff) << 8
102 #endif /* NO_ZONEINFO_FILES */
107 register struct state
* const sp
= lclptr
;
110 tzname
[0] = (char *)__UNCONST(wildabbr
);
111 tzname
[1] = (char *)__UNCONST(wildabbr
);
115 tzname
[0] = tzname
[1] = (char *)__UNCONST(gmt
);
118 for (i
= 0; i
< sp
->typecnt
; ++i
) {
119 register const struct ttinfo
* const ttisp
= &sp
->ttis
[i
];
121 tzname
[ttisp
->tt_isdst
] =
122 &sp
->chars
[ttisp
->tt_abbrind
];
125 if (i
== 0 || !ttisp
->tt_isdst
)
126 timezone
= -(ttisp
->tt_gmtoff
);
129 ** And to get the latest zone names into tzname. . .
131 for (i
= 0; i
< sp
->timecnt
; ++i
) {
132 register const struct ttinfo
* const ttisp
=
133 &sp
->ttis
[ sp
->types
[i
] ];
135 tzname
[ttisp
->tt_isdst
] =
136 &sp
->chars
[ttisp
->tt_abbrind
];
141 ** Given a pointer into a time zone string, scan until a character that is not
142 ** a valid character in a zone name is found. Return a pointer to that
146 getzname(register const char *strp
)
150 while ((c
= *strp
) != '\0' && !is_digit(c
) && c
!= ',' && c
!= '-' &&
157 ** Given a pointer into a time zone string, extract a number from that string.
158 ** Check that the number is within a specified range; if it is not, return
160 ** Otherwise, return a pointer to the first character not part of the number.
164 register const char *strp
,
173 if (strp
== NULL
|| !is_digit(c
= *strp
))
177 num
= num
* 10 + (c
- '0');
179 return NULL
; /* illegal value */
181 } while (is_digit(c
));
183 return NULL
; /* illegal value */
189 ** Given a pointer into a time zone string, extract a number of seconds,
190 ** in hh[:mm[:ss]] form, from the string.
191 ** If any error occurs, return NULL.
192 ** Otherwise, return a pointer to the first character not part of the number
197 register const char *strp
,
204 ** `HOURSPERDAY * DAYSPERWEEK - 1' allows quasi-Posix rules like
205 ** "M10.4.6/26", which does not conform to Posix,
206 ** but which specifies the equivalent of
207 ** ``02:00 on the first Sunday on or after 23 Oct''.
209 strp
= getnum(strp
, &num
, 0, HOURSPERDAY
* DAYSPERWEEK
- 1);
212 *secsp
= (long)(num
* SECSPERHOUR
);
215 strp
= getnum(strp
, &num
, 0, MINSPERHOUR
- 1);
218 *secsp
+= num
* SECSPERMIN
;
221 /* `SECSPERMIN' allows for leap seconds. */
222 strp
= getnum(strp
, &num
, 0, SECSPERMIN
);
232 ** Given a pointer into a time zone string, extract an offset, in
233 ** [+-]hh[:mm[:ss]] form, from the string.
234 ** If any error occurs, return NULL.
235 ** Otherwise, return a pointer to the first character not part of the time.
239 register const char *strp
,
240 LONG32
* const offsetp
243 register int neg
= 0;
248 } else if (*strp
== '+')
250 strp
= getsecs(strp
, offsetp
);
252 return NULL
; /* illegal time */
254 *offsetp
= -*offsetp
;
259 ** Given a pointer into a time zone string, extract a rule in the form
260 ** date[/time]. See POSIX section 8 for the format of "date" and "time".
261 ** If a valid rule is not found, return NULL.
262 ** Otherwise, return a pointer to the first character not part of the rule.
267 register struct rule
* const rulep
274 rulep
->r_type
= JULIAN_DAY
;
276 strp
= getnum(strp
, &rulep
->r_day
, 1, DAYSPERNYEAR
);
277 } else if (*strp
== 'M') {
281 rulep
->r_type
= MONTH_NTH_DAY_OF_WEEK
;
283 strp
= getnum(strp
, &rulep
->r_mon
, 1, MONSPERYEAR
);
288 strp
= getnum(strp
, &rulep
->r_week
, 1, 5);
293 strp
= getnum(strp
, &rulep
->r_day
, 0, DAYSPERWEEK
- 1);
294 } else if (is_digit(*strp
)) {
298 rulep
->r_type
= DAY_OF_YEAR
;
299 strp
= getnum(strp
, &rulep
->r_day
, 0, DAYSPERLYEAR
- 1);
300 } else return NULL
; /* invalid format */
308 strp
= getsecs(strp
, &rulep
->r_time
);
309 } else rulep
->r_time
= 2 * SECSPERHOUR
; /* default = 2:00:00 */
314 tzload(register const char *name
, register struct state
* const sp
)
316 #ifndef NO_ZONEINFO_FILES
317 register const char * p
;
321 if (name
== NULL
&& (name
= TZDEFAULT
) == NULL
)
325 register int doaccess
;
327 ** Section 4.9.1 of the C standard says that
328 ** "FILENAME_MAX expands to an integral constant expression
329 ** that is the size needed for an array of char large enough
330 ** to hold the longest file name string that the implementation
331 ** guarantees can be opened."
333 char fullname
[FILENAME_MAX
+ 1];
337 doaccess
= name
[0] == '/';
339 if ((p
= TZDIR
) == NULL
)
341 if ((strlen(p
) + strlen(name
) + 1) >= sizeof fullname
)
343 (void) strcpy(fullname
, p
); /* XXX strcpy is safe */
344 (void) strcat(fullname
, "/"); /* XXX strcat is safe */
345 (void) strcat(fullname
, name
); /* XXX strcat is safe */
347 ** Set doaccess if '.' (as in "../") shows up in name.
349 if (strchr(name
, '.') != NULL
)
353 if (doaccess
&& access(name
, R_OK
) != 0)
356 * XXX potential security problem here if user of a set-id
357 * program has set TZ (which is passed in as name) here,
358 * and uses a race condition trick to defeat the access(2)
361 if ((fid
= open(name
, OPEN_MODE
)) == -1)
365 struct tzhead
* tzhp
;
367 struct tzhead tzhead
;
368 char buf
[sizeof *sp
+ sizeof *tzhp
];
373 i
= read(fid
, u
.buf
, sizeof u
.buf
);
376 ttisstdcnt
= (int) detzcode(u
.tzhead
.tzh_ttisstdcnt
);
377 ttisgmtcnt
= (int) detzcode(u
.tzhead
.tzh_ttisgmtcnt
);
378 sp
->leapcnt
= (int) detzcode(u
.tzhead
.tzh_leapcnt
);
379 sp
->timecnt
= (int) detzcode(u
.tzhead
.tzh_timecnt
);
380 sp
->typecnt
= (int) detzcode(u
.tzhead
.tzh_typecnt
);
381 sp
->charcnt
= (int) detzcode(u
.tzhead
.tzh_charcnt
);
382 p
= u
.tzhead
.tzh_charcnt
+ sizeof u
.tzhead
.tzh_charcnt
;
383 if (sp
->leapcnt
< 0 || sp
->leapcnt
> TZ_MAX_LEAPS
||
384 sp
->typecnt
<= 0 || sp
->typecnt
> TZ_MAX_TYPES
||
385 sp
->timecnt
< 0 || sp
->timecnt
> TZ_MAX_TIMES
||
386 sp
->charcnt
< 0 || sp
->charcnt
> TZ_MAX_CHARS
||
387 (ttisstdcnt
!= sp
->typecnt
&& ttisstdcnt
!= 0) ||
388 (ttisgmtcnt
!= sp
->typecnt
&& ttisgmtcnt
!= 0))
390 if (i
- (p
- u
.buf
) < sp
->timecnt
* 4 + /* ats */
391 sp
->timecnt
+ /* types */
392 sp
->typecnt
* (4 + 2) + /* ttinfos */
393 sp
->charcnt
+ /* chars */
394 sp
->leapcnt
* (4 + 4) + /* lsinfos */
395 ttisstdcnt
+ /* ttisstds */
396 ttisgmtcnt
) /* ttisgmts */
398 for (i
= 0; i
< sp
->timecnt
; ++i
) {
399 sp
->ats
[i
] = detzcode(p
);
402 for (i
= 0; i
< sp
->timecnt
; ++i
) {
403 sp
->types
[i
] = (unsigned char) *p
++;
404 if (sp
->types
[i
] >= sp
->typecnt
)
407 for (i
= 0; i
< sp
->typecnt
; ++i
) {
408 register struct ttinfo
* ttisp
;
410 ttisp
= &sp
->ttis
[i
];
411 ttisp
->tt_gmtoff
= detzcode(p
);
413 ttisp
->tt_isdst
= (unsigned char) *p
++;
414 if (ttisp
->tt_isdst
!= 0 && ttisp
->tt_isdst
!= 1)
416 ttisp
->tt_abbrind
= (unsigned char) *p
++;
417 if (ttisp
->tt_abbrind
< 0 ||
418 ttisp
->tt_abbrind
> sp
->charcnt
)
421 for (i
= 0; i
< sp
->charcnt
; ++i
)
423 sp
->chars
[i
] = '\0'; /* ensure '\0' at end */
424 for (i
= 0; i
< sp
->leapcnt
; ++i
) {
425 register struct lsinfo
* lsisp
;
427 lsisp
= &sp
->lsis
[i
];
428 lsisp
->ls_trans
= detzcode(p
);
430 lsisp
->ls_corr
= detzcode(p
);
433 for (i
= 0; i
< sp
->typecnt
; ++i
) {
434 register struct ttinfo
* ttisp
;
436 ttisp
= &sp
->ttis
[i
];
438 ttisp
->tt_ttisstd
= FALSE
;
440 ttisp
->tt_ttisstd
= *p
++;
441 if (ttisp
->tt_ttisstd
!= TRUE
&&
442 ttisp
->tt_ttisstd
!= FALSE
)
446 for (i
= 0; i
< sp
->typecnt
; ++i
) {
447 register struct ttinfo
* ttisp
;
449 ttisp
= &sp
->ttis
[i
];
451 ttisp
->tt_ttisgmt
= FALSE
;
453 ttisp
->tt_ttisgmt
= *p
++;
454 if (ttisp
->tt_ttisgmt
!= TRUE
&&
455 ttisp
->tt_ttisgmt
!= FALSE
)
461 #else /* ! NO_ZONEINFO_FILES */
467 ** Given the Epoch-relative time of January 1, 00:00:00 UTC, in a year, the
468 ** year, a rule, and the offset from UTC at the time that rule takes effect,
469 ** calculate the Epoch-relative time that rule takes effect.
474 const time_t janfirst
,
476 const struct rule
* const rulep
,
480 register int leapyear
;
481 register time_t value
;
483 int d
, m1
, yy0
, yy1
, yy2
, dow
;
486 leapyear
= isleap(year
);
487 switch (rulep
->r_type
) {
491 ** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap
493 ** In non-leap years, or if the day number is 59 or less, just
494 ** add SECSPERDAY times the day number-1 to the time of
495 ** January 1, midnight, to get the day.
497 value
= janfirst
+ (rulep
->r_day
- 1) * SECSPERDAY
;
498 if (leapyear
&& rulep
->r_day
>= 60)
505 ** Just add SECSPERDAY times the day number to the time of
506 ** January 1, midnight, to get the day.
508 value
= janfirst
+ rulep
->r_day
* SECSPERDAY
;
511 case MONTH_NTH_DAY_OF_WEEK
:
513 ** Mm.n.d - nth "dth day" of month m.
516 for (i
= 0; i
< rulep
->r_mon
- 1; ++i
)
517 value
+= mon_lengths
[leapyear
][i
] * SECSPERDAY
;
520 ** Use Zeller's Congruence to get day-of-week of first day of
523 m1
= (rulep
->r_mon
+ 9) % 12 + 1;
524 yy0
= (rulep
->r_mon
<= 2) ? (year
- 1) : year
;
527 dow
= ((26 * m1
- 2) / 10 +
528 1 + yy2
+ yy2
/ 4 + yy1
/ 4 - 2 * yy1
) % 7;
533 ** "dow" is the day-of-week of the first day of the month. Get
534 ** the day-of-month (zero-origin) of the first "dow" day of the
537 d
= rulep
->r_day
- dow
;
540 for (i
= 1; i
< rulep
->r_week
; ++i
) {
541 if (d
+ DAYSPERWEEK
>=
542 mon_lengths
[leapyear
][rulep
->r_mon
- 1])
548 ** "d" is the day-of-month (zero-origin) of the day we want.
550 value
+= d
* SECSPERDAY
;
555 ** "value" is the Epoch-relative time of 00:00:00 UTC on the day in
556 ** question. To get the Epoch-relative time of the specified local
557 ** time on that day, add the transition time and the current offset
560 return value
+ rulep
->r_time
+ offset
;
564 ** Given a POSIX section 8-style TZ string, fill in the rule tables as
570 struct state
* const sp
,
581 unsigned char *typep
;
588 stdlen
= strlen(name
); /* length of standard zone name */
590 if (stdlen
>= sizeof sp
->chars
)
591 stdlen
= (sizeof sp
->chars
) - 1;
594 name
= getzname(name
);
595 stdlen
= name
- stdname
;
600 name
= getoffset(name
, &stdoffset
);
604 load_result
= tzload(TZDEFRULES
, sp
);
605 if (load_result
!= 0)
606 sp
->leapcnt
= 0; /* so, we're off a little */
609 name
= getzname(name
);
610 dstlen
= name
- dstname
; /* length of DST zone name */
613 if (*name
!= '\0' && *name
!= ',' && *name
!= ';') {
614 name
= getoffset(name
, &dstoffset
);
617 } else dstoffset
= stdoffset
- SECSPERHOUR
;
618 if (*name
== '\0' && load_result
!= 0)
619 name
= TZDEFRULESTRING
;
620 if (*name
== ',' || *name
== ';') {
624 register time_t janfirst
;
629 if ((name
= getrule(name
, &start
)) == NULL
)
633 if ((name
= getrule(name
, &end
)) == NULL
)
637 sp
->typecnt
= 2; /* standard time and DST */
639 ** Two transitions per year, from EPOCH_YEAR to 2037.
641 sp
->timecnt
= 2 * (2037 - EPOCH_YEAR
+ 1);
642 if (sp
->timecnt
> TZ_MAX_TIMES
)
644 sp
->ttis
[0].tt_gmtoff
= -dstoffset
;
645 sp
->ttis
[0].tt_isdst
= 1;
646 sp
->ttis
[0].tt_abbrind
= (int)stdlen
+ 1;
647 sp
->ttis
[1].tt_gmtoff
= -stdoffset
;
648 sp
->ttis
[1].tt_isdst
= 0;
649 sp
->ttis
[1].tt_abbrind
= 0;
653 for (year
= EPOCH_YEAR
; year
<= 2037; ++year
) {
654 starttime
= transtime(janfirst
, year
, &start
,
656 endtime
= transtime(janfirst
, year
, &end
,
658 if (starttime
> endtime
) {
660 *typep
++ = 1; /* DST ends */
662 *typep
++ = 0; /* DST begins */
665 *typep
++ = 0; /* DST begins */
667 *typep
++ = 1; /* DST ends */
669 janfirst
+= year_lengths
[isleap(year
)] *
673 register LONG32 theirstdoffset
;
674 register LONG32 theiroffset
;
681 ** Initial values of theirstdoffset
684 for (i
= 0; i
< sp
->timecnt
; ++i
) {
686 if (!sp
->ttis
[j
].tt_isdst
) {
688 -sp
->ttis
[j
].tt_gmtoff
;
693 ** Initially we're assumed to be in standard time.
695 theiroffset
= theirstdoffset
;
697 ** Now juggle transition times and types
698 ** tracking offsets as you do.
700 for (i
= 0; i
< sp
->timecnt
; ++i
) {
702 sp
->types
[i
] = (unsigned char)sp
->ttis
[j
].tt_isdst
;
703 if (sp
->ttis
[j
].tt_ttisgmt
) {
704 /* No adjustment to transition time */
707 ** If summer time is in effect, and the
708 ** transition time was not specified as
709 ** standard time, add the summer time
710 ** offset to the transition time;
711 ** otherwise, add the standard time
712 ** offset to the transition time.
715 ** Transitions from DST to DDST
716 ** will effectively disappear since
717 ** POSIX provides for only one DST
720 sp
->ats
[i
] += stdoffset
-
723 theiroffset
= -sp
->ttis
[j
].tt_gmtoff
;
724 if (!sp
->ttis
[j
].tt_isdst
)
725 theirstdoffset
= theiroffset
;
728 ** Finally, fill in ttis.
729 ** ttisstd and ttisgmt need not be handled.
731 sp
->ttis
[0].tt_gmtoff
= -stdoffset
;
732 sp
->ttis
[0].tt_isdst
= FALSE
;
733 sp
->ttis
[0].tt_abbrind
= 0;
734 sp
->ttis
[1].tt_gmtoff
= -dstoffset
;
735 sp
->ttis
[1].tt_isdst
= TRUE
;
736 sp
->ttis
[1].tt_abbrind
= (int)stdlen
+ 1;
741 sp
->typecnt
= 1; /* only standard time */
743 sp
->ttis
[0].tt_gmtoff
= -stdoffset
;
744 sp
->ttis
[0].tt_isdst
= 0;
745 sp
->ttis
[0].tt_abbrind
= 0;
747 sp
->charcnt
= (int)stdlen
+ 1;
749 sp
->charcnt
+= (int)dstlen
+ 1;
750 if ((size_t) sp
->charcnt
> sizeof sp
->chars
)
753 (void) strncpy(cp
, stdname
, stdlen
);
757 (void) strncpy(cp
, dstname
, dstlen
);
758 *(cp
+ dstlen
) = '\0';
764 gmtload(struct state
* const sp
)
766 if (tzload(gmt
, sp
) != 0)
767 (void) tzparse(gmt
, sp
, TRUE
);
777 if (lclptr
== NULL
) {
778 lclptr
= (struct state
*) malloc(sizeof *lclptr
);
779 if (lclptr
== NULL
) {
780 settzname(); /* all we can do */
784 if (tzload((char *) NULL
, lclptr
) != 0)
792 register const char * name
;
800 if (lcl_is_set
> 0 && strcmp(lcl_TZname
, name
) == 0)
802 lcl_is_set
= strlen(name
) < sizeof lcl_TZname
;
804 (void)strncpyX(lcl_TZname
, name
, sizeof(lcl_TZname
));
806 if (lclptr
== NULL
) {
807 lclptr
= (struct state
*) malloc(sizeof *lclptr
);
808 if (lclptr
== NULL
) {
809 settzname(); /* all we can do */
815 ** User wants it fast rather than right.
817 lclptr
->leapcnt
= 0; /* so, we're off a little */
820 lclptr
->ttis
[0].tt_isdst
= 0;
821 lclptr
->ttis
[0].tt_gmtoff
= 0;
822 lclptr
->ttis
[0].tt_abbrind
= 0;
823 (void)strncpyX(lclptr
->chars
, gmt
, sizeof(lclptr
->chars
));
824 } else if (tzload(name
, lclptr
) != 0)
825 if (name
[0] == ':' || tzparse(name
, lclptr
, FALSE
) != 0)
826 (void) gmtload(lclptr
);