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