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