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