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