Import tzcode 2022g
This commit is contained in:
parent
cc16bfc34e
commit
85639444f4
55
Makefile
55
Makefile
@ -196,6 +196,7 @@ PACKRATLIST=
|
||||
UTF8_LOCALE= en_US.utf8
|
||||
|
||||
# Non-default libraries needed to link.
|
||||
# On some hosts, this should have -lintl unless CFLAGS has -DHAVE_GETTEXT=0.
|
||||
LDLIBS=
|
||||
|
||||
# Add the following to the end of the "CFLAGS=" line as needed to override
|
||||
@ -208,14 +209,18 @@ LDLIBS=
|
||||
# For example, N is 252460800 on AmigaOS.
|
||||
# -DHAVE_DECL_ASCTIME_R=0 if <time.h> does not declare asctime_r
|
||||
# -DHAVE_DECL_ENVIRON if <unistd.h> declares 'environ'
|
||||
# -DHAVE_DECL_TIMEGM=0 if <time.h> does not declare timegm
|
||||
# -DHAVE_DIRECT_H if mkdir needs <direct.h> (MS-Windows)
|
||||
# -DHAVE_GENERIC=0 if _Generic does not work
|
||||
# -DHAVE_GETRANDOM if getgrandom works (e.g., GNU/Linux)*
|
||||
# -DHAVE_GETTEXT if 'gettext' works (e.g., GNU/Linux, FreeBSD, Solaris)*
|
||||
# -DHAVE_GENERIC=0 if _Generic does not work*
|
||||
# -DHAVE_GETRANDOM if getrandom works (e.g., GNU/Linux),
|
||||
# -DHAVE_GETRANDOM=0 to avoid using getrandom
|
||||
# -DHAVE_GETTEXT if gettext works (e.g., GNU/Linux, FreeBSD, Solaris),
|
||||
# where LDLIBS also needs to contain -lintl on some hosts;
|
||||
# -DHAVE_GETTEXT=0 to avoid using gettext
|
||||
# -DHAVE_INCOMPATIBLE_CTIME_R if your system's time.h declares
|
||||
# ctime_r and asctime_r incompatibly with the POSIX standard
|
||||
# (Solaris when _POSIX_PTHREAD_SEMANTICS is not defined).
|
||||
# -DHAVE_INTTYPES_H if you have a non-C99 compiler with <inttypes.h>
|
||||
# -DHAVE_INTTYPES_H=0 if <inttypes.h> does not work*
|
||||
# -DHAVE_LINK=0 if your system lacks a link function
|
||||
# -DHAVE_LOCALTIME_R=0 if your system lacks a localtime_r function
|
||||
# -DHAVE_LOCALTIME_RZ=0 if you do not want zdump to use localtime_rz
|
||||
@ -225,15 +230,17 @@ LDLIBS=
|
||||
# functions like 'link' or variables like 'tzname' required by POSIX
|
||||
# -DHAVE_SETENV=0 if your system lacks the setenv function
|
||||
# -DHAVE_SNPRINTF=0 if your system lacks the snprintf function
|
||||
# -DHAVE_STDINT_H if you have a non-C99 compiler with <stdint.h>*
|
||||
# -DHAVE_STDCKDINT_H=0 if neither <stdckdint.h> nor substitutes like
|
||||
# __builtin_add_overflow work*
|
||||
# -DHAVE_STDINT_H=0 if <stdint.h> does not work*
|
||||
# -DHAVE_STRFTIME_L if <time.h> declares locale_t and strftime_l
|
||||
# -DHAVE_STRDUP=0 if your system lacks the strdup function
|
||||
# -DHAVE_STRTOLL=0 if your system lacks the strtoll function
|
||||
# -DHAVE_SYMLINK=0 if your system lacks the symlink function
|
||||
# -DHAVE_SYS_STAT_H=0 if your compiler lacks a <sys/stat.h>*
|
||||
# -DHAVE_SYS_STAT_H=0 if <sys/stat.h> does not work*
|
||||
# -DHAVE_TZSET=0 if your system lacks a tzset function
|
||||
# -DHAVE_UNISTD_H=0 if your compiler lacks a <unistd.h>*
|
||||
# -DHAVE_UTMPX_H=0 if your compiler lacks a <utmpx.h>*
|
||||
# -DHAVE_UNISTD_H=0 if <unistd.h> does not work*
|
||||
# -DHAVE_UTMPX_H=0 if <utmpx.h> does not work*
|
||||
# -Dlocale_t=XXX if your system uses XXX instead of locale_t
|
||||
# -DRESERVE_STD_EXT_IDS if your platform reserves standard identifiers
|
||||
# with external linkage, e.g., applications cannot define 'localtime'.
|
||||
@ -280,7 +287,7 @@ GCC_DEBUG_FLAGS = -DGCC_LINT -g3 -O3 -fno-common \
|
||||
-Wdeclaration-after-statement -Wdouble-promotion \
|
||||
-Wduplicated-branches -Wduplicated-cond \
|
||||
-Wformat=2 -Wformat-overflow=2 -Wformat-signedness -Wformat-truncation \
|
||||
-Winit-self -Wlogical-op \
|
||||
-Wimplicit-fallthrough=5 -Winit-self -Wlogical-op \
|
||||
-Wmissing-declarations -Wmissing-prototypes -Wnested-externs \
|
||||
-Wnull-dereference \
|
||||
-Wold-style-definition -Woverlength-strings -Wpointer-arith \
|
||||
@ -293,7 +300,7 @@ GCC_DEBUG_FLAGS = -DGCC_LINT -g3 -O3 -fno-common \
|
||||
-Wtrampolines -Wundef -Wuninitialized -Wunused-macros -Wuse-after-free=3 \
|
||||
-Wvariadic-macros -Wvla -Wwrite-strings \
|
||||
-Wno-address -Wno-format-nonliteral -Wno-sign-compare \
|
||||
-Wno-type-limits -Wno-unused-parameter
|
||||
-Wno-type-limits
|
||||
#
|
||||
# If your system has a "GMT offset" field in its "struct tm"s
|
||||
# (or if you decide to add such a field in your system's "time.h" file),
|
||||
@ -340,14 +347,11 @@ GCC_DEBUG_FLAGS = -DGCC_LINT -g3 -O3 -fno-common \
|
||||
# If you want functions that were inspired by early versions of X3J11's work,
|
||||
# add
|
||||
# -DSTD_INSPIRED
|
||||
# to the end of the "CFLAGS=" line. This arranges for the functions
|
||||
# "offtime", "timelocal", "timegm", "timeoff",
|
||||
# "posix2time", and "time2posix" to be added to the time conversion library.
|
||||
# to the end of the "CFLAGS=" line. This arranges for the following
|
||||
# functions to be added to the time conversion library.
|
||||
# "offtime" is like "gmtime" except that it accepts a second (long) argument
|
||||
# that gives an offset to add to the time_t when converting it.
|
||||
# "timelocal" is equivalent to "mktime".
|
||||
# "timegm" is like "timelocal" except that it turns a struct tm into
|
||||
# a time_t using UT (rather than local time as "timelocal" does).
|
||||
# "timeoff" is like "timegm" except that it accepts a second (long) argument
|
||||
# that gives an offset to use when converting to a time_t.
|
||||
# "posix2time" and "time2posix" are described in an included manual page.
|
||||
@ -495,6 +499,11 @@ TARFLAGS= `if tar $(GNUTARFLAGS) --version >/dev/null 2>&1; \
|
||||
# Flags to give 'gzip' when making a distribution.
|
||||
GZIPFLAGS= -9n
|
||||
|
||||
# When comparing .tzs files, use GNU diff's -F'^TZ=' option if supported.
|
||||
# This makes it easier to see which Zone has been affected.
|
||||
DIFF_TZS= diff -u$$(! diff -u -F'^TZ=' - - <>/dev/null >&0 2>&1 \
|
||||
|| echo ' -F^TZ=')
|
||||
|
||||
###############################################################################
|
||||
|
||||
#MAKE= make
|
||||
@ -773,7 +782,8 @@ tzselect: tzselect.ksh version
|
||||
chmod +x $@.out
|
||||
mv $@.out $@
|
||||
|
||||
check: check_character_set check_white_space check_links \
|
||||
check: check_back check_mild
|
||||
check_mild: check_character_set check_white_space check_links \
|
||||
check_name_lengths check_slashed_abbrs check_sorted \
|
||||
check_tables check_web check_ziguard check_zishrink check_tzs
|
||||
|
||||
@ -824,16 +834,19 @@ check_slashed_abbrs: $(TDATA_TO_CHECK)
|
||||
CHECK_CC_LIST = { n = split($$1,a,/,/); for (i=2; i<=n; i++) print a[1], a[i]; }
|
||||
|
||||
check_sorted: backward backzone iso3166.tab zone.tab zone1970.tab
|
||||
$(AWK) '/^Link/ {printf "%.5d %s\n", g, $$3} /^$$/ {g++}' \
|
||||
$(AWK) '/^Link/ {printf "%.5d %s\n", g, $$3} !/./ {g++}' \
|
||||
backward | LC_ALL=C sort -cu
|
||||
$(AWK) '/^Zone/ {print $$2}' backzone | LC_ALL=C sort -cu
|
||||
touch $@
|
||||
|
||||
check_links: checklinks.awk $(TDATA_TO_CHECK) tzdata.zi
|
||||
check_back: checklinks.awk $(TDATA_TO_CHECK)
|
||||
$(AWK) \
|
||||
-v DATAFORM=$(DATAFORM) \
|
||||
-v backcheck=backward \
|
||||
-f checklinks.awk $(TDATA_TO_CHECK)
|
||||
touch $@
|
||||
|
||||
check_links: checklinks.awk tzdata.zi
|
||||
$(AWK) \
|
||||
-v DATAFORM=$(DATAFORM) \
|
||||
-f checklinks.awk tzdata.zi
|
||||
@ -849,7 +862,7 @@ check_tables: checktab.awk $(YDATA) backward $(ZONETABLES)
|
||||
|
||||
check_tzs: $(TZS) $(TZS_NEW)
|
||||
if test -s $(TZS); then \
|
||||
diff -u $(TZS) $(TZS_NEW); \
|
||||
$(DIFF_TZS) $(TZS) $(TZS_NEW); \
|
||||
else \
|
||||
cp $(TZS_NEW) $(TZS); \
|
||||
fi
|
||||
@ -1050,7 +1063,7 @@ $(TIME_T_ALTERNATIVES): $(VERSION_DEPS)
|
||||
TZS_YEAR="$$range" TZS_CUTOFF_FLAG="-t $$range" \
|
||||
D=$$wd/$@.dir \
|
||||
to$$range.tzs) && \
|
||||
diff -u $(TIME_T_ALTERNATIVES_HEAD).dir/to$$range.tzs \
|
||||
$(DIFF_TZS) $(TIME_T_ALTERNATIVES_HEAD).dir/to$$range.tzs \
|
||||
$@.dir/to$$range.tzs && \
|
||||
if diff -q Makefile Makefile 2>/dev/null; then \
|
||||
quiet_option='-q'; \
|
||||
@ -1220,7 +1233,7 @@ zdump.o: version.h
|
||||
zic.o: private.h tzfile.h version.h
|
||||
|
||||
.PHONY: ALL INSTALL all
|
||||
.PHONY: check check_time_t_alternatives
|
||||
.PHONY: check check_mild check_time_t_alternatives
|
||||
.PHONY: check_web check_zishrink
|
||||
.PHONY: clean clean_misc dummy.zd force_tzs
|
||||
.PHONY: install install_data maintainer-clean names
|
||||
|
89
NEWS
89
NEWS
@ -1,5 +1,91 @@
|
||||
News for the tz database
|
||||
|
||||
Release 2022g - 2022-11-29 08:58:31 -0800
|
||||
|
||||
Briefly:
|
||||
The northern edge of Chihuahua changes to US timekeeping.
|
||||
Much of Greenland stops changing clocks after March 2023.
|
||||
Fix some pre-1996 timestamps in northern Canada.
|
||||
C89 is now deprecated; please use C99 or later.
|
||||
Portability fixes for AIX, libintl, MS-Windows, musl, z/OS
|
||||
In C code, use more C23 features if available.
|
||||
C23 timegm now supported by default
|
||||
Fixes for unlikely integer overflows
|
||||
|
||||
Changes to future timestamps
|
||||
|
||||
In the Mexican state of Chihuahua, the border strip near the US
|
||||
will change to agree with nearby US locations on 2022-11-30.
|
||||
The strip's western part, represented by Ciudad Juárez, switches
|
||||
from -06 all year to -07/-06 with US DST rules, like El Paso, TX.
|
||||
The eastern part, represented by Ojinaga, will observe US DST next
|
||||
year, like Presidio, TX. (Thanks to Heitor David Pinto.)
|
||||
A new Zone America/Ciudad_Juarez splits from America/Ojinaga.
|
||||
|
||||
Much of Greenland, represented by America/Nuuk, stops observing
|
||||
winter time after March 2023, so its daylight saving time becomes
|
||||
standard time. (Thanks to Jonas Nyrup and Jürgen Appel.)
|
||||
|
||||
Changes to past timestamps
|
||||
|
||||
Changes for pre-1996 northern Canada (thanks to Chris Walton):
|
||||
|
||||
Merge America/Iqaluit and America/Pangnirtung into the former,
|
||||
with a backward compatibility link for the latter name.
|
||||
There is no good evidence the two locations differ since 1970.
|
||||
This change affects pre-1996 America/Pangnirtung timestamps.
|
||||
|
||||
Cambridge Bay, Inuvik, Iqaluit, Rankin Inlet, Resolute and
|
||||
Yellowknife did not observe DST in 1965, and did observe DST
|
||||
from 1972 through 1979.
|
||||
|
||||
Whitehorse moved from -09 to -08 on 1966-02-27, not 1967-05-28.
|
||||
|
||||
Colombia's 1993 fallback was 02-06 24:00, not 04-04 00:00.
|
||||
(Thanks to Alois Treindl.)
|
||||
|
||||
Singapore's 1981-12-31 change was at 16:00 UTC (23:30 local time),
|
||||
not 24:00 local time. (Thanks to Geoff Clare via Robert Elz.)
|
||||
|
||||
Changes to code
|
||||
|
||||
Although tzcode still works with C89, bugs found in recent routine
|
||||
maintenance indicate that bitrot has set in and that in practice
|
||||
C89 is no longer used to build tzcode. As it is a maintenance
|
||||
burden, support for C89 is planned to be removed soon. Instead,
|
||||
please use compilers compatible with C99, C11, C17, or C23.
|
||||
|
||||
timegm, which tzcode implemented in 1989, will finally be
|
||||
standardized 34 years later as part of C23, so timegm is now
|
||||
supported even if STD_INSPIRED is not defined.
|
||||
|
||||
Fix bug in zdump's tzalloc emulation on hosts that lack tm_zone.
|
||||
(Problem reported by Đoàn Trần Công Danh.)
|
||||
|
||||
Fix bug in zic on hosts where malloc(0) yields NULL on success.
|
||||
(Problem reported by Tim McBrayer for AIX 6.1.)
|
||||
|
||||
Fix zic configuration to avoid linkage failures on some platforms.
|
||||
(Problems reported by Gilmore Davidson and Igor Ivanov.)
|
||||
|
||||
Work around MS-Windows nmake incompatibility with POSIX.
|
||||
(Problem reported by Manuela Friedrich.)
|
||||
|
||||
Port mktime and strftime to debugging platforms where accessing
|
||||
uninitialized data has undefined behavior (strftime problem
|
||||
reported by Robert Elz).
|
||||
|
||||
Check more carefully for unlikely integer overflows, preferring
|
||||
C23 <stdckdint.h> to overflow checking by hand, as the latter has
|
||||
had obscure bugs.
|
||||
|
||||
Changes to build procedure
|
||||
|
||||
New Makefile rule check_mild that skips checking whether Link
|
||||
lines are in the file 'backward'. (Inspired by a suggestion from
|
||||
Stephen Colebourne.)
|
||||
|
||||
|
||||
Release 2022f - 2022-10-28 18:04:57 -0700
|
||||
|
||||
Briefly:
|
||||
@ -16,7 +102,7 @@ Release 2022f - 2022-10-28 18:04:57 -0700
|
||||
In C code, use some C23 features if available.
|
||||
Remove no-longer-needed workaround for Qt bug 53071.
|
||||
|
||||
Changes to future timestamps.
|
||||
Changes to future timestamps
|
||||
|
||||
Mexico will no longer observe DST after 2022, except for areas
|
||||
near the US border that continue to observe US DST rules.
|
||||
@ -24,6 +110,7 @@ Release 2022f - 2022-10-28 18:04:57 -0700
|
||||
from -07 (-06 with DST) to year-round -06, thus not changing
|
||||
its clocks that day. The new law states that Chihuahua
|
||||
near the US border no longer observes US DST.
|
||||
(Thanks to gera for the heads-up about Chihuahua.)
|
||||
|
||||
Fiji will not observe DST in 2022/3. (Thanks to Shalvin Narayan.)
|
||||
For now, assume DST is suspended indefinitely.
|
||||
|
8
date.1
8
date.1
@ -1,10 +1,12 @@
|
||||
.TH DATE 1
|
||||
.\" This file is in the public domain, so clarified as of
|
||||
.\" 2009-05-17 by Arthur David Olson.
|
||||
.TH date 1
|
||||
.SH NAME
|
||||
date \- show and set date and time
|
||||
.SH SYNOPSIS
|
||||
.if n .nh
|
||||
.if n .na
|
||||
.ie \n(.g .ds - \f(CW-\fP
|
||||
.ie \n(.g .ds - \f(CR-\fP
|
||||
.el .ds - \-
|
||||
.B date
|
||||
[
|
||||
@ -163,5 +165,3 @@ If
|
||||
is absent,
|
||||
UTC leap seconds are loaded from
|
||||
.BR /usr/share/zoneinfo/posixrules .
|
||||
.\" This file is in the public domain, so clarified as of
|
||||
.\" 2009-05-17 by Arthur David Olson.
|
||||
|
@ -1,4 +1,4 @@
|
||||
DATE(1) General Commands Manual DATE(1)
|
||||
date(1) General Commands Manual date(1)
|
||||
|
||||
NAME
|
||||
date - show and set date and time
|
||||
@ -104,4 +104,4 @@ FILES
|
||||
If /usr/share/zoneinfo/GMT is absent, UTC leap seconds are loaded from
|
||||
/usr/share/zoneinfo/posixrules.
|
||||
|
||||
DATE(1)
|
||||
date(1)
|
||||
|
44
date.c
44
date.c
@ -42,7 +42,7 @@ static void display(const char *, time_t);
|
||||
static void dogmt(void);
|
||||
static void errensure(void);
|
||||
static void timeout(FILE *, const char *, const struct tm *);
|
||||
static _Noreturn void usage(void);
|
||||
static ATTRIBUTE_NORETURN void usage(void);
|
||||
|
||||
int
|
||||
main(const int argc, char *argv[])
|
||||
@ -117,14 +117,19 @@ dogmt(void)
|
||||
static char ** fakeenv;
|
||||
|
||||
if (fakeenv == NULL) {
|
||||
register int from;
|
||||
register int to;
|
||||
register int n;
|
||||
static char tzeutc0[] = "TZ=UTC0";
|
||||
ptrdiff_t from, to, n;
|
||||
|
||||
for (n = 0; environ[n] != NULL; ++n)
|
||||
continue;
|
||||
fakeenv = malloc((n + 2) * sizeof *fakeenv);
|
||||
#if defined ckd_add && defined ckd_mul
|
||||
if (!ckd_add(&n, n, 2) && !ckd_mul(&n, n, sizeof *fakeenv)
|
||||
&& n <= SIZE_MAX)
|
||||
fakeenv = malloc(n);
|
||||
#else
|
||||
if (n <= min(PTRDIFF_MAX, SIZE_MAX) / sizeof *fakeenv - 2)
|
||||
fakeenv = malloc((n + 2) * sizeof *fakeenv);
|
||||
#endif
|
||||
if (fakeenv == NULL) {
|
||||
fprintf(stderr, _("date: Memory exhausted\n"));
|
||||
errensure();
|
||||
@ -183,33 +188,28 @@ display(char const *format, time_t now)
|
||||
static void
|
||||
timeout(FILE *fp, char const *format, struct tm const *tmp)
|
||||
{
|
||||
char * cp;
|
||||
size_t result;
|
||||
size_t size;
|
||||
struct tm tm;
|
||||
int INCR = 1024;
|
||||
char *cp = NULL;
|
||||
ptrdiff_t result;
|
||||
ptrdiff_t size = 1024 / 2;
|
||||
|
||||
if (!tmp) {
|
||||
fprintf(stderr, _("date: error: time out of range\n"));
|
||||
errensure();
|
||||
return;
|
||||
}
|
||||
tm = *tmp;
|
||||
tmp = &tm;
|
||||
size = INCR;
|
||||
cp = malloc(size);
|
||||
for ( ; ; ) {
|
||||
if (cp == NULL) {
|
||||
#ifdef ckd_mul
|
||||
bool bigger = !ckd_mul(&size, size, 2) && size <= SIZE_MAX;
|
||||
#else
|
||||
bool bigger = (size <= min(PTRDIFF_MAX, SIZE_MAX) / 2
|
||||
&& (size *= 2, true));
|
||||
#endif
|
||||
char *newcp = bigger ? realloc(cp, size) : NULL;
|
||||
if (!newcp) {
|
||||
fprintf(stderr,
|
||||
_("date: error: can't get memory\n"));
|
||||
errensure();
|
||||
exit(retval);
|
||||
}
|
||||
cp = newcp;
|
||||
result = strftime(cp, size, format, tmp);
|
||||
if (result != 0)
|
||||
break;
|
||||
size += INCR;
|
||||
cp = realloc(cp, size);
|
||||
}
|
||||
fwrite(cp + 1, 1, result - 1, fp);
|
||||
free(cp);
|
||||
|
94
localtime.c
94
localtime.c
@ -425,8 +425,7 @@ tzloadbody(char const *name, struct state *sp, bool doextend,
|
||||
#endif
|
||||
if (!doaccess) {
|
||||
char const *dot;
|
||||
size_t namelen = strlen(name);
|
||||
if (sizeof lsp->fullname - sizeof tzdirslash <= namelen)
|
||||
if (sizeof lsp->fullname - sizeof tzdirslash <= strlen(name))
|
||||
return ENAMETOOLONG;
|
||||
|
||||
/* Create a string "TZDIR/NAME". Using sprintf here
|
||||
@ -839,7 +838,7 @@ is_digit(char c)
|
||||
** Return a pointer to that character.
|
||||
*/
|
||||
|
||||
static ATTRIBUTE_PURE const char *
|
||||
static ATTRIBUTE_REPRODUCIBLE const char *
|
||||
getzname(register const char *strp)
|
||||
{
|
||||
register char c;
|
||||
@ -860,7 +859,7 @@ getzname(register const char *strp)
|
||||
** We don't do any checking here; checking is done later in common-case code.
|
||||
*/
|
||||
|
||||
static ATTRIBUTE_PURE const char *
|
||||
static ATTRIBUTE_REPRODUCIBLE const char *
|
||||
getqzname(register const char *strp, const int delim)
|
||||
{
|
||||
register int c;
|
||||
@ -1120,13 +1119,11 @@ tzparse(const char *name, struct state *sp, struct state *basep)
|
||||
{
|
||||
const char * stdname;
|
||||
const char * dstname;
|
||||
size_t stdlen;
|
||||
size_t dstlen;
|
||||
size_t charcnt;
|
||||
int_fast32_t stdoffset;
|
||||
int_fast32_t dstoffset;
|
||||
register char * cp;
|
||||
register bool load_ok;
|
||||
ptrdiff_t stdlen, dstlen, charcnt;
|
||||
time_t atlo = TIME_T_MIN, leaplo = TIME_T_MIN;
|
||||
|
||||
stdname = name;
|
||||
@ -1568,6 +1565,14 @@ localsub(struct state const *sp, time_t const *timep, int_fast32_t setname,
|
||||
return NULL; /* "cannot happen" */
|
||||
result = localsub(sp, &newt, setname, tmp);
|
||||
if (result) {
|
||||
#if defined ckd_add && defined ckd_sub
|
||||
if (t < sp->ats[0]
|
||||
? ckd_sub(&result->tm_year,
|
||||
result->tm_year, years)
|
||||
: ckd_add(&result->tm_year,
|
||||
result->tm_year, years))
|
||||
return NULL;
|
||||
#else
|
||||
register int_fast64_t newy;
|
||||
|
||||
newy = result->tm_year;
|
||||
@ -1577,6 +1582,7 @@ localsub(struct state const *sp, time_t const *timep, int_fast32_t setname,
|
||||
if (! (INT_MIN <= newy && newy <= INT_MAX))
|
||||
return NULL;
|
||||
result->tm_year = newy;
|
||||
#endif
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@ -1656,8 +1662,8 @@ localtime_r(const time_t *timep, struct tm *tmp)
|
||||
*/
|
||||
|
||||
static struct tm *
|
||||
gmtsub(struct state const *sp, time_t const *timep, int_fast32_t offset,
|
||||
struct tm *tmp)
|
||||
gmtsub(ATTRIBUTE_MAYBE_UNUSED struct state const *sp, time_t const *timep,
|
||||
int_fast32_t offset, struct tm *tmp)
|
||||
{
|
||||
register struct tm * result;
|
||||
|
||||
@ -1786,6 +1792,12 @@ timesub(const time_t *timep, int_fast32_t offset,
|
||||
y = newy;
|
||||
}
|
||||
|
||||
#ifdef ckd_add
|
||||
if (ckd_add(&tmp->tm_year, y, -TM_YEAR_BASE)) {
|
||||
errno = EOVERFLOW;
|
||||
return NULL;
|
||||
}
|
||||
#else
|
||||
if (!TYPE_SIGNED(time_t) && y < TM_YEAR_BASE) {
|
||||
int signed_y = y;
|
||||
tmp->tm_year = signed_y - TM_YEAR_BASE;
|
||||
@ -1796,6 +1808,7 @@ timesub(const time_t *timep, int_fast32_t offset,
|
||||
errno = EOVERFLOW;
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
tmp->tm_yday = idays;
|
||||
/*
|
||||
** The "extra" mods below avoid overflow problems.
|
||||
@ -1870,6 +1883,9 @@ ctime_r(const time_t *timep, char *buf)
|
||||
static bool
|
||||
increment_overflow(int *ip, int j)
|
||||
{
|
||||
#ifdef ckd_add
|
||||
return ckd_add(ip, *ip, j);
|
||||
#else
|
||||
register int const i = *ip;
|
||||
|
||||
/*
|
||||
@ -1882,22 +1898,30 @@ increment_overflow(int *ip, int j)
|
||||
return true;
|
||||
*ip += j;
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool
|
||||
increment_overflow32(int_fast32_t *const lp, int const m)
|
||||
{
|
||||
#ifdef ckd_add
|
||||
return ckd_add(lp, *lp, m);
|
||||
#else
|
||||
register int_fast32_t const l = *lp;
|
||||
|
||||
if ((l >= 0) ? (m > INT_FAST32_MAX - l) : (m < INT_FAST32_MIN - l))
|
||||
return true;
|
||||
*lp += m;
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool
|
||||
increment_overflow_time(time_t *tp, int_fast32_t j)
|
||||
{
|
||||
#ifdef ckd_add
|
||||
return ckd_add(tp, *tp, j);
|
||||
#else
|
||||
/*
|
||||
** This is like
|
||||
** 'if (! (TIME_T_MIN <= *tp + j && *tp + j <= TIME_T_MAX)) ...',
|
||||
@ -1909,6 +1933,7 @@ increment_overflow_time(time_t *tp, int_fast32_t j)
|
||||
return true;
|
||||
*tp += j;
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool
|
||||
@ -1951,6 +1976,23 @@ tmcomp(register const struct tm *const atmp,
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Copy to *DEST from *SRC. Copy only the members needed for mktime,
|
||||
as other members might not be initialized. */
|
||||
static void
|
||||
mktmcpy(struct tm *dest, struct tm const *src)
|
||||
{
|
||||
dest->tm_sec = src->tm_sec;
|
||||
dest->tm_min = src->tm_min;
|
||||
dest->tm_hour = src->tm_hour;
|
||||
dest->tm_mday = src->tm_mday;
|
||||
dest->tm_mon = src->tm_mon;
|
||||
dest->tm_year = src->tm_year;
|
||||
dest->tm_isdst = src->tm_isdst;
|
||||
#if defined TM_GMTOFF && ! UNINIT_TRAP
|
||||
dest->TM_GMTOFF = src->TM_GMTOFF;
|
||||
#endif
|
||||
}
|
||||
|
||||
static time_t
|
||||
time2sub(struct tm *const tmp,
|
||||
struct tm *(*funcp)(struct state const *, time_t const *,
|
||||
@ -1972,7 +2014,8 @@ time2sub(struct tm *const tmp,
|
||||
struct tm yourtm, mytm;
|
||||
|
||||
*okayp = false;
|
||||
yourtm = *tmp;
|
||||
mktmcpy(&yourtm, tmp);
|
||||
|
||||
if (do_norm_secs) {
|
||||
if (normalize_overflow(&yourtm.tm_min, &yourtm.tm_sec,
|
||||
SECSPERMIN))
|
||||
@ -2014,14 +2057,19 @@ time2sub(struct tm *const tmp,
|
||||
return WRONG;
|
||||
}
|
||||
}
|
||||
#ifdef ckd_add
|
||||
if (ckd_add(&yourtm.tm_year, y, -TM_YEAR_BASE))
|
||||
return WRONG;
|
||||
#else
|
||||
if (increment_overflow32(&y, -TM_YEAR_BASE))
|
||||
return WRONG;
|
||||
if (! (INT_MIN <= y && y <= INT_MAX))
|
||||
return WRONG;
|
||||
yourtm.tm_year = y;
|
||||
#endif
|
||||
if (yourtm.tm_sec >= 0 && yourtm.tm_sec < SECSPERMIN)
|
||||
saved_seconds = 0;
|
||||
else if (y + TM_YEAR_BASE < EPOCH_YEAR) {
|
||||
else if (yourtm.tm_year < EPOCH_YEAR - TM_YEAR_BASE) {
|
||||
/*
|
||||
** We can't set tm_sec to 0, because that might push the
|
||||
** time below the minimum representable time.
|
||||
@ -2278,7 +2326,6 @@ mktime(struct tm *tmp)
|
||||
}
|
||||
|
||||
#ifdef STD_INSPIRED
|
||||
|
||||
time_t
|
||||
timelocal(struct tm *tmp)
|
||||
{
|
||||
@ -2286,13 +2333,9 @@ timelocal(struct tm *tmp)
|
||||
tmp->tm_isdst = -1; /* in case it wasn't initialized */
|
||||
return mktime(tmp);
|
||||
}
|
||||
|
||||
time_t
|
||||
timegm(struct tm *tmp)
|
||||
{
|
||||
return timeoff(tmp, 0);
|
||||
}
|
||||
|
||||
#else
|
||||
static
|
||||
#endif
|
||||
time_t
|
||||
timeoff(struct tm *tmp, long offset)
|
||||
{
|
||||
@ -2302,7 +2345,18 @@ timeoff(struct tm *tmp, long offset)
|
||||
return time1(tmp, gmtsub, gmtptr, offset);
|
||||
}
|
||||
|
||||
#endif /* defined STD_INSPIRED */
|
||||
time_t
|
||||
timegm(struct tm *tmp)
|
||||
{
|
||||
time_t t;
|
||||
struct tm tmcpy;
|
||||
mktmcpy(&tmcpy, tmp);
|
||||
tmcpy.tm_wday = -1;
|
||||
t = timeoff(&tmcpy, 0);
|
||||
if (0 <= tmcpy.tm_wday)
|
||||
*tmp = tmcpy;
|
||||
return t;
|
||||
}
|
||||
|
||||
static int_fast32_t
|
||||
leapcorr(struct state const *sp, time_t t)
|
||||
|
@ -1,9 +1,11 @@
|
||||
.\" This file is in the public domain, so clarified as of
|
||||
.\" 2009-05-17 by Arthur David Olson.
|
||||
.TH NEWCTIME 3
|
||||
.SH NAME
|
||||
asctime, ctime, difftime, gmtime, localtime, mktime \- convert date and time
|
||||
.SH SYNOPSIS
|
||||
.nf
|
||||
.ie \n(.g .ds - \f(CW-\fP
|
||||
.ie \n(.g .ds - \f(CR-\fP
|
||||
.el .ds - \-
|
||||
.B #include <time.h>
|
||||
.PP
|
||||
@ -340,5 +342,3 @@ restricted to years in the range 1900 through 2099.
|
||||
To avoid this portability mess, new programs should use
|
||||
.B strftime
|
||||
instead.
|
||||
.\" This file is in the public domain, so clarified as of
|
||||
.\" 2009-05-17 by Arthur David Olson.
|
||||
|
@ -40,7 +40,7 @@
|
||||
strftime \- format date and time
|
||||
.SH SYNOPSIS
|
||||
.nf
|
||||
.ie \n(.g .ds - \f(CW-\fP
|
||||
.ie \n(.g .ds - \f(CR-\fP
|
||||
.el .ds - \-
|
||||
.B #include <time.h>
|
||||
.PP
|
||||
@ -55,7 +55,7 @@ strftime \- format date and time
|
||||
.ie '\(rq'' .ds rq \&"\"
|
||||
.el .ds rq \(rq\"
|
||||
.de c
|
||||
.ie \n(.g \f(CW\\$1\fP\\$2
|
||||
.ie \n(.g \f(CR\\$1\fP\\$2
|
||||
.el \\$1\\$2
|
||||
..
|
||||
.de q
|
||||
|
@ -1,9 +1,11 @@
|
||||
.\" This file is in the public domain, so clarified as of
|
||||
.\" 2009-05-17 by Arthur David Olson.
|
||||
.TH NEWTZSET 3
|
||||
.SH NAME
|
||||
tzset \- initialize time conversion information
|
||||
.SH SYNOPSIS
|
||||
.nf
|
||||
.ie \n(.g .ds - \f(CW-\fP
|
||||
.ie \n(.g .ds - \f(CR-\fP
|
||||
.el .ds - \-
|
||||
.B #include <time.h>
|
||||
.PP
|
||||
@ -331,7 +333,7 @@ from the rest of the specification.
|
||||
.br
|
||||
/usr/share/zoneinfo/localtime local timezone file
|
||||
.br
|
||||
/usr/share/zoneinfo/posixrules used with POSIX-style TZ's
|
||||
/usr/share/zoneinfo/posixrules used with POSIX-style TZ
|
||||
.br
|
||||
/usr/share/zoneinfo/GMT for UTC leap seconds
|
||||
.sp
|
||||
@ -346,5 +348,3 @@ newctime(3),
|
||||
newstrftime(3),
|
||||
time(2),
|
||||
tzfile(5)
|
||||
.\" This file is in the public domain, so clarified as of
|
||||
.\" 2009-05-17 by Arthur David Olson.
|
||||
|
@ -187,7 +187,7 @@ DESCRIPTION
|
||||
FILES
|
||||
/usr/share/zoneinfo timezone information directory
|
||||
/usr/share/zoneinfo/localtime local timezone file
|
||||
/usr/share/zoneinfo/posixrules used with POSIX-style TZ's
|
||||
/usr/share/zoneinfo/posixrules used with POSIX-style TZ
|
||||
/usr/share/zoneinfo/GMT for UTC leap seconds
|
||||
|
||||
If /usr/share/zoneinfo/GMT is absent, UTC leap seconds are loaded from
|
||||
|
202
private.h
202
private.h
@ -17,6 +17,10 @@
|
||||
** Thank you!
|
||||
*/
|
||||
|
||||
#ifndef __STDC_VERSION__
|
||||
# define __STDC_VERSION__ 0
|
||||
#endif
|
||||
|
||||
/* Define true, false and bool if they don't work out of the box. */
|
||||
#if __STDC_VERSION__ < 199901
|
||||
# define true 1
|
||||
@ -56,24 +60,13 @@
|
||||
# endif
|
||||
#endif
|
||||
/* _Generic is buggy in pre-4.9 GCC. */
|
||||
#if !defined HAVE_GENERIC && defined __GNUC__
|
||||
#if !defined HAVE_GENERIC && defined __GNUC__ && !defined __STRICT_ANSI__
|
||||
# define HAVE_GENERIC (4 < __GNUC__ + (9 <= __GNUC_MINOR__))
|
||||
#endif
|
||||
#ifndef HAVE_GENERIC
|
||||
# define HAVE_GENERIC (201112 <= __STDC_VERSION__)
|
||||
#endif
|
||||
|
||||
#if !defined HAVE_GETRANDOM && defined __has_include
|
||||
# if __has_include(<sys/random.h>)
|
||||
# define HAVE_GETRANDOM true
|
||||
# else
|
||||
# define HAVE_GETRANDOM false
|
||||
# endif
|
||||
#endif
|
||||
#ifndef HAVE_GETRANDOM
|
||||
# define HAVE_GETRANDOM (2 < __GLIBC__ + (25 <= __GLIBC_MINOR__))
|
||||
#endif
|
||||
|
||||
#if !defined HAVE_GETTEXT && defined __has_include
|
||||
# if __has_include(<libintl.h>)
|
||||
# define HAVE_GETTEXT true
|
||||
@ -289,36 +282,36 @@
|
||||
#endif
|
||||
|
||||
/* Pre-C99 GCC compilers define __LONG_LONG_MAX__ instead of LLONG_MAX. */
|
||||
#ifdef __LONG_LONG_MAX__
|
||||
#if defined __LONG_LONG_MAX__ && !defined __STRICT_ANSI__
|
||||
# ifndef LLONG_MAX
|
||||
# define LLONG_MAX __LONG_LONG_MAX__
|
||||
# endif
|
||||
# ifndef LLONG_MIN
|
||||
# define LLONG_MIN (-1 - LLONG_MAX)
|
||||
# endif
|
||||
# ifndef ULLONG_MAX
|
||||
# define ULLONG_MAX (LLONG_MAX * 2ull + 1)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef INT_FAST64_MAX
|
||||
# ifdef LLONG_MAX
|
||||
typedef long long int_fast64_t;
|
||||
# define INT_FAST64_MIN LLONG_MIN
|
||||
# define INT_FAST64_MAX LLONG_MAX
|
||||
# else
|
||||
# if LONG_MAX >> 31 < 0xffffffff
|
||||
Please use a compiler that supports a 64-bit integer type (or wider);
|
||||
you may need to compile with "-DHAVE_STDINT_H".
|
||||
# endif
|
||||
typedef long int_fast64_t;
|
||||
# if 1 <= LONG_MAX >> 31 >> 31
|
||||
typedef long int_fast64_t;
|
||||
# define INT_FAST64_MIN LONG_MIN
|
||||
# define INT_FAST64_MAX LONG_MAX
|
||||
# else
|
||||
/* If this fails, compile with -DHAVE_STDINT_H or with a better compiler. */
|
||||
typedef long long int_fast64_t;
|
||||
# define INT_FAST64_MIN LLONG_MIN
|
||||
# define INT_FAST64_MAX LLONG_MAX
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef PRIdFAST64
|
||||
# if INT_FAST64_MAX == LLONG_MAX
|
||||
# define PRIdFAST64 "lld"
|
||||
# else
|
||||
# if INT_FAST64_MAX == LONG_MAX
|
||||
# define PRIdFAST64 "ld"
|
||||
# else
|
||||
# define PRIdFAST64 "lld"
|
||||
# endif
|
||||
#endif
|
||||
|
||||
@ -364,24 +357,27 @@ typedef long intmax_t;
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef PTRDIFF_MAX
|
||||
# define PTRDIFF_MAX MAXVAL(ptrdiff_t, TYPE_BIT(ptrdiff_t))
|
||||
#endif
|
||||
|
||||
#ifndef UINT_FAST32_MAX
|
||||
typedef unsigned long uint_fast32_t;
|
||||
#endif
|
||||
|
||||
#ifndef UINT_FAST64_MAX
|
||||
# if defined ULLONG_MAX || defined __LONG_LONG_MAX__
|
||||
typedef unsigned long long uint_fast64_t;
|
||||
# if 3 <= ULONG_MAX >> 31 >> 31
|
||||
typedef unsigned long uint_fast64_t;
|
||||
# define UINT_FAST64_MAX ULONG_MAX
|
||||
# else
|
||||
# if ULONG_MAX >> 31 >> 1 < 0xffffffff
|
||||
Please use a compiler that supports a 64-bit integer type (or wider);
|
||||
you may need to compile with "-DHAVE_STDINT_H".
|
||||
# endif
|
||||
typedef unsigned long uint_fast64_t;
|
||||
/* If this fails, compile with -DHAVE_STDINT_H or with a better compiler. */
|
||||
typedef unsigned long long uint_fast64_t;
|
||||
# define UINT_FAST64_MAX ULLONG_MAX
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef UINTMAX_MAX
|
||||
# if defined ULLONG_MAX || defined __LONG_LONG_MAX__
|
||||
# ifdef ULLONG_MAX
|
||||
typedef unsigned long long uintmax_t;
|
||||
# else
|
||||
typedef unsigned long uintmax_t;
|
||||
@ -389,7 +385,7 @@ typedef unsigned long uintmax_t;
|
||||
#endif
|
||||
|
||||
#ifndef PRIuMAX
|
||||
# if defined ULLONG_MAX || defined __LONG_LONG_MAX__
|
||||
# ifdef ULLONG_MAX
|
||||
# define PRIuMAX "llu"
|
||||
# else
|
||||
# define PRIuMAX "lu"
|
||||
@ -400,23 +396,114 @@ typedef unsigned long uintmax_t;
|
||||
# define SIZE_MAX ((size_t) -1)
|
||||
#endif
|
||||
|
||||
/* Support ckd_add, ckd_sub, ckd_mul on C23 or recent-enough GCC-like
|
||||
hosts, unless compiled with -DHAVE_STDCKDINT_H=0 or with pre-C23 EDG. */
|
||||
#if !defined HAVE_STDCKDINT_H && defined __has_include
|
||||
# if __has_include(<stdckdint.h>)
|
||||
# define HAVE_STDCKDINT_H true
|
||||
# endif
|
||||
#endif
|
||||
#ifdef HAVE_STDCKDINT_H
|
||||
# if HAVE_STDCKDINT_H
|
||||
# include <stdckdint.h>
|
||||
# endif
|
||||
#elif defined __EDG__
|
||||
/* Do nothing, to work around EDG bug <https://bugs.gnu.org/53256>. */
|
||||
#elif defined __has_builtin
|
||||
# if __has_builtin(__builtin_add_overflow)
|
||||
# define ckd_add(r, a, b) __builtin_add_overflow(a, b, r)
|
||||
# endif
|
||||
# if __has_builtin(__builtin_sub_overflow)
|
||||
# define ckd_sub(r, a, b) __builtin_sub_overflow(a, b, r)
|
||||
# endif
|
||||
# if __has_builtin(__builtin_mul_overflow)
|
||||
# define ckd_mul(r, a, b) __builtin_mul_overflow(a, b, r)
|
||||
# endif
|
||||
#elif 7 <= __GNUC__
|
||||
# define ckd_add(r, a, b) __builtin_add_overflow(a, b, r)
|
||||
# define ckd_sub(r, a, b) __builtin_sub_overflow(a, b, r)
|
||||
# define ckd_mul(r, a, b) __builtin_mul_overflow(a, b, r)
|
||||
#endif
|
||||
|
||||
#if 3 <= __GNUC__
|
||||
# define ATTRIBUTE_CONST __attribute__((const))
|
||||
# define ATTRIBUTE_MALLOC __attribute__((__malloc__))
|
||||
# define ATTRIBUTE_PURE __attribute__((__pure__))
|
||||
# define ATTRIBUTE_FORMAT(spec) __attribute__((__format__ spec))
|
||||
# define ATTRIBUTE_MALLOC __attribute__((malloc))
|
||||
# define ATTRIBUTE_FORMAT(spec) __attribute__((format spec))
|
||||
#else
|
||||
# define ATTRIBUTE_CONST /* empty */
|
||||
# define ATTRIBUTE_MALLOC /* empty */
|
||||
# define ATTRIBUTE_PURE /* empty */
|
||||
# define ATTRIBUTE_FORMAT(spec) /* empty */
|
||||
#endif
|
||||
|
||||
#if !defined _Noreturn && __STDC_VERSION__ < 201112
|
||||
# if 2 < __GNUC__ + (8 <= __GNUC_MINOR__)
|
||||
# define _Noreturn __attribute__((__noreturn__))
|
||||
#if (defined __has_c_attribute \
|
||||
&& (202311 <= __STDC_VERSION__ || !defined __STRICT_ANSI__))
|
||||
# define HAVE_HAS_C_ATTRIBUTE true
|
||||
#else
|
||||
# define HAVE_HAS_C_ATTRIBUTE false
|
||||
#endif
|
||||
|
||||
#if HAVE_HAS_C_ATTRIBUTE
|
||||
# if __has_c_attribute(fallthrough)
|
||||
# define ATTRIBUTE_FALLTHROUGH [[fallthrough]]
|
||||
# endif
|
||||
#endif
|
||||
#ifndef ATTRIBUTE_FALLTHROUGH
|
||||
# if 7 <= __GNUC__
|
||||
# define ATTRIBUTE_FALLTHROUGH __attribute__((fallthrough))
|
||||
# else
|
||||
# define _Noreturn
|
||||
# define ATTRIBUTE_FALLTHROUGH ((void) 0)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if HAVE_HAS_C_ATTRIBUTE
|
||||
# if __has_c_attribute(maybe_unused)
|
||||
# define ATTRIBUTE_MAYBE_UNUSED [[maybe_unused]]
|
||||
# endif
|
||||
#endif
|
||||
#ifndef ATTRIBUTE_MAYBE_UNUSED
|
||||
# if 2 < __GNUC__ + (7 <= __GNUC_MINOR__)
|
||||
# define ATTRIBUTE_MAYBE_UNUSED __attribute__((unused))
|
||||
# else
|
||||
# define ATTRIBUTE_MAYBE_UNUSED /* empty */
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if HAVE_HAS_C_ATTRIBUTE
|
||||
# if __has_c_attribute(noreturn)
|
||||
# define ATTRIBUTE_NORETURN [[noreturn]]
|
||||
# endif
|
||||
#endif
|
||||
#ifndef ATTRIBUTE_NORETURN
|
||||
# if 201112 <= __STDC_VERSION__
|
||||
# define ATTRIBUTE_NORETURN _Noreturn
|
||||
# elif 2 < __GNUC__ + (8 <= __GNUC_MINOR__)
|
||||
# define ATTRIBUTE_NORETURN __attribute__((noreturn))
|
||||
# else
|
||||
# define ATTRIBUTE_NORETURN /* empty */
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if HAVE_HAS_C_ATTRIBUTE
|
||||
# if __has_c_attribute(reproducible)
|
||||
# define ATTRIBUTE_REPRODUCIBLE [[reproducible]]
|
||||
# endif
|
||||
#endif
|
||||
#ifndef ATTRIBUTE_REPRODUCIBLE
|
||||
# if 3 <= __GNUC__
|
||||
# define ATTRIBUTE_REPRODUCIBLE __attribute__((pure))
|
||||
# else
|
||||
# define ATTRIBUTE_REPRODUCIBLE /* empty */
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if HAVE_HAS_C_ATTRIBUTE
|
||||
# if __has_c_attribute(unsequenced)
|
||||
# define ATTRIBUTE_UNSEQUENCED [[unsequenced]]
|
||||
# endif
|
||||
#endif
|
||||
#ifndef ATTRIBUTE_UNSEQUENCED
|
||||
# if 3 <= __GNUC__
|
||||
# define ATTRIBUTE_UNSEQUENCED __attribute__((const))
|
||||
# else
|
||||
# define ATTRIBUTE_UNSEQUENCED /* empty */
|
||||
# endif
|
||||
#endif
|
||||
|
||||
@ -541,7 +628,7 @@ char *asctime(struct tm const *);
|
||||
char *asctime_r(struct tm const *restrict, char *restrict);
|
||||
char *ctime(time_t const *);
|
||||
char *ctime_r(time_t const *, char *);
|
||||
double difftime(time_t, time_t) ATTRIBUTE_CONST;
|
||||
double difftime(time_t, time_t) ATTRIBUTE_UNSEQUENCED;
|
||||
size_t strftime(char *restrict, size_t, char const *restrict,
|
||||
struct tm const *restrict);
|
||||
# if HAVE_STRFTIME_L
|
||||
@ -554,9 +641,24 @@ struct tm *localtime(time_t const *);
|
||||
struct tm *localtime_r(time_t const *restrict, struct tm *restrict);
|
||||
time_t mktime(struct tm *);
|
||||
time_t time(time_t *);
|
||||
time_t timegm(struct tm *);
|
||||
void tzset(void);
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_DECL_TIMEGM
|
||||
# if (202311 <= __STDC_VERSION__ \
|
||||
|| defined __GLIBC__ || defined __tm_zone /* musl */ \
|
||||
|| defined __FreeBSD__ || defined __NetBSD__ || defined __OpenBSD__ \
|
||||
|| (defined __APPLE__ && defined __MACH__))
|
||||
# define HAVE_DECL_TIMEGM true
|
||||
# else
|
||||
# define HAVE_DECL_TIMEGM false
|
||||
# endif
|
||||
#endif
|
||||
#if !HAVE_DECL_TIMEGM && !defined timegm
|
||||
time_t timegm(struct tm *);
|
||||
#endif
|
||||
|
||||
#if !HAVE_DECL_ASCTIME_R && !defined asctime_r
|
||||
extern char *asctime_r(struct tm const *restrict, char *restrict);
|
||||
#endif
|
||||
@ -593,9 +695,6 @@ extern long altzone;
|
||||
# if TZ_TIME_T || !defined offtime
|
||||
struct tm *offtime(time_t const *, long);
|
||||
# endif
|
||||
# if TZ_TIME_T || !defined timegm
|
||||
time_t timegm(struct tm *);
|
||||
# endif
|
||||
# if TZ_TIME_T || !defined timelocal
|
||||
time_t timelocal(struct tm *);
|
||||
# endif
|
||||
@ -613,6 +712,7 @@ time_t posix2time(time_t);
|
||||
/* Infer TM_ZONE on systems where this information is known, but suppress
|
||||
guessing if NO_TM_ZONE is defined. Similarly for TM_GMTOFF. */
|
||||
#if (defined __GLIBC__ \
|
||||
|| defined __tm_zone /* musl */ \
|
||||
|| defined __FreeBSD__ || defined __NetBSD__ || defined __OpenBSD__ \
|
||||
|| (defined __APPLE__ && defined __MACH__))
|
||||
# if !defined TM_GMTOFF && !defined NO_TM_GMTOFF
|
||||
@ -640,10 +740,10 @@ timezone_t tzalloc(char const *);
|
||||
void tzfree(timezone_t);
|
||||
# ifdef STD_INSPIRED
|
||||
# if TZ_TIME_T || !defined posix2time_z
|
||||
time_t posix2time_z(timezone_t, time_t) ATTRIBUTE_PURE;
|
||||
time_t posix2time_z(timezone_t, time_t) ATTRIBUTE_REPRODUCIBLE;
|
||||
# endif
|
||||
# if TZ_TIME_T || !defined time2posix_z
|
||||
time_t time2posix_z(timezone_t, time_t) ATTRIBUTE_PURE;
|
||||
time_t time2posix_z(timezone_t, time_t) ATTRIBUTE_REPRODUCIBLE;
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
21
strftime.c
21
strftime.c
@ -117,7 +117,7 @@ static char * _yconv(int, int, bool, bool, char *, char const *);
|
||||
#if HAVE_STRFTIME_L
|
||||
size_t
|
||||
strftime_l(char *s, size_t maxsize, char const *format, struct tm const *t,
|
||||
locale_t locale)
|
||||
ATTRIBUTE_MAYBE_UNUSED locale_t locale)
|
||||
{
|
||||
/* Just call strftime, as only the C locale is supported. */
|
||||
return strftime(s, maxsize, format, t);
|
||||
@ -319,12 +319,21 @@ _fmt(const char *format, const struct tm *t, char *pt,
|
||||
time_t) + 1];
|
||||
time_t mkt;
|
||||
|
||||
tm = *t;
|
||||
tm.tm_sec = t->tm_sec;
|
||||
tm.tm_min = t->tm_min;
|
||||
tm.tm_hour = t->tm_hour;
|
||||
tm.tm_mday = t->tm_mday;
|
||||
tm.tm_mon = t->tm_mon;
|
||||
tm.tm_year = t->tm_year;
|
||||
tm.tm_isdst = t->tm_isdst;
|
||||
#if defined TM_GMTOFF && ! UNINIT_TRAP
|
||||
tm.TM_GMTOFF = t->TM_GMTOFF;
|
||||
#endif
|
||||
mkt = mktime(&tm);
|
||||
/* There is no portable, definitive
|
||||
test for whether whether mktime
|
||||
succeeded, so treat (time_t) -1 as
|
||||
the success that it might be. */
|
||||
/* If mktime fails, %s expands to the
|
||||
value of (time_t) -1 as a failure
|
||||
marker; this is better in practice
|
||||
than strftime failing. */
|
||||
if (TYPE_SIGNED(time_t)) {
|
||||
intmax_t n = mkt;
|
||||
sprintf(buf, "%"PRIdMAX, n);
|
||||
|
@ -60,7 +60,6 @@ with current and future timestamps in the traditional North
|
||||
American mountain time zone can choose from the timezones
|
||||
<code>America/Denver</code> which observes US-style daylight saving
|
||||
time (<abbr>DST</abbr>),
|
||||
<code>America/Mazatlan</code> which observes Mexican-style <abbr>DST</abbr>,
|
||||
and <code>America/Phoenix</code> which does not observe <abbr>DST</abbr>.
|
||||
Applications that also deal with past timestamps in the mountain time
|
||||
zone can choose from over a dozen timezones, such as
|
||||
|
16
time2posix.3
16
time2posix.3
@ -1,9 +1,11 @@
|
||||
.TH TIME2POSIX 3
|
||||
.\" This file is in the public domain, so clarified as of
|
||||
.\" 1996-06-05 by Arthur David Olson.
|
||||
.TH time2posix 3
|
||||
.SH NAME
|
||||
time2posix, posix2time \- convert seconds since the Epoch
|
||||
.SH SYNOPSIS
|
||||
.nf
|
||||
.ie \n(.g .ds - \f(CW-\fP
|
||||
.ie \n(.g .ds - \f(CR-\fP
|
||||
.el .ds - \-
|
||||
.B #include <time.h>
|
||||
.PP
|
||||
@ -58,7 +60,7 @@ expression for directly computing a time_t value from a given date/time,
|
||||
and the same relationship is assumed by some
|
||||
(usually older)
|
||||
applications.
|
||||
Any programs creating/dissecting time_t's
|
||||
Any programs creating/dissecting time_t values
|
||||
using such a relationship will typically not handle intervals
|
||||
over leap seconds correctly.
|
||||
.PP
|
||||
@ -93,7 +95,7 @@ Both of these are good indicators of the inferiority of the
|
||||
POSIX representation.
|
||||
.PP
|
||||
The following table summarizes the relationship between a time
|
||||
T and it's conversion to,
|
||||
T and its conversion to,
|
||||
and back from,
|
||||
the POSIX representation over the leap second inserted at the end of June,
|
||||
1993.
|
||||
@ -117,8 +119,8 @@ DATE TIME T X=time2posix(T) posix2time(X)
|
||||
.fi
|
||||
.PP
|
||||
If leap-second support is not enabled,
|
||||
local time_t's and
|
||||
POSIX time_t's are equivalent,
|
||||
local time_t and
|
||||
POSIX time_t values are equivalent,
|
||||
and both
|
||||
.B time2posix
|
||||
and
|
||||
@ -129,5 +131,3 @@ difftime(3),
|
||||
localtime(3),
|
||||
mktime(3),
|
||||
time(2)
|
||||
.\" This file is in the public domain, so clarified as of
|
||||
.\" 1996-06-05 by Arthur David Olson.
|
||||
|
@ -1,4 +1,4 @@
|
||||
TIME2POSIX(3) Library Functions Manual TIME2POSIX(3)
|
||||
time2posix(3) Library Functions Manual time2posix(3)
|
||||
|
||||
NAME
|
||||
time2posix, posix2time - convert seconds since the Epoch
|
||||
@ -30,8 +30,8 @@ DESCRIPTION
|
||||
difftime(3). However, POSIX gives an arithmetic expression for
|
||||
directly computing a time_t value from a given date/time, and the same
|
||||
relationship is assumed by some (usually older) applications. Any
|
||||
programs creating/dissecting time_t's using such a relationship will
|
||||
typically not handle intervals over leap seconds correctly.
|
||||
programs creating/dissecting time_t values using such a relationship
|
||||
will typically not handle intervals over leap seconds correctly.
|
||||
|
||||
The time2posix and posix2time functions are provided to address this
|
||||
time_t mismatch by converting between local time_t values and their
|
||||
@ -49,7 +49,7 @@ DESCRIPTION
|
||||
indicators of the inferiority of the POSIX representation.
|
||||
|
||||
The following table summarizes the relationship between a time T and
|
||||
it's conversion to, and back from, the POSIX representation over the
|
||||
its conversion to, and back from, the POSIX representation over the
|
||||
leap second inserted at the end of June, 1993.
|
||||
DATE TIME T X=time2posix(T) posix2time(X)
|
||||
93/06/30 23:59:59 A+0 B+0 A+0
|
||||
@ -66,11 +66,11 @@ DESCRIPTION
|
||||
|
||||
[Note: posix2time(B+1) => A+0 or A+1]
|
||||
|
||||
If leap-second support is not enabled, local time_t's and POSIX
|
||||
time_t's are equivalent, and both time2posix and posix2time degenerate
|
||||
to the identity function.
|
||||
If leap-second support is not enabled, local time_t and POSIX time_t
|
||||
values are equivalent, and both time2posix and posix2time degenerate to
|
||||
the identity function.
|
||||
|
||||
SEE ALSO
|
||||
difftime(3), localtime(3), mktime(3), time(2)
|
||||
|
||||
TIME2POSIX(3)
|
||||
time2posix(3)
|
||||
|
6
tzfile.5
6
tzfile.5
@ -1,3 +1,5 @@
|
||||
.\" This file is in the public domain, so clarified as of
|
||||
.\" 1996-06-05 by Arthur David Olson.
|
||||
.TH TZFILE 5
|
||||
.SH NAME
|
||||
tzfile \- timezone information
|
||||
@ -9,7 +11,7 @@ tzfile \- timezone information
|
||||
.de q
|
||||
\\$3\*(lq\\$1\*(rq\\$2
|
||||
..
|
||||
.ie \n(.g .ds - \f(CW-\fP
|
||||
.ie \n(.g .ds - \f(CR-\fP
|
||||
.el .ds - \-
|
||||
The timezone information files used by
|
||||
.BR tzset (3)
|
||||
@ -492,5 +494,3 @@ Internet RFC 8536
|
||||
.UR https://\:doi.org/\:10.17487/\:RFC8536
|
||||
doi:10.17487/RFC8536
|
||||
.UE .
|
||||
.\" This file is in the public domain, so clarified as of
|
||||
.\" 1996-06-05 by Arthur David Olson.
|
||||
|
@ -1,8 +1,10 @@
|
||||
.\" This file is in the public domain, so clarified as of
|
||||
.\" 2009-05-17 by Arthur David Olson.
|
||||
.TH TZSELECT 8
|
||||
.SH NAME
|
||||
tzselect \- select a timezone
|
||||
.SH SYNOPSIS
|
||||
.ie \n(.g .ds - \f(CW-\fP
|
||||
.ie \n(.g .ds - \f(CR-\fP
|
||||
.el .ds - \-
|
||||
.ds d " degrees
|
||||
.ds m " minutes
|
||||
@ -121,5 +123,3 @@ newctime(3), tzfile(5), zdump(8), zic(8)
|
||||
Applications should not assume that
|
||||
.BR tzselect 's
|
||||
output matches the user's political preferences.
|
||||
.\" This file is in the public domain, so clarified as of
|
||||
.\" 2009-05-17 by Arthur David Olson.
|
||||
|
12
zdump.8
12
zdump.8
@ -1,4 +1,6 @@
|
||||
.TH ZDUMP 8
|
||||
.\" This file is in the public domain, so clarified as of
|
||||
.\" 2009-05-17 by Arthur David Olson.
|
||||
.TH zdump 8
|
||||
.SH NAME
|
||||
zdump \- timezone dumper
|
||||
.SH SYNOPSIS
|
||||
@ -16,7 +18,7 @@ zdump \- timezone dumper
|
||||
.de q
|
||||
\\$3\*(lq\\$1\*(rq\\$2
|
||||
..
|
||||
.ie \n(.g .ds - \f(CW-\fP
|
||||
.ie \n(.g .ds - \f(CR-\fP
|
||||
.el .ds - \-
|
||||
The
|
||||
.B zdump
|
||||
@ -149,7 +151,7 @@ Here is an example of the output, with the leading empty line omitted.
|
||||
tabbed columns line up.)
|
||||
.nf
|
||||
.sp
|
||||
.if \n(.g .ft CW
|
||||
.if \n(.g .ft CR
|
||||
.if t .in +.5i
|
||||
.if n .in +2
|
||||
.nr w \w'1896-01-13 'u+\n(.i
|
||||
@ -182,7 +184,7 @@ UT, a standard time abbreviated HST.
|
||||
Here are excerpts from another example:
|
||||
.nf
|
||||
.sp
|
||||
.if \n(.g .ft CW
|
||||
.if \n(.g .ft CR
|
||||
.if t .in +.5i
|
||||
.if n .in +2
|
||||
TZ="Europe/Astrakhan"
|
||||
@ -227,5 +229,3 @@ introduction of UTC is problematic.
|
||||
.SH SEE ALSO
|
||||
.BR tzfile (5),
|
||||
.BR zic (8)
|
||||
.\" This file is in the public domain, so clarified as of
|
||||
.\" 2009-05-17 by Arthur David Olson.
|
||||
|
@ -1,4 +1,4 @@
|
||||
ZDUMP(8) System Manager's Manual ZDUMP(8)
|
||||
zdump(8) System Manager's Manual zdump(8)
|
||||
|
||||
NAME
|
||||
zdump - timezone dumper
|
||||
@ -141,4 +141,4 @@ LIMITATIONS
|
||||
SEE ALSO
|
||||
tzfile(5), zic(8)
|
||||
|
||||
ZDUMP(8)
|
||||
zdump(8)
|
||||
|
101
zdump.c
101
zdump.c
@ -84,20 +84,20 @@ static time_t const absolute_max_time =
|
||||
? (((time_t) 1 << atime_shift) - 1 + ((time_t) 1 << atime_shift))
|
||||
: -1);
|
||||
static int longest;
|
||||
static char * progname;
|
||||
static char const *progname;
|
||||
static bool warned;
|
||||
static bool errout;
|
||||
|
||||
static char const *abbr(struct tm const *);
|
||||
static intmax_t delta(struct tm *, struct tm *) ATTRIBUTE_PURE;
|
||||
static intmax_t delta(struct tm *, struct tm *) ATTRIBUTE_REPRODUCIBLE;
|
||||
static void dumptime(struct tm const *);
|
||||
static time_t hunt(timezone_t, char *, time_t, time_t, bool);
|
||||
static time_t hunt(timezone_t, time_t, time_t, bool);
|
||||
static void show(timezone_t, char *, time_t, bool);
|
||||
static void showextrema(timezone_t, char *, time_t, struct tm *, time_t);
|
||||
static void showtrans(char const *, struct tm const *, time_t, char const *,
|
||||
char const *);
|
||||
static const char *tformat(void);
|
||||
static time_t yeartot(intmax_t) ATTRIBUTE_PURE;
|
||||
static time_t yeartot(intmax_t) ATTRIBUTE_REPRODUCIBLE;
|
||||
|
||||
/* Is C an ASCII digit? */
|
||||
static bool
|
||||
@ -125,16 +125,28 @@ is_alpha(char a)
|
||||
}
|
||||
}
|
||||
|
||||
/* Return A + B, exiting if the result would overflow. */
|
||||
static size_t
|
||||
static ATTRIBUTE_NORETURN void
|
||||
size_overflow(void)
|
||||
{
|
||||
fprintf(stderr, _("%s: size overflow\n"), progname);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* Return A + B, exiting if the result would overflow either ptrdiff_t
|
||||
or size_t. */
|
||||
static ATTRIBUTE_REPRODUCIBLE ptrdiff_t
|
||||
sumsize(size_t a, size_t b)
|
||||
{
|
||||
size_t sum = a + b;
|
||||
if (sum < a) {
|
||||
fprintf(stderr, _("%s: size overflow\n"), progname);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
return sum;
|
||||
#ifdef ckd_add
|
||||
ptrdiff_t sum;
|
||||
if (!ckd_add(&sum, a, b) && sum <= SIZE_MAX)
|
||||
return sum;
|
||||
#else
|
||||
ptrdiff_t sum_max = min(PTRDIFF_MAX, SIZE_MAX);
|
||||
if (a <= sum_max && b <= sum_max - a)
|
||||
return a + b;
|
||||
#endif
|
||||
size_overflow();
|
||||
}
|
||||
|
||||
/* Return a pointer to a newly allocated buffer of size SIZE, exiting
|
||||
@ -234,22 +246,30 @@ tzalloc(char const *val)
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
tzset();
|
||||
return NULL;
|
||||
return &optarg; /* Any valid non-null char ** will do. */
|
||||
# else
|
||||
enum { TZeqlen = 3 };
|
||||
static char const TZeq[TZeqlen] = "TZ=";
|
||||
static char **fakeenv;
|
||||
static size_t fakeenv0size;
|
||||
static ptrdiff_t fakeenv0size;
|
||||
void *freeable = NULL;
|
||||
char **env = fakeenv, **initial_environ;
|
||||
size_t valsize = strlen(val) + 1;
|
||||
if (fakeenv0size < valsize) {
|
||||
char **e = environ, **to;
|
||||
ptrdiff_t initial_nenvptrs; /* Counting the trailing NULL pointer. */
|
||||
ptrdiff_t initial_nenvptrs = 1; /* Counting the trailing NULL pointer. */
|
||||
|
||||
while (*e++)
|
||||
continue;
|
||||
initial_nenvptrs = e - environ;
|
||||
while (*e++) {
|
||||
# ifdef ckd_add
|
||||
if (ckd_add(&initial_nenvptrs, initial_envptrs, 1)
|
||||
|| SIZE_MAX < initial_envptrs)
|
||||
size_overflow();
|
||||
# else
|
||||
if (initial_nenvptrs == min(PTRDIFF_MAX, SIZE_MAX) / sizeof *environ)
|
||||
size_overflow();
|
||||
initial_nenvptrs++;
|
||||
# endif
|
||||
}
|
||||
fakeenv0size = sumsize(valsize, valsize);
|
||||
fakeenv0size = max(fakeenv0size, 64);
|
||||
freeable = env;
|
||||
@ -385,7 +405,7 @@ abbrok(const char *const abbrp, const char *const zone)
|
||||
return the abbreviation. Get the abbreviation from TMP.
|
||||
Exit on memory allocation failure. */
|
||||
static char const *
|
||||
saveabbr(char **buf, size_t *bufalloc, struct tm const *tmp)
|
||||
saveabbr(char **buf, ptrdiff_t *bufalloc, struct tm const *tmp)
|
||||
{
|
||||
char const *ab = abbr(tmp);
|
||||
if (HAVE_LOCALTIME_RZ)
|
||||
@ -442,7 +462,7 @@ main(int argc, char *argv[])
|
||||
{
|
||||
/* These are static so that they're initially zero. */
|
||||
static char * abbrev;
|
||||
static size_t abbrevsize;
|
||||
static ptrdiff_t abbrevsize;
|
||||
|
||||
register int i;
|
||||
register bool vflag;
|
||||
@ -463,7 +483,7 @@ main(int argc, char *argv[])
|
||||
# endif /* defined TEXTDOMAINDIR */
|
||||
textdomain(TZ_DOMAIN);
|
||||
#endif /* HAVE_GETTEXT */
|
||||
progname = argv[0];
|
||||
progname = argv[0] ? argv[0] : "zdump";
|
||||
for (i = 1; i < argc; ++i)
|
||||
if (strcmp(argv[i], "--version") == 0) {
|
||||
printf("zdump %s%s\n", PKGVERSION, TZVERSION);
|
||||
@ -483,7 +503,7 @@ main(int argc, char *argv[])
|
||||
case -1:
|
||||
if (! (optind == argc - 1 && strcmp(argv[optind], "=") == 0))
|
||||
goto arg_processing_done;
|
||||
/* Fall through. */
|
||||
ATTRIBUTE_FALLTHROUGH;
|
||||
default:
|
||||
usage(stderr, EXIT_FAILURE);
|
||||
}
|
||||
@ -607,7 +627,7 @@ main(int argc, char *argv[])
|
||||
|| (ab && (delta(&newtm, &tm) != newt - t
|
||||
|| newtm.tm_isdst != tm.tm_isdst
|
||||
|| strcmp(abbr(&newtm), ab) != 0))) {
|
||||
newt = hunt(tz, argv[i], t, newt, false);
|
||||
newt = hunt(tz, t, newt, false);
|
||||
newtmp = localtime_rz(tz, &newt, &newtm);
|
||||
newtm_ok = newtmp != NULL;
|
||||
if (iflag)
|
||||
@ -687,7 +707,7 @@ yeartot(intmax_t y)
|
||||
return t;
|
||||
}
|
||||
|
||||
/* Search for a discontinuity in timezone TZ with name NAME, in the
|
||||
/* Search for a discontinuity in timezone TZ, in the
|
||||
timestamps ranging from LOT through HIT. LOT and HIT disagree
|
||||
about some aspect of timezone. If ONLY_OK, search only for
|
||||
definedness changes, i.e., localtime succeeds on one side of the
|
||||
@ -695,10 +715,10 @@ yeartot(intmax_t y)
|
||||
before the transition from LOT's settings. */
|
||||
|
||||
static time_t
|
||||
hunt(timezone_t tz, char *name, time_t lot, time_t hit, bool only_ok)
|
||||
hunt(timezone_t tz, time_t lot, time_t hit, bool only_ok)
|
||||
{
|
||||
static char * loab;
|
||||
static size_t loabsize;
|
||||
static ptrdiff_t loabsize;
|
||||
struct tm lotm;
|
||||
struct tm tm;
|
||||
|
||||
@ -787,7 +807,8 @@ adjusted_yday(struct tm const *a, struct tm const *b)
|
||||
my_gmtime_r and use its result instead of B. Otherwise, B is the
|
||||
possibly nonnull result of an earlier call to my_gmtime_r. */
|
||||
static long
|
||||
gmtoff(struct tm const *a, time_t *t, struct tm const *b)
|
||||
gmtoff(struct tm const *a, ATTRIBUTE_MAYBE_UNUSED time_t *t,
|
||||
ATTRIBUTE_MAYBE_UNUSED struct tm const *b)
|
||||
{
|
||||
#ifdef TM_GMTOFF
|
||||
return a->TM_GMTOFF;
|
||||
@ -858,7 +879,7 @@ static void
|
||||
showextrema(timezone_t tz, char *zone, time_t lo, struct tm *lotmp, time_t hi)
|
||||
{
|
||||
struct tm localtm[2], gmtm[2];
|
||||
time_t t, boundary = hunt(tz, zone, lo, hi, true);
|
||||
time_t t, boundary = hunt(tz, lo, hi, true);
|
||||
bool old = false;
|
||||
hi = (SECSPERDAY < hi - boundary
|
||||
? boundary + SECSPERDAY
|
||||
@ -937,7 +958,7 @@ my_snprintf(char *s, size_t size, char const *format, ...)
|
||||
fit, return the length that the string would have been if it had
|
||||
fit; do not overrun the output buffer. */
|
||||
static int
|
||||
format_local_time(char *buf, size_t size, struct tm const *tm)
|
||||
format_local_time(char *buf, ptrdiff_t size, struct tm const *tm)
|
||||
{
|
||||
int ss = tm->tm_sec, mm = tm->tm_min, hh = tm->tm_hour;
|
||||
return (ss
|
||||
@ -960,7 +981,7 @@ format_local_time(char *buf, size_t size, struct tm const *tm)
|
||||
the length that the string would have been if it had fit; do not
|
||||
overrun the output buffer. */
|
||||
static int
|
||||
format_utc_offset(char *buf, size_t size, struct tm const *tm, time_t t)
|
||||
format_utc_offset(char *buf, ptrdiff_t size, struct tm const *tm, time_t t)
|
||||
{
|
||||
long off = gmtoff(tm, &t, NULL);
|
||||
char sign = ((off < 0
|
||||
@ -989,11 +1010,11 @@ format_utc_offset(char *buf, size_t size, struct tm const *tm, time_t t)
|
||||
If the representation's length is less than SIZE, return the
|
||||
length; the representation is not null terminated. Otherwise
|
||||
return SIZE, to indicate that BUF is too small. */
|
||||
static size_t
|
||||
format_quoted_string(char *buf, size_t size, char const *p)
|
||||
static ptrdiff_t
|
||||
format_quoted_string(char *buf, ptrdiff_t size, char const *p)
|
||||
{
|
||||
char *b = buf;
|
||||
size_t s = size;
|
||||
ptrdiff_t s = size;
|
||||
if (!s)
|
||||
return size;
|
||||
*b++ = '"', s--;
|
||||
@ -1031,11 +1052,11 @@ format_quoted_string(char *buf, size_t size, char const *p)
|
||||
and omit any trailing tabs. */
|
||||
|
||||
static bool
|
||||
istrftime(char *buf, size_t size, char const *time_fmt,
|
||||
istrftime(char *buf, ptrdiff_t size, char const *time_fmt,
|
||||
struct tm const *tm, time_t t, char const *ab, char const *zone_name)
|
||||
{
|
||||
char *b = buf;
|
||||
size_t s = size;
|
||||
ptrdiff_t s = size;
|
||||
char const *f = time_fmt, *p;
|
||||
|
||||
for (p = f; ; p++)
|
||||
@ -1044,9 +1065,9 @@ istrftime(char *buf, size_t size, char const *time_fmt,
|
||||
else if (!*p
|
||||
|| (*p == '%'
|
||||
&& (p[1] == 'f' || p[1] == 'L' || p[1] == 'Q'))) {
|
||||
size_t formatted_len;
|
||||
size_t f_prefix_len = p - f;
|
||||
size_t f_prefix_copy_size = p - f + 2;
|
||||
ptrdiff_t formatted_len;
|
||||
ptrdiff_t f_prefix_len = p - f;
|
||||
ptrdiff_t f_prefix_copy_size = sumsize(f_prefix_len, 2);
|
||||
char fbuf[100];
|
||||
bool oversized = sizeof fbuf <= f_prefix_copy_size;
|
||||
char *f_prefix_copy = oversized ? xmalloc(f_prefix_copy_size) : fbuf;
|
||||
@ -1078,7 +1099,7 @@ istrftime(char *buf, size_t size, char const *time_fmt,
|
||||
b += offlen, s -= offlen;
|
||||
if (show_abbr) {
|
||||
char const *abp;
|
||||
size_t len;
|
||||
ptrdiff_t len;
|
||||
if (s <= 1)
|
||||
return false;
|
||||
*b++ = '\t', s--;
|
||||
@ -1117,7 +1138,7 @@ showtrans(char const *time_fmt, struct tm const *tm, time_t t, char const *ab,
|
||||
putchar('\n');
|
||||
} else {
|
||||
char stackbuf[1000];
|
||||
size_t size = sizeof stackbuf;
|
||||
ptrdiff_t size = sizeof stackbuf;
|
||||
char *buf = stackbuf;
|
||||
char *bufalloc = NULL;
|
||||
while (! istrftime(buf, size, time_fmt, tm, t, ab, zone_name)) {
|
||||
|
12
zic.8
12
zic.8
@ -1,4 +1,6 @@
|
||||
.TH ZIC 8
|
||||
.\" This file is in the public domain, so clarified as of
|
||||
.\" 2009-05-17 by Arthur David Olson.
|
||||
.TH zic 8
|
||||
.SH NAME
|
||||
zic \- timezone compiler
|
||||
.SH SYNOPSIS
|
||||
@ -22,7 +24,7 @@ zic \- timezone compiler
|
||||
.el .ds > \(ra
|
||||
.ie \n(.g \{\
|
||||
. ds : \:
|
||||
. ds - \f(CW-\fP
|
||||
. ds - \f(CR-\fP
|
||||
.\}
|
||||
.el \{\
|
||||
. ds :
|
||||
@ -347,7 +349,9 @@ nor
|
||||
.q + .
|
||||
To allow for future extensions,
|
||||
an unquoted name should not contain characters from the set
|
||||
.q !$%&'()*,/:;<=>?@[\e]^`{|}~ .
|
||||
.ie \n(.g .q \f(CR!$%&\(aq()*,/:;<=>?@[\e]\(ha\(ga{|}\(ti\fP .
|
||||
.el .ie t .q \f(CW!$%&'()*,/:;<=>?@[\e]^\(ga{|}~\fP .
|
||||
.el .q !$%&'()*,/:;<=>?@[\e]^`{|}~ .
|
||||
.TP
|
||||
.B FROM
|
||||
Gives the first year in which the rule applies.
|
||||
@ -894,5 +898,3 @@ specifying transition instants using universal time.
|
||||
.SH SEE ALSO
|
||||
.BR tzfile (5),
|
||||
.BR zdump (8)
|
||||
.\" This file is in the public domain, so clarified as of
|
||||
.\" 2009-05-17 by Arthur David Olson.
|
||||
|
@ -1,4 +1,4 @@
|
||||
ZIC(8) System Manager's Manual ZIC(8)
|
||||
zic(8) System Manager's Manual zic(8)
|
||||
|
||||
NAME
|
||||
zic - timezone compiler
|
||||
@ -513,4 +513,4 @@ NOTES
|
||||
SEE ALSO
|
||||
tzfile(5), zdump(8)
|
||||
|
||||
ZIC(8)
|
||||
zic(8)
|
||||
|
287
zic.c
287
zic.c
@ -34,6 +34,9 @@ static zic_t const
|
||||
# define ZIC_MAX_ABBR_LEN_WO_WARN 6
|
||||
#endif /* !defined ZIC_MAX_ABBR_LEN_WO_WARN */
|
||||
|
||||
/* An upper bound on how much a format might grow due to concatenation. */
|
||||
enum { FORMAT_LEN_GROWTH_BOUND = 5 };
|
||||
|
||||
#ifdef HAVE_DIRECT_H
|
||||
# include <direct.h>
|
||||
# include <io.h>
|
||||
@ -41,7 +44,16 @@ static zic_t const
|
||||
# define mkdir(name, mode) _mkdir(name)
|
||||
#endif
|
||||
|
||||
#if HAVE_GETRANDOM
|
||||
#ifndef HAVE_GETRANDOM
|
||||
# ifdef __has_include
|
||||
# if __has_include(<sys/random.h>)
|
||||
# include <sys/random.h>
|
||||
# endif
|
||||
# elif 2 < __GLIBC__ + (25 <= __GLIBC_MINOR__)
|
||||
# include <sys/random.h>
|
||||
# endif
|
||||
# define HAVE_GETRANDOM GRND_RANDOM
|
||||
#elif HAVE_GETRANDOM
|
||||
# include <sys/random.h>
|
||||
#endif
|
||||
|
||||
@ -54,11 +66,6 @@ static zic_t const
|
||||
# define MKDIR_UMASK 0755
|
||||
#endif
|
||||
|
||||
/* The maximum ptrdiff_t value, for pre-C99 platforms. */
|
||||
#ifndef PTRDIFF_MAX
|
||||
static ptrdiff_t const PTRDIFF_MAX = MAXVAL(ptrdiff_t, TYPE_BIT(ptrdiff_t));
|
||||
#endif
|
||||
|
||||
/* The minimum alignment of a type, for pre-C23 platforms. */
|
||||
#if __STDC_VERSION__ < 201112
|
||||
# define alignof(type) offsetof(struct { char a; type b; }, b)
|
||||
@ -452,29 +459,54 @@ static char roll[TZ_MAX_LEAPS];
|
||||
** Memory allocation.
|
||||
*/
|
||||
|
||||
static _Noreturn void
|
||||
static ATTRIBUTE_NORETURN void
|
||||
memory_exhausted(const char *msg)
|
||||
{
|
||||
fprintf(stderr, _("%s: Memory exhausted: %s\n"), progname, msg);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
static ATTRIBUTE_PURE size_t
|
||||
size_product(size_t nitems, size_t itemsize)
|
||||
static ATTRIBUTE_NORETURN void
|
||||
size_overflow(void)
|
||||
{
|
||||
if (SIZE_MAX / itemsize < nitems)
|
||||
memory_exhausted(_("size overflow"));
|
||||
return nitems * itemsize;
|
||||
memory_exhausted(_("size overflow"));
|
||||
}
|
||||
|
||||
static ATTRIBUTE_PURE size_t
|
||||
align_to(size_t size, size_t alignment)
|
||||
static ATTRIBUTE_REPRODUCIBLE ptrdiff_t
|
||||
size_sum(size_t a, size_t b)
|
||||
{
|
||||
size_t aligned_size = size + alignment - 1;
|
||||
aligned_size -= aligned_size % alignment;
|
||||
if (aligned_size < size)
|
||||
memory_exhausted(_("alignment overflow"));
|
||||
return aligned_size;
|
||||
#ifdef ckd_add
|
||||
ptrdiff_t sum;
|
||||
if (!ckd_add(&sum, a, b) && sum <= SIZE_MAX)
|
||||
return sum;
|
||||
#else
|
||||
ptrdiff_t sum_max = min(PTRDIFF_MAX, SIZE_MAX);
|
||||
if (a <= sum_max && b <= sum_max - a)
|
||||
return a + b;
|
||||
#endif
|
||||
size_overflow();
|
||||
}
|
||||
|
||||
static ATTRIBUTE_REPRODUCIBLE ptrdiff_t
|
||||
size_product(ptrdiff_t nitems, ptrdiff_t itemsize)
|
||||
{
|
||||
#ifdef ckd_mul
|
||||
ptrdiff_t product;
|
||||
if (!ckd_mul(&product, nitems, itemsize) && product <= SIZE_MAX)
|
||||
return product;
|
||||
#else
|
||||
ptrdiff_t nitems_max = min(PTRDIFF_MAX, SIZE_MAX) / itemsize;
|
||||
if (nitems <= nitems_max)
|
||||
return nitems * itemsize;
|
||||
#endif
|
||||
size_overflow();
|
||||
}
|
||||
|
||||
static ATTRIBUTE_REPRODUCIBLE ptrdiff_t
|
||||
align_to(ptrdiff_t size, ptrdiff_t alignment)
|
||||
{
|
||||
ptrdiff_t lo_bits = alignment - 1, sum = size_sum(size, lo_bits);
|
||||
return sum & ~lo_bits;
|
||||
}
|
||||
|
||||
#if !HAVE_STRDUP
|
||||
@ -507,23 +539,37 @@ erealloc(void *ptr, size_t size)
|
||||
}
|
||||
|
||||
static char * ATTRIBUTE_MALLOC
|
||||
ecpyalloc(char const *str)
|
||||
estrdup(char const *str)
|
||||
{
|
||||
return memcheck(strdup(str));
|
||||
}
|
||||
|
||||
static void *
|
||||
growalloc(void *ptr, size_t itemsize, ptrdiff_t nitems, ptrdiff_t *nitems_alloc)
|
||||
static ptrdiff_t
|
||||
grow_nitems_alloc(ptrdiff_t *nitems_alloc, ptrdiff_t itemsize)
|
||||
{
|
||||
if (nitems < *nitems_alloc)
|
||||
return ptr;
|
||||
else {
|
||||
ptrdiff_t amax = min(PTRDIFF_MAX, SIZE_MAX);
|
||||
if ((amax - 1) / 3 * 2 < *nitems_alloc)
|
||||
memory_exhausted(_("integer overflow"));
|
||||
*nitems_alloc += (*nitems_alloc >> 1) + 1;
|
||||
return erealloc(ptr, size_product(*nitems_alloc, itemsize));
|
||||
}
|
||||
ptrdiff_t addend = (*nitems_alloc >> 1) + 1;
|
||||
#if defined ckd_add && defined ckd_mul
|
||||
ptrdiff_t product;
|
||||
if (!ckd_add(nitems_alloc, *nitems_alloc, addend)
|
||||
&& !ckd_mul(&product, *nitems_alloc, itemsize) && product <= SIZE_MAX)
|
||||
return product;
|
||||
#else
|
||||
ptrdiff_t amax = min(PTRDIFF_MAX, SIZE_MAX);
|
||||
if (*nitems_alloc <= ((amax - 1) / 3 * 2) / itemsize) {
|
||||
*nitems_alloc += addend;
|
||||
return *nitems_alloc * itemsize;
|
||||
}
|
||||
#endif
|
||||
memory_exhausted(_("integer overflow"));
|
||||
}
|
||||
|
||||
static void *
|
||||
growalloc(void *ptr, ptrdiff_t itemsize, ptrdiff_t nitems,
|
||||
ptrdiff_t *nitems_alloc)
|
||||
{
|
||||
return (nitems < *nitems_alloc
|
||||
? ptr
|
||||
: erealloc(ptr, grow_nitems_alloc(nitems_alloc, itemsize)));
|
||||
}
|
||||
|
||||
/*
|
||||
@ -620,7 +666,7 @@ close_file(FILE *stream, char const *dir, char const *name,
|
||||
}
|
||||
}
|
||||
|
||||
static _Noreturn void
|
||||
static ATTRIBUTE_NORETURN void
|
||||
usage(FILE *stream, int status)
|
||||
{
|
||||
fprintf(stream,
|
||||
@ -943,7 +989,7 @@ main(int argc, char **argv)
|
||||
textdomain(TZ_DOMAIN);
|
||||
#endif /* HAVE_GETTEXT */
|
||||
main_argv = argv;
|
||||
progname = argv[0];
|
||||
progname = argv[0] ? argv[0] : "zic";
|
||||
if (TYPE_BIT(zic_t) < 64) {
|
||||
fprintf(stderr, "%s: %s\n", progname,
|
||||
_("wild compilation-time specification of zic_t"));
|
||||
@ -1201,21 +1247,12 @@ get_rand_u64(void)
|
||||
#endif
|
||||
|
||||
/* getrandom didn't work, so fall back on portable code that is
|
||||
not the best because the seed doesn't necessarily have enough bits,
|
||||
the seed isn't cryptographically random on platforms lacking
|
||||
getrandom, and 'rand' might not be cryptographically secure. */
|
||||
not the best because the seed isn't cryptographically random and
|
||||
'rand' might not be cryptographically secure. */
|
||||
{
|
||||
static bool initialized;
|
||||
if (!initialized) {
|
||||
unsigned seed;
|
||||
#ifdef CLOCK_REALTIME
|
||||
struct timespec now;
|
||||
clock_gettime (CLOCK_REALTIME, &now);
|
||||
seed = now.tv_sec ^ now.tv_nsec;
|
||||
#else
|
||||
seed = time(NULL);
|
||||
#endif
|
||||
srand(seed);
|
||||
srand(time(NULL));
|
||||
initialized = true;
|
||||
}
|
||||
}
|
||||
@ -1224,13 +1261,21 @@ get_rand_u64(void)
|
||||
the typical case where RAND_MAX is one less than a power of two.
|
||||
In other cases this code yields a sort-of-random number. */
|
||||
{
|
||||
uint_fast64_t
|
||||
rand_max = RAND_MAX,
|
||||
multiplier = rand_max + 1, /* It's OK if this overflows to 0. */
|
||||
uint_fast64_t rand_max = RAND_MAX,
|
||||
nrand = rand_max < UINT_FAST64_MAX ? rand_max + 1 : 0,
|
||||
rmod = INT_MAX < UINT_FAST64_MAX ? 0 : UINT_FAST64_MAX / nrand + 1,
|
||||
r = 0, rmax = 0;
|
||||
|
||||
do {
|
||||
uint_fast64_t rmax1 = rmax * multiplier + rand_max;
|
||||
r = r * multiplier + rand();
|
||||
uint_fast64_t rmax1 = rmax;
|
||||
if (rmod) {
|
||||
/* Avoid signed integer overflow on theoretical platforms
|
||||
where uint_fast64_t promotes to int. */
|
||||
rmax1 %= rmod;
|
||||
r %= rmod;
|
||||
}
|
||||
rmax1 = nrand * rmax1 + rand_max;
|
||||
r = nrand * r + rand();
|
||||
rmax = rmax < rmax1 ? rmax1 : UINT_FAST64_MAX;
|
||||
} while (rmax < UINT_FAST64_MAX);
|
||||
|
||||
@ -1272,7 +1317,7 @@ random_dirent(char const **name, char **namealloc)
|
||||
uint_fast64_t unfair_min = - ((UINTMAX_MAX % base__6 + 1) % base__6);
|
||||
|
||||
if (!dst) {
|
||||
dst = emalloc(dirlen + prefixlen + suffixlen + 1);
|
||||
dst = emalloc(size_sum(dirlen, prefixlen + suffixlen + 1));
|
||||
memcpy(dst, src, dirlen);
|
||||
memcpy(dst + dirlen, prefix, prefixlen);
|
||||
dst[dirlen + prefixlen + suffixlen] = '\0';
|
||||
@ -1351,19 +1396,20 @@ rename_dest(char *tempname, char const *name)
|
||||
static char *
|
||||
relname(char const *target, char const *linkname)
|
||||
{
|
||||
size_t i, taillen, dotdotetcsize;
|
||||
size_t dir_len = 0, dotdots = 0, linksize = SIZE_MAX;
|
||||
size_t i, taillen, dir_len = 0, dotdots = 0;
|
||||
ptrdiff_t dotdotetcsize, linksize = min(PTRDIFF_MAX, SIZE_MAX);
|
||||
char const *f = target;
|
||||
char *result = NULL;
|
||||
if (*linkname == '/') {
|
||||
/* Make F absolute too. */
|
||||
size_t len = strlen(directory);
|
||||
bool needslash = len && directory[len - 1] != '/';
|
||||
linksize = len + needslash + strlen(target) + 1;
|
||||
size_t lenslash = len + (len && directory[len - 1] != '/');
|
||||
size_t targetsize = strlen(target) + 1;
|
||||
linksize = size_sum(lenslash, targetsize);
|
||||
f = result = emalloc(linksize);
|
||||
strcpy(result, directory);
|
||||
memcpy(result, directory, len);
|
||||
result[len] = '/';
|
||||
strcpy(result + len + needslash, target);
|
||||
memcpy(result + lenslash, target, targetsize);
|
||||
}
|
||||
for (i = 0; f[i] && f[i] == linkname[i]; i++)
|
||||
if (f[i] == '/')
|
||||
@ -1371,7 +1417,7 @@ relname(char const *target, char const *linkname)
|
||||
for (; linkname[i]; i++)
|
||||
dotdots += linkname[i] == '/' && linkname[i - 1] != '/';
|
||||
taillen = strlen(f + dir_len);
|
||||
dotdotetcsize = 3 * dotdots + taillen + 1;
|
||||
dotdotetcsize = size_sum(size_product(dotdots, 3), taillen + 1);
|
||||
if (dotdotetcsize <= linksize) {
|
||||
if (!result)
|
||||
result = emalloc(dotdotetcsize);
|
||||
@ -1575,10 +1621,9 @@ associate(void)
|
||||
|
||||
/* Read a text line from FP into BUF, which is of size BUFSIZE.
|
||||
Terminate it with a NUL byte instead of a newline.
|
||||
Return the line's length, not counting the NUL byte.
|
||||
On EOF, return a negative number.
|
||||
Return true if successful, false if EOF.
|
||||
On error, report the error and exit. */
|
||||
static ptrdiff_t
|
||||
static bool
|
||||
inputline(FILE *fp, char *buf, ptrdiff_t bufsize)
|
||||
{
|
||||
ptrdiff_t linelen = 0, ch;
|
||||
@ -1589,7 +1634,7 @@ inputline(FILE *fp, char *buf, ptrdiff_t bufsize)
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (linelen == 0)
|
||||
return -1;
|
||||
return false;
|
||||
error(_("unterminated line"));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
@ -1604,7 +1649,7 @@ inputline(FILE *fp, char *buf, ptrdiff_t bufsize)
|
||||
}
|
||||
}
|
||||
buf[linelen] = '\0';
|
||||
return linelen;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -1626,13 +1671,14 @@ infile(int fnum, char const *name)
|
||||
}
|
||||
wantcont = false;
|
||||
for (num = 1; ; ++num) {
|
||||
ptrdiff_t linelen;
|
||||
char buf[_POSIX2_LINE_MAX];
|
||||
enum { bufsize_bound
|
||||
= (min(INT_MAX, min(PTRDIFF_MAX, SIZE_MAX))
|
||||
/ FORMAT_LEN_GROWTH_BOUND) };
|
||||
char buf[min(_POSIX2_LINE_MAX, bufsize_bound)];
|
||||
int nfields;
|
||||
char *fields[MAX_FIELDS];
|
||||
eat(fnum, num);
|
||||
linelen = inputline(fp, buf, sizeof buf);
|
||||
if (linelen < 0)
|
||||
if (!inputline(fp, buf, sizeof buf))
|
||||
break;
|
||||
nfields = getfields(buf, fields,
|
||||
sizeof fields / sizeof *fields);
|
||||
@ -1704,15 +1750,15 @@ gethms(char const *string, char const *errstring)
|
||||
default: ok = false; break;
|
||||
case 8:
|
||||
ok = '0' <= xr && xr <= '9';
|
||||
/* fallthrough */
|
||||
ATTRIBUTE_FALLTHROUGH;
|
||||
case 7:
|
||||
ok &= ssx == '.';
|
||||
if (ok && noise)
|
||||
warning(_("fractional seconds rejected by"
|
||||
" pre-2018 versions of zic"));
|
||||
/* fallthrough */
|
||||
case 5: ok &= mmx == ':'; /* fallthrough */
|
||||
case 3: ok &= hhx == ':'; /* fallthrough */
|
||||
ATTRIBUTE_FALLTHROUGH;
|
||||
case 5: ok &= mmx == ':'; ATTRIBUTE_FALLTHROUGH;
|
||||
case 3: ok &= hhx == ':'; ATTRIBUTE_FALLTHROUGH;
|
||||
case 1: break;
|
||||
}
|
||||
if (!ok) {
|
||||
@ -1742,7 +1788,7 @@ getsave(char *field, bool *isdst)
|
||||
{
|
||||
int dst = -1;
|
||||
zic_t save;
|
||||
size_t fieldlen = strlen(field);
|
||||
ptrdiff_t fieldlen = strlen(field);
|
||||
if (fieldlen != 0) {
|
||||
char *ep = field + fieldlen - 1;
|
||||
switch (*ep) {
|
||||
@ -1780,8 +1826,8 @@ inrule(char **fields, int nfields)
|
||||
fields[RF_COMMAND], fields[RF_MONTH], fields[RF_DAY],
|
||||
fields[RF_TOD]))
|
||||
return;
|
||||
r.r_name = ecpyalloc(fields[RF_NAME]);
|
||||
r.r_abbrvar = ecpyalloc(fields[RF_ABBRVAR]);
|
||||
r.r_name = estrdup(fields[RF_NAME]);
|
||||
r.r_abbrvar = estrdup(fields[RF_ABBRVAR]);
|
||||
if (max_abbrvar_len < strlen(r.r_abbrvar))
|
||||
max_abbrvar_len = strlen(r.r_abbrvar);
|
||||
rules = growalloc(rules, sizeof *rules, nrules, &nrules_alloc);
|
||||
@ -1838,7 +1884,7 @@ inzsub(char **fields, int nfields, bool iscont)
|
||||
register char * cp;
|
||||
char * cp1;
|
||||
struct zone z;
|
||||
size_t format_len;
|
||||
int format_len;
|
||||
register int i_stdoff, i_rule, i_format;
|
||||
register int i_untilyear, i_untilmonth;
|
||||
register int i_untilday, i_untiltime;
|
||||
@ -1905,9 +1951,9 @@ inzsub(char **fields, int nfields, bool iscont)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
z.z_name = iscont ? NULL : ecpyalloc(fields[ZF_NAME]);
|
||||
z.z_rule = ecpyalloc(fields[i_rule]);
|
||||
z.z_format = cp1 = ecpyalloc(fields[i_format]);
|
||||
z.z_name = iscont ? NULL : estrdup(fields[ZF_NAME]);
|
||||
z.z_rule = estrdup(fields[i_rule]);
|
||||
z.z_format = cp1 = estrdup(fields[i_format]);
|
||||
if (z.z_format_specifier == 'z') {
|
||||
cp1[cp - fields[i_format]] = 's';
|
||||
if (noise)
|
||||
@ -1924,7 +1970,7 @@ inzsub(char **fields, int nfields, bool iscont)
|
||||
}
|
||||
|
||||
static zic_t
|
||||
getleapdatetime(char **fields, int nfields, bool expire_line)
|
||||
getleapdatetime(char **fields, bool expire_line)
|
||||
{
|
||||
register const char * cp;
|
||||
register const struct lookup * lp;
|
||||
@ -2002,7 +2048,7 @@ inleap(char **fields, int nfields)
|
||||
if (nfields != LEAP_FIELDS)
|
||||
error(_("wrong number of fields on Leap line"));
|
||||
else {
|
||||
zic_t t = getleapdatetime(fields, nfields, false);
|
||||
zic_t t = getleapdatetime(fields, false);
|
||||
if (0 <= t) {
|
||||
struct lookup const *lp = byword(fields[LP_ROLL], leap_types);
|
||||
if (!lp)
|
||||
@ -2030,7 +2076,7 @@ inexpires(char **fields, int nfields)
|
||||
else if (0 <= leapexpires)
|
||||
error(_("multiple Expires lines"));
|
||||
else
|
||||
leapexpires = getleapdatetime(fields, nfields, true);
|
||||
leapexpires = getleapdatetime(fields, true);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -2050,8 +2096,8 @@ inlink(char **fields, int nfields)
|
||||
return;
|
||||
l.l_filenum = filenum;
|
||||
l.l_linenum = linenum;
|
||||
l.l_target = ecpyalloc(fields[LF_TARGET]);
|
||||
l.l_linkname = ecpyalloc(fields[LF_LINKNAME]);
|
||||
l.l_target = estrdup(fields[LF_TARGET]);
|
||||
l.l_linkname = estrdup(fields[LF_LINKNAME]);
|
||||
links = growalloc(links, sizeof *links, nlinks, &nlinks_alloc);
|
||||
links[nlinks++] = l;
|
||||
}
|
||||
@ -2074,7 +2120,7 @@ rulesub(struct rule *rp, const char *loyearp, const char *hiyearp,
|
||||
rp->r_month = lp->l_value;
|
||||
rp->r_todisstd = false;
|
||||
rp->r_todisut = false;
|
||||
dp = ecpyalloc(timep);
|
||||
dp = estrdup(timep);
|
||||
if (*dp != '\0') {
|
||||
ep = dp + strlen(dp) - 1;
|
||||
switch (lowerit(*ep)) {
|
||||
@ -2153,7 +2199,7 @@ rulesub(struct rule *rp, const char *loyearp, const char *hiyearp,
|
||||
** Sun<=20
|
||||
** Sun>=7
|
||||
*/
|
||||
dp = ecpyalloc(dayp);
|
||||
dp = estrdup(dayp);
|
||||
if ((lp = byword(dp, lasts)) != NULL) {
|
||||
rp->r_dycode = DC_DOWLEQ;
|
||||
rp->r_wday = lp->l_value;
|
||||
@ -2216,7 +2262,7 @@ convert64(uint_fast64_t val, char *buf)
|
||||
}
|
||||
|
||||
static void
|
||||
puttzcode(const int_fast32_t val, FILE *const fp)
|
||||
puttzcode(zic_t val, FILE *fp)
|
||||
{
|
||||
char buf[4];
|
||||
|
||||
@ -2305,8 +2351,10 @@ writezone(const char *const name, const char *const string, char version,
|
||||
char const *outname = name;
|
||||
|
||||
/* Allocate the ATS and TYPES arrays via a single malloc,
|
||||
as this is a bit faster. */
|
||||
zic_t *ats = emalloc(align_to(size_product(timecnt, sizeof *ats + 1),
|
||||
as this is a bit faster. Do not malloc(0) if !timecnt,
|
||||
as that might return NULL even on success. */
|
||||
zic_t *ats = emalloc(align_to(size_product(timecnt + !timecnt,
|
||||
sizeof *ats + 1),
|
||||
alignof(zic_t)));
|
||||
void *typesptr = ats + timecnt;
|
||||
unsigned char *types = typesptr;
|
||||
@ -2739,13 +2787,13 @@ abbroffset(char *buf, zic_t offset)
|
||||
|
||||
static char const disable_percent_s[] = "";
|
||||
|
||||
static size_t
|
||||
static ptrdiff_t
|
||||
doabbr(char *abbr, struct zone const *zp, char const *letters,
|
||||
bool isdst, zic_t save, bool doquotes)
|
||||
{
|
||||
register char * cp;
|
||||
register char * slashp;
|
||||
register size_t len;
|
||||
ptrdiff_t len;
|
||||
char const *format = zp->z_format;
|
||||
|
||||
slashp = strchr(format, '/');
|
||||
@ -2911,9 +2959,9 @@ stringzone(char *result, struct zone const *zpfirst, ptrdiff_t zonecount)
|
||||
register ptrdiff_t i;
|
||||
register int compat = 0;
|
||||
register int c;
|
||||
size_t len;
|
||||
int offsetlen;
|
||||
struct rule stdr, dstr;
|
||||
ptrdiff_t len;
|
||||
int dstcmp;
|
||||
struct rule *lastrp[2] = { NULL, NULL };
|
||||
struct zone zstr[2];
|
||||
@ -3046,8 +3094,10 @@ outzone(const struct zone *zpfirst, ptrdiff_t zonecount)
|
||||
|
||||
check_for_signal();
|
||||
|
||||
/* This cannot overflow; see FORMAT_LEN_GROWTH_BOUND. */
|
||||
max_abbr_len = 2 + max_format_len + max_abbrvar_len;
|
||||
max_envvar_len = 2 * max_abbr_len + 5 * 9;
|
||||
|
||||
startbuf = emalloc(max_abbr_len + 1);
|
||||
ab = emalloc(max_abbr_len + 1);
|
||||
envvar = emalloc(max_envvar_len + 1);
|
||||
@ -3547,7 +3597,7 @@ lowerit(char a)
|
||||
}
|
||||
|
||||
/* case-insensitive equality */
|
||||
static ATTRIBUTE_PURE bool
|
||||
static ATTRIBUTE_REPRODUCIBLE bool
|
||||
ciequal(register const char *ap, register const char *bp)
|
||||
{
|
||||
while (lowerit(*ap) == lowerit(*bp++))
|
||||
@ -3556,7 +3606,7 @@ ciequal(register const char *ap, register const char *bp)
|
||||
return false;
|
||||
}
|
||||
|
||||
static ATTRIBUTE_PURE bool
|
||||
static ATTRIBUTE_REPRODUCIBLE bool
|
||||
itsabbr(register const char *abbr, register const char *word)
|
||||
{
|
||||
if (lowerit(*abbr) != lowerit(*word))
|
||||
@ -3572,7 +3622,7 @@ itsabbr(register const char *abbr, register const char *word)
|
||||
|
||||
/* Return true if ABBR is an initial prefix of WORD, ignoring ASCII case. */
|
||||
|
||||
static ATTRIBUTE_PURE bool
|
||||
static ATTRIBUTE_REPRODUCIBLE bool
|
||||
ciprefix(char const *abbr, char const *word)
|
||||
{
|
||||
do
|
||||
@ -3675,38 +3725,41 @@ getfields(char *cp, char **array, int arrayelts)
|
||||
return nsubs;
|
||||
}
|
||||
|
||||
static _Noreturn void
|
||||
static ATTRIBUTE_NORETURN void
|
||||
time_overflow(void)
|
||||
{
|
||||
error(_("time overflow"));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
static ATTRIBUTE_PURE zic_t
|
||||
static ATTRIBUTE_REPRODUCIBLE zic_t
|
||||
oadd(zic_t t1, zic_t t2)
|
||||
{
|
||||
if (t1 < 0 ? t2 < ZIC_MIN - t1 : ZIC_MAX - t1 < t2)
|
||||
time_overflow();
|
||||
return t1 + t2;
|
||||
#ifdef ckd_add
|
||||
zic_t sum;
|
||||
if (!ckd_add(&sum, t1, t2))
|
||||
return sum;
|
||||
#else
|
||||
if (t1 < 0 ? ZIC_MIN - t1 <= t2 : t2 <= ZIC_MAX - t1)
|
||||
return t1 + t2;
|
||||
#endif
|
||||
time_overflow();
|
||||
}
|
||||
|
||||
static ATTRIBUTE_PURE zic_t
|
||||
static ATTRIBUTE_REPRODUCIBLE zic_t
|
||||
tadd(zic_t t1, zic_t t2)
|
||||
{
|
||||
if (t1 < 0) {
|
||||
if (t2 < min_time - t1) {
|
||||
if (t1 != min_time)
|
||||
time_overflow();
|
||||
return min_time;
|
||||
}
|
||||
} else {
|
||||
if (max_time - t1 < t2) {
|
||||
if (t1 != max_time)
|
||||
time_overflow();
|
||||
return max_time;
|
||||
}
|
||||
}
|
||||
return t1 + t2;
|
||||
#ifdef ckd_add
|
||||
zic_t sum;
|
||||
if (!ckd_add(&sum, t1, t2) && min_time <= sum && sum <= max_time)
|
||||
return sum;
|
||||
#else
|
||||
if (t1 < 0 ? min_time - t1 <= t2 : t2 <= max_time - t1)
|
||||
return t1 + t2;
|
||||
#endif
|
||||
if (t1 == min_time || t1 == max_time)
|
||||
return t1;
|
||||
time_overflow();
|
||||
}
|
||||
|
||||
/*
|
||||
@ -3830,10 +3883,8 @@ mp = _("time zone abbreviation differs from POSIX standard");
|
||||
static void
|
||||
mkdirs(char const *argname, bool ancestors)
|
||||
{
|
||||
register char * name;
|
||||
register char * cp;
|
||||
|
||||
cp = name = ecpyalloc(argname);
|
||||
char *name = estrdup(argname);
|
||||
char *cp = name;
|
||||
|
||||
/* On MS-Windows systems, do not worry about drive letters or
|
||||
backslashes, as this should suffice in practice. Time zone
|
||||
|
Loading…
Reference in New Issue
Block a user