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