Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. /*
  2.   Copyright (c) 1990-2001 Info-ZIP.  All rights reserved.
  3.  
  4.   See the accompanying file LICENSE, version 2000-Apr-09 or later
  5.   (the contents of which are also included in zip.h) for terms of use.
  6.   If, for some reason, all these files are missing, the Info-ZIP license
  7.   also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
  8. */
  9. /* Replacement time library functions, based on platform independent public
  10.  * domain timezone code from ftp://elsie.nci.nih.gov/pub, with mktime and
  11.  * mkgmtime from our own mktime.c in Zip.
  12.  *
  13.  * Contains:  tzset()
  14.  *            __tzset()
  15.  *            gmtime()
  16.  *            localtime()
  17.  *            mktime()
  18.  *            mkgmtime()
  19.  *            GetPlatformLocalTimezone()  [different versions]
  20.  */
  21.  
  22. /* HISTORY/CHANGES
  23.  * 17 Jun 00, Paul Kienitz, added the PD-based tzset(), localtime(), and so on
  24.  *            to amiga/filedate.c, replacing GNU-based functions which had
  25.  *            replaced time_lib.c, both having been rejected for licensing
  26.  *            reasons.  Support for timezone files and leap seconds was removed.
  27.  *
  28.  * 23 Aug 00, Paul Kienitz, split into separate timezone.c file, made platform
  29.  *            independent, copied in mktime() and mkgmtime() from Zip, renamed
  30.  *            locale_TZ as GetPlatformLocalTimezone(), for use as a generic
  31.  *            hook by other platforms.
  32.  */
  33.  
  34. #ifndef __timezone_c
  35. #define __timezone_c
  36.  
  37.  
  38. #include "zip.h"
  39. #include "timezone.h"
  40. #include <ctype.h>
  41. #include <errno.h>
  42.  
  43. #ifdef IZTZ_DEFINESTDGLOBALS
  44. long timezone = 0;
  45. int daylight = 0;
  46. char *tzname[2];
  47. #endif
  48.  
  49. #ifndef IZTZ_GETLOCALETZINFO
  50. #  define IZTZ_GETLOCALETZINFO(ptzstruct, pgenrulefunct) (FALSE)
  51. #endif
  52.  
  53. int real_timezone_is_set = FALSE;       /* set by tzset() */
  54.  
  55.  
  56. #define TZDEFRULESTRING ",M4.1.0,M10.5.0"
  57. #define TZDEFAULT       "EST5EDT"
  58.  
  59. #define SECSPERMIN      60
  60. #define MINSPERHOUR     60
  61. #define HOURSPERDAY     24
  62. #define DAYSPERWEEK     7
  63. #define DAYSPERNYEAR    365
  64. #define DAYSPERLYEAR    366
  65. #define SECSPERHOUR     (SECSPERMIN * MINSPERHOUR)
  66. #define SECSPERDAY      ((long) SECSPERHOUR * HOURSPERDAY)
  67. #define MONSPERYEAR 12
  68.  
  69. #define EPOCH_WDAY      4     /* Jan 1, 1970 was thursday */
  70. #define EPOCH_YEAR      1970
  71. #define TM_YEAR_BASE    1900
  72. #define FIRST_GOOD_YEAR ((time_t) -1 < (time_t) 1 ? EPOCH_YEAR-68 : EPOCH_YEAR)
  73. #define LAST_GOOD_YEAR  (EPOCH_YEAR + ((time_t) -1 < (time_t) 1 ? 67 : 135))
  74.  
  75. #define YDAYS(month, year) yr_days[leap(year)][month]
  76.  
  77. /* Nonzero if `y' is a leap year, else zero. */
  78. #define leap(y)  (((y) % 4 == 0 && (y) % 100 != 0) || (y) % 400 == 0)
  79.  
  80. /* Number of leap years from EPOCH_YEAR  to `y' (not including `y' itself). */
  81. #define _P4      ((EPOCH_YEAR / 4) * 4 + 1)
  82. #define _P100    ((EPOCH_YEAR / 100) * 100 + 1)
  83. #define _P400    ((EPOCH_YEAR / 400) * 400 + 1)
  84. #define nleap(y) (((y) - _P4) / 4 - ((y) - _P100) / 100 + ((y) - _P400) / 400)
  85.  
  86. /* Length of month `m' (0 .. 11) */
  87. #define monthlen(m, y) (yr_days[0][(m)+1] - yr_days[0][m] + \
  88.                         ((m) == 1 && leap(y)))
  89.  
  90. /* internal module-level constants */
  91. #ifndef IZ_MKTIME_ONLY
  92. static ZCONST char  gmt[] = "GMT";
  93. static ZCONST int    mon_lengths[2][MONSPERYEAR] = {
  94.     { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
  95.     { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
  96. };
  97. #endif /* !IZ_MKTIME_ONLY */
  98. static ZCONST int    yr_days[2][MONSPERYEAR+1] = {
  99.     { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
  100.     { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
  101. };
  102. #ifndef IZ_MKTIME_ONLY
  103. static ZCONST int   year_lengths[2] = {
  104.     DAYSPERNYEAR, DAYSPERLYEAR
  105. };
  106.  
  107. /* internal variables */
  108. static struct state statism;
  109.  
  110.  
  111. /* prototypes of static functions */
  112. static time_t transtime OF((ZCONST time_t janfirst, ZCONST int year,
  113.                             ZCONST struct rule * ZCONST rulep,
  114.                             ZCONST long offset));
  115. static void generate_transitions OF((register struct state * ZCONST sp,
  116.                                      ZCONST struct rule * ZCONST start,
  117.                                      ZCONST struct rule * ZCONST end));
  118. static ZCONST char *getzname OF((ZCONST char *strp));
  119. static ZCONST char *getnum OF((ZCONST char *strp, int * ZCONST nump,
  120.                                ZCONST int min, ZCONST int max));
  121. static ZCONST char *getsecs OF((ZCONST char *strp, long * ZCONST secsp));
  122. static ZCONST char *getoffset OF((ZCONST char *strp, long * ZCONST offsetp));
  123. static ZCONST char *getrule OF((ZCONST char *strp, struct rule * ZCONST rulep));
  124. static int Parse_TZ OF((ZCONST char *name, register struct state * ZCONST sp));
  125.  
  126.  
  127. static time_t transtime(janfirst, year, rulep, offset)
  128.      ZCONST time_t janfirst;
  129.      ZCONST int year;
  130.      ZCONST struct rule * ZCONST rulep;
  131.      ZCONST long offset;
  132. {
  133.     register int    leapyear;
  134.     register time_t value;
  135.     register int    i;
  136.     int             d, m1, yy0, yy1, yy2, dow;
  137.  
  138.     value = 0;
  139.     leapyear = leap(year);
  140.     switch (rulep->r_type) {
  141.  
  142.     case JULIAN_DAY:
  143.         /*
  144.         ** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap
  145.         ** years.
  146.         ** In non-leap years, or if the day number is 59 or less, just
  147.         ** add SECSPERDAY times the day number-1 to the time of
  148.         ** January 1, midnight, to get the day.
  149.         */
  150.         value = janfirst + (rulep->r_day - 1) * SECSPERDAY;
  151.         if (leapyear && rulep->r_day >= 60)
  152.             value += SECSPERDAY;
  153.         break;
  154.  
  155.     case DAY_OF_YEAR:
  156.         /*
  157.         ** n - day of year.
  158.         ** Just add SECSPERDAY times the day number to the time of
  159.         ** January 1, midnight, to get the day.
  160.         */
  161.         value = janfirst + rulep->r_day * SECSPERDAY;
  162.         break;
  163.  
  164.     case MONTH_NTH_DAY_OF_WEEK:
  165.         /*
  166.         ** Mm.n.d - nth "dth day" of month m.
  167.         */
  168.         value = janfirst;
  169. /*
  170.         for (i = 0; i < rulep->r_mon - 1; ++i)
  171.             value += mon_lengths[leapyear][i] * SECSPERDAY;
  172. */
  173.         value += yr_days[leapyear][rulep->r_mon - 1] * SECSPERDAY;
  174.  
  175.         /*
  176.         ** Use Zeller's Congruence to get day-of-week of first day of
  177.         ** month.
  178.         */
  179.         m1 = (rulep->r_mon + 9) % 12 + 1;
  180.         yy0 = (rulep->r_mon <= 2) ? (year - 1) : year;
  181.         yy1 = yy0 / 100;
  182.         yy2 = yy0 % 100;
  183.         dow = ((26 * m1 - 2) / 10 +
  184.             1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7;
  185.         if (dow < 0)
  186.             dow += DAYSPERWEEK;
  187.  
  188.         /*
  189.         ** "dow" is the day-of-week of the first day of the month.  Get
  190.         ** the day-of-month (zero-origin) of the first "dow" day of the
  191.         ** month.
  192.         */
  193.         d = rulep->r_day - dow;
  194.         if (d < 0)
  195.             d += DAYSPERWEEK;
  196.         for (i = 1; i < rulep->r_week; ++i) {
  197.             if (d + DAYSPERWEEK >= mon_lengths[leapyear][rulep->r_mon - 1])
  198.                 break;
  199.             d += DAYSPERWEEK;
  200.         }
  201.  
  202.         /*
  203.         ** "d" is the day-of-month (zero-origin) of the day we want.
  204.         */
  205.         value += d * SECSPERDAY;
  206.         break;
  207.     }
  208.  
  209.     /*
  210.     ** "value" is the Epoch-relative time of 00:00:00 UTC on the day in
  211.     ** question.  To get the Epoch-relative time of the specified local
  212.     ** time on that day, add the transition time and the current offset
  213.     ** from UTC.
  214.     */
  215.     return value + rulep->r_time + offset;
  216. }
  217.  
  218. static void generate_transitions(sp, start, end)
  219.      register struct state * ZCONST sp;
  220.      ZCONST struct rule * ZCONST start;
  221.      ZCONST struct rule * ZCONST end;
  222. {
  223.     register int             year;
  224.     register time_t          janfirst;
  225.     time_t                   starttime;
  226.     time_t                   endtime;
  227.     long                     stdoffset = -sp->ttis[0].tt_gmtoff;
  228.     long                     dstoffset = -sp->ttis[1].tt_gmtoff;
  229.     register time_t *        atp;
  230.     register unsigned char * typep;
  231.  
  232.     /*
  233.     ** Two transitions per year, from EPOCH_YEAR to LAST_GOOD_YEAR.
  234.     */
  235.     sp->timecnt = 2 * (LAST_GOOD_YEAR - EPOCH_YEAR + 1);
  236.     atp = sp->ats;
  237.     typep = sp->types;
  238.     janfirst = 0;
  239.     for (year = EPOCH_YEAR; year <= LAST_GOOD_YEAR; ++year) {
  240.         starttime = transtime(janfirst, year, start, stdoffset);
  241.         endtime = transtime(janfirst, year, end, dstoffset);
  242.         if (starttime > endtime) {
  243.             *atp++ = endtime;
  244.             *typep++ = 0;   /* DST ends */
  245.             *atp++ = starttime;
  246.             *typep++ = 1;   /* DST begins */
  247.         } else {
  248.             *atp++ = starttime;
  249.             *typep++ = 1;   /* DST begins */
  250.             *atp++ = endtime;
  251.             *typep++ = 0;   /* DST ends */
  252.         }
  253.         janfirst += year_lengths[leap(year)] * SECSPERDAY;
  254.     }
  255. }
  256.  
  257. static ZCONST char *getzname(strp)
  258.      ZCONST char *strp;
  259. {
  260.     register char   c;
  261.  
  262.     while ((c = *strp) != '\0' && !isdigit(c) && c != ',' && c != '-' &&
  263.         c != '+')
  264.             ++strp;
  265.     return strp;
  266. }
  267.  
  268. static ZCONST char *getnum(strp, nump, min, max)
  269.      ZCONST char *strp;
  270.      int * ZCONST nump;
  271.      ZCONST int min;
  272.      ZCONST int max;
  273. {
  274.     register char   c;
  275.     register int    num;
  276.  
  277.     if (strp == NULL || !isdigit(c = *strp))
  278.         return NULL;
  279.     num = 0;
  280.     do {
  281.         num = num * 10 + (c - '0');
  282.         if (num > max)
  283.             return NULL;    /* illegal value */
  284.         c = *++strp;
  285.     } while (isdigit(c));
  286.     if (num < min)
  287.         return NULL;        /* illegal value */
  288.     *nump = num;
  289.     return strp;
  290. }
  291.  
  292. static ZCONST char *getsecs(strp, secsp)
  293.      ZCONST char *strp;
  294.      long * ZCONST secsp;
  295. {
  296.     int num;
  297.  
  298.     /*
  299.     ** `HOURSPERDAY * DAYSPERWEEK - 1' allows quasi-Posix rules like
  300.     ** "M10.4.6/26", which does not conform to Posix,
  301.     ** but which specifies the equivalent of
  302.     ** ``02:00 on the first Sunday on or after 23 Oct''.
  303.     */
  304.     strp = getnum(strp, &num, 0, HOURSPERDAY * DAYSPERWEEK - 1);
  305.     if (strp == NULL)
  306.         return NULL;
  307.     *secsp = num * (long) SECSPERHOUR;
  308.     if (*strp == ':') {
  309.         ++strp;
  310.         strp = getnum(strp, &num, 0, MINSPERHOUR - 1);
  311.         if (strp == NULL)
  312.             return NULL;
  313.         *secsp += num * SECSPERMIN;
  314.         if (*strp == ':') {
  315.             ++strp;
  316.             /* `SECSPERMIN' allows for leap seconds.  */
  317.             strp = getnum(strp, &num, 0, SECSPERMIN);
  318.             if (strp == NULL)
  319.                 return NULL;
  320.             *secsp += num;
  321.         }
  322.     }
  323.     return strp;
  324. }
  325.  
  326. static ZCONST char *getoffset(strp, offsetp)
  327.      ZCONST char *strp;
  328.      long * ZCONST offsetp;
  329. {
  330.     register int    neg = 0;
  331.  
  332.     if (*strp == '-') {
  333.         neg = 1;
  334.         ++strp;
  335.     } else if (*strp == '+')
  336.         ++strp;
  337.     strp = getsecs(strp, offsetp);
  338.     if (strp == NULL)
  339.         return NULL;        /* illegal time */
  340.     if (neg)
  341.         *offsetp = -*offsetp;
  342.     return strp;
  343. }
  344.  
  345. static ZCONST char *getrule(strp, rulep)
  346.      ZCONST char *strp;
  347.      struct rule * ZCONST rulep;
  348. {
  349.     if (*strp == 'J') {
  350.         /*
  351.         ** Julian day.
  352.         */
  353.         rulep->r_type = JULIAN_DAY;
  354.         ++strp;
  355.         strp = getnum(strp, &rulep->r_day, 1, DAYSPERNYEAR);
  356.     } else if (*strp == 'M') {
  357.         /*
  358.         ** Month, week, day.
  359.         */
  360.         rulep->r_type = MONTH_NTH_DAY_OF_WEEK;
  361.         ++strp;
  362.         strp = getnum(strp, &rulep->r_mon, 1, MONSPERYEAR);
  363.         if (strp == NULL)
  364.             return NULL;
  365.         if (*strp++ != '.')
  366.             return NULL;
  367.         strp = getnum(strp, &rulep->r_week, 1, 5);
  368.         if (strp == NULL)
  369.             return NULL;
  370.         if (*strp++ != '.')
  371.             return NULL;
  372.         strp = getnum(strp, &rulep->r_day, 0, DAYSPERWEEK - 1);
  373.     } else if (isdigit(*strp)) {
  374.         /*
  375.         ** Day of year.
  376.         */
  377.         rulep->r_type = DAY_OF_YEAR;
  378.         strp = getnum(strp, &rulep->r_day, 0, DAYSPERLYEAR - 1);
  379.     } else  return NULL;        /* invalid format */
  380.     if (strp == NULL)
  381.         return NULL;
  382.     if (*strp == '/') {
  383.         /*
  384.         ** Time specified.
  385.         */
  386.         ++strp;
  387.         strp = getsecs(strp, &rulep->r_time);
  388.     } else
  389.         rulep->r_time = 2 * SECSPERHOUR;    /* default = 2:00:00 */
  390.     return strp;
  391. }
  392.  
  393. static int Parse_TZ(name, sp)
  394.      ZCONST char *name;
  395.      register struct state * ZCONST sp;
  396. {
  397.     ZCONST char *            stdname;
  398.     ZCONST char *            dstname;
  399.     size_t                   stdlen;
  400.     size_t                   dstlen;
  401.     long                     stdoffset;
  402.     long                     dstoffset;
  403.     register char *          cp;
  404.  
  405.     dstname = NULL;
  406.     stdname = name;
  407.     name = getzname(name);
  408.     stdlen = name - stdname;
  409.     if (stdlen < 3)
  410.         return -1;
  411.     if (*name == '\0')
  412.         return -1;
  413.     name = getoffset(name, &stdoffset);
  414.     if (name == NULL)
  415.         return -1;
  416.     if (*name != '\0') {
  417.         dstname = name;
  418.         name = getzname(name);
  419.         dstlen = name - dstname;    /* length of DST zone name */
  420.         if (dstlen < 3)
  421.             return -1;
  422.         if (*name != '\0' && *name != ',' && *name != ';') {
  423.             name = getoffset(name, &dstoffset);
  424.             if (name == NULL)
  425.                 return -1;
  426.         } else
  427.             dstoffset = stdoffset - SECSPERHOUR;
  428.         if (*name == '\0')
  429.             name = TZDEFRULESTRING;
  430.         if (*name == ',' || *name == ';') {
  431.             struct rule     start;
  432.             struct rule     end;
  433.  
  434.             ++name;
  435.             if ((name = getrule(name, &start)) == NULL)
  436.                 return -1;
  437.             if (*name++ != ',')
  438.                 return -1;
  439.             if ((name = getrule(name, &end)) == NULL)
  440.                 return -1;
  441.             if (*name != '\0')
  442.                 return -1;
  443.             sp->typecnt = 2;    /* standard time and DST */
  444.             sp->ttis[0].tt_gmtoff = -stdoffset;
  445.             sp->ttis[0].tt_isdst = 0;
  446.             sp->ttis[0].tt_abbrind = 0;
  447.             sp->ttis[1].tt_gmtoff = -dstoffset;
  448.             sp->ttis[1].tt_isdst = 1;
  449.             sp->ttis[1].tt_abbrind = stdlen + 1;
  450.             generate_transitions(sp, &start, &end);
  451.         }
  452.     } else {
  453.         dstlen = 0;
  454.         sp->typecnt = 1;        /* only standard time */
  455.         sp->timecnt = 0;
  456.         sp->ttis[0].tt_gmtoff = -stdoffset;
  457.         sp->ttis[0].tt_isdst = 0;
  458.         sp->ttis[0].tt_abbrind = 0;
  459.     }
  460.     sp->charcnt = stdlen + 1;
  461.     if (dstlen != 0)
  462.         sp->charcnt += dstlen + 1;
  463.     if ((size_t) sp->charcnt > sizeof(sp->chars))
  464.         return -1;
  465.     cp = sp->chars;
  466.     (void) strncpy(cp, stdname, stdlen);
  467.     cp += stdlen;
  468.     *cp++ = '\0';
  469.     if (dstlen != 0) {
  470.         (void) strncpy(cp, dstname, dstlen);
  471.         *(cp + dstlen) = '\0';
  472.     }
  473.     return 0;
  474. }
  475.  
  476. void tzset()
  477. {
  478.     char *TZstring;
  479.     int dstfirst;
  480.     static char *old_TZstring = NULL;
  481.  
  482.     TZstring = getenv("TZ");    /* read TZ envvar */
  483.     if (old_TZstring && TZstring && !strcmp(old_TZstring, TZstring))
  484.         /* do not repeatedly parse an unchanged TZ specification */
  485.         return;
  486.     if ((TZstring && TZstring[0] && Parse_TZ(TZstring, &statism) == 0)
  487.                 || IZTZ_GETLOCALETZINFO(&statism, generate_transitions)
  488.                 || Parse_TZ(gmt, &statism) == 0) {
  489.         daylight  = statism.typecnt > 1;
  490.         dstfirst  = daylight && statism.ttis[0].tt_isdst && !statism.ttis[1].tt_isdst;
  491.         timezone  = -statism.ttis[dstfirst].tt_gmtoff;
  492.         tzname[0] = statism.chars + statism.ttis[dstfirst].tt_abbrind;
  493.         tzname[1] = statism.chars + statism.ttis[!dstfirst].tt_abbrind;
  494.         real_timezone_is_set = TRUE;
  495.         if (TZstring) {
  496.             if (old_TZstring)
  497.                 old_TZstring = realloc(old_TZstring, strlen(TZstring) + 1);
  498.             else
  499.                 old_TZstring = malloc(strlen(TZstring) + 1);
  500.             if (old_TZstring)
  501.                 strcpy(old_TZstring, TZstring);
  502.         }
  503.     } else {
  504.         timezone = 0;   /* default is GMT0 which means no offsets */
  505.         daylight = 0;   /* from local system time                 */
  506.         real_timezone_is_set = FALSE;
  507.         if (old_TZstring) {
  508.             free(old_TZstring);
  509.             old_TZstring = NULL;
  510.         }
  511.     }
  512. #ifdef IZTZ_SETLOCALTZINFO
  513.     /* Some SAS/C library functions, e.g. stat(), call library       */
  514.     /* __tzset() themselves. So envvar TZ *must* exist in order to   */
  515.     /* to get the right offset from GMT.  XXX  TRY HARD to fix this! */
  516.     set_TZ(timezone, daylight);
  517. #endif /* IZTZ_SETLOCALTZINFO */
  518. }
  519.  
  520. /* XXX  Does this also help SAS/C library work? */
  521. void __tzset()
  522. {
  523.     if (!real_timezone_is_set) tzset();
  524. }
  525.  
  526. static struct tm _tmbuf;
  527.  
  528. struct tm *gmtime(when)
  529.      ZCONST time_t *when;
  530. {
  531.     long days = *when / SECSPERDAY;
  532.     long secs = *when % SECSPERDAY;
  533.     int isleap;
  534.  
  535.     memset(&_tmbuf, 0, sizeof(_tmbuf));   /* get any nonstandard fields */
  536.     _tmbuf.tm_wday = (days + EPOCH_WDAY) % 7;
  537.     _tmbuf.tm_year = EPOCH_YEAR - TM_YEAR_BASE;
  538.     isleap = leap(_tmbuf.tm_year + TM_YEAR_BASE);
  539.     while (days >= year_lengths[isleap]) {
  540.         days -= year_lengths[isleap];
  541.         _tmbuf.tm_year++;
  542.         isleap = leap(_tmbuf.tm_year + TM_YEAR_BASE);
  543.     }
  544.     _tmbuf.tm_mon = 0;
  545.     _tmbuf.tm_yday = days;
  546.     while (days >= mon_lengths[isleap][_tmbuf.tm_mon])
  547.         days -= mon_lengths[isleap][_tmbuf.tm_mon++];
  548.     _tmbuf.tm_mday = days + 1;
  549.     _tmbuf.tm_isdst = 0;
  550.     _tmbuf.tm_sec = secs % SECSPERMIN;
  551.     _tmbuf.tm_min = (secs / SECSPERMIN) % SECSPERMIN;
  552.     _tmbuf.tm_hour = secs / SECSPERHOUR;
  553.     return &_tmbuf;
  554. }
  555.  
  556. struct tm *localtime(when)
  557.      ZCONST time_t *when;
  558. {
  559.     time_t     localwhen = *when;
  560.     int        timetype;
  561.     struct tm *ret;
  562.  
  563.     __tzset();
  564.     if (statism.timecnt == 0 || localwhen < statism.ats[0])
  565.         timetype = statism.ttis[0].tt_isdst && statism.typecnt > 1 &&
  566.                    !statism.ttis[1].tt_isdst;
  567.     else {
  568.         for (timetype = 1; timetype < statism.timecnt; ++timetype)
  569.             if (localwhen < statism.ats[timetype])
  570.                 break;
  571.         timetype = statism.types[timetype - 1];
  572.     }
  573.     localwhen += statism.ttis[timetype].tt_gmtoff;
  574.     ret = gmtime(&localwhen);
  575.     ret->tm_isdst = statism.ttis[timetype].tt_isdst;
  576.     return ret;
  577. }
  578.  
  579. #ifdef NEED__ISINDST
  580. int _isindst(tb)
  581.     struct tm *tb;
  582. {
  583.     time_t     localt;          /* time_t equivalent of given tm struct */
  584.     time_t     univt;           /* assumed UTC value of given time */
  585.     long       tzoffset_adj;    /* timezone-adjustment `remainder' */
  586.     int        bailout_cnt;     /* counter of tries for tz correction */
  587.     int        timetype;
  588.  
  589.     __tzset();
  590.  
  591.     /* when DST is unsupported in current timezone, DST is always off */
  592.     if (statism.typecnt <= 1) return FALSE;
  593.  
  594.     localt = mkgmtime(tb);
  595.     if (localt == (time_t)-1)
  596.         /* specified time is out-of-range, default to FALSE */
  597.         return FALSE;
  598.  
  599.     univt = localt - statism.ttis[0].tt_gmtoff;
  600.     bailout_cnt = 3;
  601.     do {
  602.         if (statism.timecnt == 0 || univt < statism.ats[0])
  603.             timetype = statism.ttis[0].tt_isdst && statism.typecnt > 1 &&
  604.                        !statism.ttis[1].tt_isdst;
  605.         else {
  606.             for (timetype = 1; timetype < statism.timecnt; ++timetype)
  607.                 if (univt < statism.ats[timetype])
  608.                     break;
  609.             timetype = statism.types[timetype - 1];
  610.         }
  611.         if ((tzoffset_adj = localt - univt - statism.ttis[timetype].tt_gmtoff)
  612.             == 0L)
  613.             break;
  614.         univt += tzoffset_adj;
  615.     } while (--bailout_cnt > 0);
  616.  
  617.     /* return TRUE when DST is active at given time */
  618.     return (statism.ttis[timetype].tt_isdst);
  619. }
  620. #endif /* NEED__ISINDST */
  621. #endif /* !IZ_MKTIME_ONLY */
  622.  
  623. /* Return the equivalent in seconds past 12:00:00 a.m. Jan 1, 1970 GMT
  624.    of the local time and date in the exploded time structure `tm',
  625.    adjust out of range fields in `tm' and set `tm->tm_yday', `tm->tm_wday'.
  626.    If `tm->tm_isdst < 0' was passed to mktime(), the correct setting of
  627.    tm_isdst is determined and returned. Otherwise, mktime() assumes this
  628.    field as valid; its information is used when converting local time
  629.    to UTC.
  630.    Return -1 if time in `tm' cannot be represented as time_t value. */
  631.  
  632. time_t mktime(tm)
  633.      struct tm *tm;
  634. {
  635.   struct tm *ltm;               /* Local time. */
  636.   time_t loctime;               /* The time_t value of local time. */
  637.   time_t then;                  /* The time to return. */
  638.   long tzoffset_adj;            /* timezone-adjustment `remainder' */
  639.   int bailout_cnt;              /* counter of tries for tz correction */
  640.   int save_isdst;               /* Copy of the tm->isdst input value */
  641.  
  642.   save_isdst = tm->tm_isdst;
  643.   loctime = mkgmtime(tm);
  644.   if (loctime == -1) {
  645.     tm->tm_isdst = save_isdst;
  646.     return (time_t)-1;
  647.   }
  648.  
  649.   /* Correct for the timezone and any daylight savings time.
  650.      The correction is verified and repeated when not correct, to
  651.      take into account the rare case that a change to or from daylight
  652.      savings time occurs between when it is the time in `tm' locally
  653.      and when it is that time in Greenwich. After the second correction,
  654.      the "timezone & daylight" offset should be correct in all cases. To
  655.      be sure, we allow a third try, but then the loop is stopped. */
  656.   bailout_cnt = 3;
  657.   then = loctime;
  658.   do {
  659.     ltm = localtime(&then);
  660.     if (ltm == (struct tm *)NULL ||
  661.         (tzoffset_adj = loctime - mkgmtime(ltm)) == 0L)
  662.       break;
  663.     then += tzoffset_adj;
  664.   } while (--bailout_cnt > 0);
  665.  
  666.   if (ltm == (struct tm *)NULL || tzoffset_adj != 0L) {
  667.     /* Signal failure if timezone adjustment did not converge. */
  668.     tm->tm_isdst = save_isdst;
  669.     return (time_t)-1;
  670.   }
  671.  
  672.   if (save_isdst >= 0) {
  673.     if (ltm->tm_isdst  && !save_isdst)
  674.     {
  675.       if (then + 3600 < then)
  676.         then = (time_t)-1;
  677.       else
  678.         then += 3600;
  679.     }
  680.     else if (!ltm->tm_isdst && save_isdst)
  681.     {
  682.       if (then - 3600 > then)
  683.         then = (time_t)-1;
  684.       else
  685.         then -= 3600;
  686.     }
  687.     ltm->tm_isdst = save_isdst;
  688.   }
  689.  
  690.   if (tm != ltm)  /* `tm' may already point to localtime's internal storage */
  691.     *tm = *ltm;
  692.  
  693.   return then;
  694. }
  695.  
  696.  
  697. #ifndef NO_TIME_T_MAX
  698.    /* Provide default values for the upper limit of the time_t range.
  699.       These are the result of the decomposition into a `struct tm' for
  700.       the time value 0xFFFFFFFEL ( = (time_t)-2 ).
  701.       Note: `(time_t)-1' is reserved for "invalid time"!  */
  702. #  ifndef TM_YEAR_MAX
  703. #    define TM_YEAR_MAX         2106
  704. #  endif
  705. #  ifndef TM_MON_MAX
  706. #    define TM_MON_MAX          1       /* February */
  707. #  endif
  708. #  ifndef TM_MDAY_MAX
  709. #    define TM_MDAY_MAX         7
  710. #  endif
  711. #  ifndef TM_HOUR_MAX
  712. #    define TM_HOUR_MAX         6
  713. #  endif
  714. #  ifndef TM_MIN_MAX
  715. #    define TM_MIN_MAX          28
  716. #  endif
  717. #  ifndef TM_SEC_MAX
  718. #    define TM_SEC_MAX          14
  719. #  endif
  720. #endif /* NO_TIME_T_MAX */
  721.  
  722. /* Adjusts out-of-range values for `tm' field `tm_member'. */
  723. #define ADJUST_TM(tm_member, tm_carry, modulus) \
  724.   if ((tm_member) < 0) { \
  725.     tm_carry -= (1 - ((tm_member)+1) / (modulus)); \
  726.     tm_member = (modulus-1) + (((tm_member)+1) % (modulus)); \
  727.   } else if ((tm_member) >= (modulus)) { \
  728.     tm_carry += (tm_member) / (modulus); \
  729.     tm_member = (tm_member) % (modulus); \
  730.   }
  731.  
  732. /* Return the equivalent in seconds past 12:00:00 a.m. Jan 1, 1970 GMT
  733.    of the Greenwich Mean time and date in the exploded time structure `tm'.
  734.    This function does always put back normalized values into the `tm' struct,
  735.    parameter, including the calculated numbers for `tm->tm_yday',
  736.    `tm->tm_wday', and `tm->tm_isdst'.
  737.    Returns -1 if the time in the `tm' parameter cannot be represented
  738.    as valid `time_t' number. */
  739.  
  740. time_t mkgmtime(tm)
  741.      struct tm *tm;
  742. {
  743.   int years, months, days, hours, minutes, seconds;
  744.  
  745.   years = tm->tm_year + TM_YEAR_BASE;   /* year - 1900 -> year */
  746.   months = tm->tm_mon;                  /* 0..11 */
  747.   days = tm->tm_mday - 1;               /* 1..31 -> 0..30 */
  748.   hours = tm->tm_hour;                  /* 0..23 */
  749.   minutes = tm->tm_min;                 /* 0..59 */
  750.   seconds = tm->tm_sec;                 /* 0..61 in ANSI C. */
  751.  
  752.   ADJUST_TM(seconds, minutes, 60)
  753.   ADJUST_TM(minutes, hours, 60)
  754.   ADJUST_TM(hours, days, 24)
  755.   ADJUST_TM(months, years, 12)
  756.   if (days < 0)
  757.     do {
  758.       if (--months < 0) {
  759.         --years;
  760.         months = 11;
  761.       }
  762.       days += monthlen(months, years);
  763.     } while (days < 0);
  764.   else
  765.     while (days >= monthlen(months, years)) {
  766.       days -= monthlen(months, years);
  767.       if (++months >= 12) {
  768.         ++years;
  769.         months = 0;
  770.       }
  771.     }
  772.  
  773.   /* Restore adjusted values in tm structure */
  774.   tm->tm_year = years - TM_YEAR_BASE;
  775.   tm->tm_mon = months;
  776.   tm->tm_mday = days + 1;
  777.   tm->tm_hour = hours;
  778.   tm->tm_min = minutes;
  779.   tm->tm_sec = seconds;
  780.  
  781.   /* Set `days' to the number of days into the year. */
  782.   days += YDAYS(months, years);
  783.   tm->tm_yday = days;
  784.  
  785.   /* Now calculate `days' to the number of days since Jan 1, 1970. */
  786.   days = (unsigned)days + 365 * (unsigned)(years - EPOCH_YEAR) +
  787.          (unsigned)(nleap (years));
  788.   tm->tm_wday = ((unsigned)days + EPOCH_WDAY) % 7;
  789.   tm->tm_isdst = 0;
  790.  
  791.   if (years < EPOCH_YEAR)
  792.     return (time_t)-1;
  793.  
  794. #if (defined(TM_YEAR_MAX) && defined(TM_MON_MAX) && defined(TM_MDAY_MAX))
  795. #if (defined(TM_HOUR_MAX) && defined(TM_MIN_MAX) && defined(TM_SEC_MAX))
  796.   if (years > TM_YEAR_MAX ||
  797.       (years == TM_YEAR_MAX &&
  798.        (tm->tm_yday > (YDAYS(TM_MON_MAX, TM_YEAR_MAX) + (TM_MDAY_MAX - 1)) ||
  799.         (tm->tm_yday == (YDAYS(TM_MON_MAX, TM_YEAR_MAX) + (TM_MDAY_MAX - 1)) &&
  800.          (hours > TM_HOUR_MAX ||
  801.           (hours == TM_HOUR_MAX &&
  802.            (minutes > TM_MIN_MAX ||
  803.             (minutes == TM_MIN_MAX && seconds > TM_SEC_MAX) )))))))
  804.     return (time_t)-1;
  805. #endif
  806. #endif
  807.  
  808.   return (time_t)(SECSPERDAY * (unsigned long)(unsigned)days +
  809.                   SECSPERHOUR * (unsigned long)hours +
  810.                   (unsigned long)(SECSPERMIN * minutes + seconds));
  811. }
  812.  
  813. #endif /* __timezone_c */
  814.