Wed Aug 18 22:33:53 2010

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  * The original source from this file may be obtained from ftp://elsie.nci.nih.gov/pub/
00031  */
00032 
00033 /*
00034 ** This file is in the public domain, so clarified as of
00035 ** 1996-06-05 by Arthur David Olson.
00036 */
00037 
00038 /*
00039 ** Leap second handling from Bradley White.
00040 ** POSIX-style TZ environment variable handling from Guy Harris.
00041 */
00042 
00043 /* #define DEBUG */
00044 
00045 /*LINTLIBRARY*/
00046 
00047 #include "asterisk.h"
00048 
00049 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 253624 $")
00050 
00051 #include <signal.h>
00052 #include <sys/stat.h>
00053 #include <fcntl.h>
00054 #include <float.h>
00055 
00056 #include "private.h"
00057 #include "tzfile.h"
00058 
00059 #include "asterisk/lock.h"
00060 #include "asterisk/localtime.h"
00061 #include "asterisk/strings.h"
00062 #include "asterisk/linkedlists.h"
00063 #include "asterisk/utils.h"
00064 
00065 #ifndef lint
00066 #ifndef NOID
00067 static char __attribute__((unused)) elsieid[] = "@(#)localtime.c  8.5";
00068 #endif /* !defined NOID */
00069 #endif /* !defined lint */
00070 
00071 #ifndef TZ_ABBR_MAX_LEN
00072 #define TZ_ABBR_MAX_LEN 16
00073 #endif /* !defined TZ_ABBR_MAX_LEN */
00074 
00075 #ifndef TZ_ABBR_CHAR_SET
00076 #define TZ_ABBR_CHAR_SET \
00077    "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 :+-._"
00078 #endif /* !defined TZ_ABBR_CHAR_SET */
00079 
00080 #ifndef TZ_ABBR_ERR_CHAR
00081 #define TZ_ABBR_ERR_CHAR   '_'
00082 #endif /* !defined TZ_ABBR_ERR_CHAR */
00083 
00084 /*
00085 ** SunOS 4.1.1 headers lack O_BINARY.
00086 */
00087 
00088 #ifdef O_BINARY
00089 #define OPEN_MODE (O_RDONLY | O_BINARY)
00090 #endif /* defined O_BINARY */
00091 #ifndef O_BINARY
00092 #define OPEN_MODE O_RDONLY
00093 #endif /* !defined O_BINARY */
00094 
00095 static const char gmt[] = "GMT";
00096 static const struct timeval WRONG = { 0, 0 };
00097 
00098 /*! \note
00099  * The DST rules to use if TZ has no rules and we can't load TZDEFRULES.
00100  * We default to US rules as of 1999-08-17.
00101  * POSIX 1003.1 section 8.1.1 says that the default DST rules are
00102  * implementation dependent; for historical reasons, US rules are a
00103  * common default.
00104  */
00105 #ifndef TZDEFRULESTRING
00106 #define TZDEFRULESTRING ",M4.1.0,M10.5.0"
00107 #endif /* !defined TZDEFDST */
00108 
00109 /*!< \brief time type information */
00110 struct ttinfo {            /* time type information */
00111    long     tt_gmtoff;  /* UTC offset in seconds */
00112    int      tt_isdst;   /* used to set tm_isdst */
00113    int      tt_abbrind; /* abbreviation list index */
00114    int      tt_ttisstd; /* TRUE if transition is std time */
00115    int      tt_ttisgmt; /* TRUE if transition is UTC */
00116 };
00117 
00118 /*! \brief leap second information */
00119 struct lsinfo {            /* leap second information */
00120    time_t      ls_trans;   /* transition time */
00121    long     ls_corr; /* correction to apply */
00122 };
00123 
00124 #define BIGGEST(a, b)   (((a) > (b)) ? (a) : (b))
00125 
00126 #ifdef TZNAME_MAX
00127 #define MY_TZNAME_MAX   TZNAME_MAX
00128 #endif /* defined TZNAME_MAX */
00129 #ifndef TZNAME_MAX
00130 #define MY_TZNAME_MAX   255
00131 #endif /* !defined TZNAME_MAX */
00132 #ifndef TZ_STRLEN_MAX
00133 #define TZ_STRLEN_MAX   255
00134 #endif /* !defined TZ_STRLEN_MAX */
00135 
00136 struct state {
00137    /*! Name of the file that this references */
00138    char    name[TZ_STRLEN_MAX + 1];
00139    int      leapcnt;
00140    int      timecnt;
00141    int      typecnt;
00142    int      charcnt;
00143    int      goback;
00144    int      goahead;
00145    time_t      ats[TZ_MAX_TIMES];
00146    unsigned char  types[TZ_MAX_TIMES];
00147    struct ttinfo  ttis[TZ_MAX_TYPES];
00148    char     chars[BIGGEST(BIGGEST(TZ_MAX_CHARS + 1, sizeof gmt),
00149             (2 * (MY_TZNAME_MAX + 1)))];
00150    struct lsinfo  lsis[TZ_MAX_LEAPS];
00151    AST_LIST_ENTRY(state) list;
00152 };
00153 
00154 struct rule {
00155    int      r_type;     /* type of rule--see below */
00156    int      r_day;      /* day number of rule */
00157    int      r_week;     /* week number of rule */
00158    int      r_mon;      /* month number of rule */
00159    long     r_time;     /* transition time of rule */
00160 };
00161 
00162 #define JULIAN_DAY      0  /* Jn - Julian day */
00163 #define DAY_OF_YEAR     1  /* n - day of year */
00164 #define MONTH_NTH_DAY_OF_WEEK 2  /* Mm.n.d - month, week, day of week */
00165 
00166 /*
00167 ** Prototypes for static functions.
00168 */
00169 
00170 static long    detzcode P((const char * codep));
00171 static time_t     detzcode64 P((const char * codep));
00172 static int     differ_by_repeat P((time_t t1, time_t t0));
00173 static const char *  getzname P((const char * strp));
00174 static const char *  getqzname P((const char * strp, const int delim));
00175 static const char *  getnum P((const char * strp, int * nump, int min,
00176             int max));
00177 static const char *  getsecs P((const char * strp, long * secsp));
00178 static const char *  getoffset P((const char * strp, long * offsetp));
00179 static const char *  getrule P((const char * strp, struct rule * rulep));
00180 static int     gmtload P((struct state * sp));
00181 static struct ast_tm *  gmtsub P((const struct timeval * timep, long offset,
00182             struct ast_tm * tmp));
00183 static struct ast_tm *  localsub P((const struct timeval * timep, long offset,
00184             struct ast_tm * tmp, const struct state *sp));
00185 static int     increment_overflow P((int * number, int delta));
00186 static int     leaps_thru_end_of P((int y));
00187 static int     long_increment_overflow P((long * number, int delta));
00188 static int     long_normalize_overflow P((long * tensptr,
00189             int * unitsptr, const int base));
00190 static int     normalize_overflow P((int * tensptr, int * unitsptr,
00191             const int base));
00192 static struct timeval   time1 P((struct ast_tm * tmp,
00193             struct ast_tm * (*funcp) P((const struct timeval *,
00194             long, struct ast_tm *, const struct state *sp)),
00195             long offset, const struct state *sp));
00196 static struct timeval   time2 P((struct ast_tm *tmp,
00197             struct ast_tm * (*funcp) P((const struct timeval *,
00198             long, struct ast_tm*, const struct state *sp)),
00199             long offset, int * okayp, const struct state *sp));
00200 static struct timeval   time2sub P((struct ast_tm *tmp,
00201             struct ast_tm * (*funcp) (const struct timeval *,
00202             long, struct ast_tm*, const struct state *sp),
00203             long offset, int * okayp, int do_norm_secs, const struct state *sp));
00204 static struct ast_tm *  timesub P((const struct timeval * timep, long offset,
00205             const struct state * sp, struct ast_tm * tmp));
00206 static int     tmcomp P((const struct ast_tm * atmp,
00207             const struct ast_tm * btmp));
00208 static time_t     transtime P((time_t janfirst, int year,
00209             const struct rule * rulep, long offset));
00210 static int     tzload P((const char * name, struct state * sp,
00211             int doextend));
00212 static int     tzparse P((const char * name, struct state * sp,
00213             int lastditch));
00214 
00215 static AST_LIST_HEAD_STATIC(zonelist, state);
00216 
00217 #ifndef TZ_STRLEN_MAX
00218 #define TZ_STRLEN_MAX 255
00219 #endif /* !defined TZ_STRLEN_MAX */
00220 
00221 /*! \note
00222 ** Section 4.12.3 of X3.159-1989 requires that
00223 ** Except for the strftime function, these functions [asctime,
00224 ** ctime, gmtime, localtime] return values in one of two static
00225 ** objects: a broken-down time structure and an array of char.
00226 ** Thanks to Paul Eggert for noting this.
00227 */
00228 
00229 static long detzcode(const char * const codep)
00230 {
00231    long  result;
00232    int   i;
00233 
00234    result = (codep[0] & 0x80) ? ~0L : 0;
00235    for (i = 0; i < 4; ++i)
00236       result = (result << 8) | (codep[i] & 0xff);
00237    return result;
00238 }
00239 
00240 static time_t detzcode64(const char * const codep)
00241 {
00242    time_t   result;
00243    int   i;
00244 
00245    result = (codep[0] & 0x80) ?  (~(int_fast64_t) 0) : 0;
00246    for (i = 0; i < 8; ++i)
00247       result = result * 256 + (codep[i] & 0xff);
00248    return result;
00249 }
00250 
00251 static int differ_by_repeat(const time_t t1, const time_t t0)
00252 {
00253    const long long at1 = t1, at0 = t0;
00254    if (TYPE_INTEGRAL(time_t) &&
00255       TYPE_BIT(time_t) - TYPE_SIGNED(time_t) < SECSPERREPEAT_BITS)
00256          return 0;
00257    return at1 - at0 == SECSPERREPEAT;
00258 }
00259 
00260 static int tzload(const char *name, struct state * const sp, const int doextend)
00261 {
00262    const char *      p;
00263    int         i;
00264    int         fid;
00265    int         stored;
00266    int         nread;
00267    union {
00268       struct tzhead  tzhead;
00269       char     buf[2 * sizeof(struct tzhead) +
00270                2 * sizeof *sp +
00271                4 * TZ_MAX_TIMES];
00272    } u;
00273 
00274    if (name == NULL && (name = TZDEFAULT) == NULL)
00275       return -1;
00276    {
00277       int   doaccess;
00278       /*
00279       ** Section 4.9.1 of the C standard says that
00280       ** "FILENAME_MAX expands to an integral constant expression
00281       ** that is the size needed for an array of char large enough
00282       ** to hold the longest file name string that the implementation
00283       ** guarantees can be opened."
00284       */
00285       char     fullname[FILENAME_MAX + 1];
00286 
00287       if (name[0] == ':')
00288          ++name;
00289       doaccess = name[0] == '/';
00290       if (!doaccess) {
00291          if ((p = TZDIR) == NULL)
00292             return -1;
00293          if ((strlen(p) + strlen(name) + 1) >= sizeof fullname)
00294             return -1;
00295          (void) strcpy(fullname, p);
00296          (void) strcat(fullname, "/");
00297          (void) strcat(fullname, name);
00298          /*
00299          ** Set doaccess if '.' (as in "../") shows up in name.
00300          */
00301          if (strchr(name, '.') != NULL)
00302             doaccess = TRUE;
00303          name = fullname;
00304       }
00305       if (doaccess && access(name, R_OK) != 0)
00306          return -1;
00307       if ((fid = open(name, OPEN_MODE)) == -1)
00308          return -1;
00309    }
00310    nread = read(fid, u.buf, sizeof u.buf);
00311    if (close(fid) < 0 || nread <= 0)
00312       return -1;
00313    for (stored = 4; stored <= 8; stored *= 2) {
00314       int      ttisstdcnt;
00315       int      ttisgmtcnt;
00316 
00317       ttisstdcnt = (int) detzcode(u.tzhead.tzh_ttisstdcnt);
00318       ttisgmtcnt = (int) detzcode(u.tzhead.tzh_ttisgmtcnt);
00319       sp->leapcnt = (int) detzcode(u.tzhead.tzh_leapcnt);
00320       sp->timecnt = (int) detzcode(u.tzhead.tzh_timecnt);
00321       sp->typecnt = (int) detzcode(u.tzhead.tzh_typecnt);
00322       sp->charcnt = (int) detzcode(u.tzhead.tzh_charcnt);
00323       p = u.tzhead.tzh_charcnt + sizeof u.tzhead.tzh_charcnt;
00324       if (sp->leapcnt < 0 || sp->leapcnt > TZ_MAX_LEAPS ||
00325          sp->typecnt <= 0 || sp->typecnt > TZ_MAX_TYPES ||
00326          sp->timecnt < 0 || sp->timecnt > TZ_MAX_TIMES ||
00327          sp->charcnt < 0 || sp->charcnt > TZ_MAX_CHARS ||
00328          (ttisstdcnt != sp->typecnt && ttisstdcnt != 0) ||
00329          (ttisgmtcnt != sp->typecnt && ttisgmtcnt != 0))
00330             return -1;
00331       if (nread - (p - u.buf) <
00332          sp->timecnt * stored +     /* ats */
00333          sp->timecnt +        /* types */
00334          sp->typecnt * 6 +    /* ttinfos */
00335          sp->charcnt +        /* chars */
00336          sp->leapcnt * (stored + 4) +  /* lsinfos */
00337          ttisstdcnt +         /* ttisstds */
00338          ttisgmtcnt)       /* ttisgmts */
00339             return -1;
00340       for (i = 0; i < sp->timecnt; ++i) {
00341          sp->ats[i] = (stored == 4) ?
00342             detzcode(p) : detzcode64(p);
00343          p += stored;
00344       }
00345       for (i = 0; i < sp->timecnt; ++i) {
00346          sp->types[i] = (unsigned char) *p++;
00347          if (sp->types[i] >= sp->typecnt)
00348             return -1;
00349       }
00350       for (i = 0; i < sp->typecnt; ++i) {
00351          struct ttinfo *   ttisp;
00352 
00353          ttisp = &sp->ttis[i];
00354          ttisp->tt_gmtoff = detzcode(p);
00355          p += 4;
00356          ttisp->tt_isdst = (unsigned char) *p++;
00357          if (ttisp->tt_isdst != 0 && ttisp->tt_isdst != 1)
00358             return -1;
00359          ttisp->tt_abbrind = (unsigned char) *p++;
00360          if (ttisp->tt_abbrind < 0 ||
00361             ttisp->tt_abbrind > sp->charcnt)
00362                return -1;
00363       }
00364       for (i = 0; i < sp->charcnt; ++i)
00365          sp->chars[i] = *p++;
00366       sp->chars[i] = '\0'; /* ensure '\0' at end */
00367       for (i = 0; i < sp->leapcnt; ++i) {
00368          struct lsinfo *   lsisp;
00369 
00370          lsisp = &sp->lsis[i];
00371          lsisp->ls_trans = (stored == 4) ?
00372             detzcode(p) : detzcode64(p);
00373          p += stored;
00374          lsisp->ls_corr = detzcode(p);
00375          p += 4;
00376       }
00377       for (i = 0; i < sp->typecnt; ++i) {
00378          struct ttinfo *   ttisp;
00379 
00380          ttisp = &sp->ttis[i];
00381          if (ttisstdcnt == 0)
00382             ttisp->tt_ttisstd = FALSE;
00383          else {
00384             ttisp->tt_ttisstd = *p++;
00385             if (ttisp->tt_ttisstd != TRUE &&
00386                ttisp->tt_ttisstd != FALSE)
00387                   return -1;
00388          }
00389       }
00390       for (i = 0; i < sp->typecnt; ++i) {
00391          struct ttinfo *   ttisp;
00392 
00393          ttisp = &sp->ttis[i];
00394          if (ttisgmtcnt == 0)
00395             ttisp->tt_ttisgmt = FALSE;
00396          else {
00397             ttisp->tt_ttisgmt = *p++;
00398             if (ttisp->tt_ttisgmt != TRUE &&
00399                ttisp->tt_ttisgmt != FALSE)
00400                   return -1;
00401          }
00402       }
00403       /*
00404       ** Out-of-sort ats should mean we're running on a
00405       ** signed time_t system but using a data file with
00406       ** unsigned values (or vice versa).
00407       */
00408       for (i = 0; i < sp->timecnt - 2; ++i)
00409          if (sp->ats[i] > sp->ats[i + 1]) {
00410             ++i;
00411             if (TYPE_SIGNED(time_t)) {
00412                /*
00413                ** Ignore the end (easy).
00414                */
00415                sp->timecnt = i;
00416             } else {
00417                /*
00418                ** Ignore the beginning (harder).
00419                */
00420                int   j;
00421 
00422                for (j = 0; j + i < sp->timecnt; ++j) {
00423                   sp->ats[j] = sp->ats[j + i];
00424                   sp->types[j] = sp->types[j + i];
00425                }
00426                sp->timecnt = j;
00427             }
00428             break;
00429          }
00430       /*
00431       ** If this is an old file, we're done.
00432       */
00433       if (u.tzhead.tzh_version[0] == '\0')
00434          break;
00435       nread -= p - u.buf;
00436       for (i = 0; i < nread; ++i)
00437          u.buf[i] = p[i];
00438       /*
00439       ** If this is a narrow integer time_t system, we're done.
00440       */
00441       if (stored >= (int) sizeof(time_t) && TYPE_INTEGRAL(time_t))
00442          break;
00443    }
00444    if (doextend && nread > 2 &&
00445       u.buf[0] == '\n' && u.buf[nread - 1] == '\n' &&
00446       sp->typecnt + 2 <= TZ_MAX_TYPES) {
00447          struct state   ts;
00448          int   result;
00449 
00450          u.buf[nread - 1] = '\0';
00451          result = tzparse(&u.buf[1], &ts, FALSE);
00452          if (result == 0 && ts.typecnt == 2 &&
00453             sp->charcnt + ts.charcnt <= TZ_MAX_CHARS) {
00454                for (i = 0; i < 2; ++i)
00455                   ts.ttis[i].tt_abbrind +=
00456                      sp->charcnt;
00457                for (i = 0; i < ts.charcnt; ++i)
00458                   sp->chars[sp->charcnt++] =
00459                      ts.chars[i];
00460                i = 0;
00461                while (i < ts.timecnt &&
00462                   ts.ats[i] <=
00463                   sp->ats[sp->timecnt - 1])
00464                      ++i;
00465                while (i < ts.timecnt &&
00466                    sp->timecnt < TZ_MAX_TIMES) {
00467                   sp->ats[sp->timecnt] =
00468                      ts.ats[i];
00469                   sp->types[sp->timecnt] =
00470                      sp->typecnt +
00471                      ts.types[i];
00472                   ++sp->timecnt;
00473                   ++i;
00474                }
00475                sp->ttis[sp->typecnt++] = ts.ttis[0];
00476                sp->ttis[sp->typecnt++] = ts.ttis[1];
00477          }
00478    }
00479    i = 2 * YEARSPERREPEAT;
00480    sp->goback = sp->goahead = sp->timecnt > i;
00481    sp->goback = sp->goback && sp->types[i] == sp->types[0] &&
00482       differ_by_repeat(sp->ats[i], sp->ats[0]);
00483    sp->goahead = sp->goahead &&
00484       sp->types[sp->timecnt - 1] == sp->types[sp->timecnt - 1 - i] &&
00485       differ_by_repeat(sp->ats[sp->timecnt - 1],
00486           sp->ats[sp->timecnt - 1 - i]);
00487    return 0;
00488 }
00489 
00490 static const int  mon_lengths[2][MONSPERYEAR] = {
00491    { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
00492    { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
00493 };
00494 
00495 static const int  year_lengths[2] = {
00496    DAYSPERNYEAR, DAYSPERLYEAR
00497 };
00498 
00499 /*! \brief
00500 ** Given a pointer into a time zone string, scan until a character that is not
00501 ** a valid character in a zone name is found. Return a pointer to that
00502 ** character.
00503 */
00504 
00505 static const char * getzname(const char *strp)
00506 {
00507    char  c;
00508 
00509    while ((c = *strp) != '\0' && !is_digit(c) && c != ',' && c != '-' &&
00510       c != '+')
00511          ++strp;
00512    return strp;
00513 }
00514 
00515 /*! \brief
00516 ** Given a pointer into an extended time zone string, scan until the ending
00517 ** delimiter of the zone name is located. Return a pointer to the delimiter.
00518 **
00519 ** As with getzname above, the legal character set is actually quite
00520 ** restricted, with other characters producing undefined results.
00521 ** We don't do any checking here; checking is done later in common-case code.
00522 */
00523 
00524 static const char * getqzname(const char *strp, const int delim)
00525 {
00526    int   c;
00527 
00528    while ((c = *strp) != '\0' && c != delim)
00529       ++strp;
00530    return strp;
00531 }
00532 
00533 /*! \brief
00534 ** Given a pointer into a time zone string, extract a number from that string.
00535 ** Check that the number is within a specified range; if it is not, return
00536 ** NULL.
00537 ** Otherwise, return a pointer to the first character not part of the number.
00538 */
00539 
00540 static const char *getnum(const char *strp, int *nump, const int min, const int max)
00541 {
00542    char  c;
00543    int   num;
00544 
00545    if (strp == NULL || !is_digit(c = *strp))
00546       return NULL;
00547    num = 0;
00548    do {
00549       num = num * 10 + (c - '0');
00550       if (num > max)
00551          return NULL;   /* illegal value */
00552       c = *++strp;
00553    } while (is_digit(c));
00554    if (num < min)
00555       return NULL;      /* illegal value */
00556    *nump = num;
00557    return strp;
00558 }
00559 
00560 /*! \brief
00561 ** Given a pointer into a time zone string, extract a number of seconds,
00562 ** in hh[:mm[:ss]] form, from the string.
00563 ** If any error occurs, return NULL.
00564 ** Otherwise, return a pointer to the first character not part of the number
00565 ** of seconds.
00566 */
00567 
00568 static const char *getsecs(const char *strp, long * const secsp)
00569 {
00570    int   num;
00571 
00572    /*
00573    ** `HOURSPERDAY * DAYSPERWEEK - 1' allows quasi-Posix rules like
00574    ** "M10.4.6/26", which does not conform to Posix,
00575    ** but which specifies the equivalent of
00576    ** ``02:00 on the first Sunday on or after 23 Oct''.
00577    */
00578    strp = getnum(strp, &num, 0, HOURSPERDAY * DAYSPERWEEK - 1);
00579    if (strp == NULL)
00580       return NULL;
00581    *secsp = num * (long) SECSPERHOUR;
00582    if (*strp == ':') {
00583       ++strp;
00584       strp = getnum(strp, &num, 0, MINSPERHOUR - 1);
00585       if (strp == NULL)
00586          return NULL;
00587       *secsp += num * SECSPERMIN;
00588       if (*strp == ':') {
00589          ++strp;
00590          /* `SECSPERMIN' allows for leap seconds. */
00591          strp = getnum(strp, &num, 0, SECSPERMIN);
00592          if (strp == NULL)
00593             return NULL;
00594          *secsp += num;
00595       }
00596    }
00597    return strp;
00598 }
00599 
00600 /*! \brief
00601 ** Given a pointer into a time zone string, extract an offset, in
00602 ** [+-]hh[:mm[:ss]] form, from the string.
00603 ** If any error occurs, return NULL.
00604 ** Otherwise, return a pointer to the first character not part of the time.
00605 */
00606 
00607 static const char *getoffset(const char *strp, long *offsetp)
00608 {
00609    int   neg = 0;
00610 
00611    if (*strp == '-') {
00612       neg = 1;
00613       ++strp;
00614    } else if (*strp == '+')
00615       ++strp;
00616    strp = getsecs(strp, offsetp);
00617    if (strp == NULL)
00618       return NULL;      /* illegal time */
00619    if (neg)
00620       *offsetp = -*offsetp;
00621    return strp;
00622 }
00623 
00624 /*! \brief
00625 ** Given a pointer into a time zone string, extract a rule in the form
00626 ** date[/time]. See POSIX section 8 for the format of "date" and "time".
00627 ** If a valid rule is not found, return NULL.
00628 ** Otherwise, return a pointer to the first character not part of the rule.
00629 */
00630 
00631 static const char *getrule(const char *strp, struct rule *rulep)
00632 {
00633    if (*strp == 'J') {
00634       /*
00635       ** Julian day.
00636       */
00637       rulep->r_type = JULIAN_DAY;
00638       ++strp;
00639       strp = getnum(strp, &rulep->r_day, 1, DAYSPERNYEAR);
00640    } else if (*strp == 'M') {
00641       /*
00642       ** Month, week, day.
00643       */
00644       rulep->r_type = MONTH_NTH_DAY_OF_WEEK;
00645       ++strp;
00646       strp = getnum(strp, &rulep->r_mon, 1, MONSPERYEAR);
00647       if (strp == NULL)
00648          return NULL;
00649       if (*strp++ != '.')
00650          return NULL;
00651       strp = getnum(strp, &rulep->r_week, 1, 5);
00652       if (strp == NULL)
00653          return NULL;
00654       if (*strp++ != '.')
00655          return NULL;
00656       strp = getnum(strp, &rulep->r_day, 0, DAYSPERWEEK - 1);
00657    } else if (is_digit(*strp)) {
00658       /*
00659       ** Day of year.
00660       */
00661       rulep->r_type = DAY_OF_YEAR;
00662       strp = getnum(strp, &rulep->r_day, 0, DAYSPERLYEAR - 1);
00663    } else   return NULL;      /* invalid format */
00664    if (strp == NULL)
00665       return NULL;
00666    if (*strp == '/') {
00667       /*
00668       ** Time specified.
00669       */
00670       ++strp;
00671       strp = getsecs(strp, &rulep->r_time);
00672    } else   rulep->r_time = 2 * SECSPERHOUR; /* default = 2:00:00 */
00673    return strp;
00674 }
00675 
00676 /*! \brief
00677 ** Given the Epoch-relative time of January 1, 00:00:00 UTC, in a year, the
00678 ** year, a rule, and the offset from UTC at the time that rule takes effect,
00679 ** calculate the Epoch-relative time that rule takes effect.
00680 */
00681 
00682 static time_t transtime(const time_t janfirst, const int year, const struct rule *rulep, const long offset)
00683 {
00684    int   leapyear;
00685    time_t   value;
00686    int   i;
00687    int      d, m1, yy0, yy1, yy2, dow;
00688 
00689    INITIALIZE(value);
00690    leapyear = isleap(year);
00691    switch (rulep->r_type) {
00692 
00693    case JULIAN_DAY:
00694       /*
00695       ** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap
00696       ** years.
00697       ** In non-leap years, or if the day number is 59 or less, just
00698       ** add SECSPERDAY times the day number-1 to the time of
00699       ** January 1, midnight, to get the day.
00700       */
00701       value = janfirst + (rulep->r_day - 1) * SECSPERDAY;
00702       if (leapyear && rulep->r_day >= 60)
00703          value += SECSPERDAY;
00704       break;
00705 
00706    case DAY_OF_YEAR:
00707       /*
00708       ** n - day of year.
00709       ** Just add SECSPERDAY times the day number to the time of
00710       ** January 1, midnight, to get the day.
00711       */
00712       value = janfirst + rulep->r_day * SECSPERDAY;
00713       break;
00714 
00715    case MONTH_NTH_DAY_OF_WEEK:
00716       /*
00717       ** Mm.n.d - nth "dth day" of month m.
00718       */
00719       value = janfirst;
00720       for (i = 0; i < rulep->r_mon - 1; ++i)
00721          value += mon_lengths[leapyear][i] * SECSPERDAY;
00722 
00723       /*
00724       ** Use Zeller's Congruence to get day-of-week of first day of
00725       ** month.
00726       */
00727       m1 = (rulep->r_mon + 9) % 12 + 1;
00728       yy0 = (rulep->r_mon <= 2) ? (year - 1) : year;
00729       yy1 = yy0 / 100;
00730       yy2 = yy0 % 100;
00731       dow = ((26 * m1 - 2) / 10 +
00732          1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7;
00733       if (dow < 0)
00734          dow += DAYSPERWEEK;
00735 
00736       /*
00737       ** "dow" is the day-of-week of the first day of the month. Get
00738       ** the day-of-month (zero-origin) of the first "dow" day of the
00739       ** month.
00740       */
00741       d = rulep->r_day - dow;
00742       if (d < 0)
00743          d += DAYSPERWEEK;
00744       for (i = 1; i < rulep->r_week; ++i) {
00745          if (d + DAYSPERWEEK >=
00746             mon_lengths[leapyear][rulep->r_mon - 1])
00747                break;
00748          d += DAYSPERWEEK;
00749       }
00750 
00751       /*
00752       ** "d" is the day-of-month (zero-origin) of the day we want.
00753       */
00754       value += d * SECSPERDAY;
00755       break;
00756    }
00757 
00758    /*
00759    ** "value" is the Epoch-relative time of 00:00:00 UTC on the day in
00760    ** question. To get the Epoch-relative time of the specified local
00761    ** time on that day, add the transition time and the current offset
00762    ** from UTC.
00763    */
00764    return value + rulep->r_time + offset;
00765 }
00766 
00767 /*! \note
00768 ** Given a POSIX section 8-style TZ string, fill in the rule tables as
00769 ** appropriate.
00770 */
00771 
00772 static int tzparse(const char *name, struct state *sp, const int lastditch)
00773 {
00774    const char *         stdname;
00775    const char *         dstname;
00776    size_t            stdlen;
00777    size_t            dstlen;
00778    long           stdoffset;
00779    long           dstoffset;
00780    time_t *    atp;
00781    unsigned char *   typep;
00782    char *         cp;
00783    int         load_result;
00784 
00785    INITIALIZE(dstname);
00786    stdname = name;
00787    if (lastditch) {
00788       stdlen = strlen(name);  /* length of standard zone name */
00789       name += stdlen;
00790       if (stdlen >= sizeof sp->chars)
00791          stdlen = (sizeof sp->chars) - 1;
00792       stdoffset = 0;
00793    } else {
00794       if (*name == '<') {
00795          name++;
00796          stdname = name;
00797          name = getqzname(name, '>');
00798          if (*name != '>')
00799             return -1;
00800          stdlen = name - stdname;
00801          name++;
00802       } else {
00803          name = getzname(name);
00804          stdlen = name - stdname;
00805       }
00806       if (*name == '\0')
00807          return -1;
00808       name = getoffset(name, &stdoffset);
00809       if (name == NULL)
00810          return -1;
00811    }
00812    load_result = tzload(TZDEFRULES, sp, FALSE);
00813    if (load_result != 0)
00814       sp->leapcnt = 0;     /* so, we're off a little */
00815    if (*name != '\0') {
00816       if (*name == '<') {
00817          dstname = ++name;
00818          name = getqzname(name, '>');
00819          if (*name != '>')
00820             return -1;
00821          dstlen = name - dstname;
00822          name++;
00823       } else {
00824          dstname = name;
00825          name = getzname(name);
00826          dstlen = name - dstname; /* length of DST zone name */
00827       }
00828       if (*name != '\0' && *name != ',' && *name != ';') {
00829          name = getoffset(name, &dstoffset);
00830          if (name == NULL)
00831             return -1;
00832       } else   dstoffset = stdoffset - SECSPERHOUR;
00833       if (*name == '\0' && load_result != 0)
00834          name = TZDEFRULESTRING;
00835       if (*name == ',' || *name == ';') {
00836          struct rule start;
00837          struct rule end;
00838          int   year;
00839          time_t   janfirst;
00840          time_t      starttime;
00841          time_t      endtime;
00842 
00843          ++name;
00844          if ((name = getrule(name, &start)) == NULL)
00845             return -1;
00846          if (*name++ != ',')
00847             return -1;
00848          if ((name = getrule(name, &end)) == NULL)
00849             return -1;
00850          if (*name != '\0')
00851             return -1;
00852          sp->typecnt = 2;  /* standard time and DST */
00853          /*
00854          ** Two transitions per year, from EPOCH_YEAR forward.
00855          */
00856          sp->ttis[0].tt_gmtoff = -dstoffset;
00857          sp->ttis[0].tt_isdst = 1;
00858          sp->ttis[0].tt_abbrind = stdlen + 1;
00859          sp->ttis[1].tt_gmtoff = -stdoffset;
00860          sp->ttis[1].tt_isdst = 0;
00861          sp->ttis[1].tt_abbrind = 0;
00862          atp = sp->ats;
00863          typep = sp->types;
00864          janfirst = 0;
00865          sp->timecnt = 0;
00866          for (year = EPOCH_YEAR;
00867              sp->timecnt + 2 <= TZ_MAX_TIMES;
00868              ++year) {
00869                time_t   newfirst;
00870 
00871             starttime = transtime(janfirst, year, &start,
00872                stdoffset);
00873             endtime = transtime(janfirst, year, &end,
00874                dstoffset);
00875             if (starttime > endtime) {
00876                *atp++ = endtime;
00877                *typep++ = 1;  /* DST ends */
00878                *atp++ = starttime;
00879                *typep++ = 0;  /* DST begins */
00880             } else {
00881                *atp++ = starttime;
00882                *typep++ = 0;  /* DST begins */
00883                *atp++ = endtime;
00884                *typep++ = 1;  /* DST ends */
00885             }
00886             sp->timecnt += 2;
00887             newfirst = janfirst;
00888             newfirst += year_lengths[isleap(year)] *
00889                SECSPERDAY;
00890             if (newfirst <= janfirst)
00891                break;
00892             janfirst = newfirst;
00893          }
00894       } else {
00895          long  theirstdoffset;
00896          long  theirdstoffset;
00897          long  theiroffset;
00898          int   isdst;
00899          int   i;
00900          int   j;
00901 
00902          if (*name != '\0')
00903             return -1;
00904          /*
00905          ** Initial values of theirstdoffset and theirdstoffset.
00906          */
00907          theirstdoffset = 0;
00908          for (i = 0; i < sp->timecnt; ++i) {
00909             j = sp->types[i];
00910             if (!sp->ttis[j].tt_isdst) {
00911                theirstdoffset =
00912                   -sp->ttis[j].tt_gmtoff;
00913                break;
00914             }
00915          }
00916          theirdstoffset = 0;
00917          for (i = 0; i < sp->timecnt; ++i) {
00918             j = sp->types[i];
00919             if (sp->ttis[j].tt_isdst) {
00920                theirdstoffset =
00921                   -sp->ttis[j].tt_gmtoff;
00922                break;
00923             }
00924          }
00925          /*
00926          ** Initially we're assumed to be in standard time.
00927          */
00928          isdst = FALSE;
00929          theiroffset = theirstdoffset;
00930          /*
00931          ** Now juggle transition times and types
00932          ** tracking offsets as you do.
00933          */
00934          for (i = 0; i < sp->timecnt; ++i) {
00935             j = sp->types[i];
00936             sp->types[i] = sp->ttis[j].tt_isdst;
00937             if (sp->ttis[j].tt_ttisgmt) {
00938                /* No adjustment to transition time */
00939             } else {
00940                /*
00941                ** If summer time is in effect, and the
00942                ** transition time was not specified as
00943                ** standard time, add the summer time
00944                ** offset to the transition time;
00945                ** otherwise, add the standard time
00946                ** offset to the transition time.
00947                */
00948                /*
00949                ** Transitions from DST to DDST
00950                ** will effectively disappear since
00951                ** POSIX provides for only one DST
00952                ** offset.
00953                */
00954                if (isdst && !sp->ttis[j].tt_ttisstd) {
00955                   sp->ats[i] += dstoffset -
00956                      theirdstoffset;
00957                } else {
00958                   sp->ats[i] += stdoffset -
00959                      theirstdoffset;
00960                }
00961             }
00962             theiroffset = -sp->ttis[j].tt_gmtoff;
00963             if (sp->ttis[j].tt_isdst)
00964                theirdstoffset = theiroffset;
00965             else  theirstdoffset = theiroffset;
00966          }
00967          /*
00968          ** Finally, fill in ttis.
00969          ** ttisstd and ttisgmt need not be handled.
00970          */
00971          sp->ttis[0].tt_gmtoff = -stdoffset;
00972          sp->ttis[0].tt_isdst = FALSE;
00973          sp->ttis[0].tt_abbrind = 0;
00974          sp->ttis[1].tt_gmtoff = -dstoffset;
00975          sp->ttis[1].tt_isdst = TRUE;
00976          sp->ttis[1].tt_abbrind = stdlen + 1;
00977          sp->typecnt = 2;
00978       }
00979    } else {
00980       dstlen = 0;
00981       sp->typecnt = 1;     /* only standard time */
00982       sp->timecnt = 0;
00983       sp->ttis[0].tt_gmtoff = -stdoffset;
00984       sp->ttis[0].tt_isdst = 0;
00985       sp->ttis[0].tt_abbrind = 0;
00986    }
00987    sp->charcnt = stdlen + 1;
00988    if (dstlen != 0)
00989       sp->charcnt += dstlen + 1;
00990    if ((size_t) sp->charcnt > sizeof sp->chars)
00991       return -1;
00992    cp = sp->chars;
00993    (void) strncpy(cp, stdname, stdlen);
00994    cp += stdlen;
00995    *cp++ = '\0';
00996    if (dstlen != 0) {
00997       (void) strncpy(cp, dstname, dstlen);
00998       *(cp + dstlen) = '\0';
00999    }
01000    return 0;
01001 }
01002 
01003 static int gmtload(struct state *sp)
01004 {
01005    if (tzload(gmt, sp, TRUE) != 0)
01006       return tzparse(gmt, sp, TRUE);
01007    else
01008       return -1;
01009 }
01010 
01011 static const struct state *ast_tzset(const char *zone)
01012 {
01013    struct state *sp;
01014 
01015    if (ast_strlen_zero(zone))
01016       zone = "/etc/localtime";
01017 
01018    AST_LIST_LOCK(&zonelist);
01019    AST_LIST_TRAVERSE(&zonelist, sp, list) {
01020       if (!strcmp(sp->name, zone)) {
01021          AST_LIST_UNLOCK(&zonelist);
01022          return sp;
01023       }
01024    }
01025    AST_LIST_UNLOCK(&zonelist);
01026 
01027    if (!(sp = ast_calloc(1, sizeof *sp)))
01028       return NULL;
01029 
01030    if (tzload(zone, sp, TRUE) != 0) {
01031       if (zone[0] == ':' || tzparse(zone, sp, FALSE) != 0)
01032          (void) gmtload(sp);
01033    }
01034    ast_copy_string(sp->name, zone, sizeof(sp->name));
01035    AST_LIST_LOCK(&zonelist);
01036    AST_LIST_INSERT_TAIL(&zonelist, sp, list);
01037    AST_LIST_UNLOCK(&zonelist);
01038    return sp;
01039 }
01040 
01041 /*! \note
01042 ** The easy way to behave "as if no library function calls" localtime
01043 ** is to not call it--so we drop its guts into "localsub", which can be
01044 ** freely called. (And no, the PANS doesn't require the above behavior--
01045 ** but it *is* desirable.)
01046 **
01047 ** The unused offset argument is for the benefit of mktime variants.
01048 */
01049 
01050 static struct ast_tm *localsub(const struct timeval *timep, const long offset, struct ast_tm *tmp, const struct state *sp)
01051 {
01052    const struct ttinfo *   ttisp;
01053    int         i;
01054    struct ast_tm *      result;
01055    struct timeval t;
01056    memcpy(&t, timep, sizeof(t));
01057 
01058    if (sp == NULL)
01059       return gmtsub(timep, offset, tmp);
01060    if ((sp->goback && t.tv_sec < sp->ats[0]) ||
01061       (sp->goahead && t.tv_sec > sp->ats[sp->timecnt - 1])) {
01062          struct timeval newt = t;
01063          time_t      seconds;
01064          time_t      tcycles;
01065          int_fast64_t   icycles;
01066 
01067          if (t.tv_sec < sp->ats[0])
01068             seconds = sp->ats[0] - t.tv_sec;
01069          else  seconds = t.tv_sec - sp->ats[sp->timecnt - 1];
01070          --seconds;
01071          tcycles = seconds / YEARSPERREPEAT / AVGSECSPERYEAR;
01072          ++tcycles;
01073          icycles = tcycles;
01074          if (tcycles - icycles >= 1 || icycles - tcycles >= 1)
01075             return NULL;
01076          seconds = icycles;
01077          seconds *= YEARSPERREPEAT;
01078          seconds *= AVGSECSPERYEAR;
01079          if (t.tv_sec < sp->ats[0])
01080             newt.tv_sec += seconds;
01081          else  newt.tv_sec -= seconds;
01082          if (newt.tv_sec < sp->ats[0] ||
01083             newt.tv_sec > sp->ats[sp->timecnt - 1])
01084                return NULL;   /* "cannot happen" */
01085          result = localsub(&newt, offset, tmp, sp);
01086          if (result == tmp) {
01087             time_t   newy;
01088 
01089             newy = tmp->tm_year;
01090             if (t.tv_sec < sp->ats[0])
01091                newy -= icycles * YEARSPERREPEAT;
01092             else
01093                newy += icycles * YEARSPERREPEAT;
01094             tmp->tm_year = newy;
01095             if (tmp->tm_year != newy)
01096                return NULL;
01097          }
01098          return result;
01099    }
01100    if (sp->timecnt == 0 || t.tv_sec < sp->ats[0]) {
01101       i = 0;
01102       while (sp->ttis[i].tt_isdst) {
01103          if (++i >= sp->typecnt) {
01104             i = 0;
01105             break;
01106          }
01107       }
01108    } else {
01109       int   lo = 1;
01110       int   hi = sp->timecnt;
01111 
01112       while (lo < hi) {
01113          int   mid = (lo + hi) >> 1;
01114 
01115          if (t.tv_sec < sp->ats[mid])
01116             hi = mid;
01117          else
01118             lo = mid + 1;
01119       }
01120       i = (int) sp->types[lo - 1];
01121    }
01122    ttisp = &sp->ttis[i];
01123    /*
01124    ** To get (wrong) behavior that's compatible with System V Release 2.0
01125    ** you'd replace the statement below with
01126    ** t += ttisp->tt_gmtoff;
01127    ** timesub(&t, 0L, sp, tmp);
01128    */
01129    result = timesub(&t, ttisp->tt_gmtoff, sp, tmp);
01130    tmp->tm_isdst = ttisp->tt_isdst;
01131 #ifndef SOLARIS /* Solaris doesn't have this element */
01132    tmp->tm_gmtoff = ttisp->tt_gmtoff;
01133 #endif
01134 #ifdef TM_ZONE
01135    tmp->TM_ZONE = &sp->chars[ttisp->tt_abbrind];
01136 #endif /* defined TM_ZONE */
01137    tmp->tm_usec = timep->tv_usec;
01138    return result;
01139 }
01140 
01141 struct ast_tm *ast_localtime(const struct timeval *timep, struct ast_tm *tmp, const char *zone)
01142 {
01143    const struct state *sp = ast_tzset(zone);
01144    memset(tmp, 0, sizeof(*tmp));
01145    return sp ? localsub(timep, 0L, tmp, sp) : NULL;
01146 }
01147 
01148 /*
01149 ** This function provides informaton about daylight savings time 
01150 ** for the given timezone.  This includes whether it can determine 
01151 ** if daylight savings is used for this timezone, the UTC times for 
01152 ** when daylight savings transitions, and the offset in seconds from 
01153 ** UTC. 
01154 */
01155 
01156 void ast_get_dst_info(const time_t * const timep, int *dst_enabled, time_t *dst_start, time_t *dst_end, int *gmt_off, const char * const zone)
01157 {
01158    int i;   
01159    int transition1 = -1;
01160    int transition2 = -1;
01161    time_t      seconds;
01162    int  bounds_exceeded = 0;
01163    time_t  t = *timep;
01164    const struct state *sp;
01165    
01166    if (NULL == dst_enabled)
01167       return;
01168    *dst_enabled = 0;
01169 
01170    if (NULL == dst_start || NULL == dst_end || NULL == gmt_off)
01171       return;
01172 
01173    *gmt_off = 0; 
01174    
01175    sp = ast_tzset(zone);
01176    if (NULL == sp) 
01177       return;
01178    
01179    /* If the desired time exceeds the bounds of the defined time transitions  
01180    * then give give up on determining DST info and simply look for gmt offset 
01181    * This requires that I adjust the given time using increments of Gregorian 
01182    * repeats to place the time within the defined time transitions in the 
01183    * timezone structure.  
01184    */
01185    if ((sp->goback && t < sp->ats[0]) ||
01186          (sp->goahead && t > sp->ats[sp->timecnt - 1])) {
01187       time_t      tcycles;
01188       int_fast64_t   icycles;
01189 
01190       if (t < sp->ats[0])
01191          seconds = sp->ats[0] - t;
01192       else  seconds = t - sp->ats[sp->timecnt - 1];
01193       --seconds;
01194       tcycles = seconds / YEARSPERREPEAT / AVGSECSPERYEAR;
01195       ++tcycles;
01196       icycles = tcycles;
01197       if (tcycles - icycles >= 1 || icycles - tcycles >= 1)
01198          return;
01199       seconds = icycles;
01200       seconds *= YEARSPERREPEAT;
01201       seconds *= AVGSECSPERYEAR;
01202       if (t < sp->ats[0])
01203          t += seconds;
01204       else
01205          t -= seconds;
01206       
01207       if (t < sp->ats[0] || t > sp->ats[sp->timecnt - 1])
01208          return;  /* "cannot happen" */
01209 
01210       bounds_exceeded = 1;
01211    }
01212 
01213    if (sp->timecnt == 0 || t < sp->ats[0]) {
01214       /* I have no transition times or I'm before time */
01215       *dst_enabled = 0;
01216       /* Find where I can get gmtoff */
01217       i = 0;
01218       while (sp->ttis[i].tt_isdst)
01219          if (++i >= sp->typecnt) {
01220          i = 0;
01221          break;
01222          }
01223          *gmt_off = sp->ttis[i].tt_gmtoff;
01224          return;
01225    } 
01226 
01227    for (i = 1; i < sp->timecnt; ++i) {
01228       if (t < sp->ats[i]) {
01229          transition1 = sp->types[i - 1];
01230          transition2 = sp->types[i];
01231          break;
01232       } 
01233    }
01234    /* if I found transition times that do not bounded the given time and these correspond to 
01235       or the bounding zones do not reflect a changes in day light savings, then I do not have dst active */
01236    if (i >= sp->timecnt || 0 > transition1 || 0 > transition2 ||
01237          (sp->ttis[transition1].tt_isdst == sp->ttis[transition2].tt_isdst)) {
01238       *dst_enabled = 0;
01239       *gmt_off     = sp->ttis[sp->types[sp->timecnt -1]].tt_gmtoff;
01240    } else {
01241       /* I have valid daylight savings information. */
01242       if(sp->ttis[transition2].tt_isdst) 
01243          *gmt_off = sp->ttis[transition1].tt_gmtoff;
01244       else 
01245          *gmt_off = sp->ttis[transition2].tt_gmtoff;
01246 
01247       /* If I adjusted the time earlier, indicate that the dst is invalid */
01248       if (!bounds_exceeded) {
01249          *dst_enabled = 1;
01250          /* Determine which of the bounds is the start of daylight savings and which is the end */
01251          if(sp->ttis[transition2].tt_isdst) {
01252             *dst_start = sp->ats[i];
01253             *dst_end = sp->ats[i -1];
01254          } else {
01255             *dst_start = sp->ats[i -1];
01256             *dst_end = sp->ats[i];
01257          }
01258       }
01259    }  
01260    return;
01261 }
01262 
01263 /*
01264 ** gmtsub is to gmtime as localsub is to localtime.
01265 */
01266 
01267 static struct ast_tm *gmtsub(const struct timeval *timep, const long offset, struct ast_tm *tmp)
01268 {
01269    struct ast_tm *   result;
01270    struct state *sp;
01271 
01272    AST_LIST_LOCK(&zonelist);
01273    AST_LIST_TRAVERSE(&zonelist, sp, list) {
01274       if (!strcmp(sp->name, "UTC"))
01275          break;
01276    }
01277 
01278    if (!sp) {
01279       if (!(sp = (struct state *) ast_calloc(1, sizeof *sp)))
01280          return NULL;
01281       gmtload(sp);
01282       AST_LIST_INSERT_TAIL(&zonelist, sp, list);
01283    }
01284    AST_LIST_UNLOCK(&zonelist);
01285 
01286    result = timesub(timep, offset, sp, tmp);
01287 #ifdef TM_ZONE
01288    /*
01289    ** Could get fancy here and deliver something such as
01290    ** "UTC+xxxx" or "UTC-xxxx" if offset is non-zero,
01291    ** but this is no time for a treasure hunt.
01292    */
01293    if (offset != 0)
01294       tmp->TM_ZONE = "    ";
01295    else
01296       tmp->TM_ZONE = sp->chars;
01297 #endif /* defined TM_ZONE */
01298    return result;
01299 }
01300 
01301 /*! \brief
01302 ** Return the number of leap years through the end of the given year
01303 ** where, to make the math easy, the answer for year zero is defined as zero.
01304 */
01305 
01306 static int leaps_thru_end_of(const int y)
01307 {
01308    return (y >= 0) ? (y / 4 - y / 100 + y / 400) :
01309       -(leaps_thru_end_of(-(y + 1)) + 1);
01310 }
01311 
01312 static struct ast_tm *timesub(const struct timeval *timep, const long offset, const struct state *sp, struct ast_tm *tmp)
01313 {
01314    const struct lsinfo *   lp;
01315    time_t         tdays;
01316    int         idays;   /* unsigned would be so 2003 */
01317    long        rem;
01318    int            y;
01319    const int *    ip;
01320    long        corr;
01321    int         hit;
01322    int         i;
01323    long  seconds;
01324 
01325 
01326    corr = 0;
01327    hit = 0;
01328    i = (sp == NULL) ? 0 : sp->leapcnt;
01329    while (--i >= 0) {
01330       lp = &sp->lsis[i];
01331       if (timep->tv_sec >= lp->ls_trans) {
01332          if (timep->tv_sec == lp->ls_trans) {
01333             hit = ((i == 0 && lp->ls_corr > 0) ||
01334                lp->ls_corr > sp->lsis[i - 1].ls_corr);
01335             if (hit)
01336                while (i > 0 &&
01337                   sp->lsis[i].ls_trans ==
01338                   sp->lsis[i - 1].ls_trans + 1 &&
01339                   sp->lsis[i].ls_corr ==
01340                   sp->lsis[i - 1].ls_corr + 1) {
01341                      ++hit;
01342                      --i;
01343                }
01344          }
01345          corr = lp->ls_corr;
01346          break;
01347       }
01348    }
01349    y = EPOCH_YEAR;
01350    tdays = timep->tv_sec / SECSPERDAY;
01351    rem = timep->tv_sec - tdays * SECSPERDAY;
01352    while (tdays < 0 || tdays >= year_lengths[isleap(y)]) {
01353       int      newy;
01354       time_t   tdelta;
01355       int   idelta;
01356       int   leapdays;
01357 
01358       tdelta = tdays / DAYSPERLYEAR;
01359       idelta = tdelta;
01360       if (tdelta - idelta >= 1 || idelta - tdelta >= 1)
01361          return NULL;
01362       if (idelta == 0)
01363          idelta = (tdays < 0) ? -1 : 1;
01364       newy = y;
01365       if (increment_overflow(&newy, idelta))
01366          return NULL;
01367       leapdays = leaps_thru_end_of(newy - 1) -
01368          leaps_thru_end_of(y - 1);
01369       tdays -= ((time_t) newy - y) * DAYSPERNYEAR;
01370       tdays -= leapdays;
01371       y = newy;
01372    }
01373 
01374    seconds = tdays * SECSPERDAY + 0.5;
01375    tdays = seconds / SECSPERDAY;
01376    rem += seconds - tdays * SECSPERDAY;
01377 
01378    /*
01379    ** Given the range, we can now fearlessly cast...
01380    */
01381    idays = tdays;
01382    rem += offset - corr;
01383    while (rem < 0) {
01384       rem += SECSPERDAY;
01385       --idays;
01386    }
01387    while (rem >= SECSPERDAY) {
01388       rem -= SECSPERDAY;
01389       ++idays;
01390    }
01391    while (idays < 0) {
01392       if (increment_overflow(&y, -1))
01393          return NULL;
01394       idays += year_lengths[isleap(y)];
01395    }
01396    while (idays >= year_lengths[isleap(y)]) {
01397       idays -= year_lengths[isleap(y)];
01398       if (increment_overflow(&y, 1))
01399          return NULL;
01400    }
01401    tmp->tm_year = y;
01402    if (increment_overflow(&tmp->tm_year, -TM_YEAR_BASE))
01403       return NULL;
01404    tmp->tm_yday = idays;
01405    /*
01406    ** The "extra" mods below avoid overflow problems.
01407    */
01408    tmp->tm_wday = EPOCH_WDAY +
01409       ((y - EPOCH_YEAR) % DAYSPERWEEK) *
01410       (DAYSPERNYEAR % DAYSPERWEEK) +
01411       leaps_thru_end_of(y - 1) -
01412       leaps_thru_end_of(EPOCH_YEAR - 1) +
01413       idays;
01414    tmp->tm_wday %= DAYSPERWEEK;
01415    if (tmp->tm_wday < 0)
01416       tmp->tm_wday += DAYSPERWEEK;
01417    tmp->tm_hour = (int) (rem / SECSPERHOUR);
01418    rem %= SECSPERHOUR;
01419    tmp->tm_min = (int) (rem / SECSPERMIN);
01420    /*
01421    ** A positive leap second requires a special
01422    ** representation. This uses "... ??:59:60" et seq.
01423    */
01424    tmp->tm_sec = (int) (rem % SECSPERMIN) + hit;
01425    ip = mon_lengths[isleap(y)];
01426    for (tmp->tm_mon = 0; idays >= ip[tmp->tm_mon]; ++(tmp->tm_mon))
01427       idays -= ip[tmp->tm_mon];
01428    tmp->tm_mday = (int) (idays + 1);
01429    tmp->tm_isdst = 0;
01430 #ifdef TM_GMTOFF
01431    tmp->TM_GMTOFF = offset;
01432 #endif /* defined TM_GMTOFF */
01433    tmp->tm_usec = timep->tv_usec;
01434    return tmp;
01435 }
01436 
01437 /*! \note
01438 ** Adapted from code provided by Robert Elz, who writes:
01439 ** The "best" way to do mktime I think is based on an idea of Bob
01440 ** Kridle's (so its said...) from a long time ago.
01441 ** It does a binary search of the time_t space. Since time_t's are
01442 ** just 32 bits, its a max of 32 iterations (even at 64 bits it
01443 ** would still be very reasonable).
01444 */
01445 
01446 /*! \brief
01447 ** Simplified normalize logic courtesy Paul Eggert.
01448 */
01449 
01450 static int increment_overflow(int *number, int delta)
01451 {
01452    int   number0;
01453 
01454    number0 = *number;
01455    *number += delta;
01456    return (*number < number0) != (delta < 0);
01457 }
01458 
01459 static int long_increment_overflow(long *number, int delta)
01460 {
01461    long  number0;
01462 
01463    number0 = *number;
01464    *number += delta;
01465    return (*number < number0) != (delta < 0);
01466 }
01467 
01468 static int normalize_overflow(int *tensptr, int *unitsptr, const int base)
01469 {
01470    int   tensdelta;
01471 
01472    tensdelta = (*unitsptr >= 0) ?
01473       (*unitsptr / base) :
01474       (-1 - (-1 - *unitsptr) / base);
01475    *unitsptr -= tensdelta * base;
01476    return increment_overflow(tensptr, tensdelta);
01477 }
01478 
01479 static int long_normalize_overflow(long *tensptr, int *unitsptr, const int base)
01480 {
01481    int   tensdelta;
01482 
01483    tensdelta = (*unitsptr >= 0) ?
01484       (*unitsptr / base) :
01485       (-1 - (-1 - *unitsptr) / base);
01486    *unitsptr -= tensdelta * base;
01487    return long_increment_overflow(tensptr, tensdelta);
01488 }
01489 
01490 static int tmcomp(const struct ast_tm *atmp, const struct ast_tm *btmp)
01491 {
01492    int   result;
01493 
01494    if ((result = (atmp->tm_year - btmp->tm_year)) == 0 &&
01495       (result = (atmp->tm_mon - btmp->tm_mon)) == 0 &&
01496       (result = (atmp->tm_mday - btmp->tm_mday)) == 0 &&
01497       (result = (atmp->tm_hour - btmp->tm_hour)) == 0 &&
01498       (result = (atmp->tm_min - btmp->tm_min)) == 0 &&
01499       (result = (atmp->tm_sec - btmp->tm_sec)) == 0)
01500          result = atmp->tm_usec - btmp->tm_usec;
01501    return result;
01502 }
01503 
01504 static struct timeval time2sub(struct ast_tm *tmp, struct ast_tm * (* const funcp) (const struct timeval *, long, struct ast_tm *, const struct state *), const long offset, int *okayp, const int do_norm_secs, const struct state *sp)
01505 {
01506    int         dir;
01507    int         i, j;
01508    int         saved_seconds;
01509    long        li;
01510    time_t         lo;
01511    time_t         hi;
01512    long           y;
01513    struct timeval       newt = { 0, 0 };
01514    struct timeval       t = { 0, 0 };
01515    struct ast_tm        yourtm, mytm;
01516 
01517    *okayp = FALSE;
01518    yourtm = *tmp;
01519    if (do_norm_secs) {
01520       if (normalize_overflow(&yourtm.tm_min, &yourtm.tm_sec,
01521          SECSPERMIN))
01522             return WRONG;
01523    }
01524    if (normalize_overflow(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR))
01525       return WRONG;
01526    if (normalize_overflow(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY))
01527       return WRONG;
01528    y = yourtm.tm_year;
01529    if (long_normalize_overflow(&y, &yourtm.tm_mon, MONSPERYEAR))
01530       return WRONG;
01531    /*
01532    ** Turn y into an actual year number for now.
01533    ** It is converted back to an offset from TM_YEAR_BASE later.
01534    */
01535    if (long_increment_overflow(&y, TM_YEAR_BASE))
01536       return WRONG;
01537    while (yourtm.tm_mday <= 0) {
01538       if (long_increment_overflow(&y, -1))
01539          return WRONG;
01540       li = y + (1 < yourtm.tm_mon);
01541       yourtm.tm_mday += year_lengths[isleap(li)];
01542    }
01543    while (yourtm.tm_mday > DAYSPERLYEAR) {
01544       li = y + (1 < yourtm.tm_mon);
01545       yourtm.tm_mday -= year_lengths[isleap(li)];
01546       if (long_increment_overflow(&y, 1))
01547          return WRONG;
01548    }
01549    for ( ; ; ) {
01550       i = mon_lengths[isleap(y)][yourtm.tm_mon];
01551       if (yourtm.tm_mday <= i)
01552          break;
01553       yourtm.tm_mday -= i;
01554       if (++yourtm.tm_mon >= MONSPERYEAR) {
01555          yourtm.tm_mon = 0;
01556          if (long_increment_overflow(&y, 1))
01557             return WRONG;
01558       }
01559    }
01560    if (long_increment_overflow(&y, -TM_YEAR_BASE))
01561       return WRONG;
01562    yourtm.tm_year = y;
01563    if (yourtm.tm_year != y)
01564       return WRONG;
01565    if (yourtm.tm_sec >= 0 && yourtm.tm_sec < SECSPERMIN)
01566       saved_seconds = 0;
01567    else if (y + TM_YEAR_BASE < EPOCH_YEAR) {
01568       /*
01569       ** We can't set tm_sec to 0, because that might push the
01570       ** time below the minimum representable time.
01571       ** Set tm_sec to 59 instead.
01572       ** This assumes that the minimum representable time is
01573       ** not in the same minute that a leap second was deleted from,
01574       ** which is a safer assumption than using 58 would be.
01575       */
01576       if (increment_overflow(&yourtm.tm_sec, 1 - SECSPERMIN))
01577          return WRONG;
01578       saved_seconds = yourtm.tm_sec;
01579       yourtm.tm_sec = SECSPERMIN - 1;
01580    } else {
01581       saved_seconds = yourtm.tm_sec;
01582       yourtm.tm_sec = 0;
01583    }
01584    /*
01585    ** Do a binary search (this works whatever time_t's type is).
01586    */
01587    if (!TYPE_SIGNED(time_t)) {
01588       lo = 0;
01589       hi = lo - 1;
01590    } else if (!TYPE_INTEGRAL(time_t)) {
01591       if (sizeof(time_t) > sizeof(float))
01592          hi = (time_t) DBL_MAX;
01593       else  hi = (time_t) FLT_MAX;
01594       lo = -hi;
01595    } else {
01596       lo = 1;
01597       for (i = 0; i < (int) TYPE_BIT(time_t) - 1; ++i)
01598          lo *= 2;
01599       hi = -(lo + 1);
01600    }
01601    for ( ; ; ) {
01602       t.tv_sec = lo / 2 + hi / 2;
01603       if (t.tv_sec < lo)
01604          t.tv_sec = lo;
01605       else if (t.tv_sec > hi)
01606          t.tv_sec = hi;
01607       if ((*funcp)(&t, offset, &mytm, sp) == NULL) {
01608          /*
01609          ** Assume that t is too extreme to be represented in
01610          ** a struct ast_tm; arrange things so that it is less
01611          ** extreme on the next pass.
01612          */
01613          dir = (t.tv_sec > 0) ? 1 : -1;
01614       } else   dir = tmcomp(&mytm, &yourtm);
01615       if (dir != 0) {
01616          if (t.tv_sec == lo) {
01617             ++t.tv_sec;
01618             if (t.tv_sec <= lo)
01619                return WRONG;
01620             ++lo;
01621          } else if (t.tv_sec == hi) {
01622             --t.tv_sec;
01623             if (t.tv_sec >= hi)
01624                return WRONG;
01625             --hi;
01626          }
01627          if (lo > hi)
01628             return WRONG;
01629          if (dir > 0)
01630             hi = t.tv_sec;
01631          else  lo = t.tv_sec;
01632          continue;
01633       }
01634       if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst)
01635          break;
01636       /*
01637       ** Right time, wrong type.
01638       ** Hunt for right time, right type.
01639       ** It's okay to guess wrong since the guess
01640       ** gets checked.
01641       */
01642       /*
01643       ** The (void *) casts are the benefit of SunOS 3.3 on Sun 2's.
01644       */
01645       for (i = sp->typecnt - 1; i >= 0; --i) {
01646          if (sp->ttis[i].tt_isdst != yourtm.tm_isdst)
01647             continue;
01648          for (j = sp->typecnt - 1; j >= 0; --j) {
01649             if (sp->ttis[j].tt_isdst == yourtm.tm_isdst)
01650                continue;
01651             newt.tv_sec = t.tv_sec + sp->ttis[j].tt_gmtoff -
01652                sp->ttis[i].tt_gmtoff;
01653             if ((*funcp)(&newt, offset, &mytm, sp) == NULL)
01654                continue;
01655             if (tmcomp(&mytm, &yourtm) != 0)
01656                continue;
01657             if (mytm.tm_isdst != yourtm.tm_isdst)
01658                continue;
01659             /*
01660             ** We have a match.
01661             */
01662             t = newt;
01663             goto label;
01664          }
01665       }
01666       return WRONG;
01667    }
01668 label:
01669    newt.tv_sec = t.tv_sec + saved_seconds;
01670    if ((newt.tv_sec < t.tv_sec) != (saved_seconds < 0))
01671       return WRONG;
01672    t.tv_sec = newt.tv_sec;
01673    if ((*funcp)(&t, offset, tmp, sp))
01674       *okayp = TRUE;
01675    return t;
01676 }
01677 
01678 static struct timeval time2(struct ast_tm *tmp, struct ast_tm * (* const funcp) (const struct timeval *, long, struct ast_tm*, const struct state *sp), const long offset, int *okayp, const struct state *sp)
01679 {
01680    struct timeval t;
01681 
01682    /*! \note
01683    ** First try without normalization of seconds
01684    ** (in case tm_sec contains a value associated with a leap second).
01685    ** If that fails, try with normalization of seconds.
01686    */
01687    t = time2sub(tmp, funcp, offset, okayp, FALSE, sp);
01688    return *okayp ? t : time2sub(tmp, funcp, offset, okayp, TRUE, sp);
01689 }
01690 
01691 static struct timeval time1(struct ast_tm *tmp, struct ast_tm * (* const funcp) (const struct timeval *, long, struct ast_tm *, const struct state *), const long offset, const struct state *sp)
01692 {
01693    struct timeval       t;
01694    int         samei, otheri;
01695    int         sameind, otherind;
01696    int         i;
01697    int         nseen;
01698    int            seen[TZ_MAX_TYPES];
01699    int            types[TZ_MAX_TYPES];
01700    int            okay;
01701 
01702    if (tmp->tm_isdst > 1)
01703       tmp->tm_isdst = 1;
01704    t = time2(tmp, funcp, offset, &okay, sp);
01705 #ifdef PCTS
01706    /*
01707    ** PCTS code courtesy Grant Sullivan.
01708    */
01709    if (okay)
01710       return t;
01711    if (tmp->tm_isdst < 0)
01712       tmp->tm_isdst = 0;   /* reset to std and try again */
01713 #endif /* defined PCTS */
01714 #ifndef PCTS
01715    if (okay || tmp->tm_isdst < 0)
01716       return t;
01717 #endif /* !defined PCTS */
01718    /*
01719    ** We're supposed to assume that somebody took a time of one type
01720    ** and did some math on it that yielded a "struct ast_tm" that's bad.
01721    ** We try to divine the type they started from and adjust to the
01722    ** type they need.
01723    */
01724    if (sp == NULL)
01725       return WRONG;
01726    for (i = 0; i < sp->typecnt; ++i)
01727       seen[i] = FALSE;
01728    nseen = 0;
01729    for (i = sp->timecnt - 1; i >= 0; --i)
01730       if (!seen[sp->types[i]]) {
01731          seen[sp->types[i]] = TRUE;
01732          types[nseen++] = sp->types[i];
01733       }
01734    for (sameind = 0; sameind < nseen; ++sameind) {
01735       samei = types[sameind];
01736       if (sp->ttis[samei].tt_isdst != tmp->tm_isdst)
01737          continue;
01738       for (otherind = 0; otherind < nseen; ++otherind) {
01739          otheri = types[otherind];
01740          if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst)
01741             continue;
01742          tmp->tm_sec += sp->ttis[otheri].tt_gmtoff -
01743                sp->ttis[samei].tt_gmtoff;
01744          tmp->tm_isdst = !tmp->tm_isdst;
01745          t = time2(tmp, funcp, offset, &okay, sp);
01746          if (okay)
01747             return t;
01748          tmp->tm_sec -= sp->ttis[otheri].tt_gmtoff -
01749                sp->ttis[samei].tt_gmtoff;
01750          tmp->tm_isdst = !tmp->tm_isdst;
01751       }
01752    }
01753    return WRONG;
01754 }
01755 
01756 struct timeval ast_mktime(struct ast_tm *tmp, const char *zone)
01757 {
01758    const struct state *sp;
01759    if (!(sp = ast_tzset(zone)))
01760       return WRONG;
01761    return time1(tmp, localsub, 0L, sp);
01762 }
01763 
01764 int ast_strftime(char *buf, size_t len, const char *tmp, const struct ast_tm *tm)
01765 {
01766    size_t fmtlen = strlen(tmp) + 1;
01767    char *format = ast_calloc(1, fmtlen), *fptr = format, *newfmt;
01768    int decimals = -1, i, res;
01769    long fraction;
01770 
01771    if (!format)
01772       return -1;
01773    for (; *tmp; tmp++) {
01774       if (*tmp == '%') {
01775          switch (tmp[1]) {
01776          case '1':
01777          case '2':
01778          case '3':
01779          case '4':
01780          case '5':
01781          case '6':
01782             if (tmp[2] != 'q')
01783                goto defcase;
01784             decimals = tmp[1] - '0';
01785             tmp++;
01786             /* Fall through */
01787          case 'q': /* Milliseconds */
01788             if (decimals == -1)
01789                decimals = 3;
01790 
01791             /* Juggle some memory to fit the item */
01792             newfmt = ast_realloc(format, fmtlen + decimals);
01793             if (!newfmt) {
01794                ast_free(format);
01795                return -1;
01796             }
01797             fptr = fptr - format + newfmt;
01798             format = newfmt;
01799             fmtlen += decimals;
01800 
01801             /* Reduce the fraction of time to the accuracy needed */
01802             for (i = 6, fraction = tm->tm_usec; i > decimals; i--)
01803                fraction /= 10;
01804             fptr += sprintf(fptr, "%0*ld", decimals, fraction);
01805 
01806             /* Reset, in case more than one 'q' specifier exists */
01807             decimals = -1;
01808             tmp++;
01809             break;
01810          default:
01811             goto defcase;
01812          }
01813       } else
01814 defcase: *fptr++ = *tmp;
01815    }
01816    *fptr = '\0';
01817 #undef strftime
01818    res = (int)strftime(buf, len, format, (struct tm *)tm);
01819    ast_free(format);
01820    return res;
01821 }
01822 

Generated on Wed Aug 18 22:33:53 2010 for Asterisk - the Open Source PBX by  doxygen 1.4.7