59 #include <sys/inotify.h>
60 #elif defined(HAVE_KQUEUE)
61 #include <sys/types.h>
63 #include <sys/event.h>
82 static char __attribute__((unused)) elsieid[] = "@(
#)localtime.c 8.5";
86 #ifndef TZ_ABBR_MAX_LEN
87 #define TZ_ABBR_MAX_LEN 16
90 #ifndef TZ_ABBR_CHAR_SET
91 #define TZ_ABBR_CHAR_SET \
92 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 :+-._"
95 #ifndef TZ_ABBR_ERR_CHAR
96 #define TZ_ABBR_ERR_CHAR '_'
104 #define OPEN_MODE (O_RDONLY | O_BINARY)
107 #define OPEN_MODE O_RDONLY
110 static const char gmt[] =
"GMT";
111 static const struct timeval WRONG = { 0, 0 };
113 #ifdef TEST_FRAMEWORK
115 static struct ast_test *
test = NULL;
127 #ifndef TZDEFRULESTRING
128 #define TZDEFRULESTRING ",M4.1.0,M10.5.0"
146 #define BIGGEST(a, b) (((a) > (b)) ? (a) : (b))
149 #define MY_TZNAME_MAX TZNAME_MAX
152 #define MY_TZNAME_MAX 255
154 #ifndef TZ_STRLEN_MAX
155 #define TZ_STRLEN_MAX 255
167 time_t ats[TZ_MAX_TIMES];
168 unsigned char types[TZ_MAX_TIMES];
169 struct ttinfo ttis[TZ_MAX_TYPES];
170 char chars[BIGGEST(BIGGEST(TZ_MAX_CHARS + 1,
sizeof gmt),
171 (2 * (MY_TZNAME_MAX + 1)))];
172 struct lsinfo lsis[TZ_MAX_LEAPS];
175 #elif defined(HAVE_KQUEUE)
177 # ifdef HAVE_O_SYMLINK
189 #define SP_STACK_FLAG INT_MIN
191 # define SP_STACK_INIT(sp) do { \
192 (sp).wd[0] = SP_STACK_FLAG; \
194 # define SP_STACK_CHECK(sp) ((sp)->wd[0] == SP_STACK_FLAG)
195 # define SP_HEAP_INIT(sp) do { \
199 # define SP_HEAP_FREE(sp) do {} while (0)
201 #elif defined(HAVE_KQUEUE)
202 # define SP_STACK_INIT(sp) do { \
203 (sp).fd = SP_STACK_FLAG; \
205 # define SP_STACK_CHECK(sp) ((sp)->fd == SP_STACK_FLAG)
206 #ifdef HAVE_O_SYMLINK
207 # define SP_HEAP_INIT(sp) do { \
211 # define SP_HEAP_FREE(sp) do { \
213 kqueue_daemon_freestate(sp); \
214 if ((sp)->fd > -1) { close((sp)->fd); (sp)->fd = -1; } \
215 if ((sp)->fds > -1) { close((sp)->fds); (sp)->fds = -1; } \
220 # define SP_HEAP_INIT(sp) do { \
224 # define SP_HEAP_FREE(sp) do { \
226 kqueue_daemon_freestate(sp); \
227 if ((sp)->fd > -1) { close((sp)->fd); (sp)->fd = -1; } \
228 if ((sp)->dir != NULL) { closedir((sp)->dir); (sp)->dir = NULL; } \
235 # define SP_STACK_INIT(sp) do {} while (0)
236 # define SP_STACK_CHECK(sp) (0)
237 # define SP_HEAP_INIT(sp) do {} while (0)
238 # define SP_HEAP_FREE(sp) do {} while (0)
257 #define DAY_OF_YEAR 1
258 #define MONTH_NTH_DAY_OF_WEEK 2
264 static long detzcode P((
const char * codep));
265 static time_t detzcode64 P((
const char * codep));
266 static int differ_by_repeat P((time_t t1, time_t t0));
267 static const char *
getzname P((
const char * strp));
268 static const char *
getqzname P((
const char * strp,
const int delim));
269 static const char *
getnum P((
const char * strp,
int * nump,
int min,
271 static const char *
getsecs P((
const char * strp,
long * secsp));
272 static const char *
getoffset P((
const char * strp,
long * offsetp));
273 static const char *
getrule P((
const char * strp,
struct rule * rulep));
274 static int gmtload P((
struct state * sp));
275 static struct ast_tm * gmtsub P((
const struct timeval * timep,
long offset,
277 static struct ast_tm *
localsub P((
const struct timeval * timep,
long offset,
281 static int long_increment_overflow P((
long *
number,
int delta));
282 static int long_normalize_overflow P((
long * tensptr,
283 int * unitsptr,
const int base));
284 static int normalize_overflow P((
int * tensptr,
int * unitsptr,
286 static struct timeval time1 P((struct
ast_tm * tmp,
287 struct ast_tm * (*funcp) P((
const struct timeval *,
289 long offset,
const struct state *sp));
291 struct ast_tm * (*funcp) P((
const struct timeval *,
293 long offset,
int * okayp,
const struct state *sp));
294 static struct timeval time2sub P((struct
ast_tm *tmp,
295 struct ast_tm * (*funcp) (
const struct timeval *,
297 long offset,
int * okayp,
int do_norm_secs,
const struct state *sp));
298 static struct ast_tm * timesub P((
const struct timeval * timep,
long offset,
300 static int tmcomp P((
const struct ast_tm * atmp,
301 const struct ast_tm * btmp));
302 static time_t
transtime P((time_t janfirst,
int year,
303 const struct rule * rulep,
long offset));
304 static int tzload P((
const char * name,
struct state * sp,
306 static int tzparse P((
const char * name,
struct state * sp,
309 static struct state * sstate_alloc(
void);
310 static void sstate_free(
struct state *p);
313 #if defined(HAVE_NEWLOCALE) && defined(HAVE_USELOCALE)
317 #ifndef TZ_STRLEN_MAX
318 #define TZ_STRLEN_MAX 255
321 static pthread_t inotify_thread = AST_PTHREADT_NULL;
322 static ast_cond_t initialization;
325 static void add_notify(
struct state *sp,
const char *path);
335 char name[FILENAME_MAX + 1];
337 if (sp->
name[0] ==
'/') {
338 snprintf(name,
sizeof(name),
"%s", sp->
name);
339 }
else if (!strcmp(sp->
name, TZDEFAULT)) {
340 snprintf(name,
sizeof(name),
"/etc/%s", sp->
name);
342 snprintf(name,
sizeof(name),
"%s/%s", TZDIR, sp->
name);
345 add_notify(sp, name);
351 static int inotify_fd = -1;
353 static void *inotify_daemon(
void *data)
356 struct inotify_event *iev;
357 size_t real_sizeof_iev =
sizeof(*iev) + FILENAME_MAX + 1;
361 inotify_fd = inotify_init();
363 ast_mutex_lock(&initialization_lock);
364 ast_cond_broadcast(&initialization);
365 ast_mutex_unlock(&initialization_lock);
367 if (inotify_fd < 0) {
368 ast_log(LOG_ERROR,
"Cannot initialize file notification service: %s (%d)\n", strerror(errno), errno);
369 inotify_thread = AST_PTHREADT_NULL;
378 if ((res = read(inotify_fd, iev, real_sizeof_iev)) <
sizeof(*iev) && res > 0) {
380 ast_log(LOG_ERROR,
"Inotify read less than a full event (%zd < %zu)?!!\n", res,
sizeof(*iev));
382 }
else if (res < 0) {
383 if (errno == EINTR || errno == EAGAIN) {
386 ast_cond_broadcast(&initialization);
391 ast_log(LOG_ERROR,
"Inotify failed: %s\n", strerror(errno));
396 if (cur->wd[0] == iev->wd || cur->wd[1] == iev->wd) {
403 ast_cond_broadcast(&initialization);
407 inotify_thread = AST_PTHREADT_NULL;
411 static void add_notify(
struct state *sp,
const char *path)
416 if (SP_STACK_CHECK(sp)) {
420 if (inotify_thread == AST_PTHREADT_NULL) {
421 ast_cond_init(&initialization, NULL);
422 ast_mutex_init(&initialization_lock);
423 ast_mutex_lock(&initialization_lock);
424 if (!(ast_pthread_create_background(&inotify_thread, NULL, inotify_daemon, NULL))) {
426 ast_cond_wait(&initialization, &initialization_lock);
428 fprintf(stderr,
"Unable to start notification thread\n");
429 ast_mutex_unlock(&initialization_lock);
432 ast_mutex_unlock(&initialization_lock);
435 if (inotify_fd > -1) {
436 char fullpath[FILENAME_MAX + 1] =
"";
437 if (readlink(path, fullpath,
sizeof(fullpath) - 1) != -1) {
439 sp->wd[1] = inotify_add_watch(inotify_fd, fullpath, IN_ATTRIB | IN_DELETE_SELF | IN_MODIFY | IN_MOVE_SELF | IN_CLOSE_WRITE );
444 sp->wd[0] = inotify_add_watch(inotify_fd, path, IN_ATTRIB | IN_DELETE_SELF | IN_MODIFY | IN_MOVE_SELF | IN_CLOSE_WRITE
445 #ifdef IN_DONT_FOLLOW
451 #elif defined(HAVE_KQUEUE)
452 static int queue_fd = -1;
462 static struct state *psx_sp = NULL;
467 # define EVVN_NOTES_BITS \
468 (NOTE_DELETE|NOTE_WRITE|NOTE_EXTEND|NOTE_REVOKE|NOTE_ATTRIB \
469 |NOTE_RENAME|NOTE_LINK|NOTE_TRUNCATE)
471 # define EVVN_NOTES_BITS \
472 (NOTE_DELETE|NOTE_WRITE|NOTE_EXTEND|NOTE_REVOKE|NOTE_ATTRIB \
473 |NOTE_RENAME|NOTE_LINK)
476 static void *kqueue_daemon(
void *data)
481 ast_mutex_lock(&initialization_lock);
482 if (queue_fd < 0 && (queue_fd = kqueue()) < 0) {
485 fprintf(stderr,
"Unable to initialize kqueue(): %s\n", strerror(errno));
486 inotify_thread = AST_PTHREADT_NULL;
489 ast_cond_signal(&initialization);
490 ast_mutex_unlock(&initialization_lock);
494 ast_cond_signal(&initialization);
495 ast_mutex_unlock(&initialization_lock);
500 if (kevent(queue_fd, NULL, 0, &kev, 1, NULL) < 0) {
502 ast_cond_broadcast(&initialization);
507 sp = (
struct state *) kev.udata;
525 ast_cond_broadcast(&initialization);
529 inotify_thread = AST_PTHREADT_NULL;
533 static void kqueue_daemon_freestate(
struct state *sp)
536 struct timespec no_wait = { 0, 1 };
552 EV_SET(&kev, sp->fd, EVFILT_VNODE, EV_DELETE, 0, 0, NULL);
553 kevent(queue_fd, &kev, 1, NULL, 0, &no_wait);
556 #ifdef HAVE_O_SYMLINK
559 EV_SET(&kev, sp->fds, EVFILT_VNODE, EV_DELETE, 0, 0, NULL);
560 kevent(queue_fd, &kev, 1, NULL, 0, &no_wait);
565 EV_SET(&kev, dirfd(sp->dir), EVFILT_VNODE, EV_DELETE, 0, 0, NULL);
566 kevent(queue_fd, &kev, 1, NULL, 0, &no_wait);
571 static void add_notify(
struct state *sp,
const char *path)
574 struct timespec no_wait = { 0, 1 };
575 char watchdir[PATH_MAX + 1] =
"";
580 if (SP_STACK_CHECK(sp) || sp->fd != -1) {
588 if (!strcmp(path, TZDEFRULES) ||
589 !strcmp(path, TZDIR
"/" TZDEFRULES)) {
596 if (psx_sp != NULL ||
597 (psx_sp = sstate_alloc()) == NULL) {
603 sizeof(psx_sp->
name));
608 if (inotify_thread == AST_PTHREADT_NULL) {
609 ast_cond_init(&initialization, NULL);
610 ast_mutex_init(&initialization_lock);
611 ast_mutex_lock(&initialization_lock);
612 if (!(ast_pthread_create_background(&inotify_thread, NULL, kqueue_daemon, NULL))) {
614 ast_cond_wait(&initialization, &initialization_lock);
616 ast_mutex_unlock(&initialization_lock);
624 #ifdef HAVE_O_SYMLINK
625 if (readlink(path, watchdir,
sizeof(watchdir) - 1) != -1 && (sp->fds = open(path, O_RDONLY | O_SYMLINK
626 # ifdef HAVE_O_EVTONLY
630 EV_SET(&kev, sp->fds, EVFILT_VNODE, EV_ADD | EV_ENABLE | EV_ONESHOT, EVVN_NOTES_BITS, 0, sp);
632 if (kevent(queue_fd, &kev, 1, NULL, 0, &no_wait) < 0 && errno != 0) {
637 fprintf(stderr,
"Unable to watch '%s': %s\n", path, strerror(errno));
643 if (readlink(path, watchdir,
sizeof(watchdir) - 1) != -1) {
649 if ((slash = strrchr(watchdir,
'/'))) {
652 if (!(sp->dir = opendir(watchdir))) {
653 fprintf(stderr,
"Unable to watch directory with symlink '%s': %s\n", path, strerror(errno));
666 EV_SET(&kev, dirfd(sp->dir), EVFILT_VNODE, EV_ADD | EV_ENABLE | EV_ONESHOT,
667 EVVN_NOTES_BITS, 0, sp);
669 if (kevent(queue_fd, &kev, 1, NULL, 0, &no_wait) < 0 && errno != 0) {
670 fprintf(stderr,
"Unable to watch '%s': %s\n", watchdir, strerror(errno));
679 if ((sp->fd = open(path, O_RDONLY
680 # ifdef HAVE_O_EVTONLY
684 fprintf(stderr,
"Unable to watch '%s' for changes: %s\n", path, strerror(errno));
688 EV_SET(&kev, sp->fd, EVFILT_VNODE, EV_ADD | EV_ENABLE | EV_ONESHOT, EVVN_NOTES_BITS, 0, sp);
690 if (kevent(queue_fd, &kev, 1, NULL, 0, &no_wait) < 0 && errno != 0) {
695 fprintf(stderr,
"Unable to watch '%s': %s\n", path, strerror(errno));
702 static void *notify_daemon(
void *data)
706 struct timespec sixty_seconds = { 60, 0 };
708 ast_mutex_lock(&initialization_lock);
709 ast_cond_broadcast(&initialization);
710 ast_mutex_unlock(&initialization_lock);
715 char fullname[FILENAME_MAX + 1];
717 nanosleep(&sixty_seconds, NULL);
720 char *name = cur->
name;
724 if (name[0] !=
'/') {
725 (void) strcpy(fullname, TZDIR
"/");
726 (void) strcat(fullname, name);
731 if (st.st_mtime > cur->mtime[0] || lst.st_mtime > cur->mtime[1]) {
732 #ifdef TEST_FRAMEWORK
734 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]);
738 ast_log(LOG_NOTICE,
"Removing cached TZ entry '%s' because underlying file changed.\n", name);
746 ast_cond_broadcast(&initialization);
749 inotify_thread = AST_PTHREADT_NULL;
753 static void add_notify(
struct state *sp,
const char *path)
757 if (inotify_thread == AST_PTHREADT_NULL) {
758 ast_cond_init(&initialization, NULL);
759 ast_mutex_init(&initialization_lock);
760 ast_mutex_lock(&initialization_lock);
761 if (!(ast_pthread_create_background(&inotify_thread, NULL, notify_daemon, NULL))) {
763 ast_cond_wait(&initialization, &initialization_lock);
765 ast_mutex_unlock(&initialization_lock);
769 sp->mtime[0] = st.st_mtime;
771 sp->mtime[1] = st.st_mtime;
778 static struct state *sstate_alloc(
void)
789 static void sstate_free(
struct state *p)
795 void ast_localtime_wakeup_monitor(
struct ast_test *info)
798 struct timespec wait_time = { .tv_sec = wait_now.tv_sec + 2, .tv_nsec = wait_now.tv_usec * 1000 };
800 if (inotify_thread != AST_PTHREADT_NULL) {
802 #ifdef TEST_FRAMEWORK
805 pthread_kill(inotify_thread, SIGURG);
806 ast_cond_timedwait(&initialization, &(&
zonelist)->
lock, &wait_time);
807 #ifdef TEST_FRAMEWORK
827 result = (codep[0] & 0x80) ? ~0L : 0;
828 for (i = 0; i < 4; ++i)
829 result = (result << 8) | (codep[i] & 0xff);
833 static time_t detzcode64(
const char *
const codep)
838 result = (codep[0] & 0x80) ? (~(int_fast64_t) 0) : 0;
839 for (i = 0; i < 8; ++i)
840 result = result * 256 + (codep[i] & 0xff);
844 static int differ_by_repeat(
const time_t t1,
const time_t t0)
846 const long long at1 = t1, at0 = t0;
847 if (TYPE_INTEGRAL(time_t) &&
848 TYPE_BIT(time_t) - TYPE_SIGNED(time_t) < SECSPERREPEAT_BITS)
850 return at1 - at0 == SECSPERREPEAT;
853 static int tzload(
const char *name,
struct state *
const sp,
const int doextend)
862 char buf[2 *
sizeof(
struct tzhead) +
867 if (name == NULL && (name = TZDEFAULT) == NULL)
878 char fullname[FILENAME_MAX + 1];
882 doaccess = name[0] ==
'/';
884 if ((p = TZDIR) == NULL)
886 if ((strlen(p) + strlen(name) + 1) >=
sizeof fullname)
888 (void) strcpy(fullname, p);
889 (void) strcat(fullname,
"/");
890 (void) strcat(fullname, name);
894 if (strchr(name,
'.') != NULL)
898 if (doaccess && access(name, R_OK) != 0)
900 if ((fid = open(name, OPEN_MODE)) == -1)
902 if (ast_fully_booted) {
908 add_notify(sp, name);
911 nread = read(fid, u.buf,
sizeof u.buf);
913 if (close(fid) < 0 || nread <
sizeof u.tzhead)
915 for (stored = 4; stored <= 8; stored *= 2) {
919 ttisstdcnt = (int)
detzcode(u.tzhead.tzh_ttisstdcnt);
920 ttisgmtcnt = (int)
detzcode(u.tzhead.tzh_ttisgmtcnt);
921 sp->leapcnt = (int)
detzcode(u.tzhead.tzh_leapcnt);
922 sp->timecnt = (int)
detzcode(u.tzhead.tzh_timecnt);
923 sp->typecnt = (int)
detzcode(u.tzhead.tzh_typecnt);
924 sp->charcnt = (int)
detzcode(u.tzhead.tzh_charcnt);
925 p = u.tzhead.tzh_charcnt +
sizeof u.tzhead.tzh_charcnt;
926 if (sp->leapcnt < 0 || sp->leapcnt > TZ_MAX_LEAPS ||
927 sp->typecnt <= 0 || sp->typecnt > TZ_MAX_TYPES ||
928 sp->timecnt < 0 || sp->timecnt > TZ_MAX_TIMES ||
929 sp->charcnt < 0 || sp->charcnt > TZ_MAX_CHARS ||
930 (ttisstdcnt != sp->typecnt && ttisstdcnt != 0) ||
931 (ttisgmtcnt != sp->typecnt && ttisgmtcnt != 0))
933 if (nread - (p - u.buf) <
934 sp->timecnt * stored +
938 sp->leapcnt * (stored + 4) +
942 for (i = 0; i < sp->timecnt; ++i) {
943 sp->ats[i] = (stored == 4) ?
947 for (i = 0; i < sp->timecnt; ++i) {
948 sp->types[i] = (
unsigned char) *p++;
949 if (sp->types[i] >= sp->typecnt)
952 for (i = 0; i < sp->typecnt; ++i) {
955 ttisp = &sp->ttis[i];
958 ttisp->tt_isdst = (
unsigned char) *p++;
959 if (ttisp->tt_isdst != 0 && ttisp->tt_isdst != 1)
961 ttisp->tt_abbrind = (
unsigned char) *p++;
962 if (ttisp->tt_abbrind < 0 ||
963 ttisp->tt_abbrind > sp->charcnt)
966 for (i = 0; i < sp->charcnt; ++i)
969 for (i = 0; i < sp->leapcnt; ++i) {
972 lsisp = &sp->lsis[i];
973 lsisp->ls_trans = (stored == 4) ?
979 for (i = 0; i < sp->typecnt; ++i) {
982 ttisp = &sp->ttis[i];
984 ttisp->tt_ttisstd = FALSE;
986 ttisp->tt_ttisstd = *p++;
987 if (ttisp->tt_ttisstd != TRUE &&
988 ttisp->tt_ttisstd != FALSE)
992 for (i = 0; i < sp->typecnt; ++i) {
995 ttisp = &sp->ttis[i];
997 ttisp->tt_ttisgmt = FALSE;
999 ttisp->tt_ttisgmt = *p++;
1000 if (ttisp->tt_ttisgmt != TRUE &&
1001 ttisp->tt_ttisgmt != FALSE)
1010 for (i = 0; i < sp->timecnt - 2; ++i)
1011 if (sp->ats[i] > sp->ats[i + 1]) {
1013 if (TYPE_SIGNED(time_t)) {
1024 for (j = 0; j + i < sp->timecnt; ++j) {
1025 sp->ats[j] = sp->ats[j + i];
1026 sp->types[j] = sp->types[j + i];
1035 if (u.tzhead.tzh_version[0] ==
'\0')
1038 for (i = 0; i < nread; ++i)
1042 if (nread <
sizeof(u.tzhead)) {
1048 if (stored >= (
int)
sizeof(time_t) && TYPE_INTEGRAL(time_t))
1051 if (doextend && nread > 2 &&
1052 u.buf[0] ==
'\n' && u.buf[nread - 1] ==
'\n' &&
1053 sp->typecnt + 2 <= TZ_MAX_TYPES) {
1063 u.buf[nread - 1] =
'\0';
1064 result =
tzparse(&u.buf[1], &ts, FALSE);
1065 if (result == 0 && ts.typecnt == 2 &&
1066 sp->charcnt + ts.charcnt <= TZ_MAX_CHARS) {
1067 for (i = 0; i < 2; ++i)
1068 ts.ttis[i].tt_abbrind +=
1070 for (i = 0; i < ts.charcnt; ++i)
1071 sp->chars[sp->charcnt++] =
1074 while (i < ts.timecnt &&
1076 sp->ats[sp->timecnt - 1])
1078 while (i < ts.timecnt &&
1079 sp->timecnt < TZ_MAX_TIMES) {
1080 sp->ats[sp->timecnt] =
1082 sp->types[sp->timecnt] =
1088 sp->ttis[sp->typecnt++] = ts.ttis[0];
1089 sp->ttis[sp->typecnt++] = ts.ttis[1];
1092 i = 2 * YEARSPERREPEAT;
1093 sp->goback = sp->goahead = sp->timecnt > i;
1094 sp->goback = sp->goback && sp->types[i] == sp->types[0] &&
1095 differ_by_repeat(sp->ats[i], sp->ats[0]);
1096 sp->goahead = sp->goahead &&
1097 sp->types[sp->timecnt - 1] == sp->types[sp->timecnt - 1 - i] &&
1098 differ_by_repeat(sp->ats[sp->timecnt - 1],
1099 sp->ats[sp->timecnt - 1 - i]);
1103 static const int mon_lengths[2][MONSPERYEAR] = {
1104 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
1105 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
1108 static const int year_lengths[2] = {
1109 DAYSPERNYEAR, DAYSPERLYEAR
1122 while ((c = *strp) !=
'\0' && !is_digit(c) && c !=
',' && c !=
'-' &&
1137 static const char *
getqzname(
const char *strp,
const int delim)
1141 while ((c = *strp) !=
'\0' && c != delim)
1153 static const char *
getnum(
const char *strp,
int *nump,
const int min,
const int max)
1158 if (strp == NULL || !is_digit(c = *strp))
1162 num = num * 10 + (c -
'0');
1166 }
while (is_digit(c));
1181 static const char *
getsecs(
const char *strp,
long *
const secsp)
1191 strp =
getnum(strp, &num, 0, HOURSPERDAY * DAYSPERWEEK - 1);
1194 *secsp = num * (long) SECSPERHOUR;
1197 strp =
getnum(strp, &num, 0, MINSPERHOUR - 1);
1200 *secsp += num * SECSPERMIN;
1204 strp =
getnum(strp, &num, 0, SECSPERMIN);
1220 static const char *
getoffset(
const char *strp,
long *offsetp)
1227 }
else if (*strp ==
'+')
1229 strp =
getsecs(strp, offsetp);
1233 *offsetp = -*offsetp;
1250 rulep->r_type = JULIAN_DAY;
1252 strp =
getnum(strp, &rulep->r_day, 1, DAYSPERNYEAR);
1253 }
else if (*strp ==
'M') {
1257 rulep->r_type = MONTH_NTH_DAY_OF_WEEK;
1259 strp =
getnum(strp, &rulep->r_mon, 1, MONSPERYEAR);
1264 strp =
getnum(strp, &rulep->r_week, 1, 5);
1269 strp =
getnum(strp, &rulep->r_day, 0, DAYSPERWEEK - 1);
1270 }
else if (is_digit(*strp)) {
1274 rulep->r_type = DAY_OF_YEAR;
1275 strp =
getnum(strp, &rulep->r_day, 0, DAYSPERLYEAR - 1);
1284 strp =
getsecs(strp, &rulep->r_time);
1285 }
else rulep->r_time = 2 * SECSPERHOUR;
1295 static time_t
transtime(
const time_t janfirst,
const int year,
const struct rule *rulep,
const long offset)
1300 int d, m1, yy0, yy1, yy2, dow;
1303 leapyear = isleap(year);
1304 switch (rulep->r_type) {
1314 value = janfirst + (rulep->r_day - 1) * SECSPERDAY;
1315 if (leapyear && rulep->r_day >= 60)
1316 value += SECSPERDAY;
1325 value = janfirst + rulep->r_day * SECSPERDAY;
1328 case MONTH_NTH_DAY_OF_WEEK:
1333 for (i = 0; i < rulep->r_mon - 1; ++i)
1334 value += mon_lengths[leapyear][i] * SECSPERDAY;
1340 m1 = (rulep->r_mon + 9) % 12 + 1;
1341 yy0 = (rulep->r_mon <= 2) ? (year - 1) : year;
1344 dow = ((26 * m1 - 2) / 10 +
1345 1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7;
1354 d = rulep->r_day - dow;
1357 for (i = 1; i < rulep->r_week; ++i) {
1358 if (d + DAYSPERWEEK >=
1359 mon_lengths[leapyear][rulep->r_mon - 1])
1367 value += d * SECSPERDAY;
1377 return value + rulep->r_time + offset;
1385 static int tzparse(
const char *name,
struct state *sp,
const int lastditch)
1387 const char * stdname;
1388 const char * dstname;
1394 unsigned char * typep;
1398 INITIALIZE(dstname);
1401 stdlen = strlen(name);
1403 if (stdlen >=
sizeof sp->chars)
1404 stdlen = (
sizeof sp->chars) - 1;
1413 stdlen = name - stdname;
1417 stdlen = name - stdname;
1425 load_result = tzload(TZDEFRULES, sp, FALSE);
1426 if (load_result != 0)
1428 if (*name !=
'\0') {
1434 dstlen = name - dstname;
1439 dstlen = name - dstname;
1441 if (*name !=
'\0' && *name !=
',' && *name !=
';') {
1445 }
else dstoffset = stdoffset - SECSPERHOUR;
1446 if (*name ==
'\0' && load_result != 0)
1448 if (*name ==
',' || *name ==
';') {
1457 if ((name =
getrule(name, &start)) == NULL)
1461 if ((name =
getrule(name, &end)) == NULL)
1469 sp->ttis[0].tt_gmtoff = -dstoffset;
1470 sp->ttis[0].tt_isdst = 1;
1471 sp->ttis[0].tt_abbrind = stdlen + 1;
1472 sp->ttis[1].tt_gmtoff = -stdoffset;
1473 sp->ttis[1].tt_isdst = 0;
1474 sp->ttis[1].tt_abbrind = 0;
1479 for (year = EPOCH_YEAR;
1480 sp->timecnt + 2 <= TZ_MAX_TIMES;
1484 starttime =
transtime(janfirst, year, &start,
1486 endtime =
transtime(janfirst, year, &end,
1488 if (starttime > endtime) {
1500 newfirst = janfirst;
1501 newfirst += year_lengths[isleap(year)] *
1503 if (newfirst <= janfirst)
1505 janfirst = newfirst;
1508 long theirstdoffset;
1519 for (i = 0; i < sp->timecnt; ++i) {
1521 if (!sp->ttis[j].tt_isdst) {
1523 -sp->ttis[j].tt_gmtoff;
1527 theiroffset = theirstdoffset;
1532 for (i = 0; i < sp->timecnt; ++i) {
1534 sp->types[i] = sp->ttis[j].tt_isdst;
1535 if (sp->ttis[j].tt_ttisgmt) {
1539 sp->ats[i] += stdoffset - theirstdoffset;
1541 theiroffset = -sp->ttis[j].tt_gmtoff;
1542 if (!sp->ttis[j].tt_isdst) {
1543 theirstdoffset = theiroffset;
1550 sp->ttis[0].tt_gmtoff = -stdoffset;
1551 sp->ttis[0].tt_isdst = FALSE;
1552 sp->ttis[0].tt_abbrind = 0;
1553 sp->ttis[1].tt_gmtoff = -dstoffset;
1554 sp->ttis[1].tt_isdst = TRUE;
1555 sp->ttis[1].tt_abbrind = stdlen + 1;
1562 sp->ttis[0].tt_gmtoff = -stdoffset;
1563 sp->ttis[0].tt_isdst = 0;
1564 sp->ttis[0].tt_abbrind = 0;
1566 sp->charcnt = stdlen + 1;
1568 sp->charcnt += dstlen + 1;
1569 if ((
size_t) sp->charcnt >
sizeof sp->chars)
1572 (void) strncpy(cp, stdname, stdlen);
1576 (void) strncpy(cp, dstname, dstlen);
1577 *(cp + dstlen) =
'\0';
1582 static int gmtload(
struct state *sp)
1584 if (tzload(gmt, sp, TRUE) != 0)
1585 return tzparse(gmt, sp, TRUE);
1601 static const struct state *ast_tzset(
const char *zone)
1605 if (ast_strlen_zero(zone)) {
1607 zone = getenv(
"TZ");
1608 if (ast_strlen_zero(zone)) {
1612 zone =
"/etc/localtime";
1618 if (!strcmp(sp->
name, zone)) {
1624 if (!(sp = sstate_alloc())) {
1629 if (tzload(zone, sp, TRUE) != 0) {
1630 if (zone[0] ==
':' ||
tzparse(zone, sp, FALSE) != 0)
1650 const struct ttinfo * ttisp;
1654 memcpy(&t, timep,
sizeof(t));
1657 return gmtsub(timep, offset, tmp);
1658 if ((sp->goback && t.tv_sec < sp->ats[0]) ||
1659 (sp->goahead && t.tv_sec > sp->ats[sp->timecnt - 1])) {
1660 struct timeval newt = t;
1663 int_fast64_t icycles;
1665 if (t.tv_sec < sp->ats[0])
1666 seconds = sp->ats[0] - t.tv_sec;
1667 else seconds = t.tv_sec - sp->ats[sp->timecnt - 1];
1669 tcycles = seconds / YEARSPERREPEAT / AVGSECSPERYEAR;
1672 if (tcycles - icycles >= 1 || icycles - tcycles >= 1)
1675 seconds *= YEARSPERREPEAT;
1676 seconds *= AVGSECSPERYEAR;
1677 if (t.tv_sec < sp->ats[0])
1678 newt.tv_sec += seconds;
1679 else newt.tv_sec -= seconds;
1680 if (newt.tv_sec < sp->ats[0] ||
1681 newt.tv_sec > sp->ats[sp->timecnt - 1])
1683 result =
localsub(&newt, offset, tmp, sp);
1684 if (result == tmp) {
1688 if (t.tv_sec < sp->ats[0])
1689 newy -= icycles * YEARSPERREPEAT;
1691 newy += icycles * YEARSPERREPEAT;
1698 if (sp->timecnt == 0 || t.tv_sec < sp->ats[0]) {
1700 while (sp->ttis[i].tt_isdst) {
1701 if (++i >= sp->typecnt) {
1708 int hi = sp->timecnt;
1711 int mid = (lo + hi) >> 1;
1713 if (t.tv_sec < sp->ats[mid])
1718 i = (int) sp->types[lo - 1];
1720 ttisp = &sp->ttis[i];
1727 result = timesub(&t, ttisp->tt_gmtoff, sp, tmp);
1733 tmp->TM_ZONE = &sp->chars[ttisp->tt_abbrind];
1735 tmp->
tm_usec = timep->tv_usec;
1741 const struct state *sp = ast_tzset(zone);
1742 memset(tmp, 0,
sizeof(*tmp));
1743 return sp ?
localsub(timep, 0L, tmp, sp) : NULL;
1754 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)
1757 int transition1 = -1;
1758 int transition2 = -1;
1760 int bounds_exceeded = 0;
1762 const struct state *sp;
1764 if (NULL == dst_enabled)
1768 if (NULL == dst_start || NULL == dst_end || NULL == gmt_off)
1773 sp = ast_tzset(zone);
1783 if ((sp->goback && t < sp->ats[0]) ||
1784 (sp->goahead && t > sp->ats[sp->timecnt - 1])) {
1786 int_fast64_t icycles;
1789 seconds = sp->ats[0] - t;
1790 else seconds = t - sp->ats[sp->timecnt - 1];
1792 tcycles = seconds / YEARSPERREPEAT / AVGSECSPERYEAR;
1795 if (tcycles - icycles >= 1 || icycles - tcycles >= 1)
1798 seconds *= YEARSPERREPEAT;
1799 seconds *= AVGSECSPERYEAR;
1805 if (t < sp->ats[0] || t > sp->ats[sp->timecnt - 1])
1808 bounds_exceeded = 1;
1811 if (sp->timecnt == 0 || t < sp->ats[0]) {
1816 while (sp->ttis[i].tt_isdst) {
1817 if (++i >= sp->typecnt) {
1822 *gmt_off = sp->ttis[i].tt_gmtoff;
1826 for (i = 1; i < sp->timecnt; ++i) {
1827 if (t < sp->ats[i]) {
1828 transition1 = sp->types[i - 1];
1829 transition2 = sp->types[i];
1835 if (i >= sp->timecnt || 0 > transition1 || 0 > transition2 ||
1836 (sp->ttis[transition1].tt_isdst == sp->ttis[transition2].tt_isdst)) {
1838 *gmt_off = sp->ttis[sp->types[sp->timecnt -1]].tt_gmtoff;
1841 if(sp->ttis[transition2].tt_isdst)
1842 *gmt_off = sp->ttis[transition1].tt_gmtoff;
1844 *gmt_off = sp->ttis[transition2].tt_gmtoff;
1847 if (!bounds_exceeded) {
1850 if(sp->ttis[transition2].tt_isdst) {
1851 *dst_start = sp->ats[i];
1852 *dst_end = sp->ats[i -1];
1854 *dst_start = sp->ats[i -1];
1855 *dst_end = sp->ats[i];
1866 static struct ast_tm *gmtsub(
const struct timeval *timep,
const long offset,
struct ast_tm *tmp)
1873 if (!strcmp(sp->
name,
"UTC"))
1878 if (!(sp = sstate_alloc())) {
1887 result = timesub(timep, offset, sp, tmp);
1897 tmp->TM_ZONE = sp->chars;
1909 return (y >= 0) ? (y / 4 - y / 100 + y / 400) :
1913 static struct ast_tm *timesub(
const struct timeval *timep,
const long offset,
const struct state *sp,
struct ast_tm *tmp)
1915 const struct lsinfo * lp;
1929 i = (sp == NULL) ? 0 : sp->leapcnt;
1932 if (timep->tv_sec >= lp->ls_trans) {
1933 if (timep->tv_sec == lp->ls_trans) {
1934 hit = ((i == 0 && lp->ls_corr > 0) ||
1935 lp->ls_corr > sp->lsis[i - 1].ls_corr);
1938 sp->lsis[i].ls_trans ==
1939 sp->lsis[i - 1].ls_trans + 1 &&
1940 sp->lsis[i].ls_corr ==
1941 sp->lsis[i - 1].ls_corr + 1) {
1951 tdays = timep->tv_sec / SECSPERDAY;
1952 rem = timep->tv_sec - tdays * SECSPERDAY;
1953 while (tdays < 0 || tdays >= year_lengths[isleap(y)]) {
1959 tdelta = tdays / DAYSPERLYEAR;
1961 if (tdelta - idelta >= 1 || idelta - tdelta >= 1)
1964 idelta = (tdays < 0) ? -1 : 1;
1970 tdays -= ((time_t) newy - y) * DAYSPERNYEAR;
1975 seconds = tdays * SECSPERDAY + 0.5;
1976 tdays = seconds / SECSPERDAY;
1977 rem += seconds - tdays * SECSPERDAY;
1983 rem += offset - corr;
1988 while (rem >= SECSPERDAY) {
1995 idays += year_lengths[isleap(y)];
1997 while (idays >= year_lengths[isleap(y)]) {
1998 idays -= year_lengths[isleap(y)];
2010 ((y - EPOCH_YEAR) % DAYSPERWEEK) *
2011 (DAYSPERNYEAR % DAYSPERWEEK) +
2018 tmp->
tm_hour = (int) (rem / SECSPERHOUR);
2020 tmp->
tm_min = (int) (rem / SECSPERMIN);
2025 tmp->
tm_sec = (int) (rem % SECSPERMIN) + hit;
2026 ip = mon_lengths[isleap(y)];
2028 idays -= ip[tmp->
tm_mon];
2029 tmp->
tm_mday = (int) (idays + 1);
2032 tmp->TM_GMTOFF = offset;
2034 tmp->
tm_usec = timep->tv_usec;
2057 return (*number < number0) != (delta < 0);
2060 static int long_increment_overflow(
long *
number,
int delta)
2066 return (*number < number0) != (delta < 0);
2069 static int normalize_overflow(
int *tensptr,
int *unitsptr,
const int base)
2073 tensdelta = (*unitsptr >= 0) ?
2074 (*unitsptr / base) :
2075 (-1 - (-1 - *unitsptr) / base);
2076 *unitsptr -= tensdelta * base;
2080 static int long_normalize_overflow(
long *tensptr,
int *unitsptr,
const int base)
2084 tensdelta = (*unitsptr >= 0) ?
2085 (*unitsptr / base) :
2086 (-1 - (-1 - *unitsptr) / base);
2087 *unitsptr -= tensdelta * base;
2088 return long_increment_overflow(tensptr, tensdelta);
2091 static int tmcomp(
const struct ast_tm *atmp,
const struct ast_tm *btmp)
2105 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)
2114 struct timeval newt = { 0, 0 };
2115 struct timeval t = { 0, 0 };
2116 struct ast_tm yourtm, mytm;
2121 if (normalize_overflow(&yourtm.tm_min, &yourtm.tm_sec,
2125 if (normalize_overflow(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR))
2127 if (normalize_overflow(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY))
2130 if (long_normalize_overflow(&y, &yourtm.tm_mon, MONSPERYEAR))
2136 if (long_increment_overflow(&y, TM_YEAR_BASE))
2138 while (yourtm.tm_mday <= 0) {
2139 if (long_increment_overflow(&y, -1))
2141 li = y + (1 < yourtm.tm_mon);
2142 yourtm.tm_mday += year_lengths[isleap(li)];
2144 while (yourtm.tm_mday > DAYSPERLYEAR) {
2145 li = y + (1 < yourtm.tm_mon);
2146 yourtm.tm_mday -= year_lengths[isleap(li)];
2147 if (long_increment_overflow(&y, 1))
2151 i = mon_lengths[isleap(y)][yourtm.tm_mon];
2152 if (yourtm.tm_mday <= i)
2154 yourtm.tm_mday -= i;
2155 if (++yourtm.tm_mon >= MONSPERYEAR) {
2157 if (long_increment_overflow(&y, 1))
2161 if (long_increment_overflow(&y, -TM_YEAR_BASE))
2164 if (yourtm.tm_year != y)
2166 if (yourtm.tm_sec >= 0 && yourtm.tm_sec < SECSPERMIN)
2168 else if (y + TM_YEAR_BASE < EPOCH_YEAR) {
2179 saved_seconds = yourtm.tm_sec;
2180 yourtm.tm_sec = SECSPERMIN - 1;
2182 saved_seconds = yourtm.tm_sec;
2188 if (!TYPE_SIGNED(time_t)) {
2191 }
else if (!TYPE_INTEGRAL(time_t)) {
2192 if (
sizeof(time_t) >
sizeof(
float))
2193 hi = (time_t) DBL_MAX;
2194 else hi = (time_t) FLT_MAX;
2198 for (i = 0; i < (int) TYPE_BIT(time_t) - 1; ++i)
2203 t.tv_sec = lo / 2 + hi / 2;
2206 else if (t.tv_sec > hi)
2208 if ((*funcp)(&t, offset, &mytm, sp) == NULL) {
2214 dir = (t.tv_sec > 0) ? 1 : -1;
2215 }
else dir = tmcomp(&mytm, &yourtm);
2217 if (t.tv_sec == lo) {
2222 }
else if (t.tv_sec == hi) {
2235 if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst)
2246 for (i = sp->typecnt - 1; i >= 0; --i) {
2247 if (sp->ttis[i].tt_isdst != yourtm.tm_isdst)
2249 for (j = sp->typecnt - 1; j >= 0; --j) {
2250 if (sp->ttis[j].tt_isdst == yourtm.tm_isdst)
2252 newt.tv_sec = t.tv_sec + sp->ttis[j].tt_gmtoff -
2253 sp->ttis[i].tt_gmtoff;
2254 if ((*funcp)(&newt, offset, &mytm, sp) == NULL)
2256 if (tmcomp(&mytm, &yourtm) != 0)
2258 if (mytm.tm_isdst != yourtm.tm_isdst)
2270 newt.tv_sec = t.tv_sec + saved_seconds;
2271 if ((newt.tv_sec < t.tv_sec) != (saved_seconds < 0))
2273 t.tv_sec = newt.tv_sec;
2274 if ((*funcp)(&t, offset, tmp, sp))
2279 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)
2288 t = time2sub(tmp, funcp, offset, okayp, FALSE, sp);
2289 return *okayp ? t : time2sub(tmp, funcp, offset, okayp, TRUE, sp);
2292 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)
2296 int sameind, otherind;
2299 int seen[TZ_MAX_TYPES];
2300 int types[TZ_MAX_TYPES];
2303 if (tmp->tm_isdst > 1)
2305 t =
time2(tmp, funcp, offset, &okay, sp);
2312 if (tmp->tm_isdst < 0)
2316 if (okay || tmp->tm_isdst < 0)
2327 for (i = 0; i < sp->typecnt; ++i)
2330 for (i = sp->timecnt - 1; i >= 0; --i)
2331 if (!seen[sp->types[i]]) {
2332 seen[sp->types[i]] = TRUE;
2333 types[nseen++] = sp->types[i];
2335 for (sameind = 0; sameind < nseen; ++sameind) {
2336 samei = types[sameind];
2337 if (sp->ttis[samei].tt_isdst != tmp->tm_isdst)
2339 for (otherind = 0; otherind < nseen; ++otherind) {
2340 otheri = types[otherind];
2341 if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst)
2343 tmp->tm_sec += sp->ttis[otheri].tt_gmtoff -
2344 sp->ttis[samei].tt_gmtoff;
2345 tmp->tm_isdst = !tmp->tm_isdst;
2346 t =
time2(tmp, funcp, offset, &okay, sp);
2349 tmp->tm_sec -= sp->ttis[otheri].tt_gmtoff -
2350 sp->ttis[samei].tt_gmtoff;
2351 tmp->tm_isdst = !tmp->tm_isdst;
2359 const struct state *sp;
2360 if (!(sp = ast_tzset(zone)))
2362 return time1(tmp,
localsub, 0L, sp);
2365 #if defined(HAVE_NEWLOCALE) && defined(HAVE_USELOCALE)
2366 static struct locale_entry *find_by_locale(locale_t locale)
2370 if (locale == cur->locale) {
2381 if (strcmp(name, cur->name) == 0) {
2388 static const char *store_by_locale(locale_t prevlocale)
2391 if (prevlocale == LC_GLOBAL_LOCALE) {
2395 if ((cur = find_by_locale(prevlocale))) {
2402 for (x = 0; x < 10000; x++) {
2404 snprintf(name,
sizeof(name),
"%04d", x);
2406 if ((cur =
ast_calloc(1,
sizeof(*cur) + strlen(name) + 1))) {
2407 cur->locale = prevlocale;
2408 strcpy(cur->name, name);
2415 return cur ? cur->name : NULL;
2423 locale_t prevlocale = LC_GLOBAL_LOCALE;
2425 if (locale == NULL) {
2426 return store_by_locale(uselocale(LC_GLOBAL_LOCALE));
2431 prevlocale = uselocale(cur->locale);
2435 if ((cur =
ast_calloc(1,
sizeof(*cur) + strlen(locale) + 1))) {
2436 cur->locale = newlocale(LC_ALL_MASK, locale, NULL);
2437 strcpy(cur->name, locale);
2439 prevlocale = uselocale(cur->locale);
2443 return store_by_locale(prevlocale);
2452 int ast_strftime_locale(
char *buf,
size_t len,
const char *tmp,
const struct ast_tm *tm,
const char *locale)
2454 size_t fmtlen = strlen(tmp) + 1;
2455 char *format =
ast_calloc(1, fmtlen), *fptr = format, *newfmt;
2456 int decimals = -1, i, res;
2458 const char *prevlocale;
2464 for (; *tmp; tmp++) {
2473 if (tmp[2] !=
'q') {
2476 decimals = tmp[1] -
'0';
2480 if (decimals == -1) {
2490 fptr = fptr - format + newfmt;
2495 for (i = 6, fraction = tm->
tm_usec; i > decimals; i--) {
2498 fptr += sprintf(fptr,
"%0*ld", decimals, fraction);
2508 defcase: *fptr++ = *tmp;
2516 res = (int)strftime(buf, len, format, (
struct tm *)tm);
2526 return ast_strftime_locale(buf, len, tmp, tm, NULL);
2529 char *ast_strptime_locale(
const char *s,
const char *format,
struct ast_tm *tm,
const char *locale)
2531 struct tm tm2 = { 0, };
2533 const char *prevlocale;
2536 res = strptime(s, format, &tm2);
2542 memcpy(tm, &tm2,
sizeof(tm2));
2552 return ast_strptime_locale(s, format, tm, NULL);
static struct ast_tm * localsub(const struct timeval *timep, const long offset, struct ast_tm *tmp, const struct state *sp)
#define AST_LIST_LOCK(head)
Locks a list.
Asterisk locking-related definitions:
Asterisk main include file. File version handling, generic pbx functions.
static const char * getoffset(const char *strp, long *offsetp)
Given a pointer into a time zone string, extract an offset, in [+-]hh[:mm[:ss]] form, from the string. If any error occurs, return NULL. Otherwise, return a pointer to the first character not part of the time.
#define ast_realloc(p, len)
A wrapper for realloc()
String manipulation functions.
const char * ast_setlocale(const char *locale)
Set the thread-local representation of the current locale.
char name[TZ_STRLEN_MAX+1]
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
static const char * getqzname(const char *strp, const int delim)
Given a pointer into an extended time zone string, scan until the ending delimiter of the zone name i...
int ast_strftime(char *buf, size_t len, const char *tmp, const struct ast_tm *tm)
Special version of strftime(3) that handles fractions of a second. Takes the same arguments as strfti...
static const char * getrule(const char *strp, struct rule *rulep)
Given a pointer into a time zone string, extract a rule in the form date[/time]. See POSIX section 8 ...
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
struct ast_tm * ast_localtime(const struct timeval *timep, struct ast_tm *tmp, const char *zone)
Timezone-independent version of localtime_r(3).
#define AST_LIST_REMOVE(head, elm, field)
Removes a specific entry from a list.
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
Custom localtime functions for multiple timezones.
struct timeval ast_mktime(struct ast_tm *tmp, const char *zone)
Timezone-independent version of mktime(3).
static int find_by_name(void *obj, void *arg, void *data, int flags)
#define AST_LIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
A set of macros to manage forward-linked lists.
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
static long detzcode(const char *const codep)
#define AST_LIST_HEAD_STATIC(name, type)
Defines a structure to be used to hold a list of specified type, statically initialized.
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
static const char * getnum(const char *strp, int *nump, const int min, const int max)
Given a pointer into a time zone string, extract a number from that string. Check that the number is ...
static int increment_overflow(int *number, int delta)
Simplified normalize logic courtesy Paul Eggert.
static void common_startup(void)
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
#define AST_LIST_ENTRY(type)
Declare a forward link structure inside a list entry.
char * ast_strptime(const char *s, const char *format, struct ast_tm *tm)
Special version of strptime(3) which places the answer in the common structure ast_tm. Also, unlike strptime(3), ast_strptime() initializes its memory prior to use.
#define ast_calloc(num, len)
A wrapper for calloc()
Prototypes for public functions only of internal interest,.
static int leaps_thru_end_of(const int y)
Return the number of leap years through the end of the given year where, to make the math easy...
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
#define AST_LIST_TRYLOCK(head)
Locks a list, without blocking if the list is locked.
static const char * getsecs(const char *strp, long *const secsp)
Given a pointer into a time zone string, extract a number of seconds, in hh[:mm[:ss]] form...
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
static int tzparse(const char *name, struct state *sp, const int lastditch)
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)
void clean_time_zones(void)
Structure for mutex and tracking information.
static const char * getzname(const char *strp)
Given a pointer into a time zone string, scan until a character that is not a valid character in a zo...
static time_t transtime(const time_t janfirst, const int year, const struct rule *rulep, const long offset)
Given the Epoch-relative time of January 1, 00:00:00 UTC, in a year, the year, a rule, and the offset from UTC at the time that rule takes effect, calculate the Epoch-relative time that rule takes effect.