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