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