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