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