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