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