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