Fri May 26 01:45:34 2006

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

Generated on Fri May 26 01:45:34 2006 for Asterisk - the Open Source PBX by  doxygen 1.4.6