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