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