Sat Aug 6 00:39:29 2011

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

Generated on Sat Aug 6 00:39:29 2011 for Asterisk - the Open Source PBX by  doxygen 1.4.7