Mon Oct 8 12:39:03 2012

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 - 2010, 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 /*** MODULEINFO
00048    <support_level>core</support_level>
00049  ***/
00050 
00051 #include "asterisk.h"
00052 
00053 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 369001 $")
00054 
00055 #include <signal.h>
00056 #include <sys/stat.h>
00057 #include <fcntl.h>
00058 #include <float.h>
00059 #include <stdlib.h>
00060 #ifdef HAVE_INOTIFY
00061 #include <sys/inotify.h>
00062 #elif defined(HAVE_KQUEUE)
00063 #include <sys/types.h>
00064 #include <sys/time.h>
00065 #include <sys/event.h>
00066 #include <dirent.h>
00067 #include <sys/stat.h>
00068 #include <fcntl.h>
00069 #endif
00070 
00071 #include "private.h"
00072 #include "tzfile.h"
00073 
00074 #include "asterisk/lock.h"
00075 #include "asterisk/localtime.h"
00076 #include "asterisk/strings.h"
00077 #include "asterisk/linkedlists.h"
00078 #include "asterisk/utils.h"
00079 #include "asterisk/test.h"
00080 
00081 #ifndef lint
00082 #ifndef NOID
00083 static char __attribute__((unused)) elsieid[] = "@(#)localtime.c  8.5";
00084 #endif /* !defined NOID */
00085 #endif /* !defined lint */
00086 
00087 #ifndef TZ_ABBR_MAX_LEN
00088 #define TZ_ABBR_MAX_LEN 16
00089 #endif /* !defined TZ_ABBR_MAX_LEN */
00090 
00091 #ifndef TZ_ABBR_CHAR_SET
00092 #define TZ_ABBR_CHAR_SET \
00093    "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 :+-._"
00094 #endif /* !defined TZ_ABBR_CHAR_SET */
00095 
00096 #ifndef TZ_ABBR_ERR_CHAR
00097 #define TZ_ABBR_ERR_CHAR   '_'
00098 #endif /* !defined TZ_ABBR_ERR_CHAR */
00099 
00100 /*
00101 ** SunOS 4.1.1 headers lack O_BINARY.
00102 */
00103 
00104 #ifdef O_BINARY
00105 #define OPEN_MODE (O_RDONLY | O_BINARY)
00106 #endif /* defined O_BINARY */
00107 #ifndef O_BINARY
00108 #define OPEN_MODE O_RDONLY
00109 #endif /* !defined O_BINARY */
00110 
00111 static const char gmt[] = "GMT";
00112 static const struct timeval WRONG = { 0, 0 };
00113 
00114 #ifdef TEST_FRAMEWORK
00115 /* Protected from multiple threads by the zonelist lock */
00116 static struct ast_test *test = NULL;
00117 #else
00118 struct ast_test;
00119 #endif
00120 
00121 /*! \note
00122  * The DST rules to use if TZ has no rules and we can't load TZDEFRULES.
00123  * We default to US rules as of 1999-08-17.
00124  * POSIX 1003.1 section 8.1.1 says that the default DST rules are
00125  * implementation dependent; for historical reasons, US rules are a
00126  * common default.
00127  */
00128 #ifndef TZDEFRULESTRING
00129 #define TZDEFRULESTRING ",M4.1.0,M10.5.0"
00130 #endif /* !defined TZDEFDST */
00131 
00132 /*!< \brief time type information */
00133 struct ttinfo {            /* time type information */
00134    long     tt_gmtoff;  /* UTC offset in seconds */
00135    int      tt_isdst;   /* used to set tm_isdst */
00136    int      tt_abbrind; /* abbreviation list index */
00137    int      tt_ttisstd; /* TRUE if transition is std time */
00138    int      tt_ttisgmt; /* TRUE if transition is UTC */
00139 };
00140 
00141 /*! \brief leap second information */
00142 struct lsinfo {            /* leap second information */
00143    time_t      ls_trans;   /* transition time */
00144    long     ls_corr; /* correction to apply */
00145 };
00146 
00147 #define BIGGEST(a, b)   (((a) > (b)) ? (a) : (b))
00148 
00149 #ifdef TZNAME_MAX
00150 #define MY_TZNAME_MAX   TZNAME_MAX
00151 #endif /* defined TZNAME_MAX */
00152 #ifndef TZNAME_MAX
00153 #define MY_TZNAME_MAX   255
00154 #endif /* !defined TZNAME_MAX */
00155 #ifndef TZ_STRLEN_MAX
00156 #define TZ_STRLEN_MAX   255
00157 #endif /* !defined TZ_STRLEN_MAX */
00158 
00159 struct state {
00160    /*! Name of the file that this references */
00161    char    name[TZ_STRLEN_MAX + 1];
00162    int      leapcnt;
00163    int      timecnt;
00164    int      typecnt;
00165    int      charcnt;
00166    int      goback;
00167    int      goahead;
00168    time_t      ats[TZ_MAX_TIMES];
00169    unsigned char  types[TZ_MAX_TIMES];
00170    struct ttinfo  ttis[TZ_MAX_TYPES];
00171    char     chars[BIGGEST(BIGGEST(TZ_MAX_CHARS + 1, sizeof gmt),
00172             (2 * (MY_TZNAME_MAX + 1)))];
00173    struct lsinfo  lsis[TZ_MAX_LEAPS];
00174 #ifdef HAVE_INOTIFY
00175    int wd[2];
00176 #elif defined(HAVE_KQUEUE)
00177    int fd;
00178 # ifdef HAVE_O_SYMLINK
00179    int fds;
00180 # else
00181    DIR *dir;
00182 # endif /* defined(HAVE_O_SYMLINK) */
00183 #else
00184    time_t  mtime[2];
00185 #endif
00186    AST_LIST_ENTRY(state) list;
00187 };
00188 
00189 struct locale_entry {
00190    AST_LIST_ENTRY(locale_entry) list;
00191    locale_t locale;
00192    char name[0];
00193 };
00194 
00195 struct rule {
00196    int      r_type;     /* type of rule--see below */
00197    int      r_day;      /* day number of rule */
00198    int      r_week;     /* week number of rule */
00199    int      r_mon;      /* month number of rule */
00200    long     r_time;     /* transition time of rule */
00201 };
00202 
00203 #define JULIAN_DAY      0  /* Jn - Julian day */
00204 #define DAY_OF_YEAR     1  /* n - day of year */
00205 #define MONTH_NTH_DAY_OF_WEEK 2  /* Mm.n.d - month, week, day of week */
00206 
00207 /*
00208 ** Prototypes for static functions.
00209 */
00210 
00211 static long    detzcode P((const char * codep));
00212 static time_t     detzcode64 P((const char * codep));
00213 static int     differ_by_repeat P((time_t t1, time_t t0));
00214 static const char *  getzname P((const char * strp));
00215 static const char *  getqzname P((const char * strp, const int delim));
00216 static const char *  getnum P((const char * strp, int * nump, int min,
00217             int max));
00218 static const char *  getsecs P((const char * strp, long * secsp));
00219 static const char *  getoffset P((const char * strp, long * offsetp));
00220 static const char *  getrule P((const char * strp, struct rule * rulep));
00221 static int     gmtload P((struct state * sp));
00222 static struct ast_tm *  gmtsub P((const struct timeval * timep, long offset,
00223             struct ast_tm * tmp));
00224 static struct ast_tm *  localsub P((const struct timeval * timep, long offset,
00225             struct ast_tm * tmp, const struct state *sp));
00226 static int     increment_overflow P((int * number, int delta));
00227 static int     leaps_thru_end_of P((int y));
00228 static int     long_increment_overflow P((long * number, int delta));
00229 static int     long_normalize_overflow P((long * tensptr,
00230             int * unitsptr, const int base));
00231 static int     normalize_overflow P((int * tensptr, int * unitsptr,
00232             const int base));
00233 static struct timeval   time1 P((struct ast_tm * tmp,
00234             struct ast_tm * (*funcp) P((const struct timeval *,
00235             long, struct ast_tm *, const struct state *sp)),
00236             long offset, const struct state *sp));
00237 static struct timeval   time2 P((struct ast_tm *tmp,
00238             struct ast_tm * (*funcp) P((const struct timeval *,
00239             long, struct ast_tm*, const struct state *sp)),
00240             long offset, int * okayp, const struct state *sp));
00241 static struct timeval   time2sub P((struct ast_tm *tmp,
00242             struct ast_tm * (*funcp) (const struct timeval *,
00243             long, struct ast_tm*, const struct state *sp),
00244             long offset, int * okayp, int do_norm_secs, const struct state *sp));
00245 static struct ast_tm *  timesub P((const struct timeval * timep, long offset,
00246             const struct state * sp, struct ast_tm * tmp));
00247 static int     tmcomp P((const struct ast_tm * atmp,
00248             const struct ast_tm * btmp));
00249 static time_t     transtime P((time_t janfirst, int year,
00250             const struct rule * rulep, long offset));
00251 static int     tzload P((const char * name, struct state * sp,
00252             int doextend));
00253 static int     tzparse P((const char * name, struct state * sp,
00254             int lastditch));
00255 
00256 static AST_LIST_HEAD_STATIC(zonelist, state);
00257 #ifdef HAVE_NEWLOCALE
00258 static AST_LIST_HEAD_STATIC(localelist, locale_entry);
00259 #endif
00260 
00261 #ifndef TZ_STRLEN_MAX
00262 #define TZ_STRLEN_MAX 255
00263 #endif /* !defined TZ_STRLEN_MAX */
00264 
00265 static pthread_t inotify_thread = AST_PTHREADT_NULL;
00266 static ast_cond_t initialization;
00267 static ast_mutex_t initialization_lock;
00268 #ifdef HAVE_INOTIFY
00269 static int inotify_fd = -1;
00270 
00271 static void *inotify_daemon(void *data)
00272 {
00273    struct {
00274       struct inotify_event iev;
00275       char name[FILENAME_MAX + 1];
00276    } buf;
00277    ssize_t res;
00278    struct state *cur;
00279 
00280    inotify_fd = inotify_init();
00281 
00282    ast_mutex_lock(&initialization_lock);
00283    ast_cond_broadcast(&initialization);
00284    ast_mutex_unlock(&initialization_lock);
00285 
00286    if (inotify_fd < 0) {
00287       ast_log(LOG_ERROR, "Cannot initialize file notification service: %s (%d)\n", strerror(errno), errno);
00288       inotify_thread = AST_PTHREADT_NULL;
00289       return NULL;
00290    }
00291 
00292    for (;/*ever*/;) {
00293       /* This read should block, most of the time. */
00294       if ((res = read(inotify_fd, &buf, sizeof(buf))) < sizeof(buf.iev) && res > 0) {
00295          /* This should never happen */
00296          ast_log(LOG_ERROR, "Inotify read less than a full event (%zd < %zd)?!!\n", res, sizeof(buf.iev));
00297          break;
00298       } else if (res < 0) {
00299          if (errno == EINTR || errno == EAGAIN) {
00300             /* If read fails, try again */
00301             AST_LIST_LOCK(&zonelist);
00302             ast_cond_broadcast(&initialization);
00303             AST_LIST_UNLOCK(&zonelist);
00304             continue;
00305          }
00306          /* Sanity check -- this should never happen, either */
00307          ast_log(LOG_ERROR, "Inotify failed: %s\n", strerror(errno));
00308          break;
00309       }
00310       AST_LIST_LOCK(&zonelist);
00311       AST_LIST_TRAVERSE_SAFE_BEGIN(&zonelist, cur, list) {
00312          if (cur->wd[0] == buf.iev.wd || cur->wd[1] == buf.iev.wd) {
00313             AST_LIST_REMOVE_CURRENT(list);
00314             ast_free(cur);
00315             break;
00316          }
00317       }
00318       AST_LIST_TRAVERSE_SAFE_END
00319       ast_cond_broadcast(&initialization);
00320       AST_LIST_UNLOCK(&zonelist);
00321    }
00322    close(inotify_fd);
00323    inotify_thread = AST_PTHREADT_NULL;
00324    return NULL;
00325 }
00326 
00327 static void add_notify(struct state *sp, const char *path)
00328 {
00329    if (inotify_thread == AST_PTHREADT_NULL) {
00330       ast_cond_init(&initialization, NULL);
00331       ast_mutex_init(&initialization_lock);
00332       ast_mutex_lock(&initialization_lock);
00333       if (!(ast_pthread_create_background(&inotify_thread, NULL, inotify_daemon, NULL))) {
00334          /* Give the thread a chance to initialize */
00335          ast_cond_wait(&initialization, &initialization_lock);
00336       } else {
00337          fprintf(stderr, "Unable to start notification thread\n");
00338          ast_mutex_unlock(&initialization_lock);
00339          return;
00340       }
00341       ast_mutex_unlock(&initialization_lock);
00342    }
00343 
00344    if (inotify_fd > -1) {
00345       char fullpath[FILENAME_MAX + 1] = "";
00346       if (readlink(path, fullpath, sizeof(fullpath) - 1) != -1) {
00347          /* If file the symlink points to changes */
00348          sp->wd[1] = inotify_add_watch(inotify_fd, fullpath, IN_ATTRIB | IN_DELETE_SELF | IN_MODIFY | IN_MOVE_SELF | IN_CLOSE_WRITE );
00349       } else {
00350          sp->wd[1] = -1;
00351       }
00352       /* or if the symlink itself changes (or the real file is here, if path is not a symlink) */
00353       sp->wd[0] = inotify_add_watch(inotify_fd, path, IN_ATTRIB | IN_DELETE_SELF | IN_MODIFY | IN_MOVE_SELF | IN_CLOSE_WRITE
00354 #ifdef IN_DONT_FOLLOW   /* Only defined in glibc 2.5 and above */
00355          | IN_DONT_FOLLOW
00356 #endif
00357       );
00358    }
00359 }
00360 #elif defined(HAVE_KQUEUE)
00361 static int queue_fd = -1;
00362 
00363 static void *kqueue_daemon(void *data)
00364 {
00365    struct kevent kev;
00366    struct state *sp;
00367    struct timespec no_wait = { 0, 1 };
00368 
00369    ast_mutex_lock(&initialization_lock);
00370    if ((queue_fd = kqueue()) < 0) {
00371       /* ast_log uses us to format messages, so if we called ast_log, we'd be
00372        * in for a nasty loop (seen already in testing) */
00373       fprintf(stderr, "Unable to initialize kqueue(): %s\n", strerror(errno));
00374       inotify_thread = AST_PTHREADT_NULL;
00375 
00376       /* Okay to proceed */
00377       ast_cond_signal(&initialization);
00378       ast_mutex_unlock(&initialization_lock);
00379       return NULL;
00380    }
00381 
00382    ast_cond_signal(&initialization);
00383    ast_mutex_unlock(&initialization_lock);
00384 
00385    for (;/*ever*/;) {
00386       if (kevent(queue_fd, NULL, 0, &kev, 1, NULL) < 0) {
00387          AST_LIST_LOCK(&zonelist);
00388          ast_cond_broadcast(&initialization);
00389          AST_LIST_UNLOCK(&zonelist);
00390          continue;
00391       }
00392 
00393       sp = kev.udata;
00394 
00395       /*!\note
00396        * If the file event fired, then the file was removed, so we'll need
00397        * to reparse the entry.  The directory event is a bit more
00398        * interesting.  Unfortunately, the queue doesn't contain information
00399        * about the file that changed (only the directory itself), so unless
00400        * we kept a record of the directory state before, it's not really
00401        * possible to know what change occurred.  But if we act paranoid and
00402        * just purge the associated file, then it will get reparsed, and
00403        * everything works fine.  It may be more work, but it's a vast
00404        * improvement over the alternative implementation, which is to stat
00405        * the file repeatedly in what is essentially a busy loop. */
00406       AST_LIST_LOCK(&zonelist);
00407       AST_LIST_REMOVE(&zonelist, sp, list);
00408       AST_LIST_UNLOCK(&zonelist);
00409 
00410       /* If the directory event fired, remove the file event */
00411       EV_SET(&kev, sp->fd, EVFILT_VNODE, EV_DELETE, 0, 0, NULL);
00412       kevent(queue_fd, &kev, 1, NULL, 0, &no_wait);
00413       close(sp->fd);
00414 
00415 #ifdef HAVE_O_SYMLINK
00416       if (sp->fds > -1) {
00417          /* If the file event fired, remove the symlink event */
00418          EV_SET(&kev, sp->fds, EVFILT_VNODE, EV_DELETE, 0, 0, NULL);
00419          kevent(queue_fd, &kev, 1, NULL, 0, &no_wait);
00420          close(sp->fds);
00421       }
00422 #else
00423       if (sp->dir) {
00424          /* If the file event fired, remove the directory event */
00425          EV_SET(&kev, dirfd(sp->dir), EVFILT_VNODE, EV_DELETE, 0, 0, NULL);
00426          kevent(queue_fd, &kev, 1, NULL, 0, &no_wait);
00427          closedir(sp->dir);
00428       }
00429 #endif
00430       free(sp);
00431 
00432       /* Just in case the signal was sent late */
00433       AST_LIST_LOCK(&zonelist);
00434       ast_cond_broadcast(&initialization);
00435       AST_LIST_UNLOCK(&zonelist);
00436    }
00437 }
00438 
00439 static void add_notify(struct state *sp, const char *path)
00440 {
00441    struct kevent kev;
00442    struct timespec no_wait = { 0, 1 };
00443    char watchdir[PATH_MAX + 1] = "";
00444 
00445    if (inotify_thread == AST_PTHREADT_NULL) {
00446       ast_cond_init(&initialization, NULL);
00447       ast_mutex_init(&initialization_lock);
00448       ast_mutex_lock(&initialization_lock);
00449       if (!(ast_pthread_create_background(&inotify_thread, NULL, kqueue_daemon, NULL))) {
00450          /* Give the thread a chance to initialize */
00451          ast_cond_wait(&initialization, &initialization_lock);
00452       }
00453       ast_mutex_unlock(&initialization_lock);
00454    }
00455 
00456    if (queue_fd < 0) {
00457       /* Error already sent */
00458       return;
00459    }
00460 
00461 #ifdef HAVE_O_SYMLINK
00462    if (readlink(path, watchdir, sizeof(watchdir) - 1) != -1 && (sp->fds = open(path, O_RDONLY | O_SYMLINK
00463 # ifdef HAVE_O_EVTONLY
00464          | O_EVTONLY
00465 # endif
00466          )) >= 0) {
00467       EV_SET(&kev, sp->fds, EVFILT_VNODE, EV_ADD | EV_ENABLE | EV_ONESHOT, NOTE_WRITE | NOTE_EXTEND | NOTE_DELETE | NOTE_REVOKE | NOTE_ATTRIB, 0, sp);
00468       if (kevent(queue_fd, &kev, 1, NULL, 0, &no_wait) < 0 && errno != 0) {
00469          /* According to the API docs, we may get -1 return value, due to the
00470           * NULL space for a returned event, but errno should be 0 unless
00471           * there's a real error. Otherwise, kevent will return 0 to indicate
00472           * that the time limit expired. */
00473          fprintf(stderr, "Unable to watch '%s': %s\n", path, strerror(errno));
00474          close(sp->fds);
00475          sp->fds = -1;
00476       }
00477    }
00478 #else
00479    if (readlink(path, watchdir, sizeof(watchdir) - 1) != -1) {
00480       /* Special -- watch the directory for changes, because we cannot directly watch a symlink */
00481       char *slash;
00482 
00483       ast_copy_string(watchdir, path, sizeof(watchdir));
00484 
00485       if ((slash = strrchr(watchdir, '/'))) {
00486          *slash = '\0';
00487       }
00488       if (!(sp->dir = opendir(watchdir))) {
00489          fprintf(stderr, "Unable to watch directory with symlink '%s': %s\n", path, strerror(errno));
00490          goto watch_file;
00491       }
00492 
00493       /*!\note
00494        * You may be wondering about whether there is a potential conflict
00495        * with the kqueue interface, because we might be watching the same
00496        * directory for multiple zones.  The answer is no, because kqueue
00497        * looks at the descriptor to know if there's a duplicate.  Since we
00498        * (may) have opened the directory multiple times, each represents a
00499        * different event, so no replacement of an existing event will occur.
00500        * Likewise, there's no potential leak of a descriptor.
00501        */
00502       EV_SET(&kev, dirfd(sp->dir), EVFILT_VNODE, EV_ADD | EV_ENABLE | EV_ONESHOT,
00503             NOTE_DELETE | NOTE_WRITE | NOTE_EXTEND | NOTE_REVOKE | NOTE_ATTRIB, 0, sp);
00504       if (kevent(queue_fd, &kev, 1, NULL, 0, &no_wait) < 0 && errno != 0) {
00505          fprintf(stderr, "Unable to watch '%s': %s\n", watchdir, strerror(errno));
00506          closedir(sp->dir);
00507          sp->dir = NULL;
00508       }
00509    }
00510 
00511 watch_file:
00512 #endif
00513 
00514    if ((sp->fd = open(path, O_RDONLY
00515 # ifdef HAVE_O_EVTONLY
00516          | O_EVTONLY
00517 # endif
00518          )) < 0) {
00519       fprintf(stderr, "Unable to watch '%s' for changes: %s\n", path, strerror(errno));
00520       return;
00521    }
00522 
00523    EV_SET(&kev, sp->fd, EVFILT_VNODE, EV_ADD | EV_ENABLE | EV_ONESHOT, NOTE_WRITE | NOTE_EXTEND | NOTE_DELETE | NOTE_REVOKE | NOTE_ATTRIB, 0, sp);
00524    if (kevent(queue_fd, &kev, 1, NULL, 0, &no_wait) < 0 && errno != 0) {
00525       /* According to the API docs, we may get -1 return value, due to the
00526        * NULL space for a returned event, but errno should be 0 unless
00527        * there's a real error. Otherwise, kevent will return 0 to indicate
00528        * that the time limit expired. */
00529       fprintf(stderr, "Unable to watch '%s': %s\n", path, strerror(errno));
00530       close(sp->fd);
00531       sp->fd = -1;
00532    }
00533 }
00534 #else
00535 static void *notify_daemon(void *data)
00536 {
00537    struct stat st, lst;
00538    struct state *cur;
00539    struct timespec sixty_seconds = { 60, 0 };
00540 
00541    ast_mutex_lock(&initialization_lock);
00542    ast_cond_broadcast(&initialization);
00543    ast_mutex_unlock(&initialization_lock);
00544 
00545    for (;/*ever*/;) {
00546       char     fullname[FILENAME_MAX + 1];
00547 
00548       nanosleep(&sixty_seconds, NULL);
00549       AST_LIST_LOCK(&zonelist);
00550       AST_LIST_TRAVERSE_SAFE_BEGIN(&zonelist, cur, list) {
00551          char *name = cur->name;
00552 
00553          if (name[0] == ':')
00554             ++name;
00555          if (name[0] != '/') {
00556             (void) strcpy(fullname, TZDIR "/");
00557             (void) strcat(fullname, name);
00558             name = fullname;
00559          }
00560          stat(name, &st);
00561          lstat(name, &lst);
00562          if (st.st_mtime > cur->mtime[0] || lst.st_mtime > cur->mtime[1]) {
00563 #ifdef TEST_FRAMEWORK
00564             if (test) {
00565                ast_test_status_update(test, "Removing cached TZ entry '%s' because underlying file changed. (%ld != %ld) or (%ld != %ld)\n", name, st.st_mtime, cur->mtime[0], lst.st_mtime, cur->mtime[1]);
00566             } else
00567 #endif
00568             {
00569                ast_log(LOG_NOTICE, "Removing cached TZ entry '%s' because underlying file changed.\n", name);
00570             }
00571             AST_LIST_REMOVE_CURRENT(list);
00572             ast_free(cur);
00573             continue;
00574          }
00575       }
00576       AST_LIST_TRAVERSE_SAFE_END
00577       ast_cond_broadcast(&initialization);
00578       AST_LIST_UNLOCK(&zonelist);
00579    }
00580    inotify_thread = AST_PTHREADT_NULL;
00581    return NULL;
00582 }
00583 
00584 static void add_notify(struct state *sp, const char *path)
00585 {
00586    struct stat st;
00587 
00588    if (inotify_thread == AST_PTHREADT_NULL) {
00589       ast_cond_init(&initialization, NULL);
00590       ast_mutex_init(&initialization_lock);
00591       ast_mutex_lock(&initialization_lock);
00592       if (!(ast_pthread_create_background(&inotify_thread, NULL, notify_daemon, NULL))) {
00593          /* Give the thread a chance to initialize */
00594          ast_cond_wait(&initialization, &initialization_lock);
00595       }
00596       ast_mutex_unlock(&initialization_lock);
00597    }
00598 
00599    stat(path, &st);
00600    sp->mtime[0] = st.st_mtime;
00601    lstat(path, &st);
00602    sp->mtime[1] = st.st_mtime;
00603 }
00604 #endif
00605 
00606 void ast_localtime_wakeup_monitor(struct ast_test *info)
00607 {
00608    if (inotify_thread != AST_PTHREADT_NULL) {
00609       AST_LIST_LOCK(&zonelist);
00610 #ifdef TEST_FRAMEWORK
00611       test = info;
00612 #endif
00613       pthread_kill(inotify_thread, SIGURG);
00614       ast_cond_wait(&initialization, &(&zonelist)->lock);
00615 #ifdef TEST_FRAMEWORK
00616       test = NULL;
00617 #endif
00618       AST_LIST_UNLOCK(&zonelist);
00619    }
00620 }
00621 
00622 /*! \note
00623 ** Section 4.12.3 of X3.159-1989 requires that
00624 ** Except for the strftime function, these functions [asctime,
00625 ** ctime, gmtime, localtime] return values in one of two static
00626 ** objects: a broken-down time structure and an array of char.
00627 ** Thanks to Paul Eggert for noting this.
00628 */
00629 
00630 static long detzcode(const char * const codep)
00631 {
00632    long  result;
00633    int   i;
00634 
00635    result = (codep[0] & 0x80) ? ~0L : 0;
00636    for (i = 0; i < 4; ++i)
00637       result = (result << 8) | (codep[i] & 0xff);
00638    return result;
00639 }
00640 
00641 static time_t detzcode64(const char * const codep)
00642 {
00643    time_t   result;
00644    int   i;
00645 
00646    result = (codep[0] & 0x80) ?  (~(int_fast64_t) 0) : 0;
00647    for (i = 0; i < 8; ++i)
00648       result = result * 256 + (codep[i] & 0xff);
00649    return result;
00650 }
00651 
00652 static int differ_by_repeat(const time_t t1, const time_t t0)
00653 {
00654    const long long at1 = t1, at0 = t0;
00655    if (TYPE_INTEGRAL(time_t) &&
00656       TYPE_BIT(time_t) - TYPE_SIGNED(time_t) < SECSPERREPEAT_BITS)
00657          return 0;
00658    return at1 - at0 == SECSPERREPEAT;
00659 }
00660 
00661 static int tzload(const char *name, struct state * const sp, const int doextend)
00662 {
00663    const char *      p;
00664    int         i;
00665    int         fid;
00666    int         stored;
00667    int         nread;
00668    union {
00669       struct tzhead  tzhead;
00670       char     buf[2 * sizeof(struct tzhead) +
00671                2 * sizeof *sp +
00672                4 * TZ_MAX_TIMES];
00673    } u;
00674 
00675    if (name == NULL && (name = TZDEFAULT) == NULL)
00676       return -1;
00677    {
00678       int   doaccess;
00679       /*
00680       ** Section 4.9.1 of the C standard says that
00681       ** "FILENAME_MAX expands to an integral constant expression
00682       ** that is the size needed for an array of char large enough
00683       ** to hold the longest file name string that the implementation
00684       ** guarantees can be opened."
00685       */
00686       char     fullname[FILENAME_MAX + 1];
00687 
00688       if (name[0] == ':')
00689          ++name;
00690       doaccess = name[0] == '/';
00691       if (!doaccess) {
00692          if ((p = TZDIR) == NULL)
00693             return -1;
00694          if ((strlen(p) + strlen(name) + 1) >= sizeof fullname)
00695             return -1;
00696          (void) strcpy(fullname, p);
00697          (void) strcat(fullname, "/");
00698          (void) strcat(fullname, name);
00699          /*
00700          ** Set doaccess if '.' (as in "../") shows up in name.
00701          */
00702          if (strchr(name, '.') != NULL)
00703             doaccess = TRUE;
00704          name = fullname;
00705       }
00706       if (doaccess && access(name, R_OK) != 0)
00707          return -1;
00708       if ((fid = open(name, OPEN_MODE)) == -1)
00709          return -1;
00710       add_notify(sp, name);
00711    }
00712    nread = read(fid, u.buf, sizeof u.buf);
00713    if (close(fid) < 0 || nread <= 0)
00714       return -1;
00715    for (stored = 4; stored <= 8; stored *= 2) {
00716       int      ttisstdcnt;
00717       int      ttisgmtcnt;
00718 
00719       ttisstdcnt = (int) detzcode(u.tzhead.tzh_ttisstdcnt);
00720       ttisgmtcnt = (int) detzcode(u.tzhead.tzh_ttisgmtcnt);
00721       sp->leapcnt = (int) detzcode(u.tzhead.tzh_leapcnt);
00722       sp->timecnt = (int) detzcode(u.tzhead.tzh_timecnt);
00723       sp->typecnt = (int) detzcode(u.tzhead.tzh_typecnt);
00724       sp->charcnt = (int) detzcode(u.tzhead.tzh_charcnt);
00725       p = u.tzhead.tzh_charcnt + sizeof u.tzhead.tzh_charcnt;
00726       if (sp->leapcnt < 0 || sp->leapcnt > TZ_MAX_LEAPS ||
00727          sp->typecnt <= 0 || sp->typecnt > TZ_MAX_TYPES ||
00728          sp->timecnt < 0 || sp->timecnt > TZ_MAX_TIMES ||
00729          sp->charcnt < 0 || sp->charcnt > TZ_MAX_CHARS ||
00730          (ttisstdcnt != sp->typecnt && ttisstdcnt != 0) ||
00731          (ttisgmtcnt != sp->typecnt && ttisgmtcnt != 0))
00732             return -1;
00733       if (nread - (p - u.buf) <
00734          sp->timecnt * stored +     /* ats */
00735          sp->timecnt +        /* types */
00736          sp->typecnt * 6 +    /* ttinfos */
00737          sp->charcnt +        /* chars */
00738          sp->leapcnt * (stored + 4) +  /* lsinfos */
00739          ttisstdcnt +         /* ttisstds */
00740          ttisgmtcnt)       /* ttisgmts */
00741             return -1;
00742       for (i = 0; i < sp->timecnt; ++i) {
00743          sp->ats[i] = (stored == 4) ?
00744             detzcode(p) : detzcode64(p);
00745          p += stored;
00746       }
00747       for (i = 0; i < sp->timecnt; ++i) {
00748          sp->types[i] = (unsigned char) *p++;
00749          if (sp->types[i] >= sp->typecnt)
00750             return -1;
00751       }
00752       for (i = 0; i < sp->typecnt; ++i) {
00753          struct ttinfo *   ttisp;
00754 
00755          ttisp = &sp->ttis[i];
00756          ttisp->tt_gmtoff = detzcode(p);
00757          p += 4;
00758          ttisp->tt_isdst = (unsigned char) *p++;
00759          if (ttisp->tt_isdst != 0 && ttisp->tt_isdst != 1)
00760             return -1;
00761          ttisp->tt_abbrind = (unsigned char) *p++;
00762          if (ttisp->tt_abbrind < 0 ||
00763             ttisp->tt_abbrind > sp->charcnt)
00764                return -1;
00765       }
00766       for (i = 0; i < sp->charcnt; ++i)
00767          sp->chars[i] = *p++;
00768       sp->chars[i] = '\0'; /* ensure '\0' at end */
00769       for (i = 0; i < sp->leapcnt; ++i) {
00770          struct lsinfo *   lsisp;
00771 
00772          lsisp = &sp->lsis[i];
00773          lsisp->ls_trans = (stored == 4) ?
00774             detzcode(p) : detzcode64(p);
00775          p += stored;
00776          lsisp->ls_corr = detzcode(p);
00777          p += 4;
00778       }
00779       for (i = 0; i < sp->typecnt; ++i) {
00780          struct ttinfo *   ttisp;
00781 
00782          ttisp = &sp->ttis[i];
00783          if (ttisstdcnt == 0)
00784             ttisp->tt_ttisstd = FALSE;
00785          else {
00786             ttisp->tt_ttisstd = *p++;
00787             if (ttisp->tt_ttisstd != TRUE &&
00788                ttisp->tt_ttisstd != FALSE)
00789                   return -1;
00790          }
00791       }
00792       for (i = 0; i < sp->typecnt; ++i) {
00793          struct ttinfo *   ttisp;
00794 
00795          ttisp = &sp->ttis[i];
00796          if (ttisgmtcnt == 0)
00797             ttisp->tt_ttisgmt = FALSE;
00798          else {
00799             ttisp->tt_ttisgmt = *p++;
00800             if (ttisp->tt_ttisgmt != TRUE &&
00801                ttisp->tt_ttisgmt != FALSE)
00802                   return -1;
00803          }
00804       }
00805       /*
00806       ** Out-of-sort ats should mean we're running on a
00807       ** signed time_t system but using a data file with
00808       ** unsigned values (or vice versa).
00809       */
00810       for (i = 0; i < sp->timecnt - 2; ++i)
00811          if (sp->ats[i] > sp->ats[i + 1]) {
00812             ++i;
00813             if (TYPE_SIGNED(time_t)) {
00814                /*
00815                ** Ignore the end (easy).
00816                */
00817                sp->timecnt = i;
00818             } else {
00819                /*
00820                ** Ignore the beginning (harder).
00821                */
00822                int   j;
00823 
00824                for (j = 0; j + i < sp->timecnt; ++j) {
00825                   sp->ats[j] = sp->ats[j + i];
00826                   sp->types[j] = sp->types[j + i];
00827                }
00828                sp->timecnt = j;
00829             }
00830             break;
00831          }
00832       /*
00833       ** If this is an old file, we're done.
00834       */
00835       if (u.tzhead.tzh_version[0] == '\0')
00836          break;
00837       nread -= p - u.buf;
00838       for (i = 0; i < nread; ++i)
00839          u.buf[i] = p[i];
00840       /*
00841       ** If this is a narrow integer time_t system, we're done.
00842       */
00843       if (stored >= (int) sizeof(time_t) && TYPE_INTEGRAL(time_t))
00844          break;
00845    }
00846    if (doextend && nread > 2 &&
00847       u.buf[0] == '\n' && u.buf[nread - 1] == '\n' &&
00848       sp->typecnt + 2 <= TZ_MAX_TYPES) {
00849          struct state   ts;
00850          int   result;
00851 
00852          u.buf[nread - 1] = '\0';
00853          result = tzparse(&u.buf[1], &ts, FALSE);
00854          if (result == 0 && ts.typecnt == 2 &&
00855             sp->charcnt + ts.charcnt <= TZ_MAX_CHARS) {
00856                for (i = 0; i < 2; ++i)
00857                   ts.ttis[i].tt_abbrind +=
00858                      sp->charcnt;
00859                for (i = 0; i < ts.charcnt; ++i)
00860                   sp->chars[sp->charcnt++] =
00861                      ts.chars[i];
00862                i = 0;
00863                while (i < ts.timecnt &&
00864                   ts.ats[i] <=
00865                   sp->ats[sp->timecnt - 1])
00866                      ++i;
00867                while (i < ts.timecnt &&
00868                    sp->timecnt < TZ_MAX_TIMES) {
00869                   sp->ats[sp->timecnt] =
00870                      ts.ats[i];
00871                   sp->types[sp->timecnt] =
00872                      sp->typecnt +
00873                      ts.types[i];
00874                   ++sp->timecnt;
00875                   ++i;
00876                }
00877                sp->ttis[sp->typecnt++] = ts.ttis[0];
00878                sp->ttis[sp->typecnt++] = ts.ttis[1];
00879          }
00880    }
00881    i = 2 * YEARSPERREPEAT;
00882    sp->goback = sp->goahead = sp->timecnt > i;
00883    sp->goback = sp->goback && sp->types[i] == sp->types[0] &&
00884       differ_by_repeat(sp->ats[i], sp->ats[0]);
00885    sp->goahead = sp->goahead &&
00886       sp->types[sp->timecnt - 1] == sp->types[sp->timecnt - 1 - i] &&
00887       differ_by_repeat(sp->ats[sp->timecnt - 1],
00888           sp->ats[sp->timecnt - 1 - i]);
00889    return 0;
00890 }
00891 
00892 static const int  mon_lengths[2][MONSPERYEAR] = {
00893    { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
00894    { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
00895 };
00896 
00897 static const int  year_lengths[2] = {
00898    DAYSPERNYEAR, DAYSPERLYEAR
00899 };
00900 
00901 /*! \brief
00902 ** Given a pointer into a time zone string, scan until a character that is not
00903 ** a valid character in a zone name is found. Return a pointer to that
00904 ** character.
00905 */
00906 
00907 static const char * getzname(const char *strp)
00908 {
00909    char  c;
00910 
00911    while ((c = *strp) != '\0' && !is_digit(c) && c != ',' && c != '-' &&
00912       c != '+')
00913          ++strp;
00914    return strp;
00915 }
00916 
00917 /*! \brief
00918 ** Given a pointer into an extended time zone string, scan until the ending
00919 ** delimiter of the zone name is located. Return a pointer to the delimiter.
00920 **
00921 ** As with getzname above, the legal character set is actually quite
00922 ** restricted, with other characters producing undefined results.
00923 ** We don't do any checking here; checking is done later in common-case code.
00924 */
00925 
00926 static const char * getqzname(const char *strp, const int delim)
00927 {
00928    int   c;
00929 
00930    while ((c = *strp) != '\0' && c != delim)
00931       ++strp;
00932    return strp;
00933 }
00934 
00935 /*! \brief
00936 ** Given a pointer into a time zone string, extract a number from that string.
00937 ** Check that the number is within a specified range; if it is not, return
00938 ** NULL.
00939 ** Otherwise, return a pointer to the first character not part of the number.
00940 */
00941 
00942 static const char *getnum(const char *strp, int *nump, const int min, const int max)
00943 {
00944    char  c;
00945    int   num;
00946 
00947    if (strp == NULL || !is_digit(c = *strp))
00948       return NULL;
00949    num = 0;
00950    do {
00951       num = num * 10 + (c - '0');
00952       if (num > max)
00953          return NULL;   /* illegal value */
00954       c = *++strp;
00955    } while (is_digit(c));
00956    if (num < min)
00957       return NULL;      /* illegal value */
00958    *nump = num;
00959    return strp;
00960 }
00961 
00962 /*! \brief
00963 ** Given a pointer into a time zone string, extract a number of seconds,
00964 ** in hh[:mm[:ss]] form, from the string.
00965 ** If any error occurs, return NULL.
00966 ** Otherwise, return a pointer to the first character not part of the number
00967 ** of seconds.
00968 */
00969 
00970 static const char *getsecs(const char *strp, long * const secsp)
00971 {
00972    int   num;
00973 
00974    /*
00975    ** `HOURSPERDAY * DAYSPERWEEK - 1' allows quasi-Posix rules like
00976    ** "M10.4.6/26", which does not conform to Posix,
00977    ** but which specifies the equivalent of
00978    ** ``02:00 on the first Sunday on or after 23 Oct''.
00979    */
00980    strp = getnum(strp, &num, 0, HOURSPERDAY * DAYSPERWEEK - 1);
00981    if (strp == NULL)
00982       return NULL;
00983    *secsp = num * (long) SECSPERHOUR;
00984    if (*strp == ':') {
00985       ++strp;
00986       strp = getnum(strp, &num, 0, MINSPERHOUR - 1);
00987       if (strp == NULL)
00988          return NULL;
00989       *secsp += num * SECSPERMIN;
00990       if (*strp == ':') {
00991          ++strp;
00992          /* `SECSPERMIN' allows for leap seconds. */
00993          strp = getnum(strp, &num, 0, SECSPERMIN);
00994          if (strp == NULL)
00995             return NULL;
00996          *secsp += num;
00997       }
00998    }
00999    return strp;
01000 }
01001 
01002 /*! \brief
01003 ** Given a pointer into a time zone string, extract an offset, in
01004 ** [+-]hh[:mm[:ss]] form, from the string.
01005 ** If any error occurs, return NULL.
01006 ** Otherwise, return a pointer to the first character not part of the time.
01007 */
01008 
01009 static const char *getoffset(const char *strp, long *offsetp)
01010 {
01011    int   neg = 0;
01012 
01013    if (*strp == '-') {
01014       neg = 1;
01015       ++strp;
01016    } else if (*strp == '+')
01017       ++strp;
01018    strp = getsecs(strp, offsetp);
01019    if (strp == NULL)
01020       return NULL;      /* illegal time */
01021    if (neg)
01022       *offsetp = -*offsetp;
01023    return strp;
01024 }
01025 
01026 /*! \brief
01027 ** Given a pointer into a time zone string, extract a rule in the form
01028 ** date[/time]. See POSIX section 8 for the format of "date" and "time".
01029 ** If a valid rule is not found, return NULL.
01030 ** Otherwise, return a pointer to the first character not part of the rule.
01031 */
01032 
01033 static const char *getrule(const char *strp, struct rule *rulep)
01034 {
01035    if (*strp == 'J') {
01036       /*
01037       ** Julian day.
01038       */
01039       rulep->r_type = JULIAN_DAY;
01040       ++strp;
01041       strp = getnum(strp, &rulep->r_day, 1, DAYSPERNYEAR);
01042    } else if (*strp == 'M') {
01043       /*
01044       ** Month, week, day.
01045       */
01046       rulep->r_type = MONTH_NTH_DAY_OF_WEEK;
01047       ++strp;
01048       strp = getnum(strp, &rulep->r_mon, 1, MONSPERYEAR);
01049       if (strp == NULL)
01050          return NULL;
01051       if (*strp++ != '.')
01052          return NULL;
01053       strp = getnum(strp, &rulep->r_week, 1, 5);
01054       if (strp == NULL)
01055          return NULL;
01056       if (*strp++ != '.')
01057          return NULL;
01058       strp = getnum(strp, &rulep->r_day, 0, DAYSPERWEEK - 1);
01059    } else if (is_digit(*strp)) {
01060       /*
01061       ** Day of year.
01062       */
01063       rulep->r_type = DAY_OF_YEAR;
01064       strp = getnum(strp, &rulep->r_day, 0, DAYSPERLYEAR - 1);
01065    } else   return NULL;      /* invalid format */
01066    if (strp == NULL)
01067       return NULL;
01068    if (*strp == '/') {
01069       /*
01070       ** Time specified.
01071       */
01072       ++strp;
01073       strp = getsecs(strp, &rulep->r_time);
01074    } else   rulep->r_time = 2 * SECSPERHOUR; /* default = 2:00:00 */
01075    return strp;
01076 }
01077 
01078 /*! \brief
01079 ** Given the Epoch-relative time of January 1, 00:00:00 UTC, in a year, the
01080 ** year, a rule, and the offset from UTC at the time that rule takes effect,
01081 ** calculate the Epoch-relative time that rule takes effect.
01082 */
01083 
01084 static time_t transtime(const time_t janfirst, const int year, const struct rule *rulep, const long offset)
01085 {
01086    int   leapyear;
01087    time_t   value;
01088    int   i;
01089    int      d, m1, yy0, yy1, yy2, dow;
01090 
01091    INITIALIZE(value);
01092    leapyear = isleap(year);
01093    switch (rulep->r_type) {
01094 
01095    case JULIAN_DAY:
01096       /*
01097       ** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap
01098       ** years.
01099       ** In non-leap years, or if the day number is 59 or less, just
01100       ** add SECSPERDAY times the day number-1 to the time of
01101       ** January 1, midnight, to get the day.
01102       */
01103       value = janfirst + (rulep->r_day - 1) * SECSPERDAY;
01104       if (leapyear && rulep->r_day >= 60)
01105          value += SECSPERDAY;
01106       break;
01107 
01108    case DAY_OF_YEAR:
01109       /*
01110       ** n - day of year.
01111       ** Just add SECSPERDAY times the day number to the time of
01112       ** January 1, midnight, to get the day.
01113       */
01114       value = janfirst + rulep->r_day * SECSPERDAY;
01115       break;
01116 
01117    case MONTH_NTH_DAY_OF_WEEK:
01118       /*
01119       ** Mm.n.d - nth "dth day" of month m.
01120       */
01121       value = janfirst;
01122       for (i = 0; i < rulep->r_mon - 1; ++i)
01123          value += mon_lengths[leapyear][i] * SECSPERDAY;
01124 
01125       /*
01126       ** Use Zeller's Congruence to get day-of-week of first day of
01127       ** month.
01128       */
01129       m1 = (rulep->r_mon + 9) % 12 + 1;
01130       yy0 = (rulep->r_mon <= 2) ? (year - 1) : year;
01131       yy1 = yy0 / 100;
01132       yy2 = yy0 % 100;
01133       dow = ((26 * m1 - 2) / 10 +
01134          1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7;
01135       if (dow < 0)
01136          dow += DAYSPERWEEK;
01137 
01138       /*
01139       ** "dow" is the day-of-week of the first day of the month. Get
01140       ** the day-of-month (zero-origin) of the first "dow" day of the
01141       ** month.
01142       */
01143       d = rulep->r_day - dow;
01144       if (d < 0)
01145          d += DAYSPERWEEK;
01146       for (i = 1; i < rulep->r_week; ++i) {
01147          if (d + DAYSPERWEEK >=
01148             mon_lengths[leapyear][rulep->r_mon - 1])
01149                break;
01150          d += DAYSPERWEEK;
01151       }
01152 
01153       /*
01154       ** "d" is the day-of-month (zero-origin) of the day we want.
01155       */
01156       value += d * SECSPERDAY;
01157       break;
01158    }
01159 
01160    /*
01161    ** "value" is the Epoch-relative time of 00:00:00 UTC on the day in
01162    ** question. To get the Epoch-relative time of the specified local
01163    ** time on that day, add the transition time and the current offset
01164    ** from UTC.
01165    */
01166    return value + rulep->r_time + offset;
01167 }
01168 
01169 /*! \note
01170 ** Given a POSIX section 8-style TZ string, fill in the rule tables as
01171 ** appropriate.
01172 */
01173 
01174 static int tzparse(const char *name, struct state *sp, const int lastditch)
01175 {
01176    const char *         stdname;
01177    const char *         dstname;
01178    size_t            stdlen;
01179    size_t            dstlen;
01180    long           stdoffset;
01181    long           dstoffset;
01182    time_t *    atp;
01183    unsigned char *   typep;
01184    char *         cp;
01185    int         load_result;
01186 
01187    INITIALIZE(dstname);
01188    stdname = name;
01189    if (lastditch) {
01190       stdlen = strlen(name);  /* length of standard zone name */
01191       name += stdlen;
01192       if (stdlen >= sizeof sp->chars)
01193          stdlen = (sizeof sp->chars) - 1;
01194       stdoffset = 0;
01195    } else {
01196       if (*name == '<') {
01197          name++;
01198          stdname = name;
01199          name = getqzname(name, '>');
01200          if (*name != '>')
01201             return -1;
01202          stdlen = name - stdname;
01203          name++;
01204       } else {
01205          name = getzname(name);
01206          stdlen = name - stdname;
01207       }
01208       if (*name == '\0')
01209          return -1;
01210       name = getoffset(name, &stdoffset);
01211       if (name == NULL)
01212          return -1;
01213    }
01214    load_result = tzload(TZDEFRULES, sp, FALSE);
01215    if (load_result != 0)
01216       sp->leapcnt = 0;     /* so, we're off a little */
01217    if (*name != '\0') {
01218       if (*name == '<') {
01219          dstname = ++name;
01220          name = getqzname(name, '>');
01221          if (*name != '>')
01222             return -1;
01223          dstlen = name - dstname;
01224          name++;
01225       } else {
01226          dstname = name;
01227          name = getzname(name);
01228          dstlen = name - dstname; /* length of DST zone name */
01229       }
01230       if (*name != '\0' && *name != ',' && *name != ';') {
01231          name = getoffset(name, &dstoffset);
01232          if (name == NULL)
01233             return -1;
01234       } else   dstoffset = stdoffset - SECSPERHOUR;
01235       if (*name == '\0' && load_result != 0)
01236          name = TZDEFRULESTRING;
01237       if (*name == ',' || *name == ';') {
01238          struct rule start;
01239          struct rule end;
01240          int   year;
01241          time_t   janfirst;
01242          time_t      starttime;
01243          time_t      endtime;
01244 
01245          ++name;
01246          if ((name = getrule(name, &start)) == NULL)
01247             return -1;
01248          if (*name++ != ',')
01249             return -1;
01250          if ((name = getrule(name, &end)) == NULL)
01251             return -1;
01252          if (*name != '\0')
01253             return -1;
01254          sp->typecnt = 2;  /* standard time and DST */
01255          /*
01256          ** Two transitions per year, from EPOCH_YEAR forward.
01257          */
01258          sp->ttis[0].tt_gmtoff = -dstoffset;
01259          sp->ttis[0].tt_isdst = 1;
01260          sp->ttis[0].tt_abbrind = stdlen + 1;
01261          sp->ttis[1].tt_gmtoff = -stdoffset;
01262          sp->ttis[1].tt_isdst = 0;
01263          sp->ttis[1].tt_abbrind = 0;
01264          atp = sp->ats;
01265          typep = sp->types;
01266          janfirst = 0;
01267          sp->timecnt = 0;
01268          for (year = EPOCH_YEAR;
01269              sp->timecnt + 2 <= TZ_MAX_TIMES;
01270              ++year) {
01271                time_t   newfirst;
01272 
01273             starttime = transtime(janfirst, year, &start,
01274                stdoffset);
01275             endtime = transtime(janfirst, year, &end,
01276                dstoffset);
01277             if (starttime > endtime) {
01278                *atp++ = endtime;
01279                *typep++ = 1;  /* DST ends */
01280                *atp++ = starttime;
01281                *typep++ = 0;  /* DST begins */
01282             } else {
01283                *atp++ = starttime;
01284                *typep++ = 0;  /* DST begins */
01285                *atp++ = endtime;
01286                *typep++ = 1;  /* DST ends */
01287             }
01288             sp->timecnt += 2;
01289             newfirst = janfirst;
01290             newfirst += year_lengths[isleap(year)] *
01291                SECSPERDAY;
01292             if (newfirst <= janfirst)
01293                break;
01294             janfirst = newfirst;
01295          }
01296       } else {
01297          long  theirstdoffset;
01298          long  theirdstoffset;
01299          long  theiroffset;
01300          int   isdst;
01301          int   i;
01302          int   j;
01303 
01304          if (*name != '\0')
01305             return -1;
01306          /*
01307          ** Initial values of theirstdoffset and theirdstoffset.
01308          */
01309          theirstdoffset = 0;
01310          for (i = 0; i < sp->timecnt; ++i) {
01311             j = sp->types[i];
01312             if (!sp->ttis[j].tt_isdst) {
01313                theirstdoffset =
01314                   -sp->ttis[j].tt_gmtoff;
01315                break;
01316             }
01317          }
01318          theirdstoffset = 0;
01319          for (i = 0; i < sp->timecnt; ++i) {
01320             j = sp->types[i];
01321             if (sp->ttis[j].tt_isdst) {
01322                theirdstoffset =
01323                   -sp->ttis[j].tt_gmtoff;
01324                break;
01325             }
01326          }
01327          /*
01328          ** Initially we're assumed to be in standard time.
01329          */
01330          isdst = FALSE;
01331          theiroffset = theirstdoffset;
01332          /*
01333          ** Now juggle transition times and types
01334          ** tracking offsets as you do.
01335          */
01336          for (i = 0; i < sp->timecnt; ++i) {
01337             j = sp->types[i];
01338             sp->types[i] = sp->ttis[j].tt_isdst;
01339             if (sp->ttis[j].tt_ttisgmt) {
01340                /* No adjustment to transition time */
01341             } else {
01342                /*
01343                ** If summer time is in effect, and the
01344                ** transition time was not specified as
01345                ** standard time, add the summer time
01346                ** offset to the transition time;
01347                ** otherwise, add the standard time
01348                ** offset to the transition time.
01349                */
01350                /*
01351                ** Transitions from DST to DDST
01352                ** will effectively disappear since
01353                ** POSIX provides for only one DST
01354                ** offset.
01355                */
01356                if (isdst && !sp->ttis[j].tt_ttisstd) {
01357                   sp->ats[i] += dstoffset -
01358                      theirdstoffset;
01359                } else {
01360                   sp->ats[i] += stdoffset -
01361                      theirstdoffset;
01362                }
01363             }
01364             theiroffset = -sp->ttis[j].tt_gmtoff;
01365             if (sp->ttis[j].tt_isdst)
01366                theirdstoffset = theiroffset;
01367             else  theirstdoffset = theiroffset;
01368          }
01369          /*
01370          ** Finally, fill in ttis.
01371          ** ttisstd and ttisgmt need not be handled.
01372          */
01373          sp->ttis[0].tt_gmtoff = -stdoffset;
01374          sp->ttis[0].tt_isdst = FALSE;
01375          sp->ttis[0].tt_abbrind = 0;
01376          sp->ttis[1].tt_gmtoff = -dstoffset;
01377          sp->ttis[1].tt_isdst = TRUE;
01378          sp->ttis[1].tt_abbrind = stdlen + 1;
01379          sp->typecnt = 2;
01380       }
01381    } else {
01382       dstlen = 0;
01383       sp->typecnt = 1;     /* only standard time */
01384       sp->timecnt = 0;
01385       sp->ttis[0].tt_gmtoff = -stdoffset;
01386       sp->ttis[0].tt_isdst = 0;
01387       sp->ttis[0].tt_abbrind = 0;
01388    }
01389    sp->charcnt = stdlen + 1;
01390    if (dstlen != 0)
01391       sp->charcnt += dstlen + 1;
01392    if ((size_t) sp->charcnt > sizeof sp->chars)
01393       return -1;
01394    cp = sp->chars;
01395    (void) strncpy(cp, stdname, stdlen);
01396    cp += stdlen;
01397    *cp++ = '\0';
01398    if (dstlen != 0) {
01399       (void) strncpy(cp, dstname, dstlen);
01400       *(cp + dstlen) = '\0';
01401    }
01402    return 0;
01403 }
01404 
01405 static int gmtload(struct state *sp)
01406 {
01407    if (tzload(gmt, sp, TRUE) != 0)
01408       return tzparse(gmt, sp, TRUE);
01409    else
01410       return -1;
01411 }
01412 
01413 static const struct state *ast_tzset(const char *zone)
01414 {
01415    struct state *sp;
01416 
01417    if (ast_strlen_zero(zone)) {
01418 #ifdef SOLARIS
01419       zone = getenv("TZ");
01420       if (ast_strlen_zero(zone)) {
01421          zone = "GMT";
01422       }
01423 #else
01424       zone = "/etc/localtime";
01425 #endif
01426    }
01427 
01428    AST_LIST_LOCK(&zonelist);
01429    AST_LIST_TRAVERSE(&zonelist, sp, list) {
01430       if (!strcmp(sp->name, zone)) {
01431          AST_LIST_UNLOCK(&zonelist);
01432          return sp;
01433       }
01434    }
01435    AST_LIST_UNLOCK(&zonelist);
01436 
01437    if (!(sp = ast_calloc(1, sizeof *sp)))
01438       return NULL;
01439 
01440    if (tzload(zone, sp, TRUE) != 0) {
01441       if (zone[0] == ':' || tzparse(zone, sp, FALSE) != 0)
01442          (void) gmtload(sp);
01443    }
01444    ast_copy_string(sp->name, zone, sizeof(sp->name));
01445    AST_LIST_LOCK(&zonelist);
01446    AST_LIST_INSERT_TAIL(&zonelist, sp, list);
01447    AST_LIST_UNLOCK(&zonelist);
01448    return sp;
01449 }
01450 
01451 /*! \note
01452 ** The easy way to behave "as if no library function calls" localtime
01453 ** is to not call it--so we drop its guts into "localsub", which can be
01454 ** freely called. (And no, the PANS doesn't require the above behavior--
01455 ** but it *is* desirable.)
01456 **
01457 ** The unused offset argument is for the benefit of mktime variants.
01458 */
01459 
01460 static struct ast_tm *localsub(const struct timeval *timep, const long offset, struct ast_tm *tmp, const struct state *sp)
01461 {
01462    const struct ttinfo *   ttisp;
01463    int         i;
01464    struct ast_tm *      result;
01465    struct timeval t;
01466    memcpy(&t, timep, sizeof(t));
01467 
01468    if (sp == NULL)
01469       return gmtsub(timep, offset, tmp);
01470    if ((sp->goback && t.tv_sec < sp->ats[0]) ||
01471       (sp->goahead && t.tv_sec > sp->ats[sp->timecnt - 1])) {
01472          struct timeval newt = t;
01473          time_t      seconds;
01474          time_t      tcycles;
01475          int_fast64_t   icycles;
01476 
01477          if (t.tv_sec < sp->ats[0])
01478             seconds = sp->ats[0] - t.tv_sec;
01479          else  seconds = t.tv_sec - sp->ats[sp->timecnt - 1];
01480          --seconds;
01481          tcycles = seconds / YEARSPERREPEAT / AVGSECSPERYEAR;
01482          ++tcycles;
01483          icycles = tcycles;
01484          if (tcycles - icycles >= 1 || icycles - tcycles >= 1)
01485             return NULL;
01486          seconds = icycles;
01487          seconds *= YEARSPERREPEAT;
01488          seconds *= AVGSECSPERYEAR;
01489          if (t.tv_sec < sp->ats[0])
01490             newt.tv_sec += seconds;
01491          else  newt.tv_sec -= seconds;
01492          if (newt.tv_sec < sp->ats[0] ||
01493             newt.tv_sec > sp->ats[sp->timecnt - 1])
01494                return NULL;   /* "cannot happen" */
01495          result = localsub(&newt, offset, tmp, sp);
01496          if (result == tmp) {
01497             time_t   newy;
01498 
01499             newy = tmp->tm_year;
01500             if (t.tv_sec < sp->ats[0])
01501                newy -= icycles * YEARSPERREPEAT;
01502             else
01503                newy += icycles * YEARSPERREPEAT;
01504             tmp->tm_year = newy;
01505             if (tmp->tm_year != newy)
01506                return NULL;
01507          }
01508          return result;
01509    }
01510    if (sp->timecnt == 0 || t.tv_sec < sp->ats[0]) {
01511       i = 0;
01512       while (sp->ttis[i].tt_isdst) {
01513          if (++i >= sp->typecnt) {
01514             i = 0;
01515             break;
01516          }
01517       }
01518    } else {
01519       int   lo = 1;
01520       int   hi = sp->timecnt;
01521 
01522       while (lo < hi) {
01523          int   mid = (lo + hi) >> 1;
01524 
01525          if (t.tv_sec < sp->ats[mid])
01526             hi = mid;
01527          else
01528             lo = mid + 1;
01529       }
01530       i = (int) sp->types[lo - 1];
01531    }
01532    ttisp = &sp->ttis[i];
01533    /*
01534    ** To get (wrong) behavior that's compatible with System V Release 2.0
01535    ** you'd replace the statement below with
01536    ** t += ttisp->tt_gmtoff;
01537    ** timesub(&t, 0L, sp, tmp);
01538    */
01539    result = timesub(&t, ttisp->tt_gmtoff, sp, tmp);
01540    tmp->tm_isdst = ttisp->tt_isdst;
01541 #ifndef SOLARIS /* Solaris doesn't have this element */
01542    tmp->tm_gmtoff = ttisp->tt_gmtoff;
01543 #endif
01544 #ifdef TM_ZONE
01545    tmp->TM_ZONE = &sp->chars[ttisp->tt_abbrind];
01546 #endif /* defined TM_ZONE */
01547    tmp->tm_usec = timep->tv_usec;
01548    return result;
01549 }
01550 
01551 struct ast_tm *ast_localtime(const struct timeval *timep, struct ast_tm *tmp, const char *zone)
01552 {
01553    const struct state *sp = ast_tzset(zone);
01554    memset(tmp, 0, sizeof(*tmp));
01555    return sp ? localsub(timep, 0L, tmp, sp) : NULL;
01556 }
01557 
01558 /*
01559 ** This function provides informaton about daylight savings time 
01560 ** for the given timezone.  This includes whether it can determine 
01561 ** if daylight savings is used for this timezone, the UTC times for 
01562 ** when daylight savings transitions, and the offset in seconds from 
01563 ** UTC. 
01564 */
01565 
01566 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)
01567 {
01568    int i;   
01569    int transition1 = -1;
01570    int transition2 = -1;
01571    time_t      seconds;
01572    int  bounds_exceeded = 0;
01573    time_t  t = *timep;
01574    const struct state *sp;
01575    
01576    if (NULL == dst_enabled)
01577       return;
01578    *dst_enabled = 0;
01579 
01580    if (NULL == dst_start || NULL == dst_end || NULL == gmt_off)
01581       return;
01582 
01583    *gmt_off = 0; 
01584    
01585    sp = ast_tzset(zone);
01586    if (NULL == sp) 
01587       return;
01588    
01589    /* If the desired time exceeds the bounds of the defined time transitions  
01590    * then give give up on determining DST info and simply look for gmt offset 
01591    * This requires that I adjust the given time using increments of Gregorian 
01592    * repeats to place the time within the defined time transitions in the 
01593    * timezone structure.  
01594    */
01595    if ((sp->goback && t < sp->ats[0]) ||
01596          (sp->goahead && t > sp->ats[sp->timecnt - 1])) {
01597       time_t      tcycles;
01598       int_fast64_t   icycles;
01599 
01600       if (t < sp->ats[0])
01601          seconds = sp->ats[0] - t;
01602       else  seconds = t - sp->ats[sp->timecnt - 1];
01603       --seconds;
01604       tcycles = seconds / YEARSPERREPEAT / AVGSECSPERYEAR;
01605       ++tcycles;
01606       icycles = tcycles;
01607       if (tcycles - icycles >= 1 || icycles - tcycles >= 1)
01608          return;
01609       seconds = icycles;
01610       seconds *= YEARSPERREPEAT;
01611       seconds *= AVGSECSPERYEAR;
01612       if (t < sp->ats[0])
01613          t += seconds;
01614       else
01615          t -= seconds;
01616       
01617       if (t < sp->ats[0] || t > sp->ats[sp->timecnt - 1])
01618          return;  /* "cannot happen" */
01619 
01620       bounds_exceeded = 1;
01621    }
01622 
01623    if (sp->timecnt == 0 || t < sp->ats[0]) {
01624       /* I have no transition times or I'm before time */
01625       *dst_enabled = 0;
01626       /* Find where I can get gmtoff */
01627       i = 0;
01628       while (sp->ttis[i].tt_isdst)
01629          if (++i >= sp->typecnt) {
01630          i = 0;
01631          break;
01632          }
01633          *gmt_off = sp->ttis[i].tt_gmtoff;
01634          return;
01635    } 
01636 
01637    for (i = 1; i < sp->timecnt; ++i) {
01638       if (t < sp->ats[i]) {
01639          transition1 = sp->types[i - 1];
01640          transition2 = sp->types[i];
01641          break;
01642       } 
01643    }
01644    /* if I found transition times that do not bounded the given time and these correspond to 
01645       or the bounding zones do not reflect a changes in day light savings, then I do not have dst active */
01646    if (i >= sp->timecnt || 0 > transition1 || 0 > transition2 ||
01647          (sp->ttis[transition1].tt_isdst == sp->ttis[transition2].tt_isdst)) {
01648       *dst_enabled = 0;
01649       *gmt_off     = sp->ttis[sp->types[sp->timecnt -1]].tt_gmtoff;
01650    } else {
01651       /* I have valid daylight savings information. */
01652       if(sp->ttis[transition2].tt_isdst) 
01653          *gmt_off = sp->ttis[transition1].tt_gmtoff;
01654       else 
01655          *gmt_off = sp->ttis[transition2].tt_gmtoff;
01656 
01657       /* If I adjusted the time earlier, indicate that the dst is invalid */
01658       if (!bounds_exceeded) {
01659          *dst_enabled = 1;
01660          /* Determine which of the bounds is the start of daylight savings and which is the end */
01661          if(sp->ttis[transition2].tt_isdst) {
01662             *dst_start = sp->ats[i];
01663             *dst_end = sp->ats[i -1];
01664          } else {
01665             *dst_start = sp->ats[i -1];
01666             *dst_end = sp->ats[i];
01667          }
01668       }
01669    }  
01670    return;
01671 }
01672 
01673 /*
01674 ** gmtsub is to gmtime as localsub is to localtime.
01675 */
01676 
01677 static struct ast_tm *gmtsub(const struct timeval *timep, const long offset, struct ast_tm *tmp)
01678 {
01679    struct ast_tm *   result;
01680    struct state *sp;
01681 
01682    AST_LIST_LOCK(&zonelist);
01683    AST_LIST_TRAVERSE(&zonelist, sp, list) {
01684       if (!strcmp(sp->name, "UTC"))
01685          break;
01686    }
01687 
01688    if (!sp) {
01689       if (!(sp = (struct state *) ast_calloc(1, sizeof *sp)))
01690          return NULL;
01691       gmtload(sp);
01692       AST_LIST_INSERT_TAIL(&zonelist, sp, list);
01693    }
01694    AST_LIST_UNLOCK(&zonelist);
01695 
01696    result = timesub(timep, offset, sp, tmp);
01697 #ifdef TM_ZONE
01698    /*
01699    ** Could get fancy here and deliver something such as
01700    ** "UTC+xxxx" or "UTC-xxxx" if offset is non-zero,
01701    ** but this is no time for a treasure hunt.
01702    */
01703    if (offset != 0)
01704       tmp->TM_ZONE = "    ";
01705    else
01706       tmp->TM_ZONE = sp->chars;
01707 #endif /* defined TM_ZONE */
01708    return result;
01709 }
01710 
01711 /*! \brief
01712 ** Return the number of leap years through the end of the given year
01713 ** where, to make the math easy, the answer for year zero is defined as zero.
01714 */
01715 
01716 static int leaps_thru_end_of(const int y)
01717 {
01718    return (y >= 0) ? (y / 4 - y / 100 + y / 400) :
01719       -(leaps_thru_end_of(-(y + 1)) + 1);
01720 }
01721 
01722 static struct ast_tm *timesub(const struct timeval *timep, const long offset, const struct state *sp, struct ast_tm *tmp)
01723 {
01724    const struct lsinfo *   lp;
01725    time_t         tdays;
01726    int         idays;   /* unsigned would be so 2003 */
01727    long        rem;
01728    int            y;
01729    const int *    ip;
01730    long        corr;
01731    int         hit;
01732    int         i;
01733    long  seconds;
01734 
01735 
01736    corr = 0;
01737    hit = 0;
01738    i = (sp == NULL) ? 0 : sp->leapcnt;
01739    while (--i >= 0) {
01740       lp = &sp->lsis[i];
01741       if (timep->tv_sec >= lp->ls_trans) {
01742          if (timep->tv_sec == lp->ls_trans) {
01743             hit = ((i == 0 && lp->ls_corr > 0) ||
01744                lp->ls_corr > sp->lsis[i - 1].ls_corr);
01745             if (hit)
01746                while (i > 0 &&
01747                   sp->lsis[i].ls_trans ==
01748                   sp->lsis[i - 1].ls_trans + 1 &&
01749                   sp->lsis[i].ls_corr ==
01750                   sp->lsis[i - 1].ls_corr + 1) {
01751                      ++hit;
01752                      --i;
01753                }
01754          }
01755          corr = lp->ls_corr;
01756          break;
01757       }
01758    }
01759    y = EPOCH_YEAR;
01760    tdays = timep->tv_sec / SECSPERDAY;
01761    rem = timep->tv_sec - tdays * SECSPERDAY;
01762    while (tdays < 0 || tdays >= year_lengths[isleap(y)]) {
01763       int      newy;
01764       time_t   tdelta;
01765       int   idelta;
01766       int   leapdays;
01767 
01768       tdelta = tdays / DAYSPERLYEAR;
01769       idelta = tdelta;
01770       if (tdelta - idelta >= 1 || idelta - tdelta >= 1)
01771          return NULL;
01772       if (idelta == 0)
01773          idelta = (tdays < 0) ? -1 : 1;
01774       newy = y;
01775       if (increment_overflow(&newy, idelta))
01776          return NULL;
01777       leapdays = leaps_thru_end_of(newy - 1) -
01778          leaps_thru_end_of(y - 1);
01779       tdays -= ((time_t) newy - y) * DAYSPERNYEAR;
01780       tdays -= leapdays;
01781       y = newy;
01782    }
01783 
01784    seconds = tdays * SECSPERDAY + 0.5;
01785    tdays = seconds / SECSPERDAY;
01786    rem += seconds - tdays * SECSPERDAY;
01787 
01788    /*
01789    ** Given the range, we can now fearlessly cast...
01790    */
01791    idays = tdays;
01792    rem += offset - corr;
01793    while (rem < 0) {
01794       rem += SECSPERDAY;
01795       --idays;
01796    }
01797    while (rem >= SECSPERDAY) {
01798       rem -= SECSPERDAY;
01799       ++idays;
01800    }
01801    while (idays < 0) {
01802       if (increment_overflow(&y, -1))
01803          return NULL;
01804       idays += year_lengths[isleap(y)];
01805    }
01806    while (idays >= year_lengths[isleap(y)]) {
01807       idays -= year_lengths[isleap(y)];
01808       if (increment_overflow(&y, 1))
01809          return NULL;
01810    }
01811    tmp->tm_year = y;
01812    if (increment_overflow(&tmp->tm_year, -TM_YEAR_BASE))
01813       return NULL;
01814    tmp->tm_yday = idays;
01815    /*
01816    ** The "extra" mods below avoid overflow problems.
01817    */
01818    tmp->tm_wday = EPOCH_WDAY +
01819       ((y - EPOCH_YEAR) % DAYSPERWEEK) *
01820       (DAYSPERNYEAR % DAYSPERWEEK) +
01821       leaps_thru_end_of(y - 1) -
01822       leaps_thru_end_of(EPOCH_YEAR - 1) +
01823       idays;
01824    tmp->tm_wday %= DAYSPERWEEK;
01825    if (tmp->tm_wday < 0)
01826       tmp->tm_wday += DAYSPERWEEK;
01827    tmp->tm_hour = (int) (rem / SECSPERHOUR);
01828    rem %= SECSPERHOUR;
01829    tmp->tm_min = (int) (rem / SECSPERMIN);
01830    /*
01831    ** A positive leap second requires a special
01832    ** representation. This uses "... ??:59:60" et seq.
01833    */
01834    tmp->tm_sec = (int) (rem % SECSPERMIN) + hit;
01835    ip = mon_lengths[isleap(y)];
01836    for (tmp->tm_mon = 0; idays >= ip[tmp->tm_mon]; ++(tmp->tm_mon))
01837       idays -= ip[tmp->tm_mon];
01838    tmp->tm_mday = (int) (idays + 1);
01839    tmp->tm_isdst = 0;
01840 #ifdef TM_GMTOFF
01841    tmp->TM_GMTOFF = offset;
01842 #endif /* defined TM_GMTOFF */
01843    tmp->tm_usec = timep->tv_usec;
01844    return tmp;
01845 }
01846 
01847 /*! \note
01848 ** Adapted from code provided by Robert Elz, who writes:
01849 ** The "best" way to do mktime I think is based on an idea of Bob
01850 ** Kridle's (so its said...) from a long time ago.
01851 ** It does a binary search of the time_t space. Since time_t's are
01852 ** just 32 bits, its a max of 32 iterations (even at 64 bits it
01853 ** would still be very reasonable).
01854 */
01855 
01856 /*! \brief
01857 ** Simplified normalize logic courtesy Paul Eggert.
01858 */
01859 
01860 static int increment_overflow(int *number, int delta)
01861 {
01862    int   number0;
01863 
01864    number0 = *number;
01865    *number += delta;
01866    return (*number < number0) != (delta < 0);
01867 }
01868 
01869 static int long_increment_overflow(long *number, int delta)
01870 {
01871    long  number0;
01872 
01873    number0 = *number;
01874    *number += delta;
01875    return (*number < number0) != (delta < 0);
01876 }
01877 
01878 static int normalize_overflow(int *tensptr, int *unitsptr, const int base)
01879 {
01880    int   tensdelta;
01881 
01882    tensdelta = (*unitsptr >= 0) ?
01883       (*unitsptr / base) :
01884       (-1 - (-1 - *unitsptr) / base);
01885    *unitsptr -= tensdelta * base;
01886    return increment_overflow(tensptr, tensdelta);
01887 }
01888 
01889 static int long_normalize_overflow(long *tensptr, int *unitsptr, const int base)
01890 {
01891    int   tensdelta;
01892 
01893    tensdelta = (*unitsptr >= 0) ?
01894       (*unitsptr / base) :
01895       (-1 - (-1 - *unitsptr) / base);
01896    *unitsptr -= tensdelta * base;
01897    return long_increment_overflow(tensptr, tensdelta);
01898 }
01899 
01900 static int tmcomp(const struct ast_tm *atmp, const struct ast_tm *btmp)
01901 {
01902    int   result;
01903 
01904    if ((result = (atmp->tm_year - btmp->tm_year)) == 0 &&
01905       (result = (atmp->tm_mon - btmp->tm_mon)) == 0 &&
01906       (result = (atmp->tm_mday - btmp->tm_mday)) == 0 &&
01907       (result = (atmp->tm_hour - btmp->tm_hour)) == 0 &&
01908       (result = (atmp->tm_min - btmp->tm_min)) == 0 &&
01909       (result = (atmp->tm_sec - btmp->tm_sec)) == 0)
01910          result = atmp->tm_usec - btmp->tm_usec;
01911    return result;
01912 }
01913 
01914 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)
01915 {
01916    int         dir;
01917    int         i, j;
01918    int         saved_seconds;
01919    long        li;
01920    time_t         lo;
01921    time_t         hi;
01922    long           y;
01923    struct timeval       newt = { 0, 0 };
01924    struct timeval       t = { 0, 0 };
01925    struct ast_tm        yourtm, mytm;
01926 
01927    *okayp = FALSE;
01928    yourtm = *tmp;
01929    if (do_norm_secs) {
01930       if (normalize_overflow(&yourtm.tm_min, &yourtm.tm_sec,
01931          SECSPERMIN))
01932             return WRONG;
01933    }
01934    if (normalize_overflow(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR))
01935       return WRONG;
01936    if (normalize_overflow(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY))
01937       return WRONG;
01938    y = yourtm.tm_year;
01939    if (long_normalize_overflow(&y, &yourtm.tm_mon, MONSPERYEAR))
01940       return WRONG;
01941    /*
01942    ** Turn y into an actual year number for now.
01943    ** It is converted back to an offset from TM_YEAR_BASE later.
01944    */
01945    if (long_increment_overflow(&y, TM_YEAR_BASE))
01946       return WRONG;
01947    while (yourtm.tm_mday <= 0) {
01948       if (long_increment_overflow(&y, -1))
01949          return WRONG;
01950       li = y + (1 < yourtm.tm_mon);
01951       yourtm.tm_mday += year_lengths[isleap(li)];
01952    }
01953    while (yourtm.tm_mday > DAYSPERLYEAR) {
01954       li = y + (1 < yourtm.tm_mon);
01955       yourtm.tm_mday -= year_lengths[isleap(li)];
01956       if (long_increment_overflow(&y, 1))
01957          return WRONG;
01958    }
01959    for ( ; ; ) {
01960       i = mon_lengths[isleap(y)][yourtm.tm_mon];
01961       if (yourtm.tm_mday <= i)
01962          break;
01963       yourtm.tm_mday -= i;
01964       if (++yourtm.tm_mon >= MONSPERYEAR) {
01965          yourtm.tm_mon = 0;
01966          if (long_increment_overflow(&y, 1))
01967             return WRONG;
01968       }
01969    }
01970    if (long_increment_overflow(&y, -TM_YEAR_BASE))
01971       return WRONG;
01972    yourtm.tm_year = y;
01973    if (yourtm.tm_year != y)
01974       return WRONG;
01975    if (yourtm.tm_sec >= 0 && yourtm.tm_sec < SECSPERMIN)
01976       saved_seconds = 0;
01977    else if (y + TM_YEAR_BASE < EPOCH_YEAR) {
01978       /*
01979       ** We can't set tm_sec to 0, because that might push the
01980       ** time below the minimum representable time.
01981       ** Set tm_sec to 59 instead.
01982       ** This assumes that the minimum representable time is
01983       ** not in the same minute that a leap second was deleted from,
01984       ** which is a safer assumption than using 58 would be.
01985       */
01986       if (increment_overflow(&yourtm.tm_sec, 1 - SECSPERMIN))
01987          return WRONG;
01988       saved_seconds = yourtm.tm_sec;
01989       yourtm.tm_sec = SECSPERMIN - 1;
01990    } else {
01991       saved_seconds = yourtm.tm_sec;
01992       yourtm.tm_sec = 0;
01993    }
01994    /*
01995    ** Do a binary search (this works whatever time_t's type is).
01996    */
01997    if (!TYPE_SIGNED(time_t)) {
01998       lo = 0;
01999       hi = lo - 1;
02000    } else if (!TYPE_INTEGRAL(time_t)) {
02001       if (sizeof(time_t) > sizeof(float))
02002          hi = (time_t) DBL_MAX;
02003       else  hi = (time_t) FLT_MAX;
02004       lo = -hi;
02005    } else {
02006       lo = 1;
02007       for (i = 0; i < (int) TYPE_BIT(time_t) - 1; ++i)
02008          lo *= 2;
02009       hi = -(lo + 1);
02010    }
02011    for ( ; ; ) {
02012       t.tv_sec = lo / 2 + hi / 2;
02013       if (t.tv_sec < lo)
02014          t.tv_sec = lo;
02015       else if (t.tv_sec > hi)
02016          t.tv_sec = hi;
02017       if ((*funcp)(&t, offset, &mytm, sp) == NULL) {
02018          /*
02019          ** Assume that t is too extreme to be represented in
02020          ** a struct ast_tm; arrange things so that it is less
02021          ** extreme on the next pass.
02022          */
02023          dir = (t.tv_sec > 0) ? 1 : -1;
02024       } else   dir = tmcomp(&mytm, &yourtm);
02025       if (dir != 0) {
02026          if (t.tv_sec == lo) {
02027             ++t.tv_sec;
02028             if (t.tv_sec <= lo)
02029                return WRONG;
02030             ++lo;
02031          } else if (t.tv_sec == hi) {
02032             --t.tv_sec;
02033             if (t.tv_sec >= hi)
02034                return WRONG;
02035             --hi;
02036          }
02037          if (lo > hi)
02038             return WRONG;
02039          if (dir > 0)
02040             hi = t.tv_sec;
02041          else  lo = t.tv_sec;
02042          continue;
02043       }
02044       if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst)
02045          break;
02046       /*
02047       ** Right time, wrong type.
02048       ** Hunt for right time, right type.
02049       ** It's okay to guess wrong since the guess
02050       ** gets checked.
02051       */
02052       /*
02053       ** The (void *) casts are the benefit of SunOS 3.3 on Sun 2's.
02054       */
02055       for (i = sp->typecnt - 1; i >= 0; --i) {
02056          if (sp->ttis[i].tt_isdst != yourtm.tm_isdst)
02057             continue;
02058          for (j = sp->typecnt - 1; j >= 0; --j) {
02059             if (sp->ttis[j].tt_isdst == yourtm.tm_isdst)
02060                continue;
02061             newt.tv_sec = t.tv_sec + sp->ttis[j].tt_gmtoff -
02062                sp->ttis[i].tt_gmtoff;
02063             if ((*funcp)(&newt, offset, &mytm, sp) == NULL)
02064                continue;
02065             if (tmcomp(&mytm, &yourtm) != 0)
02066                continue;
02067             if (mytm.tm_isdst != yourtm.tm_isdst)
02068                continue;
02069             /*
02070             ** We have a match.
02071             */
02072             t = newt;
02073             goto label;
02074          }
02075       }
02076       return WRONG;
02077    }
02078 label:
02079    newt.tv_sec = t.tv_sec + saved_seconds;
02080    if ((newt.tv_sec < t.tv_sec) != (saved_seconds < 0))
02081       return WRONG;
02082    t.tv_sec = newt.tv_sec;
02083    if ((*funcp)(&t, offset, tmp, sp))
02084       *okayp = TRUE;
02085    return t;
02086 }
02087 
02088 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)
02089 {
02090    struct timeval t;
02091 
02092    /*! \note
02093    ** First try without normalization of seconds
02094    ** (in case tm_sec contains a value associated with a leap second).
02095    ** If that fails, try with normalization of seconds.
02096    */
02097    t = time2sub(tmp, funcp, offset, okayp, FALSE, sp);
02098    return *okayp ? t : time2sub(tmp, funcp, offset, okayp, TRUE, sp);
02099 }
02100 
02101 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)
02102 {
02103    struct timeval       t;
02104    int         samei, otheri;
02105    int         sameind, otherind;
02106    int         i;
02107    int         nseen;
02108    int            seen[TZ_MAX_TYPES];
02109    int            types[TZ_MAX_TYPES];
02110    int            okay;
02111 
02112    if (tmp->tm_isdst > 1)
02113       tmp->tm_isdst = 1;
02114    t = time2(tmp, funcp, offset, &okay, sp);
02115 #ifdef PCTS
02116    /*
02117    ** PCTS code courtesy Grant Sullivan.
02118    */
02119    if (okay)
02120       return t;
02121    if (tmp->tm_isdst < 0)
02122       tmp->tm_isdst = 0;   /* reset to std and try again */
02123 #endif /* defined PCTS */
02124 #ifndef PCTS
02125    if (okay || tmp->tm_isdst < 0)
02126       return t;
02127 #endif /* !defined PCTS */
02128    /*
02129    ** We're supposed to assume that somebody took a time of one type
02130    ** and did some math on it that yielded a "struct ast_tm" that's bad.
02131    ** We try to divine the type they started from and adjust to the
02132    ** type they need.
02133    */
02134    if (sp == NULL)
02135       return WRONG;
02136    for (i = 0; i < sp->typecnt; ++i)
02137       seen[i] = FALSE;
02138    nseen = 0;
02139    for (i = sp->timecnt - 1; i >= 0; --i)
02140       if (!seen[sp->types[i]]) {
02141          seen[sp->types[i]] = TRUE;
02142          types[nseen++] = sp->types[i];
02143       }
02144    for (sameind = 0; sameind < nseen; ++sameind) {
02145       samei = types[sameind];
02146       if (sp->ttis[samei].tt_isdst != tmp->tm_isdst)
02147          continue;
02148       for (otherind = 0; otherind < nseen; ++otherind) {
02149          otheri = types[otherind];
02150          if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst)
02151             continue;
02152          tmp->tm_sec += sp->ttis[otheri].tt_gmtoff -
02153                sp->ttis[samei].tt_gmtoff;
02154          tmp->tm_isdst = !tmp->tm_isdst;
02155          t = time2(tmp, funcp, offset, &okay, sp);
02156          if (okay)
02157             return t;
02158          tmp->tm_sec -= sp->ttis[otheri].tt_gmtoff -
02159                sp->ttis[samei].tt_gmtoff;
02160          tmp->tm_isdst = !tmp->tm_isdst;
02161       }
02162    }
02163    return WRONG;
02164 }
02165 
02166 struct timeval ast_mktime(struct ast_tm *tmp, const char *zone)
02167 {
02168    const struct state *sp;
02169    if (!(sp = ast_tzset(zone)))
02170       return WRONG;
02171    return time1(tmp, localsub, 0L, sp);
02172 }
02173 
02174 #ifdef HAVE_NEWLOCALE
02175 static struct locale_entry *find_by_locale(locale_t locale)
02176 {
02177    struct locale_entry *cur;
02178    AST_LIST_TRAVERSE(&localelist, cur, list) {
02179       if (locale == cur->locale) {
02180          return cur;
02181       }
02182    }
02183    return NULL;
02184 }
02185 
02186 static struct locale_entry *find_by_name(const char *name)
02187 {
02188    struct locale_entry *cur;
02189    AST_LIST_TRAVERSE(&localelist, cur, list) {
02190       if (strcmp(name, cur->name) == 0) {
02191          return cur;
02192       }
02193    }
02194    return NULL;
02195 }
02196 
02197 static const char *store_by_locale(locale_t prevlocale)
02198 {
02199    struct locale_entry *cur;
02200    if (prevlocale == LC_GLOBAL_LOCALE) {
02201       return NULL;
02202    } else {
02203       /* Get a handle for this entry, if any */
02204       if ((cur = find_by_locale(prevlocale))) {
02205          return cur->name;
02206       } else {
02207          /* Create an entry, so it can be restored later */
02208          int x;
02209          cur = NULL;
02210          AST_LIST_LOCK(&localelist);
02211          for (x = 0; x < 10000; x++) {
02212             char name[5];
02213             snprintf(name, sizeof(name), "%04d", x);
02214             if (!find_by_name(name)) {
02215                if ((cur = ast_calloc(1, sizeof(*cur) + strlen(name) + 1))) {
02216                   cur->locale = prevlocale;
02217                   strcpy(cur->name, name); /* SAFE */
02218                   AST_LIST_INSERT_TAIL(&localelist, cur, list);
02219                }
02220                break;
02221             }
02222          }
02223          AST_LIST_UNLOCK(&localelist);
02224          return cur ? cur->name : NULL;
02225       }
02226    }
02227 }
02228 
02229 const char *ast_setlocale(const char *locale)
02230 {
02231    struct locale_entry *cur;
02232    locale_t prevlocale = LC_GLOBAL_LOCALE;
02233 
02234    if (locale == NULL) {
02235       return store_by_locale(uselocale(LC_GLOBAL_LOCALE));
02236    }
02237 
02238    AST_LIST_LOCK(&localelist);
02239    if ((cur = find_by_name(locale))) {
02240       prevlocale = uselocale(cur->locale);
02241    }
02242 
02243    if (!cur) {
02244       if ((cur = ast_calloc(1, sizeof(*cur) + strlen(locale) + 1))) {
02245          cur->locale = newlocale(LC_ALL_MASK, locale, NULL);
02246          strcpy(cur->name, locale); /* SAFE */
02247          AST_LIST_INSERT_TAIL(&localelist, cur, list);
02248          prevlocale = uselocale(cur->locale);
02249       }
02250    }
02251    AST_LIST_UNLOCK(&localelist);
02252    return store_by_locale(prevlocale);
02253 }
02254 #else
02255 const char *ast_setlocale(const char *unused)
02256 {
02257    return NULL;
02258 }
02259 #endif
02260 
02261 int ast_strftime_locale(char *buf, size_t len, const char *tmp, const struct ast_tm *tm, const char *locale)
02262 {
02263    size_t fmtlen = strlen(tmp) + 1;
02264    char *format = ast_calloc(1, fmtlen), *fptr = format, *newfmt;
02265    int decimals = -1, i, res;
02266    long fraction;
02267    const char *prevlocale;
02268 
02269    if (!format) {
02270       return -1;
02271    }
02272    for (; *tmp; tmp++) {
02273       if (*tmp == '%') {
02274          switch (tmp[1]) {
02275          case '1':
02276          case '2':
02277          case '3':
02278          case '4':
02279          case '5':
02280          case '6':
02281             if (tmp[2] != 'q') {
02282                goto defcase;
02283             }
02284             decimals = tmp[1] - '0';
02285             tmp++;
02286             /* Fall through */
02287          case 'q': /* Milliseconds */
02288             if (decimals == -1) {
02289                decimals = 3;
02290             }
02291 
02292             /* Juggle some memory to fit the item */
02293             newfmt = ast_realloc(format, fmtlen + decimals);
02294             if (!newfmt) {
02295                ast_free(format);
02296                return -1;
02297             }
02298             fptr = fptr - format + newfmt;
02299             format = newfmt;
02300             fmtlen += decimals;
02301 
02302             /* Reduce the fraction of time to the accuracy needed */
02303             for (i = 6, fraction = tm->tm_usec; i > decimals; i--) {
02304                fraction /= 10;
02305             }
02306             fptr += sprintf(fptr, "%0*ld", decimals, fraction);
02307 
02308             /* Reset, in case more than one 'q' specifier exists */
02309             decimals = -1;
02310             tmp++;
02311             break;
02312          default:
02313             goto defcase;
02314          }
02315       } else {
02316 defcase: *fptr++ = *tmp;
02317       }
02318    }
02319    *fptr = '\0';
02320 #undef strftime
02321    if (locale) {
02322       prevlocale = ast_setlocale(locale);
02323    }
02324    res = (int)strftime(buf, len, format, (struct tm *)tm);
02325    if (locale) {
02326       ast_setlocale(prevlocale);
02327    }
02328    ast_free(format);
02329    return res;
02330 }
02331 
02332 int ast_strftime(char *buf, size_t len, const char *tmp, const struct ast_tm *tm)
02333 {
02334    return ast_strftime_locale(buf, len, tmp, tm, NULL);
02335 }
02336 
02337 char *ast_strptime_locale(const char *s, const char *format, struct ast_tm *tm, const char *locale)
02338 {
02339    struct tm tm2 = { 0, };
02340    char *res;
02341    const char *prevlocale;
02342 
02343    prevlocale = ast_setlocale(locale);
02344    res = strptime(s, format, &tm2);
02345    ast_setlocale(prevlocale);
02346    /* ast_time and tm are not the same size - tm is a subset of
02347     * ast_time.  Hence, the size of tm needs to be used for the
02348     * memcpy
02349     */
02350    memcpy(tm, &tm2, sizeof(tm2));
02351    tm->tm_usec = 0;
02352    /* strptime(3) doesn't set .tm_isdst correctly, so to force ast_mktime(3)
02353     * to deal with it correctly, we set it to -1. */
02354    tm->tm_isdst = -1;
02355    return res;
02356 }
02357 
02358 char *ast_strptime(const char *s, const char *format, struct ast_tm *tm)
02359 {
02360    return ast_strptime_locale(s, format, tm, NULL);
02361 }
02362 

Generated on Mon Oct 8 12:39:03 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7