Fri Nov 12 12:04:57 2010

Asterisk developer's documentation


localtime.c File Reference

#include "asterisk.h"
#include <sys/stat.h>
#include <fcntl.h>
#include <float.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 dependency graph for localtime.c:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

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)
struct ast_tmast_localtime (const struct timeval *timep, struct ast_tm *tmp, const char *zone)
 Timezone-independent version of localtime_r(3).
struct timeval ast_mktime (struct ast_tm *tmp, const char *zone)
 Timezone-independent version of mktime(3).
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.
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.
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 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 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 126 of file localtime.c.

#define DAY_OF_YEAR   1

Definition at line 170 of file localtime.c.

Referenced by getrule(), and transtime().

#define JULIAN_DAY   0

Definition at line 169 of file localtime.c.

Referenced by getrule(), and transtime().

#define MONTH_NTH_DAY_OF_WEEK   2

Definition at line 171 of file localtime.c.

Referenced by getrule(), and transtime().

#define MY_TZNAME_MAX   255

Definition at line 132 of file localtime.c.

#define OPEN_MODE   O_RDONLY

Definition at line 94 of file localtime.c.

Referenced by tzload().

#define TZ_ABBR_CHAR_SET   "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 :+-._"

Definition at line 78 of file localtime.c.

#define TZ_ABBR_ERR_CHAR   '_'

Definition at line 83 of file localtime.c.

#define TZ_ABBR_MAX_LEN   16

Definition at line 74 of file localtime.c.

#define TZ_STRLEN_MAX   255

Definition at line 135 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 108 of file localtime.c.

Referenced by tzparse().


Function Documentation

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

Definition at line 288 of file localtime.c.

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

Referenced by tzload().

00289 {
00290    if (inotify_thread == AST_PTHREADT_NULL) {
00291       ast_cond_init(&initialization, NULL);
00292       ast_mutex_init(&initialization_lock);
00293       ast_mutex_lock(&initialization_lock);
00294       if (!(ast_pthread_create_background(&inotify_thread, NULL, inotify_daemon, NULL))) {
00295          /* Give the thread a chance to initialize */
00296          ast_cond_wait(&initialization, &initialization_lock);
00297       } else {
00298          ast_log(LOG_ERROR, "Unable to start notification thread\n");
00299          ast_mutex_unlock(&initialization_lock);
00300          return;
00301       }
00302       ast_mutex_unlock(&initialization_lock);
00303    }
00304 
00305    if (inotify_fd > -1) {
00306       char fullpath[FILENAME_MAX + 1] = "";
00307       if (readlink(path, fullpath, sizeof(fullpath) - 1) != -1) {
00308          /* If file the symlink points to changes */
00309          sp->wd[1] = inotify_add_watch(inotify_fd, fullpath, IN_ATTRIB | IN_DELETE_SELF | IN_MODIFY | IN_MOVE_SELF | IN_CLOSE_WRITE );
00310       } else {
00311          sp->wd[1] = -1;
00312       }
00313       /* or if the symlink itself changes (or the real file is here, if path is not a symlink) */
00314       sp->wd[0] = inotify_add_watch(inotify_fd, path, IN_ATTRIB | IN_DELETE_SELF | IN_MODIFY | IN_MOVE_SELF | IN_CLOSE_WRITE
00315 #ifdef IN_DONT_FOLLOW   /* Only defined in glibc 2.5 and above */
00316          | IN_DONT_FOLLOW
00317 #endif
00318       );
00319    }
00320 }

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 1320 of file localtime.c.

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

Referenced by set_timezone_variables().

01321 {
01322    int i;   
01323    int transition1 = -1;
01324    int transition2 = -1;
01325    time_t      seconds;
01326    int  bounds_exceeded = 0;
01327    time_t  t = *timep;
01328    const struct state *sp;
01329    
01330    if (NULL == dst_enabled)
01331       return;
01332    *dst_enabled = 0;
01333 
01334    if (NULL == dst_start || NULL == dst_end || NULL == gmt_off)
01335       return;
01336 
01337    *gmt_off = 0; 
01338    
01339    sp = ast_tzset(zone);
01340    if (NULL == sp) 
01341       return;
01342    
01343    /* If the desired time exceeds the bounds of the defined time transitions  
01344    * then give give up on determining DST info and simply look for gmt offset 
01345    * This requires that I adjust the given time using increments of Gregorian 
01346    * repeats to place the time within the defined time transitions in the 
01347    * timezone structure.  
01348    */
01349    if ((sp->goback && t < sp->ats[0]) ||
01350          (sp->goahead && t > sp->ats[sp->timecnt - 1])) {
01351       time_t      tcycles;
01352       int_fast64_t   icycles;
01353 
01354       if (t < sp->ats[0])
01355          seconds = sp->ats[0] - t;
01356       else  seconds = t - sp->ats[sp->timecnt - 1];
01357       --seconds;
01358       tcycles = seconds / YEARSPERREPEAT / AVGSECSPERYEAR;
01359       ++tcycles;
01360       icycles = tcycles;
01361       if (tcycles - icycles >= 1 || icycles - tcycles >= 1)
01362          return;
01363       seconds = icycles;
01364       seconds *= YEARSPERREPEAT;
01365       seconds *= AVGSECSPERYEAR;
01366       if (t < sp->ats[0])
01367          t += seconds;
01368       else
01369          t -= seconds;
01370       
01371       if (t < sp->ats[0] || t > sp->ats[sp->timecnt - 1])
01372          return;  /* "cannot happen" */
01373 
01374       bounds_exceeded = 1;
01375    }
01376 
01377    if (sp->timecnt == 0 || t < sp->ats[0]) {
01378       /* I have no transition times or I'm before time */
01379       *dst_enabled = 0;
01380       /* Find where I can get gmtoff */
01381       i = 0;
01382       while (sp->ttis[i].tt_isdst)
01383          if (++i >= sp->typecnt) {
01384          i = 0;
01385          break;
01386          }
01387          *gmt_off = sp->ttis[i].tt_gmtoff;
01388          return;
01389    } 
01390 
01391    for (i = 1; i < sp->timecnt; ++i) {
01392       if (t < sp->ats[i]) {
01393          transition1 = sp->types[i - 1];
01394          transition2 = sp->types[i];
01395          break;
01396       } 
01397    }
01398    /* if I found transition times that do not bounded the given time and these correspond to 
01399       or the bounding zones do not reflect a changes in day light savings, then I do not have dst active */
01400    if (i >= sp->timecnt || 0 > transition1 || 0 > transition2 ||
01401          (sp->ttis[transition1].tt_isdst == sp->ttis[transition2].tt_isdst)) {
01402       *dst_enabled = 0;
01403       *gmt_off     = sp->ttis[sp->types[sp->timecnt -1]].tt_gmtoff;
01404    } else {
01405       /* I have valid daylight savings information. */
01406       if(sp->ttis[transition2].tt_isdst) 
01407          *gmt_off = sp->ttis[transition1].tt_gmtoff;
01408       else 
01409          *gmt_off = sp->ttis[transition2].tt_gmtoff;
01410 
01411       /* If I adjusted the time earlier, indicate that the dst is invalid */
01412       if (!bounds_exceeded) {
01413          *dst_enabled = 1;
01414          /* Determine which of the bounds is the start of daylight savings and which is the end */
01415          if(sp->ttis[transition2].tt_isdst) {
01416             *dst_start = sp->ats[i];
01417             *dst_end = sp->ats[i -1];
01418          } else {
01419             *dst_start = sp->ats[i -1];
01420             *dst_end = sp->ats[i];
01421          }
01422       }
01423    }  
01424    return;
01425 }

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

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 1305 of file localtime.c.

References ast_tzset(), and localsub().

Referenced by __ast_verbose_ap(), acf_strftime(), action_corestatus(), append_date(), ast_check_timing(), ast_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_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(), execute_cb(), find_conf_realtime(), format_date(), get_date(), handle_minivm_show_stats(), handle_show_settings(), handle_time_date_req_message(), httpd_helper_thread(), iax2_datetime(), isodate(), leave_voicemail(), main(), make_email_file(), manager_log(), odbc_log(), packdate(), pgsql_log(), phone_call(), phoneprov_callback(), play_message_datetime(), prep_email_sub_vars(), rpt_localtime(), 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_notify_request_with_callerid(), vmu_tm(), write_history(), and write_metadata().

01306 {
01307    const struct state *sp = ast_tzset(zone);
01308    memset(tmp, 0, sizeof(*tmp));
01309    return sp ? localsub(timep, 0L, tmp, sp) : NULL;
01310 }

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

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 1920 of file localtime.c.

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

Referenced by acf_strptime(), conf_run(), find_conf_realtime(), rt_extend_conf(), sms_handleincoming_proto2(), sms_readfile(), and unpackdate().

01921 {
01922    const struct state *sp;
01923    if (!(sp = ast_tzset(zone)))
01924       return WRONG;
01925    return time1(tmp, localsub, 0L, sp);
01926 }

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.
Return values:
An integer value specifying the number of bytes placed into buf or -1 on error.

Definition at line 1928 of file localtime.c.

References ast_calloc, ast_free, ast_realloc, format, and ast_tm::tm_usec.

Referenced by __ast_verbose_ap(), acf_strftime(), action_corestatus(), append_date(), ast_log(), build_radius_record(), cdr_get_tv(), cli_prompt(), conf_run(), dump_datetime(), execute_cb(), find_conf_realtime(), format_date(), get_date(), handle_minivm_show_stats(), handle_show_settings(), httpd_helper_thread(), isodate(), leave_voicemail(), make_email_file(), manager_log(), odbc_log(), pgsql_log(), phoneprov_callback(), prep_email_sub_vars(), rt_extend_conf(), sendmail(), sendpage(), sip_show_registry(), static_callback(), timeout_write(), and write_metadata().

01929 {
01930    size_t fmtlen = strlen(tmp) + 1;
01931    char *format = ast_calloc(1, fmtlen), *fptr = format, *newfmt;
01932    int decimals = -1, i, res;
01933    long fraction;
01934 
01935    if (!format)
01936       return -1;
01937    for (; *tmp; tmp++) {
01938       if (*tmp == '%') {
01939          switch (tmp[1]) {
01940          case '1':
01941          case '2':
01942          case '3':
01943          case '4':
01944          case '5':
01945          case '6':
01946             if (tmp[2] != 'q')
01947                goto defcase;
01948             decimals = tmp[1] - '0';
01949             tmp++;
01950             /* Fall through */
01951          case 'q': /* Milliseconds */
01952             if (decimals == -1)
01953                decimals = 3;
01954 
01955             /* Juggle some memory to fit the item */
01956             newfmt = ast_realloc(format, fmtlen + decimals);
01957             if (!newfmt) {
01958                ast_free(format);
01959                return -1;
01960             }
01961             fptr = fptr - format + newfmt;
01962             format = newfmt;
01963             fmtlen += decimals;
01964 
01965             /* Reduce the fraction of time to the accuracy needed */
01966             for (i = 6, fraction = tm->tm_usec; i > decimals; i--)
01967                fraction /= 10;
01968             fptr += sprintf(fptr, "%0*ld", decimals, fraction);
01969 
01970             /* Reset, in case more than one 'q' specifier exists */
01971             decimals = -1;
01972             tmp++;
01973             break;
01974          default:
01975             goto defcase;
01976          }
01977       } else
01978 defcase: *fptr++ = *tmp;
01979    }
01980    *fptr = '\0';
01981 #undef strftime
01982    res = (int)strftime(buf, len, format, (struct tm *)tm);
01983    ast_free(format);
01984    return res;
01985 }

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.
Return values:
A pointer to the first character within s not used to parse the date and time.

Definition at line 1987 of file localtime.c.

References ast_tm::tm_isdst, and ast_tm::tm_usec.

Referenced by acf_strptime(), conf_run(), find_conf_realtime(), and rt_extend_conf().

01988 {
01989    struct tm tm2 = { 0, };
01990    char *res = strptime(s, format, &tm2);
01991    memcpy(tm, &tm2, sizeof(*tm));
01992    tm->tm_usec = 0;
01993    /* strptime(3) doesn't set .tm_isdst correctly, so to force ast_mktime(3)
01994     * to deal with it correctly, we set it to -1. */
01995    tm->tm_isdst = -1;
01996    return res;
01997 }

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

Definition at line 1175 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().

01176 {
01177    struct state *sp;
01178 
01179    if (ast_strlen_zero(zone))
01180       zone = "/etc/localtime";
01181 
01182    AST_LIST_LOCK(&zonelist);
01183    AST_LIST_TRAVERSE(&zonelist, sp, list) {
01184       if (!strcmp(sp->name, zone)) {
01185          AST_LIST_UNLOCK(&zonelist);
01186          return sp;
01187       }
01188    }
01189    AST_LIST_UNLOCK(&zonelist);
01190 
01191    if (!(sp = ast_calloc(1, sizeof *sp)))
01192       return NULL;
01193 
01194    if (tzload(zone, sp, TRUE) != 0) {
01195       if (zone[0] == ':' || tzparse(zone, sp, FALSE) != 0)
01196          (void) gmtload(sp);
01197    }
01198    ast_copy_string(sp->name, zone, sizeof(sp->name));
01199    AST_LIST_LOCK(&zonelist);
01200    AST_LIST_INSERT_TAIL(&zonelist, sp, list);
01201    AST_LIST_UNLOCK(&zonelist);
01202    return sp;
01203 }

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 392 of file localtime.c.

Referenced by tzload().

00393 {
00394    long  result;
00395    int   i;
00396 
00397    result = (codep[0] & 0x80) ? ~0L : 0;
00398    for (i = 0; i < 4; ++i)
00399       result = (result << 8) | (codep[i] & 0xff);
00400    return result;
00401 }

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

Definition at line 403 of file localtime.c.

Referenced by tzload().

00404 {
00405    time_t   result;
00406    int   i;
00407 
00408    result = (codep[0] & 0x80) ?  (~(int_fast64_t) 0) : 0;
00409    for (i = 0; i < 8; ++i)
00410       result = result * 256 + (codep[i] & 0xff);
00411    return result;
00412 }

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

Definition at line 414 of file localtime.c.

Referenced by tzload().

00415 {
00416    const long long at1 = t1, at0 = t0;
00417    if (TYPE_INTEGRAL(time_t) &&
00418       TYPE_BIT(time_t) - TYPE_SIGNED(time_t) < SECSPERREPEAT_BITS)
00419          return 0;
00420    return at1 - at0 == SECSPERREPEAT;
00421 }

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 704 of file localtime.c.

References is_digit, and num.

Referenced by getrule(), and getsecs().

00705 {
00706    char  c;
00707    int   num;
00708 
00709    if (strp == NULL || !is_digit(c = *strp))
00710       return NULL;
00711    num = 0;
00712    do {
00713       num = num * 10 + (c - '0');
00714       if (num > max)
00715          return NULL;   /* illegal value */
00716       c = *++strp;
00717    } while (is_digit(c));
00718    if (num < min)
00719       return NULL;      /* illegal value */
00720    *nump = num;
00721    return strp;
00722 }

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 771 of file localtime.c.

References getsecs().

Referenced by tzparse().

00772 {
00773    int   neg = 0;
00774 
00775    if (*strp == '-') {
00776       neg = 1;
00777       ++strp;
00778    } else if (*strp == '+')
00779       ++strp;
00780    strp = getsecs(strp, offsetp);
00781    if (strp == NULL)
00782       return NULL;      /* illegal time */
00783    if (neg)
00784       *offsetp = -*offsetp;
00785    return strp;
00786 }

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 688 of file localtime.c.

Referenced by tzparse().

00689 {
00690    int   c;
00691 
00692    while ((c = *strp) != '\0' && c != delim)
00693       ++strp;
00694    return strp;
00695 }

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 795 of file localtime.c.

References DAY_OF_YEAR, DAYSPERLYEAR, 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().

00796 {
00797    if (*strp == 'J') {
00798       /*
00799       ** Julian day.
00800       */
00801       rulep->r_type = JULIAN_DAY;
00802       ++strp;
00803       strp = getnum(strp, &rulep->r_day, 1, DAYSPERNYEAR);
00804    } else if (*strp == 'M') {
00805       /*
00806       ** Month, week, day.
00807       */
00808       rulep->r_type = MONTH_NTH_DAY_OF_WEEK;
00809       ++strp;
00810       strp = getnum(strp, &rulep->r_mon, 1, MONSPERYEAR);
00811       if (strp == NULL)
00812          return NULL;
00813       if (*strp++ != '.')
00814          return NULL;
00815       strp = getnum(strp, &rulep->r_week, 1, 5);
00816       if (strp == NULL)
00817          return NULL;
00818       if (*strp++ != '.')
00819          return NULL;
00820       strp = getnum(strp, &rulep->r_day, 0, DAYSPERWEEK - 1);
00821    } else if (is_digit(*strp)) {
00822       /*
00823       ** Day of year.
00824       */
00825       rulep->r_type = DAY_OF_YEAR;
00826       strp = getnum(strp, &rulep->r_day, 0, DAYSPERLYEAR - 1);
00827    } else   return NULL;      /* invalid format */
00828    if (strp == NULL)
00829       return NULL;
00830    if (*strp == '/') {
00831       /*
00832       ** Time specified.
00833       */
00834       ++strp;
00835       strp = getsecs(strp, &rulep->r_time);
00836    } else   rulep->r_time = 2 * SECSPERHOUR; /* default = 2:00:00 */
00837    return strp;
00838 }

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 732 of file localtime.c.

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

Referenced by getoffset(), and getrule().

00733 {
00734    int   num;
00735 
00736    /*
00737    ** `HOURSPERDAY * DAYSPERWEEK - 1' allows quasi-Posix rules like
00738    ** "M10.4.6/26", which does not conform to Posix,
00739    ** but which specifies the equivalent of
00740    ** ``02:00 on the first Sunday on or after 23 Oct''.
00741    */
00742    strp = getnum(strp, &num, 0, HOURSPERDAY * DAYSPERWEEK - 1);
00743    if (strp == NULL)
00744       return NULL;
00745    *secsp = num * (long) SECSPERHOUR;
00746    if (*strp == ':') {
00747       ++strp;
00748       strp = getnum(strp, &num, 0, MINSPERHOUR - 1);
00749       if (strp == NULL)
00750          return NULL;
00751       *secsp += num * SECSPERMIN;
00752       if (*strp == ':') {
00753          ++strp;
00754          /* `SECSPERMIN' allows for leap seconds. */
00755          strp = getnum(strp, &num, 0, SECSPERMIN);
00756          if (strp == NULL)
00757             return NULL;
00758          *secsp += num;
00759       }
00760    }
00761    return strp;
00762 }

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 669 of file localtime.c.

References is_digit.

Referenced by tzparse().

00670 {
00671    char  c;
00672 
00673    while ((c = *strp) != '\0' && !is_digit(c) && c != ',' && c != '-' &&
00674       c != '+')
00675          ++strp;
00676    return strp;
00677 }

static int gmtload ( struct state sp  )  [static]

Definition at line 1167 of file localtime.c.

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

Referenced by ast_tzset(), and gmtsub().

01168 {
01169    if (tzload(gmt, sp, TRUE) != 0)
01170       return tzparse(gmt, sp, TRUE);
01171    else
01172       return -1;
01173 }

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

Definition at line 1431 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().

01432 {
01433    struct ast_tm *   result;
01434    struct state *sp;
01435 
01436    AST_LIST_LOCK(&zonelist);
01437    AST_LIST_TRAVERSE(&zonelist, sp, list) {
01438       if (!strcmp(sp->name, "UTC"))
01439          break;
01440    }
01441 
01442    if (!sp) {
01443       if (!(sp = (struct state *) ast_calloc(1, sizeof *sp)))
01444          return NULL;
01445       gmtload(sp);
01446       AST_LIST_INSERT_TAIL(&zonelist, sp, list);
01447    }
01448    AST_LIST_UNLOCK(&zonelist);
01449 
01450    result = timesub(timep, offset, sp, tmp);
01451 #ifdef TM_ZONE
01452    /*
01453    ** Could get fancy here and deliver something such as
01454    ** "UTC+xxxx" or "UTC-xxxx" if offset is non-zero,
01455    ** but this is no time for a treasure hunt.
01456    */
01457    if (offset != 0)
01458       tmp->TM_ZONE = "    ";
01459    else
01460       tmp->TM_ZONE = sp->chars;
01461 #endif /* defined TM_ZONE */
01462    return result;
01463 }

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

Simplified normalize logic courtesy Paul Eggert.

Note:
Adapted from code provided by Robert Elz, who writes: The "best" way to do mktime I think is based on an idea of Bob Kridle's (so its said...) from a long time ago. It does a binary search of the time_t space. Since time_t's are just 32 bits, its a max of 32 iterations (even at 64 bits it would still be very reasonable).

Definition at line 1614 of file localtime.c.

Referenced by normalize_overflow(), time2sub(), and timesub().

01615 {
01616    int   number0;
01617 
01618    number0 = *number;
01619    *number += delta;
01620    return (*number < number0) != (delta < 0);
01621 }

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

Definition at line 234 of file localtime.c.

References ast_cond_signal(), 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, buf, errno, initialization, initialization_lock, inotify_fd, inotify_thread, state::list, LOG_ERROR, state::name, and state::wd.

Referenced by add_notify().

00235 {
00236    struct {
00237       struct inotify_event iev;
00238       char name[FILENAME_MAX + 1];
00239    } buf;
00240    ssize_t res;
00241    struct state *cur;
00242    struct timespec ten_seconds = { 10, 0 };
00243 
00244    inotify_fd = inotify_init();
00245 
00246    ast_mutex_lock(&initialization_lock);
00247    ast_cond_signal(&initialization);
00248    ast_mutex_unlock(&initialization_lock);
00249 
00250    if (inotify_fd < 0) {
00251       ast_log(LOG_ERROR, "Cannot initialize file notification service: %s (%d)\n", strerror(errno), errno);
00252       inotify_thread = AST_PTHREADT_NULL;
00253       return NULL;
00254    }
00255 
00256    for (;/*ever*/;) {
00257       /* This read should block, most of the time. */
00258       if ((res = read(inotify_fd, &buf, sizeof(buf))) < sizeof(buf.iev) && res > 0) {
00259          /* This should never happen */
00260          ast_log(LOG_ERROR, "Inotify read less than a full event (%zd < %zd)?!!\n", res, sizeof(buf.iev));
00261          break;
00262       } else if (res < 0) {
00263          if (errno == EINTR || errno == EAGAIN) {
00264             /* If read fails, then wait a bit, then continue */
00265             nanosleep(&ten_seconds, NULL);
00266             continue;
00267          }
00268          /* Sanity check -- this should never happen, either */
00269          ast_log(LOG_ERROR, "Inotify failed: %s\n", strerror(errno));
00270          break;
00271       }
00272       AST_LIST_LOCK(&zonelist);
00273       AST_LIST_TRAVERSE_SAFE_BEGIN(&zonelist, cur, list) {
00274          if (cur->wd[0] == buf.iev.wd || cur->wd[1] == buf.iev.wd) {
00275             AST_LIST_REMOVE_CURRENT(list);
00276             ast_free(cur);
00277             break;
00278          }
00279       }
00280       AST_LIST_TRAVERSE_SAFE_END
00281       AST_LIST_UNLOCK(&zonelist);
00282    }
00283    close(inotify_fd);
00284    inotify_thread = AST_PTHREADT_NULL;
00285    return NULL;
00286 }

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 1470 of file localtime.c.

Referenced by timesub().

01471 {
01472    return (y >= 0) ? (y / 4 - y / 100 + y / 400) :
01473       -(leaps_thru_end_of(-(y + 1)) + 1);
01474 }

static struct ast_tm* localsub ( const struct timeval *  timep,
const long  offset,
struct ast_tm tmp,
const struct state sp 
) [static, read]
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 1214 of file localtime.c.

References state::ats, state::chars, gmtsub(), state::goahead, state::goback, 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, and state::types.

Referenced by ast_localtime(), and ast_mktime().

01215 {
01216    const struct ttinfo *   ttisp;
01217    int         i;
01218    struct ast_tm *      result;
01219    struct timeval t;
01220    memcpy(&t, timep, sizeof(t));
01221 
01222    if (sp == NULL)
01223       return gmtsub(timep, offset, tmp);
01224    if ((sp->goback && t.tv_sec < sp->ats[0]) ||
01225       (sp->goahead && t.tv_sec > sp->ats[sp->timecnt - 1])) {
01226          struct timeval newt = t;
01227          time_t      seconds;
01228          time_t      tcycles;
01229          int_fast64_t   icycles;
01230 
01231          if (t.tv_sec < sp->ats[0])
01232             seconds = sp->ats[0] - t.tv_sec;
01233          else  seconds = t.tv_sec - sp->ats[sp->timecnt - 1];
01234          --seconds;
01235          tcycles = seconds / YEARSPERREPEAT / AVGSECSPERYEAR;
01236          ++tcycles;
01237          icycles = tcycles;
01238          if (tcycles - icycles >= 1 || icycles - tcycles >= 1)
01239             return NULL;
01240          seconds = icycles;
01241          seconds *= YEARSPERREPEAT;
01242          seconds *= AVGSECSPERYEAR;
01243          if (t.tv_sec < sp->ats[0])
01244             newt.tv_sec += seconds;
01245          else  newt.tv_sec -= seconds;
01246          if (newt.tv_sec < sp->ats[0] ||
01247             newt.tv_sec > sp->ats[sp->timecnt - 1])
01248                return NULL;   /* "cannot happen" */
01249          result = localsub(&newt, offset, tmp, sp);
01250          if (result == tmp) {
01251             time_t   newy;
01252 
01253             newy = tmp->tm_year;
01254             if (t.tv_sec < sp->ats[0])
01255                newy -= icycles * YEARSPERREPEAT;
01256             else
01257                newy += icycles * YEARSPERREPEAT;
01258             tmp->tm_year = newy;
01259             if (tmp->tm_year != newy)
01260                return NULL;
01261          }
01262          return result;
01263    }
01264    if (sp->timecnt == 0 || t.tv_sec < sp->ats[0]) {
01265       i = 0;
01266       while (sp->ttis[i].tt_isdst) {
01267          if (++i >= sp->typecnt) {
01268             i = 0;
01269             break;
01270          }
01271       }
01272    } else {
01273       int   lo = 1;
01274       int   hi = sp->timecnt;
01275 
01276       while (lo < hi) {
01277          int   mid = (lo + hi) >> 1;
01278 
01279          if (t.tv_sec < sp->ats[mid])
01280             hi = mid;
01281          else
01282             lo = mid + 1;
01283       }
01284       i = (int) sp->types[lo - 1];
01285    }
01286    ttisp = &sp->ttis[i];
01287    /*
01288    ** To get (wrong) behavior that's compatible with System V Release 2.0
01289    ** you'd replace the statement below with
01290    ** t += ttisp->tt_gmtoff;
01291    ** timesub(&t, 0L, sp, tmp);
01292    */
01293    result = timesub(&t, ttisp->tt_gmtoff, sp, tmp);
01294    tmp->tm_isdst = ttisp->tt_isdst;
01295 #ifndef SOLARIS /* Solaris doesn't have this element */
01296    tmp->tm_gmtoff = ttisp->tt_gmtoff;
01297 #endif
01298 #ifdef TM_ZONE
01299    tmp->TM_ZONE = &sp->chars[ttisp->tt_abbrind];
01300 #endif /* defined TM_ZONE */
01301    tmp->tm_usec = timep->tv_usec;
01302    return result;
01303 }

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

Definition at line 1623 of file localtime.c.

Referenced by long_normalize_overflow(), and time2sub().

01624 {
01625    long  number0;
01626 
01627    number0 = *number;
01628    *number += delta;
01629    return (*number < number0) != (delta < 0);
01630 }

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

Definition at line 1643 of file localtime.c.

References long_increment_overflow().

Referenced by time2sub().

01644 {
01645    int   tensdelta;
01646 
01647    tensdelta = (*unitsptr >= 0) ?
01648       (*unitsptr / base) :
01649       (-1 - (-1 - *unitsptr) / base);
01650    *unitsptr -= tensdelta * base;
01651    return long_increment_overflow(tensptr, tensdelta);
01652 }

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

Definition at line 1632 of file localtime.c.

References increment_overflow().

Referenced by time2sub().

01633 {
01634    int   tensdelta;
01635 
01636    tensdelta = (*unitsptr >= 0) ?
01637       (*unitsptr / base) :
01638       (-1 - (-1 - *unitsptr) / base);
01639    *unitsptr -= tensdelta * base;
01640    return increment_overflow(tensptr, tensdelta);
01641 }

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, read]
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, read]
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, read]
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, read]
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, read]
static struct ast_tm* gmtsub P ( (const struct timeval *timep, long offset, struct ast_tm *tmp)   )  [static, read]
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 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, read]

Definition at line 1855 of file localtime.c.

References FALSE, time2(), state::timecnt, TRUE, ttinfo::tt_gmtoff, ttinfo::tt_isdst, state::ttis, state::typecnt, and state::types.

Referenced by ast_mktime().

01856 {
01857    struct timeval       t;
01858    int         samei, otheri;
01859    int         sameind, otherind;
01860    int         i;
01861    int         nseen;
01862    int            seen[TZ_MAX_TYPES];
01863    int            types[TZ_MAX_TYPES];
01864    int            okay;
01865 
01866    if (tmp->tm_isdst > 1)
01867       tmp->tm_isdst = 1;
01868    t = time2(tmp, funcp, offset, &okay, sp);
01869 #ifdef PCTS
01870    /*
01871    ** PCTS code courtesy Grant Sullivan.
01872    */
01873    if (okay)
01874       return t;
01875    if (tmp->tm_isdst < 0)
01876       tmp->tm_isdst = 0;   /* reset to std and try again */
01877 #endif /* defined PCTS */
01878 #ifndef PCTS
01879    if (okay || tmp->tm_isdst < 0)
01880       return t;
01881 #endif /* !defined PCTS */
01882    /*
01883    ** We're supposed to assume that somebody took a time of one type
01884    ** and did some math on it that yielded a "struct ast_tm" that's bad.
01885    ** We try to divine the type they started from and adjust to the
01886    ** type they need.
01887    */
01888    if (sp == NULL)
01889       return WRONG;
01890    for (i = 0; i < sp->typecnt; ++i)
01891       seen[i] = FALSE;
01892    nseen = 0;
01893    for (i = sp->timecnt - 1; i >= 0; --i)
01894       if (!seen[sp->types[i]]) {
01895          seen[sp->types[i]] = TRUE;
01896          types[nseen++] = sp->types[i];
01897       }
01898    for (sameind = 0; sameind < nseen; ++sameind) {
01899       samei = types[sameind];
01900       if (sp->ttis[samei].tt_isdst != tmp->tm_isdst)
01901          continue;
01902       for (otherind = 0; otherind < nseen; ++otherind) {
01903          otheri = types[otherind];
01904          if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst)
01905             continue;
01906          tmp->tm_sec += sp->ttis[otheri].tt_gmtoff -
01907                sp->ttis[samei].tt_gmtoff;
01908          tmp->tm_isdst = !tmp->tm_isdst;
01909          t = time2(tmp, funcp, offset, &okay, sp);
01910          if (okay)
01911             return t;
01912          tmp->tm_sec -= sp->ttis[otheri].tt_gmtoff -
01913                sp->ttis[samei].tt_gmtoff;
01914          tmp->tm_isdst = !tmp->tm_isdst;
01915       }
01916    }
01917    return WRONG;
01918 }

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, read]

Note:
First try without normalization of seconds (in case tm_sec contains a value associated with a leap second). If that fails, try with normalization of seconds.

Definition at line 1842 of file localtime.c.

References FALSE, time2sub(), and TRUE.

Referenced by time1().

01843 {
01844    struct timeval t;
01845 
01846    /*! \note
01847    ** First try without normalization of seconds
01848    ** (in case tm_sec contains a value associated with a leap second).
01849    ** If that fails, try with normalization of seconds.
01850    */
01851    t = time2sub(tmp, funcp, offset, okayp, FALSE, sp);
01852    return *okayp ? t : time2sub(tmp, funcp, offset, okayp, TRUE, sp);
01853 }

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, read]

Definition at line 1668 of file localtime.c.

References DAYSPERLYEAR, dir, EPOCH_YEAR, FALSE, HOURSPERDAY, increment_overflow(), isleap, long_increment_overflow(), long_normalize_overflow(), MINSPERHOUR, mon_lengths, MONSPERYEAR, normalize_overflow(), 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_year, TM_YEAR_BASE, tmcomp(), TRUE, ttinfo::tt_gmtoff, ttinfo::tt_isdst, state::ttis, state::typecnt, and year_lengths.

Referenced by time2().

01669 {
01670    int         dir;
01671    int         i, j;
01672    int         saved_seconds;
01673    long        li;
01674    time_t         lo;
01675    time_t         hi;
01676    long           y;
01677    struct timeval       newt = { 0, 0 };
01678    struct timeval       t = { 0, 0 };
01679    struct ast_tm        yourtm, mytm;
01680 
01681    *okayp = FALSE;
01682    yourtm = *tmp;
01683    if (do_norm_secs) {
01684       if (normalize_overflow(&yourtm.tm_min, &yourtm.tm_sec,
01685          SECSPERMIN))
01686             return WRONG;
01687    }
01688    if (normalize_overflow(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR))
01689       return WRONG;
01690    if (normalize_overflow(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY))
01691       return WRONG;
01692    y = yourtm.tm_year;
01693    if (long_normalize_overflow(&y, &yourtm.tm_mon, MONSPERYEAR))
01694       return WRONG;
01695    /*
01696    ** Turn y into an actual year number for now.
01697    ** It is converted back to an offset from TM_YEAR_BASE later.
01698    */
01699    if (long_increment_overflow(&y, TM_YEAR_BASE))
01700       return WRONG;
01701    while (yourtm.tm_mday <= 0) {
01702       if (long_increment_overflow(&y, -1))
01703          return WRONG;
01704       li = y + (1 < yourtm.tm_mon);
01705       yourtm.tm_mday += year_lengths[isleap(li)];
01706    }
01707    while (yourtm.tm_mday > DAYSPERLYEAR) {
01708       li = y + (1 < yourtm.tm_mon);
01709       yourtm.tm_mday -= year_lengths[isleap(li)];
01710       if (long_increment_overflow(&y, 1))
01711          return WRONG;
01712    }
01713    for ( ; ; ) {
01714       i = mon_lengths[isleap(y)][yourtm.tm_mon];
01715       if (yourtm.tm_mday <= i)
01716          break;
01717       yourtm.tm_mday -= i;
01718       if (++yourtm.tm_mon >= MONSPERYEAR) {
01719          yourtm.tm_mon = 0;
01720          if (long_increment_overflow(&y, 1))
01721             return WRONG;
01722       }
01723    }
01724    if (long_increment_overflow(&y, -TM_YEAR_BASE))
01725       return WRONG;
01726    yourtm.tm_year = y;
01727    if (yourtm.tm_year != y)
01728       return WRONG;
01729    if (yourtm.tm_sec >= 0 && yourtm.tm_sec < SECSPERMIN)
01730       saved_seconds = 0;
01731    else if (y + TM_YEAR_BASE < EPOCH_YEAR) {
01732       /*
01733       ** We can't set tm_sec to 0, because that might push the
01734       ** time below the minimum representable time.
01735       ** Set tm_sec to 59 instead.
01736       ** This assumes that the minimum representable time is
01737       ** not in the same minute that a leap second was deleted from,
01738       ** which is a safer assumption than using 58 would be.
01739       */
01740       if (increment_overflow(&yourtm.tm_sec, 1 - SECSPERMIN))
01741          return WRONG;
01742       saved_seconds = yourtm.tm_sec;
01743       yourtm.tm_sec = SECSPERMIN - 1;
01744    } else {
01745       saved_seconds = yourtm.tm_sec;
01746       yourtm.tm_sec = 0;
01747    }
01748    /*
01749    ** Do a binary search (this works whatever time_t's type is).
01750    */
01751    if (!TYPE_SIGNED(time_t)) {
01752       lo = 0;
01753       hi = lo - 1;
01754    } else if (!TYPE_INTEGRAL(time_t)) {
01755       if (sizeof(time_t) > sizeof(float))
01756          hi = (time_t) DBL_MAX;
01757       else  hi = (time_t) FLT_MAX;
01758       lo = -hi;
01759    } else {
01760       lo = 1;
01761       for (i = 0; i < (int) TYPE_BIT(time_t) - 1; ++i)
01762          lo *= 2;
01763       hi = -(lo + 1);
01764    }
01765    for ( ; ; ) {
01766       t.tv_sec = lo / 2 + hi / 2;
01767       if (t.tv_sec < lo)
01768          t.tv_sec = lo;
01769       else if (t.tv_sec > hi)
01770          t.tv_sec = hi;
01771       if ((*funcp)(&t, offset, &mytm, sp) == NULL) {
01772          /*
01773          ** Assume that t is too extreme to be represented in
01774          ** a struct ast_tm; arrange things so that it is less
01775          ** extreme on the next pass.
01776          */
01777          dir = (t.tv_sec > 0) ? 1 : -1;
01778       } else   dir = tmcomp(&mytm, &yourtm);
01779       if (dir != 0) {
01780          if (t.tv_sec == lo) {
01781             ++t.tv_sec;
01782             if (t.tv_sec <= lo)
01783                return WRONG;
01784             ++lo;
01785          } else if (t.tv_sec == hi) {
01786             --t.tv_sec;
01787             if (t.tv_sec >= hi)
01788                return WRONG;
01789             --hi;
01790          }
01791          if (lo > hi)
01792             return WRONG;
01793          if (dir > 0)
01794             hi = t.tv_sec;
01795          else  lo = t.tv_sec;
01796          continue;
01797       }
01798       if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst)
01799          break;
01800       /*
01801       ** Right time, wrong type.
01802       ** Hunt for right time, right type.
01803       ** It's okay to guess wrong since the guess
01804       ** gets checked.
01805       */
01806       /*
01807       ** The (void *) casts are the benefit of SunOS 3.3 on Sun 2's.
01808       */
01809       for (i = sp->typecnt - 1; i >= 0; --i) {
01810          if (sp->ttis[i].tt_isdst != yourtm.tm_isdst)
01811             continue;
01812          for (j = sp->typecnt - 1; j >= 0; --j) {
01813             if (sp->ttis[j].tt_isdst == yourtm.tm_isdst)
01814                continue;
01815             newt.tv_sec = t.tv_sec + sp->ttis[j].tt_gmtoff -
01816                sp->ttis[i].tt_gmtoff;
01817             if ((*funcp)(&newt, offset, &mytm, sp) == NULL)
01818                continue;
01819             if (tmcomp(&mytm, &yourtm) != 0)
01820                continue;
01821             if (mytm.tm_isdst != yourtm.tm_isdst)
01822                continue;
01823             /*
01824             ** We have a match.
01825             */
01826             t = newt;
01827             goto label;
01828          }
01829       }
01830       return WRONG;
01831    }
01832 label:
01833    newt.tv_sec = t.tv_sec + saved_seconds;
01834    if ((newt.tv_sec < t.tv_sec) != (saved_seconds < 0))
01835       return WRONG;
01836    t.tv_sec = newt.tv_sec;
01837    if ((*funcp)(&t, offset, tmp, sp))
01838       *okayp = TRUE;
01839    return t;
01840 }

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

Definition at line 1476 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().

01477 {
01478    const struct lsinfo *   lp;
01479    time_t         tdays;
01480    int         idays;   /* unsigned would be so 2003 */
01481    long        rem;
01482    int            y;
01483    const int *    ip;
01484    long        corr;
01485    int         hit;
01486    int         i;
01487    long  seconds;
01488 
01489 
01490    corr = 0;
01491    hit = 0;
01492    i = (sp == NULL) ? 0 : sp->leapcnt;
01493    while (--i >= 0) {
01494       lp = &sp->lsis[i];
01495       if (timep->tv_sec >= lp->ls_trans) {
01496          if (timep->tv_sec == lp->ls_trans) {
01497             hit = ((i == 0 && lp->ls_corr > 0) ||
01498                lp->ls_corr > sp->lsis[i - 1].ls_corr);
01499             if (hit)
01500                while (i > 0 &&
01501                   sp->lsis[i].ls_trans ==
01502                   sp->lsis[i - 1].ls_trans + 1 &&
01503                   sp->lsis[i].ls_corr ==
01504                   sp->lsis[i - 1].ls_corr + 1) {
01505                      ++hit;
01506                      --i;
01507                }
01508          }
01509          corr = lp->ls_corr;
01510          break;
01511       }
01512    }
01513    y = EPOCH_YEAR;
01514    tdays = timep->tv_sec / SECSPERDAY;
01515    rem = timep->tv_sec - tdays * SECSPERDAY;
01516    while (tdays < 0 || tdays >= year_lengths[isleap(y)]) {
01517       int      newy;
01518       time_t   tdelta;
01519       int   idelta;
01520       int   leapdays;
01521 
01522       tdelta = tdays / DAYSPERLYEAR;
01523       idelta = tdelta;
01524       if (tdelta - idelta >= 1 || idelta - tdelta >= 1)
01525          return NULL;
01526       if (idelta == 0)
01527          idelta = (tdays < 0) ? -1 : 1;
01528       newy = y;
01529       if (increment_overflow(&newy, idelta))
01530          return NULL;
01531       leapdays = leaps_thru_end_of(newy - 1) -
01532          leaps_thru_end_of(y - 1);
01533       tdays -= ((time_t) newy - y) * DAYSPERNYEAR;
01534       tdays -= leapdays;
01535       y = newy;
01536    }
01537 
01538    seconds = tdays * SECSPERDAY + 0.5;
01539    tdays = seconds / SECSPERDAY;
01540    rem += seconds - tdays * SECSPERDAY;
01541 
01542    /*
01543    ** Given the range, we can now fearlessly cast...
01544    */
01545    idays = tdays;
01546    rem += offset - corr;
01547    while (rem < 0) {
01548       rem += SECSPERDAY;
01549       --idays;
01550    }
01551    while (rem >= SECSPERDAY) {
01552       rem -= SECSPERDAY;
01553       ++idays;
01554    }
01555    while (idays < 0) {
01556       if (increment_overflow(&y, -1))
01557          return NULL;
01558       idays += year_lengths[isleap(y)];
01559    }
01560    while (idays >= year_lengths[isleap(y)]) {
01561       idays -= year_lengths[isleap(y)];
01562       if (increment_overflow(&y, 1))
01563          return NULL;
01564    }
01565    tmp->tm_year = y;
01566    if (increment_overflow(&tmp->tm_year, -TM_YEAR_BASE))
01567       return NULL;
01568    tmp->tm_yday = idays;
01569    /*
01570    ** The "extra" mods below avoid overflow problems.
01571    */
01572    tmp->tm_wday = EPOCH_WDAY +
01573       ((y - EPOCH_YEAR) % DAYSPERWEEK) *
01574       (DAYSPERNYEAR % DAYSPERWEEK) +
01575       leaps_thru_end_of(y - 1) -
01576       leaps_thru_end_of(EPOCH_YEAR - 1) +
01577       idays;
01578    tmp->tm_wday %= DAYSPERWEEK;
01579    if (tmp->tm_wday < 0)
01580       tmp->tm_wday += DAYSPERWEEK;
01581    tmp->tm_hour = (int) (rem / SECSPERHOUR);
01582    rem %= SECSPERHOUR;
01583    tmp->tm_min = (int) (rem / SECSPERMIN);
01584    /*
01585    ** A positive leap second requires a special
01586    ** representation. This uses "... ??:59:60" et seq.
01587    */
01588    tmp->tm_sec = (int) (rem % SECSPERMIN) + hit;
01589    ip = mon_lengths[isleap(y)];
01590    for (tmp->tm_mon = 0; idays >= ip[tmp->tm_mon]; ++(tmp->tm_mon))
01591       idays -= ip[tmp->tm_mon];
01592    tmp->tm_mday = (int) (idays + 1);
01593    tmp->tm_isdst = 0;
01594 #ifdef TM_GMTOFF
01595    tmp->TM_GMTOFF = offset;
01596 #endif /* defined TM_GMTOFF */
01597    tmp->tm_usec = timep->tv_usec;
01598    return tmp;
01599 }

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

Definition at line 1654 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.

Referenced by time2sub().

01655 {
01656    int   result;
01657 
01658    if ((result = (atmp->tm_year - btmp->tm_year)) == 0 &&
01659       (result = (atmp->tm_mon - btmp->tm_mon)) == 0 &&
01660       (result = (atmp->tm_mday - btmp->tm_mday)) == 0 &&
01661       (result = (atmp->tm_hour - btmp->tm_hour)) == 0 &&
01662       (result = (atmp->tm_min - btmp->tm_min)) == 0 &&
01663       (result = (atmp->tm_sec - btmp->tm_sec)) == 0)
01664          result = atmp->tm_usec - btmp->tm_usec;
01665    return result;
01666 }

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 846 of file localtime.c.

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

Referenced by tzparse().

00847 {
00848    int   leapyear;
00849    time_t   value;
00850    int   i;
00851    int      d, m1, yy0, yy1, yy2, dow;
00852 
00853    INITIALIZE(value);
00854    leapyear = isleap(year);
00855    switch (rulep->r_type) {
00856 
00857    case JULIAN_DAY:
00858       /*
00859       ** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap
00860       ** years.
00861       ** In non-leap years, or if the day number is 59 or less, just
00862       ** add SECSPERDAY times the day number-1 to the time of
00863       ** January 1, midnight, to get the day.
00864       */
00865       value = janfirst + (rulep->r_day - 1) * SECSPERDAY;
00866       if (leapyear && rulep->r_day >= 60)
00867          value += SECSPERDAY;
00868       break;
00869 
00870    case DAY_OF_YEAR:
00871       /*
00872       ** n - day of year.
00873       ** Just add SECSPERDAY times the day number to the time of
00874       ** January 1, midnight, to get the day.
00875       */
00876       value = janfirst + rulep->r_day * SECSPERDAY;
00877       break;
00878 
00879    case MONTH_NTH_DAY_OF_WEEK:
00880       /*
00881       ** Mm.n.d - nth "dth day" of month m.
00882       */
00883       value = janfirst;
00884       for (i = 0; i < rulep->r_mon - 1; ++i)
00885          value += mon_lengths[leapyear][i] * SECSPERDAY;
00886 
00887       /*
00888       ** Use Zeller's Congruence to get day-of-week of first day of
00889       ** month.
00890       */
00891       m1 = (rulep->r_mon + 9) % 12 + 1;
00892       yy0 = (rulep->r_mon <= 2) ? (year - 1) : year;
00893       yy1 = yy0 / 100;
00894       yy2 = yy0 % 100;
00895       dow = ((26 * m1 - 2) / 10 +
00896          1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7;
00897       if (dow < 0)
00898          dow += DAYSPERWEEK;
00899 
00900       /*
00901       ** "dow" is the day-of-week of the first day of the month. Get
00902       ** the day-of-month (zero-origin) of the first "dow" day of the
00903       ** month.
00904       */
00905       d = rulep->r_day - dow;
00906       if (d < 0)
00907          d += DAYSPERWEEK;
00908       for (i = 1; i < rulep->r_week; ++i) {
00909          if (d + DAYSPERWEEK >=
00910             mon_lengths[leapyear][rulep->r_mon - 1])
00911                break;
00912          d += DAYSPERWEEK;
00913       }
00914 
00915       /*
00916       ** "d" is the day-of-month (zero-origin) of the day we want.
00917       */
00918       value += d * SECSPERDAY;
00919       break;
00920    }
00921 
00922    /*
00923    ** "value" is the Epoch-relative time of 00:00:00 UTC on the day in
00924    ** question. To get the Epoch-relative time of the specified local
00925    ** time on that day, add the transition time and the current offset
00926    ** from UTC.
00927    */
00928    return value + rulep->r_time + offset;
00929 }

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

Definition at line 423 of file localtime.c.

References add_notify(), state::ats, buf, state::charcnt, state::chars, detzcode(), detzcode64(), differ_by_repeat(), FALSE, state::goahead, state::goback, state::leapcnt, lsinfo::ls_corr, lsinfo::ls_trans, state::lsis, OPEN_MODE, state::timecnt, TRUE, ttinfo::tt_abbrind, ttinfo::tt_gmtoff, ttinfo::tt_isdst, ttinfo::tt_ttisgmt, ttinfo::tt_ttisstd, state::ttis, state::typecnt, state::types, and tzparse().

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

00424 {
00425    const char *      p;
00426    int         i;
00427    int         fid;
00428    int         stored;
00429    int         nread;
00430    union {
00431       struct tzhead  tzhead;
00432       char     buf[2 * sizeof(struct tzhead) +
00433                2 * sizeof *sp +
00434                4 * TZ_MAX_TIMES];
00435    } u;
00436 
00437    if (name == NULL && (name = TZDEFAULT) == NULL)
00438       return -1;
00439    {
00440       int   doaccess;
00441       /*
00442       ** Section 4.9.1 of the C standard says that
00443       ** "FILENAME_MAX expands to an integral constant expression
00444       ** that is the size needed for an array of char large enough
00445       ** to hold the longest file name string that the implementation
00446       ** guarantees can be opened."
00447       */
00448       char     fullname[FILENAME_MAX + 1];
00449 
00450       if (name[0] == ':')
00451          ++name;
00452       doaccess = name[0] == '/';
00453       if (!doaccess) {
00454          if ((p = TZDIR) == NULL)
00455             return -1;
00456          if ((strlen(p) + strlen(name) + 1) >= sizeof fullname)
00457             return -1;
00458          (void) strcpy(fullname, p);
00459          (void) strcat(fullname, "/");
00460          (void) strcat(fullname, name);
00461          /*
00462          ** Set doaccess if '.' (as in "../") shows up in name.
00463          */
00464          if (strchr(name, '.') != NULL)
00465             doaccess = TRUE;
00466          name = fullname;
00467       }
00468       if (doaccess && access(name, R_OK) != 0)
00469          return -1;
00470       if ((fid = open(name, OPEN_MODE)) == -1)
00471          return -1;
00472       add_notify(sp, name);
00473    }
00474    nread = read(fid, u.buf, sizeof u.buf);
00475    if (close(fid) < 0 || nread <= 0)
00476       return -1;
00477    for (stored = 4; stored <= 8; stored *= 2) {
00478       int      ttisstdcnt;
00479       int      ttisgmtcnt;
00480 
00481       ttisstdcnt = (int) detzcode(u.tzhead.tzh_ttisstdcnt);
00482       ttisgmtcnt = (int) detzcode(u.tzhead.tzh_ttisgmtcnt);
00483       sp->leapcnt = (int) detzcode(u.tzhead.tzh_leapcnt);
00484       sp->timecnt = (int) detzcode(u.tzhead.tzh_timecnt);
00485       sp->typecnt = (int) detzcode(u.tzhead.tzh_typecnt);
00486       sp->charcnt = (int) detzcode(u.tzhead.tzh_charcnt);
00487       p = u.tzhead.tzh_charcnt + sizeof u.tzhead.tzh_charcnt;
00488       if (sp->leapcnt < 0 || sp->leapcnt > TZ_MAX_LEAPS ||
00489          sp->typecnt <= 0 || sp->typecnt > TZ_MAX_TYPES ||
00490          sp->timecnt < 0 || sp->timecnt > TZ_MAX_TIMES ||
00491          sp->charcnt < 0 || sp->charcnt > TZ_MAX_CHARS ||
00492          (ttisstdcnt != sp->typecnt && ttisstdcnt != 0) ||
00493          (ttisgmtcnt != sp->typecnt && ttisgmtcnt != 0))
00494             return -1;
00495       if (nread - (p - u.buf) <
00496          sp->timecnt * stored +     /* ats */
00497          sp->timecnt +        /* types */
00498          sp->typecnt * 6 +    /* ttinfos */
00499          sp->charcnt +        /* chars */
00500          sp->leapcnt * (stored + 4) +  /* lsinfos */
00501          ttisstdcnt +         /* ttisstds */
00502          ttisgmtcnt)       /* ttisgmts */
00503             return -1;
00504       for (i = 0; i < sp->timecnt; ++i) {
00505          sp->ats[i] = (stored == 4) ?
00506             detzcode(p) : detzcode64(p);
00507          p += stored;
00508       }
00509       for (i = 0; i < sp->timecnt; ++i) {
00510          sp->types[i] = (unsigned char) *p++;
00511          if (sp->types[i] >= sp->typecnt)
00512             return -1;
00513       }
00514       for (i = 0; i < sp->typecnt; ++i) {
00515          struct ttinfo *   ttisp;
00516 
00517          ttisp = &sp->ttis[i];
00518          ttisp->tt_gmtoff = detzcode(p);
00519          p += 4;
00520          ttisp->tt_isdst = (unsigned char) *p++;
00521          if (ttisp->tt_isdst != 0 && ttisp->tt_isdst != 1)
00522             return -1;
00523          ttisp->tt_abbrind = (unsigned char) *p++;
00524          if (ttisp->tt_abbrind < 0 ||
00525             ttisp->tt_abbrind > sp->charcnt)
00526                return -1;
00527       }
00528       for (i = 0; i < sp->charcnt; ++i)
00529          sp->chars[i] = *p++;
00530       sp->chars[i] = '\0'; /* ensure '\0' at end */
00531       for (i = 0; i < sp->leapcnt; ++i) {
00532          struct lsinfo *   lsisp;
00533 
00534          lsisp = &sp->lsis[i];
00535          lsisp->ls_trans = (stored == 4) ?
00536             detzcode(p) : detzcode64(p);
00537          p += stored;
00538          lsisp->ls_corr = detzcode(p);
00539          p += 4;
00540       }
00541       for (i = 0; i < sp->typecnt; ++i) {
00542          struct ttinfo *   ttisp;
00543 
00544          ttisp = &sp->ttis[i];
00545          if (ttisstdcnt == 0)
00546             ttisp->tt_ttisstd = FALSE;
00547          else {
00548             ttisp->tt_ttisstd = *p++;
00549             if (ttisp->tt_ttisstd != TRUE &&
00550                ttisp->tt_ttisstd != FALSE)
00551                   return -1;
00552          }
00553       }
00554       for (i = 0; i < sp->typecnt; ++i) {
00555          struct ttinfo *   ttisp;
00556 
00557          ttisp = &sp->ttis[i];
00558          if (ttisgmtcnt == 0)
00559             ttisp->tt_ttisgmt = FALSE;
00560          else {
00561             ttisp->tt_ttisgmt = *p++;
00562             if (ttisp->tt_ttisgmt != TRUE &&
00563                ttisp->tt_ttisgmt != FALSE)
00564                   return -1;
00565          }
00566       }
00567       /*
00568       ** Out-of-sort ats should mean we're running on a
00569       ** signed time_t system but using a data file with
00570       ** unsigned values (or vice versa).
00571       */
00572       for (i = 0; i < sp->timecnt - 2; ++i)
00573          if (sp->ats[i] > sp->ats[i + 1]) {
00574             ++i;
00575             if (TYPE_SIGNED(time_t)) {
00576                /*
00577                ** Ignore the end (easy).
00578                */
00579                sp->timecnt = i;
00580             } else {
00581                /*
00582                ** Ignore the beginning (harder).
00583                */
00584                int   j;
00585 
00586                for (j = 0; j + i < sp->timecnt; ++j) {
00587                   sp->ats[j] = sp->ats[j + i];
00588                   sp->types[j] = sp->types[j + i];
00589                }
00590                sp->timecnt = j;
00591             }
00592             break;
00593          }
00594       /*
00595       ** If this is an old file, we're done.
00596       */
00597       if (u.tzhead.tzh_version[0] == '\0')
00598          break;
00599       nread -= p - u.buf;
00600       for (i = 0; i < nread; ++i)
00601          u.buf[i] = p[i];
00602       /*
00603       ** If this is a narrow integer time_t system, we're done.
00604       */
00605       if (stored >= (int) sizeof(time_t) && TYPE_INTEGRAL(time_t))
00606          break;
00607    }
00608    if (doextend && nread > 2 &&
00609       u.buf[0] == '\n' && u.buf[nread - 1] == '\n' &&
00610       sp->typecnt + 2 <= TZ_MAX_TYPES) {
00611          struct state   ts;
00612          int   result;
00613 
00614          u.buf[nread - 1] = '\0';
00615          result = tzparse(&u.buf[1], &ts, FALSE);
00616          if (result == 0 && ts.typecnt == 2 &&
00617             sp->charcnt + ts.charcnt <= TZ_MAX_CHARS) {
00618                for (i = 0; i < 2; ++i)
00619                   ts.ttis[i].tt_abbrind +=
00620                      sp->charcnt;
00621                for (i = 0; i < ts.charcnt; ++i)
00622                   sp->chars[sp->charcnt++] =
00623                      ts.chars[i];
00624                i = 0;
00625                while (i < ts.timecnt &&
00626                   ts.ats[i] <=
00627                   sp->ats[sp->timecnt - 1])
00628                      ++i;
00629                while (i < ts.timecnt &&
00630                    sp->timecnt < TZ_MAX_TIMES) {
00631                   sp->ats[sp->timecnt] =
00632                      ts.ats[i];
00633                   sp->types[sp->timecnt] =
00634                      sp->typecnt +
00635                      ts.types[i];
00636                   ++sp->timecnt;
00637                   ++i;
00638                }
00639                sp->ttis[sp->typecnt++] = ts.ttis[0];
00640                sp->ttis[sp->typecnt++] = ts.ttis[1];
00641          }
00642    }
00643    i = 2 * YEARSPERREPEAT;
00644    sp->goback = sp->goahead = sp->timecnt > i;
00645    sp->goback = sp->goback && sp->types[i] == sp->types[0] &&
00646       differ_by_repeat(sp->ats[i], sp->ats[0]);
00647    sp->goahead = sp->goahead &&
00648       sp->types[sp->timecnt - 1] == sp->types[sp->timecnt - 1 - i] &&
00649       differ_by_repeat(sp->ats[sp->timecnt - 1],
00650           sp->ats[sp->timecnt - 1 - i]);
00651    return 0;
00652 }

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 936 of file localtime.c.

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

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

00937 {
00938    const char *         stdname;
00939    const char *         dstname;
00940    size_t            stdlen;
00941    size_t            dstlen;
00942    long           stdoffset;
00943    long           dstoffset;
00944    time_t *    atp;
00945    unsigned char *   typep;
00946    char *         cp;
00947    int         load_result;
00948 
00949    INITIALIZE(dstname);
00950    stdname = name;
00951    if (lastditch) {
00952       stdlen = strlen(name);  /* length of standard zone name */
00953       name += stdlen;
00954       if (stdlen >= sizeof sp->chars)
00955          stdlen = (sizeof sp->chars) - 1;
00956       stdoffset = 0;
00957    } else {
00958       if (*name == '<') {
00959          name++;
00960          stdname = name;
00961          name = getqzname(name, '>');
00962          if (*name != '>')
00963             return -1;
00964          stdlen = name - stdname;
00965          name++;
00966       } else {
00967          name = getzname(name);
00968          stdlen = name - stdname;
00969       }
00970       if (*name == '\0')
00971          return -1;
00972       name = getoffset(name, &stdoffset);
00973       if (name == NULL)
00974          return -1;
00975    }
00976    load_result = tzload(TZDEFRULES, sp, FALSE);
00977    if (load_result != 0)
00978       sp->leapcnt = 0;     /* so, we're off a little */
00979    if (*name != '\0') {
00980       if (*name == '<') {
00981          dstname = ++name;
00982          name = getqzname(name, '>');
00983          if (*name != '>')
00984             return -1;
00985          dstlen = name - dstname;
00986          name++;
00987       } else {
00988          dstname = name;
00989          name = getzname(name);
00990          dstlen = name - dstname; /* length of DST zone name */
00991       }
00992       if (*name != '\0' && *name != ',' && *name != ';') {
00993          name = getoffset(name, &dstoffset);
00994          if (name == NULL)
00995             return -1;
00996       } else   dstoffset = stdoffset - SECSPERHOUR;
00997       if (*name == '\0' && load_result != 0)
00998          name = TZDEFRULESTRING;
00999       if (*name == ',' || *name == ';') {
01000          struct rule start;
01001          struct rule end;
01002          int   year;
01003          time_t   janfirst;
01004          time_t      starttime;
01005          time_t      endtime;
01006 
01007          ++name;
01008          if ((name = getrule(name, &start)) == NULL)
01009             return -1;
01010          if (*name++ != ',')
01011             return -1;
01012          if ((name = getrule(name, &end)) == NULL)
01013             return -1;
01014          if (*name != '\0')
01015             return -1;
01016          sp->typecnt = 2;  /* standard time and DST */
01017          /*
01018          ** Two transitions per year, from EPOCH_YEAR forward.
01019          */
01020          sp->ttis[0].tt_gmtoff = -dstoffset;
01021          sp->ttis[0].tt_isdst = 1;
01022          sp->ttis[0].tt_abbrind = stdlen + 1;
01023          sp->ttis[1].tt_gmtoff = -stdoffset;
01024          sp->ttis[1].tt_isdst = 0;
01025          sp->ttis[1].tt_abbrind = 0;
01026          atp = sp->ats;
01027          typep = sp->types;
01028          janfirst = 0;
01029          sp->timecnt = 0;
01030          for (year = EPOCH_YEAR;
01031              sp->timecnt + 2 <= TZ_MAX_TIMES;
01032              ++year) {
01033                time_t   newfirst;
01034 
01035             starttime = transtime(janfirst, year, &start,
01036                stdoffset);
01037             endtime = transtime(janfirst, year, &end,
01038                dstoffset);
01039             if (starttime > endtime) {
01040                *atp++ = endtime;
01041                *typep++ = 1;  /* DST ends */
01042                *atp++ = starttime;
01043                *typep++ = 0;  /* DST begins */
01044             } else {
01045                *atp++ = starttime;
01046                *typep++ = 0;  /* DST begins */
01047                *atp++ = endtime;
01048                *typep++ = 1;  /* DST ends */
01049             }
01050             sp->timecnt += 2;
01051             newfirst = janfirst;
01052             newfirst += year_lengths[isleap(year)] *
01053                SECSPERDAY;
01054             if (newfirst <= janfirst)
01055                break;
01056             janfirst = newfirst;
01057          }
01058       } else {
01059          long  theirstdoffset;
01060          long  theirdstoffset;
01061          long  theiroffset;
01062          int   isdst;
01063          int   i;
01064          int   j;
01065 
01066          if (*name != '\0')
01067             return -1;
01068          /*
01069          ** Initial values of theirstdoffset and theirdstoffset.
01070          */
01071          theirstdoffset = 0;
01072          for (i = 0; i < sp->timecnt; ++i) {
01073             j = sp->types[i];
01074             if (!sp->ttis[j].tt_isdst) {
01075                theirstdoffset =
01076                   -sp->ttis[j].tt_gmtoff;
01077                break;
01078             }
01079          }
01080          theirdstoffset = 0;
01081          for (i = 0; i < sp->timecnt; ++i) {
01082             j = sp->types[i];
01083             if (sp->ttis[j].tt_isdst) {
01084                theirdstoffset =
01085                   -sp->ttis[j].tt_gmtoff;
01086                break;
01087             }
01088          }
01089          /*
01090          ** Initially we're assumed to be in standard time.
01091          */
01092          isdst = FALSE;
01093          theiroffset = theirstdoffset;
01094          /*
01095          ** Now juggle transition times and types
01096          ** tracking offsets as you do.
01097          */
01098          for (i = 0; i < sp->timecnt; ++i) {
01099             j = sp->types[i];
01100             sp->types[i] = sp->ttis[j].tt_isdst;
01101             if (sp->ttis[j].tt_ttisgmt) {
01102                /* No adjustment to transition time */
01103             } else {
01104                /*
01105                ** If summer time is in effect, and the
01106                ** transition time was not specified as
01107                ** standard time, add the summer time
01108                ** offset to the transition time;
01109                ** otherwise, add the standard time
01110                ** offset to the transition time.
01111                */
01112                /*
01113                ** Transitions from DST to DDST
01114                ** will effectively disappear since
01115                ** POSIX provides for only one DST
01116                ** offset.
01117                */
01118                if (isdst && !sp->ttis[j].tt_ttisstd) {
01119                   sp->ats[i] += dstoffset -
01120                      theirdstoffset;
01121                } else {
01122                   sp->ats[i] += stdoffset -
01123                      theirstdoffset;
01124                }
01125             }
01126             theiroffset = -sp->ttis[j].tt_gmtoff;
01127             if (sp->ttis[j].tt_isdst)
01128                theirdstoffset = theiroffset;
01129             else  theirstdoffset = theiroffset;
01130          }
01131          /*
01132          ** Finally, fill in ttis.
01133          ** ttisstd and ttisgmt need not be handled.
01134          */
01135          sp->ttis[0].tt_gmtoff = -stdoffset;
01136          sp->ttis[0].tt_isdst = FALSE;
01137          sp->ttis[0].tt_abbrind = 0;
01138          sp->ttis[1].tt_gmtoff = -dstoffset;
01139          sp->ttis[1].tt_isdst = TRUE;
01140          sp->ttis[1].tt_abbrind = stdlen + 1;
01141          sp->typecnt = 2;
01142       }
01143    } else {
01144       dstlen = 0;
01145       sp->typecnt = 1;     /* only standard time */
01146       sp->timecnt = 0;
01147       sp->ttis[0].tt_gmtoff = -stdoffset;
01148       sp->ttis[0].tt_isdst = 0;
01149       sp->ttis[0].tt_abbrind = 0;
01150    }
01151    sp->charcnt = stdlen + 1;
01152    if (dstlen != 0)
01153       sp->charcnt += dstlen + 1;
01154    if ((size_t) sp->charcnt > sizeof sp->chars)
01155       return -1;
01156    cp = sp->chars;
01157    (void) strncpy(cp, stdname, stdlen);
01158    cp += stdlen;
01159    *cp++ = '\0';
01160    if (dstlen != 0) {
01161       (void) strncpy(cp, dstname, dstlen);
01162       *(cp + dstlen) = '\0';
01163    }
01164    return 0;
01165 }


Variable Documentation

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

Definition at line 69 of file localtime.c.

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

Definition at line 97 of file localtime.c.

Definition at line 229 of file localtime.c.

Referenced by add_notify(), and inotify_daemon().

Definition at line 230 of file localtime.c.

Referenced by add_notify(), and inotify_daemon().

int inotify_fd = -1 [static]

Definition at line 232 of file localtime.c.

Referenced by add_notify(), and inotify_daemon().

pthread_t inotify_thread = AST_PTHREADT_NULL [static]

Definition at line 228 of file localtime.c.

Referenced by add_notify(), and inotify_daemon().

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 654 of file localtime.c.

Referenced by time2sub(), timesub(), and transtime().

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

Definition at line 98 of file localtime.c.

const int year_lengths[2] [static]
Initial value:

Definition at line 659 of file localtime.c.

Referenced by time2sub(), timesub(), and tzparse().


Generated by  doxygen 1.6.2