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