Asterisk.org: Developer Documentation (28 Oct 2009)

Wed Oct 28 15:47:54 2009

## Asterisk developer's documentation

# localtime.c

Go to the documentation of this file.

    00001 /*
    00002  * Asterisk -- An open source telephony toolkit.
    00003  *
    00004  * Copyright (C) 1999 - 2005, Digium, Inc.
    00005  *
    00006  * Mark Spencer <markster@digium.com>
    00007  *
    00008  * Most of this code is in the public domain, so clarified as of
    00009  * June 5, 1996 by Arthur David Olson (arthur_david_olson@nih.gov).
    00010  *
    00011  * All modifications to this code to abstract timezones away from
    00012  * the environment are by Tilghman Lesher, <tlesher@vcch.com>, with
    00013  * the copyright assigned to Digium.
    00014  *
    00015  * See http://www.asterisk.org for more information about
    00016  * the Asterisk project. Please do not directly contact
    00017  * any of the maintainers of this project for assistance;
    00018  * the project provides a web site, mailing lists and IRC
    00019  * channels for your use.
    00020  *
    00021  * This program is free software, distributed under the terms of
    00022  * the GNU General Public License Version 2. See the LICENSE file
    00023  * at the top of the source tree.
    00024  */
    00025
    00026 /*! \file
    00027  *
    00028  * Multi-timezone Localtime code
    00029  *
    00030  * \author Leap second handling Bradley White (bww@k.gp.cs.cmu.edu).
    00031  * \author POSIX-style TZ environment variable handling from Guy Harris (guy@auspex.com).
    00032  *
    00033  */
    00034
    00035 /*
    00036  * Asterisk defines
    00037  *
    00038  * Don't mess with these unless you're really sure you know what you're doing.
    00039  */
    00040 #ifndef _THREAD_SAFE
    00041 #define _THREAD_SAFE
    00042 #endif
    00043 #define TZ_STRLEN_MAX   255
    00044 /* #define DEBUG */
    00045
    00046
    00047 /*LINTLIBRARY*/
    00048
    00049 #include <sys/types.h>
    00050 #include <sys/stat.h>
    00051 #include <fcntl.h>
    00052 #ifdef DEBUG
    00053 #include <stdio.h>
    00054 #endif
    00055 #include "private.h"
    00056 #include "tzfile.h"
    00057 #include "asterisk/lock.h"
    00058 #include "asterisk/localtime.h"
    00059 #include "asterisk/strings.h"
    00060
    00061
    00062 #ifndef lint
    00063 #ifndef NOID
    00064 static const char elsieid[] = "@(#)localtime.c  7.57";
    00065 #endif /* !defined NOID */
    00066 #endif /* !defined lint */
    00067
    00068
    00069
    00070 /*
    00071 ** SunOS 4.1.1 headers lack O_BINARY.
    00072 */
    00073
    00074 #ifdef O_BINARY
    00075 #define OPEN_MODE (O_RDONLY | O_BINARY)
    00076 #endif /* defined O_BINARY */
    00077 #ifndef O_BINARY
    00078 #define OPEN_MODE O_RDONLY
    00079 #endif /* !defined O_BINARY */
    00080
    00081 #ifdef SOLARIS
    00082 #undef TM_ZONE
    00083 #undef TM_GMTOFF
    00084 #endif
    00085
    00086 #ifdef TM_ZONE
    00087 #ifndef WILDABBR
    00088 /*! \note
    00089  * Someone might make incorrect use of a time zone abbreviation:
    00090  * 1. They might reference tzname[0] before calling ast_tzset (explicitly
    00091  *    or implicitly).
    00092  * 2. They might reference tzname[1] before calling ast_tzset (explicitly
    00093  *    or implicitly).
    00094  * 3. They might reference tzname[1] after setting to a time zone
    00095  *    in which Daylight Saving Time is never observed.
    00096  * 4. They might reference tzname[0] after setting to a time zone
    00097  *    in which Standard Time is never observed.
    00098  * 5. They might reference tm.TM_ZONE after calling offtime.
    00099  * What's best to do in the above cases is open to debate;
    00100  * for now, we just set things up so that in any of the five cases
    00101  * WILDABBR is used.  Another possibility:  initialize tzname[0] to the
    00102  * string "tzname[0] used before set", and similarly for the other cases.
    00103  * And another:  initialize tzname[0] to "ERA", with an explanation in the
    00104  * manual page of what this "time zone abbreviation" means (doing this so
    00105  * that tzname[0] has the "normal" length of three characters).
    00106  */
    00107 #define WILDABBR  "   "
    00108 #endif /* !defined WILDABBR */
    00109
    00110 static char    wildabbr[] = "WILDABBR";
    00111 #endif /* TM_ZONE */
    00112
    00113 /*! \brief FreeBSD defines 'zone' in 'struct tm' as non-const, so don't declare this
    00114    string as const. */
    00115 static char    gmt[] = "GMT";
    00116
    00117 /*!< \brief time type information */
    00118 struct ttinfo {
    00119    long     tt_gmtoff;  /*!< GMT offset in seconds */
    00120    int      tt_isdst;   /*!< used to set tm_isdst */
    00121    int      tt_abbrind; /*!< abbreviation list index */
    00122    int      tt_ttisstd; /*!< TRUE if transition is std time */
    00123    int      tt_ttisgmt; /*!< TRUE if transition is GMT */
    00124 };
    00125
    00126 /*! \brief leap second information */
    00127 struct lsinfo {
    00128    time_t      ls_trans;   /*!< transition time */
    00129    long     ls_corr; /*!< correction to apply */
    00130 };
    00131
    00132 #define BIGGEST(a, b)   (((a) > (b)) ? (a) : (b))
    00133
    00134 #ifdef TZNAME_MAX
    00135 #define MY_TZNAME_MAX   TZNAME_MAX
    00136 #endif /* defined TZNAME_MAX */
    00137 #ifndef TZNAME_MAX
    00138 #define MY_TZNAME_MAX   255
    00139 #endif /* !defined TZNAME_MAX */
    00140
    00141 struct state {
    00142    char  name[TZ_STRLEN_MAX + 1];
    00143    int      leapcnt;
    00144    int      timecnt;
    00145    int      typecnt;
    00146    int      charcnt;
    00147    time_t      ats[TZ_MAX_TIMES];
    00148    unsigned char  types[TZ_MAX_TIMES];
    00149    struct ttinfo  ttis[TZ_MAX_TYPES];
    00150    char     chars[BIGGEST(BIGGEST(TZ_MAX_CHARS + 1, sizeof gmt),
    00151             (2 * (MY_TZNAME_MAX + 1)))];
    00152    struct lsinfo  lsis[TZ_MAX_LEAPS];
    00153    struct state   *next;
    00154 };
    00155
    00156 struct rule {
    00157    int      r_type;     /*!< type of rule--see below */
    00158    int      r_day;      /*!< day number of rule */
    00159    int      r_week;     /*!< week number of rule */
    00160    int      r_mon;      /*!< month number of rule */
    00161    long     r_time;     /*!< transition time of rule */
    00162 };
    00163
    00164 #define JULIAN_DAY      0  /*!< Jn - Julian day */
    00165 #define DAY_OF_YEAR     1  /*!< n - day of year */
    00166 #define MONTH_NTH_DAY_OF_WEEK 2  /*!< Mm.n.d - month, week, day of week */
    00167
    00168 /*
    00169 ** Prototypes for static functions.
    00170 */
    00171
    00172 static long    detzcode P((const char * codep));
    00173 static const char *  getnum P((const char * strp, int * nump, int min,
    00174             int max));
    00175 static const char *  getsecs P((const char * strp, long * secsp));
    00176 static const char *  getoffset P((const char * strp, long * offsetp));
    00177 static const char *  getrule P((const char * strp, struct rule * rulep));
    00178 static void    gmtload P((struct state * sp));
    00179 static void    gmtsub P((const time_t * timep, long offset,
    00180             struct tm * tmp, const char * zone));
    00181 static void    localsub P((const time_t * timep, long offset,
    00182             struct tm * tmp, const char * zone));
    00183 static int     increment_overflow P((int * number, int delta));
    00184 static int     normalize_overflow P((int * tensptr, int * unitsptr,
    00185             int base));
    00186 static time_t     time1 P((struct tm * tmp,
    00187             void(*funcp) P((const time_t *,
    00188             long, struct tm *, const char*)),
    00189             long offset, const char * zone));
    00190 static time_t     time2 P((struct tm *tmp,
    00191             void(*funcp) P((const time_t *,
    00192             long, struct tm*, const char*)),
    00193             long offset, int * okayp, const char * zone));
    00194 static void    timesub P((const time_t * timep, long offset,
    00195             const struct state * sp, struct tm * tmp));
    00196 static int     tmcomp P((const struct tm * atmp,
    00197             const struct tm * btmp));
    00198 static time_t     transtime P((time_t janfirst, int year,
    00199             const struct rule * rulep, long offset));
    00200 static int     tzload P((const char * name, struct state * sp));
    00201 static int     tzparse P((const char * name, struct state * sp,
    00202             int lastditch));
    00203
    00204 static struct state *   lclptr      = NULL;
    00205 static struct state *   last_lclptr = NULL;
    00206 static struct state *   gmtptr      = NULL;
    00207
    00208 #ifndef TZ_STRLEN_MAX
    00209 #define TZ_STRLEN_MAX 255
    00210 #endif /* !defined TZ_STRLEN_MAX */
    00211
    00212 static int     gmt_is_set;
    00213 #ifdef   _THREAD_SAFE
    00214 AST_MUTEX_DEFINE_STATIC(lcl_mutex);
    00215 AST_MUTEX_DEFINE_STATIC(tzset_mutex);
    00216 AST_MUTEX_DEFINE_STATIC(tzsetwall_mutex);
    00217 AST_MUTEX_DEFINE_STATIC(gmt_mutex);
    00218 #endif
    00219
    00220 /*
    00221 ** Section 4.12.3 of X3.159-1989 requires that
    00222 ** Except for the strftime function, these functions [asctime,
    00223 ** ctime, gmtime, localtime] return values in one of two static
    00224 ** objects: a broken-down time structure and an array of char.
    00225 ** Thanks to Paul Eggert (eggert@twinsun.com) for noting this.
    00226 */
    00227
    00228 static long detzcode(const char * const   codep)
    00229 {
    00230    register long  result;
    00231    register int   i;
    00232
    00233    result = (codep[0] & 0x80) ? ~0L : 0L;
    00234    for (i = 0; i < 4; ++i)
    00235       result = (result << 8) | (codep[i] & 0xff);
    00236    return result;
    00237 }
    00238
    00239 static int tzload(register const char *name, register struct state *const  sp)
    00240 {
    00241    register const char *   p;
    00242    register int      i;
    00243    register int      fid;
    00244
    00245 #ifdef DEBUG
    00246    fprintf(stderr,"tzload called with name=%s, sp=%d\n", name, sp);
    00247 #endif
    00248    if (name == NULL && (name = TZDEFAULT) == NULL)
    00249       return -1;
    00250    {
    00251       register int   doaccess;
    00252       struct stat stab;
    00253       /*
    00254       ** Section 4.9.1 of the C standard says that
    00255       ** "FILENAME_MAX expands to an integral constant expression
    00256       ** that is the size needed for an array of char large enough
    00257       ** to hold the longest file name string that the implementation
    00258       ** guarantees can be opened."
    00259       */
    00260       char     fullname[FILENAME_MAX + 1] = "";
    00261
    00262       if (name[0] == ':')
    00263          ++name;
    00264       doaccess = name[0] == '/';
    00265       if (!doaccess) {
    00266          if ((p = TZDIR) == NULL)
    00267             return -1;
    00268          if ((strlen(p) + 1 + strlen(name) + 1) >= sizeof fullname)
    00269             return -1;
    00270          (void) strncpy(fullname, p, sizeof(fullname) - 1);
    00271          (void) strncat(fullname, "/", sizeof(fullname) - strlen(fullname) - 1);
    00272          (void) strncat(fullname, name, sizeof(fullname) - strlen(fullname) - 1);
    00273          /*
    00274          ** Set doaccess if '.' (as in "../") shows up in name.
    00275          */
    00276          if (strchr(name, '.') != NULL)
    00277             doaccess = TRUE;
    00278          name = fullname;
    00279       }
    00280       if (doaccess && access(name, R_OK) != 0)
    00281             return -1;
    00282       if ((fid = open(name, OPEN_MODE)) == -1)
    00283          return -1;
    00284       if ((fstat(fid, &stab) < 0) || !S_ISREG(stab.st_mode)) {
    00285          close(fid);
    00286          return -1;
    00287       }
    00288    }
    00289    {
    00290       struct tzhead *   tzhp;
    00291       char     buf[sizeof *sp + sizeof *tzhp];
    00292       int      ttisstdcnt;
    00293       int      ttisgmtcnt;
    00294
    00295       i = read(fid, buf, sizeof buf);
    00296       if (close(fid) != 0)
    00297          return -1;
    00298       p = buf;
    00299       p += (sizeof tzhp->tzh_magic) + (sizeof tzhp->tzh_reserved);
    00300       ttisstdcnt = (int) detzcode(p);
    00301       p += 4;
    00302       ttisgmtcnt = (int) detzcode(p);
    00303       p += 4;
    00304       sp->leapcnt = (int) detzcode(p);
    00305       p += 4;
    00306       sp->timecnt = (int) detzcode(p);
    00307       p += 4;
    00308       sp->typecnt = (int) detzcode(p);
    00309       p += 4;
    00310       sp->charcnt = (int) detzcode(p);
    00311       p += 4;
    00312       if (sp->leapcnt < 0 || sp->leapcnt > TZ_MAX_LEAPS ||
    00313          sp->typecnt <= 0 || sp->typecnt > TZ_MAX_TYPES ||
    00314          sp->timecnt < 0 || sp->timecnt > TZ_MAX_TIMES ||
    00315          sp->charcnt < 0 || sp->charcnt > TZ_MAX_CHARS ||
    00316          (ttisstdcnt != sp->typecnt && ttisstdcnt != 0) ||
    00317          (ttisgmtcnt != sp->typecnt && ttisgmtcnt != 0))
    00318             return -1;
    00319       if (i - (p - buf) < sp->timecnt * 4 +  /* ats */
    00320          sp->timecnt +        /* types */
    00321          sp->typecnt * (4 + 2) +    /* ttinfos */
    00322          sp->charcnt +        /* chars */
    00323          sp->leapcnt * (4 + 4) +    /* lsinfos */
    00324          ttisstdcnt +         /* ttisstds */
    00325          ttisgmtcnt)       /* ttisgmts */
    00326             return -1;
    00327       for (i = 0; i < sp->timecnt; ++i) {
    00328          sp->ats[i] = detzcode(p);
    00329          p += 4;
    00330       }
    00331       for (i = 0; i < sp->timecnt; ++i) {
    00332          sp->types[i] = (unsigned char) *p++;
    00333          if (sp->types[i] >= sp->typecnt)
    00334             return -1;
    00335       }
    00336       for (i = 0; i < sp->typecnt; ++i) {
    00337          register struct ttinfo *   ttisp;
    00338
    00339          ttisp = &sp->ttis[i];
    00340          ttisp->tt_gmtoff = detzcode(p);
    00341          p += 4;
    00342          ttisp->tt_isdst = (unsigned char) *p++;
    00343          if (ttisp->tt_isdst != 0 && ttisp->tt_isdst != 1)
    00344             return -1;
    00345          ttisp->tt_abbrind = (unsigned char) *p++;
    00346          if (ttisp->tt_abbrind < 0 ||
    00347             ttisp->tt_abbrind > sp->charcnt)
    00348                return -1;
    00349       }
    00350       for (i = 0; i < sp->charcnt; ++i)
    00351          sp->chars[i] = *p++;
    00352       sp->chars[i] = '\0'; /* ensure '\0' at end */
    00353       for (i = 0; i < sp->leapcnt; ++i) {
    00354          register struct lsinfo *   lsisp;
    00355
    00356          lsisp = &sp->lsis[i];
    00357          lsisp->ls_trans = detzcode(p);
    00358          p += 4;
    00359          lsisp->ls_corr = detzcode(p);
    00360          p += 4;
    00361       }
    00362       for (i = 0; i < sp->typecnt; ++i) {
    00363          register struct ttinfo *   ttisp;
    00364
    00365          ttisp = &sp->ttis[i];
    00366          if (ttisstdcnt == 0)
    00367             ttisp->tt_ttisstd = FALSE;
    00368          else {
    00369             ttisp->tt_ttisstd = *p++;
    00370             if (ttisp->tt_ttisstd != TRUE &&
    00371                ttisp->tt_ttisstd != FALSE)
    00372                   return -1;
    00373          }
    00374       }
    00375       for (i = 0; i < sp->typecnt; ++i) {
    00376          register struct ttinfo *   ttisp;
    00377
    00378          ttisp = &sp->ttis[i];
    00379          if (ttisgmtcnt == 0)
    00380             ttisp->tt_ttisgmt = FALSE;
    00381          else {
    00382             ttisp->tt_ttisgmt = *p++;
    00383             if (ttisp->tt_ttisgmt != TRUE &&
    00384                ttisp->tt_ttisgmt != FALSE)
    00385                   return -1;
    00386          }
    00387       }
    00388    }
    00389    return 0;
    00390 }
    00391
    00392 static const int  mon_lengths[2][MONSPERYEAR] = {
    00393    { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
    00394    { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
    00395 };
    00396
    00397 static const int  year_lengths[2] = {
    00398    DAYSPERNYEAR, DAYSPERLYEAR
    00399 };
    00400
    00401 /*! \brief
    00402  * Given a pointer into a time zone string, extract a number from that string.
    00403  * \return Check that the number is within a specified range; if it is not, return
    00404  * NULL.
    00405  * Otherwise, return a pointer to the first character not part of the number.
    00406 */
    00407
    00408 static const char *getnum(register const char *strp, int * const nump, const int min, const int max)
    00409 {
    00410    register char  c;
    00411    register int   num;
    00412
    00413    if (strp == NULL || !is_digit(c = *strp))
    00414       return NULL;
    00415    num = 0;
    00416    do {
    00417       num = num * 10 + (c - '0');
    00418       if (num > max)
    00419          return NULL;   /* illegal value */
    00420       c = *++strp;
    00421    } while (is_digit(c));
    00422    if (num < min)
    00423       return NULL;      /* illegal value */
    00424    *nump = num;
    00425    return strp;
    00426 }
    00427
    00428 /*! \brief
    00429  * Given a pointer into a time zone string, extract a number of seconds,
    00430  * in hh[:mm[:ss]] form, from the string.
    00431  * \return If any error occurs, return NULL.
    00432  * Otherwise, return a pointer to the first character not part of the number
    00433  * of seconds.
    00434 */
    00435
    00436 static const char *getsecs(register const char *strp, long * const secsp)
    00437 {
    00438    int   num;
    00439
    00440    /*
    00441    ** `HOURSPERDAY * DAYSPERWEEK - 1' allows quasi-Posix rules like
    00442    ** "M10.4.6/26", which does not conform to Posix,
    00443    ** but which specifies the equivalent of
    00444    ** ``02:00 on the first Sunday on or after 23 Oct''.
    00445    */
    00446    strp = getnum(strp, &num, 0, HOURSPERDAY * DAYSPERWEEK - 1);
    00447    if (strp == NULL)
    00448       return NULL;
    00449    *secsp = num * (long) SECSPERHOUR;
    00450    if (*strp == ':') {
    00451       ++strp;
    00452       strp = getnum(strp, &num, 0, MINSPERHOUR - 1);
    00453       if (strp == NULL)
    00454          return NULL;
    00455       *secsp += num * SECSPERMIN;
    00456       if (*strp == ':') {
    00457          ++strp;
    00458          /* `SECSPERMIN' allows for leap seconds.  */
    00459          strp = getnum(strp, &num, 0, SECSPERMIN);
    00460          if (strp == NULL)
    00461             return NULL;
    00462          *secsp += num;
    00463       }
    00464    }
    00465    return strp;
    00466 }
    00467
    00468 /*! \brief
    00469  * Given a pointer into a time zone string, extract an offset, in
    00470  * [+-]hh[:mm[:ss]] form, from the string.
    00471  * \return If any error occurs, return NULL.
    00472  * Otherwise, return a pointer to the first character not part of the time.
    00473 */
    00474
    00475 static const char * getoffset(register const char *strp, long * const offsetp)
    00476 {
    00477    register int   neg = 0;
    00478
    00479    if (*strp == '-') {
    00480       neg = 1;
    00481       ++strp;
    00482    } else if (*strp == '+')
    00483       ++strp;
    00484    strp = getsecs(strp, offsetp);
    00485    if (strp == NULL)
    00486       return NULL;      /* illegal time */
    00487    if (neg)
    00488       *offsetp = -*offsetp;
    00489    return strp;
    00490 }
    00491
    00492 /*! \brief
    00493  * Given a pointer into a time zone string, extract a rule in the form
    00494  * date[/time].  See POSIX section 8 for the format of "date" and "time".
    00495  * \return If a valid rule is not found, return NULL.
    00496  * Otherwise, return a pointer to the first character not part of the rule.
    00497 */
    00498
    00499 static const char *getrule(const char *strp, register struct rule * const rulep)
    00500 {
    00501    if (*strp == 'J') {
    00502       /*
    00503       ** Julian day.
    00504       */
    00505       rulep->r_type = JULIAN_DAY;
    00506       ++strp;
    00507       strp = getnum(strp, &rulep->r_day, 1, DAYSPERNYEAR);
    00508    } else if (*strp == 'M') {
    00509       /*
    00510       ** Month, week, day.
    00511       */
    00512       rulep->r_type = MONTH_NTH_DAY_OF_WEEK;
    00513       ++strp;
    00514       strp = getnum(strp, &rulep->r_mon, 1, MONSPERYEAR);
    00515       if (strp == NULL)
    00516          return NULL;
    00517       if (*strp++ != '.')
    00518          return NULL;
    00519       strp = getnum(strp, &rulep->r_week, 1, 5);
    00520       if (strp == NULL)
    00521          return NULL;
    00522       if (*strp++ != '.')
    00523          return NULL;
    00524       strp = getnum(strp, &rulep->r_day, 0, DAYSPERWEEK - 1);
    00525    } else if (is_digit(*strp)) {
    00526       /*
    00527       ** Day of year.
    00528       */
    00529       rulep->r_type = DAY_OF_YEAR;
    00530       strp = getnum(strp, &rulep->r_day, 0, DAYSPERLYEAR - 1);
    00531    } else   return NULL;      /* invalid format */
    00532    if (strp == NULL)
    00533       return NULL;
    00534    if (*strp == '/') {
    00535       /*
    00536       ** Time specified.
    00537       */
    00538       ++strp;
    00539       strp = getsecs(strp, &rulep->r_time);
    00540    } else   rulep->r_time = 2 * SECSPERHOUR; /* default = 2:00:00 */
    00541    return strp;
    00542 }
    00543
    00544 /*! \brief
    00545  * Given the Epoch-relative time of January 1, 00:00:00 GMT, in a year, the
    00546  * year, a rule, and the offset from GMT at the time that rule takes effect,
    00547  * calculate the Epoch-relative time that rule takes effect.
    00548 */
    00549
    00550 static time_t transtime(janfirst, year, rulep, offset)
    00551 const time_t            janfirst;
    00552 const int            year;
    00553 register const struct rule * const  rulep;
    00554 const long           offset;
    00555 {
    00556    register int   leapyear;
    00557    register time_t   value = 0;
    00558    register int   i;
    00559    int      d, m1, yy0, yy1, yy2, dow;
    00560
    00561    leapyear = isleap(year);
    00562    switch (rulep->r_type) {
    00563
    00564    case JULIAN_DAY:
    00565       /*
    00566       ** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap
    00567       ** years.
    00568       ** In non-leap years, or if the day number is 59 or less, just
    00569       ** add SECSPERDAY times the day number-1 to the time of
    00570       ** January 1, midnight, to get the day.
    00571       */
    00572       value = janfirst + (rulep->r_day - 1) * SECSPERDAY;
    00573       if (leapyear && rulep->r_day >= 60)
    00574          value += SECSPERDAY;
    00575       break;
    00576
    00577    case DAY_OF_YEAR:
    00578       /*
    00579       ** n - day of year.
    00580       ** Just add SECSPERDAY times the day number to the time of
    00581       ** January 1, midnight, to get the day.
    00582       */
    00583       value = janfirst + rulep->r_day * SECSPERDAY;
    00584       break;
    00585
    00586    case MONTH_NTH_DAY_OF_WEEK:
    00587       /*
    00588       ** Mm.n.d - nth "dth day" of month m.
    00589       */
    00590       value = janfirst;
    00591       for (i = 0; i < rulep->r_mon - 1; ++i)
    00592          value += mon_lengths[leapyear][i] * SECSPERDAY;
    00593
    00594       /*
    00595       ** Use Zeller's Congruence to get day-of-week of first day of
    00596       ** month.
    00597       */
    00598       m1 = (rulep->r_mon + 9) % 12 + 1;
    00599       yy0 = (rulep->r_mon <= 2) ? (year - 1) : year;
    00600       yy1 = yy0 / 100;
    00601       yy2 = yy0 % 100;
    00602       dow = ((26 * m1 - 2) / 10 +
    00603          1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7;
    00604       if (dow < 0)
    00605          dow += DAYSPERWEEK;
    00606
    00607       /*
    00608       ** "dow" is the day-of-week of the first day of the month.  Get
    00609       ** the day-of-month (zero-origin) of the first "dow" day of the
    00610       ** month.
    00611       */
    00612       d = rulep->r_day - dow;
    00613       if (d < 0)
    00614          d += DAYSPERWEEK;
    00615       for (i = 1; i < rulep->r_week; ++i) {
    00616          if (d + DAYSPERWEEK >=
    00617             mon_lengths[leapyear][rulep->r_mon - 1])
    00618                break;
    00619          d += DAYSPERWEEK;
    00620       }
    00621
    00622       /*
    00623       ** "d" is the day-of-month (zero-origin) of the day we want.
    00624       */
    00625       value += d * SECSPERDAY;
    00626       break;
    00627    }
    00628
    00629    /*
    00630    ** "value" is the Epoch-relative time of 00:00:00 GMT on the day in
    00631    ** question.  To get the Epoch-relative time of the specified local
    00632    ** time on that day, add the transition time and the current offset
    00633    ** from GMT.
    00634    */
    00635    return value + rulep->r_time + offset;
    00636 }
    00637
    00638 /*
    00639 ** Given a POSIX section 8-style TZ string, fill in the rule tables as
    00640 ** appropriate.
    00641 */
    00642
    00643 static int
    00644 tzparse(name, sp, lastditch)
    00645 const char *         name;
    00646 register struct state * const sp;
    00647 const int         lastditch;
    00648 {
    00649    const char *         stdname;
    00650    const char *         dstname = NULL;
    00651    size_t            stdlen = 0;
    00652    size_t            dstlen = 0;
    00653    long           stdoffset = 0L;
    00654    long           dstoffset = 0L;
    00655    register time_t *    atp;
    00656    register unsigned char *   typep;
    00657    register char *         cp;
    00658    register int         load_result;
    00659
    00660    stdname = name;
    00661 #ifdef DEBUG
    00662    fprintf(stderr, "tzparse(): loading default rules\n");
    00663 #endif
    00664    load_result = tzload(TZDEFRULES, sp);
    00665    if (load_result != 0)
    00666       sp->leapcnt = 0;     /* so, we're off a little */
    00667    if (*name != '\0') {
    00668       if (*name != '\0' && *name != ',' && *name != ';') {
    00669          name = getoffset(name, &dstoffset);
    00670          if (name == NULL)
    00671             return -1;
    00672       } else   dstoffset = stdoffset - SECSPERHOUR;
    00673       if (*name == ',' || *name == ';') {
    00674          struct rule start;
    00675          struct rule end;
    00676          register int   year;
    00677          register time_t   janfirst;
    00678          time_t      starttime;
    00679          time_t      endtime;
    00680
    00681          ++name;
    00682          if ((name = getrule(name, &start)) == NULL)
    00683             return -1;
    00684          if (*name++ != ',')
    00685             return -1;
    00686          if ((name = getrule(name, &end)) == NULL)
    00687             return -1;
    00688          if (*name != '\0')
    00689             return -1;
    00690          sp->typecnt = 2;  /* standard time and DST */
    00691          /*
    00692          ** Two transitions per year, from EPOCH_YEAR to 2037.
    00693          */
    00694          sp->timecnt = 2 * (2037 - EPOCH_YEAR + 1);
    00695          if (sp->timecnt > TZ_MAX_TIMES)
    00696             return -1;
    00697          sp->ttis[0].tt_gmtoff = -dstoffset;
    00698          sp->ttis[0].tt_isdst = 1;
    00699          sp->ttis[0].tt_abbrind = stdlen + 1;
    00700          sp->ttis[1].tt_gmtoff = -stdoffset;
    00701          sp->ttis[1].tt_isdst = 0;
    00702          sp->ttis[1].tt_abbrind = 0;
    00703          atp = sp->ats;
    00704          typep = sp->types;
    00705          janfirst = 0;
    00706          for (year = EPOCH_YEAR; year <= 2037; ++year) {
    00707             starttime = transtime(janfirst, year, &start,
    00708                stdoffset);
    00709             endtime = transtime(janfirst, year, &end,
    00710                dstoffset);
    00711             if (starttime > endtime) {
    00712                *atp++ = endtime;
    00713                *typep++ = 1;  /* DST ends */
    00714                *atp++ = starttime;
    00715                *typep++ = 0;  /* DST begins */
    00716             } else {
    00717                *atp++ = starttime;
    00718                *typep++ = 0;  /* DST begins */
    00719                *atp++ = endtime;
    00720                *typep++ = 1;  /* DST ends */
    00721             }
    00722             janfirst += year_lengths[isleap(year)] *
    00723                SECSPERDAY;
    00724          }
    00725       } else {
    00726          register long  theirstdoffset;
    00727          register long  theirdstoffset;
    00728          register long  theiroffset;
    00729          register int   isdst;
    00730          register int   i;
    00731          register int   j;
    00732
    00733          if (*name != '\0')
    00734             return -1;
    00735          if (load_result != 0)
    00736             return -1;
    00737          /*
    00738          ** Initial values of theirstdoffset and theirdstoffset.
    00739          */
    00740          theirstdoffset = 0;
    00741          for (i = 0; i < sp->timecnt; ++i) {
    00742             j = sp->types[i];
    00743             if (!sp->ttis[j].tt_isdst) {
    00744                theirstdoffset =
    00745                   -sp->ttis[j].tt_gmtoff;
    00746                break;
    00747             }
    00748          }
    00749          theirdstoffset = 0;
    00750          for (i = 0; i < sp->timecnt; ++i) {
    00751             j = sp->types[i];
    00752             if (sp->ttis[j].tt_isdst) {
    00753                theirdstoffset =
    00754                   -sp->ttis[j].tt_gmtoff;
    00755                break;
    00756             }
    00757          }
    00758          /*
    00759          ** Initially we're assumed to be in standard time.
    00760          */
    00761          isdst = FALSE;
    00762          theiroffset = theirstdoffset;
    00763          /*
    00764          ** Now juggle transition times and types
    00765          ** tracking offsets as you do.
    00766          */
    00767          for (i = 0; i < sp->timecnt; ++i) {
    00768             j = sp->types[i];
    00769             sp->types[i] = sp->ttis[j].tt_isdst;
    00770             if (sp->ttis[j].tt_ttisgmt) {
    00771                /* No adjustment to transition time */
    00772             } else {
    00773                /*
    00774                ** If summer time is in effect, and the
    00775                ** transition time was not specified as
    00776                ** standard time, add the summer time
    00777                ** offset to the transition time;
    00778                ** otherwise, add the standard time
    00779                ** offset to the transition time.
    00780                */
    00781                /*
    00782                ** Transitions from DST to DDST
    00783                ** will effectively disappear since
    00784                ** POSIX provides for only one DST
    00785                ** offset.
    00786                */
    00787                if (isdst && !sp->ttis[j].tt_ttisstd) {
    00788                   sp->ats[i] += dstoffset -
    00789                      theirdstoffset;
    00790                } else {
    00791                   sp->ats[i] += stdoffset -
    00792                      theirstdoffset;
    00793                }
    00794             }
    00795             theiroffset = -sp->ttis[j].tt_gmtoff;
    00796             if (sp->ttis[j].tt_isdst)
    00797                theirdstoffset = theiroffset;
    00798             else  theirstdoffset = theiroffset;
    00799          }
    00800          /*
    00801          ** Finally, fill in ttis.
    00802          ** ttisstd and ttisgmt need not be handled.
    00803          */
    00804          sp->ttis[0].tt_gmtoff = -stdoffset;
    00805          sp->ttis[0].tt_isdst = FALSE;
    00806          sp->ttis[0].tt_abbrind = 0;
    00807          sp->ttis[1].tt_gmtoff = -dstoffset;
    00808          sp->ttis[1].tt_isdst = TRUE;
    00809          sp->ttis[1].tt_abbrind = stdlen + 1;
    00810       }
    00811    } else {
    00812       dstlen = 0;
    00813       sp->typecnt = 1;     /* only standard time */
    00814       sp->timecnt = 0;
    00815       sp->ttis[0].tt_gmtoff = -stdoffset;
    00816       sp->ttis[0].tt_isdst = 0;
    00817       sp->ttis[0].tt_abbrind = 0;
    00818    }
    00819    sp->charcnt = stdlen + 1;
    00820    if (dstlen != 0)
    00821       sp->charcnt += dstlen + 1;
    00822    if (sp->charcnt > sizeof sp->chars)
    00823       return -1;
    00824    cp = sp->chars;
    00825    (void) strncpy(cp, stdname, stdlen);
    00826    cp += stdlen;
    00827    *cp++ = '\0';
    00828    if (dstlen != 0) {
    00829       (void) strncpy(cp, dstname, dstlen);
    00830       *(cp + dstlen) = '\0';
    00831    }
    00832    return 0;
    00833 }
    00834
    00835 static void
    00836 gmtload(sp)
    00837 struct state * const sp;
    00838 {
    00839    if (tzload(gmt, sp) != 0)
    00840       (void) tzparse(gmt, sp, TRUE);
    00841 }
    00842
    00843 /*
    00844 ** A non-static declaration of ast_tzsetwall in a system header file
    00845 ** may cause a warning about this upcoming static declaration...
    00846 */
    00847 static
    00848 #ifdef   _THREAD_SAFE
    00849 int
    00850 ast_tzsetwall_basic P((void))
    00851 #else
    00852 int
    00853 ast_tzsetwall P((void))
    00854 #endif
    00855 {
    00856    struct state *cur_state = lclptr;
    00857
    00858    /* Find the appropriate structure, if already parsed */
    00859    while (cur_state != NULL) {
    00860       if (cur_state->name[0] == '\0')
    00861          break;
    00862       cur_state = cur_state->next;
    00863    }
    00864    if (cur_state != NULL)
    00865       return 0;
    00866    cur_state = malloc(sizeof(struct state));
    00867    if (cur_state == NULL) {
    00868       return -1;
    00869    }
    00870    memset(cur_state,0,sizeof(struct state));
    00871    if (tzload((char *) NULL, cur_state) != 0)
    00872 #ifdef DEBUG
    00873    {
    00874       fprintf(stderr, "ast_tzsetwall: calling gmtload()\n");
    00875 #endif
    00876       gmtload(cur_state);
    00877 #ifdef DEBUG
    00878    }
    00879 #endif
    00880
    00881    if (last_lclptr)
    00882       last_lclptr->next = cur_state;
    00883    else
    00884       lclptr = cur_state;
    00885    last_lclptr = cur_state;
    00886    return 0;
    00887 }
    00888
    00889 #ifdef   _THREAD_SAFE
    00890 int
    00891 ast_tzsetwall P((void))
    00892 {
    00893    ast_mutex_lock(&tzsetwall_mutex);
    00894    ast_tzsetwall_basic();
    00895    ast_mutex_unlock(&tzsetwall_mutex);
    00896    return 0;
    00897 }
    00898 #endif
    00899
    00900 #ifdef   _THREAD_SAFE
    00901 static int
    00902 ast_tzset_basic P((const char *name))
    00903 #else
    00904 int
    00905 ast_tzset P((const char *name))
    00906 #endif
    00907 {
    00908    struct state *cur_state = lclptr;
    00909
    00910    /* Not set at all */
    00911    if (name == NULL) {
    00912       return ast_tzsetwall();
    00913    }
    00914
    00915    /* Find the appropriate structure, if already parsed */
    00916    while (cur_state != NULL) {
    00917       if (!strcmp(cur_state->name,name))
    00918          break;
    00919       cur_state = cur_state->next;
    00920    }
    00921    if (cur_state != NULL)
    00922       return 0;
    00923
    00924    cur_state = malloc(sizeof(struct state));
    00925    if (cur_state == NULL) {
    00926       return -1;
    00927    }
    00928    memset(cur_state,0,sizeof(*cur_state));
    00929
    00930    /* Name is set, but set to the empty string == no adjustments */
    00931    if (name[0] == '\0') {
    00932       /*
    00933       ** User wants it fast rather than right.
    00934       */
    00935       cur_state->leapcnt = 0;    /* so, we're off a little */
    00936       cur_state->timecnt = 0;
    00937       cur_state->ttis[0].tt_gmtoff = 0;
    00938       cur_state->ttis[0].tt_abbrind = 0;
    00939       (void) strncpy(cur_state->chars, gmt, sizeof(cur_state->chars) - 1);
    00940    } else if (tzload(name, cur_state) != 0) {
    00941       if (name[0] == ':') {
    00942          (void) gmtload(cur_state);
    00943       } else if (tzparse(name, cur_state, FALSE) != 0) {
    00944          /* If not found, load localtime */
    00945          if (tzload("/etc/localtime", cur_state) != 0)
    00946             /* Last ditch, get GMT */
    00947             (void) gmtload(cur_state);
    00948       }
    00949    }
    00950    strncpy(cur_state->name, name, sizeof(cur_state->name) - 1);
    00951    if (last_lclptr)
    00952       last_lclptr->next = cur_state;
    00953    else
    00954       lclptr = cur_state;
    00955    last_lclptr = cur_state;
    00956    return 0;
    00957 }
    00958
    00959 #ifdef   _THREAD_SAFE
    00960 void
    00961 ast_tzset P((const char *name))
    00962 {
    00963    ast_mutex_lock(&tzset_mutex);
    00964    ast_tzset_basic(name);
    00965    ast_mutex_unlock(&tzset_mutex);
    00966 }
    00967 #endif
    00968
    00969 /*
    00970 ** The easy way to behave "as if no library function calls" localtime
    00971 ** is to not call it--so we drop its guts into "localsub", which can be
    00972 ** freely called.  (And no, the PANS doesn't require the above behavior--
    00973 ** but it *is* desirable.)
    00974 **
    00975 ** The unused offset argument is for the benefit of mktime variants.
    00976 */
    00977
    00978 /*ARGSUSED*/
    00979 static void
    00980 localsub(timep, offset, tmp, zone)
    00981 const time_t * const timep;
    00982 const long     offset;
    00983 struct tm * const tmp;
    00984 const char * const   zone;
    00985 {
    00986    register struct state *    sp;
    00987    register const struct ttinfo *   ttisp;
    00988    register int         i;
    00989    const time_t         t = *timep;
    00990
    00991    sp = lclptr;
    00992    /* Find the right zone record */
    00993    if (zone == NULL)
    00994       sp = NULL;
    00995    else
    00996       while (sp != NULL) {
    00997          if (!strcmp(sp->name,zone))
    00998             break;
    00999          sp = sp->next;
    01000       }
    01001
    01002    if (sp == NULL) {
    01003       ast_tzsetwall();
    01004       sp = lclptr;
    01005       /* Find the default zone record */
    01006       while (sp != NULL) {
    01007          if (sp->name[0] == '\0')
    01008             break;
    01009          sp = sp->next;
    01010       }
    01011    }
    01012
    01013    /* Last ditch effort, use GMT */
    01014    if (sp == NULL) {
    01015       gmtsub(timep, offset, tmp, zone);
    01016       return;
    01017    }
    01018    if (sp->timecnt == 0 || t < sp->ats[0]) {
    01019       i = 0;
    01020       while (sp->ttis[i].tt_isdst)
    01021          if (++i >= sp->typecnt) {
    01022             i = 0;
    01023             break;
    01024          }
    01025    } else {
    01026       for (i = 1; i < sp->timecnt; ++i)
    01027          if (t < sp->ats[i])
    01028             break;
    01029       i = sp->types[i - 1];
    01030    }
    01031    ttisp = &sp->ttis[i];
    01032    /*
    01033    ** To get (wrong) behavior that's compatible with System V Release 2.0
    01034    ** you'd replace the statement below with
    01035    ** t += ttisp->tt_gmtoff;
    01036    ** timesub(&t, 0L, sp, tmp);
    01037    */
    01038    timesub(&t, ttisp->tt_gmtoff, sp, tmp);
    01039    tmp->tm_isdst = ttisp->tt_isdst;
    01040    tzname[tmp->tm_isdst] = &sp->chars[ttisp->tt_abbrind];
    01041 #ifdef TM_ZONE
    01042    tmp->TM_ZONE = &sp->chars[ttisp->tt_abbrind];
    01043 #endif /* defined TM_ZONE */
    01044 }
    01045
    01046 struct tm *
    01047 ast_localtime(timep, p_tm, zone)
    01048 const time_t * const timep;
    01049 struct tm *p_tm;
    01050 const char * const   zone;
    01051 {
    01052 #ifdef _THREAD_SAFE
    01053    ast_mutex_lock(&lcl_mutex);
    01054 #endif
    01055    ast_tzset(ast_strlen_zero(zone) ? "/etc/localtime" : zone);
    01056    localsub(timep, 0L, p_tm, zone);
    01057 #ifdef _THREAD_SAFE
    01058    ast_mutex_unlock(&lcl_mutex);
    01059 #endif
    01060    return(p_tm);
    01061 }
    01062
    01063 /*
    01064 ** gmtsub is to gmtime as localsub is to localtime.
    01065 */
    01066
    01067 static void
    01068 gmtsub(timep, offset, tmp, zone)
    01069 const time_t * const timep;
    01070 const long     offset;
    01071 struct tm * const tmp;
    01072 const char * const   zone;
    01073 {
    01074 #ifdef   _THREAD_SAFE
    01075    ast_mutex_lock(&gmt_mutex);
    01076 #endif
    01077    if (!gmt_is_set) {
    01078       gmt_is_set = TRUE;
    01079       gmtptr = (struct state *) malloc(sizeof *gmtptr);
    01080       if (gmtptr != NULL)
    01081          gmtload(gmtptr);
    01082    }
    01083    ast_mutex_unlock(&gmt_mutex);
    01084    timesub(timep, offset, gmtptr, tmp);
    01085 #ifdef TM_ZONE
    01086    /*
    01087    ** Could get fancy here and deliver something such as
    01088    ** "GMT+xxxx" or "GMT-xxxx" if offset is non-zero,
    01089    ** but this is no time for a treasure hunt.
    01090    */
    01091    if (offset != 0)
    01092       tmp->TM_ZONE = wildabbr;
    01093    else {
    01094       if (gmtptr == NULL)
    01095          tmp->TM_ZONE = gmt;
    01096       else  tmp->TM_ZONE = gmtptr->chars;
    01097    }
    01098 #endif /* defined TM_ZONE */
    01099 }
    01100
    01101 static void
    01102 timesub(timep, offset, sp, tmp)
    01103 const time_t * const       timep;
    01104 const long           offset;
    01105 register const struct state * const sp;
    01106 register struct tm * const    tmp;
    01107 {
    01108    register const struct lsinfo *   lp;
    01109    register long        days;
    01110    register long        rem;
    01111    register int         y;
    01112    register int         yleap;
    01113    register const int *    ip;
    01114    register long        corr;
    01115    register int         hit;
    01116    register int         i;
    01117
    01118    corr = 0;
    01119    hit = 0;
    01120    i = (sp == NULL) ? 0 : sp->leapcnt;
    01121    while (--i >= 0) {
    01122       lp = &sp->lsis[i];
    01123       if (*timep >= lp->ls_trans) {
    01124          if (*timep == lp->ls_trans) {
    01125             hit = ((i == 0 && lp->ls_corr > 0) ||
    01126                lp->ls_corr > sp->lsis[i - 1].ls_corr);
    01127             if (hit)
    01128                while (i > 0 &&
    01129                   sp->lsis[i].ls_trans ==
    01130                   sp->lsis[i - 1].ls_trans + 1 &&
    01131                   sp->lsis[i].ls_corr ==
    01132                   sp->lsis[i - 1].ls_corr + 1) {
    01133                      ++hit;
    01134                      --i;
    01135                }
    01136          }
    01137          corr = lp->ls_corr;
    01138          break;
    01139       }
    01140    }
    01141    days = *timep / SECSPERDAY;
    01142    rem = *timep % SECSPERDAY;
    01143 #ifdef mc68k
    01144    if (*timep == 0x80000000) {
    01145       /*
    01146       ** A 3B1 muffs the division on the most negative number.
    01147       */
    01148       days = -24855;
    01149       rem = -11648;
    01150    }
    01151 #endif /* defined mc68k */
    01152    rem += (offset - corr);
    01153    while (rem < 0) {
    01154       rem += SECSPERDAY;
    01155       --days;
    01156    }
    01157    while (rem >= SECSPERDAY) {
    01158       rem -= SECSPERDAY;
    01159       ++days;
    01160    }
    01161    tmp->tm_hour = (int) (rem / SECSPERHOUR);
    01162    rem = rem % SECSPERHOUR;
    01163    tmp->tm_min = (int) (rem / SECSPERMIN);
    01164    /*
    01165    ** A positive leap second requires a special
    01166    ** representation.  This uses "... ??:59:60" et seq.
    01167    */
    01168    tmp->tm_sec = (int) (rem % SECSPERMIN) + hit;
    01169    tmp->tm_wday = (int) ((EPOCH_WDAY + days) % DAYSPERWEEK);
    01170    if (tmp->tm_wday < 0)
    01171       tmp->tm_wday += DAYSPERWEEK;
    01172    y = EPOCH_YEAR;
    01173 #define LEAPS_THRU_END_OF(y)  ((y) / 4 - (y) / 100 + (y) / 400)
    01174    while (days < 0 || days >= (long) year_lengths[yleap = isleap(y)]) {
    01175       register int   newy;
    01176
    01177       newy = y + days / DAYSPERNYEAR;
    01178       if (days < 0)
    01179          --newy;
    01180       days -= (newy - y) * DAYSPERNYEAR +
    01181          LEAPS_THRU_END_OF(newy - 1) -
    01182          LEAPS_THRU_END_OF(y - 1);
    01183       y = newy;
    01184    }
    01185    tmp->tm_year = y - TM_YEAR_BASE;
    01186    tmp->tm_yday = (int) days;
    01187    ip = mon_lengths[yleap];
    01188    for (tmp->tm_mon = 0; days >= (long) ip[tmp->tm_mon]; ++(tmp->tm_mon))
    01189       days = days - (long) ip[tmp->tm_mon];
    01190    tmp->tm_mday = (int) (days + 1);
    01191    tmp->tm_isdst = 0;
    01192 #ifdef TM_GMTOFF
    01193    tmp->TM_GMTOFF = offset;
    01194 #endif /* defined TM_GMTOFF */
    01195 }
    01196
    01197 char *
    01198 ast_ctime(timep)
    01199 const time_t * const timep;
    01200 {
    01201 /*
    01202 ** Section 4.12.3.2 of X3.159-1989 requires that
    01203 ** The ctime funciton converts the calendar time pointed to by timer
    01204 ** to local time in the form of a string.  It is equivalent to
    01205 **    asctime(localtime(timer))
    01206 */
    01207    return asctime(localtime(timep));
    01208 }
    01209
    01210 char *
    01211 ast_ctime_r(timep, buf)
    01212 const time_t * const timep;
    01213 char *buf;
    01214 {
    01215         struct tm tm;
    01216 #ifdef SOLARIS
    01217    return asctime_r(localtime_r(timep, &tm), buf, 256);
    01218 #else
    01219    return asctime_r(localtime_r(timep, &tm), buf);
    01220 #endif
    01221 }
    01222
    01223 /*
    01224 ** Adapted from code provided by Robert Elz, who writes:
    01225 ** The "best" way to do mktime I think is based on an idea of Bob
    01226 ** Kridle's (so its said...) from a long time ago.
    01227 ** [kridle@xinet.com as of 1996-01-16.]
    01228 ** It does a binary search of the time_t space.  Since time_t's are
    01229 ** just 32 bits, its a max of 32 iterations (even at 64 bits it
    01230 ** would still be very reasonable).
    01231 */
    01232
    01233 #ifndef WRONG
    01234 #define WRONG  (-1)
    01235 #endif /* !defined WRONG */
    01236
    01237 /*
    01238 ** Simplified normalize logic courtesy Paul Eggert (eggert@twinsun.com).
    01239 */
    01240
    01241 static int
    01242 increment_overflow(number, delta)
    01243 int * number;
    01244 int   delta;
    01245 {
    01246    int   number0;
    01247
    01248    number0 = *number;
    01249    *number += delta;
    01250    return (*number < number0) != (delta < 0);
    01251 }
    01252
    01253 static int
    01254 normalize_overflow(tensptr, unitsptr, base)
    01255 int * const tensptr;
    01256 int * const unitsptr;
    01257 const int   base;
    01258 {
    01259    register int   tensdelta;
    01260
    01261    tensdelta = (*unitsptr >= 0) ?
    01262       (*unitsptr / base) :
    01263       (-1 - (-1 - *unitsptr) / base);
    01264    *unitsptr -= tensdelta * base;
    01265    return increment_overflow(tensptr, tensdelta);
    01266 }
    01267
    01268 static int
    01269 tmcomp(atmp, btmp)
    01270 register const struct tm * const atmp;
    01271 register const struct tm * const btmp;
    01272 {
    01273    register int   result;
    01274
    01275    if ((result = (atmp->tm_year - btmp->tm_year)) == 0 &&
    01276       (result = (atmp->tm_mon - btmp->tm_mon)) == 0 &&
    01277       (result = (atmp->tm_mday - btmp->tm_mday)) == 0 &&
    01278       (result = (atmp->tm_hour - btmp->tm_hour)) == 0 &&
    01279       (result = (atmp->tm_min - btmp->tm_min)) == 0)
    01280          result = atmp->tm_sec - btmp->tm_sec;
    01281    return result;
    01282 }
    01283
    01284 static time_t
    01285 time2(tmp, funcp, offset, okayp, zone)
    01286 struct tm * const tmp;
    01287 void (* const     funcp) P((const time_t*, long, struct tm*, const char*));
    01288 const long     offset;
    01289 int * const    okayp;
    01290 const char * const   zone;
    01291 {
    01292    register const struct state * sp;
    01293    register int         dir;
    01294    register int         bits;
    01295    register int         i, j ;
    01296    register int         saved_seconds;
    01297    time_t            newt;
    01298    time_t            t;
    01299    struct tm         yourtm, mytm;
    01300
    01301    *okayp = FALSE;
    01302    yourtm = *tmp;
    01303    if (normalize_overflow(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR))
    01304       return WRONG;
    01305    if (normalize_overflow(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY))
    01306       return WRONG;
    01307    if (normalize_overflow(&yourtm.tm_year, &yourtm.tm_mon, MONSPERYEAR))
    01308       return WRONG;
    01309    /*
    01310    ** Turn yourtm.tm_year into an actual year number for now.
    01311    ** It is converted back to an offset from TM_YEAR_BASE later.
    01312    */
    01313    if (increment_overflow(&yourtm.tm_year, TM_YEAR_BASE))
    01314       return WRONG;
    01315    while (yourtm.tm_mday <= 0) {
    01316       if (increment_overflow(&yourtm.tm_year, -1))
    01317          return WRONG;
    01318       i = yourtm.tm_year + (1 < yourtm.tm_mon);
    01319       yourtm.tm_mday += year_lengths[isleap(i)];
    01320    }
    01321    while (yourtm.tm_mday > DAYSPERLYEAR) {
    01322       i = yourtm.tm_year + (1 < yourtm.tm_mon);
    01323       yourtm.tm_mday -= year_lengths[isleap(i)];
    01324       if (increment_overflow(&yourtm.tm_year, 1))
    01325          return WRONG;
    01326    }
    01327    for ( ; ; ) {
    01328       i = mon_lengths[isleap(yourtm.tm_year)][yourtm.tm_mon];
    01329       if (yourtm.tm_mday <= i)
    01330          break;
    01331       yourtm.tm_mday -= i;
    01332       if (++yourtm.tm_mon >= MONSPERYEAR) {
    01333          yourtm.tm_mon = 0;
    01334          if (increment_overflow(&yourtm.tm_year, 1))
    01335             return WRONG;
    01336       }
    01337    }
    01338    if (increment_overflow(&yourtm.tm_year, -TM_YEAR_BASE))
    01339       return WRONG;
    01340    if (yourtm.tm_year + TM_YEAR_BASE < EPOCH_YEAR) {
    01341       /*
    01342       ** We can't set tm_sec to 0, because that might push the
    01343       ** time below the minimum representable time.
    01344       ** Set tm_sec to 59 instead.
    01345       ** This assumes that the minimum representable time is
    01346       ** not in the same minute that a leap second was deleted from,
    01347       ** which is a safer assumption than using 58 would be.
    01348       */
    01349       if (increment_overflow(&yourtm.tm_sec, 1 - SECSPERMIN))
    01350          return WRONG;
    01351       saved_seconds = yourtm.tm_sec;
    01352       yourtm.tm_sec = SECSPERMIN - 1;
    01353    } else {
    01354       saved_seconds = yourtm.tm_sec;
    01355       yourtm.tm_sec = 0;
    01356    }
    01357    /*
    01358    ** Divide the search space in half
    01359    ** (this works whether time_t is signed or unsigned).
    01360    */
    01361    bits = TYPE_BIT(time_t) - 1;
    01362    /*
    01363    ** If time_t is signed, then 0 is just above the median,
    01364    ** assuming two's complement arithmetic.
    01365    ** If time_t is unsigned, then (1 << bits) is just above the median.
    01366    */
    01367    t = TYPE_SIGNED(time_t) ? 0 : (((time_t) 1) << bits);
    01368    for ( ; ; ) {
    01369       (*funcp)(&t, offset, &mytm, zone);
    01370       dir = tmcomp(&mytm, &yourtm);
    01371       if (dir != 0) {
    01372          if (bits-- < 0)
    01373             return WRONG;
    01374          if (bits < 0)
    01375             --t; /* may be needed if new t is minimal */
    01376          else if (dir > 0)
    01377             t -= ((time_t) 1) << bits;
    01378          else  t += ((time_t) 1) << bits;
    01379          continue;
    01380       }
    01381       if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst)
    01382          break;
    01383       /*
    01384       ** Right time, wrong type.
    01385       ** Hunt for right time, right type.
    01386       ** It's okay to guess wrong since the guess
    01387       ** gets checked.
    01388       */
    01389       /*
    01390       ** The (void *) casts are the benefit of SunOS 3.3 on Sun 2's.
    01391       */
    01392       sp = (const struct state *)
    01393          (((void *) funcp == (void *) localsub) ?
    01394          lclptr : gmtptr);
    01395       if (sp == NULL)
    01396          return WRONG;
    01397       for (i = sp->typecnt - 1; i >= 0; --i) {
    01398          if (sp->ttis[i].tt_isdst != yourtm.tm_isdst)
    01399             continue;
    01400          for (j = sp->typecnt - 1; j >= 0; --j) {
    01401             if (sp->ttis[j].tt_isdst == yourtm.tm_isdst)
    01402                continue;
    01403             newt = t + sp->ttis[j].tt_gmtoff -
    01404                sp->ttis[i].tt_gmtoff;
    01405             (*funcp)(&newt, offset, &mytm, zone);
    01406             if (tmcomp(&mytm, &yourtm) != 0)
    01407                continue;
    01408             if (mytm.tm_isdst != yourtm.tm_isdst)
    01409                continue;
    01410             /*
    01411             ** We have a match.
    01412             */
    01413             t = newt;
    01414             goto label;
    01415          }
    01416       }
    01417       return WRONG;
    01418    }
    01419 label:
    01420    newt = t + saved_seconds;
    01421    if ((newt < t) != (saved_seconds < 0))
    01422       return WRONG;
    01423    t = newt;
    01424    (*funcp)(&t, offset, tmp, zone);
    01425    *okayp = TRUE;
    01426    return t;
    01427 }
    01428
    01429 static time_t
    01430 time1(tmp, funcp, offset, zone)
    01431 struct tm * const tmp;
    01432 void (* const     funcp) P((const time_t *, long, struct tm *, const char*));
    01433 const long     offset;
    01434 const char * const   zone;
    01435 {
    01436    register time_t         t;
    01437    register const struct state * sp;
    01438    register int         samei, otheri;
    01439    int            okay;
    01440
    01441    if (tmp->tm_isdst > 1)
    01442       tmp->tm_isdst = 1;
    01443    t = time2(tmp, funcp, offset, &okay, zone);
    01444 #ifdef PCTS
    01445    /*
    01446    ** PCTS code courtesy Grant Sullivan (grant@osf.org).
    01447    */
    01448    if (okay)
    01449       return t;
    01450    if (tmp->tm_isdst < 0)
    01451       tmp->tm_isdst = 0;   /* reset to std and try again */
    01452 #endif /* defined PCTS */
    01453 #ifndef PCTS
    01454    if (okay || tmp->tm_isdst < 0)
    01455       return t;
    01456 #endif /* !defined PCTS */
    01457    /*
    01458    ** We're supposed to assume that somebody took a time of one type
    01459    ** and did some math on it that yielded a "struct tm" that's bad.
    01460    ** We try to divine the type they started from and adjust to the
    01461    ** type they need.
    01462    */
    01463    /*
    01464    ** The (void *) casts are the benefit of SunOS 3.3 on Sun 2's.
    01465    */
    01466    sp = (const struct state *) (((void *) funcp == (void *) localsub) ?
    01467       lclptr : gmtptr);
    01468    if (sp == NULL)
    01469       return WRONG;
    01470    for (samei = sp->typecnt - 1; samei >= 0; --samei) {
    01471       if (sp->ttis[samei].tt_isdst != tmp->tm_isdst)
    01472          continue;
    01473       for (otheri = sp->typecnt - 1; otheri >= 0; --otheri) {
    01474          if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst)
    01475             continue;
    01476          tmp->tm_sec += sp->ttis[otheri].tt_gmtoff -
    01477                sp->ttis[samei].tt_gmtoff;
    01478          tmp->tm_isdst = !tmp->tm_isdst;
    01479          t = time2(tmp, funcp, offset, &okay, zone);
    01480          if (okay)
    01481             return t;
    01482          tmp->tm_sec -= sp->ttis[otheri].tt_gmtoff -
    01483                sp->ttis[samei].tt_gmtoff;
    01484          tmp->tm_isdst = !tmp->tm_isdst;
    01485       }
    01486    }
    01487    return WRONG;
    01488 }
    01489
    01490 time_t
    01491 ast_mktime(tmp,zone)
    01492 struct tm * const tmp;
    01493 const char * const   zone;
    01494 {
    01495    time_t mktime_return_value;
    01496 #ifdef   _THREAD_SAFE
    01497    ast_mutex_lock(&lcl_mutex);
    01498 #endif
    01499    ast_tzset(!ast_strlen_zero(zone) ? zone : "/etc/localtime");
    01500    mktime_return_value = time1(tmp, localsub, 0L, !ast_strlen_zero(zone) ? zone : "/etc/localtime");
    01501 #ifdef   _THREAD_SAFE
    01502    ast_mutex_unlock(&lcl_mutex);
    01503 #endif
    01504    return(mktime_return_value);
    01505 }
    01506