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