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