1 /* 2 * Copyright (c) 1987, 1989, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Arthur David Olson of the National Cancer Institute. 7 * 8 * %sccs.include.redist.c% 9 */ 10 11 #if defined(LIBC_SCCS) && !defined(lint) 12 static char sccsid[] = "@(#)ctime.c 8.1 (Berkeley) 06/04/93"; 13 #endif /* LIBC_SCCS and not lint */ 14 15 /* 16 ** Leap second handling from Bradley White (bww@k.gp.cs.cmu.edu). 17 ** POSIX-style TZ environment variable handling from Guy Harris 18 ** (guy@auspex.com). 19 */ 20 21 /*LINTLIBRARY*/ 22 23 #include <sys/param.h> 24 #include <fcntl.h> 25 #include <time.h> 26 #include <tzfile.h> 27 #include <string.h> 28 #include <ctype.h> 29 #include <stdio.h> 30 #include <unistd.h> 31 32 #ifdef __STDC__ 33 #include <stdlib.h> 34 35 #define P(s) s 36 #define alloc_size_t size_t 37 #define qsort_size_t size_t 38 #define fread_size_t size_t 39 #define fwrite_size_t size_t 40 41 #else /* !defined __STDC__ */ 42 43 #define P(s) () 44 45 typedef char * genericptr_t; 46 typedef unsigned alloc_size_t; 47 typedef int qsort_size_t; 48 typedef int fread_size_t; 49 typedef int fwrite_size_t; 50 51 extern char * calloc(); 52 extern char * malloc(); 53 extern char * realloc(); 54 extern char * getenv(); 55 56 #endif /* !defined __STDC__ */ 57 58 extern time_t time(); 59 60 #define ACCESS_MODE O_RDONLY 61 #define OPEN_MODE O_RDONLY 62 63 #ifndef WILDABBR 64 /* 65 ** Someone might make incorrect use of a time zone abbreviation: 66 ** 1. They might reference tzname[0] before calling tzset (explicitly 67 ** or implicitly). 68 ** 2. They might reference tzname[1] before calling tzset (explicitly 69 ** or implicitly). 70 ** 3. They might reference tzname[1] after setting to a time zone 71 ** in which Daylight Saving Time is never observed. 72 ** 4. They might reference tzname[0] after setting to a time zone 73 ** in which Standard Time is never observed. 74 ** 5. They might reference tm.TM_ZONE after calling offtime. 75 ** What's best to do in the above cases is open to debate; 76 ** for now, we just set things up so that in any of the five cases 77 ** WILDABBR is used. Another possibility: initialize tzname[0] to the 78 ** string "tzname[0] used before set", and similarly for the other cases. 79 ** And another: initialize tzname[0] to "ERA", with an explanation in the 80 ** manual page of what this "time zone abbreviation" means (doing this so 81 ** that tzname[0] has the "normal" length of three characters). 82 */ 83 #define WILDABBR " " 84 #endif /* !defined WILDABBR */ 85 86 #ifndef TRUE 87 #define TRUE 1 88 #define FALSE 0 89 #endif /* !defined TRUE */ 90 91 static const char GMT[] = "GMT"; 92 93 struct ttinfo { /* time type information */ 94 long tt_gmtoff; /* GMT offset in seconds */ 95 int tt_isdst; /* used to set tm_isdst */ 96 int tt_abbrind; /* abbreviation list index */ 97 int tt_ttisstd; /* TRUE if transition is std time */ 98 }; 99 100 struct lsinfo { /* leap second information */ 101 time_t ls_trans; /* transition time */ 102 long ls_corr; /* correction to apply */ 103 }; 104 105 struct state { 106 int leapcnt; 107 int timecnt; 108 int typecnt; 109 int charcnt; 110 time_t ats[TZ_MAX_TIMES]; 111 unsigned char types[TZ_MAX_TIMES]; 112 struct ttinfo ttis[TZ_MAX_TYPES]; 113 char chars[(TZ_MAX_CHARS + 1 > sizeof GMT) ? 114 TZ_MAX_CHARS + 1 : sizeof GMT]; 115 struct lsinfo lsis[TZ_MAX_LEAPS]; 116 }; 117 118 struct rule { 119 int r_type; /* type of rule--see below */ 120 int r_day; /* day number of rule */ 121 int r_week; /* week number of rule */ 122 int r_mon; /* month number of rule */ 123 long r_time; /* transition time of rule */ 124 }; 125 126 #define JULIAN_DAY 0 /* Jn - Julian day */ 127 #define DAY_OF_YEAR 1 /* n - day of year */ 128 #define MONTH_NTH_DAY_OF_WEEK 2 /* Mm.n.d - month, week, day of week */ 129 130 /* 131 ** Prototypes for static functions. 132 */ 133 134 static long detzcode P((const char * codep)); 135 static const char * getzname P((const char * strp)); 136 static const char * getnum P((const char * strp, int * nump, int min, 137 int max)); 138 static const char * getsecs P((const char * strp, long * secsp)); 139 static const char * getoffset P((const char * strp, long * offsetp)); 140 static const char * getrule P((const char * strp, struct rule * rulep)); 141 static void gmtload P((struct state * sp)); 142 static void gmtsub P((const time_t * timep, long offset, 143 struct tm * tmp)); 144 static void localsub P((const time_t * timep, long offset, 145 struct tm * tmp)); 146 static void normalize P((int * tensptr, int * unitsptr, int base)); 147 static void settzname P((void)); 148 static time_t time1 P((struct tm * tmp, void (* funcp)(), 149 long offset)); 150 static time_t time2 P((struct tm *tmp, void (* funcp)(), 151 long offset, int * okayp)); 152 static void timesub P((const time_t * timep, long offset, 153 const struct state * sp, struct tm * tmp)); 154 static int tmcomp P((const struct tm * atmp, 155 const struct tm * btmp)); 156 static time_t transtime P((time_t janfirst, int year, 157 const struct rule * rulep, long offset)); 158 static int tzload P((const char * name, struct state * sp)); 159 static int tzparse P((const char * name, struct state * sp, 160 int lastditch)); 161 162 #ifdef ALL_STATE 163 static struct state * lclptr; 164 static struct state * gmtptr; 165 #endif /* defined ALL_STATE */ 166 167 #ifndef ALL_STATE 168 static struct state lclmem; 169 static struct state gmtmem; 170 #define lclptr (&lclmem) 171 #define gmtptr (&gmtmem) 172 #endif /* State Farm */ 173 174 static int lcl_is_set; 175 static int gmt_is_set; 176 177 char * tzname[2] = { 178 WILDABBR, 179 WILDABBR 180 }; 181 182 #ifdef USG_COMPAT 183 time_t timezone = 0; 184 int daylight = 0; 185 #endif /* defined USG_COMPAT */ 186 187 #ifdef ALTZONE 188 time_t altzone = 0; 189 #endif /* defined ALTZONE */ 190 191 static long 192 detzcode(codep) 193 const char * const codep; 194 { 195 register long result; 196 register int i; 197 198 result = 0; 199 for (i = 0; i < 4; ++i) 200 result = (result << 8) | (codep[i] & 0xff); 201 return result; 202 } 203 204 static void 205 settzname() 206 { 207 register const struct state * const sp = lclptr; 208 register int i; 209 210 tzname[0] = WILDABBR; 211 tzname[1] = WILDABBR; 212 #ifdef USG_COMPAT 213 daylight = 0; 214 timezone = 0; 215 #endif /* defined USG_COMPAT */ 216 #ifdef ALTZONE 217 altzone = 0; 218 #endif /* defined ALTZONE */ 219 #ifdef ALL_STATE 220 if (sp == NULL) { 221 tzname[0] = tzname[1] = GMT; 222 return; 223 } 224 #endif /* defined ALL_STATE */ 225 for (i = 0; i < sp->typecnt; ++i) { 226 register const struct ttinfo * const ttisp = &sp->ttis[i]; 227 228 tzname[ttisp->tt_isdst] = 229 (char *) &sp->chars[ttisp->tt_abbrind]; 230 #ifdef USG_COMPAT 231 if (ttisp->tt_isdst) 232 daylight = 1; 233 if (i == 0 || !ttisp->tt_isdst) 234 timezone = -(ttisp->tt_gmtoff); 235 #endif /* defined USG_COMPAT */ 236 #ifdef ALTZONE 237 if (i == 0 || ttisp->tt_isdst) 238 altzone = -(ttisp->tt_gmtoff); 239 #endif /* defined ALTZONE */ 240 } 241 /* 242 ** And to get the latest zone names into tzname. . . 243 */ 244 for (i = 0; i < sp->timecnt; ++i) { 245 register const struct ttinfo * const ttisp = 246 &sp->ttis[sp->types[i]]; 247 248 tzname[ttisp->tt_isdst] = 249 (char *) &sp->chars[ttisp->tt_abbrind]; 250 } 251 } 252 253 static int 254 tzload(name, sp) 255 register const char * name; 256 register struct state * const sp; 257 { 258 register const char * p; 259 register int i; 260 register int fid; 261 262 if (name == NULL && (name = TZDEFAULT) == NULL) 263 return -1; 264 { 265 char fullname[FILENAME_MAX + 1]; 266 267 if (name[0] == ':') 268 ++name; 269 if (name[0] != '/') { 270 if ((p = TZDIR) == NULL) 271 return -1; 272 if ((strlen(p) + strlen(name) + 1) >= sizeof fullname) 273 return -1; 274 (void) strcpy(fullname, p); 275 (void) strcat(fullname, "/"); 276 (void) strcat(fullname, name); 277 name = fullname; 278 } 279 if ((fid = open(name, OPEN_MODE)) == -1) 280 return -1; 281 } 282 { 283 register const struct tzhead * tzhp; 284 char buf[sizeof *sp + sizeof *tzhp]; 285 int ttisstdcnt; 286 287 i = read(fid, buf, sizeof buf); 288 if (close(fid) != 0 || i < sizeof *tzhp) 289 return -1; 290 tzhp = (struct tzhead *) buf; 291 ttisstdcnt = (int) detzcode(tzhp->tzh_ttisstdcnt); 292 sp->leapcnt = (int) detzcode(tzhp->tzh_leapcnt); 293 sp->timecnt = (int) detzcode(tzhp->tzh_timecnt); 294 sp->typecnt = (int) detzcode(tzhp->tzh_typecnt); 295 sp->charcnt = (int) detzcode(tzhp->tzh_charcnt); 296 if (sp->leapcnt < 0 || sp->leapcnt > TZ_MAX_LEAPS || 297 sp->typecnt <= 0 || sp->typecnt > TZ_MAX_TYPES || 298 sp->timecnt < 0 || sp->timecnt > TZ_MAX_TIMES || 299 sp->charcnt < 0 || sp->charcnt > TZ_MAX_CHARS || 300 (ttisstdcnt != sp->typecnt && ttisstdcnt != 0)) 301 return -1; 302 if (i < sizeof *tzhp + 303 sp->timecnt * (4 + sizeof (char)) + 304 sp->typecnt * (4 + 2 * sizeof (char)) + 305 sp->charcnt * sizeof (char) + 306 sp->leapcnt * 2 * 4 + 307 ttisstdcnt * sizeof (char)) 308 return -1; 309 p = buf + sizeof *tzhp; 310 for (i = 0; i < sp->timecnt; ++i) { 311 sp->ats[i] = detzcode(p); 312 p += 4; 313 } 314 for (i = 0; i < sp->timecnt; ++i) { 315 sp->types[i] = (unsigned char) *p++; 316 if (sp->types[i] >= sp->typecnt) 317 return -1; 318 } 319 for (i = 0; i < sp->typecnt; ++i) { 320 register struct ttinfo * ttisp; 321 322 ttisp = &sp->ttis[i]; 323 ttisp->tt_gmtoff = detzcode(p); 324 p += 4; 325 ttisp->tt_isdst = (unsigned char) *p++; 326 if (ttisp->tt_isdst != 0 && ttisp->tt_isdst != 1) 327 return -1; 328 ttisp->tt_abbrind = (unsigned char) *p++; 329 if (ttisp->tt_abbrind < 0 || 330 ttisp->tt_abbrind > sp->charcnt) 331 return -1; 332 } 333 for (i = 0; i < sp->charcnt; ++i) 334 sp->chars[i] = *p++; 335 sp->chars[i] = '\0'; /* ensure '\0' at end */ 336 for (i = 0; i < sp->leapcnt; ++i) { 337 register struct lsinfo * lsisp; 338 339 lsisp = &sp->lsis[i]; 340 lsisp->ls_trans = detzcode(p); 341 p += 4; 342 lsisp->ls_corr = detzcode(p); 343 p += 4; 344 } 345 for (i = 0; i < sp->typecnt; ++i) { 346 register struct ttinfo * ttisp; 347 348 ttisp = &sp->ttis[i]; 349 if (ttisstdcnt == 0) 350 ttisp->tt_ttisstd = FALSE; 351 else { 352 ttisp->tt_ttisstd = *p++; 353 if (ttisp->tt_ttisstd != TRUE && 354 ttisp->tt_ttisstd != FALSE) 355 return -1; 356 } 357 } 358 } 359 return 0; 360 } 361 362 static const int mon_lengths[2][MONSPERYEAR] = { 363 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 364 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 365 }; 366 367 static const int year_lengths[2] = { 368 DAYSPERNYEAR, DAYSPERLYEAR 369 }; 370 371 /* 372 ** Given a pointer into a time zone string, scan until a character that is not 373 ** a valid character in a zone name is found. Return a pointer to that 374 ** character. 375 */ 376 377 static const char * 378 getzname(strp) 379 register const char * strp; 380 { 381 register char c; 382 383 while ((c = *strp) != '\0' && !isdigit(c) && c != ',' && c != '-' && 384 c != '+') 385 ++strp; 386 return strp; 387 } 388 389 /* 390 ** Given a pointer into a time zone string, extract a number from that string. 391 ** Check that the number is within a specified range; if it is not, return 392 ** NULL. 393 ** Otherwise, return a pointer to the first character not part of the number. 394 */ 395 396 static const char * 397 getnum(strp, nump, min, max) 398 register const char * strp; 399 int * const nump; 400 const int min; 401 const int max; 402 { 403 register char c; 404 register int num; 405 406 if (strp == NULL || !isdigit(*strp)) 407 return NULL; 408 num = 0; 409 while ((c = *strp) != '\0' && isdigit(c)) { 410 num = num * 10 + (c - '0'); 411 if (num > max) 412 return NULL; /* illegal value */ 413 ++strp; 414 } 415 if (num < min) 416 return NULL; /* illegal value */ 417 *nump = num; 418 return strp; 419 } 420 421 /* 422 ** Given a pointer into a time zone string, extract a number of seconds, 423 ** in hh[:mm[:ss]] form, from the string. 424 ** If any error occurs, return NULL. 425 ** Otherwise, return a pointer to the first character not part of the number 426 ** of seconds. 427 */ 428 429 static const char * 430 getsecs(strp, secsp) 431 register const char * strp; 432 long * const secsp; 433 { 434 int num; 435 436 strp = getnum(strp, &num, 0, HOURSPERDAY); 437 if (strp == NULL) 438 return NULL; 439 *secsp = num * SECSPERHOUR; 440 if (*strp == ':') { 441 ++strp; 442 strp = getnum(strp, &num, 0, MINSPERHOUR - 1); 443 if (strp == NULL) 444 return NULL; 445 *secsp += num * SECSPERMIN; 446 if (*strp == ':') { 447 ++strp; 448 strp = getnum(strp, &num, 0, SECSPERMIN - 1); 449 if (strp == NULL) 450 return NULL; 451 *secsp += num; 452 } 453 } 454 return strp; 455 } 456 457 /* 458 ** Given a pointer into a time zone string, extract an offset, in 459 ** [+-]hh[:mm[:ss]] form, from the string. 460 ** If any error occurs, return NULL. 461 ** Otherwise, return a pointer to the first character not part of the time. 462 */ 463 464 static const char * 465 getoffset(strp, offsetp) 466 register const char * strp; 467 long * const offsetp; 468 { 469 register int neg; 470 471 if (*strp == '-') { 472 neg = 1; 473 ++strp; 474 } else if (isdigit(*strp) || *strp++ == '+') 475 neg = 0; 476 else return NULL; /* illegal offset */ 477 strp = getsecs(strp, offsetp); 478 if (strp == NULL) 479 return NULL; /* illegal time */ 480 if (neg) 481 *offsetp = -*offsetp; 482 return strp; 483 } 484 485 /* 486 ** Given a pointer into a time zone string, extract a rule in the form 487 ** date[/time]. See POSIX section 8 for the format of "date" and "time". 488 ** If a valid rule is not found, return NULL. 489 ** Otherwise, return a pointer to the first character not part of the rule. 490 */ 491 492 static const char * 493 getrule(strp, rulep) 494 const char * strp; 495 register struct rule * const rulep; 496 { 497 if (*strp == 'J') { 498 /* 499 ** Julian day. 500 */ 501 rulep->r_type = JULIAN_DAY; 502 ++strp; 503 strp = getnum(strp, &rulep->r_day, 1, DAYSPERNYEAR); 504 } else if (*strp == 'M') { 505 /* 506 ** Month, week, day. 507 */ 508 rulep->r_type = MONTH_NTH_DAY_OF_WEEK; 509 ++strp; 510 strp = getnum(strp, &rulep->r_mon, 1, MONSPERYEAR); 511 if (strp == NULL) 512 return NULL; 513 if (*strp++ != '.') 514 return NULL; 515 strp = getnum(strp, &rulep->r_week, 1, 5); 516 if (strp == NULL) 517 return NULL; 518 if (*strp++ != '.') 519 return NULL; 520 strp = getnum(strp, &rulep->r_day, 0, DAYSPERWEEK - 1); 521 } else if (isdigit(*strp)) { 522 /* 523 ** Day of year. 524 */ 525 rulep->r_type = DAY_OF_YEAR; 526 strp = getnum(strp, &rulep->r_day, 0, DAYSPERLYEAR - 1); 527 } else return NULL; /* invalid format */ 528 if (strp == NULL) 529 return NULL; 530 if (*strp == '/') { 531 /* 532 ** Time specified. 533 */ 534 ++strp; 535 strp = getsecs(strp, &rulep->r_time); 536 } else rulep->r_time = 2 * SECSPERHOUR; /* default = 2:00:00 */ 537 return strp; 538 } 539 540 /* 541 ** Given the Epoch-relative time of January 1, 00:00:00 GMT, in a year, the 542 ** year, a rule, and the offset from GMT at the time that rule takes effect, 543 ** calculate the Epoch-relative time that rule takes effect. 544 */ 545 546 static time_t 547 transtime(janfirst, year, rulep, offset) 548 const time_t janfirst; 549 const int year; 550 register const struct rule * const rulep; 551 const long offset; 552 { 553 register int leapyear; 554 register time_t value; 555 register int i; 556 int d, m1, yy0, yy1, yy2, dow; 557 558 leapyear = isleap(year); 559 switch (rulep->r_type) { 560 561 case JULIAN_DAY: 562 /* 563 ** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap 564 ** years. 565 ** In non-leap years, or if the day number is 59 or less, just 566 ** add SECSPERDAY times the day number-1 to the time of 567 ** January 1, midnight, to get the day. 568 */ 569 value = janfirst + (rulep->r_day - 1) * SECSPERDAY; 570 if (leapyear && rulep->r_day >= 60) 571 value += SECSPERDAY; 572 break; 573 574 case DAY_OF_YEAR: 575 /* 576 ** n - day of year. 577 ** Just add SECSPERDAY times the day number to the time of 578 ** January 1, midnight, to get the day. 579 */ 580 value = janfirst + rulep->r_day * SECSPERDAY; 581 break; 582 583 case MONTH_NTH_DAY_OF_WEEK: 584 /* 585 ** Mm.n.d - nth "dth day" of month m. 586 */ 587 value = janfirst; 588 for (i = 0; i < rulep->r_mon - 1; ++i) 589 value += mon_lengths[leapyear][i] * SECSPERDAY; 590 591 /* 592 ** Use Zeller's Congruence to get day-of-week of first day of 593 ** month. 594 */ 595 m1 = (rulep->r_mon + 9) % 12 + 1; 596 yy0 = (rulep->r_mon <= 2) ? (year - 1) : year; 597 yy1 = yy0 / 100; 598 yy2 = yy0 % 100; 599 dow = ((26 * m1 - 2) / 10 + 600 1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7; 601 if (dow < 0) 602 dow += DAYSPERWEEK; 603 604 /* 605 ** "dow" is the day-of-week of the first day of the month. Get 606 ** the day-of-month (zero-origin) of the first "dow" day of the 607 ** month. 608 */ 609 d = rulep->r_day - dow; 610 if (d < 0) 611 d += DAYSPERWEEK; 612 for (i = 1; i < rulep->r_week; ++i) { 613 if (d + DAYSPERWEEK >= 614 mon_lengths[leapyear][rulep->r_mon - 1]) 615 break; 616 d += DAYSPERWEEK; 617 } 618 619 /* 620 ** "d" is the day-of-month (zero-origin) of the day we want. 621 */ 622 value += d * SECSPERDAY; 623 break; 624 } 625 626 /* 627 ** "value" is the Epoch-relative time of 00:00:00 GMT on the day in 628 ** question. To get the Epoch-relative time of the specified local 629 ** time on that day, add the transition time and the current offset 630 ** from GMT. 631 */ 632 return value + rulep->r_time + offset; 633 } 634 635 /* 636 ** Given a POSIX section 8-style TZ string, fill in the rule tables as 637 ** appropriate. 638 */ 639 640 static int 641 tzparse(name, sp, lastditch) 642 const char * name; 643 register struct state * const sp; 644 const int lastditch; 645 { 646 const char * stdname; 647 const char * dstname; 648 int stdlen; 649 int dstlen; 650 long stdoffset; 651 long dstoffset; 652 register time_t * atp; 653 register unsigned char * typep; 654 register char * cp; 655 register int load_result; 656 657 stdname = name; 658 if (lastditch) { 659 stdlen = strlen(name); /* length of standard zone name */ 660 name += stdlen; 661 if (stdlen >= sizeof sp->chars) 662 stdlen = (sizeof sp->chars) - 1; 663 } else { 664 name = getzname(name); 665 stdlen = name - stdname; 666 if (stdlen < 3) 667 return -1; 668 } 669 if (*name == '\0') 670 return -1; 671 else { 672 name = getoffset(name, &stdoffset); 673 if (name == NULL) 674 return -1; 675 } 676 load_result = tzload(TZDEFRULES, sp); 677 if (load_result != 0) 678 sp->leapcnt = 0; /* so, we're off a little */ 679 if (*name != '\0') { 680 dstname = name; 681 name = getzname(name); 682 dstlen = name - dstname; /* length of DST zone name */ 683 if (dstlen < 3) 684 return -1; 685 if (*name != '\0' && *name != ',' && *name != ';') { 686 name = getoffset(name, &dstoffset); 687 if (name == NULL) 688 return -1; 689 } else dstoffset = stdoffset - SECSPERHOUR; 690 if (*name == ',' || *name == ';') { 691 struct rule start; 692 struct rule end; 693 register int year; 694 register time_t janfirst; 695 time_t starttime; 696 time_t endtime; 697 698 ++name; 699 if ((name = getrule(name, &start)) == NULL) 700 return -1; 701 if (*name++ != ',') 702 return -1; 703 if ((name = getrule(name, &end)) == NULL) 704 return -1; 705 if (*name != '\0') 706 return -1; 707 sp->typecnt = 2; /* standard time and DST */ 708 /* 709 ** Two transitions per year, from EPOCH_YEAR to 2037. 710 */ 711 sp->timecnt = 2 * (2037 - EPOCH_YEAR + 1); 712 if (sp->timecnt > TZ_MAX_TIMES) 713 return -1; 714 sp->ttis[0].tt_gmtoff = -dstoffset; 715 sp->ttis[0].tt_isdst = 1; 716 sp->ttis[0].tt_abbrind = stdlen + 1; 717 sp->ttis[1].tt_gmtoff = -stdoffset; 718 sp->ttis[1].tt_isdst = 0; 719 sp->ttis[1].tt_abbrind = 0; 720 atp = sp->ats; 721 typep = sp->types; 722 janfirst = 0; 723 for (year = EPOCH_YEAR; year <= 2037; ++year) { 724 starttime = transtime(janfirst, year, &start, 725 stdoffset); 726 endtime = transtime(janfirst, year, &end, 727 dstoffset); 728 if (starttime > endtime) { 729 *atp++ = endtime; 730 *typep++ = 1; /* DST ends */ 731 *atp++ = starttime; 732 *typep++ = 0; /* DST begins */ 733 } else { 734 *atp++ = starttime; 735 *typep++ = 0; /* DST begins */ 736 *atp++ = endtime; 737 *typep++ = 1; /* DST ends */ 738 } 739 janfirst += 740 year_lengths[isleap(year)] * SECSPERDAY; 741 } 742 } else { 743 int sawstd; 744 int sawdst; 745 long stdfix; 746 long dstfix; 747 long oldfix; 748 int isdst; 749 register int i; 750 751 if (*name != '\0') 752 return -1; 753 if (load_result != 0) 754 return -1; 755 /* 756 ** Compute the difference between the real and 757 ** prototype standard and summer time offsets 758 ** from GMT, and put the real standard and summer 759 ** time offsets into the rules in place of the 760 ** prototype offsets. 761 */ 762 sawstd = FALSE; 763 sawdst = FALSE; 764 stdfix = 0; 765 dstfix = 0; 766 for (i = 0; i < sp->typecnt; ++i) { 767 if (sp->ttis[i].tt_isdst) { 768 oldfix = dstfix; 769 dstfix = 770 sp->ttis[i].tt_gmtoff + dstoffset; 771 if (sawdst && (oldfix != dstfix)) 772 return -1; 773 sp->ttis[i].tt_gmtoff = -dstoffset; 774 sp->ttis[i].tt_abbrind = stdlen + 1; 775 sawdst = TRUE; 776 } else { 777 oldfix = stdfix; 778 stdfix = 779 sp->ttis[i].tt_gmtoff + stdoffset; 780 if (sawstd && (oldfix != stdfix)) 781 return -1; 782 sp->ttis[i].tt_gmtoff = -stdoffset; 783 sp->ttis[i].tt_abbrind = 0; 784 sawstd = TRUE; 785 } 786 } 787 /* 788 ** Make sure we have both standard and summer time. 789 */ 790 if (!sawdst || !sawstd) 791 return -1; 792 /* 793 ** Now correct the transition times by shifting 794 ** them by the difference between the real and 795 ** prototype offsets. Note that this difference 796 ** can be different in standard and summer time; 797 ** the prototype probably has a 1-hour difference 798 ** between standard and summer time, but a different 799 ** difference can be specified in TZ. 800 */ 801 isdst = FALSE; /* we start in standard time */ 802 for (i = 0; i < sp->timecnt; ++i) { 803 register const struct ttinfo * ttisp; 804 805 /* 806 ** If summer time is in effect, and the 807 ** transition time was not specified as 808 ** standard time, add the summer time 809 ** offset to the transition time; 810 ** otherwise, add the standard time offset 811 ** to the transition time. 812 */ 813 ttisp = &sp->ttis[sp->types[i]]; 814 sp->ats[i] += 815 (isdst && !ttisp->tt_ttisstd) ? 816 dstfix : stdfix; 817 isdst = ttisp->tt_isdst; 818 } 819 } 820 } else { 821 dstlen = 0; 822 sp->typecnt = 1; /* only standard time */ 823 sp->timecnt = 0; 824 sp->ttis[0].tt_gmtoff = -stdoffset; 825 sp->ttis[0].tt_isdst = 0; 826 sp->ttis[0].tt_abbrind = 0; 827 } 828 sp->charcnt = stdlen + 1; 829 if (dstlen != 0) 830 sp->charcnt += dstlen + 1; 831 if (sp->charcnt > sizeof sp->chars) 832 return -1; 833 cp = sp->chars; 834 (void) strncpy(cp, stdname, stdlen); 835 cp += stdlen; 836 *cp++ = '\0'; 837 if (dstlen != 0) { 838 (void) strncpy(cp, dstname, dstlen); 839 *(cp + dstlen) = '\0'; 840 } 841 return 0; 842 } 843 844 static void 845 gmtload(sp) 846 struct state * const sp; 847 { 848 if (tzload(GMT, sp) != 0) 849 (void) tzparse(GMT, sp, TRUE); 850 } 851 852 void 853 tzset() 854 { 855 register const char * name; 856 void tzsetwall(); 857 858 name = getenv("TZ"); 859 if (name == NULL) { 860 tzsetwall(); 861 return; 862 } 863 lcl_is_set = TRUE; 864 #ifdef ALL_STATE 865 if (lclptr == NULL) { 866 lclptr = (struct state *) malloc(sizeof *lclptr); 867 if (lclptr == NULL) { 868 settzname(); /* all we can do */ 869 return; 870 } 871 } 872 #endif /* defined ALL_STATE */ 873 if (*name == '\0') { 874 /* 875 ** User wants it fast rather than right. 876 */ 877 lclptr->leapcnt = 0; /* so, we're off a little */ 878 lclptr->timecnt = 0; 879 lclptr->ttis[0].tt_gmtoff = 0; 880 lclptr->ttis[0].tt_abbrind = 0; 881 (void) strcpy(lclptr->chars, GMT); 882 } else if (tzload(name, lclptr) != 0) 883 if (name[0] == ':' || tzparse(name, lclptr, FALSE) != 0) 884 (void) gmtload(lclptr); 885 settzname(); 886 } 887 888 void 889 tzsetwall() 890 { 891 lcl_is_set = TRUE; 892 #ifdef ALL_STATE 893 if (lclptr == NULL) { 894 lclptr = (struct state *) malloc(sizeof *lclptr); 895 if (lclptr == NULL) { 896 settzname(); /* all we can do */ 897 return; 898 } 899 } 900 #endif /* defined ALL_STATE */ 901 if (tzload((char *) NULL, lclptr) != 0) 902 gmtload(lclptr); 903 settzname(); 904 } 905 906 /* 907 ** The easy way to behave "as if no library function calls" localtime 908 ** is to not call it--so we drop its guts into "localsub", which can be 909 ** freely called. (And no, the PANS doesn't require the above behavior-- 910 ** but it *is* desirable.) 911 ** 912 ** The unused offset argument is for the benefit of mktime variants. 913 */ 914 915 /*ARGSUSED*/ 916 static void 917 localsub(timep, offset, tmp) 918 const time_t * const timep; 919 const long offset; 920 struct tm * const tmp; 921 { 922 register struct state * sp; 923 register const struct ttinfo * ttisp; 924 register int i; 925 const time_t t = *timep; 926 927 if (!lcl_is_set) 928 tzset(); 929 sp = lclptr; 930 #ifdef ALL_STATE 931 if (sp == NULL) { 932 gmtsub(timep, offset, tmp); 933 return; 934 } 935 #endif /* defined ALL_STATE */ 936 if (sp->timecnt == 0 || t < sp->ats[0]) { 937 i = 0; 938 while (sp->ttis[i].tt_isdst) 939 if (++i >= sp->typecnt) { 940 i = 0; 941 break; 942 } 943 } else { 944 for (i = 1; i < sp->timecnt; ++i) 945 if (t < sp->ats[i]) 946 break; 947 i = sp->types[i - 1]; 948 } 949 ttisp = &sp->ttis[i]; 950 /* 951 ** To get (wrong) behavior that's compatible with System V Release 2.0 952 ** you'd replace the statement below with 953 ** t += ttisp->tt_gmtoff; 954 ** timesub(&t, 0L, sp, tmp); 955 */ 956 timesub(&t, ttisp->tt_gmtoff, sp, tmp); 957 tmp->tm_isdst = ttisp->tt_isdst; 958 tzname[tmp->tm_isdst] = (char *) &sp->chars[ttisp->tt_abbrind]; 959 tmp->tm_zone = &sp->chars[ttisp->tt_abbrind]; 960 } 961 962 struct tm * 963 localtime(timep) 964 const time_t * const timep; 965 { 966 static struct tm tm; 967 968 localsub(timep, 0L, &tm); 969 return &tm; 970 } 971 972 /* 973 ** gmtsub is to gmtime as localsub is to localtime. 974 */ 975 976 static void 977 gmtsub(timep, offset, tmp) 978 const time_t * const timep; 979 const long offset; 980 struct tm * const tmp; 981 { 982 if (!gmt_is_set) { 983 gmt_is_set = TRUE; 984 #ifdef ALL_STATE 985 gmtptr = (struct state *) malloc(sizeof *gmtptr); 986 if (gmtptr != NULL) 987 #endif /* defined ALL_STATE */ 988 gmtload(gmtptr); 989 } 990 timesub(timep, offset, gmtptr, tmp); 991 /* 992 ** Could get fancy here and deliver something such as 993 ** "GMT+xxxx" or "GMT-xxxx" if offset is non-zero, 994 ** but this is no time for a treasure hunt. 995 */ 996 if (offset != 0) 997 tmp->tm_zone = WILDABBR; 998 else { 999 #ifdef ALL_STATE 1000 if (gmtptr == NULL) 1001 tmp->TM_ZONE = GMT; 1002 else tmp->TM_ZONE = gmtptr->chars; 1003 #endif /* defined ALL_STATE */ 1004 #ifndef ALL_STATE 1005 tmp->tm_zone = gmtptr->chars; 1006 #endif /* State Farm */ 1007 } 1008 } 1009 1010 struct tm * 1011 gmtime(timep) 1012 const time_t * const timep; 1013 { 1014 static struct tm tm; 1015 1016 gmtsub(timep, 0L, &tm); 1017 return &tm; 1018 } 1019 1020 static void 1021 timesub(timep, offset, sp, tmp) 1022 const time_t * const timep; 1023 const long offset; 1024 register const struct state * const sp; 1025 register struct tm * const tmp; 1026 { 1027 register const struct lsinfo * lp; 1028 register long days; 1029 register long rem; 1030 register int y; 1031 register int yleap; 1032 register const int * ip; 1033 register long corr; 1034 register int hit; 1035 register int i; 1036 1037 corr = 0; 1038 hit = FALSE; 1039 #ifdef ALL_STATE 1040 i = (sp == NULL) ? 0 : sp->leapcnt; 1041 #endif /* defined ALL_STATE */ 1042 #ifndef ALL_STATE 1043 i = sp->leapcnt; 1044 #endif /* State Farm */ 1045 while (--i >= 0) { 1046 lp = &sp->lsis[i]; 1047 if (*timep >= lp->ls_trans) { 1048 if (*timep == lp->ls_trans) 1049 hit = ((i == 0 && lp->ls_corr > 0) || 1050 lp->ls_corr > sp->lsis[i - 1].ls_corr); 1051 corr = lp->ls_corr; 1052 break; 1053 } 1054 } 1055 days = *timep / SECSPERDAY; 1056 rem = *timep % SECSPERDAY; 1057 #ifdef mc68k 1058 if (*timep == 0x80000000) { 1059 /* 1060 ** A 3B1 muffs the division on the most negative number. 1061 */ 1062 days = -24855; 1063 rem = -11648; 1064 } 1065 #endif /* mc68k */ 1066 rem += (offset - corr); 1067 while (rem < 0) { 1068 rem += SECSPERDAY; 1069 --days; 1070 } 1071 while (rem >= SECSPERDAY) { 1072 rem -= SECSPERDAY; 1073 ++days; 1074 } 1075 tmp->tm_hour = (int) (rem / SECSPERHOUR); 1076 rem = rem % SECSPERHOUR; 1077 tmp->tm_min = (int) (rem / SECSPERMIN); 1078 tmp->tm_sec = (int) (rem % SECSPERMIN); 1079 if (hit) 1080 /* 1081 ** A positive leap second requires a special 1082 ** representation. This uses "... ??:59:60". 1083 */ 1084 ++(tmp->tm_sec); 1085 tmp->tm_wday = (int) ((EPOCH_WDAY + days) % DAYSPERWEEK); 1086 if (tmp->tm_wday < 0) 1087 tmp->tm_wday += DAYSPERWEEK; 1088 y = EPOCH_YEAR; 1089 if (days >= 0) 1090 for ( ; ; ) { 1091 yleap = isleap(y); 1092 if (days < (long) year_lengths[yleap]) 1093 break; 1094 ++y; 1095 days = days - (long) year_lengths[yleap]; 1096 } 1097 else do { 1098 --y; 1099 yleap = isleap(y); 1100 days = days + (long) year_lengths[yleap]; 1101 } while (days < 0); 1102 tmp->tm_year = y - TM_YEAR_BASE; 1103 tmp->tm_yday = (int) days; 1104 ip = mon_lengths[yleap]; 1105 for (tmp->tm_mon = 0; days >= (long) ip[tmp->tm_mon]; ++(tmp->tm_mon)) 1106 days = days - (long) ip[tmp->tm_mon]; 1107 tmp->tm_mday = (int) (days + 1); 1108 tmp->tm_isdst = 0; 1109 tmp->tm_gmtoff = offset; 1110 } 1111 1112 /* 1113 ** A la X3J11 1114 */ 1115 1116 char * 1117 asctime(timeptr) 1118 register const struct tm * timeptr; 1119 { 1120 static const char wday_name[DAYSPERWEEK][3] = { 1121 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" 1122 }; 1123 static const char mon_name[MONSPERYEAR][3] = { 1124 "Jan", "Feb", "Mar", "Apr", "May", "Jun", 1125 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" 1126 }; 1127 static char result[26]; 1128 1129 (void) sprintf(result, "%.3s %.3s%3d %02.2d:%02.2d:%02.2d %d\n", 1130 wday_name[timeptr->tm_wday], 1131 mon_name[timeptr->tm_mon], 1132 timeptr->tm_mday, timeptr->tm_hour, 1133 timeptr->tm_min, timeptr->tm_sec, 1134 TM_YEAR_BASE + timeptr->tm_year); 1135 return result; 1136 } 1137 1138 char * 1139 ctime(timep) 1140 const time_t * const timep; 1141 { 1142 return asctime(localtime(timep)); 1143 } 1144 1145 /* 1146 ** Adapted from code provided by Robert Elz, who writes: 1147 ** The "best" way to do mktime I think is based on an idea of Bob 1148 ** Kridle's (so its said...) from a long time ago. (mtxinu!kridle now). 1149 ** It does a binary search of the time_t space. Since time_t's are 1150 ** just 32 bits, its a max of 32 iterations (even at 64 bits it 1151 ** would still be very reasonable). 1152 */ 1153 1154 #ifndef WRONG 1155 #define WRONG (-1) 1156 #endif /* !defined WRONG */ 1157 1158 static void 1159 normalize(tensptr, unitsptr, base) 1160 int * const tensptr; 1161 int * const unitsptr; 1162 const int base; 1163 { 1164 if (*unitsptr >= base) { 1165 *tensptr += *unitsptr / base; 1166 *unitsptr %= base; 1167 } else if (*unitsptr < 0) { 1168 *tensptr -= 1 + (-(*unitsptr + 1)) / base; 1169 *unitsptr = base - 1 - (-(*unitsptr + 1)) % base; 1170 } 1171 } 1172 1173 static int 1174 tmcomp(atmp, btmp) 1175 register const struct tm * const atmp; 1176 register const struct tm * const btmp; 1177 { 1178 register int result; 1179 1180 if ((result = (atmp->tm_year - btmp->tm_year)) == 0 && 1181 (result = (atmp->tm_mon - btmp->tm_mon)) == 0 && 1182 (result = (atmp->tm_mday - btmp->tm_mday)) == 0 && 1183 (result = (atmp->tm_hour - btmp->tm_hour)) == 0 && 1184 (result = (atmp->tm_min - btmp->tm_min)) == 0) 1185 result = atmp->tm_sec - btmp->tm_sec; 1186 return result; 1187 } 1188 1189 static time_t 1190 time2(tmp, funcp, offset, okayp) 1191 struct tm * const tmp; 1192 void (* const funcp)(); 1193 const long offset; 1194 int * const okayp; 1195 { 1196 register const struct state * sp; 1197 register int dir; 1198 register int bits; 1199 register int i, j ; 1200 register int saved_seconds; 1201 time_t newt; 1202 time_t t; 1203 struct tm yourtm, mytm; 1204 1205 *okayp = FALSE; 1206 yourtm = *tmp; 1207 if (yourtm.tm_sec >= SECSPERMIN + 2 || yourtm.tm_sec < 0) 1208 normalize(&yourtm.tm_min, &yourtm.tm_sec, SECSPERMIN); 1209 normalize(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR); 1210 normalize(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY); 1211 normalize(&yourtm.tm_year, &yourtm.tm_mon, MONSPERYEAR); 1212 while (yourtm.tm_mday <= 0) { 1213 --yourtm.tm_year; 1214 yourtm.tm_mday += 1215 year_lengths[isleap(yourtm.tm_year + TM_YEAR_BASE)]; 1216 } 1217 for ( ; ; ) { 1218 i = mon_lengths[isleap(yourtm.tm_year + 1219 TM_YEAR_BASE)][yourtm.tm_mon]; 1220 if (yourtm.tm_mday <= i) 1221 break; 1222 yourtm.tm_mday -= i; 1223 if (++yourtm.tm_mon >= MONSPERYEAR) { 1224 yourtm.tm_mon = 0; 1225 ++yourtm.tm_year; 1226 } 1227 } 1228 saved_seconds = yourtm.tm_sec; 1229 yourtm.tm_sec = 0; 1230 /* 1231 ** Calculate the number of magnitude bits in a time_t 1232 ** (this works regardless of whether time_t is 1233 ** signed or unsigned, though lint complains if unsigned). 1234 */ 1235 for (bits = 0, t = 1; t > 0; ++bits, t <<= 1) 1236 ; 1237 /* 1238 ** If time_t is signed, then 0 is the median value, 1239 ** if time_t is unsigned, then 1 << bits is median. 1240 */ 1241 t = (t < 0) ? 0 : ((time_t) 1 << bits); 1242 for ( ; ; ) { 1243 (*funcp)(&t, offset, &mytm); 1244 dir = tmcomp(&mytm, &yourtm); 1245 if (dir != 0) { 1246 if (bits-- < 0) 1247 return WRONG; 1248 if (bits < 0) 1249 --t; 1250 else if (dir > 0) 1251 t -= (time_t) 1 << bits; 1252 else t += (time_t) 1 << bits; 1253 continue; 1254 } 1255 if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst) 1256 break; 1257 /* 1258 ** Right time, wrong type. 1259 ** Hunt for right time, right type. 1260 ** It's okay to guess wrong since the guess 1261 ** gets checked. 1262 */ 1263 sp = (const struct state *) 1264 ((funcp == localsub) ? lclptr : gmtptr); 1265 #ifdef ALL_STATE 1266 if (sp == NULL) 1267 return WRONG; 1268 #endif /* defined ALL_STATE */ 1269 for (i = 0; i < sp->typecnt; ++i) { 1270 if (sp->ttis[i].tt_isdst != yourtm.tm_isdst) 1271 continue; 1272 for (j = 0; j < sp->typecnt; ++j) { 1273 if (sp->ttis[j].tt_isdst == yourtm.tm_isdst) 1274 continue; 1275 newt = t + sp->ttis[j].tt_gmtoff - 1276 sp->ttis[i].tt_gmtoff; 1277 (*funcp)(&newt, offset, &mytm); 1278 if (tmcomp(&mytm, &yourtm) != 0) 1279 continue; 1280 if (mytm.tm_isdst != yourtm.tm_isdst) 1281 continue; 1282 /* 1283 ** We have a match. 1284 */ 1285 t = newt; 1286 goto label; 1287 } 1288 } 1289 return WRONG; 1290 } 1291 label: 1292 t += saved_seconds; 1293 (*funcp)(&t, offset, tmp); 1294 *okayp = TRUE; 1295 return t; 1296 } 1297 1298 static time_t 1299 time1(tmp, funcp, offset) 1300 struct tm * const tmp; 1301 void (* const funcp)(); 1302 const long offset; 1303 { 1304 register time_t t; 1305 register const struct state * sp; 1306 register int samei, otheri; 1307 int okay; 1308 1309 if (tmp->tm_isdst > 1) 1310 tmp->tm_isdst = 1; 1311 t = time2(tmp, funcp, offset, &okay); 1312 if (okay || tmp->tm_isdst < 0) 1313 return t; 1314 /* 1315 ** We're supposed to assume that somebody took a time of one type 1316 ** and did some math on it that yielded a "struct tm" that's bad. 1317 ** We try to divine the type they started from and adjust to the 1318 ** type they need. 1319 */ 1320 sp = (const struct state *) ((funcp == localsub) ? lclptr : gmtptr); 1321 #ifdef ALL_STATE 1322 if (sp == NULL) 1323 return WRONG; 1324 #endif /* defined ALL_STATE */ 1325 for (samei = 0; samei < sp->typecnt; ++samei) { 1326 if (sp->ttis[samei].tt_isdst != tmp->tm_isdst) 1327 continue; 1328 for (otheri = 0; otheri < sp->typecnt; ++otheri) { 1329 if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst) 1330 continue; 1331 tmp->tm_sec += sp->ttis[otheri].tt_gmtoff - 1332 sp->ttis[samei].tt_gmtoff; 1333 tmp->tm_isdst = !tmp->tm_isdst; 1334 t = time2(tmp, funcp, offset, &okay); 1335 if (okay) 1336 return t; 1337 tmp->tm_sec -= sp->ttis[otheri].tt_gmtoff - 1338 sp->ttis[samei].tt_gmtoff; 1339 tmp->tm_isdst = !tmp->tm_isdst; 1340 } 1341 } 1342 return WRONG; 1343 } 1344 1345 time_t 1346 mktime(tmp) 1347 struct tm * const tmp; 1348 { 1349 return time1(tmp, localsub, 0L); 1350 } 1351