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