Fri Nov 12 11:46:52 2010

Asterisk developer's documentation


localtime.c

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

Generated by  doxygen 1.6.2