Mon Oct 8 12:39:24 2012

Asterisk developer's documentation


localtime.c File Reference

#include "asterisk.h"
#include <signal.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <float.h>
#include <stdlib.h>
#include <sys/inotify.h>
#include "private.h"
#include "tzfile.h"
#include "asterisk/lock.h"
#include "asterisk/localtime.h"
#include "asterisk/strings.h"
#include "asterisk/linkedlists.h"
#include "asterisk/utils.h"
#include "asterisk/test.h"

Go to the source code of this file.

Data Structures

struct  locale_entry
struct  localelist
struct  lsinfo
 leap second information More...
struct  rule
struct  state
struct  ttinfo
 time type information More...
struct  zonelist

Defines

#define BIGGEST(a, b)   (((a) > (b)) ? (a) : (b))
#define DAY_OF_YEAR   1
#define JULIAN_DAY   0
#define MONTH_NTH_DAY_OF_WEEK   2
#define MY_TZNAME_MAX   255
#define OPEN_MODE   O_RDONLY
#define TZ_ABBR_CHAR_SET   "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 :+-._"
#define TZ_ABBR_ERR_CHAR   '_'
#define TZ_ABBR_MAX_LEN   16
#define TZ_STRLEN_MAX   255
#define TZDEFRULESTRING   ",M4.1.0,M10.5.0"

Functions

static void add_notify (struct state *sp, const char *path)
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)
ast_tmast_localtime (const struct timeval *timep, struct ast_tm *tmp, const char *zone)
 Timezone-independent version of localtime_r(3).
void ast_localtime_wakeup_monitor (struct ast_test *info)
timeval ast_mktime (struct ast_tm *tmp, const char *zone)
 Timezone-independent version of mktime(3).
const char * ast_setlocale (const char *locale)
 Set the thread-local representation of the current locale.
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 strftime(3), with the addition of q, which specifies microseconds.
int ast_strftime_locale (char *buf, size_t len, const char *tmp, const struct ast_tm *tm, const char *locale)
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.
char * ast_strptime_locale (const char *s, const char *format, struct ast_tm *tm, const char *locale)
static struct stateast_tzset (const char *zone)
static long detzcode (const char *const codep)
static time_t detzcode64 (const char *const codep)
static int differ_by_repeat (const time_t t1, const time_t t0)
static struct locale_entryfind_by_locale (locale_t locale)
static struct locale_entryfind_by_name (const char *name)
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 within a specified range; if it is not, return NULL. Otherwise, return a pointer to the first character not part of the number.
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.
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 is located. Return a pointer to the delimiter.
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 for the format of "date" and "time". If a valid rule is not found, return NULL. Otherwise, return a pointer to the first character not part of the rule.
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, from the string. If any error occurs, return NULL. Otherwise, return a pointer to the first character not part of the number of seconds.
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 zone name is found. Return a pointer to that character.
static int gmtload (struct state *sp)
static struct ast_tmgmtsub (const struct timeval *timep, const long offset, struct ast_tm *tmp)
static int increment_overflow (int *number, int delta)
 Simplified normalize logic courtesy Paul Eggert.
static void * inotify_daemon (void *data)
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, the answer for year zero is defined as zero.
static struct ast_tmlocalsub (const struct timeval *timep, const long offset, struct ast_tm *tmp, const struct state *sp)
static int long_increment_overflow (long *number, int delta)
static int long_normalize_overflow (long *tensptr, int *unitsptr, const int base)
static int normalize_overflow (int *tensptr, int *unitsptr, const int base)
static int tzparse P ((const char *name, struct state *sp, int lastditch))
static int tzload P ((const char *name, struct state *sp, int doextend))
static time_t transtime P ((time_t janfirst, int year, const struct rule *rulep, long offset))
static int tmcomp P ((const struct ast_tm *atmp, const struct ast_tm *btmp))
static struct ast_tm *timesub P ((const struct timeval *timep, long offset, const struct state *sp, struct ast_tm *tmp))
static struct timeval time2sub P ((struct ast_tm *tmp, struct ast_tm *(*funcp)(const struct timeval *, long, struct ast_tm *, const struct state *sp), long offset, int *okayp, int do_norm_secs, const struct state *sp))
static struct timeval time2 P ((struct ast_tm *tmp, struct ast_tm *(*funcp) P((const struct timeval *, long, struct ast_tm *, const struct state *sp)), long offset, int *okayp, const struct state *sp))
static struct timeval time1 P ((struct ast_tm *tmp, struct ast_tm *(*funcp) P((const struct timeval *, long, struct ast_tm *, const struct state *sp)), long offset, const struct state *sp))
static int normalize_overflow P ((int *tensptr, int *unitsptr, const int base))
static int long_normalize_overflow P ((long *tensptr, int *unitsptr, const int base))
static int long_increment_overflow P ((long *number, int delta))
static int leaps_thru_end_of P ((int y))
static int increment_overflow P ((int *number, int delta))
static struct ast_tm *localsub P ((const struct timeval *timep, long offset, struct ast_tm *tmp, const struct state *sp))
static struct ast_tm *gmtsub P ((const struct timeval *timep, long offset, struct ast_tm *tmp))
static int gmtload P ((struct state *sp))
static const char *getrule P ((const char *strp, struct rule *rulep))
static const char *getoffset P ((const char *strp, long *offsetp))
static const char *getsecs P ((const char *strp, long *secsp))
static const char *getnum P ((const char *strp, int *nump, int min, int max))
static const char *getqzname P ((const char *strp, const int delim))
static const char *getzname P ((const char *strp))
static int differ_by_repeat P ((time_t t1, time_t t0))
static long detzcode P ((const char *codep))
static const char * store_by_locale (locale_t prevlocale)
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)
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)
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)
static struct ast_tmtimesub (const struct timeval *timep, const long offset, const struct state *sp, struct ast_tm *tmp)
static int tmcomp (const struct ast_tm *atmp, const struct ast_tm *btmp)
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.
static int tzload (const char *name, struct state *const sp, const int doextend)
static int tzparse (const char *name, struct state *sp, const int lastditch)

Variables

static char elsieid [] = "@(#)localtime.c 8.5"
static const char gmt [] = "GMT"
static ast_cond_t initialization
static ast_mutex_t initialization_lock
static int inotify_fd = -1
static pthread_t inotify_thread = AST_PTHREADT_NULL
static const int mon_lengths [2][MONSPERYEAR]
static struct timeval WRONG = { 0, 0 }
static const int year_lengths [2]


Detailed Description

Multi-timezone Localtime code

The original source from this file may be obtained from ftp://elsie.nci.nih.gov/pub/

Definition in file localtime.c.


Define Documentation

#define BIGGEST ( a,
 )     (((a) > (b)) ? (a) : (b))

Definition at line 147 of file localtime.c.

#define DAY_OF_YEAR   1

Definition at line 204 of file localtime.c.

Referenced by getrule(), and transtime().

#define JULIAN_DAY   0

Definition at line 203 of file localtime.c.

Referenced by getrule(), and transtime().

#define MONTH_NTH_DAY_OF_WEEK   2

Definition at line 205 of file localtime.c.

Referenced by getrule(), and transtime().

#define MY_TZNAME_MAX   255

Definition at line 153 of file localtime.c.

#define OPEN_MODE   O_RDONLY

Definition at line 108 of file localtime.c.

Referenced by tzload().

#define TZ_ABBR_CHAR_SET   "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 :+-._"

Definition at line 92 of file localtime.c.

#define TZ_ABBR_ERR_CHAR   '_'

Definition at line 97 of file localtime.c.

#define TZ_ABBR_MAX_LEN   16

Definition at line 88 of file localtime.c.

#define TZ_STRLEN_MAX   255

Definition at line 156 of file localtime.c.

#define TZDEFRULESTRING   ",M4.1.0,M10.5.0"

Note:
The DST rules to use if TZ has no rules and we can't load TZDEFRULES. We default to US rules as of 1999-08-17. POSIX 1003.1 section 8.1.1 says that the default DST rules are implementation dependent; for historical reasons, US rules are a common default.

Definition at line 129 of file localtime.c.

Referenced by tzparse().


Function Documentation

static void add_notify ( struct state sp,
const char *  path 
) [static]

Definition at line 327 of file localtime.c.

References ast_cond_init, ast_cond_wait, ast_mutex_init, ast_mutex_lock, ast_mutex_unlock, ast_pthread_create_background, AST_PTHREADT_NULL, FILENAME_MAX, initialization, initialization_lock, inotify_daemon(), inotify_fd, inotify_thread, and state::wd.

Referenced by tzload().

00328 {
00329    if (inotify_thread == AST_PTHREADT_NULL) {
00330       ast_cond_init(&initialization, NULL);
00331       ast_mutex_init(&initialization_lock);
00332       ast_mutex_lock(&initialization_lock);
00333       if (!(ast_pthread_create_background(&inotify_thread, NULL, inotify_daemon, NULL))) {
00334          /* Give the thread a chance to initialize */
00335          ast_cond_wait(&initialization, &initialization_lock);
00336       } else {
00337          fprintf(stderr, "Unable to start notification thread\n");
00338          ast_mutex_unlock(&initialization_lock);
00339          return;
00340       }
00341       ast_mutex_unlock(&initialization_lock);
00342    }
00343 
00344    if (inotify_fd > -1) {
00345       char fullpath[FILENAME_MAX + 1] = "";
00346       if (readlink(path, fullpath, sizeof(fullpath) - 1) != -1) {
00347          /* If file the symlink points to changes */
00348          sp->wd[1] = inotify_add_watch(inotify_fd, fullpath, IN_ATTRIB | IN_DELETE_SELF | IN_MODIFY | IN_MOVE_SELF | IN_CLOSE_WRITE );
00349       } else {
00350          sp->wd[1] = -1;
00351       }
00352       /* or if the symlink itself changes (or the real file is here, if path is not a symlink) */
00353       sp->wd[0] = inotify_add_watch(inotify_fd, path, IN_ATTRIB | IN_DELETE_SELF | IN_MODIFY | IN_MOVE_SELF | IN_CLOSE_WRITE
00354 #ifdef IN_DONT_FOLLOW   /* Only defined in glibc 2.5 and above */
00355          | IN_DONT_FOLLOW
00356 #endif
00357       );
00358    }
00359 }

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 
)

Definition at line 1566 of file localtime.c.

References ast_tzset(), state::ats, AVGSECSPERYEAR, state::goahead, state::goback, int_fast64_t, state::timecnt, ttinfo::tt_gmtoff, ttinfo::tt_isdst, state::ttis, state::typecnt, state::types, and YEARSPERREPEAT.

Referenced by set_timezone_variables().

01567 {
01568    int i;   
01569    int transition1 = -1;
01570    int transition2 = -1;
01571    time_t      seconds;
01572    int  bounds_exceeded = 0;
01573    time_t  t = *timep;
01574    const struct state *sp;
01575    
01576    if (NULL == dst_enabled)
01577       return;
01578    *dst_enabled = 0;
01579 
01580    if (NULL == dst_start || NULL == dst_end || NULL == gmt_off)
01581       return;
01582 
01583    *gmt_off = 0; 
01584    
01585    sp = ast_tzset(zone);
01586    if (NULL == sp) 
01587       return;
01588    
01589    /* If the desired time exceeds the bounds of the defined time transitions  
01590    * then give give up on determining DST info and simply look for gmt offset 
01591    * This requires that I adjust the given time using increments of Gregorian 
01592    * repeats to place the time within the defined time transitions in the 
01593    * timezone structure.  
01594    */
01595    if ((sp->goback && t < sp->ats[0]) ||
01596          (sp->goahead && t > sp->ats[sp->timecnt - 1])) {
01597       time_t      tcycles;
01598       int_fast64_t   icycles;
01599 
01600       if (t < sp->ats[0])
01601          seconds = sp->ats[0] - t;
01602       else  seconds = t - sp->ats[sp->timecnt - 1];
01603       --seconds;
01604       tcycles = seconds / YEARSPERREPEAT / AVGSECSPERYEAR;
01605       ++tcycles;
01606       icycles = tcycles;
01607       if (tcycles - icycles >= 1 || icycles - tcycles >= 1)
01608          return;
01609       seconds = icycles;
01610       seconds *= YEARSPERREPEAT;
01611       seconds *= AVGSECSPERYEAR;
01612       if (t < sp->ats[0])
01613          t += seconds;
01614       else
01615          t -= seconds;
01616       
01617       if (t < sp->ats[0] || t > sp->ats[sp->timecnt - 1])
01618          return;  /* "cannot happen" */
01619 
01620       bounds_exceeded = 1;
01621    }
01622 
01623    if (sp->timecnt == 0 || t < sp->ats[0]) {
01624       /* I have no transition times or I'm before time */
01625       *dst_enabled = 0;
01626       /* Find where I can get gmtoff */
01627       i = 0;
01628       while (sp->ttis[i].tt_isdst)
01629          if (++i >= sp->typecnt) {
01630          i = 0;
01631          break;
01632          }
01633          *gmt_off = sp->ttis[i].tt_gmtoff;
01634          return;
01635    } 
01636 
01637    for (i = 1; i < sp->timecnt; ++i) {
01638       if (t < sp->ats[i]) {
01639          transition1 = sp->types[i - 1];
01640          transition2 = sp->types[i];
01641          break;
01642       } 
01643    }
01644    /* if I found transition times that do not bounded the given time and these correspond to 
01645       or the bounding zones do not reflect a changes in day light savings, then I do not have dst active */
01646    if (i >= sp->timecnt || 0 > transition1 || 0 > transition2 ||
01647          (sp->ttis[transition1].tt_isdst == sp->ttis[transition2].tt_isdst)) {
01648       *dst_enabled = 0;
01649       *gmt_off     = sp->ttis[sp->types[sp->timecnt -1]].tt_gmtoff;
01650    } else {
01651       /* I have valid daylight savings information. */
01652       if(sp->ttis[transition2].tt_isdst) 
01653          *gmt_off = sp->ttis[transition1].tt_gmtoff;
01654       else 
01655          *gmt_off = sp->ttis[transition2].tt_gmtoff;
01656 
01657       /* If I adjusted the time earlier, indicate that the dst is invalid */
01658       if (!bounds_exceeded) {
01659          *dst_enabled = 1;
01660          /* Determine which of the bounds is the start of daylight savings and which is the end */
01661          if(sp->ttis[transition2].tt_isdst) {
01662             *dst_start = sp->ats[i];
01663             *dst_end = sp->ats[i -1];
01664          } else {
01665             *dst_start = sp->ats[i -1];
01666             *dst_end = sp->ats[i];
01667          }
01668       }
01669    }  
01670    return;
01671 }

struct ast_tm* ast_localtime ( const struct timeval *  timep,
struct ast_tm p_tm,
const char *  zone 
)

Timezone-independent version of localtime_r(3).

Parameters:
timep Current time, including microseconds
p_tm Pointer to memory where the broken-out time will be stored
zone Text string of a standard system zoneinfo file. If NULL, the system localtime will be used.
Return values:
p_tm is returned for convenience

Definition at line 1551 of file localtime.c.

References ast_tzset(), and localsub().

Referenced by __ast_verbose_ap(), acf_strftime(), action_corestatus(), append_date(), ast_cel_fabricate_channel_from_event(), ast_check_timing2(), ast_http_send(), ast_log(), ast_queue_log(), ast_say_date_da(), ast_say_date_de(), ast_say_date_en(), ast_say_date_fr(), ast_say_date_gr(), ast_say_date_he(), ast_say_date_hu(), ast_say_date_ka(), ast_say_date_nl(), ast_say_date_pt(), ast_say_date_th(), ast_say_date_with_format_da(), ast_say_date_with_format_de(), ast_say_date_with_format_en(), ast_say_date_with_format_es(), ast_say_date_with_format_fr(), ast_say_date_with_format_gr(), ast_say_date_with_format_he(), ast_say_date_with_format_it(), ast_say_date_with_format_nl(), ast_say_date_with_format_pl(), ast_say_date_with_format_pt(), ast_say_date_with_format_th(), ast_say_date_with_format_vi(), ast_say_date_with_format_zh(), ast_say_datetime_de(), ast_say_datetime_en(), ast_say_datetime_fr(), ast_say_datetime_from_now_en(), ast_say_datetime_from_now_fr(), ast_say_datetime_from_now_he(), ast_say_datetime_from_now_ka(), ast_say_datetime_from_now_pt(), ast_say_datetime_gr(), ast_say_datetime_he(), ast_say_datetime_hu(), ast_say_datetime_ka(), ast_say_datetime_nl(), ast_say_datetime_pt(), ast_say_datetime_pt_BR(), ast_say_datetime_th(), ast_say_datetime_zh(), ast_say_time_de(), ast_say_time_en(), ast_say_time_fr(), ast_say_time_gr(), ast_say_time_he(), ast_say_time_hu(), ast_say_time_ka(), ast_say_time_nl(), ast_say_time_pt(), ast_say_time_pt_BR(), ast_say_time_th(), ast_say_time_zh(), build_device(), build_radius_record(), callerid_genmsg(), cdr_get_tv(), cli_prompt(), conf_run(), enc_ie_date(), epoch_to_string(), exchangecal_get_events_between(), execute_cb(), find_conf_realtime(), format_date(), get_date(), get_ewscal_ids_for(), handle_cli_odbc_show(), handle_minivm_show_stats(), handle_show_settings(), iax2_datetime(), isodate(), leave_voicemail(), main(), make_email_file(), manager_log(), mstime(), odbc_log(), packdate(), pgsql_log(), phone_call(), play_message_datetime(), prep_email_sub_vars(), rt_extend_conf(), say_date_generic(), send_date_time(), send_date_time2(), send_date_time3(), sendmail(), set_timezone_variables(), sip_show_registry(), sms_compose2(), sms_handleincoming_proto2(), static_callback(), timeout_write(), transmit_definetimedate(), transmit_notify_request_with_callerid(), vmu_tm(), write_history(), and write_metadata().

01552 {
01553    const struct state *sp = ast_tzset(zone);
01554    memset(tmp, 0, sizeof(*tmp));
01555    return sp ? localsub(timep, 0L, tmp, sp) : NULL;
01556 }

void ast_localtime_wakeup_monitor ( struct ast_test *  info  ) 

Definition at line 606 of file localtime.c.

References ast_cond_wait, AST_LIST_LOCK, AST_LIST_UNLOCK, AST_PTHREADT_NULL, initialization, inotify_thread, and lock.

00607 {
00608    if (inotify_thread != AST_PTHREADT_NULL) {
00609       AST_LIST_LOCK(&zonelist);
00610 #ifdef TEST_FRAMEWORK
00611       test = info;
00612 #endif
00613       pthread_kill(inotify_thread, SIGURG);
00614       ast_cond_wait(&initialization, &(&zonelist)->lock);
00615 #ifdef TEST_FRAMEWORK
00616       test = NULL;
00617 #endif
00618       AST_LIST_UNLOCK(&zonelist);
00619    }
00620 }

struct timeval ast_mktime ( struct ast_tm *const   tmp,
const char *  zone 
)

Timezone-independent version of mktime(3).

Parameters:
tmp Current broken-out time, including microseconds
zone Text string of a standard system zoneinfo file. If NULL, the system localtime will be used.
Return values:
A structure containing both seconds and fractional thereof since January 1st, 1970 UTC

Definition at line 2166 of file localtime.c.

References ast_tzset(), localsub(), and time1().

Referenced by acf_strptime(), conf_run(), icalfloat_to_timet(), mstime_to_time_t(), rt_extend_conf(), sms_handleincoming_proto2(), sms_readfile(), testtime_write(), and unpackdate().

02167 {
02168    const struct state *sp;
02169    if (!(sp = ast_tzset(zone)))
02170       return WRONG;
02171    return time1(tmp, localsub, 0L, sp);
02172 }

const char* ast_setlocale ( const char *  locale  ) 

Set the thread-local representation of the current locale.

Definition at line 2229 of file localtime.c.

References ast_calloc, AST_LIST_INSERT_TAIL, AST_LIST_LOCK, AST_LIST_UNLOCK, find_by_name(), locale_entry::list, locale_entry::locale, and store_by_locale().

Referenced by ast_strftime_locale(), and ast_strptime_locale().

02230 {
02231    struct locale_entry *cur;
02232    locale_t prevlocale = LC_GLOBAL_LOCALE;
02233 
02234    if (locale == NULL) {
02235       return store_by_locale(uselocale(LC_GLOBAL_LOCALE));
02236    }
02237 
02238    AST_LIST_LOCK(&localelist);
02239    if ((cur = find_by_name(locale))) {
02240       prevlocale = uselocale(cur->locale);
02241    }
02242 
02243    if (!cur) {
02244       if ((cur = ast_calloc(1, sizeof(*cur) + strlen(locale) + 1))) {
02245          cur->locale = newlocale(LC_ALL_MASK, locale, NULL);
02246          strcpy(cur->name, locale); /* SAFE */
02247          AST_LIST_INSERT_TAIL(&localelist, cur, list);
02248          prevlocale = uselocale(cur->locale);
02249       }
02250    }
02251    AST_LIST_UNLOCK(&localelist);
02252    return store_by_locale(prevlocale);
02253 }

int ast_strftime ( char *  buf,
size_t  len,
const char *  format,
const struct ast_tm tm 
)

Special version of strftime(3) that handles fractions of a second. Takes the same arguments as strftime(3), with the addition of q, which specifies microseconds.

Parameters:
buf Address in memory where the resulting string will be stored.
len Size of the chunk of memory buf.
format A string specifying the format of time to be placed into buf.
tm Pointer to the broken out time to be used for the format.
locale Text string specifying the locale to be used for language strings.
Return values:
An integer value specifying the number of bytes placed into buf or -1 on error.

Definition at line 2332 of file localtime.c.

References ast_strftime_locale().

Referenced by __ast_verbose_ap(), acf_strftime(), action_corestatus(), append_date(), ast_cel_fabricate_channel_from_event(), ast_http_send(), ast_log(), ast_queue_log(), build_radius_record(), cdr_get_tv(), cli_prompt(), conf_run(), dump_datetime(), epoch_to_string(), exchangecal_get_events_between(), execute_cb(), find_conf_realtime(), format_date(), get_date(), get_ewscal_ids_for(), handle_cli_odbc_show(), handle_minivm_show_stats(), handle_show_settings(), isodate(), leave_voicemail(), make_email_file(), manager_log(), mstime(), odbc_log(), pgsql_log(), rt_extend_conf(), sendmail(), sendpage(), sip_show_registry(), static_callback(), timeout_write(), and write_metadata().

02333 {
02334    return ast_strftime_locale(buf, len, tmp, tm, NULL);
02335 }

int ast_strftime_locale ( char *  buf,
size_t  len,
const char *  tmp,
const struct ast_tm tm,
const char *  locale 
)

Definition at line 2261 of file localtime.c.

References ast_calloc, ast_free, ast_realloc, ast_setlocale(), format, and ast_tm::tm_usec.

Referenced by ast_strftime(), make_email_file(), prep_email_sub_vars(), and sendpage().

02262 {
02263    size_t fmtlen = strlen(tmp) + 1;
02264    char *format = ast_calloc(1, fmtlen), *fptr = format, *newfmt;
02265    int decimals = -1, i, res;
02266    long fraction;
02267    const char *prevlocale;
02268 
02269    if (!format) {
02270       return -1;
02271    }
02272    for (; *tmp; tmp++) {
02273       if (*tmp == '%') {
02274          switch (tmp[1]) {
02275          case '1':
02276          case '2':
02277          case '3':
02278          case '4':
02279          case '5':
02280          case '6':
02281             if (tmp[2] != 'q') {
02282                goto defcase;
02283             }
02284             decimals = tmp[1] - '0';
02285             tmp++;
02286             /* Fall through */
02287          case 'q': /* Milliseconds */
02288             if (decimals == -1) {
02289                decimals = 3;
02290             }
02291 
02292             /* Juggle some memory to fit the item */
02293             newfmt = ast_realloc(format, fmtlen + decimals);
02294             if (!newfmt) {
02295                ast_free(format);
02296                return -1;
02297             }
02298             fptr = fptr - format + newfmt;
02299             format = newfmt;
02300             fmtlen += decimals;
02301 
02302             /* Reduce the fraction of time to the accuracy needed */
02303             for (i = 6, fraction = tm->tm_usec; i > decimals; i--) {
02304                fraction /= 10;
02305             }
02306             fptr += sprintf(fptr, "%0*ld", decimals, fraction);
02307 
02308             /* Reset, in case more than one 'q' specifier exists */
02309             decimals = -1;
02310             tmp++;
02311             break;
02312          default:
02313             goto defcase;
02314          }
02315       } else {
02316 defcase: *fptr++ = *tmp;
02317       }
02318    }
02319    *fptr = '\0';
02320 #undef strftime
02321    if (locale) {
02322       prevlocale = ast_setlocale(locale);
02323    }
02324    res = (int)strftime(buf, len, format, (struct tm *)tm);
02325    if (locale) {
02326       ast_setlocale(prevlocale);
02327    }
02328    ast_free(format);
02329    return res;
02330 }

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.

Parameters:
s A string specifying some portion of a date and time.
format The format in which the string, s, is expected.
tm The broken-out time structure into which the parsed data is expected.
locale Text string specifying the locale to be used for language strings.
Return values:
A pointer to the first character within s not used to parse the date and time.

Definition at line 2358 of file localtime.c.

References ast_strptime_locale().

Referenced by acf_strptime(), conf_run(), mstime_to_time_t(), rt_extend_conf(), and testtime_write().

02359 {
02360    return ast_strptime_locale(s, format, tm, NULL);
02361 }

char* ast_strptime_locale ( const char *  s,
const char *  format,
struct ast_tm tm,
const char *  locale 
)

Definition at line 2337 of file localtime.c.

References ast_setlocale(), ast_tm::tm_isdst, and ast_tm::tm_usec.

Referenced by ast_strptime().

02338 {
02339    struct tm tm2 = { 0, };
02340    char *res;
02341    const char *prevlocale;
02342 
02343    prevlocale = ast_setlocale(locale);
02344    res = strptime(s, format, &tm2);
02345    ast_setlocale(prevlocale);
02346    /* ast_time and tm are not the same size - tm is a subset of
02347     * ast_time.  Hence, the size of tm needs to be used for the
02348     * memcpy
02349     */
02350    memcpy(tm, &tm2, sizeof(tm2));
02351    tm->tm_usec = 0;
02352    /* strptime(3) doesn't set .tm_isdst correctly, so to force ast_mktime(3)
02353     * to deal with it correctly, we set it to -1. */
02354    tm->tm_isdst = -1;
02355    return res;
02356 }

static struct state* ast_tzset ( const char *  zone  )  [static]

Definition at line 1413 of file localtime.c.

References ast_calloc, ast_copy_string(), AST_LIST_INSERT_TAIL, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_strlen_zero(), FALSE, gmtload(), state::list, state::name, TRUE, tzload(), and tzparse().

Referenced by ast_get_dst_info(), ast_localtime(), and ast_mktime().

01414 {
01415    struct state *sp;
01416 
01417    if (ast_strlen_zero(zone)) {
01418 #ifdef SOLARIS
01419       zone = getenv("TZ");
01420       if (ast_strlen_zero(zone)) {
01421          zone = "GMT";
01422       }
01423 #else
01424       zone = "/etc/localtime";
01425 #endif
01426    }
01427 
01428    AST_LIST_LOCK(&zonelist);
01429    AST_LIST_TRAVERSE(&zonelist, sp, list) {
01430       if (!strcmp(sp->name, zone)) {
01431          AST_LIST_UNLOCK(&zonelist);
01432          return sp;
01433       }
01434    }
01435    AST_LIST_UNLOCK(&zonelist);
01436 
01437    if (!(sp = ast_calloc(1, sizeof *sp)))
01438       return NULL;
01439 
01440    if (tzload(zone, sp, TRUE) != 0) {
01441       if (zone[0] == ':' || tzparse(zone, sp, FALSE) != 0)
01442          (void) gmtload(sp);
01443    }
01444    ast_copy_string(sp->name, zone, sizeof(sp->name));
01445    AST_LIST_LOCK(&zonelist);
01446    AST_LIST_INSERT_TAIL(&zonelist, sp, list);
01447    AST_LIST_UNLOCK(&zonelist);
01448    return sp;
01449 }

static long detzcode ( const char *const   codep  )  [static]

Note:
Section 4.12.3 of X3.159-1989 requires that Except for the strftime function, these functions [asctime, ctime, gmtime, localtime] return values in one of two static objects: a broken-down time structure and an array of char. Thanks to Paul Eggert for noting this.

Definition at line 630 of file localtime.c.

Referenced by tzload().

00631 {
00632    long  result;
00633    int   i;
00634 
00635    result = (codep[0] & 0x80) ? ~0L : 0;
00636    for (i = 0; i < 4; ++i)
00637       result = (result << 8) | (codep[i] & 0xff);
00638    return result;
00639 }

static time_t detzcode64 ( const char *const   codep  )  [static]

Definition at line 641 of file localtime.c.

References int_fast64_t.

Referenced by tzload().

00642 {
00643    time_t   result;
00644    int   i;
00645 
00646    result = (codep[0] & 0x80) ?  (~(int_fast64_t) 0) : 0;
00647    for (i = 0; i < 8; ++i)
00648       result = result * 256 + (codep[i] & 0xff);
00649    return result;
00650 }

static int differ_by_repeat ( const time_t  t1,
const time_t  t0 
) [static]

Definition at line 652 of file localtime.c.

References SECSPERREPEAT, SECSPERREPEAT_BITS, TYPE_BIT, TYPE_INTEGRAL, and TYPE_SIGNED.

00653 {
00654    const long long at1 = t1, at0 = t0;
00655    if (TYPE_INTEGRAL(time_t) &&
00656       TYPE_BIT(time_t) - TYPE_SIGNED(time_t) < SECSPERREPEAT_BITS)
00657          return 0;
00658    return at1 - at0 == SECSPERREPEAT;
00659 }

static struct locale_entry* find_by_locale ( locale_t  locale  )  [static]

Definition at line 2175 of file localtime.c.

References AST_LIST_TRAVERSE, locale_entry::list, and locale_entry::locale.

Referenced by store_by_locale().

02176 {
02177    struct locale_entry *cur;
02178    AST_LIST_TRAVERSE(&localelist, cur, list) {
02179       if (locale == cur->locale) {
02180          return cur;
02181       }
02182    }
02183    return NULL;
02184 }

static struct locale_entry* find_by_name ( const char *  name  )  [static]

Definition at line 2186 of file localtime.c.

References AST_LIST_TRAVERSE, locale_entry::list, and locale_entry::name.

02187 {
02188    struct locale_entry *cur;
02189    AST_LIST_TRAVERSE(&localelist, cur, list) {
02190       if (strcmp(name, cur->name) == 0) {
02191          return cur;
02192       }
02193    }
02194    return NULL;
02195 }

static const char* getnum ( const char *  strp,
int *  nump,
const int  min,
const int  max 
) [static]

Given a pointer into a time zone string, extract a number from that string. Check that the number is within a specified range; if it is not, return NULL. Otherwise, return a pointer to the first character not part of the number.

Definition at line 942 of file localtime.c.

References is_digit.

Referenced by getrule(), and getsecs().

00943 {
00944    char  c;
00945    int   num;
00946 
00947    if (strp == NULL || !is_digit(c = *strp))
00948       return NULL;
00949    num = 0;
00950    do {
00951       num = num * 10 + (c - '0');
00952       if (num > max)
00953          return NULL;   /* illegal value */
00954       c = *++strp;
00955    } while (is_digit(c));
00956    if (num < min)
00957       return NULL;      /* illegal value */
00958    *nump = num;
00959    return strp;
00960 }

static const char* getoffset ( const char *  strp,
long *  offsetp 
) [static]

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.

Definition at line 1009 of file localtime.c.

References getsecs().

Referenced by tzparse().

01010 {
01011    int   neg = 0;
01012 
01013    if (*strp == '-') {
01014       neg = 1;
01015       ++strp;
01016    } else if (*strp == '+')
01017       ++strp;
01018    strp = getsecs(strp, offsetp);
01019    if (strp == NULL)
01020       return NULL;      /* illegal time */
01021    if (neg)
01022       *offsetp = -*offsetp;
01023    return strp;
01024 }

static const char* getqzname ( const char *  strp,
const int  delim 
) [static]

Given a pointer into an extended time zone string, scan until the ending delimiter of the zone name is located. Return a pointer to the delimiter.

As with getzname above, the legal character set is actually quite restricted, with other characters producing undefined results. We don't do any checking here; checking is done later in common-case code.

Definition at line 926 of file localtime.c.

Referenced by tzparse().

00927 {
00928    int   c;
00929 
00930    while ((c = *strp) != '\0' && c != delim)
00931       ++strp;
00932    return strp;
00933 }

static const char* getrule ( const char *  strp,
struct rule rulep 
) [static]

Given a pointer into a time zone string, extract a rule in the form date[/time]. See POSIX section 8 for the format of "date" and "time". If a valid rule is not found, return NULL. Otherwise, return a pointer to the first character not part of the rule.

Definition at line 1033 of file localtime.c.

References DAY_OF_YEAR, DAYSPERNYEAR, DAYSPERWEEK, getnum(), getsecs(), is_digit, JULIAN_DAY, MONSPERYEAR, MONTH_NTH_DAY_OF_WEEK, rule::r_day, rule::r_mon, rule::r_time, rule::r_type, rule::r_week, and SECSPERHOUR.

Referenced by tzparse().

01034 {
01035    if (*strp == 'J') {
01036       /*
01037       ** Julian day.
01038       */
01039       rulep->r_type = JULIAN_DAY;
01040       ++strp;
01041       strp = getnum(strp, &rulep->r_day, 1, DAYSPERNYEAR);
01042    } else if (*strp == 'M') {
01043       /*
01044       ** Month, week, day.
01045       */
01046       rulep->r_type = MONTH_NTH_DAY_OF_WEEK;
01047       ++strp;
01048       strp = getnum(strp, &rulep->r_mon, 1, MONSPERYEAR);
01049       if (strp == NULL)
01050          return NULL;
01051       if (*strp++ != '.')
01052          return NULL;
01053       strp = getnum(strp, &rulep->r_week, 1, 5);
01054       if (strp == NULL)
01055          return NULL;
01056       if (*strp++ != '.')
01057          return NULL;
01058       strp = getnum(strp, &rulep->r_day, 0, DAYSPERWEEK - 1);
01059    } else if (is_digit(*strp)) {
01060       /*
01061       ** Day of year.
01062       */
01063       rulep->r_type = DAY_OF_YEAR;
01064       strp = getnum(strp, &rulep->r_day, 0, DAYSPERLYEAR - 1);
01065    } else   return NULL;      /* invalid format */
01066    if (strp == NULL)
01067       return NULL;
01068    if (*strp == '/') {
01069       /*
01070       ** Time specified.
01071       */
01072       ++strp;
01073       strp = getsecs(strp, &rulep->r_time);
01074    } else   rulep->r_time = 2 * SECSPERHOUR; /* default = 2:00:00 */
01075    return strp;
01076 }

static const char* getsecs ( const char *  strp,
long *const   secsp 
) [static]

Given a pointer into a time zone string, extract a number of seconds, 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 number of seconds.

Definition at line 970 of file localtime.c.

References DAYSPERWEEK, getnum(), HOURSPERDAY, MINSPERHOUR, SECSPERHOUR, and SECSPERMIN.

Referenced by getoffset(), and getrule().

00971 {
00972    int   num;
00973 
00974    /*
00975    ** `HOURSPERDAY * DAYSPERWEEK - 1' allows quasi-Posix rules like
00976    ** "M10.4.6/26", which does not conform to Posix,
00977    ** but which specifies the equivalent of
00978    ** ``02:00 on the first Sunday on or after 23 Oct''.
00979    */
00980    strp = getnum(strp, &num, 0, HOURSPERDAY * DAYSPERWEEK - 1);
00981    if (strp == NULL)
00982       return NULL;
00983    *secsp = num * (long) SECSPERHOUR;
00984    if (*strp == ':') {
00985       ++strp;
00986       strp = getnum(strp, &num, 0, MINSPERHOUR - 1);
00987       if (strp == NULL)
00988          return NULL;
00989       *secsp += num * SECSPERMIN;
00990       if (*strp == ':') {
00991          ++strp;
00992          /* `SECSPERMIN' allows for leap seconds. */
00993          strp = getnum(strp, &num, 0, SECSPERMIN);
00994          if (strp == NULL)
00995             return NULL;
00996          *secsp += num;
00997       }
00998    }
00999    return strp;
01000 }

static const char* getzname ( const char *  strp  )  [static]

Given a pointer into a time zone string, scan until a character that is not a valid character in a zone name is found. Return a pointer to that character.

Definition at line 907 of file localtime.c.

References is_digit.

Referenced by tzparse().

00908 {
00909    char  c;
00910 
00911    while ((c = *strp) != '\0' && !is_digit(c) && c != ',' && c != '-' &&
00912       c != '+')
00913          ++strp;
00914    return strp;
00915 }

static int gmtload ( struct state sp  )  [static]

Definition at line 1405 of file localtime.c.

References TRUE, tzload(), and tzparse().

Referenced by ast_tzset(), and gmtsub().

01406 {
01407    if (tzload(gmt, sp, TRUE) != 0)
01408       return tzparse(gmt, sp, TRUE);
01409    else
01410       return -1;
01411 }

static struct ast_tm* gmtsub ( const struct timeval *  timep,
const long  offset,
struct ast_tm tmp 
) [static]

Definition at line 1677 of file localtime.c.

References ast_calloc, AST_LIST_INSERT_TAIL, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, state::chars, gmtload(), state::list, state::name, and timesub().

Referenced by localsub().

01678 {
01679    struct ast_tm *   result;
01680    struct state *sp;
01681 
01682    AST_LIST_LOCK(&zonelist);
01683    AST_LIST_TRAVERSE(&zonelist, sp, list) {
01684       if (!strcmp(sp->name, "UTC"))
01685          break;
01686    }
01687 
01688    if (!sp) {
01689       if (!(sp = (struct state *) ast_calloc(1, sizeof *sp)))
01690          return NULL;
01691       gmtload(sp);
01692       AST_LIST_INSERT_TAIL(&zonelist, sp, list);
01693    }
01694    AST_LIST_UNLOCK(&zonelist);
01695 
01696    result = timesub(timep, offset, sp, tmp);
01697 #ifdef TM_ZONE
01698    /*
01699    ** Could get fancy here and deliver something such as
01700    ** "UTC+xxxx" or "UTC-xxxx" if offset is non-zero,
01701    ** but this is no time for a treasure hunt.
01702    */
01703    if (offset != 0)
01704       tmp->TM_ZONE = "    ";
01705    else
01706       tmp->TM_ZONE = sp->chars;
01707 #endif /* defined TM_ZONE */
01708    return result;
01709 }

static int increment_overflow ( int *  number,
int  delta 
) [static]

Simplified normalize logic courtesy Paul Eggert.

Definition at line 1860 of file localtime.c.

Referenced by normalize_overflow(), and timesub().

01861 {
01862    int   number0;
01863 
01864    number0 = *number;
01865    *number += delta;
01866    return (*number < number0) != (delta < 0);
01867 }

static void* inotify_daemon ( void *  data  )  [static]

Definition at line 271 of file localtime.c.

References ast_cond_broadcast, ast_free, AST_LIST_LOCK, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, AST_LIST_UNLOCK, ast_log(), ast_mutex_lock, ast_mutex_unlock, AST_PTHREADT_NULL, errno, FILENAME_MAX, initialization_lock, state::list, LOG_ERROR, state::name, and state::wd.

Referenced by add_notify().

00272 {
00273    struct {
00274       struct inotify_event iev;
00275       char name[FILENAME_MAX + 1];
00276    } buf;
00277    ssize_t res;
00278    struct state *cur;
00279 
00280    inotify_fd = inotify_init();
00281 
00282    ast_mutex_lock(&initialization_lock);
00283    ast_cond_broadcast(&initialization);
00284    ast_mutex_unlock(&initialization_lock);
00285 
00286    if (inotify_fd < 0) {
00287       ast_log(LOG_ERROR, "Cannot initialize file notification service: %s (%d)\n", strerror(errno), errno);
00288       inotify_thread = AST_PTHREADT_NULL;
00289       return NULL;
00290    }
00291 
00292    for (;/*ever*/;) {
00293       /* This read should block, most of the time. */
00294       if ((res = read(inotify_fd, &buf, sizeof(buf))) < sizeof(buf.iev) && res > 0) {
00295          /* This should never happen */
00296          ast_log(LOG_ERROR, "Inotify read less than a full event (%zd < %zd)?!!\n", res, sizeof(buf.iev));
00297          break;
00298       } else if (res < 0) {
00299          if (errno == EINTR || errno == EAGAIN) {
00300             /* If read fails, try again */
00301             AST_LIST_LOCK(&zonelist);
00302             ast_cond_broadcast(&initialization);
00303             AST_LIST_UNLOCK(&zonelist);
00304             continue;
00305          }
00306          /* Sanity check -- this should never happen, either */
00307          ast_log(LOG_ERROR, "Inotify failed: %s\n", strerror(errno));
00308          break;
00309       }
00310       AST_LIST_LOCK(&zonelist);
00311       AST_LIST_TRAVERSE_SAFE_BEGIN(&zonelist, cur, list) {
00312          if (cur->wd[0] == buf.iev.wd || cur->wd[1] == buf.iev.wd) {
00313             AST_LIST_REMOVE_CURRENT(list);
00314             ast_free(cur);
00315             break;
00316          }
00317       }
00318       AST_LIST_TRAVERSE_SAFE_END
00319       ast_cond_broadcast(&initialization);
00320       AST_LIST_UNLOCK(&zonelist);
00321    }
00322    close(inotify_fd);
00323    inotify_thread = AST_PTHREADT_NULL;
00324    return NULL;
00325 }

static int leaps_thru_end_of ( const int  y  )  [static]

Return the number of leap years through the end of the given year where, to make the math easy, the answer for year zero is defined as zero.

Definition at line 1716 of file localtime.c.

Referenced by timesub().

01717 {
01718    return (y >= 0) ? (y / 4 - y / 100 + y / 400) :
01719       -(leaps_thru_end_of(-(y + 1)) + 1);
01720 }

static struct ast_tm* localsub ( const struct timeval *  timep,
const long  offset,
struct ast_tm tmp,
const struct state sp 
) [static]

Note:
The easy way to behave "as if no library function calls" localtime is to not call it--so we drop its guts into "localsub", which can be freely called. (And no, the PANS doesn't require the above behavior-- but it *is* desirable.)
The unused offset argument is for the benefit of mktime variants.

Definition at line 1460 of file localtime.c.

References state::ats, AVGSECSPERYEAR, state::chars, gmtsub(), state::goahead, state::goback, int_fast64_t, state::timecnt, timesub(), ast_tm::tm_gmtoff, ast_tm::tm_isdst, ast_tm::tm_usec, ast_tm::tm_year, ttinfo::tt_abbrind, ttinfo::tt_gmtoff, ttinfo::tt_isdst, state::ttis, state::typecnt, state::types, and YEARSPERREPEAT.

Referenced by ast_localtime(), and ast_mktime().

01461 {
01462    const struct ttinfo *   ttisp;
01463    int         i;
01464    struct ast_tm *      result;
01465    struct timeval t;
01466    memcpy(&t, timep, sizeof(t));
01467 
01468    if (sp == NULL)
01469       return gmtsub(timep, offset, tmp);
01470    if ((sp->goback && t.tv_sec < sp->ats[0]) ||
01471       (sp->goahead && t.tv_sec > sp->ats[sp->timecnt - 1])) {
01472          struct timeval newt = t;
01473          time_t      seconds;
01474          time_t      tcycles;
01475          int_fast64_t   icycles;
01476 
01477          if (t.tv_sec < sp->ats[0])
01478             seconds = sp->ats[0] - t.tv_sec;
01479          else  seconds = t.tv_sec - sp->ats[sp->timecnt - 1];
01480          --seconds;
01481          tcycles = seconds / YEARSPERREPEAT / AVGSECSPERYEAR;
01482          ++tcycles;
01483          icycles = tcycles;
01484          if (tcycles - icycles >= 1 || icycles - tcycles >= 1)
01485             return NULL;
01486          seconds = icycles;
01487          seconds *= YEARSPERREPEAT;
01488          seconds *= AVGSECSPERYEAR;
01489          if (t.tv_sec < sp->ats[0])
01490             newt.tv_sec += seconds;
01491          else  newt.tv_sec -= seconds;
01492          if (newt.tv_sec < sp->ats[0] ||
01493             newt.tv_sec > sp->ats[sp->timecnt - 1])
01494                return NULL;   /* "cannot happen" */
01495          result = localsub(&newt, offset, tmp, sp);
01496          if (result == tmp) {
01497             time_t   newy;
01498 
01499             newy = tmp->tm_year;
01500             if (t.tv_sec < sp->ats[0])
01501                newy -= icycles * YEARSPERREPEAT;
01502             else
01503                newy += icycles * YEARSPERREPEAT;
01504             tmp->tm_year = newy;
01505             if (tmp->tm_year != newy)
01506                return NULL;
01507          }
01508          return result;
01509    }
01510    if (sp->timecnt == 0 || t.tv_sec < sp->ats[0]) {
01511       i = 0;
01512       while (sp->ttis[i].tt_isdst) {
01513          if (++i >= sp->typecnt) {
01514             i = 0;
01515             break;
01516          }
01517       }
01518    } else {
01519       int   lo = 1;
01520       int   hi = sp->timecnt;
01521 
01522       while (lo < hi) {
01523          int   mid = (lo + hi) >> 1;
01524 
01525          if (t.tv_sec < sp->ats[mid])
01526             hi = mid;
01527          else
01528             lo = mid + 1;
01529       }
01530       i = (int) sp->types[lo - 1];
01531    }
01532    ttisp = &sp->ttis[i];
01533    /*
01534    ** To get (wrong) behavior that's compatible with System V Release 2.0
01535    ** you'd replace the statement below with
01536    ** t += ttisp->tt_gmtoff;
01537    ** timesub(&t, 0L, sp, tmp);
01538    */
01539    result = timesub(&t, ttisp->tt_gmtoff, sp, tmp);
01540    tmp->tm_isdst = ttisp->tt_isdst;
01541 #ifndef SOLARIS /* Solaris doesn't have this element */
01542    tmp->tm_gmtoff = ttisp->tt_gmtoff;
01543 #endif
01544 #ifdef TM_ZONE
01545    tmp->TM_ZONE = &sp->chars[ttisp->tt_abbrind];
01546 #endif /* defined TM_ZONE */
01547    tmp->tm_usec = timep->tv_usec;
01548    return result;
01549 }

static int long_increment_overflow ( long *  number,
int  delta 
) [static]

Definition at line 1869 of file localtime.c.

Referenced by long_normalize_overflow(), and time2sub().

01870 {
01871    long  number0;
01872 
01873    number0 = *number;
01874    *number += delta;
01875    return (*number < number0) != (delta < 0);
01876 }

static int long_normalize_overflow ( long *  tensptr,
int *  unitsptr,
const int  base 
) [static]

Definition at line 1889 of file localtime.c.

References long_increment_overflow().

Referenced by time2sub().

01890 {
01891    int   tensdelta;
01892 
01893    tensdelta = (*unitsptr >= 0) ?
01894       (*unitsptr / base) :
01895       (-1 - (-1 - *unitsptr) / base);
01896    *unitsptr -= tensdelta * base;
01897    return long_increment_overflow(tensptr, tensdelta);
01898 }

static int normalize_overflow ( int *  tensptr,
int *  unitsptr,
const int  base 
) [static]

Definition at line 1878 of file localtime.c.

References increment_overflow().

Referenced by time2sub().

01879 {
01880    int   tensdelta;
01881 
01882    tensdelta = (*unitsptr >= 0) ?
01883       (*unitsptr / base) :
01884       (-1 - (-1 - *unitsptr) / base);
01885    *unitsptr -= tensdelta * base;
01886    return increment_overflow(tensptr, tensdelta);
01887 }

static int tzparse P ( (const char *name, struct state *sp, int lastditch)   )  [static]

static int tzload P ( (const char *name, struct state *sp, int doextend)   )  [static]

static time_t transtime P ( (time_t janfirst, int year, const struct rule *rulep, long offset)   )  [static]

static int tmcomp P ( (const struct ast_tm *atmp, const struct ast_tm *btmp)   )  [static]

static struct ast_tm* timesub P ( (const struct timeval *timep, long offset, const struct state *sp, struct ast_tm *tmp)   )  [static]

static struct timeval time2sub P ( (struct ast_tm *tmp, struct ast_tm *(*funcp)(const struct timeval *, long, struct ast_tm *, const struct state *sp), long offset, int *okayp, int do_norm_secs, const struct state *sp)   )  [static]

static struct timeval time2 P ( (struct ast_tm *tmp, struct ast_tm *(*funcp) P((const struct timeval *, long, struct ast_tm *, const struct state *sp)), long offset, int *okayp, const struct state *sp)   )  [static]

static struct timeval time1 P ( (struct ast_tm *tmp, struct ast_tm *(*funcp) P((const struct timeval *, long, struct ast_tm *, const struct state *sp)), long offset, const struct state *sp)   )  [static]

static int normalize_overflow P ( (int *tensptr, int *unitsptr, const int base)   )  [static]

static int long_normalize_overflow P ( (long *tensptr, int *unitsptr, const int base)   )  [static]

static int long_increment_overflow P ( (long *number, int delta)   )  [static]

static int leaps_thru_end_of P ( (int y)   )  [static]

static int increment_overflow P ( (int *number, int delta)   )  [static]

static struct ast_tm* localsub P ( (const struct timeval *timep, long offset, struct ast_tm *tmp, const struct state *sp)   )  [static]

static struct ast_tm* gmtsub P ( (const struct timeval *timep, long offset, struct ast_tm *tmp)   )  [static]

static int gmtload P ( (struct state *sp)   )  [static]

static const char* getrule P ( (const char *strp, struct rule *rulep)   )  [static]

static const char* getoffset P ( (const char *strp, long *offsetp)   )  [static]

static const char* getsecs P ( (const char *strp, long *secsp)   )  [static]

static const char* getnum P ( (const char *strp, int *nump, int min, int max)   )  [static]

static const char* getqzname P ( (const char *strp, const int delim)   )  [static]

static const char* getzname P ( (const char *strp)   )  [static]

static int differ_by_repeat P ( (time_t t1, time_t t0)   )  [static]

static time_t detzcode64 P ( (const char *codep)   )  [static]

static const char* store_by_locale ( locale_t  prevlocale  )  [static]

Definition at line 2197 of file localtime.c.

References ast_calloc, AST_LIST_INSERT_TAIL, AST_LIST_LOCK, AST_LIST_UNLOCK, find_by_locale(), find_by_name(), locale_entry::list, and locale_entry::name.

Referenced by ast_setlocale().

02198 {
02199    struct locale_entry *cur;
02200    if (prevlocale == LC_GLOBAL_LOCALE) {
02201       return NULL;
02202    } else {
02203       /* Get a handle for this entry, if any */
02204       if ((cur = find_by_locale(prevlocale))) {
02205          return cur->name;
02206       } else {
02207          /* Create an entry, so it can be restored later */
02208          int x;
02209          cur = NULL;
02210          AST_LIST_LOCK(&localelist);
02211          for (x = 0; x < 10000; x++) {
02212             char name[5];
02213             snprintf(name, sizeof(name), "%04d", x);
02214             if (!find_by_name(name)) {
02215                if ((cur = ast_calloc(1, sizeof(*cur) + strlen(name) + 1))) {
02216                   cur->locale = prevlocale;
02217                   strcpy(cur->name, name); /* SAFE */
02218                   AST_LIST_INSERT_TAIL(&localelist, cur, list);
02219                }
02220                break;
02221             }
02222          }
02223          AST_LIST_UNLOCK(&localelist);
02224          return cur ? cur->name : NULL;
02225       }
02226    }
02227 }

static struct timeval time1 ( struct ast_tm tmp,
struct ast_tm *(*)(const struct timeval *, long, struct ast_tm *, const struct state *)  funcp,
const long  offset,
const struct state sp 
) [static]

Definition at line 2101 of file localtime.c.

References FALSE, time2(), state::timecnt, TRUE, state::typecnt, state::types, and TZ_MAX_TYPES.

Referenced by ast_mktime().

02102 {
02103    struct timeval       t;
02104    int         samei, otheri;
02105    int         sameind, otherind;
02106    int         i;
02107    int         nseen;
02108    int            seen[TZ_MAX_TYPES];
02109    int            types[TZ_MAX_TYPES];
02110    int            okay;
02111 
02112    if (tmp->tm_isdst > 1)
02113       tmp->tm_isdst = 1;
02114    t = time2(tmp, funcp, offset, &okay, sp);
02115 #ifdef PCTS
02116    /*
02117    ** PCTS code courtesy Grant Sullivan.
02118    */
02119    if (okay)
02120       return t;
02121    if (tmp->tm_isdst < 0)
02122       tmp->tm_isdst = 0;   /* reset to std and try again */
02123 #endif /* defined PCTS */
02124 #ifndef PCTS
02125    if (okay || tmp->tm_isdst < 0)
02126       return t;
02127 #endif /* !defined PCTS */
02128    /*
02129    ** We're supposed to assume that somebody took a time of one type
02130    ** and did some math on it that yielded a "struct ast_tm" that's bad.
02131    ** We try to divine the type they started from and adjust to the
02132    ** type they need.
02133    */
02134    if (sp == NULL)
02135       return WRONG;
02136    for (i = 0; i < sp->typecnt; ++i)
02137       seen[i] = FALSE;
02138    nseen = 0;
02139    for (i = sp->timecnt - 1; i >= 0; --i)
02140       if (!seen[sp->types[i]]) {
02141          seen[sp->types[i]] = TRUE;
02142          types[nseen++] = sp->types[i];
02143       }
02144    for (sameind = 0; sameind < nseen; ++sameind) {
02145       samei = types[sameind];
02146       if (sp->ttis[samei].tt_isdst != tmp->tm_isdst)
02147          continue;
02148       for (otherind = 0; otherind < nseen; ++otherind) {
02149          otheri = types[otherind];
02150          if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst)
02151             continue;
02152          tmp->tm_sec += sp->ttis[otheri].tt_gmtoff -
02153                sp->ttis[samei].tt_gmtoff;
02154          tmp->tm_isdst = !tmp->tm_isdst;
02155          t = time2(tmp, funcp, offset, &okay, sp);
02156          if (okay)
02157             return t;
02158          tmp->tm_sec -= sp->ttis[otheri].tt_gmtoff -
02159                sp->ttis[samei].tt_gmtoff;
02160          tmp->tm_isdst = !tmp->tm_isdst;
02161       }
02162    }
02163    return WRONG;
02164 }

static struct timeval time2 ( struct ast_tm tmp,
struct ast_tm *(*)(const struct timeval *, long, struct ast_tm *, const struct state *sp)  funcp,
const long  offset,
int *  okayp,
const struct state sp 
) [static]

Definition at line 2088 of file localtime.c.

References FALSE, time2sub(), and TRUE.

Referenced by time1().

02089 {
02090    struct timeval t;
02091 
02092    /*! \note
02093    ** First try without normalization of seconds
02094    ** (in case tm_sec contains a value associated with a leap second).
02095    ** If that fails, try with normalization of seconds.
02096    */
02097    t = time2sub(tmp, funcp, offset, okayp, FALSE, sp);
02098    return *okayp ? t : time2sub(tmp, funcp, offset, okayp, TRUE, sp);
02099 }

static struct timeval time2sub ( struct ast_tm tmp,
struct ast_tm *(*)(const struct timeval *, long, struct ast_tm *, const struct state *)  funcp,
const long  offset,
int *  okayp,
const int  do_norm_secs,
const struct state sp 
) [static]

Definition at line 1914 of file localtime.c.

References DAYSPERLYEAR, FALSE, HOURSPERDAY, isleap, long_increment_overflow(), long_normalize_overflow(), MINSPERHOUR, mon_lengths, MONSPERYEAR, normalize_overflow(), SECSPERMIN, ast_tm::tm_hour, ast_tm::tm_mday, ast_tm::tm_min, ast_tm::tm_mon, ast_tm::tm_sec, ast_tm::tm_year, TM_YEAR_BASE, and year_lengths.

Referenced by time2().

01915 {
01916    int         dir;
01917    int         i, j;
01918    int         saved_seconds;
01919    long        li;
01920    time_t         lo;
01921    time_t         hi;
01922    long           y;
01923    struct timeval       newt = { 0, 0 };
01924    struct timeval       t = { 0, 0 };
01925    struct ast_tm        yourtm, mytm;
01926 
01927    *okayp = FALSE;
01928    yourtm = *tmp;
01929    if (do_norm_secs) {
01930       if (normalize_overflow(&yourtm.tm_min, &yourtm.tm_sec,
01931          SECSPERMIN))
01932             return WRONG;
01933    }
01934    if (normalize_overflow(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR))
01935       return WRONG;
01936    if (normalize_overflow(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY))
01937       return WRONG;
01938    y = yourtm.tm_year;
01939    if (long_normalize_overflow(&y, &yourtm.tm_mon, MONSPERYEAR))
01940       return WRONG;
01941    /*
01942    ** Turn y into an actual year number for now.
01943    ** It is converted back to an offset from TM_YEAR_BASE later.
01944    */
01945    if (long_increment_overflow(&y, TM_YEAR_BASE))
01946       return WRONG;
01947    while (yourtm.tm_mday <= 0) {
01948       if (long_increment_overflow(&y, -1))
01949          return WRONG;
01950       li = y + (1 < yourtm.tm_mon);
01951       yourtm.tm_mday += year_lengths[isleap(li)];
01952    }
01953    while (yourtm.tm_mday > DAYSPERLYEAR) {
01954       li = y + (1 < yourtm.tm_mon);
01955       yourtm.tm_mday -= year_lengths[isleap(li)];
01956       if (long_increment_overflow(&y, 1))
01957          return WRONG;
01958    }
01959    for ( ; ; ) {
01960       i = mon_lengths[isleap(y)][yourtm.tm_mon];
01961       if (yourtm.tm_mday <= i)
01962          break;
01963       yourtm.tm_mday -= i;
01964       if (++yourtm.tm_mon >= MONSPERYEAR) {
01965          yourtm.tm_mon = 0;
01966          if (long_increment_overflow(&y, 1))
01967             return WRONG;
01968       }
01969    }
01970    if (long_increment_overflow(&y, -TM_YEAR_BASE))
01971       return WRONG;
01972    yourtm.tm_year = y;
01973    if (yourtm.tm_year != y)
01974       return WRONG;
01975    if (yourtm.tm_sec >= 0 && yourtm.tm_sec < SECSPERMIN)
01976       saved_seconds = 0;
01977    else if (y + TM_YEAR_BASE < EPOCH_YEAR) {
01978       /*
01979       ** We can't set tm_sec to 0, because that might push the
01980       ** time below the minimum representable time.
01981       ** Set tm_sec to 59 instead.
01982       ** This assumes that the minimum representable time is
01983       ** not in the same minute that a leap second was deleted from,
01984       ** which is a safer assumption than using 58 would be.
01985       */
01986       if (increment_overflow(&yourtm.tm_sec, 1 - SECSPERMIN))
01987          return WRONG;
01988       saved_seconds = yourtm.tm_sec;
01989       yourtm.tm_sec = SECSPERMIN - 1;
01990    } else {
01991       saved_seconds = yourtm.tm_sec;
01992       yourtm.tm_sec = 0;
01993    }
01994    /*
01995    ** Do a binary search (this works whatever time_t's type is).
01996    */
01997    if (!TYPE_SIGNED(time_t)) {
01998       lo = 0;
01999       hi = lo - 1;
02000    } else if (!TYPE_INTEGRAL(time_t)) {
02001       if (sizeof(time_t) > sizeof(float))
02002          hi = (time_t) DBL_MAX;
02003       else  hi = (time_t) FLT_MAX;
02004       lo = -hi;
02005    } else {
02006       lo = 1;
02007       for (i = 0; i < (int) TYPE_BIT(time_t) - 1; ++i)
02008          lo *= 2;
02009       hi = -(lo + 1);
02010    }
02011    for ( ; ; ) {
02012       t.tv_sec = lo / 2 + hi / 2;
02013       if (t.tv_sec < lo)
02014          t.tv_sec = lo;
02015       else if (t.tv_sec > hi)
02016          t.tv_sec = hi;
02017       if ((*funcp)(&t, offset, &mytm, sp) == NULL) {
02018          /*
02019          ** Assume that t is too extreme to be represented in
02020          ** a struct ast_tm; arrange things so that it is less
02021          ** extreme on the next pass.
02022          */
02023          dir = (t.tv_sec > 0) ? 1 : -1;
02024       } else   dir = tmcomp(&mytm, &yourtm);
02025       if (dir != 0) {
02026          if (t.tv_sec == lo) {
02027             ++t.tv_sec;
02028             if (t.tv_sec <= lo)
02029                return WRONG;
02030             ++lo;
02031          } else if (t.tv_sec == hi) {
02032             --t.tv_sec;
02033             if (t.tv_sec >= hi)
02034                return WRONG;
02035             --hi;
02036          }
02037          if (lo > hi)
02038             return WRONG;
02039          if (dir > 0)
02040             hi = t.tv_sec;
02041          else  lo = t.tv_sec;
02042          continue;
02043       }
02044       if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst)
02045          break;
02046       /*
02047       ** Right time, wrong type.
02048       ** Hunt for right time, right type.
02049       ** It's okay to guess wrong since the guess
02050       ** gets checked.
02051       */
02052       /*
02053       ** The (void *) casts are the benefit of SunOS 3.3 on Sun 2's.
02054       */
02055       for (i = sp->typecnt - 1; i >= 0; --i) {
02056          if (sp->ttis[i].tt_isdst != yourtm.tm_isdst)
02057             continue;
02058          for (j = sp->typecnt - 1; j >= 0; --j) {
02059             if (sp->ttis[j].tt_isdst == yourtm.tm_isdst)
02060                continue;
02061             newt.tv_sec = t.tv_sec + sp->ttis[j].tt_gmtoff -
02062                sp->ttis[i].tt_gmtoff;
02063             if ((*funcp)(&newt, offset, &mytm, sp) == NULL)
02064                continue;
02065             if (tmcomp(&mytm, &yourtm) != 0)
02066                continue;
02067             if (mytm.tm_isdst != yourtm.tm_isdst)
02068                continue;
02069             /*
02070             ** We have a match.
02071             */
02072             t = newt;
02073             goto label;
02074          }
02075       }
02076       return WRONG;
02077    }
02078 label:
02079    newt.tv_sec = t.tv_sec + saved_seconds;
02080    if ((newt.tv_sec < t.tv_sec) != (saved_seconds < 0))
02081       return WRONG;
02082    t.tv_sec = newt.tv_sec;
02083    if ((*funcp)(&t, offset, tmp, sp))
02084       *okayp = TRUE;
02085    return t;
02086 }

static struct ast_tm* timesub ( const struct timeval *  timep,
const long  offset,
const struct state sp,
struct ast_tm tmp 
) [static]

Definition at line 1722 of file localtime.c.

References DAYSPERLYEAR, DAYSPERNYEAR, DAYSPERWEEK, EPOCH_WDAY, EPOCH_YEAR, increment_overflow(), isleap, state::leapcnt, leaps_thru_end_of(), lsinfo::ls_corr, lsinfo::ls_trans, state::lsis, mon_lengths, SECSPERDAY, SECSPERHOUR, SECSPERMIN, ast_tm::tm_hour, ast_tm::tm_isdst, ast_tm::tm_mday, ast_tm::tm_min, ast_tm::tm_mon, ast_tm::tm_sec, ast_tm::tm_usec, ast_tm::tm_wday, ast_tm::tm_yday, ast_tm::tm_year, TM_YEAR_BASE, and year_lengths.

Referenced by gmtsub(), and localsub().

01723 {
01724    const struct lsinfo *   lp;
01725    time_t         tdays;
01726    int         idays;   /* unsigned would be so 2003 */
01727    long        rem;
01728    int            y;
01729    const int *    ip;
01730    long        corr;
01731    int         hit;
01732    int         i;
01733    long  seconds;
01734 
01735 
01736    corr = 0;
01737    hit = 0;
01738    i = (sp == NULL) ? 0 : sp->leapcnt;
01739    while (--i >= 0) {
01740       lp = &sp->lsis[i];
01741       if (timep->tv_sec >= lp->ls_trans) {
01742          if (timep->tv_sec == lp->ls_trans) {
01743             hit = ((i == 0 && lp->ls_corr > 0) ||
01744                lp->ls_corr > sp->lsis[i - 1].ls_corr);
01745             if (hit)
01746                while (i > 0 &&
01747                   sp->lsis[i].ls_trans ==
01748                   sp->lsis[i - 1].ls_trans + 1 &&
01749                   sp->lsis[i].ls_corr ==
01750                   sp->lsis[i - 1].ls_corr + 1) {
01751                      ++hit;
01752                      --i;
01753                }
01754          }
01755          corr = lp->ls_corr;
01756          break;
01757       }
01758    }
01759    y = EPOCH_YEAR;
01760    tdays = timep->tv_sec / SECSPERDAY;
01761    rem = timep->tv_sec - tdays * SECSPERDAY;
01762    while (tdays < 0 || tdays >= year_lengths[isleap(y)]) {
01763       int      newy;
01764       time_t   tdelta;
01765       int   idelta;
01766       int   leapdays;
01767 
01768       tdelta = tdays / DAYSPERLYEAR;
01769       idelta = tdelta;
01770       if (tdelta - idelta >= 1 || idelta - tdelta >= 1)
01771          return NULL;
01772       if (idelta == 0)
01773          idelta = (tdays < 0) ? -1 : 1;
01774       newy = y;
01775       if (increment_overflow(&newy, idelta))
01776          return NULL;
01777       leapdays = leaps_thru_end_of(newy - 1) -
01778          leaps_thru_end_of(y - 1);
01779       tdays -= ((time_t) newy - y) * DAYSPERNYEAR;
01780       tdays -= leapdays;
01781       y = newy;
01782    }
01783 
01784    seconds = tdays * SECSPERDAY + 0.5;
01785    tdays = seconds / SECSPERDAY;
01786    rem += seconds - tdays * SECSPERDAY;
01787 
01788    /*
01789    ** Given the range, we can now fearlessly cast...
01790    */
01791    idays = tdays;
01792    rem += offset - corr;
01793    while (rem < 0) {
01794       rem += SECSPERDAY;
01795       --idays;
01796    }
01797    while (rem >= SECSPERDAY) {
01798       rem -= SECSPERDAY;
01799       ++idays;
01800    }
01801    while (idays < 0) {
01802       if (increment_overflow(&y, -1))
01803          return NULL;
01804       idays += year_lengths[isleap(y)];
01805    }
01806    while (idays >= year_lengths[isleap(y)]) {
01807       idays -= year_lengths[isleap(y)];
01808       if (increment_overflow(&y, 1))
01809          return NULL;
01810    }
01811    tmp->tm_year = y;
01812    if (increment_overflow(&tmp->tm_year, -TM_YEAR_BASE))
01813       return NULL;
01814    tmp->tm_yday = idays;
01815    /*
01816    ** The "extra" mods below avoid overflow problems.
01817    */
01818    tmp->tm_wday = EPOCH_WDAY +
01819       ((y - EPOCH_YEAR) % DAYSPERWEEK) *
01820       (DAYSPERNYEAR % DAYSPERWEEK) +
01821       leaps_thru_end_of(y - 1) -
01822       leaps_thru_end_of(EPOCH_YEAR - 1) +
01823       idays;
01824    tmp->tm_wday %= DAYSPERWEEK;
01825    if (tmp->tm_wday < 0)
01826       tmp->tm_wday += DAYSPERWEEK;
01827    tmp->tm_hour = (int) (rem / SECSPERHOUR);
01828    rem %= SECSPERHOUR;
01829    tmp->tm_min = (int) (rem / SECSPERMIN);
01830    /*
01831    ** A positive leap second requires a special
01832    ** representation. This uses "... ??:59:60" et seq.
01833    */
01834    tmp->tm_sec = (int) (rem % SECSPERMIN) + hit;
01835    ip = mon_lengths[isleap(y)];
01836    for (tmp->tm_mon = 0; idays >= ip[tmp->tm_mon]; ++(tmp->tm_mon))
01837       idays -= ip[tmp->tm_mon];
01838    tmp->tm_mday = (int) (idays + 1);
01839    tmp->tm_isdst = 0;
01840 #ifdef TM_GMTOFF
01841    tmp->TM_GMTOFF = offset;
01842 #endif /* defined TM_GMTOFF */
01843    tmp->tm_usec = timep->tv_usec;
01844    return tmp;
01845 }

static int tmcomp ( const struct ast_tm atmp,
const struct ast_tm btmp 
) [static]

Definition at line 1900 of file localtime.c.

References ast_tm::tm_hour, ast_tm::tm_mday, ast_tm::tm_min, ast_tm::tm_mon, ast_tm::tm_sec, ast_tm::tm_usec, and ast_tm::tm_year.

01901 {
01902    int   result;
01903 
01904    if ((result = (atmp->tm_year - btmp->tm_year)) == 0 &&
01905       (result = (atmp->tm_mon - btmp->tm_mon)) == 0 &&
01906       (result = (atmp->tm_mday - btmp->tm_mday)) == 0 &&
01907       (result = (atmp->tm_hour - btmp->tm_hour)) == 0 &&
01908       (result = (atmp->tm_min - btmp->tm_min)) == 0 &&
01909       (result = (atmp->tm_sec - btmp->tm_sec)) == 0)
01910          result = atmp->tm_usec - btmp->tm_usec;
01911    return result;
01912 }

static time_t transtime ( const time_t  janfirst,
const int  year,
const struct rule rulep,
const long  offset 
) [static]

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.

Definition at line 1084 of file localtime.c.

References DAY_OF_YEAR, DAYSPERWEEK, INITIALIZE, isleap, JULIAN_DAY, MONTH_NTH_DAY_OF_WEEK, rule::r_day, rule::r_mon, rule::r_time, rule::r_type, rule::r_week, SECSPERDAY, and value.

Referenced by tzparse().

01085 {
01086    int   leapyear;
01087    time_t   value;
01088    int   i;
01089    int      d, m1, yy0, yy1, yy2, dow;
01090 
01091    INITIALIZE(value);
01092    leapyear = isleap(year);
01093    switch (rulep->r_type) {
01094 
01095    case JULIAN_DAY:
01096       /*
01097       ** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap
01098       ** years.
01099       ** In non-leap years, or if the day number is 59 or less, just
01100       ** add SECSPERDAY times the day number-1 to the time of
01101       ** January 1, midnight, to get the day.
01102       */
01103       value = janfirst + (rulep->r_day - 1) * SECSPERDAY;
01104       if (leapyear && rulep->r_day >= 60)
01105          value += SECSPERDAY;
01106       break;
01107 
01108    case DAY_OF_YEAR:
01109       /*
01110       ** n - day of year.
01111       ** Just add SECSPERDAY times the day number to the time of
01112       ** January 1, midnight, to get the day.
01113       */
01114       value = janfirst + rulep->r_day * SECSPERDAY;
01115       break;
01116 
01117    case MONTH_NTH_DAY_OF_WEEK:
01118       /*
01119       ** Mm.n.d - nth "dth day" of month m.
01120       */
01121       value = janfirst;
01122       for (i = 0; i < rulep->r_mon - 1; ++i)
01123          value += mon_lengths[leapyear][i] * SECSPERDAY;
01124 
01125       /*
01126       ** Use Zeller's Congruence to get day-of-week of first day of
01127       ** month.
01128       */
01129       m1 = (rulep->r_mon + 9) % 12 + 1;
01130       yy0 = (rulep->r_mon <= 2) ? (year - 1) : year;
01131       yy1 = yy0 / 100;
01132       yy2 = yy0 % 100;
01133       dow = ((26 * m1 - 2) / 10 +
01134          1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7;
01135       if (dow < 0)
01136          dow += DAYSPERWEEK;
01137 
01138       /*
01139       ** "dow" is the day-of-week of the first day of the month. Get
01140       ** the day-of-month (zero-origin) of the first "dow" day of the
01141       ** month.
01142       */
01143       d = rulep->r_day - dow;
01144       if (d < 0)
01145          d += DAYSPERWEEK;
01146       for (i = 1; i < rulep->r_week; ++i) {
01147          if (d + DAYSPERWEEK >=
01148             mon_lengths[leapyear][rulep->r_mon - 1])
01149                break;
01150          d += DAYSPERWEEK;
01151       }
01152 
01153       /*
01154       ** "d" is the day-of-month (zero-origin) of the day we want.
01155       */
01156       value += d * SECSPERDAY;
01157       break;
01158    }
01159 
01160    /*
01161    ** "value" is the Epoch-relative time of 00:00:00 UTC on the day in
01162    ** question. To get the Epoch-relative time of the specified local
01163    ** time on that day, add the transition time and the current offset
01164    ** from UTC.
01165    */
01166    return value + rulep->r_time + offset;
01167 }

static int tzload ( const char *  name,
struct state *const   sp,
const int  doextend 
) [static]

Definition at line 661 of file localtime.c.

References add_notify(), state::ats, state::charcnt, state::chars, detzcode(), detzcode64(), FALSE, FILENAME_MAX, state::leapcnt, lsinfo::ls_trans, state::lsis, OPEN_MODE, state::timecnt, TRUE, ttinfo::tt_gmtoff, ttinfo::tt_ttisgmt, ttinfo::tt_ttisstd, state::ttis, state::typecnt, state::types, TZ_MAX_CHARS, TZ_MAX_LEAPS, TZ_MAX_TIMES, TZ_MAX_TYPES, TZDEFAULT, and TZDIR.

Referenced by ast_tzset(), gmtload(), and tzparse().

00662 {
00663    const char *      p;
00664    int         i;
00665    int         fid;
00666    int         stored;
00667    int         nread;
00668    union {
00669       struct tzhead  tzhead;
00670       char     buf[2 * sizeof(struct tzhead) +
00671                2 * sizeof *sp +
00672                4 * TZ_MAX_TIMES];
00673    } u;
00674 
00675    if (name == NULL && (name = TZDEFAULT) == NULL)
00676       return -1;
00677    {
00678       int   doaccess;
00679       /*
00680       ** Section 4.9.1 of the C standard says that
00681       ** "FILENAME_MAX expands to an integral constant expression
00682       ** that is the size needed for an array of char large enough
00683       ** to hold the longest file name string that the implementation
00684       ** guarantees can be opened."
00685       */
00686       char     fullname[FILENAME_MAX + 1];
00687 
00688       if (name[0] == ':')
00689          ++name;
00690       doaccess = name[0] == '/';
00691       if (!doaccess) {
00692          if ((p = TZDIR) == NULL)
00693             return -1;
00694          if ((strlen(p) + strlen(name) + 1) >= sizeof fullname)
00695             return -1;
00696          (void) strcpy(fullname, p);
00697          (void) strcat(fullname, "/");
00698          (void) strcat(fullname, name);
00699          /*
00700          ** Set doaccess if '.' (as in "../") shows up in name.
00701          */
00702          if (strchr(name, '.') != NULL)
00703             doaccess = TRUE;
00704          name = fullname;
00705       }
00706       if (doaccess && access(name, R_OK) != 0)
00707          return -1;
00708       if ((fid = open(name, OPEN_MODE)) == -1)
00709          return -1;
00710       add_notify(sp, name);
00711    }
00712    nread = read(fid, u.buf, sizeof u.buf);
00713    if (close(fid) < 0 || nread <= 0)
00714       return -1;
00715    for (stored = 4; stored <= 8; stored *= 2) {
00716       int      ttisstdcnt;
00717       int      ttisgmtcnt;
00718 
00719       ttisstdcnt = (int) detzcode(u.tzhead.tzh_ttisstdcnt);
00720       ttisgmtcnt = (int) detzcode(u.tzhead.tzh_ttisgmtcnt);
00721       sp->leapcnt = (int) detzcode(u.tzhead.tzh_leapcnt);
00722       sp->timecnt = (int) detzcode(u.tzhead.tzh_timecnt);
00723       sp->typecnt = (int) detzcode(u.tzhead.tzh_typecnt);
00724       sp->charcnt = (int) detzcode(u.tzhead.tzh_charcnt);
00725       p = u.tzhead.tzh_charcnt + sizeof u.tzhead.tzh_charcnt;
00726       if (sp->leapcnt < 0 || sp->leapcnt > TZ_MAX_LEAPS ||
00727          sp->typecnt <= 0 || sp->typecnt > TZ_MAX_TYPES ||
00728          sp->timecnt < 0 || sp->timecnt > TZ_MAX_TIMES ||
00729          sp->charcnt < 0 || sp->charcnt > TZ_MAX_CHARS ||
00730          (ttisstdcnt != sp->typecnt && ttisstdcnt != 0) ||
00731          (ttisgmtcnt != sp->typecnt && ttisgmtcnt != 0))
00732             return -1;
00733       if (nread - (p - u.buf) <
00734          sp->timecnt * stored +     /* ats */
00735          sp->timecnt +        /* types */
00736          sp->typecnt * 6 +    /* ttinfos */
00737          sp->charcnt +        /* chars */
00738          sp->leapcnt * (stored + 4) +  /* lsinfos */
00739          ttisstdcnt +         /* ttisstds */
00740          ttisgmtcnt)       /* ttisgmts */
00741             return -1;
00742       for (i = 0; i < sp->timecnt; ++i) {
00743          sp->ats[i] = (stored == 4) ?
00744             detzcode(p) : detzcode64(p);
00745          p += stored;
00746       }
00747       for (i = 0; i < sp->timecnt; ++i) {
00748          sp->types[i] = (unsigned char) *p++;
00749          if (sp->types[i] >= sp->typecnt)
00750             return -1;
00751       }
00752       for (i = 0; i < sp->typecnt; ++i) {
00753          struct ttinfo *   ttisp;
00754 
00755          ttisp = &sp->ttis[i];
00756          ttisp->tt_gmtoff = detzcode(p);
00757          p += 4;
00758          ttisp->tt_isdst = (unsigned char) *p++;
00759          if (ttisp->tt_isdst != 0 && ttisp->tt_isdst != 1)
00760             return -1;
00761          ttisp->tt_abbrind = (unsigned char) *p++;
00762          if (ttisp->tt_abbrind < 0 ||
00763             ttisp->tt_abbrind > sp->charcnt)
00764                return -1;
00765       }
00766       for (i = 0; i < sp->charcnt; ++i)
00767          sp->chars[i] = *p++;
00768       sp->chars[i] = '\0'; /* ensure '\0' at end */
00769       for (i = 0; i < sp->leapcnt; ++i) {
00770          struct lsinfo *   lsisp;
00771 
00772          lsisp = &sp->lsis[i];
00773          lsisp->ls_trans = (stored == 4) ?
00774             detzcode(p) : detzcode64(p);
00775          p += stored;
00776          lsisp->ls_corr = detzcode(p);
00777          p += 4;
00778       }
00779       for (i = 0; i < sp->typecnt; ++i) {
00780          struct ttinfo *   ttisp;
00781 
00782          ttisp = &sp->ttis[i];
00783          if (ttisstdcnt == 0)
00784             ttisp->tt_ttisstd = FALSE;
00785          else {
00786             ttisp->tt_ttisstd = *p++;
00787             if (ttisp->tt_ttisstd != TRUE &&
00788                ttisp->tt_ttisstd != FALSE)
00789                   return -1;
00790          }
00791       }
00792       for (i = 0; i < sp->typecnt; ++i) {
00793          struct ttinfo *   ttisp;
00794 
00795          ttisp = &sp->ttis[i];
00796          if (ttisgmtcnt == 0)
00797             ttisp->tt_ttisgmt = FALSE;
00798          else {
00799             ttisp->tt_ttisgmt = *p++;
00800             if (ttisp->tt_ttisgmt != TRUE &&
00801                ttisp->tt_ttisgmt != FALSE)
00802                   return -1;
00803          }
00804       }
00805       /*
00806       ** Out-of-sort ats should mean we're running on a
00807       ** signed time_t system but using a data file with
00808       ** unsigned values (or vice versa).
00809       */
00810       for (i = 0; i < sp->timecnt - 2; ++i)
00811          if (sp->ats[i] > sp->ats[i + 1]) {
00812             ++i;
00813             if (TYPE_SIGNED(time_t)) {
00814                /*
00815                ** Ignore the end (easy).
00816                */
00817                sp->timecnt = i;
00818             } else {
00819                /*
00820                ** Ignore the beginning (harder).
00821                */
00822                int   j;
00823 
00824                for (j = 0; j + i < sp->timecnt; ++j) {
00825                   sp->ats[j] = sp->ats[j + i];
00826                   sp->types[j] = sp->types[j + i];
00827                }
00828                sp->timecnt = j;
00829             }
00830             break;
00831          }
00832       /*
00833       ** If this is an old file, we're done.
00834       */
00835       if (u.tzhead.tzh_version[0] == '\0')
00836          break;
00837       nread -= p - u.buf;
00838       for (i = 0; i < nread; ++i)
00839          u.buf[i] = p[i];
00840       /*
00841       ** If this is a narrow integer time_t system, we're done.
00842       */
00843       if (stored >= (int) sizeof(time_t) && TYPE_INTEGRAL(time_t))
00844          break;
00845    }
00846    if (doextend && nread > 2 &&
00847       u.buf[0] == '\n' && u.buf[nread - 1] == '\n' &&
00848       sp->typecnt + 2 <= TZ_MAX_TYPES) {
00849          struct state   ts;
00850          int   result;
00851 
00852          u.buf[nread - 1] = '\0';
00853          result = tzparse(&u.buf[1], &ts, FALSE);
00854          if (result == 0 && ts.typecnt == 2 &&
00855             sp->charcnt + ts.charcnt <= TZ_MAX_CHARS) {
00856                for (i = 0; i < 2; ++i)
00857                   ts.ttis[i].tt_abbrind +=
00858                      sp->charcnt;
00859                for (i = 0; i < ts.charcnt; ++i)
00860                   sp->chars[sp->charcnt++] =
00861                      ts.chars[i];
00862                i = 0;
00863                while (i < ts.timecnt &&
00864                   ts.ats[i] <=
00865                   sp->ats[sp->timecnt - 1])
00866                      ++i;
00867                while (i < ts.timecnt &&
00868                    sp->timecnt < TZ_MAX_TIMES) {
00869                   sp->ats[sp->timecnt] =
00870                      ts.ats[i];
00871                   sp->types[sp->timecnt] =
00872                      sp->typecnt +
00873                      ts.types[i];
00874                   ++sp->timecnt;
00875                   ++i;
00876                }
00877                sp->ttis[sp->typecnt++] = ts.ttis[0];
00878                sp->ttis[sp->typecnt++] = ts.ttis[1];
00879          }
00880    }
00881    i = 2 * YEARSPERREPEAT;
00882    sp->goback = sp->goahead = sp->timecnt > i;
00883    sp->goback = sp->goback && sp->types[i] == sp->types[0] &&
00884       differ_by_repeat(sp->ats[i], sp->ats[0]);
00885    sp->goahead = sp->goahead &&
00886       sp->types[sp->timecnt - 1] == sp->types[sp->timecnt - 1 - i] &&
00887       differ_by_repeat(sp->ats[sp->timecnt - 1],
00888           sp->ats[sp->timecnt - 1 - i]);
00889    return 0;
00890 }

static int tzparse ( const char *  name,
struct state sp,
const int  lastditch 
) [static]

Note:
Given a POSIX section 8-style TZ string, fill in the rule tables as appropriate.

Definition at line 1174 of file localtime.c.

References state::ats, state::chars, EPOCH_YEAR, FALSE, getoffset(), getqzname(), getrule(), getzname(), INITIALIZE, isleap, state::leapcnt, SECSPERDAY, SECSPERHOUR, state::timecnt, transtime(), ttinfo::tt_abbrind, ttinfo::tt_gmtoff, ttinfo::tt_isdst, ttinfo::tt_ttisgmt, ttinfo::tt_ttisstd, state::ttis, state::typecnt, state::types, TZ_MAX_TIMES, TZDEFRULES, TZDEFRULESTRING, and tzload().

Referenced by ast_tzset(), and gmtload().

01175 {
01176    const char *         stdname;
01177    const char *         dstname;
01178    size_t            stdlen;
01179    size_t            dstlen;
01180    long           stdoffset;
01181    long           dstoffset;
01182    time_t *    atp;
01183    unsigned char *   typep;
01184    char *         cp;
01185    int         load_result;
01186 
01187    INITIALIZE(dstname);
01188    stdname = name;
01189    if (lastditch) {
01190       stdlen = strlen(name);  /* length of standard zone name */
01191       name += stdlen;
01192       if (stdlen >= sizeof sp->chars)
01193          stdlen = (sizeof sp->chars) - 1;
01194       stdoffset = 0;
01195    } else {
01196       if (*name == '<') {
01197          name++;
01198          stdname = name;
01199          name = getqzname(name, '>');
01200          if (*name != '>')
01201             return -1;
01202          stdlen = name - stdname;
01203          name++;
01204       } else {
01205          name = getzname(name);
01206          stdlen = name - stdname;
01207       }
01208       if (*name == '\0')
01209          return -1;
01210       name = getoffset(name, &stdoffset);
01211       if (name == NULL)
01212          return -1;
01213    }
01214    load_result = tzload(TZDEFRULES, sp, FALSE);
01215    if (load_result != 0)
01216       sp->leapcnt = 0;     /* so, we're off a little */
01217    if (*name != '\0') {
01218       if (*name == '<') {
01219          dstname = ++name;
01220          name = getqzname(name, '>');
01221          if (*name != '>')
01222             return -1;
01223          dstlen = name - dstname;
01224          name++;
01225       } else {
01226          dstname = name;
01227          name = getzname(name);
01228          dstlen = name - dstname; /* length of DST zone name */
01229       }
01230       if (*name != '\0' && *name != ',' && *name != ';') {
01231          name = getoffset(name, &dstoffset);
01232          if (name == NULL)
01233             return -1;
01234       } else   dstoffset = stdoffset - SECSPERHOUR;
01235       if (*name == '\0' && load_result != 0)
01236          name = TZDEFRULESTRING;
01237       if (*name == ',' || *name == ';') {
01238          struct rule start;
01239          struct rule end;
01240          int   year;
01241          time_t   janfirst;
01242          time_t      starttime;
01243          time_t      endtime;
01244 
01245          ++name;
01246          if ((name = getrule(name, &start)) == NULL)
01247             return -1;
01248          if (*name++ != ',')
01249             return -1;
01250          if ((name = getrule(name, &end)) == NULL)
01251             return -1;
01252          if (*name != '\0')
01253             return -1;
01254          sp->typecnt = 2;  /* standard time and DST */
01255          /*
01256          ** Two transitions per year, from EPOCH_YEAR forward.
01257          */
01258          sp->ttis[0].tt_gmtoff = -dstoffset;
01259          sp->ttis[0].tt_isdst = 1;
01260          sp->ttis[0].tt_abbrind = stdlen + 1;
01261          sp->ttis[1].tt_gmtoff = -stdoffset;
01262          sp->ttis[1].tt_isdst = 0;
01263          sp->ttis[1].tt_abbrind = 0;
01264          atp = sp->ats;
01265          typep = sp->types;
01266          janfirst = 0;
01267          sp->timecnt = 0;
01268          for (year = EPOCH_YEAR;
01269              sp->timecnt + 2 <= TZ_MAX_TIMES;
01270              ++year) {
01271                time_t   newfirst;
01272 
01273             starttime = transtime(janfirst, year, &start,
01274                stdoffset);
01275             endtime = transtime(janfirst, year, &end,
01276                dstoffset);
01277             if (starttime > endtime) {
01278                *atp++ = endtime;
01279                *typep++ = 1;  /* DST ends */
01280                *atp++ = starttime;
01281                *typep++ = 0;  /* DST begins */
01282             } else {
01283                *atp++ = starttime;
01284                *typep++ = 0;  /* DST begins */
01285                *atp++ = endtime;
01286                *typep++ = 1;  /* DST ends */
01287             }
01288             sp->timecnt += 2;
01289             newfirst = janfirst;
01290             newfirst += year_lengths[isleap(year)] *
01291                SECSPERDAY;
01292             if (newfirst <= janfirst)
01293                break;
01294             janfirst = newfirst;
01295          }
01296       } else {
01297          long  theirstdoffset;
01298          long  theirdstoffset;
01299          long  theiroffset;
01300          int   isdst;
01301          int   i;
01302          int   j;
01303 
01304          if (*name != '\0')
01305             return -1;
01306          /*
01307          ** Initial values of theirstdoffset and theirdstoffset.
01308          */
01309          theirstdoffset = 0;
01310          for (i = 0; i < sp->timecnt; ++i) {
01311             j = sp->types[i];
01312             if (!sp->ttis[j].tt_isdst) {
01313                theirstdoffset =
01314                   -sp->ttis[j].tt_gmtoff;
01315                break;
01316             }
01317          }
01318          theirdstoffset = 0;
01319          for (i = 0; i < sp->timecnt; ++i) {
01320             j = sp->types[i];
01321             if (sp->ttis[j].tt_isdst) {
01322                theirdstoffset =
01323                   -sp->ttis[j].tt_gmtoff;
01324                break;
01325             }
01326          }
01327          /*
01328          ** Initially we're assumed to be in standard time.
01329          */
01330          isdst = FALSE;
01331          theiroffset = theirstdoffset;
01332          /*
01333          ** Now juggle transition times and types
01334          ** tracking offsets as you do.
01335          */
01336          for (i = 0; i < sp->timecnt; ++i) {
01337             j = sp->types[i];
01338             sp->types[i] = sp->ttis[j].tt_isdst;
01339             if (sp->ttis[j].tt_ttisgmt) {
01340                /* No adjustment to transition time */
01341             } else {
01342                /*
01343                ** If summer time is in effect, and the
01344                ** transition time was not specified as
01345                ** standard time, add the summer time
01346                ** offset to the transition time;
01347                ** otherwise, add the standard time
01348                ** offset to the transition time.
01349                */
01350                /*
01351                ** Transitions from DST to DDST
01352                ** will effectively disappear since
01353                ** POSIX provides for only one DST
01354                ** offset.
01355                */
01356                if (isdst && !sp->ttis[j].tt_ttisstd) {
01357                   sp->ats[i] += dstoffset -
01358                      theirdstoffset;
01359                } else {
01360                   sp->ats[i] += stdoffset -
01361                      theirstdoffset;
01362                }
01363             }
01364             theiroffset = -sp->ttis[j].tt_gmtoff;
01365             if (sp->ttis[j].tt_isdst)
01366                theirdstoffset = theiroffset;
01367             else  theirstdoffset = theiroffset;
01368          }
01369          /*
01370          ** Finally, fill in ttis.
01371          ** ttisstd and ttisgmt need not be handled.
01372          */
01373          sp->ttis[0].tt_gmtoff = -stdoffset;
01374          sp->ttis[0].tt_isdst = FALSE;
01375          sp->ttis[0].tt_abbrind = 0;
01376          sp->ttis[1].tt_gmtoff = -dstoffset;
01377          sp->ttis[1].tt_isdst = TRUE;
01378          sp->ttis[1].tt_abbrind = stdlen + 1;
01379          sp->typecnt = 2;
01380       }
01381    } else {
01382       dstlen = 0;
01383       sp->typecnt = 1;     /* only standard time */
01384       sp->timecnt = 0;
01385       sp->ttis[0].tt_gmtoff = -stdoffset;
01386       sp->ttis[0].tt_isdst = 0;
01387       sp->ttis[0].tt_abbrind = 0;
01388    }
01389    sp->charcnt = stdlen + 1;
01390    if (dstlen != 0)
01391       sp->charcnt += dstlen + 1;
01392    if ((size_t) sp->charcnt > sizeof sp->chars)
01393       return -1;
01394    cp = sp->chars;
01395    (void) strncpy(cp, stdname, stdlen);
01396    cp += stdlen;
01397    *cp++ = '\0';
01398    if (dstlen != 0) {
01399       (void) strncpy(cp, dstname, dstlen);
01400       *(cp + dstlen) = '\0';
01401    }
01402    return 0;
01403 }


Variable Documentation

char elsieid[] = "@(#)localtime.c 8.5" [static]

Definition at line 83 of file localtime.c.

const char gmt[] = "GMT" [static]

Definition at line 111 of file localtime.c.

ast_cond_t initialization [static]

Definition at line 266 of file localtime.c.

Referenced by add_notify(), and ast_localtime_wakeup_monitor().

ast_mutex_t initialization_lock [static]

Definition at line 267 of file localtime.c.

Referenced by add_notify(), and inotify_daemon().

int inotify_fd = -1 [static]

Definition at line 269 of file localtime.c.

Referenced by add_notify(), and scan_thread().

pthread_t inotify_thread = AST_PTHREADT_NULL [static]

Definition at line 265 of file localtime.c.

Referenced by add_notify(), and ast_localtime_wakeup_monitor().

const int mon_lengths[2][MONSPERYEAR] [static]

Initial value:

 {
   { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
   { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
}

Definition at line 892 of file localtime.c.

Referenced by time2sub(), and timesub().

struct timeval WRONG = { 0, 0 } [static]

Definition at line 112 of file localtime.c.

const int year_lengths[2] [static]

Initial value:

Definition at line 897 of file localtime.c.

Referenced by time2sub(), and timesub().


Generated on Mon Oct 8 12:39:24 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7