Fri Sep 25 19:28:38 2009

Asterisk developer's documentation


localtime.c File Reference

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <float.h>
#include "private.h"
#include "tzfile.h"
#include "asterisk.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

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"
#define WRONG   (-1)

Functions

static char __attribute__ ((unused))
 time type information
static AST_LIST_HEAD_STATIC (zonelist, state)
struct tm * ast_localtime (const time_t *timep, struct tm *tmp, const char *zone)
time_t ast_mktime (struct tm *tmp, const char *zone)
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 tm * gmtsub (const time_t *timep, const long offset, struct tm *tmp)
static int increment_overflow (int *number, int delta)
 Simplified normalize logic courtesy Paul Eggert.
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 tm * localsub (const time_t *timep, const long offset, struct 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 tm *atmp, const struct tm *btmp))
static struct tm *timesub P ((const time_t *timep, long offset, const struct state *sp, struct tm *tmp))
static time_t time2sub P ((struct tm *tmp, struct tm *(*funcp)(const time_t *, long, struct tm *, const struct state *sp), long offset, int *okayp, int do_norm_secs, const struct state *sp))
static time_t time2 P ((struct tm *tmp, struct tm *(*funcp) P((const time_t *, long, struct tm *, const struct state *sp)), long offset, int *okayp, const struct state *sp))
static time_t time1 P ((struct tm *tmp, struct tm *(*funcp) P((const time_t *, long, struct 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 tm *localsub P ((const time_t *timep, long offset, struct tm *tmp, const struct state *sp))
static struct tm *gmtsub P ((const time_t *timep, long offset, struct 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 time_t time1 (struct tm *tmp, struct tm *(*const funcp)(const time_t *, long, struct tm *, const struct state *), const long offset, const struct state *sp)
static time_t time2 (struct tm *tmp, struct tm *(*const funcp)(const time_t *, long, struct tm *, const struct state *sp), const long offset, int *okayp, const struct state *sp)
static time_t time2sub (struct tm *tmp, struct tm *(*const funcp)(const time_t *, long, struct tm *, const struct state *), const long offset, int *okayp, const int do_norm_secs, const struct state *sp)
static struct tm * timesub (const time_t *timep, const long offset, const struct state *sp, struct tm *tmp)
static int tmcomp (const struct tm *atmp, const struct 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 const int mon_lengths [2][MONSPERYEAR]
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 130 of file localtime.c.

#define DAY_OF_YEAR   1

Definition at line 169 of file localtime.c.

Referenced by getrule(), and transtime().

#define JULIAN_DAY   0

Definition at line 168 of file localtime.c.

Referenced by getrule(), and transtime().

#define MONTH_NTH_DAY_OF_WEEK   2

Definition at line 170 of file localtime.c.

Referenced by getrule(), and transtime().

#define MY_TZNAME_MAX   255

Definition at line 136 of file localtime.c.

#define OPEN_MODE   O_RDONLY

Referenced by tzload().

#define TZ_ABBR_CHAR_SET   "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 :+-._"

#define TZ_ABBR_ERR_CHAR   '_'

#define TZ_ABBR_MAX_LEN   16

#define TZ_STRLEN_MAX   255

Definition at line 139 of file localtime.c.

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

Referenced by tzparse().

#define WRONG   (-1)

Referenced by gmtload(), time1(), time2sub(), tzload(), and tzparse().


Function Documentation

static char __attribute__ ( (unused)   )  [static]

time type information

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

00080                                                                    :+-._"
00081 #endif /* !defined TZ_ABBR_CHAR_SET */
00082 
00083 #ifndef TZ_ABBR_ERR_CHAR
00084 #define TZ_ABBR_ERR_CHAR   '_'
00085 #endif /* !defined TZ_ABBR_ERR_CHAR */
00086 
00087 /*
00088 ** SunOS 4.1.1 headers lack O_BINARY.
00089 */
00090 
00091 #ifdef O_BINARY
00092 #define OPEN_MODE (O_RDONLY | O_BINARY)
00093 #endif /* defined O_BINARY */
00094 #ifndef O_BINARY
00095 #define OPEN_MODE O_RDONLY
00096 #endif /* !defined O_BINARY */
00097 
00098 static const char gmt[] = "GMT";
00099 
00100 /*! \note
00101  * The DST rules to use if TZ has no rules and we can't load TZDEFRULES.
00102  * We default to US rules as of 1999-08-17.
00103  * POSIX 1003.1 section 8.1.1 says that the default DST rules are
00104  * implementation dependent; for historical reasons, US rules are a
00105  * common default.
00106  */
00107 #ifndef TZDEFRULESTRING
00108 #define TZDEFRULESTRING ",M4.1.0,M10.5.0"
00109 #endif /* !defined TZDEFDST */
00110 
00111 #ifndef WRONG
00112 #define WRONG  (-1)
00113 #endif /* !defined WRONG */
00114 
00115 /*!< \brief time type information */
00116 struct ttinfo {            /* time type information */
00117    long     tt_gmtoff;  /* UTC offset in seconds */
00118    int      tt_isdst;   /* used to set tm_isdst */
00119    int      tt_abbrind; /* abbreviation list index */
00120    int      tt_ttisstd; /* TRUE if transition is std time */
00121    int      tt_ttisgmt; /* TRUE if transition is UTC */
00122 };

static AST_LIST_HEAD_STATIC ( zonelist  ,
state   
) [static]

struct tm* ast_localtime ( const time_t *  timep,
struct tm *  tmp,
const char *  zone 
) [read]

Definition at line 1143 of file localtime.c.

References ast_tzset(), and localsub().

Referenced by acf_strftime(), 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_ge(), ast_say_date_gr(), ast_say_date_nl(), ast_say_date_pt(), 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_tw(), 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_ge(), ast_say_datetime_from_now_pt(), ast_say_datetime_ge(), ast_say_datetime_gr(), ast_say_datetime_nl(), ast_say_datetime_pt(), ast_say_datetime_pt_BR(), ast_say_datetime_tw(), ast_say_time_de(), ast_say_time_en(), ast_say_time_fr(), ast_say_time_ge(), ast_say_time_gr(), ast_say_time_nl(), ast_say_time_pt(), ast_say_time_pt_BR(), ast_say_time_tw(), ast_verbose(), build_radius_record(), callerid_genmsg(), cdr_get_tv(), cli_prompt(), get_date(), iax2_datetime(), main(), manager_log(), odbc_log(), pgsql_log(), phone_call(), play_message_datetime(), rpt_localtime(), say_date_generic(), sip_show_registry(), sqlite_log(), transmit_notify_request_with_callerid(), vmu_tm(), and write_metadata().

01144 {
01145    const struct state *sp = ast_tzset(zone);
01146    memset(tmp, 0, sizeof(*tmp));
01147    return sp ? localsub(timep, 0L, tmp, sp) : NULL;
01148 }

time_t ast_mktime ( struct tm *  tmp,
const char *  zone 
)

Definition at line 1641 of file localtime.c.

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

Referenced by acf_strptime().

01642 {
01643    const struct state *sp;
01644    if (!(sp = ast_tzset(zone)))
01645       return 0;
01646    return time1(tmp, localsub, 0L, sp);
01647 }

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

Definition at line 1017 of file localtime.c.

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

Referenced by ast_localtime(), and ast_mktime().

01018 {
01019    struct state *sp;
01020 
01021    if (ast_strlen_zero(zone))
01022       zone = "/etc/localtime";
01023 
01024    AST_LIST_LOCK(&zonelist);
01025    AST_LIST_TRAVERSE(&zonelist, sp, list) {
01026       if (!strcmp(sp->name, zone)) {
01027          AST_LIST_UNLOCK(&zonelist);
01028          return sp;
01029       }
01030    }
01031    AST_LIST_UNLOCK(&zonelist);
01032 
01033    if (!(sp = ast_calloc(1, sizeof *sp)))
01034       return NULL;
01035 
01036    if (tzload(zone, sp, TRUE) != 0) {
01037       if (zone[0] == ':' || tzparse(zone, sp, FALSE) != 0)
01038          (void) gmtload(sp);
01039    }
01040    ast_copy_string(sp->name, zone, sizeof(sp->name));
01041    AST_LIST_LOCK(&zonelist);
01042    AST_LIST_INSERT_TAIL(&zonelist, sp, list);
01043    AST_LIST_UNLOCK(&zonelist);
01044    return sp;
01045 }

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

Referenced by tzload().

00236 {
00237    long  result;
00238    int   i;
00239 
00240    result = (codep[0] & 0x80) ? ~0L : 0;
00241    for (i = 0; i < 4; ++i)
00242       result = (result << 8) | (codep[i] & 0xff);
00243    return result;
00244 }

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

Definition at line 246 of file localtime.c.

Referenced by tzload().

00247 {
00248    time_t   result;
00249    int   i;
00250 
00251    result = (codep[0] & 0x80) ?  (~(int_fast64_t) 0) : 0;
00252    for (i = 0; i < 8; ++i)
00253       result = result * 256 + (codep[i] & 0xff);
00254    return result;
00255 }

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

Definition at line 257 of file localtime.c.

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

Referenced by tzload().

00258 {
00259    const long long at1 = t1, at0 = t0;
00260    if (TYPE_INTEGRAL(time_t) &&
00261       TYPE_BIT(time_t) - TYPE_SIGNED(time_t) < SECSPERREPEAT_BITS)
00262          return 0;
00263    return at1 - at0 == SECSPERREPEAT;
00264 }

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

References is_digit.

Referenced by getrule(), and getsecs().

00547 {
00548    char  c;
00549    int   num;
00550 
00551    if (strp == NULL || !is_digit(c = *strp))
00552       return NULL;
00553    num = 0;
00554    do {
00555       num = num * 10 + (c - '0');
00556       if (num > max)
00557          return NULL;   /* illegal value */
00558       c = *++strp;
00559    } while (is_digit(c));
00560    if (num < min)
00561       return NULL;      /* illegal value */
00562    *nump = num;
00563    return strp;
00564 }

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

References getsecs().

Referenced by tzparse().

00614 {
00615    int   neg = 0;
00616 
00617    if (*strp == '-') {
00618       neg = 1;
00619       ++strp;
00620    } else if (*strp == '+')
00621       ++strp;
00622    strp = getsecs(strp, offsetp);
00623    if (strp == NULL)
00624       return NULL;      /* illegal time */
00625    if (neg)
00626       *offsetp = -*offsetp;
00627    return strp;
00628 }

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

Referenced by tzparse().

00531 {
00532    int   c;
00533 
00534    while ((c = *strp) != '\0' && c != delim)
00535       ++strp;
00536    return strp;
00537 }

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 637 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().

00638 {
00639    if (*strp == 'J') {
00640       /*
00641       ** Julian day.
00642       */
00643       rulep->r_type = JULIAN_DAY;
00644       ++strp;
00645       strp = getnum(strp, &rulep->r_day, 1, DAYSPERNYEAR);
00646    } else if (*strp == 'M') {
00647       /*
00648       ** Month, week, day.
00649       */
00650       rulep->r_type = MONTH_NTH_DAY_OF_WEEK;
00651       ++strp;
00652       strp = getnum(strp, &rulep->r_mon, 1, MONSPERYEAR);
00653       if (strp == NULL)
00654          return NULL;
00655       if (*strp++ != '.')
00656          return NULL;
00657       strp = getnum(strp, &rulep->r_week, 1, 5);
00658       if (strp == NULL)
00659          return NULL;
00660       if (*strp++ != '.')
00661          return NULL;
00662       strp = getnum(strp, &rulep->r_day, 0, DAYSPERWEEK - 1);
00663    } else if (is_digit(*strp)) {
00664       /*
00665       ** Day of year.
00666       */
00667       rulep->r_type = DAY_OF_YEAR;
00668       strp = getnum(strp, &rulep->r_day, 0, DAYSPERLYEAR - 1);
00669    } else   return NULL;      /* invalid format */
00670    if (strp == NULL)
00671       return NULL;
00672    if (*strp == '/') {
00673       /*
00674       ** Time specified.
00675       */
00676       ++strp;
00677       strp = getsecs(strp, &rulep->r_time);
00678    } else   rulep->r_time = 2 * SECSPERHOUR; /* default = 2:00:00 */
00679    return strp;
00680 }

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

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

Referenced by getoffset(), and getrule().

00575 {
00576    int   num;
00577 
00578    /*
00579    ** `HOURSPERDAY * DAYSPERWEEK - 1' allows quasi-Posix rules like
00580    ** "M10.4.6/26", which does not conform to Posix,
00581    ** but which specifies the equivalent of
00582    ** ``02:00 on the first Sunday on or after 23 Oct''.
00583    */
00584    strp = getnum(strp, &num, 0, HOURSPERDAY * DAYSPERWEEK - 1);
00585    if (strp == NULL)
00586       return NULL;
00587    *secsp = num * (long) SECSPERHOUR;
00588    if (*strp == ':') {
00589       ++strp;
00590       strp = getnum(strp, &num, 0, MINSPERHOUR - 1);
00591       if (strp == NULL)
00592          return NULL;
00593       *secsp += num * SECSPERMIN;
00594       if (*strp == ':') {
00595          ++strp;
00596          /* `SECSPERMIN' allows for leap seconds. */
00597          strp = getnum(strp, &num, 0, SECSPERMIN);
00598          if (strp == NULL)
00599             return NULL;
00600          *secsp += num;
00601       }
00602    }
00603    return strp;
00604 }

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

References is_digit.

Referenced by tzparse().

00512 {
00513    char  c;
00514 
00515    while ((c = *strp) != '\0' && !is_digit(c) && c != ',' && c != '-' &&
00516       c != '+')
00517          ++strp;
00518    return strp;
00519 }

static int gmtload ( struct state sp  )  [static]

Definition at line 1009 of file localtime.c.

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

Referenced by ast_tzset(), and gmtsub().

01010 {
01011    if (tzload(gmt, sp, TRUE) != 0)
01012       return tzparse(gmt, sp, TRUE);
01013    else
01014       return WRONG;
01015 }

static struct tm* gmtsub ( const time_t *  timep,
const long  offset,
struct tm *  tmp 
) [static, read]

Definition at line 1154 of file localtime.c.

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

Referenced by localsub().

01155 {
01156    struct tm * result;
01157    struct state *sp;
01158 
01159    AST_LIST_LOCK(&zonelist);
01160    AST_LIST_TRAVERSE(&zonelist, sp, list) {
01161       if (!strcmp(sp->name, "UTC"))
01162          break;
01163    }
01164 
01165    if (!sp) {
01166       if (!(sp = (struct state *) ast_calloc(1, sizeof *sp)))
01167          return NULL;
01168       gmtload(sp);
01169       AST_LIST_INSERT_TAIL(&zonelist, sp, list);
01170    }
01171    AST_LIST_UNLOCK(&zonelist);
01172 
01173    result = timesub(timep, offset, sp, tmp);
01174 #ifdef TM_ZONE
01175    /*
01176    ** Could get fancy here and deliver something such as
01177    ** "UTC+xxxx" or "UTC-xxxx" if offset is non-zero,
01178    ** but this is no time for a treasure hunt.
01179    */
01180    if (offset != 0)
01181       tmp->TM_ZONE = "    ";
01182    else
01183       tmp->TM_ZONE = sp->chars;
01184 #endif /* defined TM_ZONE */
01185    return result;
01186 }

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

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

01337 {
01338    int   number0;
01339 
01340    number0 = *number;
01341    *number += delta;
01342    return (*number < number0) != (delta < 0);
01343 }

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

Referenced by timesub().

01194 {
01195    return (y >= 0) ? (y / 4 - y / 100 + y / 400) :
01196       -(leaps_thru_end_of(-(y + 1)) + 1);
01197 }

static struct tm* localsub ( const time_t *  timep,
const long  offset,
struct 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 1056 of file localtime.c.

References state::ats, AVGSECSPERYEAR, state::chars, gmtsub(), state::goahead, state::goback, t, state::timecnt, timesub(), state::ttis, state::typecnt, state::types, and YEARSPERREPEAT.

Referenced by ast_localtime(), and ast_mktime().

01057 {
01058    const struct ttinfo *   ttisp;
01059    int         i;
01060    struct tm *    result;
01061    const time_t         t = *timep;
01062 
01063    if (sp == NULL)
01064       return gmtsub(timep, offset, tmp);
01065    if ((sp->goback && t < sp->ats[0]) ||
01066       (sp->goahead && t > sp->ats[sp->timecnt - 1])) {
01067          time_t         newt = t;
01068          time_t      seconds;
01069          time_t      tcycles;
01070          int_fast64_t   icycles;
01071 
01072          if (t < sp->ats[0])
01073             seconds = sp->ats[0] - t;
01074          else  seconds = t - sp->ats[sp->timecnt - 1];
01075          --seconds;
01076          tcycles = seconds / YEARSPERREPEAT / AVGSECSPERYEAR;
01077          ++tcycles;
01078          icycles = tcycles;
01079          if (tcycles - icycles >= 1 || icycles - tcycles >= 1)
01080             return NULL;
01081          seconds = icycles;
01082          seconds *= YEARSPERREPEAT;
01083          seconds *= AVGSECSPERYEAR;
01084          if (t < sp->ats[0])
01085             newt += seconds;
01086          else  newt -= seconds;
01087          if (newt < sp->ats[0] ||
01088             newt > sp->ats[sp->timecnt - 1])
01089                return NULL;   /* "cannot happen" */
01090          result = localsub(&newt, offset, tmp, sp);
01091          if (result == tmp) {
01092             time_t   newy;
01093 
01094             newy = tmp->tm_year;
01095             if (t < sp->ats[0])
01096                newy -= icycles * YEARSPERREPEAT;
01097             else
01098                newy += icycles * YEARSPERREPEAT;
01099             tmp->tm_year = newy;
01100             if (tmp->tm_year != newy)
01101                return NULL;
01102          }
01103          return result;
01104    }
01105    if (sp->timecnt == 0 || t < sp->ats[0]) {
01106       i = 0;
01107       while (sp->ttis[i].tt_isdst) {
01108          if (++i >= sp->typecnt) {
01109             i = 0;
01110             break;
01111          }
01112       }
01113    } else {
01114       int   lo = 1;
01115       int   hi = sp->timecnt;
01116 
01117       while (lo < hi) {
01118          int   mid = (lo + hi) >> 1;
01119 
01120          if (t < sp->ats[mid])
01121             hi = mid;
01122          else
01123             lo = mid + 1;
01124       }
01125       i = (int) sp->types[lo - 1];
01126    }
01127    ttisp = &sp->ttis[i];
01128    /*
01129    ** To get (wrong) behavior that's compatible with System V Release 2.0
01130    ** you'd replace the statement below with
01131    ** t += ttisp->tt_gmtoff;
01132    ** timesub(&t, 0L, sp, tmp);
01133    */
01134    result = timesub(&t, ttisp->tt_gmtoff, sp, tmp);
01135    tmp->tm_isdst = ttisp->tt_isdst;
01136    tmp->tm_gmtoff = ttisp->tt_gmtoff;
01137 #ifdef TM_ZONE
01138    tmp->TM_ZONE = &sp->chars[ttisp->tt_abbrind];
01139 #endif /* defined TM_ZONE */
01140    return result;
01141 }

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

Definition at line 1345 of file localtime.c.

Referenced by long_normalize_overflow(), and time2sub().

01346 {
01347    long  number0;
01348 
01349    number0 = *number;
01350    *number += delta;
01351    return (*number < number0) != (delta < 0);
01352 }

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

Definition at line 1365 of file localtime.c.

References long_increment_overflow().

Referenced by time2sub().

01366 {
01367    int   tensdelta;
01368 
01369    tensdelta = (*unitsptr >= 0) ?
01370       (*unitsptr / base) :
01371       (-1 - (-1 - *unitsptr) / base);
01372    *unitsptr -= tensdelta * base;
01373    return long_increment_overflow(tensptr, tensdelta);
01374 }

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

Definition at line 1354 of file localtime.c.

References increment_overflow().

Referenced by time2sub().

01355 {
01356    int   tensdelta;
01357 
01358    tensdelta = (*unitsptr >= 0) ?
01359       (*unitsptr / base) :
01360       (-1 - (-1 - *unitsptr) / base);
01361    *unitsptr -= tensdelta * base;
01362    return increment_overflow(tensptr, tensdelta);
01363 }

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 tm *atmp, const struct tm *btmp)   )  [static]

static struct tm* timesub P ( (const time_t *timep, long offset, const struct state *sp, struct tm *tmp)   )  [static, read]

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

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

static time_t time1 P ( (struct tm *tmp, struct tm *(*funcp) P((const time_t *, long, struct 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 tm* localsub P ( (const time_t *timep, long offset, struct tm *tmp, const struct state *sp)   )  [static, read]

static struct tm* gmtsub P ( (const time_t *timep, long offset, struct 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 time_t time1 ( struct tm *  tmp,
struct tm *(*)(const time_t *, long, struct tm *, const struct state *)  funcp,
const long  offset,
const struct state sp 
) [static]

Definition at line 1576 of file localtime.c.

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

Referenced by ast_mktime().

01577 {
01578    time_t         t;
01579    int         samei, otheri;
01580    int         sameind, otherind;
01581    int         i;
01582    int         nseen;
01583    int            seen[TZ_MAX_TYPES];
01584    int            types[TZ_MAX_TYPES];
01585    int            okay;
01586 
01587    if (tmp->tm_isdst > 1)
01588       tmp->tm_isdst = 1;
01589    t = time2(tmp, funcp, offset, &okay, sp);
01590 #ifdef PCTS
01591    /*
01592    ** PCTS code courtesy Grant Sullivan.
01593    */
01594    if (okay)
01595       return t;
01596    if (tmp->tm_isdst < 0)
01597       tmp->tm_isdst = 0;   /* reset to std and try again */
01598 #endif /* defined PCTS */
01599 #ifndef PCTS
01600    if (okay || tmp->tm_isdst < 0)
01601       return t;
01602 #endif /* !defined PCTS */
01603    /*
01604    ** We're supposed to assume that somebody took a time of one type
01605    ** and did some math on it that yielded a "struct tm" that's bad.
01606    ** We try to divine the type they started from and adjust to the
01607    ** type they need.
01608    */
01609    if (sp == NULL)
01610       return WRONG;
01611    for (i = 0; i < sp->typecnt; ++i)
01612       seen[i] = FALSE;
01613    nseen = 0;
01614    for (i = sp->timecnt - 1; i >= 0; --i)
01615       if (!seen[sp->types[i]]) {
01616          seen[sp->types[i]] = TRUE;
01617          types[nseen++] = sp->types[i];
01618       }
01619    for (sameind = 0; sameind < nseen; ++sameind) {
01620       samei = types[sameind];
01621       if (sp->ttis[samei].tt_isdst != tmp->tm_isdst)
01622          continue;
01623       for (otherind = 0; otherind < nseen; ++otherind) {
01624          otheri = types[otherind];
01625          if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst)
01626             continue;
01627          tmp->tm_sec += sp->ttis[otheri].tt_gmtoff -
01628                sp->ttis[samei].tt_gmtoff;
01629          tmp->tm_isdst = !tmp->tm_isdst;
01630          t = time2(tmp, funcp, offset, &okay, sp);
01631          if (okay)
01632             return t;
01633          tmp->tm_sec -= sp->ttis[otheri].tt_gmtoff -
01634                sp->ttis[samei].tt_gmtoff;
01635          tmp->tm_isdst = !tmp->tm_isdst;
01636       }
01637    }
01638    return WRONG;
01639 }

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

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

References FALSE, t, time2sub(), and TRUE.

Referenced by time1().

01564 {
01565    time_t   t;
01566 
01567    /*! \note
01568    ** First try without normalization of seconds
01569    ** (in case tm_sec contains a value associated with a leap second).
01570    ** If that fails, try with normalization of seconds.
01571    */
01572    t = time2sub(tmp, funcp, offset, okayp, FALSE, sp);
01573    return *okayp ? t : time2sub(tmp, funcp, offset, okayp, TRUE, sp);
01574 }

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

Definition at line 1389 of file localtime.c.

References DAYSPERLYEAR, EPOCH_YEAR, FALSE, HOURSPERDAY, increment_overflow(), isleap, long_increment_overflow(), long_normalize_overflow(), MINSPERHOUR, mon_lengths, MONSPERYEAR, normalize_overflow(), SECSPERMIN, t, TM_YEAR_BASE, tmcomp(), TRUE, state::ttis, TYPE_BIT, TYPE_INTEGRAL, TYPE_SIGNED, state::typecnt, WRONG, and year_lengths.

Referenced by time2().

01390 {
01391    int         dir;
01392    int         i, j;
01393    int         saved_seconds;
01394    long        li;
01395    time_t         lo;
01396    time_t         hi;
01397    long           y;
01398    time_t            newt;
01399    time_t            t;
01400    struct tm         yourtm, mytm;
01401 
01402    *okayp = FALSE;
01403    yourtm = *tmp;
01404    if (do_norm_secs) {
01405       if (normalize_overflow(&yourtm.tm_min, &yourtm.tm_sec,
01406          SECSPERMIN))
01407             return WRONG;
01408    }
01409    if (normalize_overflow(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR))
01410       return WRONG;
01411    if (normalize_overflow(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY))
01412       return WRONG;
01413    y = yourtm.tm_year;
01414    if (long_normalize_overflow(&y, &yourtm.tm_mon, MONSPERYEAR))
01415       return WRONG;
01416    /*
01417    ** Turn y into an actual year number for now.
01418    ** It is converted back to an offset from TM_YEAR_BASE later.
01419    */
01420    if (long_increment_overflow(&y, TM_YEAR_BASE))
01421       return WRONG;
01422    while (yourtm.tm_mday <= 0) {
01423       if (long_increment_overflow(&y, -1))
01424          return WRONG;
01425       li = y + (1 < yourtm.tm_mon);
01426       yourtm.tm_mday += year_lengths[isleap(li)];
01427    }
01428    while (yourtm.tm_mday > DAYSPERLYEAR) {
01429       li = y + (1 < yourtm.tm_mon);
01430       yourtm.tm_mday -= year_lengths[isleap(li)];
01431       if (long_increment_overflow(&y, 1))
01432          return WRONG;
01433    }
01434    for ( ; ; ) {
01435       i = mon_lengths[isleap(y)][yourtm.tm_mon];
01436       if (yourtm.tm_mday <= i)
01437          break;
01438       yourtm.tm_mday -= i;
01439       if (++yourtm.tm_mon >= MONSPERYEAR) {
01440          yourtm.tm_mon = 0;
01441          if (long_increment_overflow(&y, 1))
01442             return WRONG;
01443       }
01444    }
01445    if (long_increment_overflow(&y, -TM_YEAR_BASE))
01446       return WRONG;
01447    yourtm.tm_year = y;
01448    if (yourtm.tm_year != y)
01449       return WRONG;
01450    if (yourtm.tm_sec >= 0 && yourtm.tm_sec < SECSPERMIN)
01451       saved_seconds = 0;
01452    else if (y + TM_YEAR_BASE < EPOCH_YEAR) {
01453       /*
01454       ** We can't set tm_sec to 0, because that might push the
01455       ** time below the minimum representable time.
01456       ** Set tm_sec to 59 instead.
01457       ** This assumes that the minimum representable time is
01458       ** not in the same minute that a leap second was deleted from,
01459       ** which is a safer assumption than using 58 would be.
01460       */
01461       if (increment_overflow(&yourtm.tm_sec, 1 - SECSPERMIN))
01462          return WRONG;
01463       saved_seconds = yourtm.tm_sec;
01464       yourtm.tm_sec = SECSPERMIN - 1;
01465    } else {
01466       saved_seconds = yourtm.tm_sec;
01467       yourtm.tm_sec = 0;
01468    }
01469    /*
01470    ** Do a binary search (this works whatever time_t's type is).
01471    */
01472    if (!TYPE_SIGNED(time_t)) {
01473       lo = 0;
01474       hi = lo - 1;
01475    } else if (!TYPE_INTEGRAL(time_t)) {
01476       if (sizeof(time_t) > sizeof(float))
01477          hi = (time_t) DBL_MAX;
01478       else  hi = (time_t) FLT_MAX;
01479       lo = -hi;
01480    } else {
01481       lo = 1;
01482       for (i = 0; i < (int) TYPE_BIT(time_t) - 1; ++i)
01483          lo *= 2;
01484       hi = -(lo + 1);
01485    }
01486    for ( ; ; ) {
01487       t = lo / 2 + hi / 2;
01488       if (t < lo)
01489          t = lo;
01490       else if (t > hi)
01491          t = hi;
01492       if ((*funcp)(&t, offset, &mytm, sp) == NULL) {
01493          /*
01494          ** Assume that t is too extreme to be represented in
01495          ** a struct tm; arrange things so that it is less
01496          ** extreme on the next pass.
01497          */
01498          dir = (t > 0) ? 1 : -1;
01499       } else   dir = tmcomp(&mytm, &yourtm);
01500       if (dir != 0) {
01501          if (t == lo) {
01502             ++t;
01503             if (t <= lo)
01504                return WRONG;
01505             ++lo;
01506          } else if (t == hi) {
01507             --t;
01508             if (t >= hi)
01509                return WRONG;
01510             --hi;
01511          }
01512          if (lo > hi)
01513             return WRONG;
01514          if (dir > 0)
01515             hi = t;
01516          else  lo = t;
01517          continue;
01518       }
01519       if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst)
01520          break;
01521       /*
01522       ** Right time, wrong type.
01523       ** Hunt for right time, right type.
01524       ** It's okay to guess wrong since the guess
01525       ** gets checked.
01526       */
01527       /*
01528       ** The (void *) casts are the benefit of SunOS 3.3 on Sun 2's.
01529       */
01530       for (i = sp->typecnt - 1; i >= 0; --i) {
01531          if (sp->ttis[i].tt_isdst != yourtm.tm_isdst)
01532             continue;
01533          for (j = sp->typecnt - 1; j >= 0; --j) {
01534             if (sp->ttis[j].tt_isdst == yourtm.tm_isdst)
01535                continue;
01536             newt = t + sp->ttis[j].tt_gmtoff -
01537                sp->ttis[i].tt_gmtoff;
01538             if ((*funcp)(&newt, offset, &mytm, sp) == NULL)
01539                continue;
01540             if (tmcomp(&mytm, &yourtm) != 0)
01541                continue;
01542             if (mytm.tm_isdst != yourtm.tm_isdst)
01543                continue;
01544             /*
01545             ** We have a match.
01546             */
01547             t = newt;
01548             goto label;
01549          }
01550       }
01551       return WRONG;
01552    }
01553 label:
01554    newt = t + saved_seconds;
01555    if ((newt < t) != (saved_seconds < 0))
01556       return WRONG;
01557    t = newt;
01558    if ((*funcp)(&t, offset, tmp, sp))
01559       *okayp = TRUE;
01560    return t;
01561 }

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

Definition at line 1199 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, TM_YEAR_BASE, and year_lengths.

Referenced by gmtsub(), and localsub().

01200 {
01201    const struct lsinfo *   lp;
01202    time_t         tdays;
01203    int         idays;   /* unsigned would be so 2003 */
01204    long        rem;
01205    int            y;
01206    const int *    ip;
01207    long        corr;
01208    int         hit;
01209    int         i;
01210    long  seconds;
01211 
01212 
01213    corr = 0;
01214    hit = 0;
01215    i = (sp == NULL) ? 0 : sp->leapcnt;
01216    while (--i >= 0) {
01217       lp = &sp->lsis[i];
01218       if (*timep >= lp->ls_trans) {
01219          if (*timep == lp->ls_trans) {
01220             hit = ((i == 0 && lp->ls_corr > 0) ||
01221                lp->ls_corr > sp->lsis[i - 1].ls_corr);
01222             if (hit)
01223                while (i > 0 &&
01224                   sp->lsis[i].ls_trans ==
01225                   sp->lsis[i - 1].ls_trans + 1 &&
01226                   sp->lsis[i].ls_corr ==
01227                   sp->lsis[i - 1].ls_corr + 1) {
01228                      ++hit;
01229                      --i;
01230                }
01231          }
01232          corr = lp->ls_corr;
01233          break;
01234       }
01235    }
01236    y = EPOCH_YEAR;
01237    tdays = *timep / SECSPERDAY;
01238    rem = *timep - tdays * SECSPERDAY;
01239    while (tdays < 0 || tdays >= year_lengths[isleap(y)]) {
01240       int      newy;
01241       time_t   tdelta;
01242       int   idelta;
01243       int   leapdays;
01244 
01245       tdelta = tdays / DAYSPERLYEAR;
01246       idelta = tdelta;
01247       if (tdelta - idelta >= 1 || idelta - tdelta >= 1)
01248          return NULL;
01249       if (idelta == 0)
01250          idelta = (tdays < 0) ? -1 : 1;
01251       newy = y;
01252       if (increment_overflow(&newy, idelta))
01253          return NULL;
01254       leapdays = leaps_thru_end_of(newy - 1) -
01255          leaps_thru_end_of(y - 1);
01256       tdays -= ((time_t) newy - y) * DAYSPERNYEAR;
01257       tdays -= leapdays;
01258       y = newy;
01259    }
01260 
01261    seconds = tdays * SECSPERDAY + 0.5;
01262    tdays = seconds / SECSPERDAY;
01263    rem += seconds - tdays * SECSPERDAY;
01264 
01265    /*
01266    ** Given the range, we can now fearlessly cast...
01267    */
01268    idays = tdays;
01269    rem += offset - corr;
01270    while (rem < 0) {
01271       rem += SECSPERDAY;
01272       --idays;
01273    }
01274    while (rem >= SECSPERDAY) {
01275       rem -= SECSPERDAY;
01276       ++idays;
01277    }
01278    while (idays < 0) {
01279       if (increment_overflow(&y, -1))
01280          return NULL;
01281       idays += year_lengths[isleap(y)];
01282    }
01283    while (idays >= year_lengths[isleap(y)]) {
01284       idays -= year_lengths[isleap(y)];
01285       if (increment_overflow(&y, 1))
01286          return NULL;
01287    }
01288    tmp->tm_year = y;
01289    if (increment_overflow(&tmp->tm_year, -TM_YEAR_BASE))
01290       return NULL;
01291    tmp->tm_yday = idays;
01292    /*
01293    ** The "extra" mods below avoid overflow problems.
01294    */
01295    tmp->tm_wday = EPOCH_WDAY +
01296       ((y - EPOCH_YEAR) % DAYSPERWEEK) *
01297       (DAYSPERNYEAR % DAYSPERWEEK) +
01298       leaps_thru_end_of(y - 1) -
01299       leaps_thru_end_of(EPOCH_YEAR - 1) +
01300       idays;
01301    tmp->tm_wday %= DAYSPERWEEK;
01302    if (tmp->tm_wday < 0)
01303       tmp->tm_wday += DAYSPERWEEK;
01304    tmp->tm_hour = (int) (rem / SECSPERHOUR);
01305    rem %= SECSPERHOUR;
01306    tmp->tm_min = (int) (rem / SECSPERMIN);
01307    /*
01308    ** A positive leap second requires a special
01309    ** representation. This uses "... ??:59:60" et seq.
01310    */
01311    tmp->tm_sec = (int) (rem % SECSPERMIN) + hit;
01312    ip = mon_lengths[isleap(y)];
01313    for (tmp->tm_mon = 0; idays >= ip[tmp->tm_mon]; ++(tmp->tm_mon))
01314       idays -= ip[tmp->tm_mon];
01315    tmp->tm_mday = (int) (idays + 1);
01316    tmp->tm_isdst = 0;
01317 #ifdef TM_GMTOFF
01318    tmp->TM_GMTOFF = offset;
01319 #endif /* defined TM_GMTOFF */
01320    return tmp;
01321 }

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

Definition at line 1376 of file localtime.c.

Referenced by time2sub().

01377 {
01378    int   result;
01379 
01380    if ((result = (atmp->tm_year - btmp->tm_year)) == 0 &&
01381       (result = (atmp->tm_mon - btmp->tm_mon)) == 0 &&
01382       (result = (atmp->tm_mday - btmp->tm_mday)) == 0 &&
01383       (result = (atmp->tm_hour - btmp->tm_hour)) == 0 &&
01384       (result = (atmp->tm_min - btmp->tm_min)) == 0)
01385          result = atmp->tm_sec - btmp->tm_sec;
01386    return result;
01387 }

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

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

00689 {
00690    int   leapyear;
00691    time_t   value;
00692    int   i;
00693    int      d, m1, yy0, yy1, yy2, dow;
00694 
00695    INITIALIZE(value);
00696    leapyear = isleap(year);
00697    switch (rulep->r_type) {
00698 
00699    case JULIAN_DAY:
00700       /*
00701       ** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap
00702       ** years.
00703       ** In non-leap years, or if the day number is 59 or less, just
00704       ** add SECSPERDAY times the day number-1 to the time of
00705       ** January 1, midnight, to get the day.
00706       */
00707       value = janfirst + (rulep->r_day - 1) * SECSPERDAY;
00708       if (leapyear && rulep->r_day >= 60)
00709          value += SECSPERDAY;
00710       break;
00711 
00712    case DAY_OF_YEAR:
00713       /*
00714       ** n - day of year.
00715       ** Just add SECSPERDAY times the day number to the time of
00716       ** January 1, midnight, to get the day.
00717       */
00718       value = janfirst + rulep->r_day * SECSPERDAY;
00719       break;
00720 
00721    case MONTH_NTH_DAY_OF_WEEK:
00722       /*
00723       ** Mm.n.d - nth "dth day" of month m.
00724       */
00725       value = janfirst;
00726       for (i = 0; i < rulep->r_mon - 1; ++i)
00727          value += mon_lengths[leapyear][i] * SECSPERDAY;
00728 
00729       /*
00730       ** Use Zeller's Congruence to get day-of-week of first day of
00731       ** month.
00732       */
00733       m1 = (rulep->r_mon + 9) % 12 + 1;
00734       yy0 = (rulep->r_mon <= 2) ? (year - 1) : year;
00735       yy1 = yy0 / 100;
00736       yy2 = yy0 % 100;
00737       dow = ((26 * m1 - 2) / 10 +
00738          1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7;
00739       if (dow < 0)
00740          dow += DAYSPERWEEK;
00741 
00742       /*
00743       ** "dow" is the day-of-week of the first day of the month. Get
00744       ** the day-of-month (zero-origin) of the first "dow" day of the
00745       ** month.
00746       */
00747       d = rulep->r_day - dow;
00748       if (d < 0)
00749          d += DAYSPERWEEK;
00750       for (i = 1; i < rulep->r_week; ++i) {
00751          if (d + DAYSPERWEEK >=
00752             mon_lengths[leapyear][rulep->r_mon - 1])
00753                break;
00754          d += DAYSPERWEEK;
00755       }
00756 
00757       /*
00758       ** "d" is the day-of-month (zero-origin) of the day we want.
00759       */
00760       value += d * SECSPERDAY;
00761       break;
00762    }
00763 
00764    /*
00765    ** "value" is the Epoch-relative time of 00:00:00 UTC on the day in
00766    ** question. To get the Epoch-relative time of the specified local
00767    ** time on that day, add the transition time and the current offset
00768    ** from UTC.
00769    */
00770    return value + rulep->r_time + offset;
00771 }

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

Definition at line 266 of file localtime.c.

References state::ats, state::charcnt, state::chars, detzcode(), detzcode64(), differ_by_repeat(), FALSE, FILENAME_MAX, state::goahead, state::goback, state::leapcnt, lsinfo::ls_corr, lsinfo::ls_trans, state::lsis, OPEN_MODE, state::timecnt, TRUE, state::ttis, TYPE_INTEGRAL, TYPE_SIGNED, state::typecnt, state::types, TZ_MAX_CHARS, TZ_MAX_LEAPS, TZ_MAX_TIMES, TZ_MAX_TYPES, TZDEFAULT, TZDIR, tzparse(), WRONG, and YEARSPERREPEAT.

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

00267 {
00268    const char *      p;
00269    int         i;
00270    int         fid;
00271    int         stored;
00272    int         nread;
00273    union {
00274       struct tzhead  tzhead;
00275       char     buf[2 * sizeof(struct tzhead) +
00276                2 * sizeof *sp +
00277                4 * TZ_MAX_TIMES];
00278    } u;
00279 
00280    if (name == NULL && (name = TZDEFAULT) == NULL)
00281       return WRONG;
00282    {
00283       int   doaccess;
00284       /*
00285       ** Section 4.9.1 of the C standard says that
00286       ** "FILENAME_MAX expands to an integral constant expression
00287       ** that is the size needed for an array of char large enough
00288       ** to hold the longest file name string that the implementation
00289       ** guarantees can be opened."
00290       */
00291       char     fullname[FILENAME_MAX + 1];
00292 
00293       if (name[0] == ':')
00294          ++name;
00295       doaccess = name[0] == '/';
00296       if (!doaccess) {
00297          if ((p = TZDIR) == NULL)
00298             return WRONG;
00299          if ((strlen(p) + strlen(name) + 1) >= sizeof fullname)
00300             return WRONG;
00301          (void) strcpy(fullname, p);
00302          (void) strcat(fullname, "/");
00303          (void) strcat(fullname, name);
00304          /*
00305          ** Set doaccess if '.' (as in "../") shows up in name.
00306          */
00307          if (strchr(name, '.') != NULL)
00308             doaccess = TRUE;
00309          name = fullname;
00310       }
00311       if (doaccess && access(name, R_OK) != 0)
00312          return WRONG;
00313       if ((fid = open(name, OPEN_MODE)) == -1)
00314          return WRONG;
00315    }
00316    nread = read(fid, u.buf, sizeof u.buf);
00317    if (close(fid) < 0 || nread <= 0)
00318       return WRONG;
00319    for (stored = 4; stored <= 8; stored *= 2) {
00320       int      ttisstdcnt;
00321       int      ttisgmtcnt;
00322 
00323       ttisstdcnt = (int) detzcode(u.tzhead.tzh_ttisstdcnt);
00324       ttisgmtcnt = (int) detzcode(u.tzhead.tzh_ttisgmtcnt);
00325       sp->leapcnt = (int) detzcode(u.tzhead.tzh_leapcnt);
00326       sp->timecnt = (int) detzcode(u.tzhead.tzh_timecnt);
00327       sp->typecnt = (int) detzcode(u.tzhead.tzh_typecnt);
00328       sp->charcnt = (int) detzcode(u.tzhead.tzh_charcnt);
00329       p = u.tzhead.tzh_charcnt + sizeof u.tzhead.tzh_charcnt;
00330       if (sp->leapcnt < 0 || sp->leapcnt > TZ_MAX_LEAPS ||
00331          sp->typecnt <= 0 || sp->typecnt > TZ_MAX_TYPES ||
00332          sp->timecnt < 0 || sp->timecnt > TZ_MAX_TIMES ||
00333          sp->charcnt < 0 || sp->charcnt > TZ_MAX_CHARS ||
00334          (ttisstdcnt != sp->typecnt && ttisstdcnt != 0) ||
00335          (ttisgmtcnt != sp->typecnt && ttisgmtcnt != 0))
00336             return WRONG;
00337       if (nread - (p - u.buf) <
00338          sp->timecnt * stored +     /* ats */
00339          sp->timecnt +        /* types */
00340          sp->typecnt * 6 +    /* ttinfos */
00341          sp->charcnt +        /* chars */
00342          sp->leapcnt * (stored + 4) +  /* lsinfos */
00343          ttisstdcnt +         /* ttisstds */
00344          ttisgmtcnt)       /* ttisgmts */
00345             return WRONG;
00346       for (i = 0; i < sp->timecnt; ++i) {
00347          sp->ats[i] = (stored == 4) ?
00348             detzcode(p) : detzcode64(p);
00349          p += stored;
00350       }
00351       for (i = 0; i < sp->timecnt; ++i) {
00352          sp->types[i] = (unsigned char) *p++;
00353          if (sp->types[i] >= sp->typecnt)
00354             return WRONG;
00355       }
00356       for (i = 0; i < sp->typecnt; ++i) {
00357          struct ttinfo *   ttisp;
00358 
00359          ttisp = &sp->ttis[i];
00360          ttisp->tt_gmtoff = detzcode(p);
00361          p += 4;
00362          ttisp->tt_isdst = (unsigned char) *p++;
00363          if (ttisp->tt_isdst != 0 && ttisp->tt_isdst != 1)
00364             return WRONG;
00365          ttisp->tt_abbrind = (unsigned char) *p++;
00366          if (ttisp->tt_abbrind < 0 ||
00367             ttisp->tt_abbrind > sp->charcnt)
00368                return WRONG;
00369       }
00370       for (i = 0; i < sp->charcnt; ++i)
00371          sp->chars[i] = *p++;
00372       sp->chars[i] = '\0'; /* ensure '\0' at end */
00373       for (i = 0; i < sp->leapcnt; ++i) {
00374          struct lsinfo *   lsisp;
00375 
00376          lsisp = &sp->lsis[i];
00377          lsisp->ls_trans = (stored == 4) ?
00378             detzcode(p) : detzcode64(p);
00379          p += stored;
00380          lsisp->ls_corr = detzcode(p);
00381          p += 4;
00382       }
00383       for (i = 0; i < sp->typecnt; ++i) {
00384          struct ttinfo *   ttisp;
00385 
00386          ttisp = &sp->ttis[i];
00387          if (ttisstdcnt == 0)
00388             ttisp->tt_ttisstd = FALSE;
00389          else {
00390             ttisp->tt_ttisstd = *p++;
00391             if (ttisp->tt_ttisstd != TRUE &&
00392                ttisp->tt_ttisstd != FALSE)
00393                   return WRONG;
00394          }
00395       }
00396       for (i = 0; i < sp->typecnt; ++i) {
00397          struct ttinfo *   ttisp;
00398 
00399          ttisp = &sp->ttis[i];
00400          if (ttisgmtcnt == 0)
00401             ttisp->tt_ttisgmt = FALSE;
00402          else {
00403             ttisp->tt_ttisgmt = *p++;
00404             if (ttisp->tt_ttisgmt != TRUE &&
00405                ttisp->tt_ttisgmt != FALSE)
00406                   return WRONG;
00407          }
00408       }
00409       /*
00410       ** Out-of-sort ats should mean we're running on a
00411       ** signed time_t system but using a data file with
00412       ** unsigned values (or vice versa).
00413       */
00414       for (i = 0; i < sp->timecnt - 2; ++i)
00415          if (sp->ats[i] > sp->ats[i + 1]) {
00416             ++i;
00417             if (TYPE_SIGNED(time_t)) {
00418                /*
00419                ** Ignore the end (easy).
00420                */
00421                sp->timecnt = i;
00422             } else {
00423                /*
00424                ** Ignore the beginning (harder).
00425                */
00426                int   j;
00427 
00428                for (j = 0; j + i < sp->timecnt; ++j) {
00429                   sp->ats[j] = sp->ats[j + i];
00430                   sp->types[j] = sp->types[j + i];
00431                }
00432                sp->timecnt = j;
00433             }
00434             break;
00435          }
00436       /*
00437       ** If this is an old file, we're done.
00438       */
00439       if (u.tzhead.tzh_version[0] == '\0')
00440          break;
00441       nread -= p - u.buf;
00442       for (i = 0; i < nread; ++i)
00443          u.buf[i] = p[i];
00444       /*
00445       ** If this is a narrow integer time_t system, we're done.
00446       */
00447       if (stored >= (int) sizeof(time_t) && TYPE_INTEGRAL(time_t))
00448          break;
00449    }
00450    if (doextend && nread > 2 &&
00451       u.buf[0] == '\n' && u.buf[nread - 1] == '\n' &&
00452       sp->typecnt + 2 <= TZ_MAX_TYPES) {
00453          struct state   ts;
00454          int   result;
00455 
00456          u.buf[nread - 1] = '\0';
00457          result = tzparse(&u.buf[1], &ts, FALSE);
00458          if (result == 0 && ts.typecnt == 2 &&
00459             sp->charcnt + ts.charcnt <= TZ_MAX_CHARS) {
00460                for (i = 0; i < 2; ++i)
00461                   ts.ttis[i].tt_abbrind +=
00462                      sp->charcnt;
00463                for (i = 0; i < ts.charcnt; ++i)
00464                   sp->chars[sp->charcnt++] =
00465                      ts.chars[i];
00466                i = 0;
00467                while (i < ts.timecnt &&
00468                   ts.ats[i] <=
00469                   sp->ats[sp->timecnt - 1])
00470                      ++i;
00471                while (i < ts.timecnt &&
00472                    sp->timecnt < TZ_MAX_TIMES) {
00473                   sp->ats[sp->timecnt] =
00474                      ts.ats[i];
00475                   sp->types[sp->timecnt] =
00476                      sp->typecnt +
00477                      ts.types[i];
00478                   ++sp->timecnt;
00479                   ++i;
00480                }
00481                sp->ttis[sp->typecnt++] = ts.ttis[0];
00482                sp->ttis[sp->typecnt++] = ts.ttis[1];
00483          }
00484    }
00485    i = 2 * YEARSPERREPEAT;
00486    sp->goback = sp->goahead = sp->timecnt > i;
00487    sp->goback = sp->goback && sp->types[i] == sp->types[0] &&
00488       differ_by_repeat(sp->ats[i], sp->ats[0]);
00489    sp->goahead = sp->goahead &&
00490       sp->types[sp->timecnt - 1] == sp->types[sp->timecnt - 1 - i] &&
00491       differ_by_repeat(sp->ats[sp->timecnt - 1],
00492           sp->ats[sp->timecnt - 1 - i]);
00493    return 0;
00494 }

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

References state::ats, state::charcnt, state::chars, EPOCH_YEAR, FALSE, getoffset(), getqzname(), getrule(), getzname(), INITIALIZE, isleap, state::leapcnt, SECSPERDAY, SECSPERHOUR, starttime, state::timecnt, transtime(), TRUE, state::ttis, state::typecnt, state::types, TZ_MAX_TIMES, TZDEFRULES, TZDEFRULESTRING, tzload(), WRONG, and year_lengths.

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

00779 {
00780    const char *         stdname;
00781    const char *         dstname;
00782    size_t            stdlen;
00783    size_t            dstlen;
00784    long           stdoffset;
00785    long           dstoffset;
00786    time_t *    atp;
00787    unsigned char *   typep;
00788    char *         cp;
00789    int         load_result;
00790 
00791    INITIALIZE(dstname);
00792    stdname = name;
00793    if (lastditch) {
00794       stdlen = strlen(name);  /* length of standard zone name */
00795       name += stdlen;
00796       if (stdlen >= sizeof sp->chars)
00797          stdlen = (sizeof sp->chars) - 1;
00798       stdoffset = 0;
00799    } else {
00800       if (*name == '<') {
00801          name++;
00802          stdname = name;
00803          name = getqzname(name, '>');
00804          if (*name != '>')
00805             return WRONG;
00806          stdlen = name - stdname;
00807          name++;
00808       } else {
00809          name = getzname(name);
00810          stdlen = name - stdname;
00811       }
00812       if (*name == '\0')
00813          return WRONG;
00814       name = getoffset(name, &stdoffset);
00815       if (name == NULL)
00816          return WRONG;
00817    }
00818    load_result = tzload(TZDEFRULES, sp, FALSE);
00819    if (load_result != 0)
00820       sp->leapcnt = 0;     /* so, we're off a little */
00821    if (*name != '\0') {
00822       if (*name == '<') {
00823          dstname = ++name;
00824          name = getqzname(name, '>');
00825          if (*name != '>')
00826             return WRONG;
00827          dstlen = name - dstname;
00828          name++;
00829       } else {
00830          dstname = name;
00831          name = getzname(name);
00832          dstlen = name - dstname; /* length of DST zone name */
00833       }
00834       if (*name != '\0' && *name != ',' && *name != ';') {
00835          name = getoffset(name, &dstoffset);
00836          if (name == NULL)
00837             return WRONG;
00838       } else   dstoffset = stdoffset - SECSPERHOUR;
00839       if (*name == '\0' && load_result != 0)
00840          name = TZDEFRULESTRING;
00841       if (*name == ',' || *name == ';') {
00842          struct rule start;
00843          struct rule end;
00844          int   year;
00845          time_t   janfirst;
00846          time_t      starttime;
00847          time_t      endtime;
00848 
00849          ++name;
00850          if ((name = getrule(name, &start)) == NULL)
00851             return WRONG;
00852          if (*name++ != ',')
00853             return WRONG;
00854          if ((name = getrule(name, &end)) == NULL)
00855             return WRONG;
00856          if (*name != '\0')
00857             return WRONG;
00858          sp->typecnt = 2;  /* standard time and DST */
00859          /*
00860          ** Two transitions per year, from EPOCH_YEAR forward.
00861          */
00862          sp->ttis[0].tt_gmtoff = -dstoffset;
00863          sp->ttis[0].tt_isdst = 1;
00864          sp->ttis[0].tt_abbrind = stdlen + 1;
00865          sp->ttis[1].tt_gmtoff = -stdoffset;
00866          sp->ttis[1].tt_isdst = 0;
00867          sp->ttis[1].tt_abbrind = 0;
00868          atp = sp->ats;
00869          typep = sp->types;
00870          janfirst = 0;
00871          sp->timecnt = 0;
00872          for (year = EPOCH_YEAR;
00873              sp->timecnt + 2 <= TZ_MAX_TIMES;
00874              ++year) {
00875                time_t   newfirst;
00876 
00877             starttime = transtime(janfirst, year, &start,
00878                stdoffset);
00879             endtime = transtime(janfirst, year, &end,
00880                dstoffset);
00881             if (starttime > endtime) {
00882                *atp++ = endtime;
00883                *typep++ = 1;  /* DST ends */
00884                *atp++ = starttime;
00885                *typep++ = 0;  /* DST begins */
00886             } else {
00887                *atp++ = starttime;
00888                *typep++ = 0;  /* DST begins */
00889                *atp++ = endtime;
00890                *typep++ = 1;  /* DST ends */
00891             }
00892             sp->timecnt += 2;
00893             newfirst = janfirst;
00894             newfirst += year_lengths[isleap(year)] *
00895                SECSPERDAY;
00896             if (newfirst <= janfirst)
00897                break;
00898             janfirst = newfirst;
00899          }
00900       } else {
00901          long  theirstdoffset;
00902          long  theirdstoffset;
00903          long  theiroffset;
00904          int   isdst;
00905          int   i;
00906          int   j;
00907 
00908          if (*name != '\0')
00909             return WRONG;
00910          /*
00911          ** Initial values of theirstdoffset and theirdstoffset.
00912          */
00913          theirstdoffset = 0;
00914          for (i = 0; i < sp->timecnt; ++i) {
00915             j = sp->types[i];
00916             if (!sp->ttis[j].tt_isdst) {
00917                theirstdoffset =
00918                   -sp->ttis[j].tt_gmtoff;
00919                break;
00920             }
00921          }
00922          theirdstoffset = 0;
00923          for (i = 0; i < sp->timecnt; ++i) {
00924             j = sp->types[i];
00925             if (sp->ttis[j].tt_isdst) {
00926                theirdstoffset =
00927                   -sp->ttis[j].tt_gmtoff;
00928                break;
00929             }
00930          }
00931          /*
00932          ** Initially we're assumed to be in standard time.
00933          */
00934          isdst = FALSE;
00935          theiroffset = theirstdoffset;
00936          /*
00937          ** Now juggle transition times and types
00938          ** tracking offsets as you do.
00939          */
00940          for (i = 0; i < sp->timecnt; ++i) {
00941             j = sp->types[i];
00942             sp->types[i] = sp->ttis[j].tt_isdst;
00943             if (sp->ttis[j].tt_ttisgmt) {
00944                /* No adjustment to transition time */
00945             } else {
00946                /*
00947                ** If summer time is in effect, and the
00948                ** transition time was not specified as
00949                ** standard time, add the summer time
00950                ** offset to the transition time;
00951                ** otherwise, add the standard time
00952                ** offset to the transition time.
00953                */
00954                /*
00955                ** Transitions from DST to DDST
00956                ** will effectively disappear since
00957                ** POSIX provides for only one DST
00958                ** offset.
00959                */
00960                if (isdst && !sp->ttis[j].tt_ttisstd) {
00961                   sp->ats[i] += dstoffset -
00962                      theirdstoffset;
00963                } else {
00964                   sp->ats[i] += stdoffset -
00965                      theirstdoffset;
00966                }
00967             }
00968             theiroffset = -sp->ttis[j].tt_gmtoff;
00969             if (sp->ttis[j].tt_isdst)
00970                theirdstoffset = theiroffset;
00971             else  theirstdoffset = theiroffset;
00972          }
00973          /*
00974          ** Finally, fill in ttis.
00975          ** ttisstd and ttisgmt need not be handled.
00976          */
00977          sp->ttis[0].tt_gmtoff = -stdoffset;
00978          sp->ttis[0].tt_isdst = FALSE;
00979          sp->ttis[0].tt_abbrind = 0;
00980          sp->ttis[1].tt_gmtoff = -dstoffset;
00981          sp->ttis[1].tt_isdst = TRUE;
00982          sp->ttis[1].tt_abbrind = stdlen + 1;
00983          sp->typecnt = 2;
00984       }
00985    } else {
00986       dstlen = 0;
00987       sp->typecnt = 1;     /* only standard time */
00988       sp->timecnt = 0;
00989       sp->ttis[0].tt_gmtoff = -stdoffset;
00990       sp->ttis[0].tt_isdst = 0;
00991       sp->ttis[0].tt_abbrind = 0;
00992    }
00993    sp->charcnt = stdlen + 1;
00994    if (dstlen != 0)
00995       sp->charcnt += dstlen + 1;
00996    if ((size_t) sp->charcnt > sizeof sp->chars)
00997       return WRONG;
00998    cp = sp->chars;
00999    (void) strncpy(cp, stdname, stdlen);
01000    cp += stdlen;
01001    *cp++ = '\0';
01002    if (dstlen != 0) {
01003       (void) strncpy(cp, dstname, dstlen);
01004       *(cp + dstlen) = '\0';
01005    }
01006    return 0;
01007 }


Variable Documentation

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

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

const int year_lengths[2] [static]

Initial value:

Definition at line 501 of file localtime.c.

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


Generated on Fri Sep 25 19:28:38 2009 for Asterisk - the Open Source PBX by  doxygen 1.5.5