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