pidgin/purple-plugin-pack
Clone
Summary
Browse
Changes
Graph
fixed the crash on disconnect by closing conversation windows when that buddy is done with it's events, rather than when processing each event.
2009-08-30, Gary Kramlich
8ab9212b3ed3
fixed the crash on disconnect by closing conversation windows when that buddy is done with it's events, rather than when processing each event.
added status text support as a status of the stress
/*************************************************************************
* Timezone Module
* copied from the Olson Timezone code, licence unchanged.
* by Martijn van Oosterhout <kleptog@svana.org> April 2006
* Original Licence below (public domain).
*
* This code has been copied from the Olson Timezone code, but heavily
* adapted to meet my needs. In particular, you can load multiple timezones
* and specify which timezone to convert with.
*************************************************************************/
/*
** This file is in the public domain, so clarified as of
** 1996-06-05 by Arthur David Olson.
*/
#define TM_GMTOFF tm_gmtoff
#define TM_ZONE tm_zone
/*
** Leap second handling from Bradley White.
** POSIX-style TZ environment variable handling from Guy Harris.
*/
/*LINTLIBRARY*/
#include
"private.h"
#include
"tzfile.h"
#include
"fcntl.h"
#include
"float.h"
/* for FLT_MAX and DBL_MAX */
#ifndef TZ_ABBR_MAX_LEN
#define TZ_ABBR_MAX_LEN 16
#endif
/* !defined TZ_ABBR_MAX_LEN */
#ifndef TZ_ABBR_CHAR_SET
#define TZ_ABBR_CHAR_SET \
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 :+-._"
#endif
/* !defined TZ_ABBR_CHAR_SET */
#ifndef TZ_ABBR_ERR_CHAR
#define TZ_ABBR_ERR_CHAR '_'
#endif
/* !defined TZ_ABBR_ERR_CHAR */
/*
** SunOS 4.1.1 headers lack O_BINARY.
*/
#ifdef O_BINARY
#define OPEN_MODE (O_RDONLY | O_BINARY)
#endif
/* defined O_BINARY */
#ifndef O_BINARY
#define OPEN_MODE O_RDONLY
#endif
/* !defined O_BINARY */
#ifndef WILDABBR
/*
** Someone might make incorrect use of a time zone abbreviation:
** 1. They might reference tzname[0] before calling tzset (explicitly
** or implicitly).
** 2. They might reference tzname[1] before calling tzset (explicitly
** or implicitly).
** 3. They might reference tzname[1] after setting to a time zone
** in which Daylight Saving Time is never observed.
** 4. They might reference tzname[0] after setting to a time zone
** in which Standard Time is never observed.
** 5. They might reference tm.TM_ZONE after calling offtime.
** What's best to do in the above cases is open to debate;
** for now, we just set things up so that in any of the five cases
** WILDABBR is used. Another possibility: initialize tzname[0] to the
** string "tzname[0] used before set", and similarly for the other cases.
** And another: initialize tzname[0] to "ERA", with an explanation in the
** manual page of what this "time zone abbreviation" means (doing this so
** that tzname[0] has the "normal" length of three characters).
*/
#define WILDABBR " "
#endif
/* !defined WILDABBR */
static
char
wildabbr
[]
=
WILDABBR
;
static
const
char
gmt
[]
=
"GMT"
;
static
char
*
tzdir
;
/*
** 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.
*/
#ifndef TZDEFRULESTRING
#define TZDEFRULESTRING ",M4.1.0,M10.5.0"
#endif
/* !defined TZDEFDST */
struct
ttinfo
{
/* time type information */
long
tt_gmtoff
;
/* UTC offset in seconds */
int
tt_isdst
;
/* used to set tm_isdst */
int
tt_abbrind
;
/* abbreviation list index */
int
tt_ttisstd
;
/* TRUE if transition is std time */
int
tt_ttisgmt
;
/* TRUE if transition is UTC */
};
struct
lsinfo
{
/* leap second information */
time_t
ls_trans
;
/* transition time */
long
ls_corr
;
/* correction to apply */
};
#define BIGGEST(a, b) (((a) > (b)) ? (a) : (b))
#ifdef TZNAME_MAX
#define MY_TZNAME_MAX TZNAME_MAX
#endif
/* defined TZNAME_MAX */
#ifndef TZNAME_MAX
#define MY_TZNAME_MAX 255
#endif
/* !defined TZNAME_MAX */
struct
state
{
int
leapcnt
;
int
timecnt
;
int
typecnt
;
int
charcnt
;
time_t
ats
[
TZ_MAX_TIMES
];
unsigned
char
types
[
TZ_MAX_TIMES
];
struct
ttinfo
ttis
[
TZ_MAX_TYPES
];
char
chars
[
BIGGEST
(
BIGGEST
(
TZ_MAX_CHARS
+
1
,
sizeof
gmt
),
(
2
*
(
MY_TZNAME_MAX
+
1
)))];
struct
lsinfo
lsis
[
TZ_MAX_LEAPS
];
};
struct
rule
{
int
r_type
;
/* type of rule--see below */
int
r_day
;
/* day number of rule */
int
r_week
;
/* week number of rule */
int
r_mon
;
/* month number of rule */
long
r_time
;
/* transition time of rule */
};
#define JULIAN_DAY 0
/* Jn - Julian day */
#define DAY_OF_YEAR 1
/* n - day of year */
#define MONTH_NTH_DAY_OF_WEEK 2
/* Mm.n.d - month, week, day of week */
/*
** Prototypes for static functions.
*/
static
long
detzcode
P
((
const
char
*
codep
));
static
const
char
*
getzname
P
((
const
char
*
strp
));
static
const
char
*
getqzname
P
((
const
char
*
strp
,
const
char
delim
));
static
const
char
*
getnum
P
((
const
char
*
strp
,
int
*
nump
,
int
min
,
int
max
));
static
const
char
*
getsecs
P
((
const
char
*
strp
,
long
*
secsp
));
static
const
char
*
getoffset
P
((
const
char
*
strp
,
long
*
offsetp
));
static
const
char
*
getrule
P
((
const
char
*
strp
,
struct
rule
*
rulep
));
static
void
gmtload
P
((
struct
state
*
sp
));
struct
tm
*
gmtsub
P
((
const
time_t
*
timep
,
long
offset
,
struct
tm
*
tmp
));
struct
tm
*
localsub
P
((
const
time_t
*
timep
,
long
offset
,
struct
tm
*
tmp
,
struct
state
*
sp
));
static
int
increment_overflow
P
((
int
*
number
,
int
delta
));
static
int
leaps_thru_end_of
P
((
int
y
));
static
struct
tm
*
timesub
P
((
const
time_t
*
timep
,
long
offset
,
const
struct
state
*
sp
,
struct
tm
*
tmp
));
static
time_t
transtime
P
((
time_t
janfirst
,
int
year
,
const
struct
rule
*
rulep
,
long
offset
));
static
int
tzload
P
((
const
char
*
name
,
struct
state
*
sp
));
static
int
tzparse
P
((
const
char
*
name
,
struct
state
*
sp
,
int
lastditch
));
struct
state
*
timezone_load
P
((
const
char
*
name
));
#ifdef ALL_STATE
static
struct
state
*
gmtptr
;
#endif
/* defined ALL_STATE */
#ifndef ALL_STATE
static
struct
state
gmtmem
;
#define gmtptr (&gmtmem)
#endif
/* State Farm */
#ifndef TZ_STRLEN_MAX
#define TZ_STRLEN_MAX 255
#endif
/* !defined TZ_STRLEN_MAX */
//static char lcl_TZname[TZ_STRLEN_MAX + 1];
//static int lcl_is_set;
static
int
gmt_is_set
;
/*
** 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.
*/
//static struct tm tm;
#ifdef USG_COMPAT
time_t
timezone
=
0
;
int
daylight
=
0
;
#endif
/* defined USG_COMPAT */
#ifdef ALTZONE
time_t
altzone
=
0
;
#endif
/* defined ALTZONE */
static
long
detzcode
(
codep
)
const
char
*
const
codep
;
{
register
long
result
;
register
int
i
;
result
=
(
codep
[
0
]
&
0x80
)
?
~
0L
:
0L
;
for
(
i
=
0
;
i
<
4
;
++
i
)
result
=
(
result
<<
8
)
|
(
codep
[
i
]
&
0xff
);
return
result
;
}
static
int
tzload
(
name
,
sp
)
register
const
char
*
name
;
register
struct
state
*
const
sp
;
{
register
const
char
*
p
;
register
int
i
;
register
int
fid
;
if
(
name
==
NULL
&&
(
name
=
TZDEFAULT
)
==
NULL
)
return
-1
;
{
register
int
doaccess
;
/*
** Section 4.9.1 of the C standard says that
** "FILENAME_MAX expands to an integral constant expression
** that is the size needed for an array of char large enough
** to hold the longest file name string that the implementation
** guarantees can be opened."
*/
char
fullname
[
FILENAME_MAX
+
1
];
if
(
name
[
0
]
==
':'
)
++
name
;
doaccess
=
name
[
0
]
==
'/'
;
if
(
!
doaccess
)
{
if
((
p
=
tzdir
)
==
NULL
)
return
-1
;
if
((
strlen
(
p
)
+
strlen
(
name
)
+
1
)
>=
sizeof
fullname
)
return
-1
;
(
void
)
strcpy
(
fullname
,
p
);
(
void
)
strcat
(
fullname
,
"/"
);
(
void
)
strcat
(
fullname
,
name
);
/*
** Set doaccess if '.' (as in "../") shows up in name.
*/
if
(
strchr
(
name
,
'.'
)
!=
NULL
)
doaccess
=
TRUE
;
name
=
fullname
;
}
if
(
doaccess
&&
access
(
name
,
R_OK
)
!=
0
)
return
-1
;
if
((
fid
=
open
(
name
,
OPEN_MODE
))
==
-1
)
return
-1
;
}
{
struct
tzhead
*
tzhp
;
union
{
struct
tzhead
tzhead
;
char
buf
[
sizeof
*
sp
+
sizeof
*
tzhp
];
}
u
;
int
ttisstdcnt
;
int
ttisgmtcnt
;
i
=
read
(
fid
,
u
.
buf
,
sizeof
u
.
buf
);
if
(
close
(
fid
)
!=
0
)
return
-1
;
ttisstdcnt
=
(
int
)
detzcode
(
u
.
tzhead
.
tzh_ttisstdcnt
);
ttisgmtcnt
=
(
int
)
detzcode
(
u
.
tzhead
.
tzh_ttisgmtcnt
);
sp
->
leapcnt
=
(
int
)
detzcode
(
u
.
tzhead
.
tzh_leapcnt
);
sp
->
timecnt
=
(
int
)
detzcode
(
u
.
tzhead
.
tzh_timecnt
);
sp
->
typecnt
=
(
int
)
detzcode
(
u
.
tzhead
.
tzh_typecnt
);
sp
->
charcnt
=
(
int
)
detzcode
(
u
.
tzhead
.
tzh_charcnt
);
p
=
u
.
tzhead
.
tzh_charcnt
+
sizeof
u
.
tzhead
.
tzh_charcnt
;
if
(
sp
->
leapcnt
<
0
||
sp
->
leapcnt
>
TZ_MAX_LEAPS
||
sp
->
typecnt
<=
0
||
sp
->
typecnt
>
TZ_MAX_TYPES
||
sp
->
timecnt
<
0
||
sp
->
timecnt
>
TZ_MAX_TIMES
||
sp
->
charcnt
<
0
||
sp
->
charcnt
>
TZ_MAX_CHARS
||
(
ttisstdcnt
!=
sp
->
typecnt
&&
ttisstdcnt
!=
0
)
||
(
ttisgmtcnt
!=
sp
->
typecnt
&&
ttisgmtcnt
!=
0
))
return
-1
;
if
(
i
-
(
p
-
u
.
buf
)
<
sp
->
timecnt
*
4
+
/* ats */
sp
->
timecnt
+
/* types */
sp
->
typecnt
*
(
4
+
2
)
+
/* ttinfos */
sp
->
charcnt
+
/* chars */
sp
->
leapcnt
*
(
4
+
4
)
+
/* lsinfos */
ttisstdcnt
+
/* ttisstds */
ttisgmtcnt
)
/* ttisgmts */
return
-1
;
for
(
i
=
0
;
i
<
sp
->
timecnt
;
++
i
)
{
sp
->
ats
[
i
]
=
detzcode
(
p
);
p
+=
4
;
}
for
(
i
=
0
;
i
<
sp
->
timecnt
;
++
i
)
{
sp
->
types
[
i
]
=
(
unsigned
char
)
*
p
++
;
if
(
sp
->
types
[
i
]
>=
sp
->
typecnt
)
return
-1
;
}
for
(
i
=
0
;
i
<
sp
->
typecnt
;
++
i
)
{
register
struct
ttinfo
*
ttisp
;
ttisp
=
&
sp
->
ttis
[
i
];
ttisp
->
tt_gmtoff
=
detzcode
(
p
);
p
+=
4
;
ttisp
->
tt_isdst
=
(
unsigned
char
)
*
p
++
;
if
(
ttisp
->
tt_isdst
!=
0
&&
ttisp
->
tt_isdst
!=
1
)
return
-1
;
ttisp
->
tt_abbrind
=
(
unsigned
char
)
*
p
++
;
if
(
ttisp
->
tt_abbrind
<
0
||
ttisp
->
tt_abbrind
>
sp
->
charcnt
)
return
-1
;
}
for
(
i
=
0
;
i
<
sp
->
charcnt
;
++
i
)
sp
->
chars
[
i
]
=
*
p
++
;
sp
->
chars
[
i
]
=
'\0'
;
/* ensure '\0' at end */
for
(
i
=
0
;
i
<
sp
->
leapcnt
;
++
i
)
{
register
struct
lsinfo
*
lsisp
;
lsisp
=
&
sp
->
lsis
[
i
];
lsisp
->
ls_trans
=
detzcode
(
p
);
p
+=
4
;
lsisp
->
ls_corr
=
detzcode
(
p
);
p
+=
4
;
}
for
(
i
=
0
;
i
<
sp
->
typecnt
;
++
i
)
{
register
struct
ttinfo
*
ttisp
;
ttisp
=
&
sp
->
ttis
[
i
];
if
(
ttisstdcnt
==
0
)
ttisp
->
tt_ttisstd
=
FALSE
;
else
{
ttisp
->
tt_ttisstd
=
*
p
++
;
if
(
ttisp
->
tt_ttisstd
!=
TRUE
&&
ttisp
->
tt_ttisstd
!=
FALSE
)
return
-1
;
}
}
for
(
i
=
0
;
i
<
sp
->
typecnt
;
++
i
)
{
register
struct
ttinfo
*
ttisp
;
ttisp
=
&
sp
->
ttis
[
i
];
if
(
ttisgmtcnt
==
0
)
ttisp
->
tt_ttisgmt
=
FALSE
;
else
{
ttisp
->
tt_ttisgmt
=
*
p
++
;
if
(
ttisp
->
tt_ttisgmt
!=
TRUE
&&
ttisp
->
tt_ttisgmt
!=
FALSE
)
return
-1
;
}
}
/*
** Out-of-sort ats should mean we're running on a
** signed time_t system but using a data file with
** unsigned values (or vice versa).
*/
for
(
i
=
0
;
i
<
sp
->
timecnt
-
2
;
++
i
)
if
(
sp
->
ats
[
i
]
>
sp
->
ats
[
i
+
1
])
{
++
i
;
if
(
TYPE_SIGNED
(
time_t
))
{
/*
** Ignore the end (easy).
*/
sp
->
timecnt
=
i
;
}
else
{
/*
** Ignore the beginning (harder).
*/
register
int
j
;
for
(
j
=
0
;
j
+
i
<
sp
->
timecnt
;
++
j
)
{
sp
->
ats
[
j
]
=
sp
->
ats
[
j
+
i
];
sp
->
types
[
j
]
=
sp
->
types
[
j
+
i
];
}
sp
->
timecnt
=
j
;
}
break
;
}
}
return
0
;
}
struct
state
*
timezone_load
(
name
)
const
char
*
name
;
{
struct
state
*
sp
=
malloc
(
sizeof
(
struct
state
)
);
int
res
;
if
(
!
sp
)
return
NULL
;
res
=
tzload
(
name
,
sp
);
if
(
res
<
0
)
{
free
(
sp
);
return
NULL
;
}
return
sp
;
}
static
const
int
mon_lengths
[
2
][
MONSPERYEAR
]
=
{
{
31
,
28
,
31
,
30
,
31
,
30
,
31
,
31
,
30
,
31
,
30
,
31
},
{
31
,
29
,
31
,
30
,
31
,
30
,
31
,
31
,
30
,
31
,
30
,
31
}
};
static
const
int
year_lengths
[
2
]
=
{
DAYSPERNYEAR
,
DAYSPERLYEAR
};
/*
** 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
const
char
*
getzname
(
strp
)
register
const
char
*
strp
;
{
register
char
c
;
while
((
c
=
*
strp
)
!=
'\0'
&&
!
is_digit
(
c
)
&&
c
!=
','
&&
c
!=
'-'
&&
c
!=
'+'
)
++
strp
;
return
strp
;
}
/*
** 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 choose not to care - allowing almost anything to be in the zone abbrev.
*/
static
const
char
*
#if __STDC__
getqzname
(
register
const
char
*
strp
,
const
char
delim
)
#else
/* !__STDC__ */
getqzname
(
strp
,
delim
)
register
const
char
*
strp
;
const
char
delim
;
#endif
/* !__STDC__ */
{
register
char
c
;
while
((
c
=
*
strp
)
!=
'\0'
&&
c
!=
delim
)
++
strp
;
return
strp
;
}
/*
** 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
*
getnum
(
strp
,
nump
,
min
,
max
)
register
const
char
*
strp
;
int
*
const
nump
;
const
int
min
;
const
int
max
;
{
register
char
c
;
register
int
num
;
if
(
strp
==
NULL
||
!
is_digit
(
c
=
*
strp
))
return
NULL
;
num
=
0
;
do
{
num
=
num
*
10
+
(
c
-
'0'
);
if
(
num
>
max
)
return
NULL
;
/* illegal value */
c
=
*++
strp
;
}
while
(
is_digit
(
c
));
if
(
num
<
min
)
return
NULL
;
/* illegal value */
*
nump
=
num
;
return
strp
;
}
/*
** 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
*
getsecs
(
strp
,
secsp
)
register
const
char
*
strp
;
long
*
const
secsp
;
{
int
num
;
/*
** `HOURSPERDAY * DAYSPERWEEK - 1' allows quasi-Posix rules like
** "M10.4.6/26", which does not conform to Posix,
** but which specifies the equivalent of
** ``02:00 on the first Sunday on or after 23 Oct''.
*/
strp
=
getnum
(
strp
,
&
num
,
0
,
HOURSPERDAY
*
DAYSPERWEEK
-
1
);
if
(
strp
==
NULL
)
return
NULL
;
*
secsp
=
num
*
(
long
)
SECSPERHOUR
;
if
(
*
strp
==
':'
)
{
++
strp
;
strp
=
getnum
(
strp
,
&
num
,
0
,
MINSPERHOUR
-
1
);
if
(
strp
==
NULL
)
return
NULL
;
*
secsp
+=
num
*
SECSPERMIN
;
if
(
*
strp
==
':'
)
{
++
strp
;
/* `SECSPERMIN' allows for leap seconds. */
strp
=
getnum
(
strp
,
&
num
,
0
,
SECSPERMIN
);
if
(
strp
==
NULL
)
return
NULL
;
*
secsp
+=
num
;
}
}
return
strp
;
}
/*
** 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
*
getoffset
(
strp
,
offsetp
)
register
const
char
*
strp
;
long
*
const
offsetp
;
{
register
int
neg
=
0
;
if
(
*
strp
==
'-'
)
{
neg
=
1
;
++
strp
;
}
else
if
(
*
strp
==
'+'
)
++
strp
;
strp
=
getsecs
(
strp
,
offsetp
);
if
(
strp
==
NULL
)
return
NULL
;
/* illegal time */
if
(
neg
)
*
offsetp
=
-*
offsetp
;
return
strp
;
}
/*
** 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
*
getrule
(
strp
,
rulep
)
const
char
*
strp
;
register
struct
rule
*
const
rulep
;
{
if
(
*
strp
==
'J'
)
{
/*
** Julian day.
*/
rulep
->
r_type
=
JULIAN_DAY
;
++
strp
;
strp
=
getnum
(
strp
,
&
rulep
->
r_day
,
1
,
DAYSPERNYEAR
);
}
else
if
(
*
strp
==
'M'
)
{
/*
** Month, week, day.
*/
rulep
->
r_type
=
MONTH_NTH_DAY_OF_WEEK
;
++
strp
;
strp
=
getnum
(
strp
,
&
rulep
->
r_mon
,
1
,
MONSPERYEAR
);
if
(
strp
==
NULL
)
return
NULL
;
if
(
*
strp
++
!=
'.'
)
return
NULL
;
strp
=
getnum
(
strp
,
&
rulep
->
r_week
,
1
,
5
);
if
(
strp
==
NULL
)
return
NULL
;
if
(
*
strp
++
!=
'.'
)
return
NULL
;
strp
=
getnum
(
strp
,
&
rulep
->
r_day
,
0
,
DAYSPERWEEK
-
1
);
}
else
if
(
is_digit
(
*
strp
))
{
/*
** Day of year.
*/
rulep
->
r_type
=
DAY_OF_YEAR
;
strp
=
getnum
(
strp
,
&
rulep
->
r_day
,
0
,
DAYSPERLYEAR
-
1
);
}
else
return
NULL
;
/* invalid format */
if
(
strp
==
NULL
)
return
NULL
;
if
(
*
strp
==
'/'
)
{
/*
** Time specified.
*/
++
strp
;
strp
=
getsecs
(
strp
,
&
rulep
->
r_time
);
}
else
rulep
->
r_time
=
2
*
SECSPERHOUR
;
/* default = 2:00:00 */
return
strp
;
}
/*
** 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
time_t
transtime
(
janfirst
,
year
,
rulep
,
offset
)
const
time_t
janfirst
;
const
int
year
;
register
const
struct
rule
*
const
rulep
;
const
long
offset
;
{
register
int
leapyear
;
register
time_t
value
;
register
int
i
;
int
d
,
m1
,
yy0
,
yy1
,
yy2
,
dow
;
INITIALIZE
(
value
);
leapyear
=
isleap
(
year
);
switch
(
rulep
->
r_type
)
{
case
JULIAN_DAY
:
/*
** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap
** years.
** In non-leap years, or if the day number is 59 or less, just
** add SECSPERDAY times the day number-1 to the time of
** January 1, midnight, to get the day.
*/
value
=
janfirst
+
(
rulep
->
r_day
-
1
)
*
SECSPERDAY
;
if
(
leapyear
&&
rulep
->
r_day
>=
60
)
value
+=
SECSPERDAY
;
break
;
case
DAY_OF_YEAR
:
/*
** n - day of year.
** Just add SECSPERDAY times the day number to the time of
** January 1, midnight, to get the day.
*/
value
=
janfirst
+
rulep
->
r_day
*
SECSPERDAY
;
break
;
case
MONTH_NTH_DAY_OF_WEEK
:
/*
** Mm.n.d - nth "dth day" of month m.
*/
value
=
janfirst
;
for
(
i
=
0
;
i
<
rulep
->
r_mon
-
1
;
++
i
)
value
+=
mon_lengths
[
leapyear
][
i
]
*
SECSPERDAY
;
/*
** Use Zeller's Congruence to get day-of-week of first day of
** month.
*/
m1
=
(
rulep
->
r_mon
+
9
)
%
12
+
1
;
yy0
=
(
rulep
->
r_mon
<=
2
)
?
(
year
-
1
)
:
year
;
yy1
=
yy0
/
100
;
yy2
=
yy0
%
100
;
dow
=
((
26
*
m1
-
2
)
/
10
+
1
+
yy2
+
yy2
/
4
+
yy1
/
4
-
2
*
yy1
)
%
7
;
if
(
dow
<
0
)
dow
+=
DAYSPERWEEK
;
/*
** "dow" is the day-of-week of the first day of the month. Get
** the day-of-month (zero-origin) of the first "dow" day of the
** month.
*/
d
=
rulep
->
r_day
-
dow
;
if
(
d
<
0
)
d
+=
DAYSPERWEEK
;
for
(
i
=
1
;
i
<
rulep
->
r_week
;
++
i
)
{
if
(
d
+
DAYSPERWEEK
>=
mon_lengths
[
leapyear
][
rulep
->
r_mon
-
1
])
break
;
d
+=
DAYSPERWEEK
;
}
/*
** "d" is the day-of-month (zero-origin) of the day we want.
*/
value
+=
d
*
SECSPERDAY
;
break
;
}
/*
** "value" is the Epoch-relative time of 00:00:00 UTC on the day in
** question. To get the Epoch-relative time of the specified local
** time on that day, add the transition time and the current offset
** from UTC.
*/
return
value
+
rulep
->
r_time
+
offset
;
}
/*
** Given a POSIX section 8-style TZ string, fill in the rule tables as
** appropriate.
*/
static
int
tzparse
(
name
,
sp
,
lastditch
)
const
char
*
name
;
register
struct
state
*
const
sp
;
const
int
lastditch
;
{
const
char
*
stdname
;
const
char
*
dstname
;
size_t
stdlen
;
size_t
dstlen
;
long
stdoffset
;
long
dstoffset
;
register
time_t
*
atp
;
register
unsigned
char
*
typep
;
register
char
*
cp
;
register
int
load_result
;
INITIALIZE
(
dstname
);
stdname
=
name
;
if
(
lastditch
)
{
stdlen
=
strlen
(
name
);
/* length of standard zone name */
name
+=
stdlen
;
if
(
stdlen
>=
sizeof
sp
->
chars
)
stdlen
=
(
sizeof
sp
->
chars
)
-
1
;
stdoffset
=
0
;
}
else
{
if
(
*
name
==
'<'
)
{
name
++
;
stdname
=
name
;
name
=
getqzname
(
name
,
'>'
);
if
(
*
name
!=
'>'
)
return
(
-1
);
stdlen
=
name
-
stdname
;
name
++
;
}
else
{
name
=
getzname
(
name
);
stdlen
=
name
-
stdname
;
}
if
(
*
name
==
'\0'
)
return
-1
;
name
=
getoffset
(
name
,
&
stdoffset
);
if
(
name
==
NULL
)
return
-1
;
}
load_result
=
tzload
(
TZDEFRULES
,
sp
);
if
(
load_result
!=
0
)
sp
->
leapcnt
=
0
;
/* so, we're off a little */
if
(
*
name
!=
'\0'
)
{
if
(
*
name
==
'<'
)
{
dstname
=
++
name
;
name
=
getqzname
(
name
,
'>'
);
if
(
*
name
!=
'>'
)
return
-1
;
dstlen
=
name
-
dstname
;
name
++
;
}
else
{
dstname
=
name
;
name
=
getzname
(
name
);
dstlen
=
name
-
dstname
;
/* length of DST zone name */
}
if
(
*
name
!=
'\0'
&&
*
name
!=
','
&&
*
name
!=
';'
)
{
name
=
getoffset
(
name
,
&
dstoffset
);
if
(
name
==
NULL
)
return
-1
;
}
else
dstoffset
=
stdoffset
-
SECSPERHOUR
;
if
(
*
name
==
'\0'
&&
load_result
!=
0
)
name
=
TZDEFRULESTRING
;
if
(
*
name
==
','
||
*
name
==
';'
)
{
struct
rule
start
;
struct
rule
end
;
register
int
year
;
register
time_t
janfirst
;
time_t
starttime
;
time_t
endtime
;
++
name
;
if
((
name
=
getrule
(
name
,
&
start
))
==
NULL
)
return
-1
;
if
(
*
name
++
!=
','
)
return
-1
;
if
((
name
=
getrule
(
name
,
&
end
))
==
NULL
)
return
-1
;
if
(
*
name
!=
'\0'
)
return
-1
;
sp
->
typecnt
=
2
;
/* standard time and DST */
/*
** Two transitions per year, from EPOCH_YEAR to 2037.
*/
sp
->
timecnt
=
2
*
(
2037
-
EPOCH_YEAR
+
1
);
if
(
sp
->
timecnt
>
TZ_MAX_TIMES
)
return
-1
;
sp
->
ttis
[
0
].
tt_gmtoff
=
-
dstoffset
;
sp
->
ttis
[
0
].
tt_isdst
=
1
;
sp
->
ttis
[
0
].
tt_abbrind
=
stdlen
+
1
;
sp
->
ttis
[
1
].
tt_gmtoff
=
-
stdoffset
;
sp
->
ttis
[
1
].
tt_isdst
=
0
;
sp
->
ttis
[
1
].
tt_abbrind
=
0
;
atp
=
sp
->
ats
;
typep
=
sp
->
types
;
janfirst
=
0
;
for
(
year
=
EPOCH_YEAR
;
year
<=
2037
;
++
year
)
{
starttime
=
transtime
(
janfirst
,
year
,
&
start
,
stdoffset
);
endtime
=
transtime
(
janfirst
,
year
,
&
end
,
dstoffset
);
if
(
starttime
>
endtime
)
{
*
atp
++
=
endtime
;
*
typep
++
=
1
;
/* DST ends */
*
atp
++
=
starttime
;
*
typep
++
=
0
;
/* DST begins */
}
else
{
*
atp
++
=
starttime
;
*
typep
++
=
0
;
/* DST begins */
*
atp
++
=
endtime
;
*
typep
++
=
1
;
/* DST ends */
}
janfirst
+=
year_lengths
[
isleap
(
year
)]
*
SECSPERDAY
;
}
}
else
{
register
long
theirstdoffset
;
register
long
theirdstoffset
;
register
long
theiroffset
;
register
int
isdst
;
register
int
i
;
register
int
j
;
if
(
*
name
!=
'\0'
)
return
-1
;
/*
** Initial values of theirstdoffset and theirdstoffset.
*/
theirstdoffset
=
0
;
for
(
i
=
0
;
i
<
sp
->
timecnt
;
++
i
)
{
j
=
sp
->
types
[
i
];
if
(
!
sp
->
ttis
[
j
].
tt_isdst
)
{
theirstdoffset
=
-
sp
->
ttis
[
j
].
tt_gmtoff
;
break
;
}
}
theirdstoffset
=
0
;
for
(
i
=
0
;
i
<
sp
->
timecnt
;
++
i
)
{
j
=
sp
->
types
[
i
];
if
(
sp
->
ttis
[
j
].
tt_isdst
)
{
theirdstoffset
=
-
sp
->
ttis
[
j
].
tt_gmtoff
;
break
;
}
}
/*
** Initially we're assumed to be in standard time.
*/
isdst
=
FALSE
;
theiroffset
=
theirstdoffset
;
/*
** Now juggle transition times and types
** tracking offsets as you do.
*/
for
(
i
=
0
;
i
<
sp
->
timecnt
;
++
i
)
{
j
=
sp
->
types
[
i
];
sp
->
types
[
i
]
=
sp
->
ttis
[
j
].
tt_isdst
;
if
(
sp
->
ttis
[
j
].
tt_ttisgmt
)
{
/* No adjustment to transition time */
}
else
{
/*
** If summer time is in effect, and the
** transition time was not specified as
** standard time, add the summer time
** offset to the transition time;
** otherwise, add the standard time
** offset to the transition time.
*/
/*
** Transitions from DST to DDST
** will effectively disappear since
** POSIX provides for only one DST
** offset.
*/
if
(
isdst
&&
!
sp
->
ttis
[
j
].
tt_ttisstd
)
{
sp
->
ats
[
i
]
+=
dstoffset
-
theirdstoffset
;
}
else
{
sp
->
ats
[
i
]
+=
stdoffset
-
theirstdoffset
;
}
}
theiroffset
=
-
sp
->
ttis
[
j
].
tt_gmtoff
;
if
(
sp
->
ttis
[
j
].
tt_isdst
)
theirdstoffset
=
theiroffset
;
else
theirstdoffset
=
theiroffset
;
}
/*
** Finally, fill in ttis.
** ttisstd and ttisgmt need not be handled.
*/
sp
->
ttis
[
0
].
tt_gmtoff
=
-
stdoffset
;
sp
->
ttis
[
0
].
tt_isdst
=
FALSE
;
sp
->
ttis
[
0
].
tt_abbrind
=
0
;
sp
->
ttis
[
1
].
tt_gmtoff
=
-
dstoffset
;
sp
->
ttis
[
1
].
tt_isdst
=
TRUE
;
sp
->
ttis
[
1
].
tt_abbrind
=
stdlen
+
1
;
sp
->
typecnt
=
2
;
}
}
else
{
dstlen
=
0
;
sp
->
typecnt
=
1
;
/* only standard time */
sp
->
timecnt
=
0
;
sp
->
ttis
[
0
].
tt_gmtoff
=
-
stdoffset
;
sp
->
ttis
[
0
].
tt_isdst
=
0
;
sp
->
ttis
[
0
].
tt_abbrind
=
0
;
}
sp
->
charcnt
=
stdlen
+
1
;
if
(
dstlen
!=
0
)
sp
->
charcnt
+=
dstlen
+
1
;
if
((
size_t
)
sp
->
charcnt
>
sizeof
sp
->
chars
)
return
-1
;
cp
=
sp
->
chars
;
(
void
)
strncpy
(
cp
,
stdname
,
stdlen
);
cp
+=
stdlen
;
*
cp
++
=
'\0'
;
if
(
dstlen
!=
0
)
{
(
void
)
strncpy
(
cp
,
dstname
,
dstlen
);
*
(
cp
+
dstlen
)
=
'\0'
;
}
return
0
;
}
static
void
gmtload
(
sp
)
struct
state
*
const
sp
;
{
if
(
tzload
(
gmt
,
sp
)
!=
0
)
(
void
)
tzparse
(
gmt
,
sp
,
TRUE
);
}
/*
** 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.
*/
struct
tm
*
localsub
(
timep
,
offset
,
tmp
,
sp
)
const
time_t
*
const
timep
;
const
long
offset
;
struct
tm
*
const
tmp
;
struct
state
*
sp
;
{
register
const
struct
ttinfo
*
ttisp
;
register
int
i
;
register
struct
tm
*
result
;
const
time_t
t
=
*
timep
;
#ifdef ALL_STATE
if
(
sp
==
NULL
)
return
gmtsub
(
timep
,
offset
,
tmp
);
#endif
/* defined ALL_STATE */
if
(
sp
->
timecnt
==
0
||
t
<
sp
->
ats
[
0
])
{
i
=
0
;
while
(
sp
->
ttis
[
i
].
tt_isdst
)
if
(
++
i
>=
sp
->
typecnt
)
{
i
=
0
;
break
;
}
}
else
{
for
(
i
=
1
;
i
<
sp
->
timecnt
;
++
i
)
if
(
t
<
sp
->
ats
[
i
])
break
;
i
=
(
int
)
sp
->
types
[
i
-
1
];
}
ttisp
=
&
sp
->
ttis
[
i
];
/*
** To get (wrong) behavior that's compatible with System V Release 2.0
** you'd replace the statement below with
** t += ttisp->tt_gmtoff;
** timesub(&t, 0L, sp, tmp);
*/
result
=
timesub
(
&
t
,
ttisp
->
tt_gmtoff
,
sp
,
tmp
);
tmp
->
tm_isdst
=
ttisp
->
tt_isdst
;
tzname
[
tmp
->
tm_isdst
]
=
&
sp
->
chars
[
ttisp
->
tt_abbrind
];
#ifdef TM_ZONE
tmp
->
TM_ZONE
=
&
sp
->
chars
[
ttisp
->
tt_abbrind
];
#endif
/* defined TM_ZONE */
return
result
;
}
/*
** gmtsub is to gmtime as localsub is to localtime.
*/
struct
tm
*
gmtsub
(
timep
,
offset
,
tmp
)
const
time_t
*
const
timep
;
const
long
offset
;
struct
tm
*
const
tmp
;
{
register
struct
tm
*
result
;
if
(
!
gmt_is_set
)
{
gmt_is_set
=
TRUE
;
#ifdef ALL_STATE
gmtptr
=
(
struct
state
*
)
malloc
(
sizeof
*
gmtptr
);
if
(
gmtptr
!=
NULL
)
#endif
/* defined ALL_STATE */
gmtload
(
gmtptr
);
}
result
=
timesub
(
timep
,
offset
,
gmtptr
,
tmp
);
#ifdef TM_ZONE
/*
** Could get fancy here and deliver something such as
** "UTC+xxxx" or "UTC-xxxx" if offset is non-zero,
** but this is no time for a treasure hunt.
*/
if
(
offset
!=
0
)
tmp
->
TM_ZONE
=
wildabbr
;
else
{
#ifdef ALL_STATE
if
(
gmtptr
==
NULL
)
tmp
->
TM_ZONE
=
gmt
;
else
tmp
->
TM_ZONE
=
gmtptr
->
chars
;
#endif
/* defined ALL_STATE */
#ifndef ALL_STATE
tmp
->
TM_ZONE
=
gmtptr
->
chars
;
#endif
/* State Farm */
}
#endif
/* defined TM_ZONE */
return
result
;
}
/*
** 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
int
leaps_thru_end_of
(
y
)
register
const
int
y
;
{
return
(
y
>=
0
)
?
(
y
/
4
-
y
/
100
+
y
/
400
)
:
-
(
leaps_thru_end_of
(
-
(
y
+
1
))
+
1
);
}
static
struct
tm
*
timesub
(
timep
,
offset
,
sp
,
tmp
)
const
time_t
*
const
timep
;
const
long
offset
;
register
const
struct
state
*
const
sp
;
register
struct
tm
*
const
tmp
;
{
register
const
struct
lsinfo
*
lp
;
register
time_t
tdays
;
register
int
idays
;
/* unsigned would be so 2003 */
register
long
rem
;
int
y
;
register
const
int
*
ip
;
register
long
corr
;
register
int
hit
;
register
int
i
;
corr
=
0
;
hit
=
0
;
#ifdef ALL_STATE
i
=
(
sp
==
NULL
)
?
0
:
sp
->
leapcnt
;
#endif
/* defined ALL_STATE */
#ifndef ALL_STATE
i
=
sp
->
leapcnt
;
#endif
/* State Farm */
while
(
--
i
>=
0
)
{
lp
=
&
sp
->
lsis
[
i
];
if
(
*
timep
>=
lp
->
ls_trans
)
{
if
(
*
timep
==
lp
->
ls_trans
)
{
hit
=
((
i
==
0
&&
lp
->
ls_corr
>
0
)
||
lp
->
ls_corr
>
sp
->
lsis
[
i
-
1
].
ls_corr
);
if
(
hit
)
while
(
i
>
0
&&
sp
->
lsis
[
i
].
ls_trans
==
sp
->
lsis
[
i
-
1
].
ls_trans
+
1
&&
sp
->
lsis
[
i
].
ls_corr
==
sp
->
lsis
[
i
-
1
].
ls_corr
+
1
)
{
++
hit
;
--
i
;
}
}
corr
=
lp
->
ls_corr
;
break
;
}
}
y
=
EPOCH_YEAR
;
tdays
=
*
timep
/
SECSPERDAY
;
rem
=
*
timep
-
tdays
*
SECSPERDAY
;
while
(
tdays
<
0
||
tdays
>=
year_lengths
[
isleap
(
y
)])
{
int
newy
;
register
time_t
tdelta
;
register
int
idelta
;
register
int
leapdays
;
tdelta
=
tdays
/
DAYSPERLYEAR
;
idelta
=
tdelta
;
if
(
tdelta
-
idelta
>=
1
||
idelta
-
tdelta
>=
1
)
return
NULL
;
if
(
idelta
==
0
)
idelta
=
(
tdays
<
0
)
?
-1
:
1
;
newy
=
y
;
if
(
increment_overflow
(
&
newy
,
idelta
))
return
NULL
;
leapdays
=
leaps_thru_end_of
(
newy
-
1
)
-
leaps_thru_end_of
(
y
-
1
);
tdays
-=
((
time_t
)
newy
-
y
)
*
DAYSPERNYEAR
;
tdays
-=
leapdays
;
y
=
newy
;
}
{
register
long
seconds
;
seconds
=
tdays
*
SECSPERDAY
+
0.5
;
tdays
=
seconds
/
SECSPERDAY
;
rem
+=
seconds
-
tdays
*
SECSPERDAY
;
}
/*
** Given the range, we can now fearlessly cast...
*/
idays
=
tdays
;
rem
+=
offset
-
corr
;
while
(
rem
<
0
)
{
rem
+=
SECSPERDAY
;
--
idays
;
}
while
(
rem
>=
SECSPERDAY
)
{
rem
-=
SECSPERDAY
;
++
idays
;
}
while
(
idays
<
0
)
{
if
(
increment_overflow
(
&
y
,
-1
))
return
NULL
;
idays
+=
year_lengths
[
isleap
(
y
)];
}
while
(
idays
>=
year_lengths
[
isleap
(
y
)])
{
idays
-=
year_lengths
[
isleap
(
y
)];
if
(
increment_overflow
(
&
y
,
1
))
return
NULL
;
}
tmp
->
tm_year
=
y
;
if
(
increment_overflow
(
&
tmp
->
tm_year
,
-
TM_YEAR_BASE
))
return
NULL
;
tmp
->
tm_yday
=
idays
;
/*
** The "extra" mods below avoid overflow problems.
*/
tmp
->
tm_wday
=
EPOCH_WDAY
+
((
y
-
EPOCH_YEAR
)
%
DAYSPERWEEK
)
*
(
DAYSPERNYEAR
%
DAYSPERWEEK
)
+
leaps_thru_end_of
(
y
-
1
)
-
leaps_thru_end_of
(
EPOCH_YEAR
-
1
)
+
idays
;
tmp
->
tm_wday
%=
DAYSPERWEEK
;
if
(
tmp
->
tm_wday
<
0
)
tmp
->
tm_wday
+=
DAYSPERWEEK
;
tmp
->
tm_hour
=
(
int
)
(
rem
/
SECSPERHOUR
);
rem
%=
SECSPERHOUR
;
tmp
->
tm_min
=
(
int
)
(
rem
/
SECSPERMIN
);
/*
** A positive leap second requires a special
** representation. This uses "... ??:59:60" et seq.
*/
tmp
->
tm_sec
=
(
int
)
(
rem
%
SECSPERMIN
)
+
hit
;
ip
=
mon_lengths
[
isleap
(
y
)];
for
(
tmp
->
tm_mon
=
0
;
idays
>=
ip
[
tmp
->
tm_mon
];
++
(
tmp
->
tm_mon
))
idays
-=
ip
[
tmp
->
tm_mon
];
tmp
->
tm_mday
=
(
int
)
(
idays
+
1
);
tmp
->
tm_isdst
=
0
;
#ifdef TM_GMTOFF
tmp
->
TM_GMTOFF
=
offset
;
#endif
/* defined TM_GMTOFF */
return
tmp
;
}
/*
** 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).
*/
#ifndef WRONG
#define WRONG (-1)
#endif
/* !defined WRONG */
/*
** Simplified normalize logic courtesy Paul Eggert.
*/
static
int
increment_overflow
(
number
,
delta
)
int
*
number
;
int
delta
;
{
int
number0
;
number0
=
*
number
;
*
number
+=
delta
;
return
(
*
number
<
number0
)
!=
(
delta
<
0
);
}
int
tz_init
(
const
char
*
zoneinfo_dir
)
{
char
*
ptr
;
int
fd
;
if
(
zoneinfo_dir
==
NULL
)
zoneinfo_dir
=
TZDIR
;
ptr
=
malloc
(
strlen
(
zoneinfo_dir
)
+
10
);
sprintf
(
ptr
,
"%s/zone.tab"
,
zoneinfo_dir
);
fd
=
open
(
ptr
,
O_RDONLY
);
free
(
ptr
);
if
(
fd
<
0
)
return
-1
;
close
(
fd
);
if
(
tzdir
)
free
(
tzdir
);
tzdir
=
strdup
(
zoneinfo_dir
);
return
0
;
}