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