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