1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 1995-2002 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 /* from Arthur Olson's 6.1 */ 29 30 /*LINTLIBRARY*/ 31 32 #include <tzfile.h> 33 #include <time.h> 34 #include <string.h> 35 #include <ctype.h> 36 #include <stdio.h> /* for NULL */ 37 #include <fcntl.h> 38 39 #include <sys/param.h> /* for MAXPATHLEN */ 40 41 #undef FILENAME_MAX 42 #define FILENAME_MAX MAXPATHLEN 43 44 #ifdef __STDC__ 45 46 #define P(s) s 47 48 #else /* !defined __STDC__ */ 49 50 /* 51 ** Memory management functions 52 */ 53 54 extern char * calloc(); 55 extern char * malloc(); 56 57 /* 58 ** Communication with the environment 59 */ 60 61 extern char * getenv(); 62 63 #define ASTERISK * 64 #define P(s) (/ASTERISK s ASTERISK/) 65 66 #define const 67 68 #endif /* !defined __STDC__ */ 69 70 #ifndef TRUE 71 #define TRUE 1 72 #define FALSE 0 73 #endif /* !defined TRUE */ 74 75 #define ACCESS_MODE O_RDONLY 76 77 #define OPEN_MODE O_RDONLY 78 79 /* 80 ** Someone might make incorrect use of a time zone abbreviation: 81 ** 1. They might reference tzname[0] before calling tzset (explicitly 82 ** or implicitly). 83 ** 2. They might reference tzname[1] before calling tzset (explicitly 84 ** or implicitly). 85 ** 3. They might reference tzname[1] after setting to a time zone 86 ** in which Daylight Saving Time is never observed. 87 ** 4. They might reference tzname[0] after setting to a time zone 88 ** in which Standard Time is never observed. 89 ** 5. They might reference tm.TM_ZONE after calling offtime. 90 ** What's best to do in the above cases is open to debate; 91 ** for now, we just set things up so that in any of the five cases 92 ** WILDABBR is used. Another possibility: initialize tzname[0] to the 93 ** string "tzname[0] used before set", and similarly for the other cases. 94 ** And another: initialize tzname[0] to "ERA", with an explanation in the 95 ** manual page of what this "time zone abbreviation" means (doing this so 96 ** that tzname[0] has the "normal" length of three characters). 97 */ 98 static const char *WILDABBR = " "; 99 100 static const char *GMT = "GMT"; 101 102 struct ttinfo { /* time type information */ 103 long tt_gmtoff; /* GMT offset in seconds */ 104 int tt_isdst; /* used to set tm_isdst */ 105 int tt_abbrind; /* abbreviation list index */ 106 int tt_ttisstd; /* TRUE if transition is std time */ 107 }; 108 109 struct state { 110 int timecnt; 111 int typecnt; 112 int charcnt; 113 time_t *ats; 114 unsigned char *types; 115 struct ttinfo *ttis; 116 char *chars; 117 char *last_tzload; /* name of file tzload() last opened */ 118 }; 119 120 struct rule { 121 int r_type; /* type of rule--see below */ 122 int r_day; /* day number of rule */ 123 int r_week; /* week number of rule */ 124 int r_mon; /* month number of rule */ 125 long r_time; /* transition time of rule */ 126 }; 127 128 #define JULIAN_DAY 0 /* Jn - Julian day */ 129 #define DAY_OF_YEAR 1 /* n - day of year */ 130 #define MONTH_NTH_DAY_OF_WEEK 2 /* Mm.n.d - month, week, day of week */ 131 132 /* 133 ** Prototypes for static functions. 134 */ 135 136 static int allocall P((register struct state * sp)); 137 static long detzcode P((const char * codep)); 138 static void freeall P((register struct state * sp)); 139 static const char * getzname P((const char * strp, const int i)); 140 static const char * getnum P((const char * strp, int * nump, int min, 141 int max)); 142 static const char * getsecs P((const char * strp, long * secsp)); 143 static const char * getoffset P((const char * strp, long * offsetp)); 144 static const char * getrule P((const char * strp, struct rule * rulep)); 145 static void gmtload P((struct state * sp)); 146 static void gmtsub P((const time_t * timep, long offset, 147 struct tm * tmp)); 148 static void localsub P((const time_t * timep, long offset, 149 struct tm * tmp)); 150 static void normalize P((int * tensptr, int * unitsptr, int base)); 151 static void settzname P((void)); 152 static time_t time1 P((struct tm * tmp, void (* funcp)(), 153 long offset)); 154 static time_t time2 P((struct tm *tmp, void (* funcp)(), 155 long offset, int * okayp)); 156 static void timesub P((const time_t * timep, long offset, 157 struct tm * tmp)); 158 static int tmcomp P((const struct tm * atmp, 159 const struct tm * btmp)); 160 static time_t transtime P((time_t janfirst, int year, 161 const struct rule * rulep, long offset)); 162 static int tzload P((const char * name, struct state * sp)); 163 static int tzparse P((const char * name, struct state * sp, 164 int lastditch)); 165 166 static struct state * lclptr; 167 static struct state * gmtptr; 168 169 static int lcl_is_set; 170 static int gmt_is_set; 171 172 #ifdef S5EMUL 173 char * tzname[2] = { 174 "GMT", 175 " ", 176 }; 177 178 time_t timezone = 0; 179 time_t altzone = 0; 180 int daylight = 0; 181 #endif /* defined S5EMUL */ 182 183 static long 184 detzcode(codep) 185 const char * const codep; 186 { 187 register long result; 188 register int i; 189 190 result = 0; 191 for (i = 0; i < 4; ++i) 192 result = (result << 8) | (codep[i] & 0xff); 193 return result; 194 } 195 196 /* 197 ** Free up existing items pointed to by the specified "state" structure, 198 ** and allocate new ones of sizes specified by that "state" structure. 199 ** Return 0 on success; return -1 and free all previously-allocated items 200 ** on failure. 201 */ 202 static int 203 allocall(sp) 204 register struct state * const sp; 205 { 206 freeall(sp); 207 208 if (sp->timecnt != 0) { 209 sp->ats = (time_t *)calloc((unsigned)sp->timecnt, 210 (unsigned)sizeof (time_t)); 211 if (sp->ats == NULL) 212 return -1; 213 sp->types = 214 (unsigned char *)calloc((unsigned)sp->timecnt, 215 (unsigned)sizeof (unsigned char)); 216 if (sp->types == NULL) { 217 freeall(sp); 218 return -1; 219 } 220 } 221 sp->ttis = 222 (struct ttinfo *)calloc((unsigned)sp->typecnt, 223 (unsigned)sizeof (struct ttinfo)); 224 if (sp->ttis == NULL) { 225 freeall(sp); 226 return -1; 227 } 228 sp->chars = (char *)calloc((unsigned)sp->charcnt + 1, 229 (unsigned)sizeof (char)); 230 if (sp->chars == NULL) { 231 freeall(sp); 232 return -1; 233 } 234 return 0; 235 } 236 237 /* 238 ** Free all the items pointed to by the specified "state" structure (except for 239 ** "chars", which might have other references to it), and zero out all the 240 ** pointers to those items. 241 */ 242 static void 243 freeall(sp) 244 register struct state * const sp; 245 { 246 if (sp->ttis) { 247 free((char *)sp->ttis); 248 sp->ttis = 0; 249 } 250 if (sp->types) { 251 free((char *)sp->types); 252 sp->types = 0; 253 } 254 if (sp->ats) { 255 free((char *)sp->ats); 256 sp->ats = 0; 257 } 258 } 259 260 #ifdef S5EMUL 261 static void 262 settzname() 263 { 264 register const struct state * const sp = lclptr; 265 register int i; 266 267 tzname[0] = (char *)GMT; 268 tzname[1] = (char *)WILDABBR; 269 daylight = 0; 270 timezone = 0; 271 altzone = 0; 272 if (sp == NULL) 273 return; 274 for (i = 0; i < sp->typecnt; ++i) { 275 register const struct ttinfo * const ttisp = &sp->ttis[i]; 276 277 tzname[ttisp->tt_isdst] = 278 (char *) &sp->chars[ttisp->tt_abbrind]; 279 if (ttisp->tt_isdst) 280 daylight = 1; 281 if (i == 0 || !ttisp->tt_isdst) 282 timezone = -(ttisp->tt_gmtoff); 283 if (i == 0 || ttisp->tt_isdst) 284 altzone = -(ttisp->tt_gmtoff); 285 } 286 /* 287 ** And to get the latest zone names into tzname. . . 288 */ 289 for (i = 0; i < sp->timecnt; ++i) { 290 register const struct ttinfo * const ttisp = 291 &sp->ttis[sp->types[i]]; 292 293 tzname[ttisp->tt_isdst] = 294 (char *) &sp->chars[ttisp->tt_abbrind]; 295 } 296 } 297 #endif 298 299 /* 300 ** Maximum size of a time zone file. 301 */ 302 #define MAX_TZFILESZ (sizeof (struct tzhead) + \ 303 TZ_MAX_TIMES * (4 + sizeof (char)) + \ 304 TZ_MAX_TYPES * (4 + 2 * sizeof (char)) + \ 305 TZ_MAX_CHARS * sizeof (char) + \ 306 TZ_MAX_LEAPS * 2 * 4 + \ 307 TZ_MAX_TYPES * sizeof (char)) 308 309 static int 310 tzload(name, sp) 311 register const char * name; 312 register struct state * const sp; 313 { 314 register const char * p; 315 register int i; 316 register int fid; 317 318 if (name == NULL && (name = (const char *)TZDEFAULT) == NULL) 319 return -1; 320 { 321 register int doaccess; 322 char fullname[FILENAME_MAX + 1]; 323 324 if (name[0] == ':') 325 ++name; 326 doaccess = name[0] == '/'; 327 if (!doaccess) { 328 if ((p = TZDIR) == NULL) 329 return -1; 330 if ((strlen(p) + strlen(name) + 1) >= sizeof fullname) 331 return -1; 332 (void) strcpy(fullname, p); 333 (void) strcat(fullname, "/"); 334 (void) strcat(fullname, name); 335 /* 336 ** Set doaccess if '.' (as in "../") shows up in name. 337 */ 338 if (strchr(name, '.') != NULL) 339 doaccess = TRUE; 340 name = fullname; 341 } 342 if (sp->last_tzload && strcmp(sp->last_tzload, name) == 0) 343 return (0); 344 if (doaccess && access(name, ACCESS_MODE) != 0) 345 return -1; 346 if ((fid = open(name, OPEN_MODE)) == -1) 347 return -1; 348 } 349 { 350 register const struct tzhead * tzhp; 351 char buf[MAX_TZFILESZ]; 352 int leapcnt; 353 int ttisstdcnt; 354 355 i = read(fid, buf, sizeof buf); 356 if (close(fid) != 0 || i < sizeof *tzhp) 357 return -1; 358 tzhp = (struct tzhead *) buf; 359 ttisstdcnt = (int) detzcode(tzhp->tzh_ttisstdcnt); 360 leapcnt = (int) detzcode(tzhp->tzh_leapcnt); 361 sp->timecnt = (int) detzcode(tzhp->tzh_timecnt); 362 sp->typecnt = (int) detzcode(tzhp->tzh_typecnt); 363 sp->charcnt = (int) detzcode(tzhp->tzh_charcnt); 364 if (leapcnt < 0 || leapcnt > TZ_MAX_LEAPS || 365 sp->typecnt <= 0 || sp->typecnt > TZ_MAX_TYPES || 366 sp->timecnt < 0 || sp->timecnt > TZ_MAX_TIMES || 367 sp->charcnt < 0 || sp->charcnt > TZ_MAX_CHARS || 368 (ttisstdcnt != sp->typecnt && ttisstdcnt != 0)) 369 return -1; 370 if (i < sizeof *tzhp + 371 sp->timecnt * (4 + sizeof (char)) + 372 sp->typecnt * (4 + 2 * sizeof (char)) + 373 sp->charcnt * sizeof (char) + 374 leapcnt * 2 * 4 + 375 ttisstdcnt * sizeof (char)) 376 return -1; 377 if (allocall(sp) < 0) 378 return -1; 379 p = buf + sizeof *tzhp; 380 for (i = 0; i < sp->timecnt; ++i) { 381 sp->ats[i] = detzcode(p); 382 p += 4; 383 } 384 for (i = 0; i < sp->timecnt; ++i) { 385 sp->types[i] = (unsigned char) *p++; 386 if (sp->types[i] >= sp->typecnt) 387 return -1; 388 } 389 for (i = 0; i < sp->typecnt; ++i) { 390 register struct ttinfo * ttisp; 391 392 ttisp = &sp->ttis[i]; 393 ttisp->tt_gmtoff = detzcode(p); 394 p += 4; 395 ttisp->tt_isdst = (unsigned char) *p++; 396 if (ttisp->tt_isdst != 0 && ttisp->tt_isdst != 1) 397 return -1; 398 ttisp->tt_abbrind = (unsigned char) *p++; 399 if (ttisp->tt_abbrind < 0 || 400 ttisp->tt_abbrind > sp->charcnt) 401 return -1; 402 } 403 for (i = 0; i < sp->charcnt-1; ++i) 404 sp->chars[i] = *p++; 405 sp->chars[i] = '\0'; /* ensure '\0' at end */ 406 p += (4 + 4) * leapcnt; /* skip leap seconds list */ 407 for (i = 0; i < sp->typecnt; ++i) { 408 register struct ttinfo * ttisp; 409 410 ttisp = &sp->ttis[i]; 411 if (ttisstdcnt == 0) 412 ttisp->tt_ttisstd = FALSE; 413 else { 414 ttisp->tt_ttisstd = *p++; 415 if (ttisp->tt_ttisstd != TRUE && 416 ttisp->tt_ttisstd != FALSE) 417 return -1; 418 } 419 } 420 } 421 if (sp->last_tzload) 422 free(sp->last_tzload); 423 sp->last_tzload = strdup(name); 424 return 0; 425 } 426 427 static const int mon_lengths[2][MONSPERYEAR] = { 428 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 429 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 430 }; 431 432 static const int year_lengths[2] = { 433 DAYSPERNYEAR, DAYSPERLYEAR 434 }; 435 436 /* 437 ** Given a pointer into a time zone string, scan until a character that is not 438 ** a valid character in a zone name is found. Return a pointer to that 439 ** character. 440 ** Support both quoted and unquoted timezones. 441 */ 442 443 static const char * 444 getzname(strp, quoted) 445 const char * strp; 446 int quoted; 447 { 448 unsigned char c; 449 450 if (quoted) { 451 while ((c = (unsigned char)*strp) != '\0' && 452 (isalnum(c) || (c == '+') || (c == '-'))) 453 ++strp; 454 } else { 455 while ((c = (unsigned char)*strp) != '\0' && !isdigit(c) 456 && (c != ',') && (c != '-') && (c != '+')) 457 ++strp; 458 } 459 return strp; 460 } 461 462 /* 463 ** Given a pointer into a time zone string, extract a number from that string. 464 ** Check that the number is within a specified range; if it is not, return 465 ** NULL. 466 ** Otherwise, return a pointer to the first character not part of the number. 467 */ 468 469 static const char * 470 getnum(strp, nump, min, max) 471 register const char * strp; 472 int * const nump; 473 const int min; 474 const int max; 475 { 476 register char c; 477 register int num; 478 479 if (strp == NULL || !isdigit(*strp)) 480 return NULL; 481 num = 0; 482 while ((c = *strp) != '\0' && isdigit(c)) { 483 num = num * 10 + (c - '0'); 484 if (num > max) 485 return NULL; /* illegal value */ 486 ++strp; 487 } 488 if (num < min) 489 return NULL; /* illegal value */ 490 *nump = num; 491 return strp; 492 } 493 494 /* 495 ** Given a pointer into a time zone string, extract a number of seconds, 496 ** in hh[:mm[:ss]] form, from the string. 497 ** If any error occurs, return NULL. 498 ** Otherwise, return a pointer to the first character not part of the number 499 ** of seconds. 500 */ 501 502 static const char * 503 getsecs(strp, secsp) 504 register const char * strp; 505 long * const secsp; 506 { 507 int num; 508 509 strp = getnum(strp, &num, 0, HOURSPERDAY); 510 if (strp == NULL) 511 return NULL; 512 *secsp = num * SECSPERHOUR; 513 if (*strp == ':') { 514 ++strp; 515 strp = getnum(strp, &num, 0, MINSPERHOUR - 1); 516 if (strp == NULL) 517 return NULL; 518 *secsp += num * SECSPERMIN; 519 if (*strp == ':') { 520 ++strp; 521 strp = getnum(strp, &num, 0, SECSPERMIN - 1); 522 if (strp == NULL) 523 return NULL; 524 *secsp += num; 525 } 526 } 527 return strp; 528 } 529 530 /* 531 ** Given a pointer into a time zone string, extract an offset, in 532 ** [+-]hh[:mm[:ss]] form, from the string. 533 ** If any error occurs, return NULL. 534 ** Otherwise, return a pointer to the first character not part of the time. 535 */ 536 537 static const char * 538 getoffset(strp, offsetp) 539 register const char * strp; 540 long * const offsetp; 541 { 542 register int neg; 543 544 if (*strp == '-') { 545 neg = 1; 546 ++strp; 547 } else if (isdigit(*strp) || *strp++ == '+') 548 neg = 0; 549 else return NULL; /* illegal offset */ 550 strp = getsecs(strp, offsetp); 551 if (strp == NULL) 552 return NULL; /* illegal time */ 553 if (neg) 554 *offsetp = -*offsetp; 555 return strp; 556 } 557 558 /* 559 ** Given a pointer into a time zone string, extract a rule in the form 560 ** date[/time]. See POSIX section 8 for the format of "date" and "time". 561 ** If a valid rule is not found, return NULL. 562 ** Otherwise, return a pointer to the first character not part of the rule. 563 */ 564 565 static const char * 566 getrule(strp, rulep) 567 const char * strp; 568 register struct rule * const rulep; 569 { 570 if (*strp == 'J') { 571 /* 572 ** Julian day. 573 */ 574 rulep->r_type = JULIAN_DAY; 575 ++strp; 576 strp = getnum(strp, &rulep->r_day, 1, DAYSPERNYEAR); 577 } else if (*strp == 'M') { 578 /* 579 ** Month, week, day. 580 */ 581 rulep->r_type = MONTH_NTH_DAY_OF_WEEK; 582 ++strp; 583 strp = getnum(strp, &rulep->r_mon, 1, MONSPERYEAR); 584 if (strp == NULL) 585 return NULL; 586 if (*strp++ != '.') 587 return NULL; 588 strp = getnum(strp, &rulep->r_week, 1, 5); 589 if (strp == NULL) 590 return NULL; 591 if (*strp++ != '.') 592 return NULL; 593 strp = getnum(strp, &rulep->r_day, 0, DAYSPERWEEK - 1); 594 } else if (isdigit(*strp)) { 595 /* 596 ** Day of year. 597 */ 598 rulep->r_type = DAY_OF_YEAR; 599 strp = getnum(strp, &rulep->r_day, 0, DAYSPERLYEAR - 1); 600 } else return NULL; /* invalid format */ 601 if (strp == NULL) 602 return NULL; 603 if (*strp == '/') { 604 /* 605 ** Time specified. 606 */ 607 ++strp; 608 strp = getsecs(strp, &rulep->r_time); 609 } else rulep->r_time = 2 * SECSPERHOUR; /* default = 2:00:00 */ 610 return strp; 611 } 612 613 /* 614 ** Given the Epoch-relative time of January 1, 00:00:00 GMT, in a year, the 615 ** year, a rule, and the offset from GMT at the time that rule takes effect, 616 ** calculate the Epoch-relative time that rule takes effect. 617 */ 618 619 static time_t 620 transtime(janfirst, year, rulep, offset) 621 const time_t janfirst; 622 const int year; 623 register const struct rule * const rulep; 624 const long offset; 625 { 626 register int leapyear; 627 register time_t value; 628 register int i; 629 int d, m1, yy0, yy1, yy2, dow; 630 631 leapyear = isleap(year); 632 switch (rulep->r_type) { 633 634 case JULIAN_DAY: 635 /* 636 ** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap 637 ** years. 638 ** In non-leap years, or if the day number is 59 or less, just 639 ** add SECSPERDAY times the day number-1 to the time of 640 ** January 1, midnight, to get the day. 641 */ 642 value = janfirst + (rulep->r_day - 1) * SECSPERDAY; 643 if (leapyear && rulep->r_day >= 60) 644 value += SECSPERDAY; 645 break; 646 647 case DAY_OF_YEAR: 648 /* 649 ** n - day of year. 650 ** Just add SECSPERDAY times the day number to the time of 651 ** January 1, midnight, to get the day. 652 */ 653 value = janfirst + rulep->r_day * SECSPERDAY; 654 break; 655 656 case MONTH_NTH_DAY_OF_WEEK: 657 /* 658 ** Mm.n.d - nth "dth day" of month m. 659 */ 660 value = janfirst; 661 for (i = 0; i < rulep->r_mon - 1; ++i) 662 value += mon_lengths[leapyear][i] * SECSPERDAY; 663 664 /* 665 ** Use Zeller's Congruence to get day-of-week of first day of 666 ** month. 667 */ 668 m1 = (rulep->r_mon + 9) % 12 + 1; 669 yy0 = (rulep->r_mon <= 2) ? (year - 1) : year; 670 yy1 = yy0 / 100; 671 yy2 = yy0 % 100; 672 dow = ((26 * m1 - 2) / 10 + 673 1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7; 674 if (dow < 0) 675 dow += DAYSPERWEEK; 676 677 /* 678 ** "dow" is the day-of-week of the first day of the month. Get 679 ** the day-of-month (zero-origin) of the first "dow" day of the 680 ** month. 681 */ 682 d = rulep->r_day - dow; 683 if (d < 0) 684 d += DAYSPERWEEK; 685 for (i = 1; i < rulep->r_week; ++i) { 686 if (d + DAYSPERWEEK >= 687 mon_lengths[leapyear][rulep->r_mon - 1]) 688 break; 689 d += DAYSPERWEEK; 690 } 691 692 /* 693 ** "d" is the day-of-month (zero-origin) of the day we want. 694 */ 695 value += d * SECSPERDAY; 696 break; 697 } 698 699 /* 700 ** "value" is the Epoch-relative time of 00:00:00 GMT on the day in 701 ** question. To get the Epoch-relative time of the specified local 702 ** time on that day, add the transition time and the current offset 703 ** from GMT. 704 */ 705 return value + rulep->r_time + offset; 706 } 707 708 /* 709 ** Given a POSIX section 8-style TZ string, fill in the rule tables as 710 ** appropriate. 711 */ 712 713 static int 714 tzparse(name, sp, lastditch) 715 const char * name; 716 struct state * const sp; 717 const int lastditch; 718 { 719 const char * stdname; 720 const char * dstname; 721 int stdlen; 722 int dstlen; 723 long stdoffset; 724 long dstoffset; 725 time_t * atp; 726 unsigned char * typep; 727 char * cp; 728 729 freeall(sp); /* */ 730 stdname = name; 731 if (lastditch) { 732 stdlen = strlen(name); /* length of standard zone name */ 733 name += stdlen; 734 if (stdlen >= sizeof sp->chars) 735 stdlen = (sizeof sp->chars) - 1; 736 } else { 737 if (*name == '<') { 738 name++; 739 stdname++; 740 name = getzname(name, 1); 741 if (*name != '>') { 742 return (-1); 743 } 744 stdlen = name - stdname; 745 name++; 746 } else { 747 name = getzname(name, 0); 748 stdlen = name - stdname; 749 } 750 if (stdlen < 3) 751 return -1; 752 } 753 if (*name == '\0') 754 stdoffset = 0; 755 else { 756 name = getoffset(name, &stdoffset); 757 if (name == NULL) 758 return -1; 759 } 760 if (*name != '\0') { 761 dstname = name; 762 if (*name == '<') { 763 name++; 764 dstname++; 765 name = getzname(name, 1); 766 if (*name != '>') { 767 return (-1); 768 } 769 dstlen = name - dstname; 770 name++; 771 } else { 772 name = getzname(name, 0); 773 dstlen = name - dstname; 774 } 775 if (dstlen < 3) 776 return -1; 777 if (*name != '\0' && *name != ',' && *name != ';') { 778 name = getoffset(name, &dstoffset); 779 if (name == NULL) 780 return -1; 781 } else dstoffset = stdoffset - SECSPERHOUR; 782 if (*name == ',' || *name == ';') { 783 struct rule start; 784 struct rule end; 785 register int year; 786 register time_t janfirst; 787 time_t starttime; 788 time_t endtime; 789 790 ++name; 791 if ((name = getrule(name, &start)) == NULL) 792 return -1; 793 if (*name++ != ',') 794 return -1; 795 if ((name = getrule(name, &end)) == NULL) 796 return -1; 797 if (*name != '\0') 798 return -1; 799 sp->typecnt = 2; /* standard time and DST */ 800 /* 801 ** Two transitions per year, from EPOCH_YEAR to 2037. 802 */ 803 sp->timecnt = 2 * (2037 - EPOCH_YEAR + 1); 804 if (sp->timecnt > TZ_MAX_TIMES) 805 return -1; 806 sp->charcnt = stdlen + 1 + dstlen + 1; 807 if (allocall(sp) < 0) 808 return -1; 809 sp->ttis[0].tt_gmtoff = -dstoffset; 810 sp->ttis[0].tt_isdst = 1; 811 sp->ttis[0].tt_abbrind = stdlen + 1; 812 sp->ttis[1].tt_gmtoff = -stdoffset; 813 sp->ttis[1].tt_isdst = 0; 814 sp->ttis[1].tt_abbrind = 0; 815 atp = sp->ats; 816 typep = sp->types; 817 janfirst = 0; 818 for (year = EPOCH_YEAR; year <= 2037; ++year) { 819 starttime = transtime(janfirst, year, &start, 820 stdoffset); 821 endtime = transtime(janfirst, year, &end, 822 dstoffset); 823 if (starttime > endtime) { 824 *atp++ = endtime; 825 *typep++ = 1; /* DST ends */ 826 *atp++ = starttime; 827 *typep++ = 0; /* DST begins */ 828 } else { 829 *atp++ = starttime; 830 *typep++ = 0; /* DST begins */ 831 *atp++ = endtime; 832 *typep++ = 1; /* DST ends */ 833 } 834 janfirst += 835 year_lengths[isleap(year)] * SECSPERDAY; 836 } 837 } else { 838 int sawstd; 839 int sawdst; 840 long stdfix; 841 long dstfix; 842 long oldfix; 843 int isdst; 844 register int i; 845 846 if (*name != '\0') 847 return -1; 848 if (tzload(TZDEFRULES, sp) != 0) { 849 freeall(sp); 850 return -1; 851 } 852 /* 853 ** Discard zone abbreviations from file, and allocate 854 ** space for the ones from TZ. 855 */ 856 free(sp->chars); 857 sp->charcnt = stdlen + 1 + dstlen + 1; 858 sp->chars = (char *)calloc((unsigned)sp->charcnt, 859 (unsigned)sizeof (char)); 860 /* 861 ** Compute the difference between the real and 862 ** prototype standard and summer time offsets 863 ** from GMT, and put the real standard and summer 864 ** time offsets into the rules in place of the 865 ** prototype offsets. 866 */ 867 sawstd = FALSE; 868 sawdst = FALSE; 869 stdfix = 0; 870 dstfix = 0; 871 for (i = 0; i < sp->typecnt; ++i) { 872 if (sp->ttis[i].tt_isdst) { 873 oldfix = dstfix; 874 dstfix = 875 sp->ttis[i].tt_gmtoff + dstoffset; 876 if (sawdst && (oldfix != dstfix)) 877 return -1; 878 sp->ttis[i].tt_gmtoff = -dstoffset; 879 sp->ttis[i].tt_abbrind = stdlen + 1; 880 sawdst = TRUE; 881 } else { 882 oldfix = stdfix; 883 stdfix = 884 sp->ttis[i].tt_gmtoff + stdoffset; 885 if (sawstd && (oldfix != stdfix)) 886 return -1; 887 sp->ttis[i].tt_gmtoff = -stdoffset; 888 sp->ttis[i].tt_abbrind = 0; 889 sawstd = TRUE; 890 } 891 } 892 /* 893 ** Make sure we have both standard and summer time. 894 */ 895 if (!sawdst || !sawstd) 896 return -1; 897 /* 898 ** Now correct the transition times by shifting 899 ** them by the difference between the real and 900 ** prototype offsets. Note that this difference 901 ** can be different in standard and summer time; 902 ** the prototype probably has a 1-hour difference 903 ** between standard and summer time, but a different 904 ** difference can be specified in TZ. 905 */ 906 isdst = FALSE; /* we start in standard time */ 907 for (i = 0; i < sp->timecnt; ++i) { 908 register const struct ttinfo * ttisp; 909 910 /* 911 ** If summer time is in effect, and the 912 ** transition time was not specified as 913 ** standard time, add the summer time 914 ** offset to the transition time; 915 ** otherwise, add the standard time offset 916 ** to the transition time. 917 */ 918 ttisp = &sp->ttis[sp->types[i]]; 919 sp->ats[i] += 920 (isdst && !ttisp->tt_ttisstd) ? 921 dstfix : stdfix; 922 isdst = ttisp->tt_isdst; 923 } 924 } 925 } else { 926 dstlen = 0; 927 sp->typecnt = 1; /* only standard time */ 928 sp->timecnt = 0; 929 sp->charcnt = stdlen + 1; 930 if (allocall(sp) < 0) 931 return -1; 932 sp->ttis[0].tt_gmtoff = -stdoffset; 933 sp->ttis[0].tt_isdst = 0; 934 sp->ttis[0].tt_abbrind = 0; 935 } 936 cp = sp->chars; 937 (void) strncpy(cp, stdname, stdlen); 938 cp += stdlen; 939 *cp++ = '\0'; 940 if (dstlen != 0) { 941 (void) strncpy(cp, dstname, dstlen); 942 *(cp + dstlen) = '\0'; 943 } 944 return 0; 945 } 946 947 static void 948 gmtload(sp) 949 struct state * const sp; 950 { 951 if (tzload(GMT, sp) != 0) 952 (void) tzparse(GMT, sp, TRUE); 953 } 954 955 void 956 tzsetwall() 957 { 958 lcl_is_set = TRUE; 959 if (lclptr == NULL) { 960 lclptr = (struct state *) calloc(1, (unsigned)sizeof *lclptr); 961 if (lclptr == NULL) { 962 #ifdef S5EMUL 963 settzname(); /* all we can do */ 964 #endif 965 return; 966 } 967 } 968 if (tzload((char *) NULL, lclptr) != 0) 969 gmtload(lclptr); 970 #ifdef S5EMUL 971 settzname(); 972 #endif 973 } 974 975 void 976 tzset() 977 { 978 register const char * name; 979 980 name = (const char *)getenv("TZ"); 981 if (name == NULL) { 982 tzsetwall(); 983 return; 984 } 985 lcl_is_set = TRUE; 986 if (lclptr == NULL) { 987 lclptr = (struct state *) calloc(1, (unsigned)sizeof *lclptr); 988 if (lclptr == NULL) { 989 #ifdef S5EMUL 990 settzname(); /* all we can do */ 991 #endif 992 return; 993 } 994 } 995 if (*name == '\0') { 996 /* 997 ** User wants it fast rather than right. 998 */ 999 lclptr->timecnt = 0; 1000 lclptr->typecnt = 1; 1001 lclptr->charcnt = sizeof GMT; 1002 if (allocall(lclptr) < 0) 1003 return; 1004 lclptr->ttis[0].tt_gmtoff = 0; 1005 lclptr->ttis[0].tt_abbrind = 0; 1006 (void) strcpy(lclptr->chars, GMT); 1007 } else if (tzload(name, lclptr) != 0) 1008 if (name[0] == ':' || tzparse(name, lclptr, FALSE) != 0) 1009 (void) tzparse(name, lclptr, TRUE); 1010 #ifdef S5EMUL 1011 settzname(); 1012 #endif 1013 } 1014 1015 /* 1016 ** The easy way to behave "as if no library function calls" localtime 1017 ** is to not call it--so we drop its guts into "localsub", which can be 1018 ** freely called. (And no, the PANS doesn't require the above behavior-- 1019 ** but it *is* desirable.) 1020 ** 1021 ** The unused offset argument is for the benefit of mktime variants. 1022 */ 1023 1024 static struct tm tm; 1025 1026 /*ARGSUSED*/ 1027 static void 1028 localsub(timep, offset, tmp) 1029 const time_t * const timep; 1030 const long offset; 1031 struct tm * const tmp; 1032 { 1033 register const struct state * sp; 1034 register const struct ttinfo * ttisp; 1035 register int i; 1036 const time_t t = *timep; 1037 1038 if (!lcl_is_set) 1039 tzset(); 1040 sp = lclptr; 1041 if (sp == NULL) { 1042 gmtsub(timep, offset, tmp); 1043 return; 1044 } 1045 if (sp->timecnt == 0 || t < sp->ats[0]) { 1046 i = 0; 1047 while (sp->ttis[i].tt_isdst) 1048 if (++i >= sp->typecnt) { 1049 i = 0; 1050 break; 1051 } 1052 } else { 1053 for (i = 1; i < sp->timecnt; ++i) 1054 if (t < sp->ats[i]) 1055 break; 1056 i = sp->types[i - 1]; 1057 } 1058 ttisp = &sp->ttis[i]; 1059 timesub(&t, ttisp->tt_gmtoff, tmp); 1060 tmp->tm_isdst = ttisp->tt_isdst; 1061 #ifdef S5EMUL 1062 tzname[tmp->tm_isdst] = (char *) &sp->chars[ttisp->tt_abbrind]; 1063 #endif /* S5EMUL */ 1064 tmp->tm_zone = &sp->chars[ttisp->tt_abbrind]; 1065 } 1066 1067 struct tm * 1068 localtime(timep) 1069 const time_t * const timep; 1070 { 1071 time_t temp_time = *(const time_t*)timep; 1072 1073 _ltzset(&temp_time); /* 1074 * base localtime calls this to initialize 1075 * some things, so we'll do it here, too. 1076 */ 1077 localsub(timep, 0L, &tm); 1078 return &tm; 1079 } 1080 1081 /* 1082 ** gmtsub is to gmtime as localsub is to localtime. 1083 */ 1084 1085 static void 1086 gmtsub(timep, offset, tmp) 1087 const time_t * const timep; 1088 const long offset; 1089 struct tm * const tmp; 1090 { 1091 if (!gmt_is_set) { 1092 gmt_is_set = TRUE; 1093 gmtptr = (struct state *) calloc(1, (unsigned)sizeof *gmtptr); 1094 if (gmtptr != NULL) 1095 gmtload(gmtptr); 1096 } 1097 timesub(timep, offset, tmp); 1098 /* 1099 ** Could get fancy here and deliver something such as 1100 ** "GMT+xxxx" or "GMT-xxxx" if offset is non-zero, 1101 ** but this is no time for a treasure hunt. 1102 */ 1103 if (offset != 0) 1104 tmp->tm_zone = (char *)WILDABBR; 1105 else { 1106 if (gmtptr == NULL) 1107 tmp->tm_zone = (char *)GMT; 1108 else tmp->tm_zone = gmtptr->chars; 1109 } 1110 } 1111 1112 struct tm * 1113 gmtime(timep) 1114 const time_t * const timep; 1115 { 1116 gmtsub(timep, 0L, &tm); 1117 return &tm; 1118 } 1119 1120 struct tm * 1121 offtime(timep, offset) 1122 const time_t * const timep; 1123 const long offset; 1124 { 1125 gmtsub(timep, offset, &tm); 1126 return &tm; 1127 } 1128 1129 static void 1130 timesub(timep, offset, tmp) 1131 const time_t * const timep; 1132 const long offset; 1133 register struct tm * const tmp; 1134 { 1135 register long days; 1136 register long rem; 1137 register int y; 1138 register int yleap; 1139 register const int * ip; 1140 1141 days = *timep / SECSPERDAY; 1142 rem = *timep % SECSPERDAY; 1143 rem += offset; 1144 while (rem < 0) { 1145 rem += SECSPERDAY; 1146 --days; 1147 } 1148 while (rem >= SECSPERDAY) { 1149 rem -= SECSPERDAY; 1150 ++days; 1151 } 1152 tmp->tm_hour = (int) (rem / SECSPERHOUR); 1153 rem = rem % SECSPERHOUR; 1154 tmp->tm_min = (int) (rem / SECSPERMIN); 1155 tmp->tm_sec = (int) (rem % SECSPERMIN); 1156 tmp->tm_wday = (int) ((EPOCH_WDAY + days) % DAYSPERWEEK); 1157 if (tmp->tm_wday < 0) 1158 tmp->tm_wday += DAYSPERWEEK; 1159 y = EPOCH_YEAR; 1160 if (days >= 0) 1161 for ( ; ; ) { 1162 yleap = isleap(y); 1163 if (days < (long) year_lengths[yleap]) 1164 break; 1165 ++y; 1166 days = days - (long) year_lengths[yleap]; 1167 } 1168 else do { 1169 --y; 1170 yleap = isleap(y); 1171 days = days + (long) year_lengths[yleap]; 1172 } while (days < 0); 1173 tmp->tm_year = y - TM_YEAR_BASE; 1174 tmp->tm_yday = (int) days; 1175 ip = mon_lengths[yleap]; 1176 for (tmp->tm_mon = 0; days >= (long) ip[tmp->tm_mon]; ++(tmp->tm_mon)) 1177 days = days - (long) ip[tmp->tm_mon]; 1178 tmp->tm_mday = (int) (days + 1); 1179 tmp->tm_isdst = 0; 1180 tmp->tm_gmtoff = offset; 1181 } 1182 1183 /* 1184 ** Adapted from code provided by Robert Elz, who writes: 1185 ** The "best" way to do mktime I think is based on an idea of Bob 1186 ** Kridle's (so its said...) from a long time ago. (mtxinu!kridle now). 1187 ** It does a binary search of the time_t space. Since time_t's are 1188 ** just 32 bits, its a max of 32 iterations (even at 64 bits it 1189 ** would still be very reasonable). 1190 */ 1191 1192 #ifndef WRONG 1193 #define WRONG (-1) 1194 #endif /* !defined WRONG */ 1195 1196 static void 1197 normalize(tensptr, unitsptr, base) 1198 int * const tensptr; 1199 int * const unitsptr; 1200 const int base; 1201 { 1202 int tmp; 1203 1204 if (*unitsptr >= base) { 1205 *tensptr += *unitsptr / base; 1206 *unitsptr %= base; 1207 } else if (*unitsptr < 0) { 1208 /* tmp has the range 0 to abs(*unitptr) -1 */ 1209 tmp = -1 - (*unitsptr); 1210 *tensptr -= (tmp/base + 1); 1211 *unitsptr = (base - 1) - (tmp % base); 1212 } 1213 } 1214 1215 static int 1216 tmcomp(atmp, btmp) 1217 register const struct tm * const atmp; 1218 register const struct tm * const btmp; 1219 { 1220 register int result; 1221 1222 if ((result = (atmp->tm_year - btmp->tm_year)) == 0 && 1223 (result = (atmp->tm_mon - btmp->tm_mon)) == 0 && 1224 (result = (atmp->tm_mday - btmp->tm_mday)) == 0 && 1225 (result = (atmp->tm_hour - btmp->tm_hour)) == 0 && 1226 (result = (atmp->tm_min - btmp->tm_min)) == 0) 1227 result = atmp->tm_sec - btmp->tm_sec; 1228 return result; 1229 } 1230 1231 static time_t 1232 time2(tmp, funcp, offset, okayp) 1233 struct tm * const tmp; 1234 void (* const funcp)(); 1235 const long offset; 1236 int * const okayp; 1237 { 1238 register const struct state * sp; 1239 register int dir; 1240 register int bits; 1241 register int i, j ; 1242 register int saved_seconds; 1243 time_t newt; 1244 time_t t; 1245 struct tm yourtm, mytm; 1246 1247 *okayp = FALSE; 1248 yourtm = *tmp; 1249 if (yourtm.tm_sec >= SECSPERMIN + 2 || yourtm.tm_sec < 0) 1250 normalize(&yourtm.tm_min, &yourtm.tm_sec, SECSPERMIN); 1251 normalize(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR); 1252 normalize(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY); 1253 normalize(&yourtm.tm_year, &yourtm.tm_mon, MONSPERYEAR); 1254 while (yourtm.tm_mday <= 0) { 1255 if (yourtm.tm_mon == 0) { 1256 yourtm.tm_mon = 12; 1257 --yourtm.tm_year; 1258 } 1259 yourtm.tm_mday += 1260 mon_lengths[isleap(yourtm.tm_year + 1261 TM_YEAR_BASE)][--yourtm.tm_mon]; 1262 if (yourtm.tm_mon >= MONSPERYEAR) { 1263 yourtm.tm_mon = 0; 1264 --yourtm.tm_year; 1265 } 1266 } 1267 for ( ; ; ) { 1268 i = mon_lengths[isleap(yourtm.tm_year + 1269 TM_YEAR_BASE)][yourtm.tm_mon]; 1270 if (yourtm.tm_mday <= i) 1271 break; 1272 yourtm.tm_mday -= i; 1273 if (++yourtm.tm_mon >= MONSPERYEAR) { 1274 yourtm.tm_mon = 0; 1275 ++yourtm.tm_year; 1276 } 1277 } 1278 saved_seconds = yourtm.tm_sec; 1279 yourtm.tm_sec = 0; 1280 /* 1281 ** Calculate the number of magnitude bits in a time_t 1282 ** (this works regardless of whether time_t is 1283 ** signed or unsigned, though lint complains if unsigned). 1284 */ 1285 for (bits = 0, t = 1; t > 0; ++bits, t <<= 1) 1286 ; 1287 /* 1288 ** If time_t is signed, then 0 is the median value, 1289 ** if time_t is unsigned, then 1 << bits is median. 1290 */ 1291 t = (t < 0) ? 0 : ((time_t) 1 << bits); 1292 for ( ; ; ) { 1293 (*funcp)(&t, offset, &mytm); 1294 dir = tmcomp(&mytm, &yourtm); 1295 if (dir != 0) { 1296 if (bits-- < 0) 1297 return WRONG; 1298 if (bits < 0) 1299 --t; 1300 else if (dir > 0) 1301 t -= (time_t) 1 << bits; 1302 else t += (time_t) 1 << bits; 1303 continue; 1304 } 1305 if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst) 1306 break; 1307 /* 1308 ** Right time, wrong type. 1309 ** Hunt for right time, right type. 1310 ** It's okay to guess wrong since the guess 1311 ** gets checked. 1312 */ 1313 sp = (const struct state *) 1314 ((funcp == localsub) ? lclptr : gmtptr); 1315 if (sp == NULL) 1316 return WRONG; 1317 for (i = 0; i < sp->typecnt; ++i) { 1318 if (sp->ttis[i].tt_isdst != yourtm.tm_isdst) 1319 continue; 1320 for (j = 0; j < sp->typecnt; ++j) { 1321 if (sp->ttis[j].tt_isdst == yourtm.tm_isdst) 1322 continue; 1323 newt = t + sp->ttis[j].tt_gmtoff - 1324 sp->ttis[i].tt_gmtoff; 1325 (*funcp)(&newt, offset, &mytm); 1326 if (tmcomp(&mytm, &yourtm) != 0) 1327 continue; 1328 if (mytm.tm_isdst != yourtm.tm_isdst) 1329 continue; 1330 /* 1331 ** We have a match. 1332 */ 1333 t = newt; 1334 goto label; 1335 } 1336 } 1337 return WRONG; 1338 } 1339 label: 1340 t += saved_seconds; 1341 (*funcp)(&t, offset, tmp); 1342 *okayp = TRUE; 1343 return t; 1344 } 1345 1346 static time_t 1347 time1(tmp, funcp, offset) 1348 struct tm * const tmp; 1349 void (* const funcp)(); 1350 const long offset; 1351 { 1352 register time_t t; 1353 register const struct state * sp; 1354 register int samei, otheri; 1355 int okay; 1356 1357 1358 if (tmp->tm_isdst > 1) 1359 tmp->tm_isdst = 1; 1360 t = time2(tmp, funcp, offset, &okay); 1361 if (okay || tmp->tm_isdst < 0) 1362 return t; 1363 /* 1364 ** We're supposed to assume that somebody took a time of one type 1365 ** and did some math on it that yielded a "struct tm" that's bad. 1366 ** We try to divine the type they started from and adjust to the 1367 ** type they need. 1368 */ 1369 sp = (const struct state *) ((funcp == localsub) ? lclptr : gmtptr); 1370 if (sp == NULL) 1371 return WRONG; 1372 for (samei = 0; samei < sp->typecnt; ++samei) { 1373 if (sp->ttis[samei].tt_isdst != tmp->tm_isdst) 1374 continue; 1375 for (otheri = 0; otheri < sp->typecnt; ++otheri) { 1376 if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst) 1377 continue; 1378 tmp->tm_sec += sp->ttis[otheri].tt_gmtoff - 1379 sp->ttis[samei].tt_gmtoff; 1380 tmp->tm_isdst = !tmp->tm_isdst; 1381 t = time2(tmp, funcp, offset, &okay); 1382 if (okay) 1383 return t; 1384 tmp->tm_sec -= sp->ttis[otheri].tt_gmtoff - 1385 sp->ttis[samei].tt_gmtoff; 1386 tmp->tm_isdst = !tmp->tm_isdst; 1387 } 1388 } 1389 return WRONG; 1390 } 1391 1392 time_t 1393 mktime(tmp) 1394 struct tm * const tmp; 1395 { 1396 return time1(tmp, localsub, 0L); 1397 } 1398 1399 time_t 1400 timelocal(tmp) 1401 struct tm * const tmp; 1402 { 1403 tmp->tm_isdst = -1; 1404 return mktime(tmp); 1405 } 1406 1407 time_t 1408 timegm(tmp) 1409 struct tm * const tmp; 1410 { 1411 return time1(tmp, gmtsub, 0L); 1412 } 1413 1414 time_t 1415 timeoff(tmp, offset) 1416 struct tm * const tmp; 1417 const long offset; 1418 { 1419 1420 return time1(tmp, gmtsub, offset); 1421 } 1422