Tue Nov 4 13:20:20 2008

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

Generated on Tue Nov 4 13:20:20 2008 for Asterisk - the Open Source PBX by  doxygen 1.4.7