home *** CD-ROM | disk | FTP | other *** search
/ Chip 1995 March / CHIP3.mdf / slackwar / a / util / util-lin.2 / util-lin / util-linux-2.2 / time / localtime.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-02-22  |  36.8 KB  |  1,570 lines

  1. #ifndef lint
  2. #ifndef NOID
  3. static char    elsieid[] = "@(#)localtime.c    7.26";
  4. #endif /* !defined NOID */
  5. #endif /* !defined lint */
  6.  
  7. /*
  8. ** Leap second handling from Bradley White (bww@k.gp.cs.cmu.edu).
  9. ** POSIX-style TZ environment variable handling from Guy Harris
  10. ** (guy@auspex.com).
  11. */
  12.  
  13. /*LINTLIBRARY*/
  14.  
  15. #include "private.h"
  16. #include "tzfile.h"
  17. #include "fcntl.h"
  18.  
  19. #define ACCESS_MODE    O_RDONLY
  20.  
  21. #ifdef O_BINARY
  22. #define OPEN_MODE    (O_RDONLY | O_BINARY)
  23. #endif /* defined O_BINARY */
  24. #ifndef O_BINARY
  25. #define OPEN_MODE    O_RDONLY
  26. #endif /* !defined O_BINARY */
  27.  
  28. #ifndef WILDABBR
  29. /*
  30. ** Someone might make incorrect use of a time zone abbreviation:
  31. **    1.    They might reference tzname[0] before calling tzset (explicitly
  32. **         or implicitly).
  33. **    2.    They might reference tzname[1] before calling tzset (explicitly
  34. **         or implicitly).
  35. **    3.    They might reference tzname[1] after setting to a time zone
  36. **        in which Daylight Saving Time is never observed.
  37. **    4.    They might reference tzname[0] after setting to a time zone
  38. **        in which Standard Time is never observed.
  39. **    5.    They might reference tm.TM_ZONE after calling offtime.
  40. ** What's best to do in the above cases is open to debate;
  41. ** for now, we just set things up so that in any of the five cases
  42. ** WILDABBR is used.  Another possibility:  initialize tzname[0] to the
  43. ** string "tzname[0] used before set", and similarly for the other cases.
  44. ** And another:  initialize tzname[0] to "ERA", with an explanation in the
  45. ** manual page of what this "time zone abbreviation" means (doing this so
  46. ** that tzname[0] has the "normal" length of three characters).
  47. */
  48. #define WILDABBR    "   "
  49. #endif /* !defined WILDABBR */
  50.  
  51. static char        wildabbr[] = "WILDABBR";
  52.  
  53. static const char    gmt[] = "GMT";
  54.  
  55. struct ttinfo {                /* time type information */
  56.     long        tt_gmtoff;    /* GMT offset in seconds */
  57.     int        tt_isdst;    /* used to set tm_isdst */
  58.     int        tt_abbrind;    /* abbreviation list index */
  59.     int        tt_ttisstd;    /* TRUE if transition is std time */
  60. };
  61.  
  62. struct lsinfo {                /* leap second information */
  63.     time_t        ls_trans;    /* transition time */
  64.     long        ls_corr;    /* correction to apply */
  65. };
  66.  
  67. #define BIGGEST(a, b)    (((a) > (b)) ? (a) : (b))
  68.  
  69. #ifdef TZNAME_MAX
  70. #define MY_TZNAME_MAX    TZNAME_MAX
  71. #endif /* defined TZNAME_MAX */
  72. #ifndef TZNAME_MAX
  73. #define MY_TZNAME_MAX    255
  74. #endif /* !defined TZNAME_MAX */
  75.  
  76. struct state {
  77.     int        leapcnt;
  78.     int        timecnt;
  79.     int        typecnt;
  80.     int        charcnt;
  81.     time_t        ats[TZ_MAX_TIMES];
  82.     unsigned char    types[TZ_MAX_TIMES];
  83.     struct ttinfo    ttis[TZ_MAX_TYPES];
  84.     char        chars[BIGGEST(BIGGEST(TZ_MAX_CHARS + 1, sizeof gmt),
  85.                 (2 * (MY_TZNAME_MAX + 1)))];
  86.     struct lsinfo    lsis[TZ_MAX_LEAPS];
  87. };
  88.  
  89. struct rule {
  90.     int        r_type;        /* type of rule--see below */
  91.     int        r_day;        /* day number of rule */
  92.     int        r_week;        /* week number of rule */
  93.     int        r_mon;        /* month number of rule */
  94.     long        r_time;        /* transition time of rule */
  95. };
  96.  
  97. #define JULIAN_DAY        0    /* Jn - Julian day */
  98. #define DAY_OF_YEAR        1    /* n - day of year */
  99. #define MONTH_NTH_DAY_OF_WEEK    2    /* Mm.n.d - month, week, day of week */
  100.  
  101. /*
  102. ** Prototypes for static functions.
  103. */
  104.  
  105. static long        detzcode P((const char * codep));
  106. static const char *    getzname P((const char * strp));
  107. static const char *    getnum P((const char * strp, int * nump, int min,
  108.                 int max));
  109. static const char *    getsecs P((const char * strp, long * secsp));
  110. static const char *    getoffset P((const char * strp, long * offsetp));
  111. static const char *    getrule P((const char * strp, struct rule * rulep));
  112. static void        gmtload P((struct state * sp));
  113. static void        gmtsub P((const time_t * timep, long offset,
  114.                 struct tm * tmp));
  115. static void        localsub P((const time_t * timep, long offset,
  116.                 struct tm * tmp));
  117. static int        increment_overflow P((int * number, int delta));
  118. static int        normalize_overflow P((int * tensptr, int * unitsptr,
  119.                 int base));
  120. static void        settzname P((void));
  121. static time_t        time1 P((struct tm * tmp, void (* funcp)(),
  122.                 long offset));
  123. static time_t        time2 P((struct tm *tmp, void (* funcp)(),
  124.                 long offset, int * okayp));
  125. static void        timesub P((const time_t * timep, long offset,
  126.                 const struct state * sp, struct tm * tmp));
  127. static int        tmcomp P((const struct tm * atmp,
  128.                 const struct tm * btmp));
  129. static time_t        transtime P((time_t janfirst, int year,
  130.                 const struct rule * rulep, long offset));
  131. static int        tzload P((const char * name, struct state * sp));
  132. static int        tzparse P((const char * name, struct state * sp,
  133.                 int lastditch));
  134.  
  135. #ifdef ALL_STATE
  136. static struct state *    lclptr;
  137. static struct state *    gmtptr;
  138. #endif /* defined ALL_STATE */
  139.  
  140. #ifndef ALL_STATE
  141. static struct state    lclmem;
  142. static struct state    gmtmem;
  143. #define lclptr        (&lclmem)
  144. #define gmtptr        (&gmtmem)
  145. #endif /* State Farm */
  146.  
  147. #ifndef TZ_STRLEN_MAX
  148. #define TZ_STRLEN_MAX 255
  149. #endif
  150.  
  151. static char        lcl_TZname[TZ_STRLEN_MAX + 1];
  152. static int        lcl_is_set;
  153. static int        gmt_is_set;
  154.  
  155. char *            tzname[2] = {
  156.     wildabbr,
  157.     wildabbr
  158. };
  159.  
  160. /*
  161. ** Section 4.12.3 of X3.159-1989 requires that
  162. **    Except for the strftime function, these functions [asctime,
  163. **    ctime, gmtime, localtime] return values in one of two static
  164. **    objects: a broken-down time structure and an array of char.
  165. ** Thanks to Paul Eggert (eggert@twinsun.com) for noting this.
  166. */
  167.  
  168. static struct tm    tm;
  169.  
  170. #ifdef USG_COMPAT
  171. time_t            timezone = 0;
  172. int            daylight = 0;
  173. #endif /* defined USG_COMPAT */
  174.  
  175. #ifdef ALTZONE
  176. time_t            altzone = 0;
  177. #endif /* defined ALTZONE */
  178.  
  179. static long
  180. detzcode(codep)
  181. const char * const    codep;
  182. {
  183.     register long    result;
  184.     register int    i;
  185.  
  186.     result = 0;
  187.     for (i = 0; i < 4; ++i)
  188.         result = (result << 8) | (codep[i] & 0xff);
  189.     return result;
  190. }
  191.  
  192. static void
  193. settzname P((void))
  194. {
  195.     register const struct state * const    sp = lclptr;
  196.     register int                i;
  197.  
  198.     tzname[0] = wildabbr;
  199.     tzname[1] = wildabbr;
  200. #ifdef USG_COMPAT
  201.     daylight = 0;
  202.     timezone = 0;
  203. #endif /* defined USG_COMPAT */
  204. #ifdef ALTZONE
  205.     altzone = 0;
  206. #endif /* defined ALTZONE */
  207. #ifdef ALL_STATE
  208.     if (sp == NULL) {
  209.         tzname[0] = tzname[1] = gmt;
  210.         return;
  211.     }
  212. #endif /* defined ALL_STATE */
  213.     for (i = 0; i < sp->typecnt; ++i) {
  214.         register const struct ttinfo * const    ttisp = &sp->ttis[i];
  215.  
  216.         tzname[ttisp->tt_isdst] =
  217.             (char *) &sp->chars[ttisp->tt_abbrind];
  218. #ifdef USG_COMPAT
  219.         if (ttisp->tt_isdst)
  220.             daylight = 1;
  221.         if (i == 0 || !ttisp->tt_isdst)
  222.             timezone = -(ttisp->tt_gmtoff);
  223. #endif /* defined USG_COMPAT */
  224. #ifdef ALTZONE
  225.         if (i == 0 || ttisp->tt_isdst)
  226.             altzone = -(ttisp->tt_gmtoff);
  227. #endif /* defined ALTZONE */
  228.     }
  229.     /*
  230.     ** And to get the latest zone names into tzname. . .
  231.     */
  232.     for (i = 0; i < sp->timecnt; ++i) {
  233.         register const struct ttinfo * const    ttisp =
  234.                             &sp->ttis[
  235.                                 sp->types[i]];
  236.  
  237.         tzname[ttisp->tt_isdst] =
  238.             (char *) &sp->chars[ttisp->tt_abbrind];
  239.     }
  240. }
  241.  
  242. static int
  243. tzload(name, sp)
  244. register const char *        name;
  245. register struct state * const    sp;
  246. {
  247.     register const char *    p;
  248.     register int        i;
  249.     register int        fid;
  250.  
  251.     if (name == NULL && (name = TZDEFAULT) == NULL)
  252.         return -1;
  253.     {
  254.         register int     doaccess;
  255.         char        fullname[FILENAME_MAX + 1];
  256.  
  257.         if (name[0] == ':')
  258.             ++name;
  259.         doaccess = name[0] == '/';
  260.         if (!doaccess) {
  261.             if ((p = TZDIR) == NULL)
  262.                 return -1;
  263.             if ((strlen(p) + strlen(name) + 1) >= sizeof fullname)
  264.                 return -1;
  265.             (void) strcpy(fullname, p);
  266.             (void) strcat(fullname, "/");
  267.             (void) strcat(fullname, name);
  268.             /*
  269.             ** Set doaccess if '.' (as in "../") shows up in name.
  270.             */
  271.             if (strchr(name, '.') != NULL)
  272.                 doaccess = TRUE;
  273.             name = fullname;
  274.         }
  275.         if (doaccess && access(name, ACCESS_MODE) != 0)
  276.             return -1;
  277.         if ((fid = open(name, OPEN_MODE)) == -1)
  278.             return -1;
  279.     }
  280.     {
  281.         register const struct tzhead *    tzhp;
  282.         char                buf[sizeof *sp + sizeof *tzhp];
  283.         int                ttisstdcnt;
  284.  
  285.         i = read(fid, buf, sizeof buf);
  286.         if (close(fid) != 0 || i < sizeof *tzhp)
  287.             return -1;
  288.         tzhp = (struct tzhead *) buf;
  289.         ttisstdcnt = (int) detzcode(tzhp->tzh_ttisstdcnt);
  290.         sp->leapcnt = (int) detzcode(tzhp->tzh_leapcnt);
  291.         sp->timecnt = (int) detzcode(tzhp->tzh_timecnt);
  292.         sp->typecnt = (int) detzcode(tzhp->tzh_typecnt);
  293.         sp->charcnt = (int) detzcode(tzhp->tzh_charcnt);
  294.         if (sp->leapcnt < 0 || sp->leapcnt > TZ_MAX_LEAPS ||
  295.             sp->typecnt <= 0 || sp->typecnt > TZ_MAX_TYPES ||
  296.             sp->timecnt < 0 || sp->timecnt > TZ_MAX_TIMES ||
  297.             sp->charcnt < 0 || sp->charcnt > TZ_MAX_CHARS ||
  298.             (ttisstdcnt != sp->typecnt && ttisstdcnt != 0))
  299.                 return -1;
  300.         if (i < sizeof *tzhp +
  301.             sp->timecnt * (4 + sizeof (char)) +
  302.             sp->typecnt * (4 + 2 * sizeof (char)) +
  303.             sp->charcnt * sizeof (char) +
  304.             sp->leapcnt * 2 * 4 +
  305.             ttisstdcnt * sizeof (char))
  306.                 return -1;
  307.         p = buf + sizeof *tzhp;
  308.         for (i = 0; i < sp->timecnt; ++i) {
  309.             sp->ats[i] = detzcode(p);
  310.             p += 4;
  311.         }
  312.         for (i = 0; i < sp->timecnt; ++i) {
  313.             sp->types[i] = (unsigned char) *p++;
  314.             if (sp->types[i] >= sp->typecnt)
  315.                 return -1;
  316.         }
  317.         for (i = 0; i < sp->typecnt; ++i) {
  318.             register struct ttinfo *    ttisp;
  319.  
  320.             ttisp = &sp->ttis[i];
  321.             ttisp->tt_gmtoff = detzcode(p);
  322.             p += 4;
  323.             ttisp->tt_isdst = (unsigned char) *p++;
  324.             if (ttisp->tt_isdst != 0 && ttisp->tt_isdst != 1)
  325.                 return -1;
  326.             ttisp->tt_abbrind = (unsigned char) *p++;
  327.             if (ttisp->tt_abbrind < 0 ||
  328.                 ttisp->tt_abbrind > sp->charcnt)
  329.                     return -1;
  330.         }
  331.         for (i = 0; i < sp->charcnt; ++i)
  332.             sp->chars[i] = *p++;
  333.         sp->chars[i] = '\0';    /* ensure '\0' at end */
  334.         for (i = 0; i < sp->leapcnt; ++i) {
  335.             register struct lsinfo *    lsisp;
  336.  
  337.             lsisp = &sp->lsis[i];
  338.             lsisp->ls_trans = detzcode(p);
  339.             p += 4;
  340.             lsisp->ls_corr = detzcode(p);
  341.             p += 4;
  342.         }
  343.         for (i = 0; i < sp->typecnt; ++i) {
  344.             register struct ttinfo *    ttisp;
  345.  
  346.             ttisp = &sp->ttis[i];
  347.             if (ttisstdcnt == 0)
  348.                 ttisp->tt_ttisstd = FALSE;
  349.             else {
  350.                 ttisp->tt_ttisstd = *p++;
  351.                 if (ttisp->tt_ttisstd != TRUE &&
  352.                     ttisp->tt_ttisstd != FALSE)
  353.                         return -1;
  354.             }
  355.         }
  356.     }
  357.     return 0;
  358. }
  359.  
  360. static const int    mon_lengths[2][MONSPERYEAR] = {
  361.     { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
  362.     { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
  363. };
  364.  
  365. static const int    year_lengths[2] = {
  366.     DAYSPERNYEAR, DAYSPERLYEAR
  367. };
  368.  
  369. /*
  370. ** Given a pointer into a time zone string, scan until a character that is not
  371. ** a valid character in a zone name is found.  Return a pointer to that
  372. ** character.
  373. */
  374.  
  375. static const char *
  376. getzname(strp)
  377. register const char *    strp;
  378. {
  379.     register char    c;
  380.  
  381.     while ((c = *strp) != '\0' && !isdigit(c) && c != ',' && c != '-' &&
  382.         c != '+')
  383.             ++strp;
  384.     return strp;
  385. }
  386.  
  387. /*
  388. ** Given a pointer into a time zone string, extract a number from that string.
  389. ** Check that the number is within a specified range; if it is not, return
  390. ** NULL.
  391. ** Otherwise, return a pointer to the first character not part of the number.
  392. */
  393.  
  394. static const char *
  395. getnum(strp, nump, min, max)
  396. register const char *    strp;
  397. int * const        nump;
  398. const int        min;
  399. const int        max;
  400. {
  401.     register char    c;
  402.     register int    num;
  403.  
  404.     if (strp == NULL || !isdigit(*strp))
  405.         return NULL;
  406.     num = 0;
  407.     while ((c = *strp) != '\0' && isdigit(c)) {
  408.         num = num * 10 + (c - '0');
  409.         if (num > max)
  410.             return NULL;    /* illegal value */
  411.         ++strp;
  412.     }
  413.     if (num < min)
  414.         return NULL;        /* illegal value */
  415.     *nump = num;
  416.     return strp;
  417. }
  418.  
  419. /*
  420. ** Given a pointer into a time zone string, extract a number of seconds,
  421. ** in hh[:mm[:ss]] form, from the string.
  422. ** If any error occurs, return NULL.
  423. ** Otherwise, return a pointer to the first character not part of the number
  424. ** of seconds.
  425. */
  426.  
  427. static const char *
  428. getsecs(strp, secsp)
  429. register const char *    strp;
  430. long * const        secsp;
  431. {
  432.     int    num;
  433.  
  434.     /*
  435.     ** `HOURSPERDAY * DAYSPERWEEK - 1' allows quasi-Posix rules like
  436.     ** "M10.4.6/26", which does not conform to Posix,
  437.     ** but which specifies the equivalent of
  438.     ** ``02:00 on the first Sunday on or after 23 Oct''.
  439.     */
  440.     strp = getnum(strp, &num, 0, HOURSPERDAY * DAYSPERWEEK - 1);
  441.     if (strp == NULL)
  442.         return NULL;
  443.     *secsp = num * (long) SECSPERHOUR;
  444.     if (*strp == ':') {
  445.         ++strp;
  446.         strp = getnum(strp, &num, 0, MINSPERHOUR - 1);
  447.         if (strp == NULL)
  448.             return NULL;
  449.         *secsp += num * SECSPERMIN;
  450.         if (*strp == ':') {
  451.             ++strp;
  452.             /* `SECSPERMIN' allows for leap seconds.  */
  453.             strp = getnum(strp, &num, 0, SECSPERMIN);
  454.             if (strp == NULL)
  455.                 return NULL;
  456.             *secsp += num;
  457.         }
  458.     }
  459.     return strp;
  460. }
  461.  
  462. /*
  463. ** Given a pointer into a time zone string, extract an offset, in
  464. ** [+-]hh[:mm[:ss]] form, from the string.
  465. ** If any error occurs, return NULL.
  466. ** Otherwise, return a pointer to the first character not part of the time.
  467. */
  468.  
  469. static const char *
  470. getoffset(strp, offsetp)
  471. register const char *    strp;
  472. long * const        offsetp;
  473. {
  474.     register int    neg;
  475.  
  476.     if (*strp == '-') {
  477.         neg = 1;
  478.         ++strp;
  479.     } else if (isdigit(*strp) || *strp++ == '+')
  480.         neg = 0;
  481.     else    return NULL;        /* illegal offset */
  482.     strp = getsecs(strp, offsetp);
  483.     if (strp == NULL)
  484.         return NULL;        /* illegal time */
  485.     if (neg)
  486.         *offsetp = -*offsetp;
  487.     return strp;
  488. }
  489.  
  490. /*
  491. ** Given a pointer into a time zone string, extract a rule in the form
  492. ** date[/time].  See POSIX section 8 for the format of "date" and "time".
  493. ** If a valid rule is not found, return NULL.
  494. ** Otherwise, return a pointer to the first character not part of the rule.
  495. */
  496.  
  497. static const char *
  498. getrule(strp, rulep)
  499. const char *            strp;
  500. register struct rule * const    rulep;
  501. {
  502.     if (*strp == 'J') {
  503.         /*
  504.         ** Julian day.
  505.         */
  506.         rulep->r_type = JULIAN_DAY;
  507.         ++strp;
  508.         strp = getnum(strp, &rulep->r_day, 1, DAYSPERNYEAR);
  509.     } else if (*strp == 'M') {
  510.         /*
  511.         ** Month, week, day.
  512.         */
  513.         rulep->r_type = MONTH_NTH_DAY_OF_WEEK;
  514.         ++strp;
  515.         strp = getnum(strp, &rulep->r_mon, 1, MONSPERYEAR);
  516.         if (strp == NULL)
  517.             return NULL;
  518.         if (*strp++ != '.')
  519.             return NULL;
  520.         strp = getnum(strp, &rulep->r_week, 1, 5);
  521.         if (strp == NULL)
  522.             return NULL;
  523.         if (*strp++ != '.')
  524.             return NULL;
  525.         strp = getnum(strp, &rulep->r_day, 0, DAYSPERWEEK - 1);
  526.     } else if (isdigit(*strp)) {
  527.         /*
  528.         ** Day of year.
  529.         */
  530.         rulep->r_type = DAY_OF_YEAR;
  531.         strp = getnum(strp, &rulep->r_day, 0, DAYSPERLYEAR - 1);
  532.     } else    return NULL;        /* invalid format */
  533.     if (strp == NULL)
  534.         return NULL;
  535.     if (*strp == '/') {
  536.         /*
  537.         ** Time specified.
  538.         */
  539.         ++strp;
  540.         strp = getsecs(strp, &rulep->r_time);
  541.     } else    rulep->r_time = 2 * SECSPERHOUR;    /* default = 2:00:00 */
  542.     return strp;
  543. }
  544.  
  545. /*
  546. ** Given the Epoch-relative time of January 1, 00:00:00 GMT, in a year, the
  547. ** year, a rule, and the offset from GMT at the time that rule takes effect,
  548. ** calculate the Epoch-relative time that rule takes effect.
  549. */
  550.  
  551. static time_t
  552. transtime(janfirst, year, rulep, offset)
  553. const time_t                janfirst;
  554. const int                year;
  555. register const struct rule * const    rulep;
  556. const long                offset;
  557. {
  558.     register int    leapyear;
  559.     register time_t    value;
  560.     register int    i;
  561.     int        d, m1, yy0, yy1, yy2, dow;
  562.  
  563.     INITIALIZE(value);
  564.     leapyear = isleap(year);
  565.     switch (rulep->r_type) {
  566.  
  567.     case JULIAN_DAY:
  568.         /*
  569.         ** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap
  570.         ** years.
  571.         ** In non-leap years, or if the day number is 59 or less, just
  572.         ** add SECSPERDAY times the day number-1 to the time of
  573.         ** January 1, midnight, to get the day.
  574.         */
  575.         value = janfirst + (rulep->r_day - 1) * SECSPERDAY;
  576.         if (leapyear && rulep->r_day >= 60)
  577.             value += SECSPERDAY;
  578.         break;
  579.  
  580.     case DAY_OF_YEAR:
  581.         /*
  582.         ** n - day of year.
  583.         ** Just add SECSPERDAY times the day number to the time of
  584.         ** January 1, midnight, to get the day.
  585.         */
  586.         value = janfirst + rulep->r_day * SECSPERDAY;
  587.         break;
  588.  
  589.     case MONTH_NTH_DAY_OF_WEEK:
  590.         /*
  591.         ** Mm.n.d - nth "dth day" of month m.
  592.         */
  593.         value = janfirst;
  594.         for (i = 0; i < rulep->r_mon - 1; ++i)
  595.             value += mon_lengths[leapyear][i] * SECSPERDAY;
  596.  
  597.         /*
  598.         ** Use Zeller's Congruence to get day-of-week of first day of
  599.         ** month.
  600.         */
  601.         m1 = (rulep->r_mon + 9) % 12 + 1;
  602.         yy0 = (rulep->r_mon <= 2) ? (year - 1) : year;
  603.         yy1 = yy0 / 100;
  604.         yy2 = yy0 % 100;
  605.         dow = ((26 * m1 - 2) / 10 +
  606.             1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7;
  607.         if (dow < 0)
  608.             dow += DAYSPERWEEK;
  609.  
  610.         /*
  611.         ** "dow" is the day-of-week of the first day of the month.  Get
  612.         ** the day-of-month (zero-origin) of the first "dow" day of the
  613.         ** month.
  614.         */
  615.         d = rulep->r_day - dow;
  616.         if (d < 0)
  617.             d += DAYSPERWEEK;
  618.         for (i = 1; i < rulep->r_week; ++i) {
  619.             if (d + DAYSPERWEEK >=
  620.                 mon_lengths[leapyear][rulep->r_mon - 1])
  621.                     break;
  622.             d += DAYSPERWEEK;
  623.         }
  624.  
  625.         /*
  626.         ** "d" is the day-of-month (zero-origin) of the day we want.
  627.         */
  628.         value += d * SECSPERDAY;
  629.         break;
  630.     }
  631.  
  632.     /*
  633.     ** "value" is the Epoch-relative time of 00:00:00 GMT on the day in
  634.     ** question.  To get the Epoch-relative time of the specified local
  635.     ** time on that day, add the transition time and the current offset
  636.     ** from GMT.
  637.     */
  638.     return value + rulep->r_time + offset;
  639. }
  640.  
  641. /*
  642. ** Given a POSIX section 8-style TZ string, fill in the rule tables as
  643. ** appropriate.
  644. */
  645.  
  646. static int
  647. tzparse(name, sp, lastditch)
  648. const char *            name;
  649. register struct state * const    sp;
  650. const int            lastditch;
  651. {
  652.     const char *            stdname;
  653.     const char *            dstname;
  654.     size_t                stdlen;
  655.     size_t                dstlen;
  656.     long                stdoffset;
  657.     long                dstoffset;
  658.     register time_t *        atp;
  659.     register unsigned char *    typep;
  660.     register char *            cp;
  661.     register int            load_result;
  662.  
  663.     INITIALIZE(dstname);
  664.     stdname = name;
  665.     if (lastditch) {
  666.         stdlen = strlen(name);    /* length of standard zone name */
  667.         name += stdlen;
  668.         if (stdlen >= sizeof sp->chars)
  669.             stdlen = (sizeof sp->chars) - 1;
  670.     } else {
  671.         name = getzname(name);
  672.         stdlen = name - stdname;
  673.         if (stdlen < 3)
  674.             return -1;
  675.     }
  676.     if (*name == '\0')
  677.         return -1;    /* was "stdoffset = 0;" */
  678.     else {
  679.         name = getoffset(name, &stdoffset);
  680.         if (name == NULL)
  681.             return -1;
  682.     }
  683.     load_result = tzload(TZDEFRULES, sp);
  684.     if (load_result != 0)
  685.         sp->leapcnt = 0;        /* so, we're off a little */
  686.     if (*name != '\0') {
  687.         dstname = name;
  688.         name = getzname(name);
  689.         dstlen = name - dstname;    /* length of DST zone name */
  690.         if (dstlen < 3)
  691.             return -1;
  692.         if (*name != '\0' && *name != ',' && *name != ';') {
  693.             name = getoffset(name, &dstoffset);
  694.             if (name == NULL)
  695.                 return -1;
  696.         } else    dstoffset = stdoffset - SECSPERHOUR;
  697.         if (*name == ',' || *name == ';') {
  698.             struct rule    start;
  699.             struct rule    end;
  700.             register int    year;
  701.             register time_t    janfirst;
  702.             time_t        starttime;
  703.             time_t        endtime;
  704.  
  705.             ++name;
  706.             if ((name = getrule(name, &start)) == NULL)
  707.                 return -1;
  708.             if (*name++ != ',')
  709.                 return -1;
  710.             if ((name = getrule(name, &end)) == NULL)
  711.                 return -1;
  712.             if (*name != '\0')
  713.                 return -1;
  714.             sp->typecnt = 2;    /* standard time and DST */
  715.             /*
  716.             ** Two transitions per year, from EPOCH_YEAR to 2037.
  717.             */
  718.             sp->timecnt = 2 * (2037 - EPOCH_YEAR + 1);
  719.             if (sp->timecnt > TZ_MAX_TIMES)
  720.                 return -1;
  721.             sp->ttis[0].tt_gmtoff = -dstoffset;
  722.             sp->ttis[0].tt_isdst = 1;
  723.             sp->ttis[0].tt_abbrind = stdlen + 1;
  724.             sp->ttis[1].tt_gmtoff = -stdoffset;
  725.             sp->ttis[1].tt_isdst = 0;
  726.             sp->ttis[1].tt_abbrind = 0;
  727.             atp = sp->ats;
  728.             typep = sp->types;
  729.             janfirst = 0;
  730.             for (year = EPOCH_YEAR; year <= 2037; ++year) {
  731.                 starttime = transtime(janfirst, year, &start,
  732.                     stdoffset);
  733.                 endtime = transtime(janfirst, year, &end,
  734.                     dstoffset);
  735.                 if (starttime > endtime) {
  736.                     *atp++ = endtime;
  737.                     *typep++ = 1;    /* DST ends */
  738.                     *atp++ = starttime;
  739.                     *typep++ = 0;    /* DST begins */
  740.                 } else {
  741.                     *atp++ = starttime;
  742.                     *typep++ = 0;    /* DST begins */
  743.                     *atp++ = endtime;
  744.                     *typep++ = 1;    /* DST ends */
  745.                 }
  746.                 janfirst += year_lengths[isleap(year)] *
  747.                     SECSPERDAY;
  748.             }
  749.         } else {
  750.             int        sawstd;
  751.             int        sawdst;
  752.             long        stdfix;
  753.             long        dstfix;
  754.             long        oldfix;
  755.             int        isdst;
  756.             register int    i;
  757.  
  758.             if (*name != '\0')
  759.                 return -1;
  760.             if (load_result != 0)
  761.                 return -1;
  762.             /*
  763.             ** Compute the difference between the real and
  764.             ** prototype standard and summer time offsets
  765.             ** from GMT, and put the real standard and summer
  766.             ** time offsets into the rules in place of the
  767.             ** prototype offsets.
  768.             */
  769.             sawstd = FALSE;
  770.             sawdst = FALSE;
  771.             stdfix = 0;
  772.             dstfix = 0;
  773.             for (i = 0; i < sp->typecnt; ++i) {
  774.                 if (sp->ttis[i].tt_isdst) {
  775.                     oldfix = dstfix;
  776.                     dstfix = sp->ttis[i].tt_gmtoff +
  777.                         dstoffset;
  778.                     if (sawdst && (oldfix != dstfix))
  779.                         return -1;
  780.                     sp->ttis[i].tt_gmtoff = -dstoffset;
  781.                     sp->ttis[i].tt_abbrind = stdlen + 1;
  782.                     sawdst = TRUE;
  783.                 } else {
  784.                     oldfix = stdfix;
  785.                     stdfix = sp->ttis[i].tt_gmtoff +
  786.                         stdoffset;
  787.                     if (sawstd && (oldfix != stdfix))
  788.                         return -1;
  789.                     sp->ttis[i].tt_gmtoff = -stdoffset;
  790.                     sp->ttis[i].tt_abbrind = 0;
  791.                     sawstd = TRUE;
  792.                 }
  793.             }
  794.             /*
  795.             ** Make sure we have both standard and summer time.
  796.             */
  797.             if (!sawdst || !sawstd)
  798.                 return -1;
  799.             /*
  800.             ** Now correct the transition times by shifting
  801.             ** them by the difference between the real and
  802.             ** prototype offsets.  Note that this difference
  803.             ** can be different in standard and summer time;
  804.             ** the prototype probably has a 1-hour difference
  805.             ** between standard and summer time, but a different
  806.             ** difference can be specified in TZ.
  807.             */
  808.             isdst = FALSE;    /* we start in standard time */
  809.             for (i = 0; i < sp->timecnt; ++i) {
  810.                 register const struct ttinfo *    ttisp;
  811.  
  812.                 /*
  813.                 ** If summer time is in effect, and the
  814.                 ** transition time was not specified as
  815.                 ** standard time, add the summer time
  816.                 ** offset to the transition time;
  817.                 ** otherwise, add the standard time offset
  818.                 ** to the transition time.
  819.                 */
  820.                 ttisp = &sp->ttis[sp->types[i]];
  821.                 sp->ats[i] +=
  822.                     (isdst && !ttisp->tt_ttisstd) ?
  823.                         dstfix : stdfix;
  824.                 isdst = ttisp->tt_isdst;
  825.             }
  826.         }
  827.     } else {
  828.         dstlen = 0;
  829.         sp->typecnt = 1;        /* only standard time */
  830.         sp->timecnt = 0;
  831.         sp->ttis[0].tt_gmtoff = -stdoffset;
  832.         sp->ttis[0].tt_isdst = 0;
  833.         sp->ttis[0].tt_abbrind = 0;
  834.     }
  835.     sp->charcnt = stdlen + 1;
  836.     if (dstlen != 0)
  837.         sp->charcnt += dstlen + 1;
  838.     if (sp->charcnt > sizeof sp->chars)
  839.         return -1;
  840.     cp = sp->chars;
  841.     (void) strncpy(cp, stdname, stdlen);
  842.     cp += stdlen;
  843.     *cp++ = '\0';
  844.     if (dstlen != 0) {
  845.         (void) strncpy(cp, dstname, dstlen);
  846.         *(cp + dstlen) = '\0';
  847.     }
  848.     return 0;
  849. }
  850.  
  851. static void
  852. gmtload(sp)
  853. struct state * const    sp;
  854. {
  855.     if (tzload(gmt, sp) != 0)
  856.         (void) tzparse(gmt, sp, TRUE);
  857. }
  858.  
  859. #ifndef STD_INSPIRED
  860. /*
  861. ** A non-static declaration of tzsetwall in a system header file
  862. ** may cause a warning about this upcoming static declaration...
  863. */
  864. static
  865. #endif /* !defined STD_INSPIRED */
  866. void
  867. tzsetwall P((void))
  868. {
  869.     if (lcl_is_set < 0)
  870.         return;
  871.     lcl_is_set = -1;
  872.  
  873. #ifdef ALL_STATE
  874.     if (lclptr == NULL) {
  875.         lclptr = (struct state *) malloc(sizeof *lclptr);
  876.         if (lclptr == NULL) {
  877.             settzname();    /* all we can do */
  878.             return;
  879.         }
  880.     }
  881. #endif /* defined ALL_STATE */
  882.     if (tzload((char *) NULL, lclptr) != 0)
  883.         gmtload(lclptr);
  884.     settzname();
  885. }
  886.  
  887. void
  888. tzset P((void))
  889. {
  890.     register const char *    name;
  891.  
  892.     name = getenv("TZ");
  893.     if (name == NULL) {
  894.         tzsetwall();
  895.         return;
  896.     }
  897.  
  898.     if (lcl_is_set > 0  &&  strcmp(lcl_TZname, name) == 0)
  899.         return;
  900.     lcl_is_set = (strlen(name) < sizeof(lcl_TZname));
  901.     if (lcl_is_set)
  902.         (void) strcpy(lcl_TZname, name);
  903.  
  904. #ifdef ALL_STATE
  905.     if (lclptr == NULL) {
  906.         lclptr = (struct state *) malloc(sizeof *lclptr);
  907.         if (lclptr == NULL) {
  908.             settzname();    /* all we can do */
  909.             return;
  910.         }
  911.     }
  912. #endif /* defined ALL_STATE */
  913.     if (*name == '\0') {
  914.         /*
  915.         ** User wants it fast rather than right.
  916.         */
  917.         lclptr->leapcnt = 0;        /* so, we're off a little */
  918.         lclptr->timecnt = 0;
  919.         lclptr->ttis[0].tt_gmtoff = 0;
  920.         lclptr->ttis[0].tt_abbrind = 0;
  921.         (void) strcpy(lclptr->chars, gmt);
  922.     } else if (tzload(name, lclptr) != 0)
  923.         if (name[0] == ':' || tzparse(name, lclptr, FALSE) != 0)
  924.             (void) 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.     sp = lclptr;
  950. #ifdef ALL_STATE
  951.     if (sp == NULL) {
  952.         gmtsub(timep, offset, tmp);
  953.         return;
  954.     }
  955. #endif /* defined ALL_STATE */
  956.     if (sp->timecnt == 0 || t < sp->ats[0]) {
  957.         i = 0;
  958.         while (sp->ttis[i].tt_isdst)
  959.             if (++i >= sp->typecnt) {
  960.                 i = 0;
  961.                 break;
  962.             }
  963.     } else {
  964.         for (i = 1; i < sp->timecnt; ++i)
  965.             if (t < sp->ats[i])
  966.                 break;
  967.         i = sp->types[i - 1];
  968.     }
  969.     ttisp = &sp->ttis[i];
  970.     /*
  971.     ** To get (wrong) behavior that's compatible with System V Release 2.0
  972.     ** you'd replace the statement below with
  973.     **    t += ttisp->tt_gmtoff;
  974.     **    timesub(&t, 0L, sp, tmp);
  975.     */
  976.     timesub(&t, ttisp->tt_gmtoff, sp, tmp);
  977.     tmp->tm_isdst = ttisp->tt_isdst;
  978.     tzname[tmp->tm_isdst] = (char *) &sp->chars[ttisp->tt_abbrind];
  979. #ifdef TM_ZONE
  980.     tmp->TM_ZONE = &sp->chars[ttisp->tt_abbrind];
  981. #endif /* defined TM_ZONE */
  982. }
  983.  
  984. struct tm *
  985. localtime(timep)
  986. const time_t * const    timep;
  987. {
  988.     tzset();
  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. #ifdef TM_ZONE
  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. #endif /* defined TM_ZONE */
  1031. }
  1032.  
  1033. struct tm *
  1034. gmtime(timep)
  1035. const time_t * const    timep;
  1036. {
  1037.     gmtsub(timep, 0L, &tm);
  1038.     return &tm;
  1039. }
  1040.  
  1041. #ifdef STD_INSPIRED
  1042.  
  1043. struct tm *
  1044. offtime(timep, offset)
  1045. const time_t * const    timep;
  1046. const long        offset;
  1047. {
  1048.     gmtsub(timep, offset, &tm);
  1049.     return &tm;
  1050. }
  1051.  
  1052. #endif /* defined STD_INSPIRED */
  1053.  
  1054. static void
  1055. timesub(timep, offset, sp, tmp)
  1056. const time_t * const            timep;
  1057. const long                offset;
  1058. register const struct state * const    sp;
  1059. register struct tm * const        tmp;
  1060. {
  1061.     register const struct lsinfo *    lp;
  1062.     register long            days;
  1063.     register long            rem;
  1064.     register int            y;
  1065.     register int            yleap;
  1066.     register const int *        ip;
  1067.     register long            corr;
  1068.     register int            hit;
  1069.     register int            i;
  1070.  
  1071.     corr = 0;
  1072.     hit = 0;
  1073. #ifdef ALL_STATE
  1074.     i = (sp == NULL) ? 0 : sp->leapcnt;
  1075. #endif /* defined ALL_STATE */
  1076. #ifndef ALL_STATE
  1077.     i = sp->leapcnt;
  1078. #endif /* State Farm */
  1079.     while (--i >= 0) {
  1080.         lp = &sp->lsis[i];
  1081.         if (*timep >= lp->ls_trans) {
  1082.             if (*timep == lp->ls_trans) {
  1083.                 hit = ((i == 0 && lp->ls_corr > 0) ||
  1084.                     lp->ls_corr > sp->lsis[i - 1].ls_corr);
  1085.                 if (hit)
  1086.                     while (i > 0 &&
  1087.                         sp->lsis[i].ls_trans ==
  1088.                         sp->lsis[i - 1].ls_trans + 1 &&
  1089.                         sp->lsis[i].ls_corr ==
  1090.                         sp->lsis[i - 1].ls_corr + 1) {
  1091.                             ++hit;
  1092.                             --i;
  1093.                     }
  1094.             }
  1095.             corr = lp->ls_corr;
  1096.             break;
  1097.         }
  1098.     }
  1099.     days = *timep / SECSPERDAY;
  1100.     rem = *timep % SECSPERDAY;
  1101. #ifdef mc68k
  1102.     if (*timep == 0x80000000) {
  1103.         /*
  1104.         ** A 3B1 muffs the division on the most negative number.
  1105.         */
  1106.         days = -24855;
  1107.         rem = -11648;
  1108.     }
  1109. #endif /* mc68k */
  1110.     rem += (offset - corr);
  1111.     while (rem < 0) {
  1112.         rem += SECSPERDAY;
  1113.         --days;
  1114.     }
  1115.     while (rem >= SECSPERDAY) {
  1116.         rem -= SECSPERDAY;
  1117.         ++days;
  1118.     }
  1119.     tmp->tm_hour = (int) (rem / SECSPERHOUR);
  1120.     rem = rem % SECSPERHOUR;
  1121.     tmp->tm_min = (int) (rem / SECSPERMIN);
  1122.     tmp->tm_sec = (int) (rem % SECSPERMIN);
  1123.     if (hit)
  1124.         /*
  1125.         ** A positive leap second requires a special
  1126.         ** representation.  This uses "... ??:59:60" et seq.
  1127.         */
  1128.         tmp->tm_sec += hit;
  1129.     tmp->tm_wday = (int) ((EPOCH_WDAY + days) % DAYSPERWEEK);
  1130.     if (tmp->tm_wday < 0)
  1131.         tmp->tm_wday += DAYSPERWEEK;
  1132.     y = EPOCH_YEAR;
  1133.     if (days >= 0)
  1134.         for ( ; ; ) {
  1135.             yleap = isleap(y);
  1136.             if (days < (long) year_lengths[yleap])
  1137.                 break;
  1138.             ++y;
  1139.             days = days - (long) year_lengths[yleap];
  1140.         }
  1141.     else do {
  1142.         --y;
  1143.         yleap = isleap(y);
  1144.         days = days + (long) year_lengths[yleap];
  1145.     } while (days < 0);
  1146.     tmp->tm_year = y - TM_YEAR_BASE;
  1147.     tmp->tm_yday = (int) days;
  1148.     ip = mon_lengths[yleap];
  1149.     for (tmp->tm_mon = 0; days >= (long) ip[tmp->tm_mon]; ++(tmp->tm_mon))
  1150.         days = days - (long) ip[tmp->tm_mon];
  1151.     tmp->tm_mday = (int) (days + 1);
  1152.     tmp->tm_isdst = 0;
  1153. #ifdef TM_GMTOFF
  1154.     tmp->TM_GMTOFF = offset;
  1155. #endif /* defined TM_GMTOFF */
  1156. }
  1157.  
  1158. char *
  1159. ctime(timep)
  1160. const time_t * const    timep;
  1161. {
  1162. /*
  1163. ** Section 4.12.3.2 of X3.159-1989 requires that
  1164. **    The ctime funciton converts the calendar time pointed to by timer
  1165. **    to local time in the form of a string.  It is equivalent to
  1166. **        asctime(localtime(timer))
  1167. */
  1168.     return asctime(localtime(timep));
  1169. }
  1170.  
  1171. /*
  1172. ** Adapted from code provided by Robert Elz, who writes:
  1173. **    The "best" way to do mktime I think is based on an idea of Bob
  1174. **    Kridle's (so its said...) from a long time ago. (mtxinu!kridle now).
  1175. **    It does a binary search of the time_t space.  Since time_t's are
  1176. **    just 32 bits, its a max of 32 iterations (even at 64 bits it
  1177. **    would still be very reasonable).
  1178. */
  1179.  
  1180. #ifndef WRONG
  1181. #define WRONG    (-1)
  1182. #endif /* !defined WRONG */
  1183.  
  1184. /*
  1185. ** Simplified normalize logic courtesy Paul Eggert (eggert@twinsun.com).
  1186. */
  1187.  
  1188. static int
  1189. increment_overflow(number, delta)
  1190. int *    number;
  1191. int    delta;
  1192. {
  1193.     int number0;
  1194.     
  1195.     number0 = *number;
  1196.     *number += delta;
  1197.     return (*number < number0) != (delta < 0);
  1198. }
  1199.  
  1200. static int
  1201. normalize_overflow(tensptr, unitsptr, base)
  1202. int * const    tensptr;
  1203. int * const    unitsptr;
  1204. const int    base;
  1205. {
  1206.     register int    tensdelta;
  1207.  
  1208.     tensdelta = (*unitsptr >= 0) ?
  1209.         (*unitsptr / base) :
  1210.         (-1 - (-1 - *unitsptr) / base);
  1211.     *unitsptr -= tensdelta * base;
  1212.     return increment_overflow(tensptr, tensdelta);
  1213. }
  1214.  
  1215. static int
  1216. tmcomp(atmp, btmp)
  1217. register const struct tm * const atmp;
  1218. register const struct tm * const btmp;
  1219. {
  1220.     register int    result;
  1221.  
  1222.     if ((result = (atmp->tm_year - btmp->tm_year)) == 0 &&
  1223.         (result = (atmp->tm_mon - btmp->tm_mon)) == 0 &&
  1224.         (result = (atmp->tm_mday - btmp->tm_mday)) == 0 &&
  1225.         (result = (atmp->tm_hour - btmp->tm_hour)) == 0 &&
  1226.         (result = (atmp->tm_min - btmp->tm_min)) == 0)
  1227.             result = atmp->tm_sec - btmp->tm_sec;
  1228.     return result;
  1229. }
  1230.  
  1231. static time_t
  1232. time2(tmp, funcp, offset, okayp)
  1233. struct tm * const    tmp;
  1234. void (* const        funcp)();
  1235. const long        offset;
  1236. int * const        okayp;
  1237. {
  1238.     register const struct state *    sp;
  1239.     register int            dir;
  1240.     register int            bits;
  1241.     register int            i, j ;
  1242.     register int            saved_seconds;
  1243.     time_t                newt;
  1244.     time_t                t;
  1245.     struct tm            yourtm, mytm;
  1246.  
  1247.     *okayp = FALSE;
  1248.     yourtm = *tmp;
  1249.     if (normalize_overflow(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR))
  1250.         return WRONG;
  1251.     if (normalize_overflow(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY))
  1252.         return WRONG;
  1253.     if (normalize_overflow(&yourtm.tm_year, &yourtm.tm_mon, MONSPERYEAR))
  1254.         return WRONG;
  1255.     /*
  1256.     ** Turn yourtm.tm_year into an actual year number for now.
  1257.     ** It is converted back to an offset from TM_YEAR_BASE later.
  1258.     */
  1259.     if (increment_overflow(&yourtm.tm_year, TM_YEAR_BASE))
  1260.         return WRONG;
  1261.     while (yourtm.tm_mday <= 0) {
  1262.         if (increment_overflow(&yourtm.tm_year, -1))
  1263.             return WRONG;
  1264.         yourtm.tm_mday += year_lengths[isleap(yourtm.tm_year)];
  1265.     }
  1266.     while (yourtm.tm_mday > DAYSPERLYEAR) {
  1267.         yourtm.tm_mday -= year_lengths[isleap(yourtm.tm_year)];
  1268.         if (increment_overflow(&yourtm.tm_year, 1))
  1269.             return WRONG;
  1270.     }
  1271.     for ( ; ; ) {
  1272.         i = mon_lengths[isleap(yourtm.tm_year)][yourtm.tm_mon];
  1273.         if (yourtm.tm_mday <= i)
  1274.             break;
  1275.         yourtm.tm_mday -= i;
  1276.         if (++yourtm.tm_mon >= MONSPERYEAR) {
  1277.             yourtm.tm_mon = 0;
  1278.             if (increment_overflow(&yourtm.tm_year, 1))
  1279.                 return WRONG;
  1280.         }
  1281.     }
  1282.     if (increment_overflow(&yourtm.tm_year, -TM_YEAR_BASE))
  1283.         return WRONG;
  1284.     if (yourtm.tm_year + TM_YEAR_BASE < EPOCH_YEAR) {
  1285.         /*
  1286.         ** We can't set tm_sec to 0, because that might push the
  1287.         ** time below the minimum representable time.
  1288.         ** Set tm_sec to 59 instead.
  1289.         ** This assumes that the minimum representable time is
  1290.         ** not in the same minute that a leap second was deleted from,
  1291.         ** which is a safer assumption than using 58 would be.
  1292.         */
  1293.         if (increment_overflow(&yourtm.tm_sec, 1 - SECSPERMIN))
  1294.             return WRONG;
  1295.         saved_seconds = yourtm.tm_sec;
  1296.         yourtm.tm_sec = SECSPERMIN - 1;
  1297.     } else {
  1298.         saved_seconds = yourtm.tm_sec;
  1299.         yourtm.tm_sec = 0;
  1300.     }
  1301.     /*
  1302.     ** Calculate the number of magnitude bits in a time_t
  1303.     ** (this works regardless of whether time_t is
  1304.     ** signed or unsigned, though lint complains if unsigned).
  1305.     */
  1306.     for (bits = 0, t = 1; t > 0; ++bits, t <<= 1)
  1307.         continue;
  1308.     /*
  1309.     ** If time_t is signed, then 0 is the median value,
  1310.     ** if time_t is unsigned, then 1 << bits is median.
  1311.     */
  1312.     t = (t < 0) ? 0 : ((time_t) 1 << bits);
  1313.     for ( ; ; ) {
  1314.         (*funcp)(&t, offset, &mytm);
  1315.         dir = tmcomp(&mytm, &yourtm);
  1316.         if (dir != 0) {
  1317.             if (bits-- < 0)
  1318.                 return WRONG;
  1319.             if (bits < 0)
  1320.                 --t;
  1321.             else if (dir > 0)
  1322.                 t -= (time_t) 1 << bits;
  1323.             else    t += (time_t) 1 << bits;
  1324.             continue;
  1325.         }
  1326.         if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst)
  1327.             break;
  1328.         /*
  1329.         ** Right time, wrong type.
  1330.         ** Hunt for right time, right type.
  1331.         ** It's okay to guess wrong since the guess
  1332.         ** gets checked.
  1333.         */
  1334.         /*
  1335.         ** The (void *) casts are the benefit of SunOS 3.3 on Sun 2's.
  1336.         */
  1337.         sp = (const struct state *)
  1338.             (((void *) funcp == (void *) localsub) ?
  1339.             lclptr : gmtptr);
  1340. #ifdef ALL_STATE
  1341.         if (sp == NULL)
  1342.             return WRONG;
  1343. #endif /* defined ALL_STATE */
  1344.         for (i = 0; i < sp->typecnt; ++i) {
  1345.             if (sp->ttis[i].tt_isdst != yourtm.tm_isdst)
  1346.                 continue;
  1347.             for (j = 0; j < sp->typecnt; ++j) {
  1348.                 if (sp->ttis[j].tt_isdst == yourtm.tm_isdst)
  1349.                     continue;
  1350.                 newt = t + sp->ttis[j].tt_gmtoff -
  1351.                     sp->ttis[i].tt_gmtoff;
  1352.                 (*funcp)(&newt, offset, &mytm);
  1353.                 if (tmcomp(&mytm, &yourtm) != 0)
  1354.                     continue;
  1355.                 if (mytm.tm_isdst != yourtm.tm_isdst)
  1356.                     continue;
  1357.                 /*
  1358.                 ** We have a match.
  1359.                 */
  1360.                 t = newt;
  1361.                 goto label;
  1362.             }
  1363.         }
  1364.         return WRONG;
  1365.     }
  1366. label:
  1367.     newt = t + saved_seconds;
  1368.     if ((newt < t) != (saved_seconds < 0))
  1369.         return WRONG;
  1370.     t = newt;
  1371.     (*funcp)(&t, offset, tmp);
  1372.     *okayp = TRUE;
  1373.     return t;
  1374. }
  1375.  
  1376. static time_t
  1377. time1(tmp, funcp, offset)
  1378. struct tm * const    tmp;
  1379. void (* const        funcp)();
  1380. const long        offset;
  1381. {
  1382.     register time_t            t;
  1383.     register const struct state *    sp;
  1384.     register int            samei, otheri;
  1385.     int                okay;
  1386.  
  1387.     if (tmp->tm_isdst > 1)
  1388.         tmp->tm_isdst = 1;
  1389.     t = time2(tmp, funcp, offset, &okay);
  1390. #ifdef PCTS
  1391.     /*
  1392.     ** PCTS code courtesy Grant Sullivan (grant@osf.org).
  1393.     */
  1394.     if (okay)
  1395.         return t;
  1396.     if (tmp->tm_isdst < 0)
  1397.         tmp->tm_isdst = 0;    /* reset to std and try again */
  1398. #endif /* defined PCTS */
  1399. #ifndef PCTS
  1400.     if (okay || tmp->tm_isdst < 0)
  1401.         return t;
  1402. #endif /* !defined PCTS */
  1403.     /*
  1404.     ** We're supposed to assume that somebody took a time of one type
  1405.     ** and did some math on it that yielded a "struct tm" that's bad.
  1406.     ** We try to divine the type they started from and adjust to the
  1407.     ** type they need.
  1408.     */
  1409.     /*
  1410.     ** The (void *) casts are the benefit of SunOS 3.3 on Sun 2's.
  1411.     */
  1412.     sp = (const struct state *) (((void *) funcp == (void *) localsub) ?
  1413.         lclptr : gmtptr);
  1414. #ifdef ALL_STATE
  1415.     if (sp == NULL)
  1416.         return WRONG;
  1417. #endif /* defined ALL_STATE */
  1418.     for (samei = 0; samei < sp->typecnt; ++samei) {
  1419.         if (sp->ttis[samei].tt_isdst != tmp->tm_isdst)
  1420.             continue;
  1421.         for (otheri = 0; otheri < sp->typecnt; ++otheri) {
  1422.             if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst)
  1423.                 continue;
  1424.             tmp->tm_sec += sp->ttis[otheri].tt_gmtoff -
  1425.                     sp->ttis[samei].tt_gmtoff;
  1426.             tmp->tm_isdst = !tmp->tm_isdst;
  1427.             t = time2(tmp, funcp, offset, &okay);
  1428.             if (okay)
  1429.                 return t;
  1430.             tmp->tm_sec -= sp->ttis[otheri].tt_gmtoff -
  1431.                     sp->ttis[samei].tt_gmtoff;
  1432.             tmp->tm_isdst = !tmp->tm_isdst;
  1433.         }
  1434.     }
  1435.     return WRONG;
  1436. }
  1437.  
  1438. time_t
  1439. mktime(tmp)
  1440. struct tm * const    tmp;
  1441. {
  1442.     tzset();
  1443.     return time1(tmp, localsub, 0L);
  1444. }
  1445.  
  1446. #ifdef STD_INSPIRED
  1447.  
  1448. time_t
  1449. timelocal(tmp)
  1450. struct tm * const    tmp;
  1451. {
  1452.     tmp->tm_isdst = -1;    /* in case it wasn't initialized */
  1453.     return mktime(tmp);
  1454. }
  1455.  
  1456. time_t
  1457. timegm(tmp)
  1458. struct tm * const    tmp;
  1459. {
  1460.     tmp->tm_isdst = 0;
  1461.     return time1(tmp, gmtsub, 0L);
  1462. }
  1463.  
  1464. time_t
  1465. timeoff(tmp, offset)
  1466. struct tm * const    tmp;
  1467. const long        offset;
  1468. {
  1469.     tmp->tm_isdst = 0;
  1470.     return time1(tmp, gmtsub, offset);
  1471. }
  1472.  
  1473. #endif /* defined STD_INSPIRED */
  1474.  
  1475. #ifdef CMUCS
  1476.  
  1477. /*
  1478. ** The following is supplied for compatibility with
  1479. ** previous versions of the CMUCS runtime library.
  1480. */
  1481.  
  1482. long
  1483. gtime(tmp)
  1484. struct tm * const    tmp;
  1485. {
  1486.     const time_t    t = mktime(tmp);
  1487.  
  1488.     if (t == WRONG)
  1489.         return -1;
  1490.     return t;
  1491. }
  1492.  
  1493. #endif /* defined CMUCS */
  1494.  
  1495. /*
  1496. ** XXX--is the below the right way to conditionalize??
  1497. */
  1498.  
  1499. #ifdef STD_INSPIRED
  1500.  
  1501. /*
  1502. ** IEEE Std 1003.1-1988 (POSIX) legislates that 536457599
  1503. ** shall correspond to "Wed Dec 31 23:59:59 GMT 1986", which
  1504. ** is not the case if we are accounting for leap seconds.
  1505. ** So, we provide the following conversion routines for use
  1506. ** when exchanging timestamps with POSIX conforming systems.
  1507. */
  1508.  
  1509. static long
  1510. leapcorr(timep)
  1511. time_t *    timep;
  1512. {
  1513.     register struct state *        sp;
  1514.     register struct lsinfo *    lp;
  1515.     register int            i;
  1516.  
  1517.     sp = lclptr;
  1518.     i = sp->leapcnt;
  1519.     while (--i >= 0) {
  1520.         lp = &sp->lsis[i];
  1521.         if (*timep >= lp->ls_trans)
  1522.             return lp->ls_corr;
  1523.     }
  1524.     return 0;
  1525. }
  1526.  
  1527. time_t
  1528. time2posix(t)
  1529. time_t    t;
  1530. {
  1531.     tzset();
  1532.     return t - leapcorr(&t);
  1533. }
  1534.  
  1535. time_t
  1536. posix2time(t)
  1537. time_t    t;
  1538. {
  1539.     time_t    x;
  1540.     time_t    y;
  1541.  
  1542.     tzset();
  1543.     /*
  1544.     ** For a positive leap second hit, the result
  1545.     ** is not unique.  For a negative leap second
  1546.     ** hit, the corresponding time doesn't exist,
  1547.     ** so we return an adjacent second.
  1548.     */
  1549.     x = t + leapcorr(&t);
  1550.     y = x - leapcorr(&x);
  1551.     if (y < t) {
  1552.         do {
  1553.             x++;
  1554.             y = x - leapcorr(&x);
  1555.         } while (y < t);
  1556.         if (t != y)
  1557.             return x - 1;
  1558.     } else if (y > t) {
  1559.         do {
  1560.             --x;
  1561.             y = x - leapcorr(&x);
  1562.         } while (y > t);
  1563.         if (t != y)
  1564.             return x + 1;
  1565.     }
  1566.     return x;
  1567. }
  1568.  
  1569. #endif /* defined STD_INSPIRED */
  1570.