home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / ixemul-45.0-src.tgz / tar.out / contrib / ixemul / static / localtime.c < prev    next >
C/C++ Source or Header  |  1996-10-01  |  39KB  |  1,621 lines

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