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