Wed Oct 28 15:47:54 2009

Asterisk developer's documentation


localtime.c

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

Generated on Wed Oct 28 15:47:54 2009 for Asterisk - the Open Source PBX by  doxygen 1.5.6