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