Fri Aug 24 02:22:16 2007

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 /*LINTLIBRARY*/
00047 
00048 #include <sys/types.h>
00049 #include <sys/stat.h>
00050 #include <fcntl.h>
00051 #ifdef DEBUG
00052 #include <stdio.h>
00053 #endif
00054 
00055 #include "private.h"
00056 #include "tzfile.h"
00057 
00058 #include "asterisk.h"
00059 
00060 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
00061 
00062 #include "asterisk/lock.h"
00063 #include "asterisk/localtime.h"
00064 #include "asterisk/strings.h"
00065 
00066 #ifndef lint
00067 #ifndef NOID
00068 static const char elsieid[] = "@(#)localtime.c  7.57";
00069 #endif /* !defined NOID */
00070 #endif /* !defined lint */
00071 
00072 
00073 
00074 /*
00075 ** SunOS 4.1.1 headers lack O_BINARY.
00076 */
00077 
00078 #ifdef O_BINARY
00079 #define OPEN_MODE (O_RDONLY | O_BINARY)
00080 #endif /* defined O_BINARY */
00081 #ifndef O_BINARY
00082 #define OPEN_MODE O_RDONLY
00083 #endif /* !defined O_BINARY */
00084 
00085 #ifdef SOLARIS
00086 #undef TM_ZONE
00087 #undef TM_GMTOFF 
00088 #endif
00089 
00090 #ifdef TM_ZONE
00091 #ifndef WILDABBR
00092 /*! \note
00093  * Someone might make incorrect use of a time zone abbreviation:
00094  * 1. They might reference tzname[0] before calling ast_tzset (explicitly
00095  *    or implicitly).
00096  * 2. They might reference tzname[1] before calling ast_tzset (explicitly
00097  *    or implicitly).
00098  * 3. They might reference tzname[1] after setting to a time zone
00099  *    in which Daylight Saving Time is never observed.
00100  * 4. They might reference tzname[0] after setting to a time zone
00101  *    in which Standard Time is never observed.
00102  * 5. They might reference tm.TM_ZONE after calling offtime.
00103  * What's best to do in the above cases is open to debate;
00104  * for now, we just set things up so that in any of the five cases
00105  * WILDABBR is used.  Another possibility:  initialize tzname[0] to the
00106  * string "tzname[0] used before set", and similarly for the other cases.
00107  * And another:  initialize tzname[0] to "ERA", with an explanation in the
00108  * manual page of what this "time zone abbreviation" means (doing this so
00109  * that tzname[0] has the "normal" length of three characters).
00110  */
00111 #define WILDABBR  "   "
00112 #endif /* !defined WILDABBR */
00113 
00114 static char    wildabbr[] = "WILDABBR";
00115 #endif /* TM_ZONE */
00116 
00117 /*! \brief FreeBSD defines 'zone' in 'struct tm' as non-const, so don't declare this
00118    string as const. */
00119 static char    gmt[] = "GMT";
00120 
00121 /*!< \brief time type information */
00122 struct ttinfo {
00123    long     tt_gmtoff;  /*!< GMT offset in seconds */
00124    int      tt_isdst;   /*!< used to set tm_isdst */
00125    int      tt_abbrind; /*!< abbreviation list index */
00126    int      tt_ttisstd; /*!< TRUE if transition is std time */
00127    int      tt_ttisgmt; /*!< TRUE if transition is GMT */
00128 };
00129 
00130 /*! \brief leap second information */
00131 struct lsinfo {
00132    time_t      ls_trans;   /*!< transition time */
00133    long     ls_corr; /*!< correction to apply */
00134 };
00135 
00136 #define BIGGEST(a, b)   (((a) > (b)) ? (a) : (b))
00137 
00138 #ifdef TZNAME_MAX
00139 #define MY_TZNAME_MAX   TZNAME_MAX
00140 #endif /* defined TZNAME_MAX */
00141 #ifndef TZNAME_MAX
00142 #define MY_TZNAME_MAX   255
00143 #endif /* !defined TZNAME_MAX */
00144 
00145 struct state {
00146    char  name[TZ_STRLEN_MAX + 1];
00147    int      leapcnt;
00148    int      timecnt;
00149    int      typecnt;
00150    int      charcnt;
00151    time_t      ats[TZ_MAX_TIMES];
00152    unsigned char  types[TZ_MAX_TIMES];
00153    struct ttinfo  ttis[TZ_MAX_TYPES];
00154    char     chars[BIGGEST(BIGGEST(TZ_MAX_CHARS + 1, sizeof gmt),
00155             (2 * (MY_TZNAME_MAX + 1)))];
00156    struct lsinfo  lsis[TZ_MAX_LEAPS];
00157    struct state   *next;
00158 };
00159 
00160 struct rule {
00161    int      r_type;     /*!< type of rule--see below */
00162    int      r_day;      /*!< day number of rule */
00163    int      r_week;     /*!< week number of rule */
00164    int      r_mon;      /*!< month number of rule */
00165    long     r_time;     /*!< transition time of rule */
00166 };
00167 
00168 #define JULIAN_DAY      0  /*!< Jn - Julian day */
00169 #define DAY_OF_YEAR     1  /*!< n - day of year */
00170 #define MONTH_NTH_DAY_OF_WEEK 2  /*!< Mm.n.d - month, week, day of week */
00171 
00172 /*
00173 ** Prototypes for static functions.
00174 */
00175 
00176 static long    detzcode P((const char * codep));
00177 static const char *  getnum P((const char * strp, int * nump, int min,
00178             int max));
00179 static const char *  getsecs P((const char * strp, long * secsp));
00180 static const char *  getoffset P((const char * strp, long * offsetp));
00181 static const char *  getrule P((const char * strp, struct rule * rulep));
00182 static void    gmtload P((struct state * sp));
00183 static void    gmtsub P((const time_t * timep, long offset,
00184             struct tm * tmp, const char * zone));
00185 static void    localsub P((const time_t * timep, long offset,
00186             struct tm * tmp, const char * zone));
00187 static int     increment_overflow P((int * number, int delta));
00188 static int     normalize_overflow P((int * tensptr, int * unitsptr,
00189             int base));
00190 static time_t     time1 P((struct tm * tmp,
00191             void(*funcp) P((const time_t *,
00192             long, struct tm *, const char*)),
00193             long offset, const char * zone));
00194 static time_t     time2 P((struct tm *tmp,
00195             void(*funcp) P((const time_t *,
00196             long, struct tm*, const char*)),
00197             long offset, int * okayp, const char * zone));
00198 static void    timesub P((const time_t * timep, long offset,
00199             const struct state * sp, struct tm * tmp));
00200 static int     tmcomp P((const struct tm * atmp,
00201             const struct tm * btmp));
00202 static time_t     transtime P((time_t janfirst, int year,
00203             const struct rule * rulep, long offset));
00204 static int     tzload P((const char * name, struct state * sp));
00205 static int     tzparse P((const char * name, struct state * sp,
00206             int lastditch));
00207 
00208 static struct state *   lclptr      = NULL;
00209 static struct state *   last_lclptr = NULL;
00210 static struct state *   gmtptr      = NULL;
00211 
00212 #ifndef TZ_STRLEN_MAX
00213 #define TZ_STRLEN_MAX 255
00214 #endif /* !defined TZ_STRLEN_MAX */
00215 
00216 static int     gmt_is_set;
00217 #ifdef   _THREAD_SAFE
00218 AST_MUTEX_DEFINE_STATIC(lcl_mutex);
00219 AST_MUTEX_DEFINE_STATIC(tzset_mutex);
00220 AST_MUTEX_DEFINE_STATIC(tzsetwall_mutex);
00221 AST_MUTEX_DEFINE_STATIC(gmt_mutex);
00222 #endif
00223 
00224 /*
00225 ** Section 4.12.3 of X3.159-1989 requires that
00226 ** Except for the strftime function, these functions [asctime,
00227 ** ctime, gmtime, localtime] return values in one of two static
00228 ** objects: a broken-down time structure and an array of char.
00229 ** Thanks to Paul Eggert (eggert@twinsun.com) for noting this.
00230 */
00231 
00232 static long detzcode(const char * const   codep)
00233 {
00234    register long  result;
00235    register int   i;
00236 
00237    result = (codep[0] & 0x80) ? ~0L : 0L;
00238    for (i = 0; i < 4; ++i)
00239       result = (result << 8) | (codep[i] & 0xff);
00240    return result;
00241 }
00242 
00243 static int tzload(register const char *name, register struct state *const  sp)
00244 {
00245    register const char *   p;
00246    register int      i;
00247    register int      fid;
00248 
00249 #ifdef DEBUG
00250    fprintf(stderr,"tzload called with name=%s, sp=%d\n", name, sp);
00251 #endif
00252    if (name == NULL && (name = TZDEFAULT) == NULL)
00253       return -1;
00254    {
00255       register int   doaccess;
00256       struct stat stab;
00257       /*
00258       ** Section 4.9.1 of the C standard says that
00259       ** "FILENAME_MAX expands to an integral constant expression
00260       ** that is the size needed for an array of char large enough
00261       ** to hold the longest file name string that the implementation
00262       ** guarantees can be opened."
00263       */
00264       char     fullname[FILENAME_MAX + 1] = "";
00265 
00266       if (name[0] == ':')
00267          ++name;
00268       doaccess = name[0] == '/';
00269       if (!doaccess) {
00270          if ((p = TZDIR) == NULL)
00271             return -1;
00272          if ((strlen(p) + 1 + strlen(name) + 1) >= sizeof fullname)
00273             return -1;
00274          (void) strncpy(fullname, p, sizeof(fullname) - 1);
00275          (void) strncat(fullname, "/", sizeof(fullname) - strlen(fullname) - 1);
00276          (void) strncat(fullname, name, sizeof(fullname) - strlen(fullname) - 1);
00277          /*
00278          ** Set doaccess if '.' (as in "../") shows up in name.
00279          */
00280          if (strchr(name, '.') != NULL)
00281             doaccess = TRUE;
00282          name = fullname;
00283       }
00284       if (doaccess && access(name, R_OK) != 0)
00285             return -1;
00286       if ((fid = open(name, OPEN_MODE)) == -1)
00287          return -1;
00288       if ((fstat(fid, &stab) < 0) || !S_ISREG(stab.st_mode)) {
00289          close(fid);
00290          return -1;
00291       }
00292    }
00293    {
00294       struct tzhead *   tzhp;
00295       char     buf[sizeof *sp + sizeof *tzhp];
00296       int      ttisstdcnt;
00297       int      ttisgmtcnt;
00298 
00299       i = read(fid, buf, sizeof buf);
00300       if (close(fid) != 0)
00301          return -1;
00302       p = buf;
00303       p += (sizeof tzhp->tzh_magic) + (sizeof tzhp->tzh_reserved);
00304       ttisstdcnt = (int) detzcode(p);
00305       p += 4;
00306       ttisgmtcnt = (int) detzcode(p);
00307       p += 4;
00308       sp->leapcnt = (int) detzcode(p);
00309       p += 4;
00310       sp->timecnt = (int) detzcode(p);
00311       p += 4;
00312       sp->typecnt = (int) detzcode(p);
00313       p += 4;
00314       sp->charcnt = (int) detzcode(p);
00315       p += 4;
00316       if (sp->leapcnt < 0 || sp->leapcnt > TZ_MAX_LEAPS ||
00317          sp->typecnt <= 0 || sp->typecnt > TZ_MAX_TYPES ||
00318          sp->timecnt < 0 || sp->timecnt > TZ_MAX_TIMES ||
00319          sp->charcnt < 0 || sp->charcnt > TZ_MAX_CHARS ||
00320          (ttisstdcnt != sp->typecnt && ttisstdcnt != 0) ||
00321          (ttisgmtcnt != sp->typecnt && ttisgmtcnt != 0))
00322             return -1;
00323       if (i - (p - buf) < sp->timecnt * 4 +  /* ats */
00324          sp->timecnt +        /* types */
00325          sp->typecnt * (4 + 2) +    /* ttinfos */
00326          sp->charcnt +        /* chars */
00327          sp->leapcnt * (4 + 4) +    /* lsinfos */
00328          ttisstdcnt +         /* ttisstds */
00329          ttisgmtcnt)       /* ttisgmts */
00330             return -1;
00331       for (i = 0; i < sp->timecnt; ++i) {
00332          sp->ats[i] = detzcode(p);
00333          p += 4;
00334       }
00335       for (i = 0; i < sp->timecnt; ++i) {
00336          sp->types[i] = (unsigned char) *p++;
00337          if (sp->types[i] >= sp->typecnt)
00338             return -1;
00339       }
00340       for (i = 0; i < sp->typecnt; ++i) {
00341          register struct ttinfo *   ttisp;
00342 
00343          ttisp = &sp->ttis[i];
00344          ttisp->tt_gmtoff = detzcode(p);
00345          p += 4;
00346          ttisp->tt_isdst = (unsigned char) *p++;
00347          if (ttisp->tt_isdst != 0 && ttisp->tt_isdst != 1)
00348             return -1;
00349          ttisp->tt_abbrind = (unsigned char) *p++;
00350          if (ttisp->tt_abbrind < 0 ||
00351             ttisp->tt_abbrind > sp->charcnt)
00352                return -1;
00353       }
00354       for (i = 0; i < sp->charcnt; ++i)
00355          sp->chars[i] = *p++;
00356       sp->chars[i] = '\0'; /* ensure '\0' at end */
00357       for (i = 0; i < sp->leapcnt; ++i) {
00358          register struct lsinfo *   lsisp;
00359 
00360          lsisp = &sp->lsis[i];
00361          lsisp->ls_trans = detzcode(p);
00362          p += 4;
00363          lsisp->ls_corr = detzcode(p);
00364          p += 4;
00365       }
00366       for (i = 0; i < sp->typecnt; ++i) {
00367          register struct ttinfo *   ttisp;
00368 
00369          ttisp = &sp->ttis[i];
00370          if (ttisstdcnt == 0)
00371             ttisp->tt_ttisstd = FALSE;
00372          else {
00373             ttisp->tt_ttisstd = *p++;
00374             if (ttisp->tt_ttisstd != TRUE &&
00375                ttisp->tt_ttisstd != FALSE)
00376                   return -1;
00377          }
00378       }
00379       for (i = 0; i < sp->typecnt; ++i) {
00380          register struct ttinfo *   ttisp;
00381 
00382          ttisp = &sp->ttis[i];
00383          if (ttisgmtcnt == 0)
00384             ttisp->tt_ttisgmt = FALSE;
00385          else {
00386             ttisp->tt_ttisgmt = *p++;
00387             if (ttisp->tt_ttisgmt != TRUE &&
00388                ttisp->tt_ttisgmt != FALSE)
00389                   return -1;
00390          }
00391       }
00392    }
00393    return 0;
00394 }
00395 
00396 static const int  mon_lengths[2][MONSPERYEAR] = {
00397    { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
00398    { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
00399 };
00400 
00401 static const int  year_lengths[2] = {
00402    DAYSPERNYEAR, DAYSPERLYEAR
00403 };
00404 
00405 /*! \brief
00406  * Given a pointer into a time zone string, extract a number from that string.
00407  * \return Check that the number is within a specified range; if it is not, return
00408  * NULL.
00409  * Otherwise, return a pointer to the first character not part of the number.
00410 */
00411 
00412 static const char *getnum(register const char *strp, int * const nump, const int min, const int max)
00413 {
00414    register char  c;
00415    register int   num;
00416 
00417    if (strp == NULL || !is_digit(c = *strp))
00418       return NULL;
00419    num = 0;
00420    do {
00421       num = num * 10 + (c - '0');
00422       if (num > max)
00423          return NULL;   /* illegal value */
00424       c = *++strp;
00425    } while (is_digit(c));
00426    if (num < min)
00427       return NULL;      /* illegal value */
00428    *nump = num;
00429    return strp;
00430 }
00431 
00432 /*! \brief
00433  * Given a pointer into a time zone string, extract a number of seconds,
00434  * in hh[:mm[:ss]] form, from the string.
00435  * \return If any error occurs, return NULL.
00436  * Otherwise, return a pointer to the first character not part of the number
00437  * of seconds.
00438 */
00439 
00440 static const char *getsecs(register const char *strp, long * const secsp)
00441 {
00442    int   num;
00443 
00444    /*
00445    ** `HOURSPERDAY * DAYSPERWEEK - 1' allows quasi-Posix rules like
00446    ** "M10.4.6/26", which does not conform to Posix,
00447    ** but which specifies the equivalent of
00448    ** ``02:00 on the first Sunday on or after 23 Oct''.
00449    */
00450    strp = getnum(strp, &num, 0, HOURSPERDAY * DAYSPERWEEK - 1);
00451    if (strp == NULL)
00452       return NULL;
00453    *secsp = num * (long) SECSPERHOUR;
00454    if (*strp == ':') {
00455       ++strp;
00456       strp = getnum(strp, &num, 0, MINSPERHOUR - 1);
00457       if (strp == NULL)
00458          return NULL;
00459       *secsp += num * SECSPERMIN;
00460       if (*strp == ':') {
00461          ++strp;
00462          /* `SECSPERMIN' allows for leap seconds.  */
00463          strp = getnum(strp, &num, 0, SECSPERMIN);
00464          if (strp == NULL)
00465             return NULL;
00466          *secsp += num;
00467       }
00468    }
00469    return strp;
00470 }
00471 
00472 /*! \brief
00473  * Given a pointer into a time zone string, extract an offset, in
00474  * [+-]hh[:mm[:ss]] form, from the string.
00475  * \return If any error occurs, return NULL.
00476  * Otherwise, return a pointer to the first character not part of the time.
00477 */
00478 
00479 static const char * getoffset(register const char *strp, long * const offsetp)
00480 {
00481    register int   neg = 0;
00482 
00483    if (*strp == '-') {
00484       neg = 1;
00485       ++strp;
00486    } else if (*strp == '+')
00487       ++strp;
00488    strp = getsecs(strp, offsetp);
00489    if (strp == NULL)
00490       return NULL;      /* illegal time */
00491    if (neg)
00492       *offsetp = -*offsetp;
00493    return strp;
00494 }
00495 
00496 /*! \brief
00497  * Given a pointer into a time zone string, extract a rule in the form
00498  * date[/time].  See POSIX section 8 for the format of "date" and "time".
00499  * \return If a valid rule is not found, return NULL.
00500  * Otherwise, return a pointer to the first character not part of the rule.
00501 */
00502 
00503 static const char *getrule(const char *strp, register struct rule * const rulep)
00504 {
00505    if (*strp == 'J') {
00506       /*
00507       ** Julian day.
00508       */
00509       rulep->r_type = JULIAN_DAY;
00510       ++strp;
00511       strp = getnum(strp, &rulep->r_day, 1, DAYSPERNYEAR);
00512    } else if (*strp == 'M') {
00513       /*
00514       ** Month, week, day.
00515       */
00516       rulep->r_type = MONTH_NTH_DAY_OF_WEEK;
00517       ++strp;
00518       strp = getnum(strp, &rulep->r_mon, 1, MONSPERYEAR);
00519       if (strp == NULL)
00520          return NULL;
00521       if (*strp++ != '.')
00522          return NULL;
00523       strp = getnum(strp, &rulep->r_week, 1, 5);
00524       if (strp == NULL)
00525          return NULL;
00526       if (*strp++ != '.')
00527          return NULL;
00528       strp = getnum(strp, &rulep->r_day, 0, DAYSPERWEEK - 1);
00529    } else if (is_digit(*strp)) {
00530       /*
00531       ** Day of year.
00532       */
00533       rulep->r_type = DAY_OF_YEAR;
00534       strp = getnum(strp, &rulep->r_day, 0, DAYSPERLYEAR - 1);
00535    } else   return NULL;      /* invalid format */
00536    if (strp == NULL)
00537       return NULL;
00538    if (*strp == '/') {
00539       /*
00540       ** Time specified.
00541       */
00542       ++strp;
00543       strp = getsecs(strp, &rulep->r_time);
00544    } else   rulep->r_time = 2 * SECSPERHOUR; /* default = 2:00:00 */
00545    return strp;
00546 }
00547 
00548 /*! \brief
00549  * Given the Epoch-relative time of January 1, 00:00:00 GMT, in a year, the
00550  * year, a rule, and the offset from GMT at the time that rule takes effect,
00551  * calculate the Epoch-relative time that rule takes effect.
00552 */
00553 
00554 static time_t transtime(janfirst, year, rulep, offset)
00555 const time_t            janfirst;
00556 const int            year;
00557 register const struct rule * const  rulep;
00558 const long           offset;
00559 {
00560    register int   leapyear;
00561    register time_t   value = 0;
00562    register int   i;
00563    int      d, m1, yy0, yy1, yy2, dow;
00564 
00565    leapyear = isleap(year);
00566    switch (rulep->r_type) {
00567 
00568    case JULIAN_DAY:
00569       /*
00570       ** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap
00571       ** years.
00572       ** In non-leap years, or if the day number is 59 or less, just
00573       ** add SECSPERDAY times the day number-1 to the time of
00574       ** January 1, midnight, to get the day.
00575       */
00576       value = janfirst + (rulep->r_day - 1) * SECSPERDAY;
00577       if (leapyear && rulep->r_day >= 60)
00578          value += SECSPERDAY;
00579       break;
00580 
00581    case DAY_OF_YEAR:
00582       /*
00583       ** n - day of year.
00584       ** Just add SECSPERDAY times the day number to the time of
00585       ** January 1, midnight, to get the day.
00586       */
00587       value = janfirst + rulep->r_day * SECSPERDAY;
00588       break;
00589 
00590    case MONTH_NTH_DAY_OF_WEEK:
00591       /*
00592       ** Mm.n.d - nth "dth day" of month m.
00593       */
00594       value = janfirst;
00595       for (i = 0; i < rulep->r_mon - 1; ++i)
00596          value += mon_lengths[leapyear][i] * SECSPERDAY;
00597 
00598       /*
00599       ** Use Zeller's Congruence to get day-of-week of first day of
00600       ** month.
00601       */
00602       m1 = (rulep->r_mon + 9) % 12 + 1;
00603       yy0 = (rulep->r_mon <= 2) ? (year - 1) : year;
00604       yy1 = yy0 / 100;
00605       yy2 = yy0 % 100;
00606       dow = ((26 * m1 - 2) / 10 +
00607          1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7;
00608       if (dow < 0)
00609          dow += DAYSPERWEEK;
00610 
00611       /*
00612       ** "dow" is the day-of-week of the first day of the month.  Get
00613       ** the day-of-month (zero-origin) of the first "dow" day of the
00614       ** month.
00615       */
00616       d = rulep->r_day - dow;
00617       if (d < 0)
00618          d += DAYSPERWEEK;
00619       for (i = 1; i < rulep->r_week; ++i) {
00620          if (d + DAYSPERWEEK >=
00621             mon_lengths[leapyear][rulep->r_mon - 1])
00622                break;
00623          d += DAYSPERWEEK;
00624       }
00625 
00626       /*
00627       ** "d" is the day-of-month (zero-origin) of the day we want.
00628       */
00629       value += d * SECSPERDAY;
00630       break;
00631    }
00632 
00633    /*
00634    ** "value" is the Epoch-relative time of 00:00:00 GMT on the day in
00635    ** question.  To get the Epoch-relative time of the specified local
00636    ** time on that day, add the transition time and the current offset
00637    ** from GMT.
00638    */
00639    return value + rulep->r_time + offset;
00640 }
00641 
00642 /*
00643 ** Given a POSIX section 8-style TZ string, fill in the rule tables as
00644 ** appropriate.
00645 */
00646 
00647 static int
00648 tzparse(name, sp, lastditch)
00649 const char *         name;
00650 register struct state * const sp;
00651 const int         lastditch;
00652 {
00653    const char *         stdname;
00654    const char *         dstname = NULL;
00655    size_t            stdlen = 0;
00656    size_t            dstlen = 0;
00657    long           stdoffset = 0L;
00658    long           dstoffset = 0L;
00659    register time_t *    atp;
00660    register unsigned char *   typep;
00661    register char *         cp;
00662    register int         load_result;
00663 
00664    stdname = name;
00665 #ifdef DEBUG
00666    fprintf(stderr, "tzparse(): loading default rules\n");
00667 #endif
00668    load_result = tzload(TZDEFRULES, sp);
00669    if (load_result != 0)
00670       sp->leapcnt = 0;     /* so, we're off a little */
00671    if (*name != '\0') {
00672       if (*name != '\0' && *name != ',' && *name != ';') {
00673          name = getoffset(name, &dstoffset);
00674          if (name == NULL)
00675             return -1;
00676       } else   dstoffset = stdoffset - SECSPERHOUR;
00677       if (*name == ',' || *name == ';') {
00678          struct rule start;
00679          struct rule end;
00680          register int   year;
00681          register time_t   janfirst;
00682          time_t      starttime;
00683          time_t      endtime;
00684 
00685          ++name;
00686          if ((name = getrule(name, &start)) == NULL)
00687             return -1;
00688          if (*name++ != ',')
00689             return -1;
00690          if ((name = getrule(name, &end)) == NULL)
00691             return -1;
00692          if (*name != '\0')
00693             return -1;
00694          sp->typecnt = 2;  /* standard time and DST */
00695          /*
00696          ** Two transitions per year, from EPOCH_YEAR to 2037.
00697          */
00698          sp->timecnt = 2 * (2037 - EPOCH_YEAR + 1);
00699          if (sp->timecnt > TZ_MAX_TIMES)
00700             return -1;
00701          sp->ttis[0].tt_gmtoff = -dstoffset;
00702          sp->ttis[0].tt_isdst = 1;
00703          sp->ttis[0].tt_abbrind = stdlen + 1;
00704          sp->ttis[1].tt_gmtoff = -stdoffset;
00705          sp->ttis[1].tt_isdst = 0;
00706          sp->ttis[1].tt_abbrind = 0;
00707          atp = sp->ats;
00708          typep = sp->types;
00709          janfirst = 0;
00710          for (year = EPOCH_YEAR; year <= 2037; ++year) {
00711             starttime = transtime(janfirst, year, &start,
00712                stdoffset);
00713             endtime = transtime(janfirst, year, &end,
00714                dstoffset);
00715             if (starttime > endtime) {
00716                *atp++ = endtime;
00717                *typep++ = 1;  /* DST ends */
00718                *atp++ = starttime;
00719                *typep++ = 0;  /* DST begins */
00720             } else {
00721                *atp++ = starttime;
00722                *typep++ = 0;  /* DST begins */
00723                *atp++ = endtime;
00724                *typep++ = 1;  /* DST ends */
00725             }
00726             janfirst += year_lengths[isleap(year)] *
00727                SECSPERDAY;
00728          }
00729       } else {
00730          register long  theirstdoffset;
00731          register long  theirdstoffset;
00732          register long  theiroffset;
00733          register int   isdst;
00734          register int   i;
00735          register int   j;
00736 
00737          if (*name != '\0')
00738             return -1;
00739          if (load_result != 0)
00740             return -1;
00741          /*
00742          ** Initial values of theirstdoffset and theirdstoffset.
00743          */
00744          theirstdoffset = 0;
00745          for (i = 0; i < sp->timecnt; ++i) {
00746             j = sp->types[i];
00747             if (!sp->ttis[j].tt_isdst) {
00748                theirstdoffset =
00749                   -sp->ttis[j].tt_gmtoff;
00750                break;
00751             }
00752          }
00753          theirdstoffset = 0;
00754          for (i = 0; i < sp->timecnt; ++i) {
00755             j = sp->types[i];
00756             if (sp->ttis[j].tt_isdst) {
00757                theirdstoffset =
00758                   -sp->ttis[j].tt_gmtoff;
00759                break;
00760             }
00761          }
00762          /*
00763          ** Initially we're assumed to be in standard time.
00764          */
00765          isdst = FALSE;
00766          theiroffset = theirstdoffset;
00767          /*
00768          ** Now juggle transition times and types
00769          ** tracking offsets as you do.
00770          */
00771          for (i = 0; i < sp->timecnt; ++i) {
00772             j = sp->types[i];
00773             sp->types[i] = sp->ttis[j].tt_isdst;
00774             if (sp->ttis[j].tt_ttisgmt) {
00775                /* No adjustment to transition time */
00776             } else {
00777                /*
00778                ** If summer time is in effect, and the
00779                ** transition time was not specified as
00780                ** standard time, add the summer time
00781                ** offset to the transition time;
00782                ** otherwise, add the standard time
00783                ** offset to the transition time.
00784                */
00785                /*
00786                ** Transitions from DST to DDST
00787                ** will effectively disappear since
00788                ** POSIX provides for only one DST
00789                ** offset.
00790                */
00791                if (isdst && !sp->ttis[j].tt_ttisstd) {
00792                   sp->ats[i] += dstoffset -
00793                      theirdstoffset;
00794                } else {
00795                   sp->ats[i] += stdoffset -
00796                      theirstdoffset;
00797                }
00798             }
00799             theiroffset = -sp->ttis[j].tt_gmtoff;
00800             if (sp->ttis[j].tt_isdst)
00801                theirdstoffset = theiroffset;
00802             else  theirstdoffset = theiroffset;
00803          }
00804          /*
00805          ** Finally, fill in ttis.
00806          ** ttisstd and ttisgmt need not be handled.
00807          */
00808          sp->ttis[0].tt_gmtoff = -stdoffset;
00809          sp->ttis[0].tt_isdst = FALSE;
00810          sp->ttis[0].tt_abbrind = 0;
00811          sp->ttis[1].tt_gmtoff = -dstoffset;
00812          sp->ttis[1].tt_isdst = TRUE;
00813          sp->ttis[1].tt_abbrind = stdlen + 1;
00814       }
00815    } else {
00816       dstlen = 0;
00817       sp->typecnt = 1;     /* only standard time */
00818       sp->timecnt = 0;
00819       sp->ttis[0].tt_gmtoff = -stdoffset;
00820       sp->ttis[0].tt_isdst = 0;
00821       sp->ttis[0].tt_abbrind = 0;
00822    }
00823    sp->charcnt = stdlen + 1;
00824    if (dstlen != 0)
00825       sp->charcnt += dstlen + 1;
00826    if (sp->charcnt > sizeof sp->chars)
00827       return -1;
00828    cp = sp->chars;
00829    (void) strncpy(cp, stdname, stdlen);
00830    cp += stdlen;
00831    *cp++ = '\0';
00832    if (dstlen != 0) {
00833       (void) strncpy(cp, dstname, dstlen);
00834       *(cp + dstlen) = '\0';
00835    }
00836    return 0;
00837 }
00838 
00839 static void
00840 gmtload(sp)
00841 struct state * const sp;
00842 {
00843    if (tzload(gmt, sp) != 0)
00844       (void) tzparse(gmt, sp, TRUE);
00845 }
00846 
00847 /*
00848 ** A non-static declaration of ast_tzsetwall in a system header file
00849 ** may cause a warning about this upcoming static declaration...
00850 */
00851 static
00852 #ifdef   _THREAD_SAFE
00853 int
00854 ast_tzsetwall_basic P((void))
00855 #else
00856 int
00857 ast_tzsetwall P((void))
00858 #endif
00859 {
00860    struct state *cur_state = lclptr;
00861 
00862    /* Find the appropriate structure, if already parsed */
00863    while (cur_state != NULL) {
00864       if (cur_state->name[0] == '\0')
00865          break;
00866       cur_state = cur_state->next;
00867    }
00868    if (cur_state != NULL)
00869       return 0;
00870    cur_state = malloc(sizeof(struct state));
00871    if (cur_state == NULL) {
00872       return -1;
00873    }
00874    memset(cur_state,0,sizeof(struct state));
00875    if (tzload((char *) NULL, cur_state) != 0)
00876 #ifdef DEBUG
00877    {
00878       fprintf(stderr, "ast_tzsetwall: calling gmtload()\n");
00879 #endif
00880       gmtload(cur_state);
00881 #ifdef DEBUG
00882    }
00883 #endif
00884 
00885    if (last_lclptr)
00886       last_lclptr->next = cur_state;
00887    else
00888       lclptr = cur_state;
00889    last_lclptr = cur_state;
00890    return 0;
00891 }
00892 
00893 #ifdef   _THREAD_SAFE
00894 int
00895 ast_tzsetwall P((void))
00896 {
00897    ast_mutex_lock(&tzsetwall_mutex);
00898    ast_tzsetwall_basic();
00899    ast_mutex_unlock(&tzsetwall_mutex);
00900    return 0;
00901 }
00902 #endif
00903 
00904 #ifdef   _THREAD_SAFE
00905 static int
00906 ast_tzset_basic P((const char *name))
00907 #else
00908 int
00909 ast_tzset P((const char *name))
00910 #endif
00911 {
00912    struct state *cur_state = lclptr;
00913 
00914    /* Not set at all */
00915    if (name == NULL) {
00916       return ast_tzsetwall();
00917    }
00918 
00919    /* Find the appropriate structure, if already parsed */
00920    while (cur_state != NULL) {
00921       if (!strcmp(cur_state->name,name))
00922          break;
00923       cur_state = cur_state->next;
00924    }
00925    if (cur_state != NULL)
00926       return 0;
00927 
00928    cur_state = malloc(sizeof(struct state));
00929    if (cur_state == NULL) {
00930       return -1;
00931    }
00932    memset(cur_state,0,sizeof(*cur_state));
00933 
00934    /* Name is set, but set to the empty string == no adjustments */
00935    if (name[0] == '\0') {
00936       /*
00937       ** User wants it fast rather than right.
00938       */
00939       cur_state->leapcnt = 0;    /* so, we're off a little */
00940       cur_state->timecnt = 0;
00941       cur_state->ttis[0].tt_gmtoff = 0;
00942       cur_state->ttis[0].tt_abbrind = 0;
00943       (void) strncpy(cur_state->chars, gmt, sizeof(cur_state->chars) - 1);
00944    } else if (tzload(name, cur_state) != 0) {
00945       if (name[0] == ':') {
00946          (void) gmtload(cur_state);
00947       } else if (tzparse(name, cur_state, FALSE) != 0) {
00948          /* If not found, load localtime */
00949          if (tzload("/etc/localtime", cur_state) != 0)
00950             /* Last ditch, get GMT */
00951             (void) gmtload(cur_state);
00952       }
00953    }
00954    strncpy(cur_state->name, name, sizeof(cur_state->name) - 1);
00955    if (last_lclptr)
00956       last_lclptr->next = cur_state;
00957    else
00958       lclptr = cur_state;
00959    last_lclptr = cur_state;
00960    return 0;
00961 }
00962 
00963 #ifdef   _THREAD_SAFE
00964 void
00965 ast_tzset P((const char *name))
00966 {
00967    ast_mutex_lock(&tzset_mutex);
00968    ast_tzset_basic(name);
00969    ast_mutex_unlock(&tzset_mutex);
00970 }
00971 #endif
00972 
00973 /*
00974 ** The easy way to behave "as if no library function calls" localtime
00975 ** is to not call it--so we drop its guts into "localsub", which can be
00976 ** freely called.  (And no, the PANS doesn't require the above behavior--
00977 ** but it *is* desirable.)
00978 **
00979 ** The unused offset argument is for the benefit of mktime variants.
00980 */
00981 
00982 /*ARGSUSED*/
00983 static void
00984 localsub(timep, offset, tmp, zone)
00985 const time_t * const timep;
00986 const long     offset;
00987 struct tm * const tmp;
00988 const char * const   zone;
00989 {
00990    register struct state *    sp;
00991    register const struct ttinfo *   ttisp;
00992    register int         i;
00993    const time_t         t = *timep;
00994 
00995    sp = lclptr;
00996    /* Find the right zone record */
00997    if (zone == NULL)
00998       sp = NULL;
00999    else
01000       while (sp != NULL) {
01001          if (!strcmp(sp->name,zone))
01002             break;
01003          sp = sp->next;
01004       }
01005 
01006    if (sp == NULL) {
01007       ast_tzsetwall();
01008       sp = lclptr;
01009       /* Find the default zone record */
01010       while (sp != NULL) {
01011          if (sp->name[0] == '\0')
01012             break;
01013          sp = sp->next;
01014       }
01015    }
01016 
01017    /* Last ditch effort, use GMT */
01018    if (sp == NULL) {
01019       gmtsub(timep, offset, tmp, zone);
01020       return;
01021    }
01022    if (sp->timecnt == 0 || t < sp->ats[0]) {
01023       i = 0;
01024       while (sp->ttis[i].tt_isdst)
01025          if (++i >= sp->typecnt) {
01026             i = 0;
01027             break;
01028          }
01029    } else {
01030       for (i = 1; i < sp->timecnt; ++i)
01031          if (t < sp->ats[i])
01032             break;
01033       i = sp->types[i - 1];
01034    }
01035    ttisp = &sp->ttis[i];
01036    /*
01037    ** To get (wrong) behavior that's compatible with System V Release 2.0
01038    ** you'd replace the statement below with
01039    ** t += ttisp->tt_gmtoff;
01040    ** timesub(&t, 0L, sp, tmp);
01041    */
01042    timesub(&t, ttisp->tt_gmtoff, sp, tmp);
01043    tmp->tm_isdst = ttisp->tt_isdst;
01044    tzname[tmp->tm_isdst] = &sp->chars[ttisp->tt_abbrind];
01045 #ifdef TM_ZONE
01046    tmp->TM_ZONE = &sp->chars[ttisp->tt_abbrind];
01047 #endif /* defined TM_ZONE */
01048 }
01049 
01050 struct tm *
01051 ast_localtime(timep, p_tm, zone)
01052 const time_t * const timep;
01053 struct tm *p_tm;
01054 const char * const   zone;
01055 {
01056 #ifdef _THREAD_SAFE
01057    ast_mutex_lock(&lcl_mutex);
01058 #endif
01059    ast_tzset(ast_strlen_zero(zone) ? "/etc/localtime" : zone);
01060    localsub(timep, 0L, p_tm, zone);
01061 #ifdef _THREAD_SAFE
01062    ast_mutex_unlock(&lcl_mutex);
01063 #endif
01064    return(p_tm);
01065 }
01066 
01067 /*
01068 ** gmtsub is to gmtime as localsub is to localtime.
01069 */
01070 
01071 static void
01072 gmtsub(timep, offset, tmp, zone)
01073 const time_t * const timep;
01074 const long     offset;
01075 struct tm * const tmp;
01076 const char * const   zone;
01077 {
01078 #ifdef   _THREAD_SAFE
01079    ast_mutex_lock(&gmt_mutex);
01080 #endif
01081    if (!gmt_is_set) {
01082       gmt_is_set = TRUE;
01083       gmtptr = (struct state *) malloc(sizeof *gmtptr);
01084       if (gmtptr != NULL)
01085          gmtload(gmtptr);
01086    }
01087    ast_mutex_unlock(&gmt_mutex);
01088    timesub(timep, offset, gmtptr, tmp);
01089 #ifdef TM_ZONE
01090    /*
01091    ** Could get fancy here and deliver something such as
01092    ** "GMT+xxxx" or "GMT-xxxx" if offset is non-zero,
01093    ** but this is no time for a treasure hunt.
01094    */
01095    if (offset != 0)
01096       tmp->TM_ZONE = wildabbr;
01097    else {
01098       if (gmtptr == NULL)
01099          tmp->TM_ZONE = gmt;
01100       else  tmp->TM_ZONE = gmtptr->chars;
01101    }
01102 #endif /* defined TM_ZONE */
01103 }
01104 
01105 static void
01106 timesub(timep, offset, sp, tmp)
01107 const time_t * const       timep;
01108 const long           offset;
01109 register const struct state * const sp;
01110 register struct tm * const    tmp;
01111 {
01112    register const struct lsinfo *   lp;
01113    register long        days;
01114    register long        rem;
01115    register int         y;
01116    register int         yleap;
01117    register const int *    ip;
01118    register long        corr;
01119    register int         hit;
01120    register int         i;
01121 
01122    corr = 0;
01123    hit = 0;
01124    i = (sp == NULL) ? 0 : sp->leapcnt;
01125    while (--i >= 0) {
01126       lp = &sp->lsis[i];
01127       if (*timep >= lp->ls_trans) {
01128          if (*timep == lp->ls_trans) {
01129             hit = ((i == 0 && lp->ls_corr > 0) ||
01130                lp->ls_corr > sp->lsis[i - 1].ls_corr);
01131             if (hit)
01132                while (i > 0 &&
01133                   sp->lsis[i].ls_trans ==
01134                   sp->lsis[i - 1].ls_trans + 1 &&
01135                   sp->lsis[i].ls_corr ==
01136                   sp->lsis[i - 1].ls_corr + 1) {
01137                      ++hit;
01138                      --i;
01139                }
01140          }
01141          corr = lp->ls_corr;
01142          break;
01143       }
01144    }
01145    days = *timep / SECSPERDAY;
01146    rem = *timep % SECSPERDAY;
01147 #ifdef mc68k
01148    if (*timep == 0x80000000) {
01149       /*
01150       ** A 3B1 muffs the division on the most negative number.
01151       */
01152       days = -24855;
01153       rem = -11648;
01154    }
01155 #endif /* defined mc68k */
01156    rem += (offset - corr);
01157    while (rem < 0) {
01158       rem += SECSPERDAY;
01159       --days;
01160    }
01161    while (rem >= SECSPERDAY) {
01162       rem -= SECSPERDAY;
01163       ++days;
01164    }
01165    tmp->tm_hour = (int) (rem / SECSPERHOUR);
01166    rem = rem % SECSPERHOUR;
01167    tmp->tm_min = (int) (rem / SECSPERMIN);
01168    /*
01169    ** A positive leap second requires a special
01170    ** representation.  This uses "... ??:59:60" et seq.
01171    */
01172    tmp->tm_sec = (int) (rem % SECSPERMIN) + hit;
01173    tmp->tm_wday = (int) ((EPOCH_WDAY + days) % DAYSPERWEEK);
01174    if (tmp->tm_wday < 0)
01175       tmp->tm_wday += DAYSPERWEEK;
01176    y = EPOCH_YEAR;
01177 #define LEAPS_THRU_END_OF(y)  ((y) / 4 - (y) / 100 + (y) / 400)
01178    while (days < 0 || days >= (long) year_lengths[yleap = isleap(y)]) {
01179       register int   newy;
01180 
01181       newy = y + days / DAYSPERNYEAR;
01182       if (days < 0)
01183          --newy;
01184       days -= (newy - y) * DAYSPERNYEAR +
01185          LEAPS_THRU_END_OF(newy - 1) -
01186          LEAPS_THRU_END_OF(y - 1);
01187       y = newy;
01188    }
01189    tmp->tm_year = y - TM_YEAR_BASE;
01190    tmp->tm_yday = (int) days;
01191    ip = mon_lengths[yleap];
01192    for (tmp->tm_mon = 0; days >= (long) ip[tmp->tm_mon]; ++(tmp->tm_mon))
01193       days = days - (long) ip[tmp->tm_mon];
01194    tmp->tm_mday = (int) (days + 1);
01195    tmp->tm_isdst = 0;
01196 #ifdef TM_GMTOFF
01197    tmp->TM_GMTOFF = offset;
01198 #endif /* defined TM_GMTOFF */
01199 }
01200 
01201 char *
01202 ast_ctime(timep)
01203 const time_t * const timep;
01204 {
01205 /*
01206 ** Section 4.12.3.2 of X3.159-1989 requires that
01207 ** The ctime funciton converts the calendar time pointed to by timer
01208 ** to local time in the form of a string.  It is equivalent to
01209 **    asctime(localtime(timer))
01210 */
01211    return asctime(localtime(timep));
01212 }
01213 
01214 char *
01215 ast_ctime_r(timep, buf)
01216 const time_t * const timep;
01217 char *buf;
01218 {
01219         struct tm tm;
01220    return asctime_r(localtime_r(timep, &tm), buf);
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 

Generated on Fri Aug 24 02:22:16 2007 for Asterisk - the Open Source PBX by  doxygen 1.5.1