mirror of
https://git.FreeBSD.org/src.git
synced 2024-12-28 11:57:28 +00:00
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
|
UTF8_LOCALE= en_US.utf8
|
||||||
|
|
||||||
# Non-default libraries needed to link.
|
# Non-default libraries needed to link.
|
||||||
|
# On some hosts, this should have -lintl unless CFLAGS has -DHAVE_GETTEXT=0.
|
||||||
LDLIBS=
|
LDLIBS=
|
||||||
|
|
||||||
# Add the following to the end of the "CFLAGS=" line as needed to override
|
# 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.
|
# For example, N is 252460800 on AmigaOS.
|
||||||
# -DHAVE_DECL_ASCTIME_R=0 if <time.h> does not declare asctime_r
|
# -DHAVE_DECL_ASCTIME_R=0 if <time.h> does not declare asctime_r
|
||||||
# -DHAVE_DECL_ENVIRON if <unistd.h> declares 'environ'
|
# -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_DIRECT_H if mkdir needs <direct.h> (MS-Windows)
|
||||||
# -DHAVE_GENERIC=0 if _Generic does not work
|
# -DHAVE_GENERIC=0 if _Generic does not work*
|
||||||
# -DHAVE_GETRANDOM if getgrandom works (e.g., GNU/Linux)*
|
# -DHAVE_GETRANDOM if getrandom works (e.g., GNU/Linux),
|
||||||
# -DHAVE_GETTEXT if 'gettext' works (e.g., GNU/Linux, FreeBSD, Solaris)*
|
# -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
|
# -DHAVE_INCOMPATIBLE_CTIME_R if your system's time.h declares
|
||||||
# ctime_r and asctime_r incompatibly with the POSIX standard
|
# ctime_r and asctime_r incompatibly with the POSIX standard
|
||||||
# (Solaris when _POSIX_PTHREAD_SEMANTICS is not defined).
|
# (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_LINK=0 if your system lacks a link function
|
||||||
# -DHAVE_LOCALTIME_R=0 if your system lacks a localtime_r 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
|
# -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
|
# functions like 'link' or variables like 'tzname' required by POSIX
|
||||||
# -DHAVE_SETENV=0 if your system lacks the setenv function
|
# -DHAVE_SETENV=0 if your system lacks the setenv function
|
||||||
# -DHAVE_SNPRINTF=0 if your system lacks the snprintf 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_STRFTIME_L if <time.h> declares locale_t and strftime_l
|
||||||
# -DHAVE_STRDUP=0 if your system lacks the strdup function
|
# -DHAVE_STRDUP=0 if your system lacks the strdup function
|
||||||
# -DHAVE_STRTOLL=0 if your system lacks the strtoll function
|
# -DHAVE_STRTOLL=0 if your system lacks the strtoll function
|
||||||
# -DHAVE_SYMLINK=0 if your system lacks the symlink 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_TZSET=0 if your system lacks a tzset function
|
||||||
# -DHAVE_UNISTD_H=0 if your compiler lacks a <unistd.h>*
|
# -DHAVE_UNISTD_H=0 if <unistd.h> does not work*
|
||||||
# -DHAVE_UTMPX_H=0 if your compiler lacks a <utmpx.h>*
|
# -DHAVE_UTMPX_H=0 if <utmpx.h> does not work*
|
||||||
# -Dlocale_t=XXX if your system uses XXX instead of locale_t
|
# -Dlocale_t=XXX if your system uses XXX instead of locale_t
|
||||||
# -DRESERVE_STD_EXT_IDS if your platform reserves standard identifiers
|
# -DRESERVE_STD_EXT_IDS if your platform reserves standard identifiers
|
||||||
# with external linkage, e.g., applications cannot define 'localtime'.
|
# 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 \
|
-Wdeclaration-after-statement -Wdouble-promotion \
|
||||||
-Wduplicated-branches -Wduplicated-cond \
|
-Wduplicated-branches -Wduplicated-cond \
|
||||||
-Wformat=2 -Wformat-overflow=2 -Wformat-signedness -Wformat-truncation \
|
-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 \
|
-Wmissing-declarations -Wmissing-prototypes -Wnested-externs \
|
||||||
-Wnull-dereference \
|
-Wnull-dereference \
|
||||||
-Wold-style-definition -Woverlength-strings -Wpointer-arith \
|
-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 \
|
-Wtrampolines -Wundef -Wuninitialized -Wunused-macros -Wuse-after-free=3 \
|
||||||
-Wvariadic-macros -Wvla -Wwrite-strings \
|
-Wvariadic-macros -Wvla -Wwrite-strings \
|
||||||
-Wno-address -Wno-format-nonliteral -Wno-sign-compare \
|
-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
|
# 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),
|
# (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,
|
# If you want functions that were inspired by early versions of X3J11's work,
|
||||||
# add
|
# add
|
||||||
# -DSTD_INSPIRED
|
# -DSTD_INSPIRED
|
||||||
# to the end of the "CFLAGS=" line. This arranges for the functions
|
# to the end of the "CFLAGS=" line. This arranges for the following
|
||||||
# "offtime", "timelocal", "timegm", "timeoff",
|
# functions to be added to the time conversion library.
|
||||||
# "posix2time", and "time2posix" to be added to the time conversion library.
|
|
||||||
# "offtime" is like "gmtime" except that it accepts a second (long) argument
|
# "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.
|
# that gives an offset to add to the time_t when converting it.
|
||||||
# "timelocal" is equivalent to "mktime".
|
# "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
|
# "timeoff" is like "timegm" except that it accepts a second (long) argument
|
||||||
# that gives an offset to use when converting to a time_t.
|
# that gives an offset to use when converting to a time_t.
|
||||||
# "posix2time" and "time2posix" are described in an included manual page.
|
# "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.
|
# Flags to give 'gzip' when making a distribution.
|
||||||
GZIPFLAGS= -9n
|
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
|
#MAKE= make
|
||||||
@ -773,7 +782,8 @@ tzselect: tzselect.ksh version
|
|||||||
chmod +x $@.out
|
chmod +x $@.out
|
||||||
mv $@.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_name_lengths check_slashed_abbrs check_sorted \
|
||||||
check_tables check_web check_ziguard check_zishrink check_tzs
|
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_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
|
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
|
backward | LC_ALL=C sort -cu
|
||||||
$(AWK) '/^Zone/ {print $$2}' backzone | LC_ALL=C sort -cu
|
$(AWK) '/^Zone/ {print $$2}' backzone | LC_ALL=C sort -cu
|
||||||
touch $@
|
touch $@
|
||||||
|
|
||||||
check_links: checklinks.awk $(TDATA_TO_CHECK) tzdata.zi
|
check_back: checklinks.awk $(TDATA_TO_CHECK)
|
||||||
$(AWK) \
|
$(AWK) \
|
||||||
-v DATAFORM=$(DATAFORM) \
|
-v DATAFORM=$(DATAFORM) \
|
||||||
-v backcheck=backward \
|
-v backcheck=backward \
|
||||||
-f checklinks.awk $(TDATA_TO_CHECK)
|
-f checklinks.awk $(TDATA_TO_CHECK)
|
||||||
|
touch $@
|
||||||
|
|
||||||
|
check_links: checklinks.awk tzdata.zi
|
||||||
$(AWK) \
|
$(AWK) \
|
||||||
-v DATAFORM=$(DATAFORM) \
|
-v DATAFORM=$(DATAFORM) \
|
||||||
-f checklinks.awk tzdata.zi
|
-f checklinks.awk tzdata.zi
|
||||||
@ -849,7 +862,7 @@ check_tables: checktab.awk $(YDATA) backward $(ZONETABLES)
|
|||||||
|
|
||||||
check_tzs: $(TZS) $(TZS_NEW)
|
check_tzs: $(TZS) $(TZS_NEW)
|
||||||
if test -s $(TZS); then \
|
if test -s $(TZS); then \
|
||||||
diff -u $(TZS) $(TZS_NEW); \
|
$(DIFF_TZS) $(TZS) $(TZS_NEW); \
|
||||||
else \
|
else \
|
||||||
cp $(TZS_NEW) $(TZS); \
|
cp $(TZS_NEW) $(TZS); \
|
||||||
fi
|
fi
|
||||||
@ -1050,7 +1063,7 @@ $(TIME_T_ALTERNATIVES): $(VERSION_DEPS)
|
|||||||
TZS_YEAR="$$range" TZS_CUTOFF_FLAG="-t $$range" \
|
TZS_YEAR="$$range" TZS_CUTOFF_FLAG="-t $$range" \
|
||||||
D=$$wd/$@.dir \
|
D=$$wd/$@.dir \
|
||||||
to$$range.tzs) && \
|
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 && \
|
$@.dir/to$$range.tzs && \
|
||||||
if diff -q Makefile Makefile 2>/dev/null; then \
|
if diff -q Makefile Makefile 2>/dev/null; then \
|
||||||
quiet_option='-q'; \
|
quiet_option='-q'; \
|
||||||
@ -1220,7 +1233,7 @@ zdump.o: version.h
|
|||||||
zic.o: private.h tzfile.h version.h
|
zic.o: private.h tzfile.h version.h
|
||||||
|
|
||||||
.PHONY: ALL INSTALL all
|
.PHONY: ALL INSTALL all
|
||||||
.PHONY: check check_time_t_alternatives
|
.PHONY: check check_mild check_time_t_alternatives
|
||||||
.PHONY: check_web check_zishrink
|
.PHONY: check_web check_zishrink
|
||||||
.PHONY: clean clean_misc dummy.zd force_tzs
|
.PHONY: clean clean_misc dummy.zd force_tzs
|
||||||
.PHONY: install install_data maintainer-clean names
|
.PHONY: install install_data maintainer-clean names
|
||||||
|
89
NEWS
89
NEWS
@ -1,5 +1,91 @@
|
|||||||
News for the tz database
|
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
|
Release 2022f - 2022-10-28 18:04:57 -0700
|
||||||
|
|
||||||
Briefly:
|
Briefly:
|
||||||
@ -16,7 +102,7 @@ Release 2022f - 2022-10-28 18:04:57 -0700
|
|||||||
In C code, use some C23 features if available.
|
In C code, use some C23 features if available.
|
||||||
Remove no-longer-needed workaround for Qt bug 53071.
|
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
|
Mexico will no longer observe DST after 2022, except for areas
|
||||||
near the US border that continue to observe US DST rules.
|
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
|
from -07 (-06 with DST) to year-round -06, thus not changing
|
||||||
its clocks that day. The new law states that Chihuahua
|
its clocks that day. The new law states that Chihuahua
|
||||||
near the US border no longer observes US DST.
|
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.)
|
Fiji will not observe DST in 2022/3. (Thanks to Shalvin Narayan.)
|
||||||
For now, assume DST is suspended indefinitely.
|
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
|
.SH NAME
|
||||||
date \- show and set date and time
|
date \- show and set date and time
|
||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
.if n .nh
|
.if n .nh
|
||||||
.if n .na
|
.if n .na
|
||||||
.ie \n(.g .ds - \f(CW-\fP
|
.ie \n(.g .ds - \f(CR-\fP
|
||||||
.el .ds - \-
|
.el .ds - \-
|
||||||
.B date
|
.B date
|
||||||
[
|
[
|
||||||
@ -163,5 +165,3 @@ If
|
|||||||
is absent,
|
is absent,
|
||||||
UTC leap seconds are loaded from
|
UTC leap seconds are loaded from
|
||||||
.BR /usr/share/zoneinfo/posixrules .
|
.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
|
NAME
|
||||||
date - show and set date and time
|
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
|
If /usr/share/zoneinfo/GMT is absent, UTC leap seconds are loaded from
|
||||||
/usr/share/zoneinfo/posixrules.
|
/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 dogmt(void);
|
||||||
static void errensure(void);
|
static void errensure(void);
|
||||||
static void timeout(FILE *, const char *, const struct tm *);
|
static void timeout(FILE *, const char *, const struct tm *);
|
||||||
static _Noreturn void usage(void);
|
static ATTRIBUTE_NORETURN void usage(void);
|
||||||
|
|
||||||
int
|
int
|
||||||
main(const int argc, char *argv[])
|
main(const int argc, char *argv[])
|
||||||
@ -117,14 +117,19 @@ dogmt(void)
|
|||||||
static char ** fakeenv;
|
static char ** fakeenv;
|
||||||
|
|
||||||
if (fakeenv == NULL) {
|
if (fakeenv == NULL) {
|
||||||
register int from;
|
|
||||||
register int to;
|
|
||||||
register int n;
|
|
||||||
static char tzeutc0[] = "TZ=UTC0";
|
static char tzeutc0[] = "TZ=UTC0";
|
||||||
|
ptrdiff_t from, to, n;
|
||||||
|
|
||||||
for (n = 0; environ[n] != NULL; ++n)
|
for (n = 0; environ[n] != NULL; ++n)
|
||||||
continue;
|
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) {
|
if (fakeenv == NULL) {
|
||||||
fprintf(stderr, _("date: Memory exhausted\n"));
|
fprintf(stderr, _("date: Memory exhausted\n"));
|
||||||
errensure();
|
errensure();
|
||||||
@ -183,33 +188,28 @@ display(char const *format, time_t now)
|
|||||||
static void
|
static void
|
||||||
timeout(FILE *fp, char const *format, struct tm const *tmp)
|
timeout(FILE *fp, char const *format, struct tm const *tmp)
|
||||||
{
|
{
|
||||||
char * cp;
|
char *cp = NULL;
|
||||||
size_t result;
|
ptrdiff_t result;
|
||||||
size_t size;
|
ptrdiff_t size = 1024 / 2;
|
||||||
struct tm tm;
|
|
||||||
int INCR = 1024;
|
|
||||||
|
|
||||||
if (!tmp) {
|
|
||||||
fprintf(stderr, _("date: error: time out of range\n"));
|
|
||||||
errensure();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
tm = *tmp;
|
|
||||||
tmp = &tm;
|
|
||||||
size = INCR;
|
|
||||||
cp = malloc(size);
|
|
||||||
for ( ; ; ) {
|
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,
|
fprintf(stderr,
|
||||||
_("date: error: can't get memory\n"));
|
_("date: error: can't get memory\n"));
|
||||||
errensure();
|
errensure();
|
||||||
exit(retval);
|
exit(retval);
|
||||||
}
|
}
|
||||||
|
cp = newcp;
|
||||||
result = strftime(cp, size, format, tmp);
|
result = strftime(cp, size, format, tmp);
|
||||||
if (result != 0)
|
if (result != 0)
|
||||||
break;
|
break;
|
||||||
size += INCR;
|
|
||||||
cp = realloc(cp, size);
|
|
||||||
}
|
}
|
||||||
fwrite(cp + 1, 1, result - 1, fp);
|
fwrite(cp + 1, 1, result - 1, fp);
|
||||||
free(cp);
|
free(cp);
|
||||||
|
94
localtime.c
94
localtime.c
@ -425,8 +425,7 @@ tzloadbody(char const *name, struct state *sp, bool doextend,
|
|||||||
#endif
|
#endif
|
||||||
if (!doaccess) {
|
if (!doaccess) {
|
||||||
char const *dot;
|
char const *dot;
|
||||||
size_t namelen = strlen(name);
|
if (sizeof lsp->fullname - sizeof tzdirslash <= strlen(name))
|
||||||
if (sizeof lsp->fullname - sizeof tzdirslash <= namelen)
|
|
||||||
return ENAMETOOLONG;
|
return ENAMETOOLONG;
|
||||||
|
|
||||||
/* Create a string "TZDIR/NAME". Using sprintf here
|
/* Create a string "TZDIR/NAME". Using sprintf here
|
||||||
@ -839,7 +838,7 @@ is_digit(char c)
|
|||||||
** Return a pointer to that character.
|
** Return a pointer to that character.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static ATTRIBUTE_PURE const char *
|
static ATTRIBUTE_REPRODUCIBLE const char *
|
||||||
getzname(register const char *strp)
|
getzname(register const char *strp)
|
||||||
{
|
{
|
||||||
register char c;
|
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.
|
** 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)
|
getqzname(register const char *strp, const int delim)
|
||||||
{
|
{
|
||||||
register int c;
|
register int c;
|
||||||
@ -1120,13 +1119,11 @@ tzparse(const char *name, struct state *sp, struct state *basep)
|
|||||||
{
|
{
|
||||||
const char * stdname;
|
const char * stdname;
|
||||||
const char * dstname;
|
const char * dstname;
|
||||||
size_t stdlen;
|
|
||||||
size_t dstlen;
|
|
||||||
size_t charcnt;
|
|
||||||
int_fast32_t stdoffset;
|
int_fast32_t stdoffset;
|
||||||
int_fast32_t dstoffset;
|
int_fast32_t dstoffset;
|
||||||
register char * cp;
|
register char * cp;
|
||||||
register bool load_ok;
|
register bool load_ok;
|
||||||
|
ptrdiff_t stdlen, dstlen, charcnt;
|
||||||
time_t atlo = TIME_T_MIN, leaplo = TIME_T_MIN;
|
time_t atlo = TIME_T_MIN, leaplo = TIME_T_MIN;
|
||||||
|
|
||||||
stdname = name;
|
stdname = name;
|
||||||
@ -1568,6 +1565,14 @@ localsub(struct state const *sp, time_t const *timep, int_fast32_t setname,
|
|||||||
return NULL; /* "cannot happen" */
|
return NULL; /* "cannot happen" */
|
||||||
result = localsub(sp, &newt, setname, tmp);
|
result = localsub(sp, &newt, setname, tmp);
|
||||||
if (result) {
|
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;
|
register int_fast64_t newy;
|
||||||
|
|
||||||
newy = result->tm_year;
|
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))
|
if (! (INT_MIN <= newy && newy <= INT_MAX))
|
||||||
return NULL;
|
return NULL;
|
||||||
result->tm_year = newy;
|
result->tm_year = newy;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -1656,8 +1662,8 @@ localtime_r(const time_t *timep, struct tm *tmp)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
static struct tm *
|
static struct tm *
|
||||||
gmtsub(struct state const *sp, time_t const *timep, int_fast32_t offset,
|
gmtsub(ATTRIBUTE_MAYBE_UNUSED struct state const *sp, time_t const *timep,
|
||||||
struct tm *tmp)
|
int_fast32_t offset, struct tm *tmp)
|
||||||
{
|
{
|
||||||
register struct tm * result;
|
register struct tm * result;
|
||||||
|
|
||||||
@ -1786,6 +1792,12 @@ timesub(const time_t *timep, int_fast32_t offset,
|
|||||||
y = newy;
|
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) {
|
if (!TYPE_SIGNED(time_t) && y < TM_YEAR_BASE) {
|
||||||
int signed_y = y;
|
int signed_y = y;
|
||||||
tmp->tm_year = signed_y - TM_YEAR_BASE;
|
tmp->tm_year = signed_y - TM_YEAR_BASE;
|
||||||
@ -1796,6 +1808,7 @@ timesub(const time_t *timep, int_fast32_t offset,
|
|||||||
errno = EOVERFLOW;
|
errno = EOVERFLOW;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
tmp->tm_yday = idays;
|
tmp->tm_yday = idays;
|
||||||
/*
|
/*
|
||||||
** The "extra" mods below avoid overflow problems.
|
** The "extra" mods below avoid overflow problems.
|
||||||
@ -1870,6 +1883,9 @@ ctime_r(const time_t *timep, char *buf)
|
|||||||
static bool
|
static bool
|
||||||
increment_overflow(int *ip, int j)
|
increment_overflow(int *ip, int j)
|
||||||
{
|
{
|
||||||
|
#ifdef ckd_add
|
||||||
|
return ckd_add(ip, *ip, j);
|
||||||
|
#else
|
||||||
register int const i = *ip;
|
register int const i = *ip;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1882,22 +1898,30 @@ increment_overflow(int *ip, int j)
|
|||||||
return true;
|
return true;
|
||||||
*ip += j;
|
*ip += j;
|
||||||
return false;
|
return false;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
increment_overflow32(int_fast32_t *const lp, int const m)
|
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;
|
register int_fast32_t const l = *lp;
|
||||||
|
|
||||||
if ((l >= 0) ? (m > INT_FAST32_MAX - l) : (m < INT_FAST32_MIN - l))
|
if ((l >= 0) ? (m > INT_FAST32_MAX - l) : (m < INT_FAST32_MIN - l))
|
||||||
return true;
|
return true;
|
||||||
*lp += m;
|
*lp += m;
|
||||||
return false;
|
return false;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
increment_overflow_time(time_t *tp, int_fast32_t j)
|
increment_overflow_time(time_t *tp, int_fast32_t j)
|
||||||
{
|
{
|
||||||
|
#ifdef ckd_add
|
||||||
|
return ckd_add(tp, *tp, j);
|
||||||
|
#else
|
||||||
/*
|
/*
|
||||||
** This is like
|
** This is like
|
||||||
** 'if (! (TIME_T_MIN <= *tp + j && *tp + j <= TIME_T_MAX)) ...',
|
** '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;
|
return true;
|
||||||
*tp += j;
|
*tp += j;
|
||||||
return false;
|
return false;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
@ -1951,6 +1976,23 @@ tmcomp(register const struct tm *const atmp,
|
|||||||
return result;
|
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
|
static time_t
|
||||||
time2sub(struct tm *const tmp,
|
time2sub(struct tm *const tmp,
|
||||||
struct tm *(*funcp)(struct state const *, time_t const *,
|
struct tm *(*funcp)(struct state const *, time_t const *,
|
||||||
@ -1972,7 +2014,8 @@ time2sub(struct tm *const tmp,
|
|||||||
struct tm yourtm, mytm;
|
struct tm yourtm, mytm;
|
||||||
|
|
||||||
*okayp = false;
|
*okayp = false;
|
||||||
yourtm = *tmp;
|
mktmcpy(&yourtm, tmp);
|
||||||
|
|
||||||
if (do_norm_secs) {
|
if (do_norm_secs) {
|
||||||
if (normalize_overflow(&yourtm.tm_min, &yourtm.tm_sec,
|
if (normalize_overflow(&yourtm.tm_min, &yourtm.tm_sec,
|
||||||
SECSPERMIN))
|
SECSPERMIN))
|
||||||
@ -2014,14 +2057,19 @@ time2sub(struct tm *const tmp,
|
|||||||
return WRONG;
|
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))
|
if (increment_overflow32(&y, -TM_YEAR_BASE))
|
||||||
return WRONG;
|
return WRONG;
|
||||||
if (! (INT_MIN <= y && y <= INT_MAX))
|
if (! (INT_MIN <= y && y <= INT_MAX))
|
||||||
return WRONG;
|
return WRONG;
|
||||||
yourtm.tm_year = y;
|
yourtm.tm_year = y;
|
||||||
|
#endif
|
||||||
if (yourtm.tm_sec >= 0 && yourtm.tm_sec < SECSPERMIN)
|
if (yourtm.tm_sec >= 0 && yourtm.tm_sec < SECSPERMIN)
|
||||||
saved_seconds = 0;
|
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
|
** We can't set tm_sec to 0, because that might push the
|
||||||
** time below the minimum representable time.
|
** time below the minimum representable time.
|
||||||
@ -2278,7 +2326,6 @@ mktime(struct tm *tmp)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef STD_INSPIRED
|
#ifdef STD_INSPIRED
|
||||||
|
|
||||||
time_t
|
time_t
|
||||||
timelocal(struct tm *tmp)
|
timelocal(struct tm *tmp)
|
||||||
{
|
{
|
||||||
@ -2286,13 +2333,9 @@ timelocal(struct tm *tmp)
|
|||||||
tmp->tm_isdst = -1; /* in case it wasn't initialized */
|
tmp->tm_isdst = -1; /* in case it wasn't initialized */
|
||||||
return mktime(tmp);
|
return mktime(tmp);
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
time_t
|
static
|
||||||
timegm(struct tm *tmp)
|
#endif
|
||||||
{
|
|
||||||
return timeoff(tmp, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
time_t
|
time_t
|
||||||
timeoff(struct tm *tmp, long offset)
|
timeoff(struct tm *tmp, long offset)
|
||||||
{
|
{
|
||||||
@ -2302,7 +2345,18 @@ timeoff(struct tm *tmp, long offset)
|
|||||||
return time1(tmp, gmtsub, gmtptr, 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
|
static int_fast32_t
|
||||||
leapcorr(struct state const *sp, time_t 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
|
.TH NEWCTIME 3
|
||||||
.SH NAME
|
.SH NAME
|
||||||
asctime, ctime, difftime, gmtime, localtime, mktime \- convert date and time
|
asctime, ctime, difftime, gmtime, localtime, mktime \- convert date and time
|
||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
.nf
|
.nf
|
||||||
.ie \n(.g .ds - \f(CW-\fP
|
.ie \n(.g .ds - \f(CR-\fP
|
||||||
.el .ds - \-
|
.el .ds - \-
|
||||||
.B #include <time.h>
|
.B #include <time.h>
|
||||||
.PP
|
.PP
|
||||||
@ -340,5 +342,3 @@ restricted to years in the range 1900 through 2099.
|
|||||||
To avoid this portability mess, new programs should use
|
To avoid this portability mess, new programs should use
|
||||||
.B strftime
|
.B strftime
|
||||||
instead.
|
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
|
strftime \- format date and time
|
||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
.nf
|
.nf
|
||||||
.ie \n(.g .ds - \f(CW-\fP
|
.ie \n(.g .ds - \f(CR-\fP
|
||||||
.el .ds - \-
|
.el .ds - \-
|
||||||
.B #include <time.h>
|
.B #include <time.h>
|
||||||
.PP
|
.PP
|
||||||
@ -55,7 +55,7 @@ strftime \- format date and time
|
|||||||
.ie '\(rq'' .ds rq \&"\"
|
.ie '\(rq'' .ds rq \&"\"
|
||||||
.el .ds rq \(rq\"
|
.el .ds rq \(rq\"
|
||||||
.de c
|
.de c
|
||||||
.ie \n(.g \f(CW\\$1\fP\\$2
|
.ie \n(.g \f(CR\\$1\fP\\$2
|
||||||
.el \\$1\\$2
|
.el \\$1\\$2
|
||||||
..
|
..
|
||||||
.de q
|
.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
|
.TH NEWTZSET 3
|
||||||
.SH NAME
|
.SH NAME
|
||||||
tzset \- initialize time conversion information
|
tzset \- initialize time conversion information
|
||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
.nf
|
.nf
|
||||||
.ie \n(.g .ds - \f(CW-\fP
|
.ie \n(.g .ds - \f(CR-\fP
|
||||||
.el .ds - \-
|
.el .ds - \-
|
||||||
.B #include <time.h>
|
.B #include <time.h>
|
||||||
.PP
|
.PP
|
||||||
@ -331,7 +333,7 @@ from the rest of the specification.
|
|||||||
.br
|
.br
|
||||||
/usr/share/zoneinfo/localtime local timezone file
|
/usr/share/zoneinfo/localtime local timezone file
|
||||||
.br
|
.br
|
||||||
/usr/share/zoneinfo/posixrules used with POSIX-style TZ's
|
/usr/share/zoneinfo/posixrules used with POSIX-style TZ
|
||||||
.br
|
.br
|
||||||
/usr/share/zoneinfo/GMT for UTC leap seconds
|
/usr/share/zoneinfo/GMT for UTC leap seconds
|
||||||
.sp
|
.sp
|
||||||
@ -346,5 +348,3 @@ newctime(3),
|
|||||||
newstrftime(3),
|
newstrftime(3),
|
||||||
time(2),
|
time(2),
|
||||||
tzfile(5)
|
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
|
FILES
|
||||||
/usr/share/zoneinfo timezone information directory
|
/usr/share/zoneinfo timezone information directory
|
||||||
/usr/share/zoneinfo/localtime local timezone file
|
/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
|
/usr/share/zoneinfo/GMT for UTC leap seconds
|
||||||
|
|
||||||
If /usr/share/zoneinfo/GMT is absent, UTC leap seconds are loaded from
|
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!
|
** Thank you!
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#ifndef __STDC_VERSION__
|
||||||
|
# define __STDC_VERSION__ 0
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Define true, false and bool if they don't work out of the box. */
|
/* Define true, false and bool if they don't work out of the box. */
|
||||||
#if __STDC_VERSION__ < 199901
|
#if __STDC_VERSION__ < 199901
|
||||||
# define true 1
|
# define true 1
|
||||||
@ -56,24 +60,13 @@
|
|||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
/* _Generic is buggy in pre-4.9 GCC. */
|
/* _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__))
|
# define HAVE_GENERIC (4 < __GNUC__ + (9 <= __GNUC_MINOR__))
|
||||||
#endif
|
#endif
|
||||||
#ifndef HAVE_GENERIC
|
#ifndef HAVE_GENERIC
|
||||||
# define HAVE_GENERIC (201112 <= __STDC_VERSION__)
|
# define HAVE_GENERIC (201112 <= __STDC_VERSION__)
|
||||||
#endif
|
#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 !defined HAVE_GETTEXT && defined __has_include
|
||||||
# if __has_include(<libintl.h>)
|
# if __has_include(<libintl.h>)
|
||||||
# define HAVE_GETTEXT true
|
# define HAVE_GETTEXT true
|
||||||
@ -289,36 +282,36 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Pre-C99 GCC compilers define __LONG_LONG_MAX__ instead of LLONG_MAX. */
|
/* 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
|
# ifndef LLONG_MAX
|
||||||
# define LLONG_MAX __LONG_LONG_MAX__
|
# define LLONG_MAX __LONG_LONG_MAX__
|
||||||
# endif
|
# endif
|
||||||
# ifndef LLONG_MIN
|
# ifndef LLONG_MIN
|
||||||
# define LLONG_MIN (-1 - LLONG_MAX)
|
# define LLONG_MIN (-1 - LLONG_MAX)
|
||||||
# endif
|
# endif
|
||||||
|
# ifndef ULLONG_MAX
|
||||||
|
# define ULLONG_MAX (LLONG_MAX * 2ull + 1)
|
||||||
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef INT_FAST64_MAX
|
#ifndef INT_FAST64_MAX
|
||||||
# ifdef LLONG_MAX
|
# if 1 <= LONG_MAX >> 31 >> 31
|
||||||
typedef long long int_fast64_t;
|
typedef 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;
|
|
||||||
# define INT_FAST64_MIN LONG_MIN
|
# define INT_FAST64_MIN LONG_MIN
|
||||||
# define INT_FAST64_MAX LONG_MAX
|
# 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
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef PRIdFAST64
|
#ifndef PRIdFAST64
|
||||||
# if INT_FAST64_MAX == LLONG_MAX
|
# if INT_FAST64_MAX == LONG_MAX
|
||||||
# define PRIdFAST64 "lld"
|
|
||||||
# else
|
|
||||||
# define PRIdFAST64 "ld"
|
# define PRIdFAST64 "ld"
|
||||||
|
# else
|
||||||
|
# define PRIdFAST64 "lld"
|
||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -364,24 +357,27 @@ typedef long intmax_t;
|
|||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef PTRDIFF_MAX
|
||||||
|
# define PTRDIFF_MAX MAXVAL(ptrdiff_t, TYPE_BIT(ptrdiff_t))
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef UINT_FAST32_MAX
|
#ifndef UINT_FAST32_MAX
|
||||||
typedef unsigned long uint_fast32_t;
|
typedef unsigned long uint_fast32_t;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef UINT_FAST64_MAX
|
#ifndef UINT_FAST64_MAX
|
||||||
# if defined ULLONG_MAX || defined __LONG_LONG_MAX__
|
# if 3 <= ULONG_MAX >> 31 >> 31
|
||||||
typedef unsigned long long uint_fast64_t;
|
typedef unsigned long uint_fast64_t;
|
||||||
|
# define UINT_FAST64_MAX ULONG_MAX
|
||||||
# else
|
# else
|
||||||
# if ULONG_MAX >> 31 >> 1 < 0xffffffff
|
/* If this fails, compile with -DHAVE_STDINT_H or with a better compiler. */
|
||||||
Please use a compiler that supports a 64-bit integer type (or wider);
|
typedef unsigned long long uint_fast64_t;
|
||||||
you may need to compile with "-DHAVE_STDINT_H".
|
# define UINT_FAST64_MAX ULLONG_MAX
|
||||||
# endif
|
|
||||||
typedef unsigned long uint_fast64_t;
|
|
||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef UINTMAX_MAX
|
#ifndef UINTMAX_MAX
|
||||||
# if defined ULLONG_MAX || defined __LONG_LONG_MAX__
|
# ifdef ULLONG_MAX
|
||||||
typedef unsigned long long uintmax_t;
|
typedef unsigned long long uintmax_t;
|
||||||
# else
|
# else
|
||||||
typedef unsigned long uintmax_t;
|
typedef unsigned long uintmax_t;
|
||||||
@ -389,7 +385,7 @@ typedef unsigned long uintmax_t;
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef PRIuMAX
|
#ifndef PRIuMAX
|
||||||
# if defined ULLONG_MAX || defined __LONG_LONG_MAX__
|
# ifdef ULLONG_MAX
|
||||||
# define PRIuMAX "llu"
|
# define PRIuMAX "llu"
|
||||||
# else
|
# else
|
||||||
# define PRIuMAX "lu"
|
# define PRIuMAX "lu"
|
||||||
@ -400,23 +396,114 @@ typedef unsigned long uintmax_t;
|
|||||||
# define SIZE_MAX ((size_t) -1)
|
# define SIZE_MAX ((size_t) -1)
|
||||||
#endif
|
#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__
|
#if 3 <= __GNUC__
|
||||||
# define ATTRIBUTE_CONST __attribute__((const))
|
# define ATTRIBUTE_MALLOC __attribute__((malloc))
|
||||||
# define ATTRIBUTE_MALLOC __attribute__((__malloc__))
|
# define ATTRIBUTE_FORMAT(spec) __attribute__((format spec))
|
||||||
# define ATTRIBUTE_PURE __attribute__((__pure__))
|
|
||||||
# define ATTRIBUTE_FORMAT(spec) __attribute__((__format__ spec))
|
|
||||||
#else
|
#else
|
||||||
# define ATTRIBUTE_CONST /* empty */
|
|
||||||
# define ATTRIBUTE_MALLOC /* empty */
|
# define ATTRIBUTE_MALLOC /* empty */
|
||||||
# define ATTRIBUTE_PURE /* empty */
|
|
||||||
# define ATTRIBUTE_FORMAT(spec) /* empty */
|
# define ATTRIBUTE_FORMAT(spec) /* empty */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined _Noreturn && __STDC_VERSION__ < 201112
|
#if (defined __has_c_attribute \
|
||||||
# if 2 < __GNUC__ + (8 <= __GNUC_MINOR__)
|
&& (202311 <= __STDC_VERSION__ || !defined __STRICT_ANSI__))
|
||||||
# define _Noreturn __attribute__((__noreturn__))
|
# 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
|
# 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
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -541,7 +628,7 @@ char *asctime(struct tm const *);
|
|||||||
char *asctime_r(struct tm const *restrict, char *restrict);
|
char *asctime_r(struct tm const *restrict, char *restrict);
|
||||||
char *ctime(time_t const *);
|
char *ctime(time_t const *);
|
||||||
char *ctime_r(time_t const *, char *);
|
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,
|
size_t strftime(char *restrict, size_t, char const *restrict,
|
||||||
struct tm const *restrict);
|
struct tm const *restrict);
|
||||||
# if HAVE_STRFTIME_L
|
# 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);
|
struct tm *localtime_r(time_t const *restrict, struct tm *restrict);
|
||||||
time_t mktime(struct tm *);
|
time_t mktime(struct tm *);
|
||||||
time_t time(time_t *);
|
time_t time(time_t *);
|
||||||
|
time_t timegm(struct tm *);
|
||||||
void tzset(void);
|
void tzset(void);
|
||||||
#endif
|
#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
|
#if !HAVE_DECL_ASCTIME_R && !defined asctime_r
|
||||||
extern char *asctime_r(struct tm const *restrict, char *restrict);
|
extern char *asctime_r(struct tm const *restrict, char *restrict);
|
||||||
#endif
|
#endif
|
||||||
@ -593,9 +695,6 @@ extern long altzone;
|
|||||||
# if TZ_TIME_T || !defined offtime
|
# if TZ_TIME_T || !defined offtime
|
||||||
struct tm *offtime(time_t const *, long);
|
struct tm *offtime(time_t const *, long);
|
||||||
# endif
|
# endif
|
||||||
# if TZ_TIME_T || !defined timegm
|
|
||||||
time_t timegm(struct tm *);
|
|
||||||
# endif
|
|
||||||
# if TZ_TIME_T || !defined timelocal
|
# if TZ_TIME_T || !defined timelocal
|
||||||
time_t timelocal(struct tm *);
|
time_t timelocal(struct tm *);
|
||||||
# endif
|
# endif
|
||||||
@ -613,6 +712,7 @@ time_t posix2time(time_t);
|
|||||||
/* Infer TM_ZONE on systems where this information is known, but suppress
|
/* Infer TM_ZONE on systems where this information is known, but suppress
|
||||||
guessing if NO_TM_ZONE is defined. Similarly for TM_GMTOFF. */
|
guessing if NO_TM_ZONE is defined. Similarly for TM_GMTOFF. */
|
||||||
#if (defined __GLIBC__ \
|
#if (defined __GLIBC__ \
|
||||||
|
|| defined __tm_zone /* musl */ \
|
||||||
|| defined __FreeBSD__ || defined __NetBSD__ || defined __OpenBSD__ \
|
|| defined __FreeBSD__ || defined __NetBSD__ || defined __OpenBSD__ \
|
||||||
|| (defined __APPLE__ && defined __MACH__))
|
|| (defined __APPLE__ && defined __MACH__))
|
||||||
# if !defined TM_GMTOFF && !defined NO_TM_GMTOFF
|
# if !defined TM_GMTOFF && !defined NO_TM_GMTOFF
|
||||||
@ -640,10 +740,10 @@ timezone_t tzalloc(char const *);
|
|||||||
void tzfree(timezone_t);
|
void tzfree(timezone_t);
|
||||||
# ifdef STD_INSPIRED
|
# ifdef STD_INSPIRED
|
||||||
# if TZ_TIME_T || !defined posix2time_z
|
# 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
|
# endif
|
||||||
# if TZ_TIME_T || !defined time2posix_z
|
# 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
|
# 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
|
#if HAVE_STRFTIME_L
|
||||||
size_t
|
size_t
|
||||||
strftime_l(char *s, size_t maxsize, char const *format, struct tm const *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. */
|
/* Just call strftime, as only the C locale is supported. */
|
||||||
return strftime(s, maxsize, format, t);
|
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) + 1];
|
||||||
time_t mkt;
|
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);
|
mkt = mktime(&tm);
|
||||||
/* There is no portable, definitive
|
/* If mktime fails, %s expands to the
|
||||||
test for whether whether mktime
|
value of (time_t) -1 as a failure
|
||||||
succeeded, so treat (time_t) -1 as
|
marker; this is better in practice
|
||||||
the success that it might be. */
|
than strftime failing. */
|
||||||
if (TYPE_SIGNED(time_t)) {
|
if (TYPE_SIGNED(time_t)) {
|
||||||
intmax_t n = mkt;
|
intmax_t n = mkt;
|
||||||
sprintf(buf, "%"PRIdMAX, n);
|
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
|
American mountain time zone can choose from the timezones
|
||||||
<code>America/Denver</code> which observes US-style daylight saving
|
<code>America/Denver</code> which observes US-style daylight saving
|
||||||
time (<abbr>DST</abbr>),
|
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>.
|
and <code>America/Phoenix</code> which does not observe <abbr>DST</abbr>.
|
||||||
Applications that also deal with past timestamps in the mountain time
|
Applications that also deal with past timestamps in the mountain time
|
||||||
zone can choose from over a dozen timezones, such as
|
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
|
.SH NAME
|
||||||
time2posix, posix2time \- convert seconds since the Epoch
|
time2posix, posix2time \- convert seconds since the Epoch
|
||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
.nf
|
.nf
|
||||||
.ie \n(.g .ds - \f(CW-\fP
|
.ie \n(.g .ds - \f(CR-\fP
|
||||||
.el .ds - \-
|
.el .ds - \-
|
||||||
.B #include <time.h>
|
.B #include <time.h>
|
||||||
.PP
|
.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
|
and the same relationship is assumed by some
|
||||||
(usually older)
|
(usually older)
|
||||||
applications.
|
applications.
|
||||||
Any programs creating/dissecting time_t's
|
Any programs creating/dissecting time_t values
|
||||||
using such a relationship will typically not handle intervals
|
using such a relationship will typically not handle intervals
|
||||||
over leap seconds correctly.
|
over leap seconds correctly.
|
||||||
.PP
|
.PP
|
||||||
@ -93,7 +95,7 @@ Both of these are good indicators of the inferiority of the
|
|||||||
POSIX representation.
|
POSIX representation.
|
||||||
.PP
|
.PP
|
||||||
The following table summarizes the relationship between a time
|
The following table summarizes the relationship between a time
|
||||||
T and it's conversion to,
|
T and its conversion to,
|
||||||
and back from,
|
and back from,
|
||||||
the POSIX representation over the leap second inserted at the end of June,
|
the POSIX representation over the leap second inserted at the end of June,
|
||||||
1993.
|
1993.
|
||||||
@ -117,8 +119,8 @@ DATE TIME T X=time2posix(T) posix2time(X)
|
|||||||
.fi
|
.fi
|
||||||
.PP
|
.PP
|
||||||
If leap-second support is not enabled,
|
If leap-second support is not enabled,
|
||||||
local time_t's and
|
local time_t and
|
||||||
POSIX time_t's are equivalent,
|
POSIX time_t values are equivalent,
|
||||||
and both
|
and both
|
||||||
.B time2posix
|
.B time2posix
|
||||||
and
|
and
|
||||||
@ -129,5 +131,3 @@ difftime(3),
|
|||||||
localtime(3),
|
localtime(3),
|
||||||
mktime(3),
|
mktime(3),
|
||||||
time(2)
|
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
|
NAME
|
||||||
time2posix, posix2time - convert seconds since the Epoch
|
time2posix, posix2time - convert seconds since the Epoch
|
||||||
@ -30,8 +30,8 @@ DESCRIPTION
|
|||||||
difftime(3). However, POSIX gives an arithmetic expression for
|
difftime(3). However, POSIX gives an arithmetic expression for
|
||||||
directly computing a time_t value from a given date/time, and the same
|
directly computing a time_t value from a given date/time, and the same
|
||||||
relationship is assumed by some (usually older) applications. Any
|
relationship is assumed by some (usually older) applications. Any
|
||||||
programs creating/dissecting time_t's using such a relationship will
|
programs creating/dissecting time_t values using such a relationship
|
||||||
typically not handle intervals over leap seconds correctly.
|
will typically not handle intervals over leap seconds correctly.
|
||||||
|
|
||||||
The time2posix and posix2time functions are provided to address this
|
The time2posix and posix2time functions are provided to address this
|
||||||
time_t mismatch by converting between local time_t values and their
|
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.
|
indicators of the inferiority of the POSIX representation.
|
||||||
|
|
||||||
The following table summarizes the relationship between a time T and
|
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.
|
leap second inserted at the end of June, 1993.
|
||||||
DATE TIME T X=time2posix(T) posix2time(X)
|
DATE TIME T X=time2posix(T) posix2time(X)
|
||||||
93/06/30 23:59:59 A+0 B+0 A+0
|
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]
|
[Note: posix2time(B+1) => A+0 or A+1]
|
||||||
|
|
||||||
If leap-second support is not enabled, local time_t's and POSIX
|
If leap-second support is not enabled, local time_t and POSIX time_t
|
||||||
time_t's are equivalent, and both time2posix and posix2time degenerate
|
values are equivalent, and both time2posix and posix2time degenerate to
|
||||||
to the identity function.
|
the identity function.
|
||||||
|
|
||||||
SEE ALSO
|
SEE ALSO
|
||||||
difftime(3), localtime(3), mktime(3), time(2)
|
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
|
.TH TZFILE 5
|
||||||
.SH NAME
|
.SH NAME
|
||||||
tzfile \- timezone information
|
tzfile \- timezone information
|
||||||
@ -9,7 +11,7 @@ tzfile \- timezone information
|
|||||||
.de q
|
.de q
|
||||||
\\$3\*(lq\\$1\*(rq\\$2
|
\\$3\*(lq\\$1\*(rq\\$2
|
||||||
..
|
..
|
||||||
.ie \n(.g .ds - \f(CW-\fP
|
.ie \n(.g .ds - \f(CR-\fP
|
||||||
.el .ds - \-
|
.el .ds - \-
|
||||||
The timezone information files used by
|
The timezone information files used by
|
||||||
.BR tzset (3)
|
.BR tzset (3)
|
||||||
@ -492,5 +494,3 @@ Internet RFC 8536
|
|||||||
.UR https://\:doi.org/\:10.17487/\:RFC8536
|
.UR https://\:doi.org/\:10.17487/\:RFC8536
|
||||||
doi:10.17487/RFC8536
|
doi:10.17487/RFC8536
|
||||||
.UE .
|
.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
|
.TH TZSELECT 8
|
||||||
.SH NAME
|
.SH NAME
|
||||||
tzselect \- select a timezone
|
tzselect \- select a timezone
|
||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
.ie \n(.g .ds - \f(CW-\fP
|
.ie \n(.g .ds - \f(CR-\fP
|
||||||
.el .ds - \-
|
.el .ds - \-
|
||||||
.ds d " degrees
|
.ds d " degrees
|
||||||
.ds m " minutes
|
.ds m " minutes
|
||||||
@ -121,5 +123,3 @@ newctime(3), tzfile(5), zdump(8), zic(8)
|
|||||||
Applications should not assume that
|
Applications should not assume that
|
||||||
.BR tzselect 's
|
.BR tzselect 's
|
||||||
output matches the user's political preferences.
|
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
|
.SH NAME
|
||||||
zdump \- timezone dumper
|
zdump \- timezone dumper
|
||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
@ -16,7 +18,7 @@ zdump \- timezone dumper
|
|||||||
.de q
|
.de q
|
||||||
\\$3\*(lq\\$1\*(rq\\$2
|
\\$3\*(lq\\$1\*(rq\\$2
|
||||||
..
|
..
|
||||||
.ie \n(.g .ds - \f(CW-\fP
|
.ie \n(.g .ds - \f(CR-\fP
|
||||||
.el .ds - \-
|
.el .ds - \-
|
||||||
The
|
The
|
||||||
.B zdump
|
.B zdump
|
||||||
@ -149,7 +151,7 @@ Here is an example of the output, with the leading empty line omitted.
|
|||||||
tabbed columns line up.)
|
tabbed columns line up.)
|
||||||
.nf
|
.nf
|
||||||
.sp
|
.sp
|
||||||
.if \n(.g .ft CW
|
.if \n(.g .ft CR
|
||||||
.if t .in +.5i
|
.if t .in +.5i
|
||||||
.if n .in +2
|
.if n .in +2
|
||||||
.nr w \w'1896-01-13 'u+\n(.i
|
.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:
|
Here are excerpts from another example:
|
||||||
.nf
|
.nf
|
||||||
.sp
|
.sp
|
||||||
.if \n(.g .ft CW
|
.if \n(.g .ft CR
|
||||||
.if t .in +.5i
|
.if t .in +.5i
|
||||||
.if n .in +2
|
.if n .in +2
|
||||||
TZ="Europe/Astrakhan"
|
TZ="Europe/Astrakhan"
|
||||||
@ -227,5 +229,3 @@ introduction of UTC is problematic.
|
|||||||
.SH SEE ALSO
|
.SH SEE ALSO
|
||||||
.BR tzfile (5),
|
.BR tzfile (5),
|
||||||
.BR zic (8)
|
.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
|
NAME
|
||||||
zdump - timezone dumper
|
zdump - timezone dumper
|
||||||
@ -141,4 +141,4 @@ LIMITATIONS
|
|||||||
SEE ALSO
|
SEE ALSO
|
||||||
tzfile(5), zic(8)
|
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))
|
? (((time_t) 1 << atime_shift) - 1 + ((time_t) 1 << atime_shift))
|
||||||
: -1);
|
: -1);
|
||||||
static int longest;
|
static int longest;
|
||||||
static char * progname;
|
static char const *progname;
|
||||||
static bool warned;
|
static bool warned;
|
||||||
static bool errout;
|
static bool errout;
|
||||||
|
|
||||||
static char const *abbr(struct tm const *);
|
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 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 show(timezone_t, char *, time_t, bool);
|
||||||
static void showextrema(timezone_t, char *, time_t, struct tm *, time_t);
|
static void showextrema(timezone_t, char *, time_t, struct tm *, time_t);
|
||||||
static void showtrans(char const *, struct tm const *, time_t, char const *,
|
static void showtrans(char const *, struct tm const *, time_t, char const *,
|
||||||
char const *);
|
char const *);
|
||||||
static const char *tformat(void);
|
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? */
|
/* Is C an ASCII digit? */
|
||||||
static bool
|
static bool
|
||||||
@ -125,16 +125,28 @@ is_alpha(char a)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return A + B, exiting if the result would overflow. */
|
static ATTRIBUTE_NORETURN void
|
||||||
static size_t
|
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)
|
sumsize(size_t a, size_t b)
|
||||||
{
|
{
|
||||||
size_t sum = a + b;
|
#ifdef ckd_add
|
||||||
if (sum < a) {
|
ptrdiff_t sum;
|
||||||
fprintf(stderr, _("%s: size overflow\n"), progname);
|
if (!ckd_add(&sum, a, b) && sum <= SIZE_MAX)
|
||||||
exit(EXIT_FAILURE);
|
return sum;
|
||||||
}
|
#else
|
||||||
return sum;
|
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
|
/* Return a pointer to a newly allocated buffer of size SIZE, exiting
|
||||||
@ -234,22 +246,30 @@ tzalloc(char const *val)
|
|||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
tzset();
|
tzset();
|
||||||
return NULL;
|
return &optarg; /* Any valid non-null char ** will do. */
|
||||||
# else
|
# else
|
||||||
enum { TZeqlen = 3 };
|
enum { TZeqlen = 3 };
|
||||||
static char const TZeq[TZeqlen] = "TZ=";
|
static char const TZeq[TZeqlen] = "TZ=";
|
||||||
static char **fakeenv;
|
static char **fakeenv;
|
||||||
static size_t fakeenv0size;
|
static ptrdiff_t fakeenv0size;
|
||||||
void *freeable = NULL;
|
void *freeable = NULL;
|
||||||
char **env = fakeenv, **initial_environ;
|
char **env = fakeenv, **initial_environ;
|
||||||
size_t valsize = strlen(val) + 1;
|
size_t valsize = strlen(val) + 1;
|
||||||
if (fakeenv0size < valsize) {
|
if (fakeenv0size < valsize) {
|
||||||
char **e = environ, **to;
|
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++)
|
while (*e++) {
|
||||||
continue;
|
# ifdef ckd_add
|
||||||
initial_nenvptrs = e - environ;
|
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 = sumsize(valsize, valsize);
|
||||||
fakeenv0size = max(fakeenv0size, 64);
|
fakeenv0size = max(fakeenv0size, 64);
|
||||||
freeable = env;
|
freeable = env;
|
||||||
@ -385,7 +405,7 @@ abbrok(const char *const abbrp, const char *const zone)
|
|||||||
return the abbreviation. Get the abbreviation from TMP.
|
return the abbreviation. Get the abbreviation from TMP.
|
||||||
Exit on memory allocation failure. */
|
Exit on memory allocation failure. */
|
||||||
static char const *
|
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);
|
char const *ab = abbr(tmp);
|
||||||
if (HAVE_LOCALTIME_RZ)
|
if (HAVE_LOCALTIME_RZ)
|
||||||
@ -442,7 +462,7 @@ main(int argc, char *argv[])
|
|||||||
{
|
{
|
||||||
/* These are static so that they're initially zero. */
|
/* These are static so that they're initially zero. */
|
||||||
static char * abbrev;
|
static char * abbrev;
|
||||||
static size_t abbrevsize;
|
static ptrdiff_t abbrevsize;
|
||||||
|
|
||||||
register int i;
|
register int i;
|
||||||
register bool vflag;
|
register bool vflag;
|
||||||
@ -463,7 +483,7 @@ main(int argc, char *argv[])
|
|||||||
# endif /* defined TEXTDOMAINDIR */
|
# endif /* defined TEXTDOMAINDIR */
|
||||||
textdomain(TZ_DOMAIN);
|
textdomain(TZ_DOMAIN);
|
||||||
#endif /* HAVE_GETTEXT */
|
#endif /* HAVE_GETTEXT */
|
||||||
progname = argv[0];
|
progname = argv[0] ? argv[0] : "zdump";
|
||||||
for (i = 1; i < argc; ++i)
|
for (i = 1; i < argc; ++i)
|
||||||
if (strcmp(argv[i], "--version") == 0) {
|
if (strcmp(argv[i], "--version") == 0) {
|
||||||
printf("zdump %s%s\n", PKGVERSION, TZVERSION);
|
printf("zdump %s%s\n", PKGVERSION, TZVERSION);
|
||||||
@ -483,7 +503,7 @@ main(int argc, char *argv[])
|
|||||||
case -1:
|
case -1:
|
||||||
if (! (optind == argc - 1 && strcmp(argv[optind], "=") == 0))
|
if (! (optind == argc - 1 && strcmp(argv[optind], "=") == 0))
|
||||||
goto arg_processing_done;
|
goto arg_processing_done;
|
||||||
/* Fall through. */
|
ATTRIBUTE_FALLTHROUGH;
|
||||||
default:
|
default:
|
||||||
usage(stderr, EXIT_FAILURE);
|
usage(stderr, EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
@ -607,7 +627,7 @@ main(int argc, char *argv[])
|
|||||||
|| (ab && (delta(&newtm, &tm) != newt - t
|
|| (ab && (delta(&newtm, &tm) != newt - t
|
||||||
|| newtm.tm_isdst != tm.tm_isdst
|
|| newtm.tm_isdst != tm.tm_isdst
|
||||||
|| strcmp(abbr(&newtm), ab) != 0))) {
|
|| 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);
|
newtmp = localtime_rz(tz, &newt, &newtm);
|
||||||
newtm_ok = newtmp != NULL;
|
newtm_ok = newtmp != NULL;
|
||||||
if (iflag)
|
if (iflag)
|
||||||
@ -687,7 +707,7 @@ yeartot(intmax_t y)
|
|||||||
return t;
|
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
|
timestamps ranging from LOT through HIT. LOT and HIT disagree
|
||||||
about some aspect of timezone. If ONLY_OK, search only for
|
about some aspect of timezone. If ONLY_OK, search only for
|
||||||
definedness changes, i.e., localtime succeeds on one side of the
|
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. */
|
before the transition from LOT's settings. */
|
||||||
|
|
||||||
static time_t
|
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 char * loab;
|
||||||
static size_t loabsize;
|
static ptrdiff_t loabsize;
|
||||||
struct tm lotm;
|
struct tm lotm;
|
||||||
struct tm tm;
|
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
|
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. */
|
possibly nonnull result of an earlier call to my_gmtime_r. */
|
||||||
static long
|
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
|
#ifdef TM_GMTOFF
|
||||||
return a->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)
|
showextrema(timezone_t tz, char *zone, time_t lo, struct tm *lotmp, time_t hi)
|
||||||
{
|
{
|
||||||
struct tm localtm[2], gmtm[2];
|
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;
|
bool old = false;
|
||||||
hi = (SECSPERDAY < hi - boundary
|
hi = (SECSPERDAY < hi - boundary
|
||||||
? boundary + SECSPERDAY
|
? 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, return the length that the string would have been if it had
|
||||||
fit; do not overrun the output buffer. */
|
fit; do not overrun the output buffer. */
|
||||||
static int
|
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;
|
int ss = tm->tm_sec, mm = tm->tm_min, hh = tm->tm_hour;
|
||||||
return (ss
|
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
|
the length that the string would have been if it had fit; do not
|
||||||
overrun the output buffer. */
|
overrun the output buffer. */
|
||||||
static int
|
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);
|
long off = gmtoff(tm, &t, NULL);
|
||||||
char sign = ((off < 0
|
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
|
If the representation's length is less than SIZE, return the
|
||||||
length; the representation is not null terminated. Otherwise
|
length; the representation is not null terminated. Otherwise
|
||||||
return SIZE, to indicate that BUF is too small. */
|
return SIZE, to indicate that BUF is too small. */
|
||||||
static size_t
|
static ptrdiff_t
|
||||||
format_quoted_string(char *buf, size_t size, char const *p)
|
format_quoted_string(char *buf, ptrdiff_t size, char const *p)
|
||||||
{
|
{
|
||||||
char *b = buf;
|
char *b = buf;
|
||||||
size_t s = size;
|
ptrdiff_t s = size;
|
||||||
if (!s)
|
if (!s)
|
||||||
return size;
|
return size;
|
||||||
*b++ = '"', s--;
|
*b++ = '"', s--;
|
||||||
@ -1031,11 +1052,11 @@ format_quoted_string(char *buf, size_t size, char const *p)
|
|||||||
and omit any trailing tabs. */
|
and omit any trailing tabs. */
|
||||||
|
|
||||||
static bool
|
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)
|
struct tm const *tm, time_t t, char const *ab, char const *zone_name)
|
||||||
{
|
{
|
||||||
char *b = buf;
|
char *b = buf;
|
||||||
size_t s = size;
|
ptrdiff_t s = size;
|
||||||
char const *f = time_fmt, *p;
|
char const *f = time_fmt, *p;
|
||||||
|
|
||||||
for (p = f; ; p++)
|
for (p = f; ; p++)
|
||||||
@ -1044,9 +1065,9 @@ istrftime(char *buf, size_t size, char const *time_fmt,
|
|||||||
else if (!*p
|
else if (!*p
|
||||||
|| (*p == '%'
|
|| (*p == '%'
|
||||||
&& (p[1] == 'f' || p[1] == 'L' || p[1] == 'Q'))) {
|
&& (p[1] == 'f' || p[1] == 'L' || p[1] == 'Q'))) {
|
||||||
size_t formatted_len;
|
ptrdiff_t formatted_len;
|
||||||
size_t f_prefix_len = p - f;
|
ptrdiff_t f_prefix_len = p - f;
|
||||||
size_t f_prefix_copy_size = p - f + 2;
|
ptrdiff_t f_prefix_copy_size = sumsize(f_prefix_len, 2);
|
||||||
char fbuf[100];
|
char fbuf[100];
|
||||||
bool oversized = sizeof fbuf <= f_prefix_copy_size;
|
bool oversized = sizeof fbuf <= f_prefix_copy_size;
|
||||||
char *f_prefix_copy = oversized ? xmalloc(f_prefix_copy_size) : fbuf;
|
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;
|
b += offlen, s -= offlen;
|
||||||
if (show_abbr) {
|
if (show_abbr) {
|
||||||
char const *abp;
|
char const *abp;
|
||||||
size_t len;
|
ptrdiff_t len;
|
||||||
if (s <= 1)
|
if (s <= 1)
|
||||||
return false;
|
return false;
|
||||||
*b++ = '\t', s--;
|
*b++ = '\t', s--;
|
||||||
@ -1117,7 +1138,7 @@ showtrans(char const *time_fmt, struct tm const *tm, time_t t, char const *ab,
|
|||||||
putchar('\n');
|
putchar('\n');
|
||||||
} else {
|
} else {
|
||||||
char stackbuf[1000];
|
char stackbuf[1000];
|
||||||
size_t size = sizeof stackbuf;
|
ptrdiff_t size = sizeof stackbuf;
|
||||||
char *buf = stackbuf;
|
char *buf = stackbuf;
|
||||||
char *bufalloc = NULL;
|
char *bufalloc = NULL;
|
||||||
while (! istrftime(buf, size, time_fmt, tm, t, ab, zone_name)) {
|
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
|
.SH NAME
|
||||||
zic \- timezone compiler
|
zic \- timezone compiler
|
||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
@ -22,7 +24,7 @@ zic \- timezone compiler
|
|||||||
.el .ds > \(ra
|
.el .ds > \(ra
|
||||||
.ie \n(.g \{\
|
.ie \n(.g \{\
|
||||||
. ds : \:
|
. ds : \:
|
||||||
. ds - \f(CW-\fP
|
. ds - \f(CR-\fP
|
||||||
.\}
|
.\}
|
||||||
.el \{\
|
.el \{\
|
||||||
. ds :
|
. ds :
|
||||||
@ -347,7 +349,9 @@ nor
|
|||||||
.q + .
|
.q + .
|
||||||
To allow for future extensions,
|
To allow for future extensions,
|
||||||
an unquoted name should not contain characters from the set
|
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
|
.TP
|
||||||
.B FROM
|
.B FROM
|
||||||
Gives the first year in which the rule applies.
|
Gives the first year in which the rule applies.
|
||||||
@ -894,5 +898,3 @@ specifying transition instants using universal time.
|
|||||||
.SH SEE ALSO
|
.SH SEE ALSO
|
||||||
.BR tzfile (5),
|
.BR tzfile (5),
|
||||||
.BR zdump (8)
|
.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
|
NAME
|
||||||
zic - timezone compiler
|
zic - timezone compiler
|
||||||
@ -513,4 +513,4 @@ NOTES
|
|||||||
SEE ALSO
|
SEE ALSO
|
||||||
tzfile(5), zdump(8)
|
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
|
# define ZIC_MAX_ABBR_LEN_WO_WARN 6
|
||||||
#endif /* !defined ZIC_MAX_ABBR_LEN_WO_WARN */
|
#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
|
#ifdef HAVE_DIRECT_H
|
||||||
# include <direct.h>
|
# include <direct.h>
|
||||||
# include <io.h>
|
# include <io.h>
|
||||||
@ -41,7 +44,16 @@ static zic_t const
|
|||||||
# define mkdir(name, mode) _mkdir(name)
|
# define mkdir(name, mode) _mkdir(name)
|
||||||
#endif
|
#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>
|
# include <sys/random.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -54,11 +66,6 @@ static zic_t const
|
|||||||
# define MKDIR_UMASK 0755
|
# define MKDIR_UMASK 0755
|
||||||
#endif
|
#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. */
|
/* The minimum alignment of a type, for pre-C23 platforms. */
|
||||||
#if __STDC_VERSION__ < 201112
|
#if __STDC_VERSION__ < 201112
|
||||||
# define alignof(type) offsetof(struct { char a; type b; }, b)
|
# define alignof(type) offsetof(struct { char a; type b; }, b)
|
||||||
@ -452,29 +459,54 @@ static char roll[TZ_MAX_LEAPS];
|
|||||||
** Memory allocation.
|
** Memory allocation.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static _Noreturn void
|
static ATTRIBUTE_NORETURN void
|
||||||
memory_exhausted(const char *msg)
|
memory_exhausted(const char *msg)
|
||||||
{
|
{
|
||||||
fprintf(stderr, _("%s: Memory exhausted: %s\n"), progname, msg);
|
fprintf(stderr, _("%s: Memory exhausted: %s\n"), progname, msg);
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ATTRIBUTE_PURE size_t
|
static ATTRIBUTE_NORETURN void
|
||||||
size_product(size_t nitems, size_t itemsize)
|
size_overflow(void)
|
||||||
{
|
{
|
||||||
if (SIZE_MAX / itemsize < nitems)
|
memory_exhausted(_("size overflow"));
|
||||||
memory_exhausted(_("size overflow"));
|
|
||||||
return nitems * itemsize;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static ATTRIBUTE_PURE size_t
|
static ATTRIBUTE_REPRODUCIBLE ptrdiff_t
|
||||||
align_to(size_t size, size_t alignment)
|
size_sum(size_t a, size_t b)
|
||||||
{
|
{
|
||||||
size_t aligned_size = size + alignment - 1;
|
#ifdef ckd_add
|
||||||
aligned_size -= aligned_size % alignment;
|
ptrdiff_t sum;
|
||||||
if (aligned_size < size)
|
if (!ckd_add(&sum, a, b) && sum <= SIZE_MAX)
|
||||||
memory_exhausted(_("alignment overflow"));
|
return sum;
|
||||||
return aligned_size;
|
#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
|
#if !HAVE_STRDUP
|
||||||
@ -507,23 +539,37 @@ erealloc(void *ptr, size_t size)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static char * ATTRIBUTE_MALLOC
|
static char * ATTRIBUTE_MALLOC
|
||||||
ecpyalloc(char const *str)
|
estrdup(char const *str)
|
||||||
{
|
{
|
||||||
return memcheck(strdup(str));
|
return memcheck(strdup(str));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *
|
static ptrdiff_t
|
||||||
growalloc(void *ptr, size_t itemsize, ptrdiff_t nitems, ptrdiff_t *nitems_alloc)
|
grow_nitems_alloc(ptrdiff_t *nitems_alloc, ptrdiff_t itemsize)
|
||||||
{
|
{
|
||||||
if (nitems < *nitems_alloc)
|
ptrdiff_t addend = (*nitems_alloc >> 1) + 1;
|
||||||
return ptr;
|
#if defined ckd_add && defined ckd_mul
|
||||||
else {
|
ptrdiff_t product;
|
||||||
ptrdiff_t amax = min(PTRDIFF_MAX, SIZE_MAX);
|
if (!ckd_add(nitems_alloc, *nitems_alloc, addend)
|
||||||
if ((amax - 1) / 3 * 2 < *nitems_alloc)
|
&& !ckd_mul(&product, *nitems_alloc, itemsize) && product <= SIZE_MAX)
|
||||||
memory_exhausted(_("integer overflow"));
|
return product;
|
||||||
*nitems_alloc += (*nitems_alloc >> 1) + 1;
|
#else
|
||||||
return erealloc(ptr, size_product(*nitems_alloc, itemsize));
|
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)
|
usage(FILE *stream, int status)
|
||||||
{
|
{
|
||||||
fprintf(stream,
|
fprintf(stream,
|
||||||
@ -943,7 +989,7 @@ main(int argc, char **argv)
|
|||||||
textdomain(TZ_DOMAIN);
|
textdomain(TZ_DOMAIN);
|
||||||
#endif /* HAVE_GETTEXT */
|
#endif /* HAVE_GETTEXT */
|
||||||
main_argv = argv;
|
main_argv = argv;
|
||||||
progname = argv[0];
|
progname = argv[0] ? argv[0] : "zic";
|
||||||
if (TYPE_BIT(zic_t) < 64) {
|
if (TYPE_BIT(zic_t) < 64) {
|
||||||
fprintf(stderr, "%s: %s\n", progname,
|
fprintf(stderr, "%s: %s\n", progname,
|
||||||
_("wild compilation-time specification of zic_t"));
|
_("wild compilation-time specification of zic_t"));
|
||||||
@ -1201,21 +1247,12 @@ get_rand_u64(void)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* getrandom didn't work, so fall back on portable code that is
|
/* getrandom didn't work, so fall back on portable code that is
|
||||||
not the best because the seed doesn't necessarily have enough bits,
|
not the best because the seed isn't cryptographically random and
|
||||||
the seed isn't cryptographically random on platforms lacking
|
'rand' might not be cryptographically secure. */
|
||||||
getrandom, and 'rand' might not be cryptographically secure. */
|
|
||||||
{
|
{
|
||||||
static bool initialized;
|
static bool initialized;
|
||||||
if (!initialized) {
|
if (!initialized) {
|
||||||
unsigned seed;
|
srand(time(NULL));
|
||||||
#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);
|
|
||||||
initialized = true;
|
initialized = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1224,13 +1261,21 @@ get_rand_u64(void)
|
|||||||
the typical case where RAND_MAX is one less than a power of two.
|
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. */
|
In other cases this code yields a sort-of-random number. */
|
||||||
{
|
{
|
||||||
uint_fast64_t
|
uint_fast64_t rand_max = RAND_MAX,
|
||||||
rand_max = RAND_MAX,
|
nrand = rand_max < UINT_FAST64_MAX ? rand_max + 1 : 0,
|
||||||
multiplier = rand_max + 1, /* It's OK if this overflows to 0. */
|
rmod = INT_MAX < UINT_FAST64_MAX ? 0 : UINT_FAST64_MAX / nrand + 1,
|
||||||
r = 0, rmax = 0;
|
r = 0, rmax = 0;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
uint_fast64_t rmax1 = rmax * multiplier + rand_max;
|
uint_fast64_t rmax1 = rmax;
|
||||||
r = r * multiplier + rand();
|
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;
|
rmax = rmax < rmax1 ? rmax1 : UINT_FAST64_MAX;
|
||||||
} while (rmax < 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);
|
uint_fast64_t unfair_min = - ((UINTMAX_MAX % base__6 + 1) % base__6);
|
||||||
|
|
||||||
if (!dst) {
|
if (!dst) {
|
||||||
dst = emalloc(dirlen + prefixlen + suffixlen + 1);
|
dst = emalloc(size_sum(dirlen, prefixlen + suffixlen + 1));
|
||||||
memcpy(dst, src, dirlen);
|
memcpy(dst, src, dirlen);
|
||||||
memcpy(dst + dirlen, prefix, prefixlen);
|
memcpy(dst + dirlen, prefix, prefixlen);
|
||||||
dst[dirlen + prefixlen + suffixlen] = '\0';
|
dst[dirlen + prefixlen + suffixlen] = '\0';
|
||||||
@ -1351,19 +1396,20 @@ rename_dest(char *tempname, char const *name)
|
|||||||
static char *
|
static char *
|
||||||
relname(char const *target, char const *linkname)
|
relname(char const *target, char const *linkname)
|
||||||
{
|
{
|
||||||
size_t i, taillen, dotdotetcsize;
|
size_t i, taillen, dir_len = 0, dotdots = 0;
|
||||||
size_t dir_len = 0, dotdots = 0, linksize = SIZE_MAX;
|
ptrdiff_t dotdotetcsize, linksize = min(PTRDIFF_MAX, SIZE_MAX);
|
||||||
char const *f = target;
|
char const *f = target;
|
||||||
char *result = NULL;
|
char *result = NULL;
|
||||||
if (*linkname == '/') {
|
if (*linkname == '/') {
|
||||||
/* Make F absolute too. */
|
/* Make F absolute too. */
|
||||||
size_t len = strlen(directory);
|
size_t len = strlen(directory);
|
||||||
bool needslash = len && directory[len - 1] != '/';
|
size_t lenslash = len + (len && directory[len - 1] != '/');
|
||||||
linksize = len + needslash + strlen(target) + 1;
|
size_t targetsize = strlen(target) + 1;
|
||||||
|
linksize = size_sum(lenslash, targetsize);
|
||||||
f = result = emalloc(linksize);
|
f = result = emalloc(linksize);
|
||||||
strcpy(result, directory);
|
memcpy(result, directory, len);
|
||||||
result[len] = '/';
|
result[len] = '/';
|
||||||
strcpy(result + len + needslash, target);
|
memcpy(result + lenslash, target, targetsize);
|
||||||
}
|
}
|
||||||
for (i = 0; f[i] && f[i] == linkname[i]; i++)
|
for (i = 0; f[i] && f[i] == linkname[i]; i++)
|
||||||
if (f[i] == '/')
|
if (f[i] == '/')
|
||||||
@ -1371,7 +1417,7 @@ relname(char const *target, char const *linkname)
|
|||||||
for (; linkname[i]; i++)
|
for (; linkname[i]; i++)
|
||||||
dotdots += linkname[i] == '/' && linkname[i - 1] != '/';
|
dotdots += linkname[i] == '/' && linkname[i - 1] != '/';
|
||||||
taillen = strlen(f + dir_len);
|
taillen = strlen(f + dir_len);
|
||||||
dotdotetcsize = 3 * dotdots + taillen + 1;
|
dotdotetcsize = size_sum(size_product(dotdots, 3), taillen + 1);
|
||||||
if (dotdotetcsize <= linksize) {
|
if (dotdotetcsize <= linksize) {
|
||||||
if (!result)
|
if (!result)
|
||||||
result = emalloc(dotdotetcsize);
|
result = emalloc(dotdotetcsize);
|
||||||
@ -1575,10 +1621,9 @@ associate(void)
|
|||||||
|
|
||||||
/* Read a text line from FP into BUF, which is of size BUFSIZE.
|
/* Read a text line from FP into BUF, which is of size BUFSIZE.
|
||||||
Terminate it with a NUL byte instead of a newline.
|
Terminate it with a NUL byte instead of a newline.
|
||||||
Return the line's length, not counting the NUL byte.
|
Return true if successful, false if EOF.
|
||||||
On EOF, return a negative number.
|
|
||||||
On error, report the error and exit. */
|
On error, report the error and exit. */
|
||||||
static ptrdiff_t
|
static bool
|
||||||
inputline(FILE *fp, char *buf, ptrdiff_t bufsize)
|
inputline(FILE *fp, char *buf, ptrdiff_t bufsize)
|
||||||
{
|
{
|
||||||
ptrdiff_t linelen = 0, ch;
|
ptrdiff_t linelen = 0, ch;
|
||||||
@ -1589,7 +1634,7 @@ inputline(FILE *fp, char *buf, ptrdiff_t bufsize)
|
|||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
if (linelen == 0)
|
if (linelen == 0)
|
||||||
return -1;
|
return false;
|
||||||
error(_("unterminated line"));
|
error(_("unterminated line"));
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
@ -1604,7 +1649,7 @@ inputline(FILE *fp, char *buf, ptrdiff_t bufsize)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
buf[linelen] = '\0';
|
buf[linelen] = '\0';
|
||||||
return linelen;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -1626,13 +1671,14 @@ infile(int fnum, char const *name)
|
|||||||
}
|
}
|
||||||
wantcont = false;
|
wantcont = false;
|
||||||
for (num = 1; ; ++num) {
|
for (num = 1; ; ++num) {
|
||||||
ptrdiff_t linelen;
|
enum { bufsize_bound
|
||||||
char buf[_POSIX2_LINE_MAX];
|
= (min(INT_MAX, min(PTRDIFF_MAX, SIZE_MAX))
|
||||||
|
/ FORMAT_LEN_GROWTH_BOUND) };
|
||||||
|
char buf[min(_POSIX2_LINE_MAX, bufsize_bound)];
|
||||||
int nfields;
|
int nfields;
|
||||||
char *fields[MAX_FIELDS];
|
char *fields[MAX_FIELDS];
|
||||||
eat(fnum, num);
|
eat(fnum, num);
|
||||||
linelen = inputline(fp, buf, sizeof buf);
|
if (!inputline(fp, buf, sizeof buf))
|
||||||
if (linelen < 0)
|
|
||||||
break;
|
break;
|
||||||
nfields = getfields(buf, fields,
|
nfields = getfields(buf, fields,
|
||||||
sizeof fields / sizeof *fields);
|
sizeof fields / sizeof *fields);
|
||||||
@ -1704,15 +1750,15 @@ gethms(char const *string, char const *errstring)
|
|||||||
default: ok = false; break;
|
default: ok = false; break;
|
||||||
case 8:
|
case 8:
|
||||||
ok = '0' <= xr && xr <= '9';
|
ok = '0' <= xr && xr <= '9';
|
||||||
/* fallthrough */
|
ATTRIBUTE_FALLTHROUGH;
|
||||||
case 7:
|
case 7:
|
||||||
ok &= ssx == '.';
|
ok &= ssx == '.';
|
||||||
if (ok && noise)
|
if (ok && noise)
|
||||||
warning(_("fractional seconds rejected by"
|
warning(_("fractional seconds rejected by"
|
||||||
" pre-2018 versions of zic"));
|
" pre-2018 versions of zic"));
|
||||||
/* fallthrough */
|
ATTRIBUTE_FALLTHROUGH;
|
||||||
case 5: ok &= mmx == ':'; /* fallthrough */
|
case 5: ok &= mmx == ':'; ATTRIBUTE_FALLTHROUGH;
|
||||||
case 3: ok &= hhx == ':'; /* fallthrough */
|
case 3: ok &= hhx == ':'; ATTRIBUTE_FALLTHROUGH;
|
||||||
case 1: break;
|
case 1: break;
|
||||||
}
|
}
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
@ -1742,7 +1788,7 @@ getsave(char *field, bool *isdst)
|
|||||||
{
|
{
|
||||||
int dst = -1;
|
int dst = -1;
|
||||||
zic_t save;
|
zic_t save;
|
||||||
size_t fieldlen = strlen(field);
|
ptrdiff_t fieldlen = strlen(field);
|
||||||
if (fieldlen != 0) {
|
if (fieldlen != 0) {
|
||||||
char *ep = field + fieldlen - 1;
|
char *ep = field + fieldlen - 1;
|
||||||
switch (*ep) {
|
switch (*ep) {
|
||||||
@ -1780,8 +1826,8 @@ inrule(char **fields, int nfields)
|
|||||||
fields[RF_COMMAND], fields[RF_MONTH], fields[RF_DAY],
|
fields[RF_COMMAND], fields[RF_MONTH], fields[RF_DAY],
|
||||||
fields[RF_TOD]))
|
fields[RF_TOD]))
|
||||||
return;
|
return;
|
||||||
r.r_name = ecpyalloc(fields[RF_NAME]);
|
r.r_name = estrdup(fields[RF_NAME]);
|
||||||
r.r_abbrvar = ecpyalloc(fields[RF_ABBRVAR]);
|
r.r_abbrvar = estrdup(fields[RF_ABBRVAR]);
|
||||||
if (max_abbrvar_len < strlen(r.r_abbrvar))
|
if (max_abbrvar_len < strlen(r.r_abbrvar))
|
||||||
max_abbrvar_len = strlen(r.r_abbrvar);
|
max_abbrvar_len = strlen(r.r_abbrvar);
|
||||||
rules = growalloc(rules, sizeof *rules, nrules, &nrules_alloc);
|
rules = growalloc(rules, sizeof *rules, nrules, &nrules_alloc);
|
||||||
@ -1838,7 +1884,7 @@ inzsub(char **fields, int nfields, bool iscont)
|
|||||||
register char * cp;
|
register char * cp;
|
||||||
char * cp1;
|
char * cp1;
|
||||||
struct zone z;
|
struct zone z;
|
||||||
size_t format_len;
|
int format_len;
|
||||||
register int i_stdoff, i_rule, i_format;
|
register int i_stdoff, i_rule, i_format;
|
||||||
register int i_untilyear, i_untilmonth;
|
register int i_untilyear, i_untilmonth;
|
||||||
register int i_untilday, i_untiltime;
|
register int i_untilday, i_untiltime;
|
||||||
@ -1905,9 +1951,9 @@ inzsub(char **fields, int nfields, bool iscont)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
z.z_name = iscont ? NULL : ecpyalloc(fields[ZF_NAME]);
|
z.z_name = iscont ? NULL : estrdup(fields[ZF_NAME]);
|
||||||
z.z_rule = ecpyalloc(fields[i_rule]);
|
z.z_rule = estrdup(fields[i_rule]);
|
||||||
z.z_format = cp1 = ecpyalloc(fields[i_format]);
|
z.z_format = cp1 = estrdup(fields[i_format]);
|
||||||
if (z.z_format_specifier == 'z') {
|
if (z.z_format_specifier == 'z') {
|
||||||
cp1[cp - fields[i_format]] = 's';
|
cp1[cp - fields[i_format]] = 's';
|
||||||
if (noise)
|
if (noise)
|
||||||
@ -1924,7 +1970,7 @@ inzsub(char **fields, int nfields, bool iscont)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static zic_t
|
static zic_t
|
||||||
getleapdatetime(char **fields, int nfields, bool expire_line)
|
getleapdatetime(char **fields, bool expire_line)
|
||||||
{
|
{
|
||||||
register const char * cp;
|
register const char * cp;
|
||||||
register const struct lookup * lp;
|
register const struct lookup * lp;
|
||||||
@ -2002,7 +2048,7 @@ inleap(char **fields, int nfields)
|
|||||||
if (nfields != LEAP_FIELDS)
|
if (nfields != LEAP_FIELDS)
|
||||||
error(_("wrong number of fields on Leap line"));
|
error(_("wrong number of fields on Leap line"));
|
||||||
else {
|
else {
|
||||||
zic_t t = getleapdatetime(fields, nfields, false);
|
zic_t t = getleapdatetime(fields, false);
|
||||||
if (0 <= t) {
|
if (0 <= t) {
|
||||||
struct lookup const *lp = byword(fields[LP_ROLL], leap_types);
|
struct lookup const *lp = byword(fields[LP_ROLL], leap_types);
|
||||||
if (!lp)
|
if (!lp)
|
||||||
@ -2030,7 +2076,7 @@ inexpires(char **fields, int nfields)
|
|||||||
else if (0 <= leapexpires)
|
else if (0 <= leapexpires)
|
||||||
error(_("multiple Expires lines"));
|
error(_("multiple Expires lines"));
|
||||||
else
|
else
|
||||||
leapexpires = getleapdatetime(fields, nfields, true);
|
leapexpires = getleapdatetime(fields, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -2050,8 +2096,8 @@ inlink(char **fields, int nfields)
|
|||||||
return;
|
return;
|
||||||
l.l_filenum = filenum;
|
l.l_filenum = filenum;
|
||||||
l.l_linenum = linenum;
|
l.l_linenum = linenum;
|
||||||
l.l_target = ecpyalloc(fields[LF_TARGET]);
|
l.l_target = estrdup(fields[LF_TARGET]);
|
||||||
l.l_linkname = ecpyalloc(fields[LF_LINKNAME]);
|
l.l_linkname = estrdup(fields[LF_LINKNAME]);
|
||||||
links = growalloc(links, sizeof *links, nlinks, &nlinks_alloc);
|
links = growalloc(links, sizeof *links, nlinks, &nlinks_alloc);
|
||||||
links[nlinks++] = l;
|
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_month = lp->l_value;
|
||||||
rp->r_todisstd = false;
|
rp->r_todisstd = false;
|
||||||
rp->r_todisut = false;
|
rp->r_todisut = false;
|
||||||
dp = ecpyalloc(timep);
|
dp = estrdup(timep);
|
||||||
if (*dp != '\0') {
|
if (*dp != '\0') {
|
||||||
ep = dp + strlen(dp) - 1;
|
ep = dp + strlen(dp) - 1;
|
||||||
switch (lowerit(*ep)) {
|
switch (lowerit(*ep)) {
|
||||||
@ -2153,7 +2199,7 @@ rulesub(struct rule *rp, const char *loyearp, const char *hiyearp,
|
|||||||
** Sun<=20
|
** Sun<=20
|
||||||
** Sun>=7
|
** Sun>=7
|
||||||
*/
|
*/
|
||||||
dp = ecpyalloc(dayp);
|
dp = estrdup(dayp);
|
||||||
if ((lp = byword(dp, lasts)) != NULL) {
|
if ((lp = byword(dp, lasts)) != NULL) {
|
||||||
rp->r_dycode = DC_DOWLEQ;
|
rp->r_dycode = DC_DOWLEQ;
|
||||||
rp->r_wday = lp->l_value;
|
rp->r_wday = lp->l_value;
|
||||||
@ -2216,7 +2262,7 @@ convert64(uint_fast64_t val, char *buf)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
puttzcode(const int_fast32_t val, FILE *const fp)
|
puttzcode(zic_t val, FILE *fp)
|
||||||
{
|
{
|
||||||
char buf[4];
|
char buf[4];
|
||||||
|
|
||||||
@ -2305,8 +2351,10 @@ writezone(const char *const name, const char *const string, char version,
|
|||||||
char const *outname = name;
|
char const *outname = name;
|
||||||
|
|
||||||
/* Allocate the ATS and TYPES arrays via a single malloc,
|
/* Allocate the ATS and TYPES arrays via a single malloc,
|
||||||
as this is a bit faster. */
|
as this is a bit faster. Do not malloc(0) if !timecnt,
|
||||||
zic_t *ats = emalloc(align_to(size_product(timecnt, sizeof *ats + 1),
|
as that might return NULL even on success. */
|
||||||
|
zic_t *ats = emalloc(align_to(size_product(timecnt + !timecnt,
|
||||||
|
sizeof *ats + 1),
|
||||||
alignof(zic_t)));
|
alignof(zic_t)));
|
||||||
void *typesptr = ats + timecnt;
|
void *typesptr = ats + timecnt;
|
||||||
unsigned char *types = typesptr;
|
unsigned char *types = typesptr;
|
||||||
@ -2739,13 +2787,13 @@ abbroffset(char *buf, zic_t offset)
|
|||||||
|
|
||||||
static char const disable_percent_s[] = "";
|
static char const disable_percent_s[] = "";
|
||||||
|
|
||||||
static size_t
|
static ptrdiff_t
|
||||||
doabbr(char *abbr, struct zone const *zp, char const *letters,
|
doabbr(char *abbr, struct zone const *zp, char const *letters,
|
||||||
bool isdst, zic_t save, bool doquotes)
|
bool isdst, zic_t save, bool doquotes)
|
||||||
{
|
{
|
||||||
register char * cp;
|
register char * cp;
|
||||||
register char * slashp;
|
register char * slashp;
|
||||||
register size_t len;
|
ptrdiff_t len;
|
||||||
char const *format = zp->z_format;
|
char const *format = zp->z_format;
|
||||||
|
|
||||||
slashp = strchr(format, '/');
|
slashp = strchr(format, '/');
|
||||||
@ -2911,9 +2959,9 @@ stringzone(char *result, struct zone const *zpfirst, ptrdiff_t zonecount)
|
|||||||
register ptrdiff_t i;
|
register ptrdiff_t i;
|
||||||
register int compat = 0;
|
register int compat = 0;
|
||||||
register int c;
|
register int c;
|
||||||
size_t len;
|
|
||||||
int offsetlen;
|
int offsetlen;
|
||||||
struct rule stdr, dstr;
|
struct rule stdr, dstr;
|
||||||
|
ptrdiff_t len;
|
||||||
int dstcmp;
|
int dstcmp;
|
||||||
struct rule *lastrp[2] = { NULL, NULL };
|
struct rule *lastrp[2] = { NULL, NULL };
|
||||||
struct zone zstr[2];
|
struct zone zstr[2];
|
||||||
@ -3046,8 +3094,10 @@ outzone(const struct zone *zpfirst, ptrdiff_t zonecount)
|
|||||||
|
|
||||||
check_for_signal();
|
check_for_signal();
|
||||||
|
|
||||||
|
/* This cannot overflow; see FORMAT_LEN_GROWTH_BOUND. */
|
||||||
max_abbr_len = 2 + max_format_len + max_abbrvar_len;
|
max_abbr_len = 2 + max_format_len + max_abbrvar_len;
|
||||||
max_envvar_len = 2 * max_abbr_len + 5 * 9;
|
max_envvar_len = 2 * max_abbr_len + 5 * 9;
|
||||||
|
|
||||||
startbuf = emalloc(max_abbr_len + 1);
|
startbuf = emalloc(max_abbr_len + 1);
|
||||||
ab = emalloc(max_abbr_len + 1);
|
ab = emalloc(max_abbr_len + 1);
|
||||||
envvar = emalloc(max_envvar_len + 1);
|
envvar = emalloc(max_envvar_len + 1);
|
||||||
@ -3547,7 +3597,7 @@ lowerit(char a)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* case-insensitive equality */
|
/* case-insensitive equality */
|
||||||
static ATTRIBUTE_PURE bool
|
static ATTRIBUTE_REPRODUCIBLE bool
|
||||||
ciequal(register const char *ap, register const char *bp)
|
ciequal(register const char *ap, register const char *bp)
|
||||||
{
|
{
|
||||||
while (lowerit(*ap) == lowerit(*bp++))
|
while (lowerit(*ap) == lowerit(*bp++))
|
||||||
@ -3556,7 +3606,7 @@ ciequal(register const char *ap, register const char *bp)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ATTRIBUTE_PURE bool
|
static ATTRIBUTE_REPRODUCIBLE bool
|
||||||
itsabbr(register const char *abbr, register const char *word)
|
itsabbr(register const char *abbr, register const char *word)
|
||||||
{
|
{
|
||||||
if (lowerit(*abbr) != lowerit(*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. */
|
/* 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)
|
ciprefix(char const *abbr, char const *word)
|
||||||
{
|
{
|
||||||
do
|
do
|
||||||
@ -3675,38 +3725,41 @@ getfields(char *cp, char **array, int arrayelts)
|
|||||||
return nsubs;
|
return nsubs;
|
||||||
}
|
}
|
||||||
|
|
||||||
static _Noreturn void
|
static ATTRIBUTE_NORETURN void
|
||||||
time_overflow(void)
|
time_overflow(void)
|
||||||
{
|
{
|
||||||
error(_("time overflow"));
|
error(_("time overflow"));
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ATTRIBUTE_PURE zic_t
|
static ATTRIBUTE_REPRODUCIBLE zic_t
|
||||||
oadd(zic_t t1, zic_t t2)
|
oadd(zic_t t1, zic_t t2)
|
||||||
{
|
{
|
||||||
if (t1 < 0 ? t2 < ZIC_MIN - t1 : ZIC_MAX - t1 < t2)
|
#ifdef ckd_add
|
||||||
time_overflow();
|
zic_t sum;
|
||||||
return t1 + t2;
|
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)
|
tadd(zic_t t1, zic_t t2)
|
||||||
{
|
{
|
||||||
if (t1 < 0) {
|
#ifdef ckd_add
|
||||||
if (t2 < min_time - t1) {
|
zic_t sum;
|
||||||
if (t1 != min_time)
|
if (!ckd_add(&sum, t1, t2) && min_time <= sum && sum <= max_time)
|
||||||
time_overflow();
|
return sum;
|
||||||
return min_time;
|
#else
|
||||||
}
|
if (t1 < 0 ? min_time - t1 <= t2 : t2 <= max_time - t1)
|
||||||
} else {
|
return t1 + t2;
|
||||||
if (max_time - t1 < t2) {
|
#endif
|
||||||
if (t1 != max_time)
|
if (t1 == min_time || t1 == max_time)
|
||||||
time_overflow();
|
return t1;
|
||||||
return max_time;
|
time_overflow();
|
||||||
}
|
|
||||||
}
|
|
||||||
return t1 + t2;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -3830,10 +3883,8 @@ mp = _("time zone abbreviation differs from POSIX standard");
|
|||||||
static void
|
static void
|
||||||
mkdirs(char const *argname, bool ancestors)
|
mkdirs(char const *argname, bool ancestors)
|
||||||
{
|
{
|
||||||
register char * name;
|
char *name = estrdup(argname);
|
||||||
register char * cp;
|
char *cp = name;
|
||||||
|
|
||||||
cp = name = ecpyalloc(argname);
|
|
||||||
|
|
||||||
/* On MS-Windows systems, do not worry about drive letters or
|
/* On MS-Windows systems, do not worry about drive letters or
|
||||||
backslashes, as this should suffice in practice. Time zone
|
backslashes, as this should suffice in practice. Time zone
|
||||||
|
Loading…
Reference in New Issue
Block a user