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