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