1 /** @file
2 Time Zone processing.
3
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.
9
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.
12
13 Portions derived from the NIH time zone package file, localtime.c,
14 which contains the following notice:
15
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).
18
19 NetBSD: localtime.c,v 1.39 2006/03/22 14:01:30 christos Exp
20 **/
21 #include <LibConfig.h>
22
23 #include <ctype.h>
24 #include <fcntl.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <time.h>
29 #include <unistd.h>
30 #include "tzfile.h"
31 #include "TimeVals.h"
32
33 #ifndef WILDABBR
34 /*
35 ** Someone might make incorrect use of a time zone abbreviation:
36 ** 1. They might reference tzname[0] before calling tzset (explicitly
37 ** or implicitly).
38 ** 2. They might reference tzname[1] before calling tzset (explicitly
39 ** or implicitly).
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).
52 */
53 #define WILDABBR " "
54 #endif /* !defined WILDABBR */
55
56 const char wildabbr[9] = "WILDABBR";
57 const char gmt[4] = "GMT";
58
59 struct state * lclptr = NULL;
60 struct state * gmtptr = NULL;
61
62 #ifndef TZ_STRLEN_MAX
63 #define TZ_STRLEN_MAX 255
64 #endif /* !defined TZ_STRLEN_MAX */
65
66 static char lcl_TZname[TZ_STRLEN_MAX + 1];
67 static int lcl_is_set = 0;
68 //static int gmt_is_set = 0;
69
70 char * tzname[2] = {
71 (char *)__UNCONST(wildabbr),
72 (char *)__UNCONST(wildabbr)
73 };
74
75 long int timezone = 0;
76 int daylight = 0;
77
78 #ifndef NO_ZONEINFO_FILES
79 /** Get first 4 characters of codep as a 32-bit integer.
80
81 The first character of codep becomes the MSB of the resultant integer.
82 **/
83 static INT32
detzcode(const char * const codep)84 detzcode(const char * const codep)
85 {
86 register INT32 result;
87
88 /*
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.
93 */
94 #define SIGN_EXTEND_CHAR(x) ((signed char) x)
95
96 result = (SIGN_EXTEND_CHAR(codep[0]) << 24) \
97 | (codep[1] & 0xff) << 16 \
98 | (codep[2] & 0xff) << 8
99 | (codep[3] & 0xff);
100 return result;
101 }
102 #endif /* NO_ZONEINFO_FILES */
103
104 static void
settzname(void)105 settzname (void)
106 {
107 register struct state * const sp = lclptr;
108 register int i;
109
110 tzname[0] = (char *)__UNCONST(wildabbr);
111 tzname[1] = (char *)__UNCONST(wildabbr);
112 daylight = 0;
113 timezone = 0;
114 if (sp == NULL) {
115 tzname[0] = tzname[1] = (char *)__UNCONST(gmt);
116 return;
117 }
118 for (i = 0; i < sp->typecnt; ++i) {
119 register const struct ttinfo * const ttisp = &sp->ttis[i];
120
121 tzname[ttisp->tt_isdst] =
122 &sp->chars[ttisp->tt_abbrind];
123 if (ttisp->tt_isdst)
124 daylight = 1;
125 if (i == 0 || !ttisp->tt_isdst)
126 timezone = -(ttisp->tt_gmtoff);
127 }
128 /*
129 ** And to get the latest zone names into tzname. . .
130 */
131 for (i = 0; i < sp->timecnt; ++i) {
132 register const struct ttinfo * const ttisp =
133 &sp->ttis[ sp->types[i] ];
134
135 tzname[ttisp->tt_isdst] =
136 &sp->chars[ttisp->tt_abbrind];
137 }
138 }
139
140 /*
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
143 ** character.
144 */
145 static const char *
getzname(register const char * strp)146 getzname(register const char *strp)
147 {
148 register char c;
149
150 while ((c = *strp) != '\0' && !is_digit(c) && c != ',' && c != '-' &&
151 c != '+')
152 ++strp;
153 return strp;
154 }
155
156 /*
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
159 ** NULL.
160 ** Otherwise, return a pointer to the first character not part of the number.
161 */
162 static const char *
getnum(register const char * strp,int * const nump,const int min,const int max)163 getnum(
164 register const char *strp,
165 int * const nump,
166 const int min,
167 const int max
168 )
169 {
170 register char c;
171 register int num;
172
173 if (strp == NULL || !is_digit(c = *strp))
174 return NULL;
175 num = 0;
176 do {
177 num = num * 10 + (c - '0');
178 if (num > max)
179 return NULL; /* illegal value */
180 c = *++strp;
181 } while (is_digit(c));
182 if (num < min)
183 return NULL; /* illegal value */
184 *nump = num;
185 return strp;
186 }
187
188 /*
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
193 ** of seconds.
194 */
195 static const char *
getsecs(register const char * strp,LONG32 * const secsp)196 getsecs(
197 register const char *strp,
198 LONG32 * const secsp
199 )
200 {
201 int num;
202
203 /*
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''.
208 */
209 strp = getnum(strp, &num, 0, HOURSPERDAY * DAYSPERWEEK - 1);
210 if (strp == NULL)
211 return NULL;
212 *secsp = (long)(num * SECSPERHOUR);
213 if (*strp == ':') {
214 ++strp;
215 strp = getnum(strp, &num, 0, MINSPERHOUR - 1);
216 if (strp == NULL)
217 return NULL;
218 *secsp += num * SECSPERMIN;
219 if (*strp == ':') {
220 ++strp;
221 /* `SECSPERMIN' allows for leap seconds. */
222 strp = getnum(strp, &num, 0, SECSPERMIN);
223 if (strp == NULL)
224 return NULL;
225 *secsp += num;
226 }
227 }
228 return strp;
229 }
230
231 /*
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.
236 */
237 static const char *
getoffset(register const char * strp,LONG32 * const offsetp)238 getoffset(
239 register const char *strp,
240 LONG32 * const offsetp
241 )
242 {
243 register int neg = 0;
244
245 if (*strp == '-') {
246 neg = 1;
247 ++strp;
248 } else if (*strp == '+')
249 ++strp;
250 strp = getsecs(strp, offsetp);
251 if (strp == NULL)
252 return NULL; /* illegal time */
253 if (neg)
254 *offsetp = -*offsetp;
255 return strp;
256 }
257
258 /*
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.
263 */
264 static const char *
getrule(const char * strp,register struct rule * const rulep)265 getrule(
266 const char *strp,
267 register struct rule * const rulep
268 )
269 {
270 if (*strp == 'J') {
271 /*
272 ** Julian day.
273 */
274 rulep->r_type = JULIAN_DAY;
275 ++strp;
276 strp = getnum(strp, &rulep->r_day, 1, DAYSPERNYEAR);
277 } else if (*strp == 'M') {
278 /*
279 ** Month, week, day.
280 */
281 rulep->r_type = MONTH_NTH_DAY_OF_WEEK;
282 ++strp;
283 strp = getnum(strp, &rulep->r_mon, 1, MONSPERYEAR);
284 if (strp == NULL)
285 return NULL;
286 if (*strp++ != '.')
287 return NULL;
288 strp = getnum(strp, &rulep->r_week, 1, 5);
289 if (strp == NULL)
290 return NULL;
291 if (*strp++ != '.')
292 return NULL;
293 strp = getnum(strp, &rulep->r_day, 0, DAYSPERWEEK - 1);
294 } else if (is_digit(*strp)) {
295 /*
296 ** Day of year.
297 */
298 rulep->r_type = DAY_OF_YEAR;
299 strp = getnum(strp, &rulep->r_day, 0, DAYSPERLYEAR - 1);
300 } else return NULL; /* invalid format */
301 if (strp == NULL)
302 return NULL;
303 if (*strp == '/') {
304 /*
305 ** Time specified.
306 */
307 ++strp;
308 strp = getsecs(strp, &rulep->r_time);
309 } else rulep->r_time = 2 * SECSPERHOUR; /* default = 2:00:00 */
310 return strp;
311 }
312
313 static int
tzload(register const char * name,register struct state * const sp)314 tzload(register const char *name, register struct state * const sp)
315 {
316 #ifndef NO_ZONEINFO_FILES
317 register const char * p;
318 register int i;
319 register int fid;
320
321 if (name == NULL && (name = TZDEFAULT) == NULL)
322 return -1;
323
324 {
325 register int doaccess;
326 /*
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."
332 */
333 char fullname[FILENAME_MAX + 1];
334
335 if (name[0] == ':')
336 ++name;
337 doaccess = name[0] == '/';
338 if (!doaccess) {
339 if ((p = TZDIR) == NULL)
340 return -1;
341 if ((strlen(p) + strlen(name) + 1) >= sizeof fullname)
342 return -1;
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 */
346 /*
347 ** Set doaccess if '.' (as in "../") shows up in name.
348 */
349 if (strchr(name, '.') != NULL)
350 doaccess = TRUE;
351 name = fullname;
352 }
353 if (doaccess && access(name, R_OK) != 0)
354 return -1;
355 /*
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)
359 * above.
360 */
361 if ((fid = open(name, OPEN_MODE)) == -1)
362 return -1;
363 }
364 {
365 struct tzhead * tzhp;
366 union {
367 struct tzhead tzhead;
368 char buf[sizeof *sp + sizeof *tzhp];
369 } u;
370 int ttisstdcnt;
371 int ttisgmtcnt;
372
373 i = read(fid, u.buf, sizeof u.buf);
374 if (close(fid) != 0)
375 return -1;
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))
389 return -1;
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 */
397 return -1;
398 for (i = 0; i < sp->timecnt; ++i) {
399 sp->ats[i] = detzcode(p);
400 p += 4;
401 }
402 for (i = 0; i < sp->timecnt; ++i) {
403 sp->types[i] = (unsigned char) *p++;
404 if (sp->types[i] >= sp->typecnt)
405 return -1;
406 }
407 for (i = 0; i < sp->typecnt; ++i) {
408 register struct ttinfo * ttisp;
409
410 ttisp = &sp->ttis[i];
411 ttisp->tt_gmtoff = detzcode(p);
412 p += 4;
413 ttisp->tt_isdst = (unsigned char) *p++;
414 if (ttisp->tt_isdst != 0 && ttisp->tt_isdst != 1)
415 return -1;
416 ttisp->tt_abbrind = (unsigned char) *p++;
417 if (ttisp->tt_abbrind < 0 ||
418 ttisp->tt_abbrind > sp->charcnt)
419 return -1;
420 }
421 for (i = 0; i < sp->charcnt; ++i)
422 sp->chars[i] = *p++;
423 sp->chars[i] = '\0'; /* ensure '\0' at end */
424 for (i = 0; i < sp->leapcnt; ++i) {
425 register struct lsinfo * lsisp;
426
427 lsisp = &sp->lsis[i];
428 lsisp->ls_trans = detzcode(p);
429 p += 4;
430 lsisp->ls_corr = detzcode(p);
431 p += 4;
432 }
433 for (i = 0; i < sp->typecnt; ++i) {
434 register struct ttinfo * ttisp;
435
436 ttisp = &sp->ttis[i];
437 if (ttisstdcnt == 0)
438 ttisp->tt_ttisstd = FALSE;
439 else {
440 ttisp->tt_ttisstd = *p++;
441 if (ttisp->tt_ttisstd != TRUE &&
442 ttisp->tt_ttisstd != FALSE)
443 return -1;
444 }
445 }
446 for (i = 0; i < sp->typecnt; ++i) {
447 register struct ttinfo * ttisp;
448
449 ttisp = &sp->ttis[i];
450 if (ttisgmtcnt == 0)
451 ttisp->tt_ttisgmt = FALSE;
452 else {
453 ttisp->tt_ttisgmt = *p++;
454 if (ttisp->tt_ttisgmt != TRUE &&
455 ttisp->tt_ttisgmt != FALSE)
456 return -1;
457 }
458 }
459 }
460 return 0;
461 #else /* ! NO_ZONEINFO_FILES */
462 return -1;
463 #endif
464 }
465
466 /*
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.
470 */
471 static
472 time_t
transtime(const time_t janfirst,const int year,const struct rule * const rulep,const LONG32 offset)473 transtime(
474 const time_t janfirst,
475 const int year,
476 const struct rule * const rulep,
477 const LONG32 offset
478 )
479 {
480 register int leapyear;
481 register time_t value;
482 register int i;
483 int d, m1, yy0, yy1, yy2, dow;
484
485 INITIALIZE(value);
486 leapyear = isleap(year);
487 switch (rulep->r_type) {
488
489 case JULIAN_DAY:
490 /*
491 ** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap
492 ** years.
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.
496 */
497 value = janfirst + (rulep->r_day - 1) * SECSPERDAY;
498 if (leapyear && rulep->r_day >= 60)
499 value += SECSPERDAY;
500 break;
501
502 case DAY_OF_YEAR:
503 /*
504 ** n - day of year.
505 ** Just add SECSPERDAY times the day number to the time of
506 ** January 1, midnight, to get the day.
507 */
508 value = janfirst + rulep->r_day * SECSPERDAY;
509 break;
510
511 case MONTH_NTH_DAY_OF_WEEK:
512 /*
513 ** Mm.n.d - nth "dth day" of month m.
514 */
515 value = janfirst;
516 for (i = 0; i < rulep->r_mon - 1; ++i)
517 value += mon_lengths[leapyear][i] * SECSPERDAY;
518
519 /*
520 ** Use Zeller's Congruence to get day-of-week of first day of
521 ** month.
522 */
523 m1 = (rulep->r_mon + 9) % 12 + 1;
524 yy0 = (rulep->r_mon <= 2) ? (year - 1) : year;
525 yy1 = yy0 / 100;
526 yy2 = yy0 % 100;
527 dow = ((26 * m1 - 2) / 10 +
528 1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7;
529 if (dow < 0)
530 dow += DAYSPERWEEK;
531
532 /*
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
535 ** month.
536 */
537 d = rulep->r_day - dow;
538 if (d < 0)
539 d += DAYSPERWEEK;
540 for (i = 1; i < rulep->r_week; ++i) {
541 if (d + DAYSPERWEEK >=
542 mon_lengths[leapyear][rulep->r_mon - 1])
543 break;
544 d += DAYSPERWEEK;
545 }
546
547 /*
548 ** "d" is the day-of-month (zero-origin) of the day we want.
549 */
550 value += d * SECSPERDAY;
551 break;
552 }
553
554 /*
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
558 ** from UTC.
559 */
560 return value + rulep->r_time + offset;
561 }
562
563 /*
564 ** Given a POSIX section 8-style TZ string, fill in the rule tables as
565 ** appropriate.
566 */
567 static int
tzparse(const char * name,struct state * const sp,const int lastditch)568 tzparse(
569 const char * name,
570 struct state * const sp,
571 const int lastditch
572 )
573 {
574 const char *stdname;
575 const char *dstname;
576 size_t stdlen;
577 size_t dstlen;
578 LONG32 stdoffset;
579 LONG32 dstoffset;
580 time_t *atp;
581 unsigned char *typep;
582 char *cp;
583 int load_result;
584
585 dstname = NULL;
586 stdname = name;
587 if (lastditch) {
588 stdlen = strlen(name); /* length of standard zone name */
589 name += stdlen;
590 if (stdlen >= sizeof sp->chars)
591 stdlen = (sizeof sp->chars) - 1;
592 stdoffset = 0;
593 } else {
594 name = getzname(name);
595 stdlen = name - stdname;
596 if (stdlen < 3)
597 return -1;
598 if (*name == '\0')
599 return -1;
600 name = getoffset(name, &stdoffset);
601 if (name == NULL)
602 return -1;
603 }
604 load_result = tzload(TZDEFRULES, sp);
605 if (load_result != 0)
606 sp->leapcnt = 0; /* so, we're off a little */
607 if (*name != '\0') {
608 dstname = name;
609 name = getzname(name);
610 dstlen = name - dstname; /* length of DST zone name */
611 if (dstlen < 3)
612 return -1;
613 if (*name != '\0' && *name != ',' && *name != ';') {
614 name = getoffset(name, &dstoffset);
615 if (name == NULL)
616 return -1;
617 } else dstoffset = stdoffset - SECSPERHOUR;
618 if (*name == '\0' && load_result != 0)
619 name = TZDEFRULESTRING;
620 if (*name == ',' || *name == ';') {
621 struct rule start;
622 struct rule end;
623 register int year;
624 register time_t janfirst;
625 time_t starttime;
626 time_t endtime;
627
628 ++name;
629 if ((name = getrule(name, &start)) == NULL)
630 return -1;
631 if (*name++ != ',')
632 return -1;
633 if ((name = getrule(name, &end)) == NULL)
634 return -1;
635 if (*name != '\0')
636 return -1;
637 sp->typecnt = 2; /* standard time and DST */
638 /*
639 ** Two transitions per year, from EPOCH_YEAR to 2037.
640 */
641 sp->timecnt = 2 * (2037 - EPOCH_YEAR + 1);
642 if (sp->timecnt > TZ_MAX_TIMES)
643 return -1;
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;
650 atp = sp->ats;
651 typep = sp->types;
652 janfirst = 0;
653 for (year = EPOCH_YEAR; year <= 2037; ++year) {
654 starttime = transtime(janfirst, year, &start,
655 stdoffset);
656 endtime = transtime(janfirst, year, &end,
657 dstoffset);
658 if (starttime > endtime) {
659 *atp++ = endtime;
660 *typep++ = 1; /* DST ends */
661 *atp++ = starttime;
662 *typep++ = 0; /* DST begins */
663 } else {
664 *atp++ = starttime;
665 *typep++ = 0; /* DST begins */
666 *atp++ = endtime;
667 *typep++ = 1; /* DST ends */
668 }
669 janfirst += year_lengths[isleap(year)] *
670 SECSPERDAY;
671 }
672 } else {
673 register LONG32 theirstdoffset;
674 register LONG32 theiroffset;
675 register int i;
676 register int j;
677
678 if (*name != '\0')
679 return -1;
680 /*
681 ** Initial values of theirstdoffset
682 */
683 theirstdoffset = 0;
684 for (i = 0; i < sp->timecnt; ++i) {
685 j = sp->types[i];
686 if (!sp->ttis[j].tt_isdst) {
687 theirstdoffset =
688 -sp->ttis[j].tt_gmtoff;
689 break;
690 }
691 }
692 /*
693 ** Initially we're assumed to be in standard time.
694 */
695 theiroffset = theirstdoffset;
696 /*
697 ** Now juggle transition times and types
698 ** tracking offsets as you do.
699 */
700 for (i = 0; i < sp->timecnt; ++i) {
701 j = sp->types[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 */
705 } else {
706 /*
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.
713 */
714 /*
715 ** Transitions from DST to DDST
716 ** will effectively disappear since
717 ** POSIX provides for only one DST
718 ** offset.
719 */
720 sp->ats[i] += stdoffset -
721 theirstdoffset;
722 }
723 theiroffset = -sp->ttis[j].tt_gmtoff;
724 if (!sp->ttis[j].tt_isdst)
725 theirstdoffset = theiroffset;
726 }
727 /*
728 ** Finally, fill in ttis.
729 ** ttisstd and ttisgmt need not be handled.
730 */
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;
737 sp->typecnt = 2;
738 }
739 } else {
740 dstlen = 0;
741 sp->typecnt = 1; /* only standard time */
742 sp->timecnt = 0;
743 sp->ttis[0].tt_gmtoff = -stdoffset;
744 sp->ttis[0].tt_isdst = 0;
745 sp->ttis[0].tt_abbrind = 0;
746 }
747 sp->charcnt = (int)stdlen + 1;
748 if (dstlen != 0)
749 sp->charcnt += (int)dstlen + 1;
750 if ((size_t) sp->charcnt > sizeof sp->chars)
751 return -1;
752 cp = sp->chars;
753 (void) strncpy(cp, stdname, stdlen);
754 cp += stdlen;
755 *cp++ = '\0';
756 if (dstlen != 0) {
757 (void) strncpy(cp, dstname, dstlen);
758 *(cp + dstlen) = '\0';
759 }
760 return 0;
761 }
762
763 void
gmtload(struct state * const sp)764 gmtload(struct state * const sp)
765 {
766 if (tzload(gmt, sp) != 0)
767 (void) tzparse(gmt, sp, TRUE);
768 }
769
770 static void
tzsetwall(void)771 tzsetwall(void)
772 {
773 if (lcl_is_set < 0)
774 return;
775 lcl_is_set = -1;
776
777 if (lclptr == NULL) {
778 lclptr = (struct state *) malloc(sizeof *lclptr);
779 if (lclptr == NULL) {
780 settzname(); /* all we can do */
781 return;
782 }
783 }
784 if (tzload((char *) NULL, lclptr) != 0)
785 gmtload(lclptr);
786 settzname();
787 }
788
789 void
tzset(void)790 tzset(void)
791 {
792 register const char * name;
793
794 name = getenv("TZ");
795 if (name == NULL) {
796 tzsetwall();
797 return;
798 }
799
800 if (lcl_is_set > 0 && strcmp(lcl_TZname, name) == 0)
801 return;
802 lcl_is_set = strlen(name) < sizeof lcl_TZname;
803 if (lcl_is_set)
804 (void)strncpyX(lcl_TZname, name, sizeof(lcl_TZname));
805
806 if (lclptr == NULL) {
807 lclptr = (struct state *) malloc(sizeof *lclptr);
808 if (lclptr == NULL) {
809 settzname(); /* all we can do */
810 return;
811 }
812 }
813 if (*name == '\0') {
814 /*
815 ** User wants it fast rather than right.
816 */
817 lclptr->leapcnt = 0; /* so, we're off a little */
818 lclptr->timecnt = 0;
819 lclptr->typecnt = 0;
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);
827 settzname();
828 }
829