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