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