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