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