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