Remove _THREAD_SAFE depenendancies. Create weakly associated stubs for
[games.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.4 2005/01/31 22:29:44 dillon 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 P((const char * codep));
126 static const char *     getzname P((const char * strp));
127 static const char *     getnum P((const char * strp, int * nump, int min,
128                                 int max));
129 static const char *     getsecs P((const char * strp, long * secsp));
130 static const char *     getoffset P((const char * strp, long * offsetp));
131 static const char *     getrule P((const char * strp, struct rule * rulep));
132 static void             gmtload P((struct state * sp));
133 static void             gmtsub P((const time_t * timep, long offset,
134                                 struct tm * tmp));
135 static void             localsub P((const time_t * timep, long offset,
136                                 struct tm * tmp));
137 static int              increment_overflow P((int * number, int delta));
138 static int              normalize_overflow P((int * tensptr, int * unitsptr,
139                                 int base));
140 static void             settzname P((void));
141 static time_t           time1 P((struct tm * tmp,
142                                 void(*funcp) P((const time_t *,
143                                 long, struct tm *)),
144                                 long offset));
145 static time_t           time2 P((struct tm *tmp,
146                                 void(*funcp) P((const time_t *,
147                                 long, struct tm*)),
148                                 long offset, int * okayp));
149 static void             timesub P((const time_t * timep, long offset,
150                                 const struct state * sp, struct tm * tmp));
151 static int              tmcomp P((const struct tm * atmp,
152                                 const struct tm * btmp));
153 static time_t           transtime P((time_t janfirst, int year,
154                                 const struct rule * rulep, long offset));
155 static int              tzload P((const char * name, struct state * sp));
156 static int              tzparse P((const char * name, struct state * sp,
157                                 int lastditch));
158
159 #ifdef ALL_STATE
160 static struct state *   lclptr;
161 static struct state *   gmtptr;
162 #endif /* defined ALL_STATE */
163
164 #ifndef ALL_STATE
165 static struct state     lclmem;
166 static struct state     gmtmem;
167 #define lclptr          (&lclmem)
168 #define gmtptr          (&gmtmem)
169 #endif /* State Farm */
170
171 #ifndef TZ_STRLEN_MAX
172 #define TZ_STRLEN_MAX 255
173 #endif /* !defined TZ_STRLEN_MAX */
174
175 static char             lcl_TZname[TZ_STRLEN_MAX + 1];
176 static int              lcl_is_set;
177 static int              gmt_is_set;
178 static pthread_mutex_t  lcl_mutex = PTHREAD_MUTEX_INITIALIZER;
179 static pthread_mutex_t  gmt_mutex = PTHREAD_MUTEX_INITIALIZER;
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         long    result;
210         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         struct state *  sp = lclptr;
222         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                 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                 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 const char *            name;
271 struct state * const    sp;
272 {
273         const char *    p;
274         int             i;
275         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                 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                         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                         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                         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                         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 const char *    strp;
444 {
445         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 const char *    strp;
463 int * const             nump;
464 const int               min;
465 const int               max;
466 {
467         char    c;
468         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 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 const char *    strp;
538 long * const            offsetp;
539 {
540         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 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 const struct rule * const       rulep;
621 const long                              offset;
622 {
623         int     leapyear;
624         time_t  value;
625         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 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         time_t *                atp;
724         unsigned char * typep;
725         char *                  cp;
726         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                         int     year;
767                         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                         long    theirstdoffset;
817                         long    theirdstoffset;
818                         long    theiroffset;
819                         int     isdst;
820                         int     i;
821                         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 static void
934 tzsetwall_basic(void)
935 {
936         if (lcl_is_set < 0)
937                 return;
938         lcl_is_set = -1;
939
940 #ifdef ALL_STATE
941         if (lclptr == NULL) {
942                 lclptr = (struct state *) malloc(sizeof *lclptr);
943                 if (lclptr == NULL) {
944                         settzname();    /* all we can do */
945                         return;
946                 }
947         }
948 #endif /* defined ALL_STATE */
949         if (tzload((char *) NULL, lclptr) != 0)
950                 gmtload(lclptr);
951         settzname();
952 }
953
954 void
955 tzsetwall P((void))
956 {
957         _MUTEX_LOCK(&lcl_mutex);
958         tzsetwall_basic();
959         _MUTEX_UNLOCK(&lcl_mutex);
960 }
961
962 static void
963 tzset_basic (void)
964 {
965         const char *    name;
966
967         name = getenv("TZ");
968         if (name == NULL) {
969                 tzsetwall();
970                 return;
971         }
972
973         if (lcl_is_set > 0  &&  strcmp(lcl_TZname, name) == 0)
974                 return;
975         lcl_is_set = (strlen(name) < sizeof(lcl_TZname));
976         if (lcl_is_set)
977                 (void) strcpy(lcl_TZname, name);
978
979 #ifdef ALL_STATE
980         if (lclptr == NULL) {
981                 lclptr = (struct state *) malloc(sizeof *lclptr);
982                 if (lclptr == NULL) {
983                         settzname();    /* all we can do */
984                         return;
985                 }
986         }
987 #endif /* defined ALL_STATE */
988         if (*name == '\0') {
989                 /*
990                 ** User wants it fast rather than right.
991                 */
992                 lclptr->leapcnt = 0;            /* so, we're off a little */
993                 lclptr->timecnt = 0;
994                 lclptr->ttis[0].tt_gmtoff = 0;
995                 lclptr->ttis[0].tt_abbrind = 0;
996                 (void) strcpy(lclptr->chars, gmt);
997         } else if (tzload(name, lclptr) != 0)
998                 if (name[0] == ':' || tzparse(name, lclptr, FALSE) != 0)
999                         (void) gmtload(lclptr);
1000         settzname();
1001 }
1002
1003 void
1004 tzset(void)
1005 {
1006         _MUTEX_LOCK(&lcl_mutex);
1007         tzset_basic();
1008         _MUTEX_UNLOCK(&lcl_mutex);
1009 }
1010
1011 /*
1012 ** The easy way to behave "as if no library function calls" localtime
1013 ** is to not call it--so we drop its guts into "localsub", which can be
1014 ** freely called.  (And no, the PANS doesn't require the above behavior--
1015 ** but it *is* desirable.)
1016 **
1017 ** The unused offset argument is for the benefit of mktime variants.
1018 */
1019
1020 /*ARGSUSED*/
1021 static void
1022 localsub(timep, offset, tmp)
1023 const time_t * const    timep;
1024 const long              offset;
1025 struct tm * const       tmp;
1026 {
1027         struct state *          sp;
1028         const struct ttinfo *   ttisp;
1029         int                     i;
1030         const time_t                    t = *timep;
1031
1032         sp = lclptr;
1033 #ifdef ALL_STATE
1034         if (sp == NULL) {
1035                 gmtsub(timep, offset, tmp);
1036                 return;
1037         }
1038 #endif /* defined ALL_STATE */
1039         if (sp->timecnt == 0 || t < sp->ats[0]) {
1040                 i = 0;
1041                 while (sp->ttis[i].tt_isdst)
1042                         if (++i >= sp->typecnt) {
1043                                 i = 0;
1044                                 break;
1045                         }
1046         } else {
1047                 for (i = 1; i < sp->timecnt; ++i)
1048                         if (t < sp->ats[i])
1049                                 break;
1050                 i = sp->types[i - 1];
1051         }
1052         ttisp = &sp->ttis[i];
1053         /*
1054         ** To get (wrong) behavior that's compatible with System V Release 2.0
1055         ** you'd replace the statement below with
1056         **      t += ttisp->tt_gmtoff;
1057         **      timesub(&t, 0L, sp, tmp);
1058         */
1059         timesub(&t, ttisp->tt_gmtoff, sp, tmp);
1060         tmp->tm_isdst = ttisp->tt_isdst;
1061         tzname[tmp->tm_isdst] = &sp->chars[ttisp->tt_abbrind];
1062 #ifdef TM_ZONE
1063         tmp->TM_ZONE = &sp->chars[ttisp->tt_abbrind];
1064 #endif /* defined TM_ZONE */
1065 }
1066
1067 struct tm *
1068 localtime_r(timep, p_tm)
1069 const time_t * const    timep;
1070 struct tm *p_tm;
1071 {
1072         _MUTEX_LOCK(&lcl_mutex);
1073         tzset();
1074         localsub(timep, 0L, p_tm);
1075         _MUTEX_UNLOCK(&lcl_mutex);
1076         return(p_tm);
1077 }
1078
1079 struct tm *
1080 localtime(timep)
1081 const time_t * const    timep;
1082 {
1083         static pthread_mutex_t localtime_mutex = PTHREAD_MUTEX_INITIALIZER;
1084         static pthread_key_t localtime_key = -1;
1085         struct tm *p_tm;
1086
1087         if (__isthreaded != 0) {
1088                 _pthread_mutex_lock(&localtime_mutex);
1089                 if (localtime_key < 0) {
1090                         if (_pthread_key_create(&localtime_key, free) < 0) {
1091                                 _pthread_mutex_unlock(&localtime_mutex);
1092                                 return(NULL);
1093                         }
1094                 }
1095                 _pthread_mutex_unlock(&localtime_mutex);
1096                 p_tm = _pthread_getspecific(localtime_key);
1097                 if (p_tm == NULL) {
1098                         if ((p_tm = (struct tm *)malloc(sizeof(struct tm)))
1099                             == NULL)
1100                                 return(NULL);
1101                         _pthread_setspecific(localtime_key, p_tm);
1102                 }
1103                 _pthread_mutex_lock(&lcl_mutex);
1104                 tzset();
1105                 localsub(timep, 0L, p_tm);
1106                 _pthread_mutex_unlock(&lcl_mutex);
1107                 return(p_tm);
1108         } else {
1109                 tzset();
1110                 localsub(timep, 0L, &tm);
1111                 return(&tm);
1112         }
1113 }
1114
1115 /*
1116 ** gmtsub is to gmtime as localsub is to localtime.
1117 */
1118
1119 static void
1120 gmtsub(timep, offset, tmp)
1121 const time_t * const    timep;
1122 const long              offset;
1123 struct tm * const       tmp;
1124 {
1125         _MUTEX_LOCK(&gmt_mutex);
1126         if (!gmt_is_set) {
1127                 gmt_is_set = TRUE;
1128 #ifdef ALL_STATE
1129                 gmtptr = (struct state *) malloc(sizeof *gmtptr);
1130                 if (gmtptr != NULL)
1131 #endif /* defined ALL_STATE */
1132                         gmtload(gmtptr);
1133         }
1134         _MUTEX_UNLOCK(&gmt_mutex);
1135         timesub(timep, offset, gmtptr, tmp);
1136 #ifdef TM_ZONE
1137         /*
1138         ** Could get fancy here and deliver something such as
1139         ** "GMT+xxxx" or "GMT-xxxx" if offset is non-zero,
1140         ** but this is no time for a treasure hunt.
1141         */
1142         if (offset != 0)
1143                 tmp->TM_ZONE = wildabbr;
1144         else {
1145 #ifdef ALL_STATE
1146                 if (gmtptr == NULL)
1147                         tmp->TM_ZONE = gmt;
1148                 else    tmp->TM_ZONE = gmtptr->chars;
1149 #endif /* defined ALL_STATE */
1150 #ifndef ALL_STATE
1151                 tmp->TM_ZONE = gmtptr->chars;
1152 #endif /* State Farm */
1153         }
1154 #endif /* defined TM_ZONE */
1155 }
1156
1157 struct tm *
1158 gmtime(timep)
1159 const time_t * const    timep;
1160 {
1161         static pthread_mutex_t gmtime_mutex = PTHREAD_MUTEX_INITIALIZER;
1162         static pthread_key_t gmtime_key = -1;
1163         struct tm *p_tm;
1164
1165         if (__isthreaded != 0) {
1166                 _pthread_mutex_lock(&gmtime_mutex);
1167                 if (gmtime_key < 0) {
1168                         if (_pthread_key_create(&gmtime_key, free) < 0) {
1169                                 _pthread_mutex_unlock(&gmtime_mutex);
1170                                 return(NULL);
1171                 }
1172         }
1173         _pthread_mutex_unlock(&gmtime_mutex);
1174                 /*
1175                  * Changed to follow POSIX.1 threads standard, which
1176                  * is what BSD currently has.
1177                  */
1178                 if ((p_tm = _pthread_getspecific(gmtime_key)) == NULL) {
1179                         if ((p_tm = (struct tm *)malloc(sizeof(struct tm)))
1180                             == NULL) {
1181                                 return(NULL);
1182                         }
1183                         _pthread_setspecific(gmtime_key, p_tm);
1184                 }
1185                 gmtsub(timep, 0L, p_tm);
1186                 return(p_tm);
1187         }
1188         else {
1189                 gmtsub(timep, 0L, &tm);
1190                 return(&tm);
1191         }
1192 }
1193
1194 struct tm *
1195 gmtime_r(const time_t * timep, struct tm * tm)
1196 {
1197         gmtsub(timep, 0L, tm);
1198         return(tm);
1199 }
1200
1201 #ifdef STD_INSPIRED
1202
1203 struct tm *
1204 offtime(timep, offset)
1205 const time_t * const    timep;
1206 const long              offset;
1207 {
1208         gmtsub(timep, offset, &tm);
1209         return &tm;
1210 }
1211
1212 #endif /* defined STD_INSPIRED */
1213
1214 static void
1215 timesub(timep, offset, sp, tmp)
1216 const time_t * const                    timep;
1217 const long                              offset;
1218 const struct state * const      sp;
1219 struct tm * const               tmp;
1220 {
1221         const struct lsinfo *   lp;
1222         long                    days;
1223         long                    rem;
1224         int                     y;
1225         int                     yleap;
1226         const int *             ip;
1227         long                    corr;
1228         int                     hit;
1229         int                     i;
1230
1231         corr = 0;
1232         hit = 0;
1233 #ifdef ALL_STATE
1234         i = (sp == NULL) ? 0 : sp->leapcnt;
1235 #endif /* defined ALL_STATE */
1236 #ifndef ALL_STATE
1237         i = sp->leapcnt;
1238 #endif /* State Farm */
1239         while (--i >= 0) {
1240                 lp = &sp->lsis[i];
1241                 if (*timep >= lp->ls_trans) {
1242                         if (*timep == lp->ls_trans) {
1243                                 hit = ((i == 0 && lp->ls_corr > 0) ||
1244                                         lp->ls_corr > sp->lsis[i - 1].ls_corr);
1245                                 if (hit)
1246                                         while (i > 0 &&
1247                                                 sp->lsis[i].ls_trans ==
1248                                                 sp->lsis[i - 1].ls_trans + 1 &&
1249                                                 sp->lsis[i].ls_corr ==
1250                                                 sp->lsis[i - 1].ls_corr + 1) {
1251                                                         ++hit;
1252                                                         --i;
1253                                         }
1254                         }
1255                         corr = lp->ls_corr;
1256                         break;
1257                 }
1258         }
1259         days = *timep / SECSPERDAY;
1260         rem = *timep % SECSPERDAY;
1261 #ifdef mc68k
1262         if (*timep == 0x80000000) {
1263                 /*
1264                 ** A 3B1 muffs the division on the most negative number.
1265                 */
1266                 days = -24855;
1267                 rem = -11648;
1268         }
1269 #endif /* defined mc68k */
1270         rem += (offset - corr);
1271         while (rem < 0) {
1272                 rem += SECSPERDAY;
1273                 --days;
1274         }
1275         while (rem >= SECSPERDAY) {
1276                 rem -= SECSPERDAY;
1277                 ++days;
1278         }
1279         tmp->tm_hour = (int) (rem / SECSPERHOUR);
1280         rem = rem % SECSPERHOUR;
1281         tmp->tm_min = (int) (rem / SECSPERMIN);
1282         /*
1283         ** A positive leap second requires a special
1284         ** representation.  This uses "... ??:59:60" et seq.
1285         */
1286         tmp->tm_sec = (int) (rem % SECSPERMIN) + hit;
1287         tmp->tm_wday = (int) ((EPOCH_WDAY + days) % DAYSPERWEEK);
1288         if (tmp->tm_wday < 0)
1289                 tmp->tm_wday += DAYSPERWEEK;
1290         y = EPOCH_YEAR;
1291 #define LEAPS_THRU_END_OF(y)    ((y) / 4 - (y) / 100 + (y) / 400)
1292         while (days < 0 || days >= (long) year_lengths[yleap = isleap(y)]) {
1293                 int     newy;
1294
1295                 newy = y + days / DAYSPERNYEAR;
1296                 if (days < 0)
1297                         --newy;
1298                 days -= (newy - y) * DAYSPERNYEAR +
1299                         LEAPS_THRU_END_OF(newy - 1) -
1300                         LEAPS_THRU_END_OF(y - 1);
1301                 y = newy;
1302         }
1303         tmp->tm_year = y - TM_YEAR_BASE;
1304         tmp->tm_yday = (int) days;
1305         ip = mon_lengths[yleap];
1306         for (tmp->tm_mon = 0; days >= (long) ip[tmp->tm_mon]; ++(tmp->tm_mon))
1307                 days = days - (long) ip[tmp->tm_mon];
1308         tmp->tm_mday = (int) (days + 1);
1309         tmp->tm_isdst = 0;
1310 #ifdef TM_GMTOFF
1311         tmp->TM_GMTOFF = offset;
1312 #endif /* defined TM_GMTOFF */
1313 }
1314
1315 char *
1316 ctime(timep)
1317 const time_t * const    timep;
1318 {
1319 /*
1320 ** Section 4.12.3.2 of X3.159-1989 requires that
1321 **      The ctime funciton converts the calendar time pointed to by timer
1322 **      to local time in the form of a string.  It is equivalent to
1323 **              asctime(localtime(timer))
1324 */
1325         return asctime(localtime(timep));
1326 }
1327
1328 char *
1329 ctime_r(timep, buf)
1330 const time_t * const    timep;
1331 char *buf;
1332 {
1333         struct tm tm;
1334         return asctime_r(localtime_r(timep, &tm), buf);
1335 }
1336
1337 /*
1338 ** Adapted from code provided by Robert Elz, who writes:
1339 **      The "best" way to do mktime I think is based on an idea of Bob
1340 **      Kridle's (so its said...) from a long time ago.
1341 **      [kridle@xinet.com as of 1996-01-16.]
1342 **      It does a binary search of the time_t space.  Since time_t's are
1343 **      just 32 bits, its a max of 32 iterations (even at 64 bits it
1344 **      would still be very reasonable).
1345 */
1346
1347 #ifndef WRONG
1348 #define WRONG   (-1)
1349 #endif /* !defined WRONG */
1350
1351 /*
1352 ** Simplified normalize logic courtesy Paul Eggert (eggert@twinsun.com).
1353 */
1354
1355 static int
1356 increment_overflow(number, delta)
1357 int *   number;
1358 int     delta;
1359 {
1360         int     number0;
1361
1362         number0 = *number;
1363         *number += delta;
1364         return (*number < number0) != (delta < 0);
1365 }
1366
1367 static int
1368 normalize_overflow(tensptr, unitsptr, base)
1369 int * const     tensptr;
1370 int * const     unitsptr;
1371 const int       base;
1372 {
1373         int     tensdelta;
1374
1375         tensdelta = (*unitsptr >= 0) ?
1376                 (*unitsptr / base) :
1377                 (-1 - (-1 - *unitsptr) / base);
1378         *unitsptr -= tensdelta * base;
1379         return increment_overflow(tensptr, tensdelta);
1380 }
1381
1382 static int
1383 tmcomp(atmp, btmp)
1384 const struct tm * const atmp;
1385 const struct tm * const btmp;
1386 {
1387         int     result;
1388
1389         if ((result = (atmp->tm_year - btmp->tm_year)) == 0 &&
1390                 (result = (atmp->tm_mon - btmp->tm_mon)) == 0 &&
1391                 (result = (atmp->tm_mday - btmp->tm_mday)) == 0 &&
1392                 (result = (atmp->tm_hour - btmp->tm_hour)) == 0 &&
1393                 (result = (atmp->tm_min - btmp->tm_min)) == 0)
1394                         result = atmp->tm_sec - btmp->tm_sec;
1395         return result;
1396 }
1397
1398 static time_t
1399 time2(tmp, funcp, offset, okayp)
1400 struct tm * const       tmp;
1401 void (* const           funcp) P((const time_t*, long, struct tm*));
1402 const long              offset;
1403 int * const             okayp;
1404 {
1405         const struct state *    sp;
1406         int                     dir;
1407         int                     bits;
1408         int                     i, j ;
1409         int                     saved_seconds;
1410         time_t                          newt;
1411         time_t                          t;
1412         struct tm                       yourtm, mytm;
1413
1414         *okayp = FALSE;
1415         yourtm = *tmp;
1416         if (normalize_overflow(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR))
1417                 return WRONG;
1418         if (normalize_overflow(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY))
1419                 return WRONG;
1420         if (normalize_overflow(&yourtm.tm_year, &yourtm.tm_mon, MONSPERYEAR))
1421                 return WRONG;
1422         /*
1423         ** Turn yourtm.tm_year into an actual year number for now.
1424         ** It is converted back to an offset from TM_YEAR_BASE later.
1425         */
1426         if (increment_overflow(&yourtm.tm_year, TM_YEAR_BASE))
1427                 return WRONG;
1428         while (yourtm.tm_mday <= 0) {
1429                 if (increment_overflow(&yourtm.tm_year, -1))
1430                         return WRONG;
1431                 i = yourtm.tm_year + (1 < yourtm.tm_mon);
1432                 yourtm.tm_mday += year_lengths[isleap(i)];
1433         }
1434         while (yourtm.tm_mday > DAYSPERLYEAR) {
1435                 i = yourtm.tm_year + (1 < yourtm.tm_mon);
1436                 yourtm.tm_mday -= year_lengths[isleap(i)];
1437                 if (increment_overflow(&yourtm.tm_year, 1))
1438                         return WRONG;
1439         }
1440         for ( ; ; ) {
1441                 i = mon_lengths[isleap(yourtm.tm_year)][yourtm.tm_mon];
1442                 if (yourtm.tm_mday <= i)
1443                         break;
1444                 yourtm.tm_mday -= i;
1445                 if (++yourtm.tm_mon >= MONSPERYEAR) {
1446                         yourtm.tm_mon = 0;
1447                         if (increment_overflow(&yourtm.tm_year, 1))
1448                                 return WRONG;
1449                 }
1450         }
1451         if (increment_overflow(&yourtm.tm_year, -TM_YEAR_BASE))
1452                 return WRONG;
1453         if (yourtm.tm_year + TM_YEAR_BASE < EPOCH_YEAR) {
1454                 /*
1455                 ** We can't set tm_sec to 0, because that might push the
1456                 ** time below the minimum representable time.
1457                 ** Set tm_sec to 59 instead.
1458                 ** This assumes that the minimum representable time is
1459                 ** not in the same minute that a leap second was deleted from,
1460                 ** which is a safer assumption than using 58 would be.
1461                 */
1462                 if (increment_overflow(&yourtm.tm_sec, 1 - SECSPERMIN))
1463                         return WRONG;
1464                 saved_seconds = yourtm.tm_sec;
1465                 yourtm.tm_sec = SECSPERMIN - 1;
1466         } else {
1467                 saved_seconds = yourtm.tm_sec;
1468                 yourtm.tm_sec = 0;
1469         }
1470         /*
1471         ** Divide the search space in half
1472         ** (this works whether time_t is signed or unsigned).
1473         */
1474         bits = TYPE_BIT(time_t) - 1;
1475         /*
1476         ** If time_t is signed, then 0 is just above the median,
1477         ** assuming two's complement arithmetic.
1478         ** If time_t is unsigned, then (1 << bits) is just above the median.
1479         */
1480         t = TYPE_SIGNED(time_t) ? 0 : (((time_t) 1) << bits);
1481         for ( ; ; ) {
1482                 (*funcp)(&t, offset, &mytm);
1483                 dir = tmcomp(&mytm, &yourtm);
1484                 if (dir != 0) {
1485                         if (bits-- < 0)
1486                                 return WRONG;
1487                         if (bits < 0)
1488                                 --t; /* may be needed if new t is minimal */
1489                         else if (dir > 0)
1490                                 t -= ((time_t) 1) << bits;
1491                         else    t += ((time_t) 1) << bits;
1492                         continue;
1493                 }
1494                 if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst)
1495                         break;
1496                 /*
1497                 ** Right time, wrong type.
1498                 ** Hunt for right time, right type.
1499                 ** It's okay to guess wrong since the guess
1500                 ** gets checked.
1501                 */
1502                 /*
1503                 ** The (void *) casts are the benefit of SunOS 3.3 on Sun 2's.
1504                 */
1505                 sp = (const struct state *)
1506                         (((void *) funcp == (void *) localsub) ?
1507                         lclptr : gmtptr);
1508 #ifdef ALL_STATE
1509                 if (sp == NULL)
1510                         return WRONG;
1511 #endif /* defined ALL_STATE */
1512                 for (i = sp->typecnt - 1; i >= 0; --i) {
1513                         if (sp->ttis[i].tt_isdst != yourtm.tm_isdst)
1514                                 continue;
1515                         for (j = sp->typecnt - 1; j >= 0; --j) {
1516                                 if (sp->ttis[j].tt_isdst == yourtm.tm_isdst)
1517                                         continue;
1518                                 newt = t + sp->ttis[j].tt_gmtoff -
1519                                         sp->ttis[i].tt_gmtoff;
1520                                 (*funcp)(&newt, offset, &mytm);
1521                                 if (tmcomp(&mytm, &yourtm) != 0)
1522                                         continue;
1523                                 if (mytm.tm_isdst != yourtm.tm_isdst)
1524                                         continue;
1525                                 /*
1526                                 ** We have a match.
1527                                 */
1528                                 t = newt;
1529                                 goto label;
1530                         }
1531                 }
1532                 return WRONG;
1533         }
1534 label:
1535         newt = t + saved_seconds;
1536         if ((newt < t) != (saved_seconds < 0))
1537                 return WRONG;
1538         t = newt;
1539         (*funcp)(&t, offset, tmp);
1540         *okayp = TRUE;
1541         return t;
1542 }
1543
1544 static time_t
1545 time1(tmp, funcp, offset)
1546 struct tm * const       tmp;
1547 void (* const           funcp) P((const time_t *, long, struct tm *));
1548 const long              offset;
1549 {
1550         time_t                  t;
1551         const struct state *    sp;
1552         int                     samei, otheri;
1553         int                             okay;
1554
1555         if (tmp->tm_isdst > 1)
1556                 tmp->tm_isdst = 1;
1557         t = time2(tmp, funcp, offset, &okay);
1558 #ifdef PCTS
1559         /*
1560         ** PCTS code courtesy Grant Sullivan (grant@osf.org).
1561         */
1562         if (okay)
1563                 return t;
1564         if (tmp->tm_isdst < 0)
1565                 tmp->tm_isdst = 0;      /* reset to std and try again */
1566 #endif /* defined PCTS */
1567 #ifndef PCTS
1568         if (okay || tmp->tm_isdst < 0)
1569                 return t;
1570 #endif /* !defined PCTS */
1571         /*
1572         ** We're supposed to assume that somebody took a time of one type
1573         ** and did some math on it that yielded a "struct tm" that's bad.
1574         ** We try to divine the type they started from and adjust to the
1575         ** type they need.
1576         */
1577         /*
1578         ** The (void *) casts are the benefit of SunOS 3.3 on Sun 2's.
1579         */
1580         sp = (const struct state *) (((void *) funcp == (void *) localsub) ?
1581                 lclptr : gmtptr);
1582 #ifdef ALL_STATE
1583         if (sp == NULL)
1584                 return WRONG;
1585 #endif /* defined ALL_STATE */
1586         for (samei = sp->typecnt - 1; samei >= 0; --samei) {
1587                 if (sp->ttis[samei].tt_isdst != tmp->tm_isdst)
1588                         continue;
1589                 for (otheri = sp->typecnt - 1; otheri >= 0; --otheri) {
1590                         if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst)
1591                                 continue;
1592                         tmp->tm_sec += sp->ttis[otheri].tt_gmtoff -
1593                                         sp->ttis[samei].tt_gmtoff;
1594                         tmp->tm_isdst = !tmp->tm_isdst;
1595                         t = time2(tmp, funcp, offset, &okay);
1596                         if (okay)
1597                                 return t;
1598                         tmp->tm_sec -= sp->ttis[otheri].tt_gmtoff -
1599                                         sp->ttis[samei].tt_gmtoff;
1600                         tmp->tm_isdst = !tmp->tm_isdst;
1601                 }
1602         }
1603         return WRONG;
1604 }
1605
1606 time_t
1607 mktime(tmp)
1608 struct tm * const       tmp;
1609 {
1610         time_t mktime_return_value;
1611         _MUTEX_LOCK(&lcl_mutex);
1612         tzset();
1613         mktime_return_value = time1(tmp, localsub, 0L);
1614         _MUTEX_UNLOCK(&lcl_mutex);
1615         return(mktime_return_value);
1616 }
1617
1618 #ifdef STD_INSPIRED
1619
1620 time_t
1621 timelocal(tmp)
1622 struct tm * const       tmp;
1623 {
1624         tmp->tm_isdst = -1;     /* in case it wasn't initialized */
1625         return mktime(tmp);
1626 }
1627
1628 time_t
1629 timegm(tmp)
1630 struct tm * const       tmp;
1631 {
1632         tmp->tm_isdst = 0;
1633         return time1(tmp, gmtsub, 0L);
1634 }
1635
1636 time_t
1637 timeoff(tmp, offset)
1638 struct tm * const       tmp;
1639 const long              offset;
1640 {
1641         tmp->tm_isdst = 0;
1642         return time1(tmp, gmtsub, offset);
1643 }
1644
1645 #endif /* defined STD_INSPIRED */
1646
1647 #ifdef CMUCS
1648
1649 /*
1650 ** The following is supplied for compatibility with
1651 ** previous versions of the CMUCS runtime library.
1652 */
1653
1654 long
1655 gtime(tmp)
1656 struct tm * const       tmp;
1657 {
1658         const time_t    t = mktime(tmp);
1659
1660         if (t == WRONG)
1661                 return -1;
1662         return t;
1663 }
1664
1665 #endif /* defined CMUCS */
1666
1667 /*
1668 ** XXX--is the below the right way to conditionalize??
1669 */
1670
1671 #ifdef STD_INSPIRED
1672
1673 /*
1674 ** IEEE Std 1003.1-1988 (POSIX) legislates that 536457599
1675 ** shall correspond to "Wed Dec 31 23:59:59 GMT 1986", which
1676 ** is not the case if we are accounting for leap seconds.
1677 ** So, we provide the following conversion routines for use
1678 ** when exchanging timestamps with POSIX conforming systems.
1679 */
1680
1681 static long
1682 leapcorr(timep)
1683 time_t *        timep;
1684 {
1685         struct state *          sp;
1686         struct lsinfo * lp;
1687         int                     i;
1688
1689         sp = lclptr;
1690         i = sp->leapcnt;
1691         while (--i >= 0) {
1692                 lp = &sp->lsis[i];
1693                 if (*timep >= lp->ls_trans)
1694                         return lp->ls_corr;
1695         }
1696         return 0;
1697 }
1698
1699 time_t
1700 time2posix(t)
1701 time_t  t;
1702 {
1703         tzset();
1704         return t - leapcorr(&t);
1705 }
1706
1707 time_t
1708 posix2time(t)
1709 time_t  t;
1710 {
1711         time_t  x;
1712         time_t  y;
1713
1714         tzset();
1715         /*
1716         ** For a positive leap second hit, the result
1717         ** is not unique.  For a negative leap second
1718         ** hit, the corresponding time doesn't exist,
1719         ** so we return an adjacent second.
1720         */
1721         x = t + leapcorr(&t);
1722         y = x - leapcorr(&x);
1723         if (y < t) {
1724                 do {
1725                         x++;
1726                         y = x - leapcorr(&x);
1727                 } while (y < t);
1728                 if (t != y)
1729                         return x - 1;
1730         } else if (y > t) {
1731                 do {
1732                         --x;
1733                         y = x - leapcorr(&x);
1734                 } while (y > t);
1735                 if (t != y)
1736                         return x + 1;
1737         }
1738         return x;
1739 }
1740
1741 #endif /* defined STD_INSPIRED */