Skip to content
项目
群组
代码片段
帮助
正在加载...
登录
切换导航
F
freeswitch
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
分枝图
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
分枝图
统计图
创建新议题
作业
提交
议题看板
打开侧边栏
张华
freeswitch
Commits
a5a6d6a6
提交
a5a6d6a6
authored
7月 24, 2010
作者:
cypromis
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
got rid of crlf windows endings on timezone.c
上级
17a0f628
隐藏空白字符变更
内嵌
并排
正在显示
1 个修改的文件
包含
822 行增加
和
822 行删除
+822
-822
timezone.c
libs/spandsp/src/timezone.c
+822
-822
没有找到文件。
libs/spandsp/src/timezone.c
浏览文件 @
a5a6d6a6
/*
/*
* SpanDSP - a series of DSP components for telephony
* SpanDSP - a series of DSP components for telephony
*
*
* timezone.c - Timezone handling for time interpretation
* timezone.c - Timezone handling for time interpretation
*
*
* Written by Steve Underwood <steveu@coppice.org>
* Written by Steve Underwood <steveu@coppice.org>
*
*
* Copyright (C) 2010 Steve Underwood
* Copyright (C) 2010 Steve Underwood
*
*
* All rights reserved.
* All rights reserved.
*
*
* This program is free software; you can redistribute it and/or modify
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1,
* it under the terms of the GNU Lesser General Public License version 2.1,
* as published by the Free Software Foundation.
* as published by the Free Software Foundation.
*
*
* This program is distributed in the hope that it will be useful,
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
* GNU Lesser General Public License for more details.
*
*
* You should have received a copy of the GNU Lesser General Public
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
*/
/*! \file */
/*! \file */
/* Timezone processing might not seem like a DSP activity, but getting the headers
/* Timezone processing might not seem like a DSP activity, but getting the headers
right on FAXes demands it. We need to handle multiple time zones within a process,
right on FAXes demands it. We need to handle multiple time zones within a process,
for FAXes related to different parts of the globe, so the system timezone handling
for FAXes related to different parts of the globe, so the system timezone handling
is not adequate. */
is not adequate. */
/* This timezone handling is derived from public domain software by Arthur David Olson
/* This timezone handling is derived from public domain software by Arthur David Olson
<arthur_david_olson@nih.gov> which you may download from ftp://elsie.nci.nih.gov/pub
<arthur_david_olson@nih.gov> which you may download from ftp://elsie.nci.nih.gov/pub
at the time of writing. */
at the time of writing. */
#if defined(HAVE_CONFIG_H)
#if defined(HAVE_CONFIG_H)
#include "config.h"
#include "config.h"
#endif
#endif
#include <stdlib.h>
#include <stdlib.h>
#include <inttypes.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdio.h>
#include <string.h>
#include <string.h>
#include <time.h>
#include <time.h>
#include <stdlib.h>
#include <stdlib.h>
#include <assert.h>
#include <assert.h>
#include "spandsp/telephony.h"
#include "spandsp/telephony.h"
#include "spandsp/timezone.h"
#include "spandsp/timezone.h"
#include "spandsp/private/timezone.h"
#include "spandsp/private/timezone.h"
#if !defined(FALSE)
#if !defined(FALSE)
#define FALSE 0
#define FALSE 0
#endif
#endif
#if !defined(TRUE)
#if !defined(TRUE)
#define TRUE (!FALSE)
#define TRUE (!FALSE)
#endif
#endif
#define SECS_PER_MIN 60
#define SECS_PER_MIN 60
#define MINS_PER_HOUR 60
#define MINS_PER_HOUR 60
#define HOURS_PER_DAY 24
#define HOURS_PER_DAY 24
#define DAYS_PER_WEEK 7
#define DAYS_PER_WEEK 7
#define DAYS_PER_NON_LEAP_YEAR 365
#define DAYS_PER_NON_LEAP_YEAR 365
#define DAYS_PER_LEAP_YEAR 366
#define DAYS_PER_LEAP_YEAR 366
#define SECS_PER_HOUR (SECS_PER_MIN*MINS_PER_HOUR)
#define SECS_PER_HOUR (SECS_PER_MIN*MINS_PER_HOUR)
#define SECS_PER_DAY ((long int) SECS_PER_HOUR*HOURS_PER_DAY)
#define SECS_PER_DAY ((long int) SECS_PER_HOUR*HOURS_PER_DAY)
#define MONTHS_PER_YEAR 12
#define MONTHS_PER_YEAR 12
#define TM_YEAR_BASE 1900
#define TM_YEAR_BASE 1900
#define EPOCH_YEAR 1970
#define EPOCH_YEAR 1970
#define EPOCH_WDAY TM_THURSDAY
#define EPOCH_WDAY TM_THURSDAY
#define isleap(y) (((y)%4) == 0 && (((y)%100) != 0 || ((y)%400) == 0))
#define isleap(y) (((y)%4) == 0 && (((y)%100) != 0 || ((y)%400) == 0))
#define isleap_sum(a, b) isleap((a)%400 + (b)%400)
#define isleap_sum(a, b) isleap((a)%400 + (b)%400)
/* Unlike <ctype.h>'s isdigit, this also works if c < 0 | c > UCHAR_MAX. */
/* Unlike <ctype.h>'s isdigit, this also works if c < 0 | c > UCHAR_MAX. */
#define is_digit(c) ((unsigned int) (c) - '0' <= 9)
#define is_digit(c) ((unsigned int) (c) - '0' <= 9)
#define TZ_DEF_RULE_STRING ",M4.1.0,M10.5.0"
#define TZ_DEF_RULE_STRING ",M4.1.0,M10.5.0"
#define JULIAN_DAY 0
/* Jn - Julian day */
#define JULIAN_DAY 0
/* Jn - Julian day */
#define DAY_OF_YEAR 1
/* n - day of year */
#define DAY_OF_YEAR 1
/* n - day of year */
#define MONTH_NTH_DAY_OF_WEEK 2
/* Mm.n.d - month, week, day of week */
#define MONTH_NTH_DAY_OF_WEEK 2
/* Mm.n.d - month, week, day of week */
static
const
char
wildabbr
[]
=
" "
;
static
const
char
wildabbr
[]
=
" "
;
static
const
char
gmt
[]
=
"GMT"
;
static
const
char
gmt
[]
=
"GMT"
;
struct
tz_rule_s
struct
tz_rule_s
{
{
int
r_type
;
/* Type of rule--see below */
int
r_type
;
/* Type of rule--see below */
int
r_day
;
/* Day number of rule */
int
r_day
;
/* Day number of rule */
int
r_week
;
/* Week number of rule */
int
r_week
;
/* Week number of rule */
int
r_mon
;
/* Month number of rule */
int
r_mon
;
/* Month number of rule */
long
int
r_time
;
/* Transition time of rule */
long
int
r_time
;
/* Transition time of rule */
};
};
static
const
int
mon_lengths
[
2
][
MONTHS_PER_YEAR
]
=
static
const
int
mon_lengths
[
2
][
MONTHS_PER_YEAR
]
=
{
{
{
31
,
28
,
31
,
30
,
31
,
30
,
31
,
31
,
30
,
31
,
30
,
31
},
{
31
,
28
,
31
,
30
,
31
,
30
,
31
,
31
,
30
,
31
,
30
,
31
},
{
31
,
29
,
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
]
=
static
const
int
year_lengths
[
2
]
=
{
{
DAYS_PER_NON_LEAP_YEAR
,
DAYS_PER_NON_LEAP_YEAR
,
DAYS_PER_LEAP_YEAR
DAYS_PER_LEAP_YEAR
};
};
static
int
increment_overflow
(
int
*
number
,
int
delta
)
static
int
increment_overflow
(
int
*
number
,
int
delta
)
{
{
int
number0
;
int
number0
;
number0
=
*
number
;
number0
=
*
number
;
*
number
+=
delta
;
*
number
+=
delta
;
return
(
*
number
<
number0
)
!=
(
delta
<
0
);
return
(
*
number
<
number0
)
!=
(
delta
<
0
);
}
}
/*- End of function --------------------------------------------------------*/
/*- End of function --------------------------------------------------------*/
static
void
set_tzname
(
tz_t
*
tz
)
static
void
set_tzname
(
tz_t
*
tz
)
{
{
struct
tz_state_s
*
sp
;
struct
tz_state_s
*
sp
;
const
struct
tz_ttinfo_s
*
ttisp
;
const
struct
tz_ttinfo_s
*
ttisp
;
int
i
;
int
i
;
sp
=
&
tz
->
state
;
sp
=
&
tz
->
state
;
tz
->
tzname
[
0
]
=
wildabbr
;
tz
->
tzname
[
0
]
=
wildabbr
;
tz
->
tzname
[
1
]
=
wildabbr
;
tz
->
tzname
[
1
]
=
wildabbr
;
for
(
i
=
0
;
i
<
sp
->
typecnt
;
i
++
)
for
(
i
=
0
;
i
<
sp
->
typecnt
;
i
++
)
{
{
ttisp
=
&
sp
->
ttis
[
i
];
ttisp
=
&
sp
->
ttis
[
i
];
tz
->
tzname
[
ttisp
->
isdst
]
=
&
sp
->
chars
[
ttisp
->
abbrind
];
tz
->
tzname
[
ttisp
->
isdst
]
=
&
sp
->
chars
[
ttisp
->
abbrind
];
}
}
for
(
i
=
0
;
i
<
sp
->
timecnt
;
i
++
)
for
(
i
=
0
;
i
<
sp
->
timecnt
;
i
++
)
{
{
ttisp
=
&
sp
->
ttis
[
sp
->
types
[
i
]];
ttisp
=
&
sp
->
ttis
[
sp
->
types
[
i
]];
tz
->
tzname
[
ttisp
->
isdst
]
=
&
sp
->
chars
[
ttisp
->
abbrind
];
tz
->
tzname
[
ttisp
->
isdst
]
=
&
sp
->
chars
[
ttisp
->
abbrind
];
}
}
}
}
/*- End of function --------------------------------------------------------*/
/*- End of function --------------------------------------------------------*/
/* Return the number of leap years through the end of the given year
/* 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. */
where, to make the math easy, the answer for year zero is defined as zero. */
static
int
leaps_thru_end_of
(
const
int
y
)
static
int
leaps_thru_end_of
(
const
int
y
)
{
{
return
(
y
>=
0
)
?
(
y
/
4
-
y
/
100
+
y
/
400
)
:
-
(
leaps_thru_end_of
(
-
(
y
+
1
))
+
1
);
return
(
y
>=
0
)
?
(
y
/
4
-
y
/
100
+
y
/
400
)
:
-
(
leaps_thru_end_of
(
-
(
y
+
1
))
+
1
);
}
}
/*- End of function --------------------------------------------------------*/
/*- End of function --------------------------------------------------------*/
static
struct
tm
*
time_sub
(
const
time_t
*
const
timep
,
const
long
int
offset
,
const
struct
tz_state_s
*
const
sp
,
struct
tm
*
const
tmp
)
static
struct
tm
*
time_sub
(
const
time_t
*
const
timep
,
const
long
int
offset
,
const
struct
tz_state_s
*
const
sp
,
struct
tm
*
const
tmp
)
{
{
const
struct
tz_lsinfo_s
*
lp
;
const
struct
tz_lsinfo_s
*
lp
;
time_t
tdays
;
time_t
tdays
;
const
int
*
ip
;
const
int
*
ip
;
int32_t
corr
;
int32_t
corr
;
int32_t
seconds
;
int32_t
seconds
;
int32_t
rem
;
int32_t
rem
;
int
idays
;
int
idays
;
int
y
;
int
y
;
int
hit
;
int
hit
;
int
i
;
int
i
;
corr
=
0
;
corr
=
0
;
hit
=
0
;
hit
=
0
;
i
=
sp
->
leapcnt
;
i
=
sp
->
leapcnt
;
while
(
--
i
>=
0
)
while
(
--
i
>=
0
)
{
{
lp
=
&
sp
->
lsis
[
i
];
lp
=
&
sp
->
lsis
[
i
];
if
(
*
timep
>=
lp
->
trans
)
if
(
*
timep
>=
lp
->
trans
)
{
{
if
(
*
timep
==
lp
->
trans
)
if
(
*
timep
==
lp
->
trans
)
{
{
hit
=
((
i
==
0
&&
lp
->
corr
>
0
)
||
lp
->
corr
>
sp
->
lsis
[
i
-
1
].
corr
);
hit
=
((
i
==
0
&&
lp
->
corr
>
0
)
||
lp
->
corr
>
sp
->
lsis
[
i
-
1
].
corr
);
if
(
hit
)
if
(
hit
)
{
{
while
(
i
>
0
while
(
i
>
0
&&
&&
sp
->
lsis
[
i
].
trans
==
sp
->
lsis
[
i
-
1
].
trans
+
1
sp
->
lsis
[
i
].
trans
==
sp
->
lsis
[
i
-
1
].
trans
+
1
&&
&&
sp
->
lsis
[
i
].
corr
==
sp
->
lsis
[
i
-
1
].
corr
+
1
)
sp
->
lsis
[
i
].
corr
==
sp
->
lsis
[
i
-
1
].
corr
+
1
)
{
{
hit
++
;
hit
++
;
--
i
;
--
i
;
}
}
}
}
}
}
corr
=
lp
->
corr
;
corr
=
lp
->
corr
;
break
;
break
;
}
}
}
}
y
=
EPOCH_YEAR
;
y
=
EPOCH_YEAR
;
tdays
=
*
timep
/
SECS_PER_DAY
;
tdays
=
*
timep
/
SECS_PER_DAY
;
rem
=
*
timep
-
tdays
*
SECS_PER_DAY
;
rem
=
*
timep
-
tdays
*
SECS_PER_DAY
;
while
(
tdays
<
0
||
tdays
>=
year_lengths
[
isleap
(
y
)])
while
(
tdays
<
0
||
tdays
>=
year_lengths
[
isleap
(
y
)])
{
{
int
newy
;
int
newy
;
time_t
tdelta
;
time_t
tdelta
;
int
idelta
;
int
idelta
;
int
leapdays
;
int
leapdays
;
tdelta
=
tdays
/
DAYS_PER_LEAP_YEAR
;
tdelta
=
tdays
/
DAYS_PER_LEAP_YEAR
;
idelta
=
tdelta
;
idelta
=
tdelta
;
if
(
tdelta
-
idelta
>=
1
||
idelta
-
tdelta
>=
1
)
if
(
tdelta
-
idelta
>=
1
||
idelta
-
tdelta
>=
1
)
return
NULL
;
return
NULL
;
if
(
idelta
==
0
)
if
(
idelta
==
0
)
idelta
=
(
tdays
<
0
)
?
-
1
:
1
;
idelta
=
(
tdays
<
0
)
?
-
1
:
1
;
newy
=
y
;
newy
=
y
;
if
(
increment_overflow
(
&
newy
,
idelta
))
if
(
increment_overflow
(
&
newy
,
idelta
))
return
NULL
;
return
NULL
;
leapdays
=
leaps_thru_end_of
(
newy
-
1
)
-
leaps_thru_end_of
(
y
-
1
);
leapdays
=
leaps_thru_end_of
(
newy
-
1
)
-
leaps_thru_end_of
(
y
-
1
);
tdays
-=
((
time_t
)
newy
-
y
)
*
DAYS_PER_NON_LEAP_YEAR
;
tdays
-=
((
time_t
)
newy
-
y
)
*
DAYS_PER_NON_LEAP_YEAR
;
tdays
-=
leapdays
;
tdays
-=
leapdays
;
y
=
newy
;
y
=
newy
;
}
}
seconds
=
tdays
*
SECS_PER_DAY
;
seconds
=
tdays
*
SECS_PER_DAY
;
tdays
=
seconds
/
SECS_PER_DAY
;
tdays
=
seconds
/
SECS_PER_DAY
;
rem
+=
seconds
-
tdays
*
SECS_PER_DAY
;
rem
+=
seconds
-
tdays
*
SECS_PER_DAY
;
/* Given the range, we can now fearlessly cast... */
/* Given the range, we can now fearlessly cast... */
idays
=
tdays
;
idays
=
tdays
;
rem
+=
(
offset
-
corr
);
rem
+=
(
offset
-
corr
);
while
(
rem
<
0
)
while
(
rem
<
0
)
{
{
rem
+=
SECS_PER_DAY
;
rem
+=
SECS_PER_DAY
;
idays
--
;
idays
--
;
}
}
while
(
rem
>=
SECS_PER_DAY
)
while
(
rem
>=
SECS_PER_DAY
)
{
{
rem
-=
SECS_PER_DAY
;
rem
-=
SECS_PER_DAY
;
idays
++
;
idays
++
;
}
}
while
(
idays
<
0
)
while
(
idays
<
0
)
{
{
if
(
increment_overflow
(
&
y
,
-
1
))
if
(
increment_overflow
(
&
y
,
-
1
))
return
NULL
;
return
NULL
;
idays
+=
year_lengths
[
isleap
(
y
)];
idays
+=
year_lengths
[
isleap
(
y
)];
}
}
while
(
idays
>=
year_lengths
[
isleap
(
y
)])
while
(
idays
>=
year_lengths
[
isleap
(
y
)])
{
{
idays
-=
year_lengths
[
isleap
(
y
)];
idays
-=
year_lengths
[
isleap
(
y
)];
if
(
increment_overflow
(
&
y
,
1
))
if
(
increment_overflow
(
&
y
,
1
))
return
NULL
;
return
NULL
;
}
}
tmp
->
tm_year
=
y
;
tmp
->
tm_year
=
y
;
if
(
increment_overflow
(
&
tmp
->
tm_year
,
-
TM_YEAR_BASE
))
if
(
increment_overflow
(
&
tmp
->
tm_year
,
-
TM_YEAR_BASE
))
return
NULL
;
return
NULL
;
tmp
->
tm_yday
=
idays
;
tmp
->
tm_yday
=
idays
;
/* The "extra" mods below avoid overflow problems. */
/* The "extra" mods below avoid overflow problems. */
tmp
->
tm_wday
=
EPOCH_WDAY
tmp
->
tm_wday
=
EPOCH_WDAY
+
((
y
-
EPOCH_YEAR
)
%
DAYS_PER_WEEK
)
*
(
DAYS_PER_NON_LEAP_YEAR
%
DAYS_PER_WEEK
)
+
((
y
-
EPOCH_YEAR
)
%
DAYS_PER_WEEK
)
*
(
DAYS_PER_NON_LEAP_YEAR
%
DAYS_PER_WEEK
)
+
leaps_thru_end_of
(
y
-
1
)
+
leaps_thru_end_of
(
y
-
1
)
-
leaps_thru_end_of
(
EPOCH_YEAR
-
1
)
-
leaps_thru_end_of
(
EPOCH_YEAR
-
1
)
+
idays
;
+
idays
;
tmp
->
tm_wday
%=
DAYS_PER_WEEK
;
tmp
->
tm_wday
%=
DAYS_PER_WEEK
;
if
(
tmp
->
tm_wday
<
0
)
if
(
tmp
->
tm_wday
<
0
)
tmp
->
tm_wday
+=
DAYS_PER_WEEK
;
tmp
->
tm_wday
+=
DAYS_PER_WEEK
;
tmp
->
tm_hour
=
(
int
)
(
rem
/
SECS_PER_HOUR
);
tmp
->
tm_hour
=
(
int
)
(
rem
/
SECS_PER_HOUR
);
rem
%=
SECS_PER_HOUR
;
rem
%=
SECS_PER_HOUR
;
tmp
->
tm_min
=
(
int
)
(
rem
/
SECS_PER_MIN
);
tmp
->
tm_min
=
(
int
)
(
rem
/
SECS_PER_MIN
);
/* A positive leap second requires a special
/* A positive leap second requires a special
* representation. This uses "... ??:59:60" et seq. */
* representation. This uses "... ??:59:60" et seq. */
tmp
->
tm_sec
=
(
int
)
(
rem
%
SECS_PER_MIN
)
+
hit
;
tmp
->
tm_sec
=
(
int
)
(
rem
%
SECS_PER_MIN
)
+
hit
;
ip
=
mon_lengths
[
isleap
(
y
)];
ip
=
mon_lengths
[
isleap
(
y
)];
for
(
tmp
->
tm_mon
=
0
;
idays
>=
ip
[
tmp
->
tm_mon
];
(
tmp
->
tm_mon
)
++
)
for
(
tmp
->
tm_mon
=
0
;
idays
>=
ip
[
tmp
->
tm_mon
];
(
tmp
->
tm_mon
)
++
)
idays
-=
ip
[
tmp
->
tm_mon
];
idays
-=
ip
[
tmp
->
tm_mon
];
tmp
->
tm_mday
=
(
int
)
(
idays
+
1
);
tmp
->
tm_mday
=
(
int
)
(
idays
+
1
);
tmp
->
tm_isdst
=
0
;
tmp
->
tm_isdst
=
0
;
return
tmp
;
return
tmp
;
}
}
/*- End of function --------------------------------------------------------*/
/*- End of function --------------------------------------------------------*/
/* Given a pointer into a time zone string, scan until a character that is not
/* 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
* a valid character in a zone name is found. Return a pointer to that
* character. */
* character. */
static
const
char
*
get_tzname
(
const
char
*
strp
)
static
const
char
*
get_tzname
(
const
char
*
strp
)
{
{
char
c
;
char
c
;
while
((
c
=
*
strp
)
!=
'\0'
&&
!
is_digit
(
c
)
&&
c
!=
','
&&
c
!=
'-'
&&
c
!=
'+'
)
while
((
c
=
*
strp
)
!=
'\0'
&&
!
is_digit
(
c
)
&&
c
!=
','
&&
c
!=
'-'
&&
c
!=
'+'
)
strp
++
;
strp
++
;
return
strp
;
return
strp
;
}
}
/*- End of function --------------------------------------------------------*/
/*- End of function --------------------------------------------------------*/
/* Given a pointer into a time zone string, extract a number from that string.
/* 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
* Check that the number is within a specified range; if it is not, return
* NULL.
* NULL.
* Otherwise, return a pointer to the first character not part of the number. */
* Otherwise, return a pointer to the first character not part of the number. */
static
const
char
*
get_num
(
const
char
*
strp
,
int
*
const
nump
,
const
int
min
,
const
int
max
)
static
const
char
*
get_num
(
const
char
*
strp
,
int
*
const
nump
,
const
int
min
,
const
int
max
)
{
{
char
c
;
char
c
;
int
num
;
int
num
;
if
(
strp
==
NULL
||
!
is_digit
(
c
=
*
strp
))
if
(
strp
==
NULL
||
!
is_digit
(
c
=
*
strp
))
return
NULL
;
return
NULL
;
num
=
0
;
num
=
0
;
do
do
{
{
num
=
num
*
10
+
(
c
-
'0'
);
num
=
num
*
10
+
(
c
-
'0'
);
if
(
num
>
max
)
if
(
num
>
max
)
return
NULL
;
/* Illegal value */
return
NULL
;
/* Illegal value */
c
=
*++
strp
;
c
=
*++
strp
;
}
}
while
(
is_digit
(
c
));
while
(
is_digit
(
c
));
if
(
num
<
min
)
if
(
num
<
min
)
return
NULL
;
/* Illegal value */
return
NULL
;
/* Illegal value */
*
nump
=
num
;
*
nump
=
num
;
return
strp
;
return
strp
;
}
}
/*- End of function --------------------------------------------------------*/
/*- End of function --------------------------------------------------------*/
/* Given a pointer into a time zone string, extract a number of seconds,
/* Given a pointer into a time zone string, extract a number of seconds,
* in hh[:mm[:ss]] form, from the string.
* in hh[:mm[:ss]] form, from the string.
* If any error occurs, return NULL.
* If any error occurs, return NULL.
* Otherwise, return a pointer to the first character not part of the number
* Otherwise, return a pointer to the first character not part of the number
* of seconds. */
* of seconds. */
static
const
char
*
get_secs
(
const
char
*
strp
,
long
int
*
const
secsp
)
static
const
char
*
get_secs
(
const
char
*
strp
,
long
int
*
const
secsp
)
{
{
int
num
;
int
num
;
/* HOURS_PER_DAY*DAYS_PER_WEEK - 1 allows quasi-Posix rules like
/* HOURS_PER_DAY*DAYS_PER_WEEK - 1 allows quasi-Posix rules like
* "M10.4.6/26", which does not conform to Posix,
* "M10.4.6/26", which does not conform to Posix,
* but which specifies the equivalent of
* but which specifies the equivalent of
* "02:00 on the first Sunday on or after 23 Oct". */
* "02:00 on the first Sunday on or after 23 Oct". */
strp
=
get_num
(
strp
,
&
num
,
0
,
HOURS_PER_DAY
*
DAYS_PER_WEEK
-
1
);
strp
=
get_num
(
strp
,
&
num
,
0
,
HOURS_PER_DAY
*
DAYS_PER_WEEK
-
1
);
if
(
strp
==
NULL
)
if
(
strp
==
NULL
)
return
NULL
;
return
NULL
;
*
secsp
=
num
*
(
long
int
)
SECS_PER_HOUR
;
*
secsp
=
num
*
(
long
int
)
SECS_PER_HOUR
;
if
(
*
strp
==
':'
)
if
(
*
strp
==
':'
)
{
{
strp
=
get_num
(
strp
+
1
,
&
num
,
0
,
MINS_PER_HOUR
-
1
);
strp
=
get_num
(
strp
+
1
,
&
num
,
0
,
MINS_PER_HOUR
-
1
);
if
(
strp
==
NULL
)
if
(
strp
==
NULL
)
return
NULL
;
return
NULL
;
*
secsp
+=
num
*
SECS_PER_MIN
;
*
secsp
+=
num
*
SECS_PER_MIN
;
if
(
*
strp
==
':'
)
if
(
*
strp
==
':'
)
{
{
/* SECS_PER_MIN allows for leap seconds. */
/* SECS_PER_MIN allows for leap seconds. */
strp
=
get_num
(
strp
+
1
,
&
num
,
0
,
SECS_PER_MIN
);
strp
=
get_num
(
strp
+
1
,
&
num
,
0
,
SECS_PER_MIN
);
if
(
strp
==
NULL
)
if
(
strp
==
NULL
)
return
NULL
;
return
NULL
;
*
secsp
+=
num
;
*
secsp
+=
num
;
}
}
}
}
return
strp
;
return
strp
;
}
}
/*- End of function --------------------------------------------------------*/
/*- End of function --------------------------------------------------------*/
/* Given a pointer into a time zone string, extract an offset, in
/* Given a pointer into a time zone string, extract an offset, in
* [+-]hh[:mm[:ss]] form, from the string.
* [+-]hh[:mm[:ss]] form, from the string.
* If any error occurs, return NULL.
* If any error occurs, return NULL.
* Otherwise, return a pointer to the first character not part of the time. */
* Otherwise, return a pointer to the first character not part of the time. */
static
const
char
*
get_offset
(
const
char
*
strp
,
long
int
*
const
offsetp
)
static
const
char
*
get_offset
(
const
char
*
strp
,
long
int
*
const
offsetp
)
{
{
int
neg
=
0
;
int
neg
=
0
;
if
(
*
strp
==
'-'
)
if
(
*
strp
==
'-'
)
{
{
neg
=
1
;
neg
=
1
;
strp
++
;
strp
++
;
}
}
else
if
(
*
strp
==
'+'
)
else
if
(
*
strp
==
'+'
)
{
{
strp
++
;
strp
++
;
}
}
strp
=
get_secs
(
strp
,
offsetp
);
strp
=
get_secs
(
strp
,
offsetp
);
if
(
strp
==
NULL
)
if
(
strp
==
NULL
)
return
NULL
;
/* Illegal time */
return
NULL
;
/* Illegal time */
if
(
neg
)
if
(
neg
)
*
offsetp
=
-*
offsetp
;
*
offsetp
=
-*
offsetp
;
return
strp
;
return
strp
;
}
}
/*- End of function --------------------------------------------------------*/
/*- End of function --------------------------------------------------------*/
/* Given a pointer into a time zone string, extract a rule in the form
/* 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".
* date[/time]. See POSIX section 8 for the format of "date" and "time".
* If a valid rule is not found, return NULL.
* If a valid rule is not found, return NULL.
* Otherwise, return a pointer to the first character not part of the rule. */
* Otherwise, return a pointer to the first character not part of the rule. */
static
const
char
*
get_rule
(
const
char
*
strp
,
struct
tz_rule_s
*
const
rulep
)
static
const
char
*
get_rule
(
const
char
*
strp
,
struct
tz_rule_s
*
const
rulep
)
{
{
if
(
*
strp
==
'J'
)
if
(
*
strp
==
'J'
)
{
{
/* Julian day. */
/* Julian day. */
rulep
->
r_type
=
JULIAN_DAY
;
rulep
->
r_type
=
JULIAN_DAY
;
strp
=
get_num
(
strp
+
1
,
&
rulep
->
r_day
,
1
,
DAYS_PER_NON_LEAP_YEAR
);
strp
=
get_num
(
strp
+
1
,
&
rulep
->
r_day
,
1
,
DAYS_PER_NON_LEAP_YEAR
);
}
}
else
if
(
*
strp
==
'M'
)
else
if
(
*
strp
==
'M'
)
{
{
/* Month, week, day. */
/* Month, week, day. */
rulep
->
r_type
=
MONTH_NTH_DAY_OF_WEEK
;
rulep
->
r_type
=
MONTH_NTH_DAY_OF_WEEK
;
strp
=
get_num
(
strp
+
1
,
&
rulep
->
r_mon
,
1
,
MONTHS_PER_YEAR
);
strp
=
get_num
(
strp
+
1
,
&
rulep
->
r_mon
,
1
,
MONTHS_PER_YEAR
);
if
(
strp
==
NULL
||
*
strp
++
!=
'.'
)
if
(
strp
==
NULL
||
*
strp
++
!=
'.'
)
return
NULL
;
return
NULL
;
strp
=
get_num
(
strp
,
&
rulep
->
r_week
,
1
,
5
);
strp
=
get_num
(
strp
,
&
rulep
->
r_week
,
1
,
5
);
if
(
strp
==
NULL
||
*
strp
++
!=
'.'
)
if
(
strp
==
NULL
||
*
strp
++
!=
'.'
)
return
NULL
;
return
NULL
;
strp
=
get_num
(
strp
,
&
rulep
->
r_day
,
0
,
DAYS_PER_WEEK
-
1
);
strp
=
get_num
(
strp
,
&
rulep
->
r_day
,
0
,
DAYS_PER_WEEK
-
1
);
}
}
else
if
(
is_digit
(
*
strp
))
else
if
(
is_digit
(
*
strp
))
{
{
/* Day of the year. */
/* Day of the year. */
rulep
->
r_type
=
DAY_OF_YEAR
;
rulep
->
r_type
=
DAY_OF_YEAR
;
strp
=
get_num
(
strp
,
&
rulep
->
r_day
,
0
,
DAYS_PER_LEAP_YEAR
-
1
);
strp
=
get_num
(
strp
,
&
rulep
->
r_day
,
0
,
DAYS_PER_LEAP_YEAR
-
1
);
}
}
else
else
{
{
/* Invalid format */
/* Invalid format */
return
NULL
;
return
NULL
;
}
}
if
(
strp
==
NULL
)
if
(
strp
==
NULL
)
return
NULL
;
return
NULL
;
if
(
*
strp
==
'/'
)
if
(
*
strp
==
'/'
)
{
{
/* Time specified. */
/* Time specified. */
strp
=
get_secs
(
strp
+
1
,
&
rulep
->
r_time
);
strp
=
get_secs
(
strp
+
1
,
&
rulep
->
r_time
);
}
}
else
else
{
{
/* Default = 2:00:00 */
/* Default = 2:00:00 */
rulep
->
r_time
=
2
*
SECS_PER_HOUR
;
rulep
->
r_time
=
2
*
SECS_PER_HOUR
;
}
}
return
strp
;
return
strp
;
}
}
/*- End of function --------------------------------------------------------*/
/*- End of function --------------------------------------------------------*/
/* Given the Epoch-relative time of January 1, 00:00:00 UTC, in a year, the
/* 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,
* year, a rule, and the offset from UTC at the time that rule takes effect,
* calculate the Epoch-relative time that rule takes effect. */
* calculate the Epoch-relative time that rule takes effect. */
static
time_t
trans_time
(
const
time_t
janfirst
,
const
int
year
,
const
struct
tz_rule_s
*
const
rulep
,
const
long
int
offset
)
static
time_t
trans_time
(
const
time_t
janfirst
,
const
int
year
,
const
struct
tz_rule_s
*
const
rulep
,
const
long
int
offset
)
{
{
int
leapyear
;
int
leapyear
;
time_t
value
;
time_t
value
;
int
i
;
int
i
;
int
d
;
int
d
;
int
m1
;
int
m1
;
int
yy0
;
int
yy0
;
int
yy1
;
int
yy1
;
int
yy2
;
int
yy2
;
int
dow
;
int
dow
;
value
=
0
;
value
=
0
;
leapyear
=
isleap
(
year
);
leapyear
=
isleap
(
year
);
switch
(
rulep
->
r_type
)
switch
(
rulep
->
r_type
)
{
{
case
JULIAN_DAY
:
case
JULIAN_DAY
:
/* Jn - Julian day, 1 == January 1, 60 == March 1 even in leap
/* Jn - Julian day, 1 == January 1, 60 == March 1 even in leap
* years.
* years.
* In non-leap years, or if the day number is 59 or less, just
* In non-leap years, or if the day number is 59 or less, just
* add SECS_PER_DAY times the day number-1 to the time of
* add SECS_PER_DAY times the day number-1 to the time of
* January 1, midnight, to get the day. */
* January 1, midnight, to get the day. */
value
=
janfirst
+
(
rulep
->
r_day
-
1
)
*
SECS_PER_DAY
;
value
=
janfirst
+
(
rulep
->
r_day
-
1
)
*
SECS_PER_DAY
;
if
(
leapyear
&&
rulep
->
r_day
>=
60
)
if
(
leapyear
&&
rulep
->
r_day
>=
60
)
value
+=
SECS_PER_DAY
;
value
+=
SECS_PER_DAY
;
break
;
break
;
case
DAY_OF_YEAR
:
case
DAY_OF_YEAR
:
/* n - day of year.
/* n - day of year.
* Just add SECS_PER_DAY times the day number to the time of
* Just add SECS_PER_DAY times the day number to the time of
* January 1, midnight, to get the day. */
* January 1, midnight, to get the day. */
value
=
janfirst
+
rulep
->
r_day
*
SECS_PER_DAY
;
value
=
janfirst
+
rulep
->
r_day
*
SECS_PER_DAY
;
break
;
break
;
case
MONTH_NTH_DAY_OF_WEEK
:
case
MONTH_NTH_DAY_OF_WEEK
:
/* Mm.n.d - nth "dth day" of month m. */
/* Mm.n.d - nth "dth day" of month m. */
value
=
janfirst
;
value
=
janfirst
;
for
(
i
=
0
;
i
<
rulep
->
r_mon
-
1
;
i
++
)
for
(
i
=
0
;
i
<
rulep
->
r_mon
-
1
;
i
++
)
value
+=
mon_lengths
[
leapyear
][
i
]
*
SECS_PER_DAY
;
value
+=
mon_lengths
[
leapyear
][
i
]
*
SECS_PER_DAY
;
/* Use Zeller's Congruence to get day-of-week of first day of month. */
/* Use Zeller's Congruence to get day-of-week of first day of month. */
m1
=
(
rulep
->
r_mon
+
9
)
%
12
+
1
;
m1
=
(
rulep
->
r_mon
+
9
)
%
12
+
1
;
yy0
=
(
rulep
->
r_mon
<=
2
)
?
(
year
-
1
)
:
year
;
yy0
=
(
rulep
->
r_mon
<=
2
)
?
(
year
-
1
)
:
year
;
yy1
=
yy0
/
100
;
yy1
=
yy0
/
100
;
yy2
=
yy0
%
100
;
yy2
=
yy0
%
100
;
dow
=
((
26
*
m1
-
2
)
/
10
+
1
+
yy2
+
yy2
/
4
+
yy1
/
4
-
2
*
yy1
)
%
7
;
dow
=
((
26
*
m1
-
2
)
/
10
+
1
+
yy2
+
yy2
/
4
+
yy1
/
4
-
2
*
yy1
)
%
7
;
if
(
dow
<
0
)
if
(
dow
<
0
)
dow
+=
DAYS_PER_WEEK
;
dow
+=
DAYS_PER_WEEK
;
/* "dow" is the day-of-week of the first day of the month. Get
/* "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
* the day-of-month (zero-origin) of the first "dow" day of the
* month. */
* month. */
d
=
rulep
->
r_day
-
dow
;
d
=
rulep
->
r_day
-
dow
;
if
(
d
<
0
)
if
(
d
<
0
)
d
+=
DAYS_PER_WEEK
;
d
+=
DAYS_PER_WEEK
;
for
(
i
=
1
;
i
<
rulep
->
r_week
;
i
++
)
for
(
i
=
1
;
i
<
rulep
->
r_week
;
i
++
)
{
{
if
(
d
+
DAYS_PER_WEEK
>=
mon_lengths
[
leapyear
][
rulep
->
r_mon
-
1
])
if
(
d
+
DAYS_PER_WEEK
>=
mon_lengths
[
leapyear
][
rulep
->
r_mon
-
1
])
break
;
break
;
d
+=
DAYS_PER_WEEK
;
d
+=
DAYS_PER_WEEK
;
}
}
/* "d" is the day-of-month (zero-origin) of the day we want. */
/* "d" is the day-of-month (zero-origin) of the day we want. */
value
+=
d
*
SECS_PER_DAY
;
value
+=
d
*
SECS_PER_DAY
;
break
;
break
;
}
}
/* "value" is the Epoch-relative time of 00:00:00 UTC on the day in
/* "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
* question. To get the Epoch-relative time of the specified local
* time on that day, add the transition time and the current offset
* time on that day, add the transition time and the current offset
* from UTC. */
* from UTC. */
return
value
+
rulep
->
r_time
+
offset
;
return
value
+
rulep
->
r_time
+
offset
;
}
}
/*- End of function --------------------------------------------------------*/
/*- End of function --------------------------------------------------------*/
/* Given a POSIX section 8-style TZ string, fill in the rule tables as
/* Given a POSIX section 8-style TZ string, fill in the rule tables as
appropriate. */
appropriate. */
static
int
tzparse
(
const
char
*
name
,
struct
tz_state_s
*
const
sp
,
const
int
lastditch
)
static
int
tzparse
(
const
char
*
name
,
struct
tz_state_s
*
const
sp
,
const
int
lastditch
)
{
{
const
char
*
stdname
;
const
char
*
stdname
;
const
char
*
dstname
;
const
char
*
dstname
;
size_t
stdlen
;
size_t
stdlen
;
size_t
dstlen
;
size_t
dstlen
;
long
int
stdoffset
;
long
int
stdoffset
;
long
int
dstoffset
;
long
int
dstoffset
;
long
int
theirstdoffset
;
long
int
theirstdoffset
;
long
int
theirdstoffset
;
long
int
theirdstoffset
;
long
int
theiroffset
;
long
int
theiroffset
;
unsigned
char
*
typep
;
unsigned
char
*
typep
;
char
*
cp
;
char
*
cp
;
int
load_result
;
int
load_result
;
int
isdst
;
int
isdst
;
int
i
;
int
i
;
int
j
;
int
j
;
int
year
;
int
year
;
struct
tz_rule_s
start
;
struct
tz_rule_s
start
;
struct
tz_rule_s
end
;
struct
tz_rule_s
end
;
time_t
*
atp
;
time_t
*
atp
;
time_t
janfirst
;
time_t
janfirst
;
time_t
starttime
;
time_t
starttime
;
time_t
endtime
;
time_t
endtime
;
dstname
=
NULL
;
dstname
=
NULL
;
stdname
=
name
;
stdname
=
name
;
if
(
lastditch
)
if
(
lastditch
)
{
{
stdlen
=
strlen
(
name
);
/* Length of standard zone name */
stdlen
=
strlen
(
name
);
/* Length of standard zone name */
name
+=
stdlen
;
name
+=
stdlen
;
if
(
stdlen
>=
sizeof
(
sp
->
chars
))
if
(
stdlen
>=
sizeof
(
sp
->
chars
))
stdlen
=
sizeof
(
sp
->
chars
)
-
1
;
stdlen
=
sizeof
(
sp
->
chars
)
-
1
;
stdoffset
=
0
;
stdoffset
=
0
;
}
}
else
else
{
{
name
=
get_tzname
(
name
);
name
=
get_tzname
(
name
);
stdlen
=
name
-
stdname
;
stdlen
=
name
-
stdname
;
if
(
stdlen
<
3
)
if
(
stdlen
<
3
)
return
-
1
;
return
-
1
;
if
(
*
name
==
'\0'
)
if
(
*
name
==
'\0'
)
return
-
1
;
return
-
1
;
name
=
get_offset
(
name
,
&
stdoffset
);
name
=
get_offset
(
name
,
&
stdoffset
);
if
(
name
==
NULL
)
if
(
name
==
NULL
)
return
-
1
;
return
-
1
;
}
}
load_result
=
-
1
;
load_result
=
-
1
;
if
(
load_result
!=
0
)
if
(
load_result
!=
0
)
sp
->
leapcnt
=
0
;
/* So, we're off a little */
sp
->
leapcnt
=
0
;
/* So, we're off a little */
if
(
*
name
!=
'\0'
)
if
(
*
name
!=
'\0'
)
{
{
dstname
=
name
;
dstname
=
name
;
name
=
get_tzname
(
name
);
name
=
get_tzname
(
name
);
dstlen
=
name
-
dstname
;
/* Length of DST zone name */
dstlen
=
name
-
dstname
;
/* Length of DST zone name */
if
(
dstlen
<
3
)
if
(
dstlen
<
3
)
return
-
1
;
return
-
1
;
if
(
*
name
!=
'\0'
&&
*
name
!=
','
&&
*
name
!=
';'
)
if
(
*
name
!=
'\0'
&&
*
name
!=
','
&&
*
name
!=
';'
)
{
{
if
((
name
=
get_offset
(
name
,
&
dstoffset
))
==
NULL
)
if
((
name
=
get_offset
(
name
,
&
dstoffset
))
==
NULL
)
return
-
1
;
return
-
1
;
}
}
else
else
{
{
dstoffset
=
stdoffset
-
SECS_PER_HOUR
;
dstoffset
=
stdoffset
-
SECS_PER_HOUR
;
}
}
if
(
*
name
==
'\0'
&&
load_result
!=
0
)
if
(
*
name
==
'\0'
&&
load_result
!=
0
)
name
=
TZ_DEF_RULE_STRING
;
name
=
TZ_DEF_RULE_STRING
;
if
(
*
name
==
','
||
*
name
==
';'
)
if
(
*
name
==
','
||
*
name
==
';'
)
{
{
if
((
name
=
get_rule
(
name
+
1
,
&
start
))
==
NULL
)
if
((
name
=
get_rule
(
name
+
1
,
&
start
))
==
NULL
)
return
-
1
;
return
-
1
;
if
(
*
name
++
!=
','
)
if
(
*
name
++
!=
','
)
return
-
1
;
return
-
1
;
if
((
name
=
get_rule
(
name
,
&
end
))
==
NULL
)
if
((
name
=
get_rule
(
name
,
&
end
))
==
NULL
)
return
-
1
;
return
-
1
;
if
(
*
name
!=
'\0'
)
if
(
*
name
!=
'\0'
)
return
-
1
;
return
-
1
;
sp
->
typecnt
=
2
;
/* Standard time and DST */
sp
->
typecnt
=
2
;
/* Standard time and DST */
/* Two transitions per year, from EPOCH_YEAR to 2037. */
/* Two transitions per year, from EPOCH_YEAR to 2037. */
sp
->
timecnt
=
2
*
(
2037
-
EPOCH_YEAR
+
1
);
sp
->
timecnt
=
2
*
(
2037
-
EPOCH_YEAR
+
1
);
if
(
sp
->
timecnt
>
TZ_MAX_TIMES
)
if
(
sp
->
timecnt
>
TZ_MAX_TIMES
)
return
-
1
;
return
-
1
;
sp
->
ttis
[
0
].
gmtoff
=
-
dstoffset
;
sp
->
ttis
[
0
].
gmtoff
=
-
dstoffset
;
sp
->
ttis
[
0
].
isdst
=
1
;
sp
->
ttis
[
0
].
isdst
=
1
;
sp
->
ttis
[
0
].
abbrind
=
stdlen
+
1
;
sp
->
ttis
[
0
].
abbrind
=
stdlen
+
1
;
sp
->
ttis
[
1
].
gmtoff
=
-
stdoffset
;
sp
->
ttis
[
1
].
gmtoff
=
-
stdoffset
;
sp
->
ttis
[
1
].
isdst
=
0
;
sp
->
ttis
[
1
].
isdst
=
0
;
sp
->
ttis
[
1
].
abbrind
=
0
;
sp
->
ttis
[
1
].
abbrind
=
0
;
atp
=
sp
->
ats
;
atp
=
sp
->
ats
;
typep
=
sp
->
types
;
typep
=
sp
->
types
;
janfirst
=
0
;
janfirst
=
0
;
for
(
year
=
EPOCH_YEAR
;
year
<=
2037
;
year
++
)
for
(
year
=
EPOCH_YEAR
;
year
<=
2037
;
year
++
)
{
{
starttime
=
trans_time
(
janfirst
,
year
,
&
start
,
stdoffset
);
starttime
=
trans_time
(
janfirst
,
year
,
&
start
,
stdoffset
);
endtime
=
trans_time
(
janfirst
,
year
,
&
end
,
dstoffset
);
endtime
=
trans_time
(
janfirst
,
year
,
&
end
,
dstoffset
);
if
(
starttime
>
endtime
)
if
(
starttime
>
endtime
)
{
{
*
atp
++
=
endtime
;
*
atp
++
=
endtime
;
*
typep
++
=
1
;
/* DST ends */
*
typep
++
=
1
;
/* DST ends */
*
atp
++
=
starttime
;
*
atp
++
=
starttime
;
*
typep
++
=
0
;
/* DST begins */
*
typep
++
=
0
;
/* DST begins */
}
}
else
else
{
{
*
atp
++
=
starttime
;
*
atp
++
=
starttime
;
*
typep
++
=
0
;
/* DST begins */
*
typep
++
=
0
;
/* DST begins */
*
atp
++
=
endtime
;
*
atp
++
=
endtime
;
*
typep
++
=
1
;
/* DST ends */
*
typep
++
=
1
;
/* DST ends */
}
}
janfirst
+=
year_lengths
[
isleap
(
year
)]
*
SECS_PER_DAY
;
janfirst
+=
year_lengths
[
isleap
(
year
)]
*
SECS_PER_DAY
;
}
}
}
}
else
else
{
{
if
(
*
name
!=
'\0'
)
if
(
*
name
!=
'\0'
)
return
-
1
;
return
-
1
;
/* Initial values of theirstdoffset and theirdstoffset. */
/* Initial values of theirstdoffset and theirdstoffset. */
theirstdoffset
=
0
;
theirstdoffset
=
0
;
for
(
i
=
0
;
i
<
sp
->
timecnt
;
i
++
)
for
(
i
=
0
;
i
<
sp
->
timecnt
;
i
++
)
{
{
j
=
sp
->
types
[
i
];
j
=
sp
->
types
[
i
];
if
(
!
sp
->
ttis
[
j
].
isdst
)
if
(
!
sp
->
ttis
[
j
].
isdst
)
{
{
theirstdoffset
=
-
sp
->
ttis
[
j
].
gmtoff
;
theirstdoffset
=
-
sp
->
ttis
[
j
].
gmtoff
;
break
;
break
;
}
}
}
}
theirdstoffset
=
0
;
theirdstoffset
=
0
;
for
(
i
=
0
;
i
<
sp
->
timecnt
;
i
++
)
for
(
i
=
0
;
i
<
sp
->
timecnt
;
i
++
)
{
{
j
=
sp
->
types
[
i
];
j
=
sp
->
types
[
i
];
if
(
sp
->
ttis
[
j
].
isdst
)
if
(
sp
->
ttis
[
j
].
isdst
)
{
{
theirdstoffset
=
-
sp
->
ttis
[
j
].
gmtoff
;
theirdstoffset
=
-
sp
->
ttis
[
j
].
gmtoff
;
break
;
break
;
}
}
}
}
/* Initially we're assumed to be in standard time. */
/* Initially we're assumed to be in standard time. */
isdst
=
FALSE
;
isdst
=
FALSE
;
theiroffset
=
theirstdoffset
;
theiroffset
=
theirstdoffset
;
/* Now juggle transition times and types tracking offsets as you do. */
/* Now juggle transition times and types tracking offsets as you do. */
for
(
i
=
0
;
i
<
sp
->
timecnt
;
i
++
)
for
(
i
=
0
;
i
<
sp
->
timecnt
;
i
++
)
{
{
j
=
sp
->
types
[
i
];
j
=
sp
->
types
[
i
];
sp
->
types
[
i
]
=
sp
->
ttis
[
j
].
isdst
;
sp
->
types
[
i
]
=
sp
->
ttis
[
j
].
isdst
;
if
(
sp
->
ttis
[
j
].
ttisgmt
)
if
(
sp
->
ttis
[
j
].
ttisgmt
)
{
{
/* No adjustment to transition time */
/* No adjustment to transition time */
}
}
else
else
{
{
/* If summer time is in effect, and the
/* If summer time is in effect, and the
* transition time was not specified as
* transition time was not specified as
* standard time, add the summer time
* standard time, add the summer time
* offset to the transition time;
* offset to the transition time;
* otherwise, add the standard time
* otherwise, add the standard time
* offset to the transition time. */
* offset to the transition time. */
/* Transitions from DST to DDST
/* Transitions from DST to DDST
* will effectively disappear since
* will effectively disappear since
* POSIX provides for only one DST
* POSIX provides for only one DST
* offset. */
* offset. */
if
(
isdst
&&
!
sp
->
ttis
[
j
].
ttisstd
)
if
(
isdst
&&
!
sp
->
ttis
[
j
].
ttisstd
)
sp
->
ats
[
i
]
+=
(
dstoffset
-
theirdstoffset
);
sp
->
ats
[
i
]
+=
(
dstoffset
-
theirdstoffset
);
else
else
sp
->
ats
[
i
]
+=
(
stdoffset
-
theirstdoffset
);
sp
->
ats
[
i
]
+=
(
stdoffset
-
theirstdoffset
);
}
}
theiroffset
=
-
sp
->
ttis
[
j
].
gmtoff
;
theiroffset
=
-
sp
->
ttis
[
j
].
gmtoff
;
if
(
sp
->
ttis
[
j
].
isdst
)
if
(
sp
->
ttis
[
j
].
isdst
)
theirdstoffset
=
theiroffset
;
theirdstoffset
=
theiroffset
;
else
else
theirstdoffset
=
theiroffset
;
theirstdoffset
=
theiroffset
;
}
}
/* Finally, fill in ttis. ttisstd and ttisgmt need not be handled. */
/* Finally, fill in ttis. ttisstd and ttisgmt need not be handled. */
sp
->
ttis
[
0
].
gmtoff
=
-
stdoffset
;
sp
->
ttis
[
0
].
gmtoff
=
-
stdoffset
;
sp
->
ttis
[
0
].
isdst
=
FALSE
;
sp
->
ttis
[
0
].
isdst
=
FALSE
;
sp
->
ttis
[
0
].
abbrind
=
0
;
sp
->
ttis
[
0
].
abbrind
=
0
;
sp
->
ttis
[
1
].
gmtoff
=
-
dstoffset
;
sp
->
ttis
[
1
].
gmtoff
=
-
dstoffset
;
sp
->
ttis
[
1
].
isdst
=
TRUE
;
sp
->
ttis
[
1
].
isdst
=
TRUE
;
sp
->
ttis
[
1
].
abbrind
=
stdlen
+
1
;
sp
->
ttis
[
1
].
abbrind
=
stdlen
+
1
;
sp
->
typecnt
=
2
;
sp
->
typecnt
=
2
;
}
}
}
}
else
else
{
{
dstlen
=
0
;
dstlen
=
0
;
sp
->
typecnt
=
1
;
/* Only standard time */
sp
->
typecnt
=
1
;
/* Only standard time */
sp
->
timecnt
=
0
;
sp
->
timecnt
=
0
;
sp
->
ttis
[
0
].
gmtoff
=
-
stdoffset
;
sp
->
ttis
[
0
].
gmtoff
=
-
stdoffset
;
sp
->
ttis
[
0
].
isdst
=
0
;
sp
->
ttis
[
0
].
isdst
=
0
;
sp
->
ttis
[
0
].
abbrind
=
0
;
sp
->
ttis
[
0
].
abbrind
=
0
;
}
}
sp
->
charcnt
=
stdlen
+
1
;
sp
->
charcnt
=
stdlen
+
1
;
if
(
dstlen
!=
0
)
if
(
dstlen
!=
0
)
sp
->
charcnt
+=
dstlen
+
1
;
sp
->
charcnt
+=
dstlen
+
1
;
if
((
size_t
)
sp
->
charcnt
>
sizeof
(
sp
->
chars
))
if
((
size_t
)
sp
->
charcnt
>
sizeof
(
sp
->
chars
))
return
-
1
;
return
-
1
;
cp
=
sp
->
chars
;
cp
=
sp
->
chars
;
strncpy
(
cp
,
stdname
,
stdlen
);
strncpy
(
cp
,
stdname
,
stdlen
);
cp
+=
stdlen
;
cp
+=
stdlen
;
*
cp
++
=
'\0'
;
*
cp
++
=
'\0'
;
if
(
dstlen
!=
0
)
if
(
dstlen
!=
0
)
{
{
strncpy
(
cp
,
dstname
,
dstlen
);
strncpy
(
cp
,
dstname
,
dstlen
);
cp
[
dstlen
]
=
'\0'
;
cp
[
dstlen
]
=
'\0'
;
}
}
return
0
;
return
0
;
}
}
/*- End of function --------------------------------------------------------*/
/*- End of function --------------------------------------------------------*/
static
void
tz_set
(
tz_t
*
tz
,
const
char
*
tzstring
)
static
void
tz_set
(
tz_t
*
tz
,
const
char
*
tzstring
)
{
{
const
char
*
name
=
""
;
const
char
*
name
=
""
;
struct
tz_state_s
*
lclptr
=
&
tz
->
state
;
struct
tz_state_s
*
lclptr
=
&
tz
->
state
;
if
(
tzstring
)
if
(
tzstring
)
name
=
tzstring
;
name
=
tzstring
;
/* See if we are already set OK */
/* See if we are already set OK */
if
(
tz
->
lcl_is_set
>
0
&&
strcmp
(
tz
->
lcl_tzname
,
name
)
==
0
)
if
(
tz
->
lcl_is_set
>
0
&&
strcmp
(
tz
->
lcl_tzname
,
name
)
==
0
)
return
;
return
;
tz
->
lcl_is_set
=
strlen
(
name
)
<
sizeof
(
tz
->
lcl_tzname
);
tz
->
lcl_is_set
=
strlen
(
name
)
<
sizeof
(
tz
->
lcl_tzname
);
if
(
tz
->
lcl_is_set
)
if
(
tz
->
lcl_is_set
)
strcpy
(
tz
->
lcl_tzname
,
name
);
strcpy
(
tz
->
lcl_tzname
,
name
);
if
(
name
[
0
]
==
'\0'
)
if
(
name
[
0
]
==
'\0'
)
{
{
/* User wants it fast rather than right, so, we're off a little. */
/* User wants it fast rather than right, so, we're off a little. */
lclptr
->
leapcnt
=
0
;
lclptr
->
leapcnt
=
0
;
lclptr
->
timecnt
=
0
;
lclptr
->
timecnt
=
0
;
lclptr
->
typecnt
=
0
;
lclptr
->
typecnt
=
0
;
lclptr
->
ttis
[
0
].
isdst
=
0
;
lclptr
->
ttis
[
0
].
isdst
=
0
;
lclptr
->
ttis
[
0
].
gmtoff
=
0
;
lclptr
->
ttis
[
0
].
gmtoff
=
0
;
lclptr
->
ttis
[
0
].
abbrind
=
0
;
lclptr
->
ttis
[
0
].
abbrind
=
0
;
strcpy
(
lclptr
->
chars
,
gmt
);
strcpy
(
lclptr
->
chars
,
gmt
);
}
}
else
if
(
name
[
0
]
==
':'
||
tzparse
(
name
,
lclptr
,
FALSE
)
!=
0
)
else
if
(
name
[
0
]
==
':'
||
tzparse
(
name
,
lclptr
,
FALSE
)
!=
0
)
{
{
tzparse
(
gmt
,
lclptr
,
TRUE
);
tzparse
(
gmt
,
lclptr
,
TRUE
);
}
}
set_tzname
(
tz
);
set_tzname
(
tz
);
}
}
/*- End of function --------------------------------------------------------*/
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE
(
int
)
tz_localtime
(
tz_t
*
tz
,
struct
tm
*
tmp
,
time_t
t
)
SPAN_DECLARE
(
int
)
tz_localtime
(
tz_t
*
tz
,
struct
tm
*
tmp
,
time_t
t
)
{
{
struct
tz_state_s
*
sp
;
struct
tz_state_s
*
sp
;
const
struct
tz_ttinfo_s
*
ttisp
;
const
struct
tz_ttinfo_s
*
ttisp
;
int
i
;
int
i
;
sp
=
&
tz
->
state
;
sp
=
&
tz
->
state
;
if
(
sp
->
timecnt
==
0
||
t
<
sp
->
ats
[
0
])
if
(
sp
->
timecnt
==
0
||
t
<
sp
->
ats
[
0
])
{
{
i
=
0
;
i
=
0
;
while
(
sp
->
ttis
[
i
].
isdst
)
while
(
sp
->
ttis
[
i
].
isdst
)
{
{
if
(
++
i
>=
sp
->
typecnt
)
if
(
++
i
>=
sp
->
typecnt
)
{
{
i
=
0
;
i
=
0
;
break
;
break
;
}
}
}
}
}
}
else
else
{
{
for
(
i
=
1
;
i
<
sp
->
timecnt
;
i
++
)
for
(
i
=
1
;
i
<
sp
->
timecnt
;
i
++
)
{
{
if
(
t
<
sp
->
ats
[
i
])
if
(
t
<
sp
->
ats
[
i
])
break
;
break
;
}
}
i
=
(
int
)
sp
->
types
[
i
-
1
];
i
=
(
int
)
sp
->
types
[
i
-
1
];
}
}
ttisp
=
&
sp
->
ttis
[
i
];
ttisp
=
&
sp
->
ttis
[
i
];
time_sub
(
&
t
,
ttisp
->
gmtoff
,
sp
,
tmp
);
time_sub
(
&
t
,
ttisp
->
gmtoff
,
sp
,
tmp
);
tmp
->
tm_isdst
=
ttisp
->
isdst
;
tmp
->
tm_isdst
=
ttisp
->
isdst
;
tz
->
tzname
[
tmp
->
tm_isdst
]
=
&
sp
->
chars
[
ttisp
->
abbrind
];
tz
->
tzname
[
tmp
->
tm_isdst
]
=
&
sp
->
chars
[
ttisp
->
abbrind
];
return
0
;
return
0
;
}
}
/*- End of function --------------------------------------------------------*/
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE
(
const
char
*
)
tz_tzname
(
tz_t
*
tz
,
int
isdst
)
SPAN_DECLARE
(
const
char
*
)
tz_tzname
(
tz_t
*
tz
,
int
isdst
)
{
{
return
tz
->
tzname
[(
!
isdst
)
?
0
:
1
];
return
tz
->
tzname
[(
!
isdst
)
?
0
:
1
];
}
}
/*- End of function --------------------------------------------------------*/
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE
(
tz_t
*
)
tz_init
(
tz_t
*
tz
,
const
char
*
tzstring
)
SPAN_DECLARE
(
tz_t
*
)
tz_init
(
tz_t
*
tz
,
const
char
*
tzstring
)
{
{
if
(
tz
==
NULL
)
if
(
tz
==
NULL
)
{
{
if
((
tz
=
(
tz_t
*
)
malloc
(
sizeof
(
*
tz
)))
==
NULL
)
if
((
tz
=
(
tz_t
*
)
malloc
(
sizeof
(
*
tz
)))
==
NULL
)
return
NULL
;
return
NULL
;
}
}
memset
(
tz
,
0
,
sizeof
(
*
tz
));
memset
(
tz
,
0
,
sizeof
(
*
tz
));
tz
->
tzname
[
0
]
=
tz
->
tzname
[
0
]
=
tz
->
tzname
[
1
]
=
wildabbr
;
tz
->
tzname
[
1
]
=
wildabbr
;
tz_set
(
tz
,
tzstring
);
tz_set
(
tz
,
tzstring
);
return
tz
;
return
tz
;
}
}
/*- End of function --------------------------------------------------------*/
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE
(
int
)
tz_release
(
tz_t
*
tz
)
SPAN_DECLARE
(
int
)
tz_release
(
tz_t
*
tz
)
{
{
return
0
;
return
0
;
}
}
/*- End of function --------------------------------------------------------*/
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE
(
int
)
tz_free
(
tz_t
*
tz
)
SPAN_DECLARE
(
int
)
tz_free
(
tz_t
*
tz
)
{
{
if
(
tz
)
if
(
tz
)
free
(
tz
);
free
(
tz
);
return
0
;
return
0
;
}
}
/*- End of function --------------------------------------------------------*/
/*- End of function --------------------------------------------------------*/
/*- End of file ------------------------------------------------------------*/
/*- End of file ------------------------------------------------------------*/
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论