1 /* $NetBSD: localtime.c,v 1.4 1995/03/16 19:14:16 jtc Exp $ */ 2 3 #ifndef lint 4 #ifndef NOID 5 static char elsieid[] = "@(#)localtime.c 7.43"; 6 #endif /* !defined NOID */ 7 #endif /* !defined lint */ 8 9 /* 10 ** Leap second handling from Bradley White (bww@k.gp.cs.cmu.edu). 11 ** POSIX-style TZ environment variable handling from Guy Harris 12 ** (guy@auspex.com). 13 */ 14 15 /*LINTLIBRARY*/ 16 17 #include "private.h" 18 #include "tzfile.h" 19 #include "fcntl.h" 20 21 /* 22 ** SunOS 4.1.1 headers lack O_BINARY. 23 */ 24 25 #ifdef O_BINARY 26 #define OPEN_MODE (O_RDONLY | O_BINARY) 27 #endif /* defined O_BINARY */ 28 #ifndef O_BINARY 29 #define OPEN_MODE O_RDONLY 30 #endif /* !defined O_BINARY */ 31 32 #ifndef WILDABBR 33 /* 34 ** Someone might make incorrect use of a time zone abbreviation: 35 ** 1. They might reference tzname[0] before calling tzset (explicitly 36 ** or implicitly). 37 ** 2. They might reference tzname[1] before calling tzset (explicitly 38 ** or implicitly). 39 ** 3. They might reference tzname[1] after setting to a time zone 40 ** in which Daylight Saving Time is never observed. 41 ** 4. They might reference tzname[0] after setting to a time zone 42 ** in which Standard Time is never observed. 43 ** 5. They might reference tm.TM_ZONE after calling offtime. 44 ** What's best to do in the above cases is open to debate; 45 ** for now, we just set things up so that in any of the five cases 46 ** WILDABBR is used. Another possibility: initialize tzname[0] to the 47 ** string "tzname[0] used before set", and similarly for the other cases. 48 ** And another: initialize tzname[0] to "ERA", with an explanation in the 49 ** manual page of what this "time zone abbreviation" means (doing this so 50 ** that tzname[0] has the "normal" length of three characters). 51 */ 52 #define WILDABBR " " 53 #endif /* !defined WILDABBR */ 54 55 static char wildabbr[] = "WILDABBR"; 56 57 static const char gmt[] = "GMT"; 58 59 struct ttinfo { /* time type information */ 60 long tt_gmtoff; /* GMT offset in seconds */ 61 int tt_isdst; /* used to set tm_isdst */ 62 int tt_abbrind; /* abbreviation list index */ 63 int tt_ttisstd; /* TRUE if transition is std time */ 64 int tt_ttisgmt; /* TRUE if transition is GMT */ 65 }; 66 67 struct lsinfo { /* leap second information */ 68 time_t ls_trans; /* transition time */ 69 long ls_corr; /* correction to apply */ 70 }; 71 72 #define BIGGEST(a, b) (((a) > (b)) ? (a) : (b)) 73 74 #ifdef TZNAME_MAX 75 #define MY_TZNAME_MAX TZNAME_MAX 76 #endif /* defined TZNAME_MAX */ 77 #ifndef TZNAME_MAX 78 #define MY_TZNAME_MAX 255 79 #endif /* !defined TZNAME_MAX */ 80 81 struct state { 82 int leapcnt; 83 int timecnt; 84 int typecnt; 85 int charcnt; 86 time_t ats[TZ_MAX_TIMES]; 87 unsigned char types[TZ_MAX_TIMES]; 88 struct ttinfo ttis[TZ_MAX_TYPES]; 89 char chars[BIGGEST(BIGGEST(TZ_MAX_CHARS + 1, sizeof gmt), 90 (2 * (MY_TZNAME_MAX + 1)))]; 91 struct lsinfo lsis[TZ_MAX_LEAPS]; 92 }; 93 94 struct rule { 95 int r_type; /* type of rule--see below */ 96 int r_day; /* day number of rule */ 97 int r_week; /* week number of rule */ 98 int r_mon; /* month number of rule */ 99 long r_time; /* transition time of rule */ 100 }; 101 102 #define JULIAN_DAY 0 /* Jn - Julian day */ 103 #define DAY_OF_YEAR 1 /* n - day of year */ 104 #define MONTH_NTH_DAY_OF_WEEK 2 /* Mm.n.d - month, week, day of week */ 105 106 /* 107 ** Prototypes for static functions. 108 */ 109 110 static long detzcode P((const char * codep)); 111 static const char * getzname P((const char * strp)); 112 static const char * getnum P((const char * strp, int * nump, int min, 113 int max)); 114 static const char * getsecs P((const char * strp, long * secsp)); 115 static const char * getoffset P((const char * strp, long * offsetp)); 116 static const char * getrule P((const char * strp, struct rule * rulep)); 117 static void gmtload P((struct state * sp)); 118 static void gmtsub P((const time_t * timep, long offset, 119 struct tm * tmp)); 120 static void localsub P((const time_t * timep, long offset, 121 struct tm * tmp)); 122 static int increment_overflow P((int * number, int delta)); 123 static int normalize_overflow P((int * tensptr, int * unitsptr, 124 int base)); 125 static void settzname P((void)); 126 static time_t time1 P((struct tm * tmp, 127 void(*funcp) P((const time_t *, 128 long, struct tm *)), 129 long offset)); 130 static time_t time2 P((struct tm *tmp, 131 void(*funcp) P((const time_t *, 132 long, struct tm*)), 133 long offset, int * okayp)); 134 static void timesub P((const time_t * timep, long offset, 135 const struct state * sp, struct tm * tmp)); 136 static int tmcomp P((const struct tm * atmp, 137 const struct tm * btmp)); 138 static time_t transtime P((time_t janfirst, int year, 139 const struct rule * rulep, long offset)); 140 static int tzload P((const char * name, struct state * sp)); 141 static int tzparse P((const char * name, struct state * sp, 142 int lastditch)); 143 144 #ifdef ALL_STATE 145 static struct state * lclptr; 146 static struct state * gmtptr; 147 #endif /* defined ALL_STATE */ 148 149 #ifndef ALL_STATE 150 static struct state lclmem; 151 static struct state gmtmem; 152 #define lclptr (&lclmem) 153 #define gmtptr (&gmtmem) 154 #endif /* State Farm */ 155 156 #ifndef TZ_STRLEN_MAX 157 #define TZ_STRLEN_MAX 255 158 #endif /* !defined TZ_STRLEN_MAX */ 159 160 static char lcl_TZname[TZ_STRLEN_MAX + 1]; 161 static int lcl_is_set; 162 static int gmt_is_set; 163 164 char * tzname[2] = { 165 wildabbr, 166 wildabbr 167 }; 168 169 /* 170 ** Section 4.12.3 of X3.159-1989 requires that 171 ** Except for the strftime function, these functions [asctime, 172 ** ctime, gmtime, localtime] return values in one of two static 173 ** objects: a broken-down time structure and an array of char. 174 ** Thanks to Paul Eggert (eggert@twinsun.com) for noting this. 175 */ 176 177 static struct tm tm; 178 179 #ifdef USG_COMPAT 180 time_t timezone = 0; 181 int daylight = 0; 182 #endif /* defined USG_COMPAT */ 183 184 #ifdef ALTZONE 185 time_t altzone = 0; 186 #endif /* defined ALTZONE */ 187 188 static long 189 detzcode(codep) 190 const char * const codep; 191 { 192 register long result; 193 194 /* 195 ** The first character must be sign extended on systems with >32bit 196 ** longs. This was solved differently in the master tzcode sources 197 ** (the fix first appeared in tzcode95c.tar.gz). But I believe 198 ** that this implementation is superior. 199 */ 200 201 #ifdef __STDC__ 202 #define SIGN_EXTEND_CHAR(x) ((signed char) x) 203 #else 204 #define SIGN_EXTEND_CHAR(x) ((x & 0x80) ? ((~0 << 8) | x) : x) 205 #endif 206 207 result = (SIGN_EXTEND_CHAR(codep[0]) << 24) \ 208 | (codep[1] & 0xff) << 16 \ 209 | (codep[2] & 0xff) << 8 210 | (codep[3] & 0xff); 211 return result; 212 } 213 214 static void 215 settzname P((void)) 216 { 217 register struct state * const sp = lclptr; 218 register int i; 219 220 tzname[0] = wildabbr; 221 tzname[1] = wildabbr; 222 #ifdef USG_COMPAT 223 daylight = 0; 224 timezone = 0; 225 #endif /* defined USG_COMPAT */ 226 #ifdef ALTZONE 227 altzone = 0; 228 #endif /* defined ALTZONE */ 229 #ifdef ALL_STATE 230 if (sp == NULL) { 231 tzname[0] = tzname[1] = gmt; 232 return; 233 } 234 #endif /* defined ALL_STATE */ 235 for (i = 0; i < sp->typecnt; ++i) { 236 register const struct ttinfo * const ttisp = &sp->ttis[i]; 237 238 tzname[ttisp->tt_isdst] = 239 &sp->chars[ttisp->tt_abbrind]; 240 #ifdef USG_COMPAT 241 if (ttisp->tt_isdst) 242 daylight = 1; 243 if (i == 0 || !ttisp->tt_isdst) 244 timezone = -(ttisp->tt_gmtoff); 245 #endif /* defined USG_COMPAT */ 246 #ifdef ALTZONE 247 if (i == 0 || ttisp->tt_isdst) 248 altzone = -(ttisp->tt_gmtoff); 249 #endif /* defined ALTZONE */ 250 } 251 /* 252 ** And to get the latest zone names into tzname. . . 253 */ 254 for (i = 0; i < sp->timecnt; ++i) { 255 register const struct ttinfo * const ttisp = 256 &sp->ttis[ 257 sp->types[i]]; 258 259 tzname[ttisp->tt_isdst] = 260 &sp->chars[ttisp->tt_abbrind]; 261 } 262 } 263 264 static int 265 tzload(name, sp) 266 register const char * name; 267 register struct state * const sp; 268 { 269 register const char * p; 270 register int i; 271 register int fid; 272 273 if (name == NULL && (name = TZDEFAULT) == NULL) 274 return -1; 275 { 276 register int doaccess; 277 /* 278 ** Section 4.9.1 of the C standard says that 279 ** "FILENAME_MAX expands to an integral constant expression 280 ** that is the sie needed for an array of char large enough 281 ** to hold the longest file name string that the implementation 282 ** guarantees can be opened." 283 */ 284 char fullname[FILENAME_MAX + 1]; 285 286 if (name[0] == ':') 287 ++name; 288 doaccess = name[0] == '/'; 289 if (!doaccess) { 290 if ((p = TZDIR) == NULL) 291 return -1; 292 if ((strlen(p) + strlen(name) + 1) >= sizeof fullname) 293 return -1; 294 (void) strcpy(fullname, p); 295 (void) strcat(fullname, "/"); 296 (void) strcat(fullname, name); 297 /* 298 ** Set doaccess if '.' (as in "../") shows up in name. 299 */ 300 if (strchr(name, '.') != NULL) 301 doaccess = TRUE; 302 name = fullname; 303 } 304 if (doaccess && access(name, R_OK) != 0) 305 return -1; 306 if ((fid = open(name, OPEN_MODE)) == -1) 307 return -1; 308 } 309 { 310 struct tzhead * tzhp; 311 char buf[sizeof *sp + sizeof *tzhp]; 312 int ttisstdcnt; 313 int ttisgmtcnt; 314 315 i = read(fid, buf, sizeof buf); 316 if (close(fid) != 0) 317 return -1; 318 p = buf; 319 p += sizeof tzhp->tzh_reserved; 320 ttisstdcnt = (int) detzcode(p); 321 p += 4; 322 ttisgmtcnt = (int) detzcode(p); 323 p += 4; 324 sp->leapcnt = (int) detzcode(p); 325 p += 4; 326 sp->timecnt = (int) detzcode(p); 327 p += 4; 328 sp->typecnt = (int) detzcode(p); 329 p += 4; 330 sp->charcnt = (int) detzcode(p); 331 p += 4; 332 if (sp->leapcnt < 0 || sp->leapcnt > TZ_MAX_LEAPS || 333 sp->typecnt <= 0 || sp->typecnt > TZ_MAX_TYPES || 334 sp->timecnt < 0 || sp->timecnt > TZ_MAX_TIMES || 335 sp->charcnt < 0 || sp->charcnt > TZ_MAX_CHARS || 336 (ttisstdcnt != sp->typecnt && ttisstdcnt != 0) || 337 (ttisgmtcnt != sp->typecnt && ttisgmtcnt != 0)) 338 return -1; 339 if (i - (p - buf) < sp->timecnt * 4 + /* ats */ 340 sp->timecnt + /* types */ 341 sp->typecnt * (4 + 2) + /* ttinfos */ 342 sp->charcnt + /* chars */ 343 sp->leapcnt * (4 + 4) + /* lsinfos */ 344 ttisstdcnt + /* ttisstds */ 345 ttisgmtcnt) /* ttisgmts */ 346 return -1; 347 for (i = 0; i < sp->timecnt; ++i) { 348 sp->ats[i] = detzcode(p); 349 p += 4; 350 } 351 for (i = 0; i < sp->timecnt; ++i) { 352 sp->types[i] = (unsigned char) *p++; 353 if (sp->types[i] >= sp->typecnt) 354 return -1; 355 } 356 for (i = 0; i < sp->typecnt; ++i) { 357 register struct ttinfo * ttisp; 358 359 ttisp = &sp->ttis[i]; 360 ttisp->tt_gmtoff = detzcode(p); 361 p += 4; 362 ttisp->tt_isdst = (unsigned char) *p++; 363 if (ttisp->tt_isdst != 0 && ttisp->tt_isdst != 1) 364 return -1; 365 ttisp->tt_abbrind = (unsigned char) *p++; 366 if (ttisp->tt_abbrind < 0 || 367 ttisp->tt_abbrind > sp->charcnt) 368 return -1; 369 } 370 for (i = 0; i < sp->charcnt; ++i) 371 sp->chars[i] = *p++; 372 sp->chars[i] = '\0'; /* ensure '\0' at end */ 373 for (i = 0; i < sp->leapcnt; ++i) { 374 register struct lsinfo * lsisp; 375 376 lsisp = &sp->lsis[i]; 377 lsisp->ls_trans = detzcode(p); 378 p += 4; 379 lsisp->ls_corr = detzcode(p); 380 p += 4; 381 } 382 for (i = 0; i < sp->typecnt; ++i) { 383 register struct ttinfo * ttisp; 384 385 ttisp = &sp->ttis[i]; 386 if (ttisstdcnt == 0) 387 ttisp->tt_ttisstd = FALSE; 388 else { 389 ttisp->tt_ttisstd = *p++; 390 if (ttisp->tt_ttisstd != TRUE && 391 ttisp->tt_ttisstd != FALSE) 392 return -1; 393 } 394 } 395 for (i = 0; i < sp->typecnt; ++i) { 396 register struct ttinfo * ttisp; 397 398 ttisp = &sp->ttis[i]; 399 if (ttisgmtcnt == 0) 400 ttisp->tt_ttisgmt = FALSE; 401 else { 402 ttisp->tt_ttisgmt = *p++; 403 if (ttisp->tt_ttisgmt != TRUE && 404 ttisp->tt_ttisgmt != FALSE) 405 return -1; 406 } 407 } 408 } 409 return 0; 410 } 411 412 static const int mon_lengths[2][MONSPERYEAR] = { 413 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, 414 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } 415 }; 416 417 static const int year_lengths[2] = { 418 DAYSPERNYEAR, DAYSPERLYEAR 419 }; 420 421 /* 422 ** Given a pointer into a time zone string, scan until a character that is not 423 ** a valid character in a zone name is found. Return a pointer to that 424 ** character. 425 */ 426 427 static const char * 428 getzname(strp) 429 register const char * strp; 430 { 431 register char c; 432 433 while ((c = *strp) != '\0' && !isdigit(c) && c != ',' && c != '-' && 434 c != '+') 435 ++strp; 436 return strp; 437 } 438 439 /* 440 ** Given a pointer into a time zone string, extract a number from that string. 441 ** Check that the number is within a specified range; if it is not, return 442 ** NULL. 443 ** Otherwise, return a pointer to the first character not part of the number. 444 */ 445 446 static const char * 447 getnum(strp, nump, min, max) 448 register const char * strp; 449 int * const nump; 450 const int min; 451 const int max; 452 { 453 register char c; 454 register int num; 455 456 if (strp == NULL || !isdigit(*strp)) 457 return NULL; 458 num = 0; 459 while ((c = *strp) != '\0' && isdigit(c)) { 460 num = num * 10 + (c - '0'); 461 if (num > max) 462 return NULL; /* illegal value */ 463 ++strp; 464 } 465 if (num < min) 466 return NULL; /* illegal value */ 467 *nump = num; 468 return strp; 469 } 470 471 /* 472 ** Given a pointer into a time zone string, extract a number of seconds, 473 ** in hh[:mm[:ss]] form, from the string. 474 ** If any error occurs, return NULL. 475 ** Otherwise, return a pointer to the first character not part of the number 476 ** of seconds. 477 */ 478 479 static const char * 480 getsecs(strp, secsp) 481 register const char * strp; 482 long * const secsp; 483 { 484 int num; 485 486 /* 487 ** `HOURSPERDAY * DAYSPERWEEK - 1' allows quasi-Posix rules like 488 ** "M10.4.6/26", which does not conform to Posix, 489 ** but which specifies the equivalent of 490 ** ``02:00 on the first Sunday on or after 23 Oct''. 491 */ 492 strp = getnum(strp, &num, 0, HOURSPERDAY * DAYSPERWEEK - 1); 493 if (strp == NULL) 494 return NULL; 495 *secsp = num * (long) SECSPERHOUR; 496 if (*strp == ':') { 497 ++strp; 498 strp = getnum(strp, &num, 0, MINSPERHOUR - 1); 499 if (strp == NULL) 500 return NULL; 501 *secsp += num * SECSPERMIN; 502 if (*strp == ':') { 503 ++strp; 504 /* `SECSPERMIN' allows for leap seconds. */ 505 strp = getnum(strp, &num, 0, SECSPERMIN); 506 if (strp == NULL) 507 return NULL; 508 *secsp += num; 509 } 510 } 511 return strp; 512 } 513 514 /* 515 ** Given a pointer into a time zone string, extract an offset, in 516 ** [+-]hh[:mm[:ss]] form, from the string. 517 ** If any error occurs, return NULL. 518 ** Otherwise, return a pointer to the first character not part of the time. 519 */ 520 521 static const char * 522 getoffset(strp, offsetp) 523 register const char * strp; 524 long * const offsetp; 525 { 526 register int neg; 527 528 if (*strp == '-') { 529 neg = 1; 530 ++strp; 531 } else if (isdigit(*strp) || *strp++ == '+') 532 neg = 0; 533 else return NULL; /* illegal offset */ 534 strp = getsecs(strp, offsetp); 535 if (strp == NULL) 536 return NULL; /* illegal time */ 537 if (neg) 538 *offsetp = -*offsetp; 539 return strp; 540 } 541 542 /* 543 ** Given a pointer into a time zone string, extract a rule in the form 544 ** date[/time]. See POSIX section 8 for the format of "date" and "time". 545 ** If a valid rule is not found, return NULL. 546 ** Otherwise, return a pointer to the first character not part of the rule. 547 */ 548 549 static const char * 550 getrule(strp, rulep) 551 const char * strp; 552 register struct rule * const rulep; 553 { 554 if (*strp == 'J') { 555 /* 556 ** Julian day. 557 */ 558 rulep->r_type = JULIAN_DAY; 559 ++strp; 560 strp = getnum(strp, &rulep->r_day, 1, DAYSPERNYEAR); 561 } else if (*strp == 'M') { 562 /* 563 ** Month, week, day. 564 */ 565 rulep->r_type = MONTH_NTH_DAY_OF_WEEK; 566 ++strp; 567 strp = getnum(strp, &rulep->r_mon, 1, MONSPERYEAR); 568 if (strp == NULL) 569 return NULL; 570 if (*strp++ != '.') 571 return NULL; 572 strp = getnum(strp, &rulep->r_week, 1, 5); 573 if (strp == NULL) 574 return NULL; 575 if (*strp++ != '.') 576 return NULL; 577 strp = getnum(strp, &rulep->r_day, 0, DAYSPERWEEK - 1); 578 } else if (isdigit(*strp)) { 579 /* 580 ** Day of year. 581 */ 582 rulep->r_type = DAY_OF_YEAR; 583 strp = getnum(strp, &rulep->r_day, 0, DAYSPERLYEAR - 1); 584 } else return NULL; /* invalid format */ 585 if (strp == NULL) 586 return NULL; 587 if (*strp == '/') { 588 /* 589 ** Time specified. 590 */ 591 ++strp; 592 strp = getsecs(strp, &rulep->r_time); 593 } else rulep->r_time = 2 * SECSPERHOUR; /* default = 2:00:00 */ 594 return strp; 595 } 596 597 /* 598 ** Given the Epoch-relative time of January 1, 00:00:00 GMT, in a year, the 599 ** year, a rule, and the offset from GMT at the time that rule takes effect, 600 ** calculate the Epoch-relative time that rule takes effect. 601 */ 602 603 static time_t 604 transtime(janfirst, year, rulep, offset) 605 const time_t janfirst; 606 const int year; 607 register const struct rule * const rulep; 608 const long offset; 609 { 610 register int leapyear; 611 register time_t value; 612 register int i; 613 int d, m1, yy0, yy1, yy2, dow; 614 615 INITIALIZE(value); 616 leapyear = isleap(year); 617 switch (rulep->r_type) { 618 619 case JULIAN_DAY: 620 /* 621 ** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap 622 ** years. 623 ** In non-leap years, or if the day number is 59 or less, just 624 ** add SECSPERDAY times the day number-1 to the time of 625 ** January 1, midnight, to get the day. 626 */ 627 value = janfirst + (rulep->r_day - 1) * SECSPERDAY; 628 if (leapyear && rulep->r_day >= 60) 629 value += SECSPERDAY; 630 break; 631 632 case DAY_OF_YEAR: 633 /* 634 ** n - day of year. 635 ** Just add SECSPERDAY times the day number to the time of 636 ** January 1, midnight, to get the day. 637 */ 638 value = janfirst + rulep->r_day * SECSPERDAY; 639 break; 640 641 case MONTH_NTH_DAY_OF_WEEK: 642 /* 643 ** Mm.n.d - nth "dth day" of month m. 644 */ 645 value = janfirst; 646 for (i = 0; i < rulep->r_mon - 1; ++i) 647 value += mon_lengths[leapyear][i] * SECSPERDAY; 648 649 /* 650 ** Use Zeller's Congruence to get day-of-week of first day of 651 ** month. 652 */ 653 m1 = (rulep->r_mon + 9) % 12 + 1; 654 yy0 = (rulep->r_mon <= 2) ? (year - 1) : year; 655 yy1 = yy0 / 100; 656 yy2 = yy0 % 100; 657 dow = ((26 * m1 - 2) / 10 + 658 1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7; 659 if (dow < 0) 660 dow += DAYSPERWEEK; 661 662 /* 663 ** "dow" is the day-of-week of the first day of the month. Get 664 ** the day-of-month (zero-origin) of the first "dow" day of the 665 ** month. 666 */ 667 d = rulep->r_day - dow; 668 if (d < 0) 669 d += DAYSPERWEEK; 670 for (i = 1; i < rulep->r_week; ++i) { 671 if (d + DAYSPERWEEK >= 672 mon_lengths[leapyear][rulep->r_mon - 1]) 673 break; 674 d += DAYSPERWEEK; 675 } 676 677 /* 678 ** "d" is the day-of-month (zero-origin) of the day we want. 679 */ 680 value += d * SECSPERDAY; 681 break; 682 } 683 684 /* 685 ** "value" is the Epoch-relative time of 00:00:00 GMT on the day in 686 ** question. To get the Epoch-relative time of the specified local 687 ** time on that day, add the transition time and the current offset 688 ** from GMT. 689 */ 690 return value + rulep->r_time + offset; 691 } 692 693 /* 694 ** Given a POSIX section 8-style TZ string, fill in the rule tables as 695 ** appropriate. 696 */ 697 698 static int 699 tzparse(name, sp, lastditch) 700 const char * name; 701 register struct state * const sp; 702 const int lastditch; 703 { 704 const char * stdname; 705 const char * dstname; 706 size_t stdlen; 707 size_t dstlen; 708 long stdoffset; 709 long dstoffset; 710 register time_t * atp; 711 register unsigned char * typep; 712 register char * cp; 713 register int load_result; 714 715 INITIALIZE(dstname); 716 stdname = name; 717 if (lastditch) { 718 stdlen = strlen(name); /* length of standard zone name */ 719 name += stdlen; 720 if (stdlen >= sizeof sp->chars) 721 stdlen = (sizeof sp->chars) - 1; 722 } else { 723 name = getzname(name); 724 stdlen = name - stdname; 725 if (stdlen < 3) 726 return -1; 727 } 728 if (*name == '\0') 729 return -1; /* was "stdoffset = 0;" */ 730 else { 731 name = getoffset(name, &stdoffset); 732 if (name == NULL) 733 return -1; 734 } 735 load_result = tzload(TZDEFRULES, sp); 736 if (load_result != 0) 737 sp->leapcnt = 0; /* so, we're off a little */ 738 if (*name != '\0') { 739 dstname = name; 740 name = getzname(name); 741 dstlen = name - dstname; /* length of DST zone name */ 742 if (dstlen < 3) 743 return -1; 744 if (*name != '\0' && *name != ',' && *name != ';') { 745 name = getoffset(name, &dstoffset); 746 if (name == NULL) 747 return -1; 748 } else dstoffset = stdoffset - SECSPERHOUR; 749 if (*name == ',' || *name == ';') { 750 struct rule start; 751 struct rule end; 752 register int year; 753 register time_t janfirst; 754 time_t starttime; 755 time_t endtime; 756 757 ++name; 758 if ((name = getrule(name, &start)) == NULL) 759 return -1; 760 if (*name++ != ',') 761 return -1; 762 if ((name = getrule(name, &end)) == NULL) 763 return -1; 764 if (*name != '\0') 765 return -1; 766 sp->typecnt = 2; /* standard time and DST */ 767 /* 768 ** Two transitions per year, from EPOCH_YEAR to 2037. 769 */ 770 sp->timecnt = 2 * (2037 - EPOCH_YEAR + 1); 771 if (sp->timecnt > TZ_MAX_TIMES) 772 return -1; 773 sp->ttis[0].tt_gmtoff = -dstoffset; 774 sp->ttis[0].tt_isdst = 1; 775 sp->ttis[0].tt_abbrind = stdlen + 1; 776 sp->ttis[1].tt_gmtoff = -stdoffset; 777 sp->ttis[1].tt_isdst = 0; 778 sp->ttis[1].tt_abbrind = 0; 779 atp = sp->ats; 780 typep = sp->types; 781 janfirst = 0; 782 for (year = EPOCH_YEAR; year <= 2037; ++year) { 783 starttime = transtime(janfirst, year, &start, 784 stdoffset); 785 endtime = transtime(janfirst, year, &end, 786 dstoffset); 787 if (starttime > endtime) { 788 *atp++ = endtime; 789 *typep++ = 1; /* DST ends */ 790 *atp++ = starttime; 791 *typep++ = 0; /* DST begins */ 792 } else { 793 *atp++ = starttime; 794 *typep++ = 0; /* DST begins */ 795 *atp++ = endtime; 796 *typep++ = 1; /* DST ends */ 797 } 798 janfirst += year_lengths[isleap(year)] * 799 SECSPERDAY; 800 } 801 } else { 802 register long theirstdoffset; 803 register long theirdstoffset; 804 register long theiroffset; 805 register int isdst; 806 register int i; 807 register int j; 808 809 if (*name != '\0') 810 return -1; 811 if (load_result != 0) 812 return -1; 813 /* 814 ** Initial values of theirstdoffset and theirdstoffset. 815 */ 816 theirstdoffset = 0; 817 for (i = 0; i < sp->timecnt; ++i) { 818 j = sp->types[i]; 819 if (!sp->ttis[j].tt_isdst) { 820 theirstdoffset = -sp->ttis[j].tt_gmtoff; 821 break; 822 } 823 } 824 theirdstoffset = 0; 825 for (i = 0; i < sp->timecnt; ++i) { 826 j = sp->types[i]; 827 if (sp->ttis[j].tt_isdst) { 828 theirdstoffset = -sp->ttis[j].tt_gmtoff; 829 break; 830 } 831 } 832 /* 833 ** Initially we're assumed to be in standard time. 834 */ 835 isdst = FALSE; 836 theiroffset = theirstdoffset; 837 /* 838 ** Now juggle transition times and types 839 ** tracking offsets as you do. 840 */ 841 for (i = 0; i < sp->timecnt; ++i) { 842 j = sp->types[i]; 843 sp->types[i] = sp->ttis[j].tt_isdst; 844 if (sp->ttis[j].tt_ttisgmt) { 845 /* No adjustment to transition time */ 846 } else { 847 /* 848 ** If summer time is in effect, and the 849 ** transition time was not specified as 850 ** standard time, add the summer time 851 ** offset to the transition time; 852 ** otherwise, add the standard time 853 ** offset to the transition time. 854 */ 855 /* 856 ** Transitions from DST to DDST 857 ** will effectively disappear since 858 ** POSIX provides for only one DST 859 ** offset. 860 */ 861 if (isdst && !sp->ttis[j].tt_ttisstd) { 862 sp->ats[i] += dstoffset - 863 theirdstoffset; 864 } else { 865 sp->ats[i] += stdoffset - 866 theirstdoffset; 867 } 868 } 869 theiroffset = -sp->ttis[j].tt_gmtoff; 870 if (sp->ttis[j].tt_isdst) 871 theirdstoffset = theiroffset; 872 else theirstdoffset = theiroffset; 873 } 874 /* 875 ** Finally, fill in ttis. 876 ** ttisstd and ttisgmt need not be handled. 877 */ 878 sp->ttis[0].tt_gmtoff = -stdoffset; 879 sp->ttis[0].tt_isdst = FALSE; 880 sp->ttis[0].tt_abbrind = 0; 881 sp->ttis[1].tt_gmtoff = -dstoffset; 882 sp->ttis[1].tt_isdst = TRUE; 883 sp->ttis[1].tt_abbrind = stdlen + 1; 884 } 885 } else { 886 dstlen = 0; 887 sp->typecnt = 1; /* only standard time */ 888 sp->timecnt = 0; 889 sp->ttis[0].tt_gmtoff = -stdoffset; 890 sp->ttis[0].tt_isdst = 0; 891 sp->ttis[0].tt_abbrind = 0; 892 } 893 sp->charcnt = stdlen + 1; 894 if (dstlen != 0) 895 sp->charcnt += dstlen + 1; 896 if (sp->charcnt > sizeof sp->chars) 897 return -1; 898 cp = sp->chars; 899 (void) strncpy(cp, stdname, stdlen); 900 cp += stdlen; 901 *cp++ = '\0'; 902 if (dstlen != 0) { 903 (void) strncpy(cp, dstname, dstlen); 904 *(cp + dstlen) = '\0'; 905 } 906 return 0; 907 } 908 909 static void 910 gmtload(sp) 911 struct state * const sp; 912 { 913 if (tzload(gmt, sp) != 0) 914 (void) tzparse(gmt, sp, TRUE); 915 } 916 917 #ifndef STD_INSPIRED 918 /* 919 ** A non-static declaration of tzsetwall in a system header file 920 ** may cause a warning about this upcoming static declaration... 921 */ 922 static 923 #endif /* !defined STD_INSPIRED */ 924 void 925 tzsetwall P((void)) 926 { 927 if (lcl_is_set < 0) 928 return; 929 lcl_is_set = -1; 930 931 #ifdef ALL_STATE 932 if (lclptr == NULL) { 933 lclptr = (struct state *) malloc(sizeof *lclptr); 934 if (lclptr == NULL) { 935 settzname(); /* all we can do */ 936 return; 937 } 938 } 939 #endif /* defined ALL_STATE */ 940 if (tzload((char *) NULL, lclptr) != 0) 941 gmtload(lclptr); 942 settzname(); 943 } 944 945 void 946 tzset P((void)) 947 { 948 register const char * name; 949 950 name = getenv("TZ"); 951 if (name == NULL) { 952 tzsetwall(); 953 return; 954 } 955 956 if (lcl_is_set > 0 && strcmp(lcl_TZname, name) == 0) 957 return; 958 lcl_is_set = (strlen(name) < sizeof(lcl_TZname)); 959 if (lcl_is_set) 960 (void) strcpy(lcl_TZname, name); 961 962 #ifdef ALL_STATE 963 if (lclptr == NULL) { 964 lclptr = (struct state *) malloc(sizeof *lclptr); 965 if (lclptr == NULL) { 966 settzname(); /* all we can do */ 967 return; 968 } 969 } 970 #endif /* defined ALL_STATE */ 971 if (*name == '\0') { 972 /* 973 ** User wants it fast rather than right. 974 */ 975 lclptr->leapcnt = 0; /* so, we're off a little */ 976 lclptr->timecnt = 0; 977 lclptr->ttis[0].tt_gmtoff = 0; 978 lclptr->ttis[0].tt_abbrind = 0; 979 (void) strcpy(lclptr->chars, gmt); 980 } else if (tzload(name, lclptr) != 0) 981 if (name[0] == ':' || tzparse(name, lclptr, FALSE) != 0) 982 (void) gmtload(lclptr); 983 settzname(); 984 } 985 986 /* 987 ** The easy way to behave "as if no library function calls" localtime 988 ** is to not call it--so we drop its guts into "localsub", which can be 989 ** freely called. (And no, the PANS doesn't require the above behavior-- 990 ** but it *is* desirable.) 991 ** 992 ** The unused offset argument is for the benefit of mktime variants. 993 */ 994 995 /*ARGSUSED*/ 996 static void 997 localsub(timep, offset, tmp) 998 const time_t * const timep; 999 const long offset; 1000 struct tm * const tmp; 1001 { 1002 register struct state * sp; 1003 register const struct ttinfo * ttisp; 1004 register int i; 1005 const time_t t = *timep; 1006 1007 sp = lclptr; 1008 #ifdef ALL_STATE 1009 if (sp == NULL) { 1010 gmtsub(timep, offset, tmp); 1011 return; 1012 } 1013 #endif /* defined ALL_STATE */ 1014 if (sp->timecnt == 0 || t < sp->ats[0]) { 1015 i = 0; 1016 while (sp->ttis[i].tt_isdst) 1017 if (++i >= sp->typecnt) { 1018 i = 0; 1019 break; 1020 } 1021 } else { 1022 for (i = 1; i < sp->timecnt; ++i) 1023 if (t < sp->ats[i]) 1024 break; 1025 i = sp->types[i - 1]; 1026 } 1027 ttisp = &sp->ttis[i]; 1028 /* 1029 ** To get (wrong) behavior that's compatible with System V Release 2.0 1030 ** you'd replace the statement below with 1031 ** t += ttisp->tt_gmtoff; 1032 ** timesub(&t, 0L, sp, tmp); 1033 */ 1034 timesub(&t, ttisp->tt_gmtoff, sp, tmp); 1035 tmp->tm_isdst = ttisp->tt_isdst; 1036 tzname[tmp->tm_isdst] = &sp->chars[ttisp->tt_abbrind]; 1037 #ifdef TM_ZONE 1038 tmp->TM_ZONE = &sp->chars[ttisp->tt_abbrind]; 1039 #endif /* defined TM_ZONE */ 1040 } 1041 1042 struct tm * 1043 localtime(timep) 1044 const time_t * const timep; 1045 { 1046 tzset(); 1047 localsub(timep, 0L, &tm); 1048 return &tm; 1049 } 1050 1051 /* 1052 ** gmtsub is to gmtime as localsub is to localtime. 1053 */ 1054 1055 static void 1056 gmtsub(timep, offset, tmp) 1057 const time_t * const timep; 1058 const long offset; 1059 struct tm * const tmp; 1060 { 1061 if (!gmt_is_set) { 1062 gmt_is_set = TRUE; 1063 #ifdef ALL_STATE 1064 gmtptr = (struct state *) malloc(sizeof *gmtptr); 1065 if (gmtptr != NULL) 1066 #endif /* defined ALL_STATE */ 1067 gmtload(gmtptr); 1068 } 1069 timesub(timep, offset, gmtptr, tmp); 1070 #ifdef TM_ZONE 1071 /* 1072 ** Could get fancy here and deliver something such as 1073 ** "GMT+xxxx" or "GMT-xxxx" if offset is non-zero, 1074 ** but this is no time for a treasure hunt. 1075 */ 1076 if (offset != 0) 1077 tmp->TM_ZONE = wildabbr; 1078 else { 1079 #ifdef ALL_STATE 1080 if (gmtptr == NULL) 1081 tmp->TM_ZONE = gmt; 1082 else tmp->TM_ZONE = gmtptr->chars; 1083 #endif /* defined ALL_STATE */ 1084 #ifndef ALL_STATE 1085 tmp->TM_ZONE = gmtptr->chars; 1086 #endif /* State Farm */ 1087 } 1088 #endif /* defined TM_ZONE */ 1089 } 1090 1091 struct tm * 1092 gmtime(timep) 1093 const time_t * const timep; 1094 { 1095 gmtsub(timep, 0L, &tm); 1096 return &tm; 1097 } 1098 1099 #ifdef STD_INSPIRED 1100 1101 struct tm * 1102 offtime(timep, offset) 1103 const time_t * const timep; 1104 const long offset; 1105 { 1106 gmtsub(timep, offset, &tm); 1107 return &tm; 1108 } 1109 1110 #endif /* defined STD_INSPIRED */ 1111 1112 static void 1113 timesub(timep, offset, sp, tmp) 1114 const time_t * const timep; 1115 const long offset; 1116 register const struct state * const sp; 1117 register struct tm * const tmp; 1118 { 1119 register const struct lsinfo * lp; 1120 register long days; 1121 register long rem; 1122 register int y; 1123 register int yleap; 1124 register const int * ip; 1125 register long corr; 1126 register int hit; 1127 register int i; 1128 1129 corr = 0; 1130 hit = 0; 1131 #ifdef ALL_STATE 1132 i = (sp == NULL) ? 0 : sp->leapcnt; 1133 #endif /* defined ALL_STATE */ 1134 #ifndef ALL_STATE 1135 i = sp->leapcnt; 1136 #endif /* State Farm */ 1137 while (--i >= 0) { 1138 lp = &sp->lsis[i]; 1139 if (*timep >= lp->ls_trans) { 1140 if (*timep == lp->ls_trans) { 1141 hit = ((i == 0 && lp->ls_corr > 0) || 1142 lp->ls_corr > sp->lsis[i - 1].ls_corr); 1143 if (hit) 1144 while (i > 0 && 1145 sp->lsis[i].ls_trans == 1146 sp->lsis[i - 1].ls_trans + 1 && 1147 sp->lsis[i].ls_corr == 1148 sp->lsis[i - 1].ls_corr + 1) { 1149 ++hit; 1150 --i; 1151 } 1152 } 1153 corr = lp->ls_corr; 1154 break; 1155 } 1156 } 1157 days = *timep / SECSPERDAY; 1158 rem = *timep % SECSPERDAY; 1159 #ifdef mc68k 1160 if (*timep == 0x80000000) { 1161 /* 1162 ** A 3B1 muffs the division on the most negative number. 1163 */ 1164 days = -24855; 1165 rem = -11648; 1166 } 1167 #endif /* defined mc68k */ 1168 rem += (offset - corr); 1169 while (rem < 0) { 1170 rem += SECSPERDAY; 1171 --days; 1172 } 1173 while (rem >= SECSPERDAY) { 1174 rem -= SECSPERDAY; 1175 ++days; 1176 } 1177 tmp->tm_hour = (int) (rem / SECSPERHOUR); 1178 rem = rem % SECSPERHOUR; 1179 tmp->tm_min = (int) (rem / SECSPERMIN); 1180 tmp->tm_sec = (int) (rem % SECSPERMIN); 1181 if (hit) 1182 /* 1183 ** A positive leap second requires a special 1184 ** representation. This uses "... ??:59:60" et seq. 1185 */ 1186 tmp->tm_sec += hit; 1187 tmp->tm_wday = (int) ((EPOCH_WDAY + days) % DAYSPERWEEK); 1188 if (tmp->tm_wday < 0) 1189 tmp->tm_wday += DAYSPERWEEK; 1190 y = EPOCH_YEAR; 1191 if (days >= 0) 1192 for ( ; ; ) { 1193 yleap = isleap(y); 1194 if (days < (long) year_lengths[yleap]) 1195 break; 1196 ++y; 1197 days = days - (long) year_lengths[yleap]; 1198 } 1199 else do { 1200 --y; 1201 yleap = isleap(y); 1202 days = days + (long) year_lengths[yleap]; 1203 } while (days < 0); 1204 tmp->tm_year = y - TM_YEAR_BASE; 1205 tmp->tm_yday = (int) days; 1206 ip = mon_lengths[yleap]; 1207 for (tmp->tm_mon = 0; days >= (long) ip[tmp->tm_mon]; ++(tmp->tm_mon)) 1208 days = days - (long) ip[tmp->tm_mon]; 1209 tmp->tm_mday = (int) (days + 1); 1210 tmp->tm_isdst = 0; 1211 #ifdef TM_GMTOFF 1212 tmp->TM_GMTOFF = offset; 1213 #endif /* defined TM_GMTOFF */ 1214 } 1215 1216 char * 1217 ctime(timep) 1218 const time_t * const timep; 1219 { 1220 /* 1221 ** Section 4.12.3.2 of X3.159-1989 requires that 1222 ** The ctime funciton converts the calendar time pointed to by timer 1223 ** to local time in the form of a string. It is equivalent to 1224 ** asctime(localtime(timer)) 1225 */ 1226 return asctime(localtime(timep)); 1227 } 1228 1229 /* 1230 ** Adapted from code provided by Robert Elz, who writes: 1231 ** The "best" way to do mktime I think is based on an idea of Bob 1232 ** Kridle's (so its said...) from a long time ago. (mtxinu!kridle now). 1233 ** It does a binary search of the time_t space. Since time_t's are 1234 ** just 32 bits, its a max of 32 iterations (even at 64 bits it 1235 ** would still be very reasonable). 1236 */ 1237 1238 #ifndef WRONG 1239 #define WRONG (-1) 1240 #endif /* !defined WRONG */ 1241 1242 /* 1243 ** Simplified normalize logic courtesy Paul Eggert (eggert@twinsun.com). 1244 */ 1245 1246 static int 1247 increment_overflow(number, delta) 1248 int * number; 1249 int delta; 1250 { 1251 int number0; 1252 1253 number0 = *number; 1254 *number += delta; 1255 return (*number < number0) != (delta < 0); 1256 } 1257 1258 static int 1259 normalize_overflow(tensptr, unitsptr, base) 1260 int * const tensptr; 1261 int * const unitsptr; 1262 const int base; 1263 { 1264 register int tensdelta; 1265 1266 tensdelta = (*unitsptr >= 0) ? 1267 (*unitsptr / base) : 1268 (-1 - (-1 - *unitsptr) / base); 1269 *unitsptr -= tensdelta * base; 1270 return increment_overflow(tensptr, tensdelta); 1271 } 1272 1273 static int 1274 tmcomp(atmp, btmp) 1275 register const struct tm * const atmp; 1276 register const struct tm * const btmp; 1277 { 1278 register int result; 1279 1280 if ((result = (atmp->tm_year - btmp->tm_year)) == 0 && 1281 (result = (atmp->tm_mon - btmp->tm_mon)) == 0 && 1282 (result = (atmp->tm_mday - btmp->tm_mday)) == 0 && 1283 (result = (atmp->tm_hour - btmp->tm_hour)) == 0 && 1284 (result = (atmp->tm_min - btmp->tm_min)) == 0) 1285 result = atmp->tm_sec - btmp->tm_sec; 1286 return result; 1287 } 1288 1289 static time_t 1290 time2(tmp, funcp, offset, okayp) 1291 struct tm * const tmp; 1292 void (* const funcp) P((const time_t*, long, struct tm*)); 1293 const long offset; 1294 int * const okayp; 1295 { 1296 register const struct state * sp; 1297 register int dir; 1298 register int bits; 1299 register int i, j ; 1300 register int saved_seconds; 1301 time_t newt; 1302 time_t t; 1303 struct tm yourtm, mytm; 1304 1305 *okayp = FALSE; 1306 yourtm = *tmp; 1307 if (normalize_overflow(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR)) 1308 return WRONG; 1309 if (normalize_overflow(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY)) 1310 return WRONG; 1311 if (normalize_overflow(&yourtm.tm_year, &yourtm.tm_mon, MONSPERYEAR)) 1312 return WRONG; 1313 /* 1314 ** Turn yourtm.tm_year into an actual year number for now. 1315 ** It is converted back to an offset from TM_YEAR_BASE later. 1316 */ 1317 if (increment_overflow(&yourtm.tm_year, TM_YEAR_BASE)) 1318 return WRONG; 1319 while (yourtm.tm_mday <= 0) { 1320 if (increment_overflow(&yourtm.tm_year, -1)) 1321 return WRONG; 1322 yourtm.tm_mday += year_lengths[isleap(yourtm.tm_year)]; 1323 } 1324 while (yourtm.tm_mday > DAYSPERLYEAR) { 1325 yourtm.tm_mday -= year_lengths[isleap(yourtm.tm_year)]; 1326 if (increment_overflow(&yourtm.tm_year, 1)) 1327 return WRONG; 1328 } 1329 for ( ; ; ) { 1330 i = mon_lengths[isleap(yourtm.tm_year)][yourtm.tm_mon]; 1331 if (yourtm.tm_mday <= i) 1332 break; 1333 yourtm.tm_mday -= i; 1334 if (++yourtm.tm_mon >= MONSPERYEAR) { 1335 yourtm.tm_mon = 0; 1336 if (increment_overflow(&yourtm.tm_year, 1)) 1337 return WRONG; 1338 } 1339 } 1340 if (increment_overflow(&yourtm.tm_year, -TM_YEAR_BASE)) 1341 return WRONG; 1342 if (yourtm.tm_year + TM_YEAR_BASE < EPOCH_YEAR) { 1343 /* 1344 ** We can't set tm_sec to 0, because that might push the 1345 ** time below the minimum representable time. 1346 ** Set tm_sec to 59 instead. 1347 ** This assumes that the minimum representable time is 1348 ** not in the same minute that a leap second was deleted from, 1349 ** which is a safer assumption than using 58 would be. 1350 */ 1351 if (increment_overflow(&yourtm.tm_sec, 1 - SECSPERMIN)) 1352 return WRONG; 1353 saved_seconds = yourtm.tm_sec; 1354 yourtm.tm_sec = SECSPERMIN - 1; 1355 } else { 1356 saved_seconds = yourtm.tm_sec; 1357 yourtm.tm_sec = 0; 1358 } 1359 /* 1360 ** Calculate the number of magnitude bits in a time_t 1361 ** (this works regardless of whether time_t is 1362 ** signed or unsigned, though lint complains if unsigned). 1363 */ 1364 for (bits = 0, t = 1; t > 0; ++bits, t <<= 1) 1365 continue; 1366 /* 1367 ** If time_t is signed, then 0 is the median value, 1368 ** if time_t is unsigned, then 1 << bits is median. 1369 */ 1370 t = (t < 0) ? 0 : ((time_t) 1 << bits); 1371 for ( ; ; ) { 1372 (*funcp)(&t, offset, &mytm); 1373 dir = tmcomp(&mytm, &yourtm); 1374 if (dir != 0) { 1375 if (bits-- < 0) 1376 return WRONG; 1377 if (bits < 0) 1378 --t; 1379 else if (dir > 0) 1380 t -= (time_t) 1 << bits; 1381 else t += (time_t) 1 << bits; 1382 continue; 1383 } 1384 if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst) 1385 break; 1386 /* 1387 ** Right time, wrong type. 1388 ** Hunt for right time, right type. 1389 ** It's okay to guess wrong since the guess 1390 ** gets checked. 1391 */ 1392 /* 1393 ** The (void *) casts are the benefit of SunOS 3.3 on Sun 2's. 1394 */ 1395 sp = (const struct state *) 1396 (((void *) funcp == (void *) localsub) ? 1397 lclptr : gmtptr); 1398 #ifdef ALL_STATE 1399 if (sp == NULL) 1400 return WRONG; 1401 #endif /* defined ALL_STATE */ 1402 for (i = 0; i < sp->typecnt; ++i) { 1403 if (sp->ttis[i].tt_isdst != yourtm.tm_isdst) 1404 continue; 1405 for (j = 0; j < sp->typecnt; ++j) { 1406 if (sp->ttis[j].tt_isdst == yourtm.tm_isdst) 1407 continue; 1408 newt = t + sp->ttis[j].tt_gmtoff - 1409 sp->ttis[i].tt_gmtoff; 1410 (*funcp)(&newt, offset, &mytm); 1411 if (tmcomp(&mytm, &yourtm) != 0) 1412 continue; 1413 if (mytm.tm_isdst != yourtm.tm_isdst) 1414 continue; 1415 /* 1416 ** We have a match. 1417 */ 1418 t = newt; 1419 goto label; 1420 } 1421 } 1422 return WRONG; 1423 } 1424 label: 1425 newt = t + saved_seconds; 1426 if ((newt < t) != (saved_seconds < 0)) 1427 return WRONG; 1428 t = newt; 1429 (*funcp)(&t, offset, tmp); 1430 *okayp = TRUE; 1431 return t; 1432 } 1433 1434 static time_t 1435 time1(tmp, funcp, offset) 1436 struct tm * const tmp; 1437 void (* const funcp) P((const time_t*, long, struct tm*)); 1438 const long offset; 1439 { 1440 register time_t t; 1441 register const struct state * sp; 1442 register int samei, otheri; 1443 int okay; 1444 1445 if (tmp->tm_isdst > 1) 1446 tmp->tm_isdst = 1; 1447 t = time2(tmp, funcp, offset, &okay); 1448 #ifdef PCTS 1449 /* 1450 ** PCTS code courtesy Grant Sullivan (grant@osf.org). 1451 */ 1452 if (okay) 1453 return t; 1454 if (tmp->tm_isdst < 0) 1455 tmp->tm_isdst = 0; /* reset to std and try again */ 1456 #endif /* defined PCTS */ 1457 #ifndef PCTS 1458 if (okay || tmp->tm_isdst < 0) 1459 return t; 1460 #endif /* !defined PCTS */ 1461 /* 1462 ** We're supposed to assume that somebody took a time of one type 1463 ** and did some math on it that yielded a "struct tm" that's bad. 1464 ** We try to divine the type they started from and adjust to the 1465 ** type they need. 1466 */ 1467 /* 1468 ** The (void *) casts are the benefit of SunOS 3.3 on Sun 2's. 1469 */ 1470 sp = (const struct state *) (((void *) funcp == (void *) localsub) ? 1471 lclptr : gmtptr); 1472 #ifdef ALL_STATE 1473 if (sp == NULL) 1474 return WRONG; 1475 #endif /* defined ALL_STATE */ 1476 for (samei = 0; samei < sp->typecnt; ++samei) { 1477 if (sp->ttis[samei].tt_isdst != tmp->tm_isdst) 1478 continue; 1479 for (otheri = 0; otheri < sp->typecnt; ++otheri) { 1480 if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst) 1481 continue; 1482 tmp->tm_sec += sp->ttis[otheri].tt_gmtoff - 1483 sp->ttis[samei].tt_gmtoff; 1484 tmp->tm_isdst = !tmp->tm_isdst; 1485 t = time2(tmp, funcp, offset, &okay); 1486 if (okay) 1487 return t; 1488 tmp->tm_sec -= sp->ttis[otheri].tt_gmtoff - 1489 sp->ttis[samei].tt_gmtoff; 1490 tmp->tm_isdst = !tmp->tm_isdst; 1491 } 1492 } 1493 return WRONG; 1494 } 1495 1496 time_t 1497 mktime(tmp) 1498 struct tm * const tmp; 1499 { 1500 tzset(); 1501 return time1(tmp, localsub, 0L); 1502 } 1503 1504 #ifdef STD_INSPIRED 1505 1506 time_t 1507 timelocal(tmp) 1508 struct tm * const tmp; 1509 { 1510 tmp->tm_isdst = -1; /* in case it wasn't initialized */ 1511 return mktime(tmp); 1512 } 1513 1514 time_t 1515 timegm(tmp) 1516 struct tm * const tmp; 1517 { 1518 tmp->tm_isdst = 0; 1519 return time1(tmp, gmtsub, 0L); 1520 } 1521 1522 time_t 1523 timeoff(tmp, offset) 1524 struct tm * const tmp; 1525 const long offset; 1526 { 1527 tmp->tm_isdst = 0; 1528 return time1(tmp, gmtsub, offset); 1529 } 1530 1531 #endif /* defined STD_INSPIRED */ 1532 1533 #ifdef CMUCS 1534 1535 /* 1536 ** The following is supplied for compatibility with 1537 ** previous versions of the CMUCS runtime library. 1538 */ 1539 1540 long 1541 gtime(tmp) 1542 struct tm * const tmp; 1543 { 1544 const time_t t = mktime(tmp); 1545 1546 if (t == WRONG) 1547 return -1; 1548 return t; 1549 } 1550 1551 #endif /* defined CMUCS */ 1552 1553 /* 1554 ** XXX--is the below the right way to conditionalize?? 1555 */ 1556 1557 #ifdef STD_INSPIRED 1558 1559 /* 1560 ** IEEE Std 1003.1-1988 (POSIX) legislates that 536457599 1561 ** shall correspond to "Wed Dec 31 23:59:59 GMT 1986", which 1562 ** is not the case if we are accounting for leap seconds. 1563 ** So, we provide the following conversion routines for use 1564 ** when exchanging timestamps with POSIX conforming systems. 1565 */ 1566 1567 static long 1568 leapcorr(timep) 1569 time_t * timep; 1570 { 1571 register struct state * sp; 1572 register struct lsinfo * lp; 1573 register int i; 1574 1575 sp = lclptr; 1576 i = sp->leapcnt; 1577 while (--i >= 0) { 1578 lp = &sp->lsis[i]; 1579 if (*timep >= lp->ls_trans) 1580 return lp->ls_corr; 1581 } 1582 return 0; 1583 } 1584 1585 time_t 1586 time2posix(t) 1587 time_t t; 1588 { 1589 tzset(); 1590 return t - leapcorr(&t); 1591 } 1592 1593 time_t 1594 posix2time(t) 1595 time_t t; 1596 { 1597 time_t x; 1598 time_t y; 1599 1600 tzset(); 1601 /* 1602 ** For a positive leap second hit, the result 1603 ** is not unique. For a negative leap second 1604 ** hit, the corresponding time doesn't exist, 1605 ** so we return an adjacent second. 1606 */ 1607 x = t + leapcorr(&t); 1608 y = x - leapcorr(&x); 1609 if (y < t) { 1610 do { 1611 x++; 1612 y = x - leapcorr(&x); 1613 } while (y < t); 1614 if (t != y) 1615 return x - 1; 1616 } else if (y > t) { 1617 do { 1618 --x; 1619 y = x - leapcorr(&x); 1620 } while (y > t); 1621 if (t != y) 1622 return x + 1; 1623 } 1624 return x; 1625 } 1626 1627 #endif /* defined STD_INSPIRED */ 1628