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