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

Generated on Wed Oct 28 11:51:05 2009 for Asterisk - the Open Source PBX by  doxygen 1.5.6