home *** CD-ROM | disk | FTP | other *** search
/ Chip 1995 March / CHIP3.mdf / slackwar / a / util / util-lin.10 / util-lin / util-linux-1.10 / time / localtime.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-03-30  |  34.4 KB  |  1,490 lines

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