Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

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