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