Import tzcode 2022f

This commit is contained in:
Dag-Erling Smørgrav 2022-12-14 01:43:10 +01:00
parent 5644220527
commit cc16bfc34e
10 changed files with 603 additions and 232 deletions

View File

@ -210,7 +210,8 @@ LDLIBS=
# -DHAVE_DECL_ENVIRON if <unistd.h> declares 'environ'
# -DHAVE_DIRECT_H if mkdir needs <direct.h> (MS-Windows)
# -DHAVE_GENERIC=0 if _Generic does not work
# -DHAVE_GETTEXT if 'gettext' works (e.g., GNU/Linux, FreeBSD, Solaris)
# -DHAVE_GETRANDOM if getgrandom works (e.g., GNU/Linux)*
# -DHAVE_GETTEXT if 'gettext' works (e.g., GNU/Linux, FreeBSD, Solaris)*
# -DHAVE_INCOMPATIBLE_CTIME_R if your system's time.h declares
# ctime_r and asctime_r incompatibly with the POSIX standard
# (Solaris when _POSIX_PTHREAD_SEMANTICS is not defined).
@ -222,16 +223,17 @@ LDLIBS=
# -DHAVE_MALLOC_ERRNO=0 if malloc etc. do not set errno on failure.
# -DHAVE_POSIX_DECLS=0 if your system's include files do not declare
# functions like 'link' or variables like 'tzname' required by POSIX
# -DHAVE_SETENV=0 if your system lacks the setenv function
# -DHAVE_SNPRINTF=0 if your system lacks the snprintf function
# -DHAVE_STDBOOL_H if you have a non-C99 compiler with <stdbool.h>
# -DHAVE_STDINT_H if you have a non-C99 compiler with <stdint.h>
# -DHAVE_STDINT_H if you have a non-C99 compiler with <stdint.h>*
# -DHAVE_STRFTIME_L if <time.h> declares locale_t and strftime_l
# -DHAVE_STRDUP=0 if your system lacks the strdup function
# -DHAVE_STRTOLL=0 if your system lacks the strtoll function
# -DHAVE_SYMLINK=0 if your system lacks the symlink function
# -DHAVE_SYS_STAT_H=0 if your compiler lacks a <sys/stat.h>
# -DHAVE_SYS_STAT_H=0 if your compiler lacks a <sys/stat.h>*
# -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 your compiler lacks a <unistd.h>*
# -DHAVE_UTMPX_H=0 if your compiler lacks a <utmpx.h>*
# -Dlocale_t=XXX if your system uses XXX instead of locale_t
# -DRESERVE_STD_EXT_IDS if your platform reserves standard identifiers
# with external linkage, e.g., applications cannot define 'localtime'.
@ -254,14 +256,17 @@ LDLIBS=
# Also set TZDOBJS=zdump.o and CHECK_TIME_T_ALTERNATIVES= below.
# -DZIC_BLOAT_DEFAULT=\"fat\" to default zic's -b option to "fat", and
# similarly for "slim". Fat TZif files work around incompatibilities
# and bugs in some TZif readers, notably readers that mishandle 64-bit
# data in TZif files. Slim TZif files are more efficient and do not
# work around these incompatibilities and bugs. If not given, the
# default is "slim".
# and bugs in some TZif readers, notably older ones that
# ignore or otherwise mishandle 64-bit data in TZif files;
# however, fat TZif files may trigger bugs in newer TZif readers.
# Slim TZif files are more efficient, and are the default.
# -DZIC_MAX_ABBR_LEN_WO_WARN=3
# (or some other number) to set the maximum time zone abbreviation length
# that zic will accept without a warning (the default is 6)
# $(GCC_DEBUG_FLAGS) if you are using recent GCC and want lots of checking
#
# * Options marked "*" can be omitted if your compiler is C23 compatible.
#
# Select instrumentation via "make GCC_INSTRUMENT='whatever'".
GCC_INSTRUMENT = \
-fsanitize=undefined -fsanitize-address-use-after-scope \
@ -397,8 +402,9 @@ ZIC= $(zic) $(ZFLAGS)
# To shrink the size of installed TZif files,
# append "-r @N" to omit data before N-seconds-after-the-Epoch.
# To grow the files and work around older application bugs, append "-b fat";
# see ZIC_BLOAT_DEFAULT above.
# To grow the files and work around bugs in older applications,
# possibly at the expense of introducing bugs in newer ones,
# append "-b fat"; see ZIC_BLOAT_DEFAULT above.
# See the zic man page for more about -b and -r.
ZFLAGS=
@ -818,13 +824,19 @@ check_slashed_abbrs: $(TDATA_TO_CHECK)
CHECK_CC_LIST = { n = split($$1,a,/,/); for (i=2; i<=n; i++) print a[1], a[i]; }
check_sorted: backward backzone iso3166.tab zone.tab zone1970.tab
$(AWK) '/^Link/ {print $$3}' backward | LC_ALL=C sort -cu
$(AWK) '/^Link/ {printf "%.5d %s\n", g, $$3} /^$$/ {g++}' \
backward | LC_ALL=C sort -cu
$(AWK) '/^Zone/ {print $$2}' backzone | LC_ALL=C sort -cu
touch $@
check_links: checklinks.awk $(TDATA_TO_CHECK) tzdata.zi
$(AWK) -f checklinks.awk $(TDATA_TO_CHECK)
$(AWK) -f checklinks.awk tzdata.zi
$(AWK) \
-v DATAFORM=$(DATAFORM) \
-v backcheck=backward \
-f checklinks.awk $(TDATA_TO_CHECK)
$(AWK) \
-v DATAFORM=$(DATAFORM) \
-f checklinks.awk tzdata.zi
touch $@
check_tables: checktab.awk $(YDATA) backward $(ZONETABLES)

101
NEWS
View File

@ -1,5 +1,106 @@
News for the tz database
Release 2022f - 2022-10-28 18:04:57 -0700
Briefly:
Mexico will no longer observe DST except near the US border.
Chihuahua moves to year-round -06 on 2022-10-30.
Fiji no longer observes DST.
Move links to 'backward'.
In vanguard form, GMT is now a Zone and Etc/GMT a link.
zic now supports links to links, and vanguard form uses this.
Simplify four Ontario zones.
Fix a Y2438 bug when reading TZif data.
Enable 64-bit time_t on 32-bit glibc platforms.
Omit large-file support when no longer needed.
In C code, use some C23 features if available.
Remove no-longer-needed workaround for Qt bug 53071.
Changes to future timestamps.
Mexico will no longer observe DST after 2022, except for areas
near the US border that continue to observe US DST rules.
On 2022-10-30 at 02:00 the Mexican state of Chihuahua moves
from -07 (-06 with DST) to year-round -06, thus not changing
its clocks that day. The new law states that Chihuahua
near the US border no longer observes US DST.
Fiji will not observe DST in 2022/3. (Thanks to Shalvin Narayan.)
For now, assume DST is suspended indefinitely.
Changes to data
Move links to 'backward' to ease and simplify link maintenance.
This affects generated data only if you use 'make BACKWARD='.
GMT is now a Zone and Etc/GMT a link instead of vice versa,
as GMT is needed for leap second support whereas Etc/GMT is not.
However, this change exposes a bug in TZUpdater 2.3.2 so it is
present only in vanguard form for now.
Vanguard form now uses links to links, as zic now supports this.
Changes to past timestamps
Simplify four Ontario zones, as most of the post-1970 differences
seem to have been imaginary. (Problem reported by Chris Walton.)
Move America/Nipigon, America/Rainy_River, and America/Thunder_Bay
to 'backzone'; backward-compatibility links still work, albeit
with some different timestamps before November 2005.
Changes to code
zic now supports links to links regardless of input line order.
For example, if Australia/Sydney is a Zone, the lines
Link Australia/Canberra Australia/ACT
Link Australia/Sydney Australia/Canberra
now work correctly, even though the shell commands
ln Australia/Canberra Australia/ACT
ln Australia/Sydney Australia/Canberra
would fail because the first command attempts to use a link
Australia/Canberra that does not exist until after the second
command is executed. Previously, zic had unspecified behavior if
a Link line's target was another link, and zic often misbehaved if
a Link line's target was a later Link line.
Fix line number in zic's diagnostic for a link to a link.
Fix a bug that caused localtime to mishandle timestamps starting
in the year 2438 when reading data generated by 'zic -b fat' when
distant-future DST transitions occur at times given in standard
time or in UT, not the usual case of local time. This occurs when
the corresponding .zi Rule lines specify DST transitions with TO
columns of 'max' and AT columns that end in 's' or 'u'. The
number 2438 comes from the 32-bit limit in the year 2038, plus the
400-year Gregorian cycle. (Problem reported by Bradley White.)
On glibc 2.34 and later, which optionally supports 64-bit time_t
on platforms like x86 where time_t was traditionally 32 bits,
default time_t to 64 instead of 32 bits. This lets functions like
localtime support timestamps after the year 2038, and fixes
year-2038 problems in zic when accessing files dated after 2038.
To continue to limit time_t to 32 bits on these platforms, use
"make CFLAGS='-D_TIME_BITS=32'".
In C code, do not enable large-file support on platforms like AIX
and macOS that no longer need it now that tzcode does not use
off_t or related functions like 'stat'. Large-file support is
still enabled by default on GNU/Linux, as it is needed for 64-bit
time_t support.
In C code, prefer C23 keywords to pre-C23 macros for alignof,
bool, false, and true. Also, use the following C23 features if
available: __has_include, unreachable.
zic no longer works around Qt bug 53071, as the relevant Qt
releases have been out of support since 2019. This change affects
only fat TZif files, as thin files never had the workaround.
zdump no longer modifies the environ vector when compiled on
platforms lacking tm_zone or when compiled with -DUSE_LTZ=0.
This avoid undefined behavior on POSIX platforms.
Release 2022e - 2022-10-11 11:13:02 -0700
Briefly:

View File

@ -802,12 +802,14 @@ typesequiv(const struct state *sp, int a, int b)
b < 0 || b >= sp->typecnt)
result = false;
else {
/* Compare the relevant members of *AP and *BP.
Ignore tt_ttisstd and tt_ttisut, as they are
irrelevant now and counting them could cause
sp->goahead to mistakenly remain false. */
register const struct ttinfo * ap = &sp->ttis[a];
register const struct ttinfo * bp = &sp->ttis[b];
result = (ap->tt_utoff == bp->tt_utoff
&& ap->tt_isdst == bp->tt_isdst
&& ap->tt_ttisstd == bp->tt_ttisstd
&& ap->tt_ttisut == bp->tt_ttisut
&& (strcmp(&sp->chars[ap->tt_desigidx],
&sp->chars[bp->tt_desigidx])
== 0));
@ -1096,7 +1098,7 @@ transtime(const int year, register const struct rule *const rulep,
value += mon_lengths[leapyear][i] * SECSPERDAY;
break;
default: UNREACHABLE();
default: unreachable();
}
/*

110
private.h
View File

@ -17,6 +17,15 @@
** Thank you!
*/
/* Define true, false and bool if they don't work out of the box. */
#if __STDC_VERSION__ < 199901
# define true 1
# define false 0
# define bool int
#elif __STDC_VERSION__ < 202311
# include <stdbool.h>
#endif
/*
** zdump has been made independent of the rest of the time
** conversion package to increase confidence in the verification it provides.
@ -54,9 +63,25 @@
# define HAVE_GENERIC (201112 <= __STDC_VERSION__)
#endif
#if !defined HAVE_GETRANDOM && defined __has_include
# if __has_include(<sys/random.h>)
# define HAVE_GETRANDOM true
# else
# define HAVE_GETRANDOM false
# endif
#endif
#ifndef HAVE_GETRANDOM
# define HAVE_GETRANDOM (2 < __GLIBC__ + (25 <= __GLIBC_MINOR__))
#endif
#if !defined HAVE_GETTEXT && defined __has_include
# if __has_include(<libintl.h>)
# define HAVE_GETTEXT true
# endif
#endif
#ifndef HAVE_GETTEXT
# define HAVE_GETTEXT 0
#endif /* !defined HAVE_GETTEXT */
# define HAVE_GETTEXT false
#endif
#ifndef HAVE_INCOMPATIBLE_CTIME_R
# define HAVE_INCOMPATIBLE_CTIME_R 0
@ -74,8 +99,8 @@
# define HAVE_POSIX_DECLS 1
#endif
#ifndef HAVE_STDBOOL_H
# define HAVE_STDBOOL_H (199901 <= __STDC_VERSION__)
#ifndef HAVE_SETENV
# define HAVE_SETENV 1
#endif
#ifndef HAVE_STRDUP
@ -90,17 +115,23 @@
# define HAVE_SYMLINK 1
#endif /* !defined HAVE_SYMLINK */
#if !defined HAVE_SYS_STAT_H && defined __has_include
# if !__has_include(<sys/stat.h>)
# define HAVE_SYS_STAT_H false
# endif
#endif
#ifndef HAVE_SYS_STAT_H
# define HAVE_SYS_STAT_H 1
#endif /* !defined HAVE_SYS_STAT_H */
# define HAVE_SYS_STAT_H true
#endif
#if !defined HAVE_UNISTD_H && defined __has_include
# if !__has_include(<unistd.h>)
# define HAVE_UNISTD_H false
# endif
#endif
#ifndef HAVE_UNISTD_H
# define HAVE_UNISTD_H 1
#endif /* !defined HAVE_UNISTD_H */
#ifndef HAVE_UTMPX_H
# define HAVE_UTMPX_H 1
#endif /* !defined HAVE_UTMPX_H */
# define HAVE_UNISTD_H true
#endif
#ifndef NETBSD_INSPIRED
# define NETBSD_INSPIRED 1
@ -118,15 +149,17 @@
/* Enable strtoimax on pre-C99 Solaris 11. */
#define __EXTENSIONS__ 1
/* To avoid having 'stat' fail unnecessarily with errno == EOVERFLOW,
enable large files on GNUish systems ... */
/* On GNUish systems where time_t might be 32 or 64 bits, use 64.
On these platforms _FILE_OFFSET_BITS must also be 64; otherwise
setting _TIME_BITS to 64 does not work. The code does not
otherwise rely on _FILE_OFFSET_BITS being 64, since it does not
use off_t or functions like 'stat' that depend on off_t. */
#ifndef _FILE_OFFSET_BITS
# define _FILE_OFFSET_BITS 64
#endif
/* ... and on AIX ... */
#define _LARGE_FILES 1
/* ... and enable large inode numbers on Mac OS X 10.5 and later. */
#define _DARWIN_USE_64_BIT_INODE 1
#if !defined _TIME_BITS && _FILE_OFFSET_BITS == 64
# define _TIME_BITS 64
#endif
/*
** Nested includes
@ -157,7 +190,7 @@
#undef tzalloc
#undef tzfree
#include <sys/types.h> /* for time_t */
#include <stddef.h>
#include <string.h>
#include <limits.h> /* for CHAR_BIT et al. */
#include <stdlib.h>
@ -234,6 +267,9 @@
** previously-included files. glibc 2.1 and Solaris 10 and later have
** stdint.h, even with pre-C99 compilers.
*/
#if !defined HAVE_STDINT_H && defined __has_include
# define HAVE_STDINT_H true /* C23 __has_include implies C99 stdint.h. */
#endif
#ifndef HAVE_STDINT_H
# define HAVE_STDINT_H \
(199901 <= __STDC_VERSION__ \
@ -360,13 +396,6 @@ typedef unsigned long uintmax_t;
# endif
#endif
#ifndef INT32_MAX
# define INT32_MAX 0x7fffffff
#endif /* !defined INT32_MAX */
#ifndef INT32_MIN
# define INT32_MIN (-1 - INT32_MAX)
#endif /* !defined INT32_MIN */
#ifndef SIZE_MAX
# define SIZE_MAX ((size_t) -1)
#endif
@ -623,14 +652,6 @@ time_t time2posix_z(timezone_t, time_t) ATTRIBUTE_PURE;
** Finally, some convenience items.
*/
#if HAVE_STDBOOL_H
# include <stdbool.h>
#else
# define true 1
# define false 0
# define bool int
#endif
#define TYPE_BIT(type) (sizeof(type) * CHAR_BIT)
#define TYPE_SIGNED(type) (((type) -1) < 0)
#define TWOS_COMPLEMENT(t) ((t) ~ (t) 0 < 0)
@ -708,16 +729,19 @@ time_t time2posix_z(timezone_t, time_t) ATTRIBUTE_PURE;
#endif
#ifdef DEBUG
# define UNREACHABLE() abort()
#elif 4 < __GNUC__ + (5 <= __GNUC_MINOR__)
# define UNREACHABLE() __builtin_unreachable()
#elif defined __has_builtin
# if __has_builtin(__builtin_unreachable)
# define UNREACHABLE() __builtin_unreachable()
# undef unreachable
# define unreachable() abort()
#elif !defined unreachable
# ifdef __has_builtin
# if __has_builtin(__builtin_unreachable)
# define unreachable() __builtin_unreachable()
# endif
# elif 4 < __GNUC__ + (5 <= __GNUC_MINOR__)
# define unreachable() __builtin_unreachable()
# endif
# ifndef unreachable
# define unreachable() ((void) 0)
# endif
#endif
#ifndef UNREACHABLE
# define UNREACHABLE() ((void) 0)
#endif
/*

View File

@ -329,6 +329,7 @@ still supported.
These legacy names are mostly defined in the file
'<code>etcetera</code>'.
Also, the file '<code>backward</code>' defines the legacy names
'<code>Etc/GMT0</code>', '<code>Etc/GMT-0</code>', '<code>Etc/GMT+0</code>',
'<code>GMT0</code>', '<code>GMT-0</code>' and '<code>GMT+0</code>',
and the file '<code>northamerica</code>' defines the legacy names
'<code>EST5EDT</code>', '<code>CST6CDT</code>',

View File

@ -1 +1 @@
2022e
2022f

76
zdump.c
View File

@ -56,21 +56,6 @@
*/
enum { SECSPER400YEARS_FITS = SECSPERLYEAR <= INTMAX_MAX / 400 };
#if !defined HAVE_GENERIC && defined __has_extension
# if __has_extension(c_generic_selections)
# define HAVE_GENERIC 1
# else
# define HAVE_GENERIC 0
# endif
#endif
/* _Generic is buggy in pre-4.9 GCC. */
#if !defined HAVE_GENERIC && defined __GNUC__
# define HAVE_GENERIC (4 < __GNUC__ + (9 <= __GNUC_MINOR__))
#endif
#ifndef HAVE_GENERIC
# define HAVE_GENERIC (201112 <= __STDC_VERSION__)
#endif
#if HAVE_GETTEXT
# include <locale.h> /* for setlocale */
#endif /* HAVE_GETTEXT */
@ -243,33 +228,56 @@ mktime_z(timezone_t tz, struct tm *tmp)
static timezone_t
tzalloc(char const *val)
{
# if HAVE_SETENV
if (setenv("TZ", val, 1) != 0) {
perror("setenv");
exit(EXIT_FAILURE);
}
tzset();
return NULL;
# else
enum { TZeqlen = 3 };
static char const TZeq[TZeqlen] = "TZ=";
static char **fakeenv;
char **env = fakeenv;
char *env0;
if (! env) {
char **e = environ;
int to;
static size_t fakeenv0size;
void *freeable = NULL;
char **env = fakeenv, **initial_environ;
size_t valsize = strlen(val) + 1;
if (fakeenv0size < valsize) {
char **e = environ, **to;
ptrdiff_t initial_nenvptrs; /* Counting the trailing NULL pointer. */
while (*e++)
continue;
env = xmalloc(sumsize(sizeof *environ,
(e - environ) * sizeof *environ));
to = 1;
for (e = environ; (env[to] = *e); e++)
to += strncmp(*e, "TZ=", 3) != 0;
initial_nenvptrs = e - environ;
fakeenv0size = sumsize(valsize, valsize);
fakeenv0size = max(fakeenv0size, 64);
freeable = env;
fakeenv = env =
xmalloc(sumsize(sumsize(sizeof *environ,
initial_nenvptrs * sizeof *environ),
sumsize(TZeqlen, fakeenv0size)));
to = env + 1;
for (e = environ; (*to = *e); e++)
to += strncmp(*e, TZeq, TZeqlen) != 0;
env[0] = memcpy(to + 1, TZeq, TZeqlen);
}
env0 = xmalloc(sumsize(sizeof "TZ=", strlen(val)));
env[0] = strcat(strcpy(env0, "TZ="), val);
environ = fakeenv = env;
memcpy(env[0] + TZeqlen, val, valsize);
initial_environ = environ;
environ = env;
tzset();
return env;
free(freeable);
return initial_environ;
# endif
}
static void
tzfree(timezone_t env)
tzfree(timezone_t initial_environ)
{
environ = env + 1;
free(env[0]);
# if !HAVE_SETENV
environ = initial_environ;
tzset();
# endif
}
#endif /* ! USE_LOCALTIME_RZ */
@ -281,9 +289,9 @@ gmtzinit(void)
if (USE_LOCALTIME_RZ) {
/* Try "GMT" first to find out whether this is one of the rare
platforms where time_t counts leap seconds; this works due to
the "Link Etc/GMT GMT" line in the "etcetera" file. If "GMT"
the "Zone GMT 0 - GMT" line in the "etcetera" file. If "GMT"
fails, fall back on "GMT0" which might be similar due to the
"Link Etc/GMT GMT0" line in the "backward" file, and which
"Link GMT GMT0" line in the "backward" file, and which
should work on all POSIX platforms. The rest of zdump does not
use the "GMT" abbreviation that comes from this setting, so it
is OK to use "GMT" here rather than the more-modern "UTC" which

29
zic.8
View File

@ -190,7 +190,10 @@ the named file rather than in the standard location.
Be more verbose, and complain about the following situations:
.RS
.PP
The input specifies a link to a link.
The input specifies a link to a link,
something not supported by some older parsers, including
.B zic
itself through release 2022e.
.PP
A year that appears in a data file is outside the range
of representable years.
@ -691,19 +694,37 @@ The
.B TARGET
field should appear as the
.B NAME
field in some zone line.
field in some zone line or as the
.B LINK-NAME
field in some link line.
The
.B LINK-NAME
field is used as an alternative name for that zone;
it has the same syntax as a zone line's
.B NAME
field.
Links can chain together, although the behavior is unspecified if a
chain of one or more links does not terminate in a Zone name.
A link line can appear before the line that defines the link target.
For example:
.sp
.ne 3
.nf
.in +2m
.ta \w'Zone\0\0'u +\w'Greenwich\0\0'u
Link Greenwich G_M_T
Link Etc/GMT Greenwich
Zone Etc/GMT\0\00\0\0\*-\0\0GMT
.sp
.in
.fi
The two links are chained together, and G_M_T, Greenwich, and Etc/GMT
all name the same zone.
.PP
Except for continuation lines,
lines may appear in any order in the input.
However, the behavior is unspecified if multiple zone or link lines
define the same name, or if the source of one link line is the target
of another.
define the same name.
.PP
The file that describes leap seconds can have leap lines and an
expiration line.

View File

@ -93,7 +93,8 @@ OPTIONS
-v Be more verbose, and complain about the following situations:
The input specifies a link to a link.
The input specifies a link to a link, something not supported by
some older parsers, including zic itself through release 2022e.
A year that appears in a data file is outside the range of
representable years.
@ -386,14 +387,24 @@ FILES
Link Europe/Istanbul Asia/Istanbul
The TARGET field should appear as the NAME field in some zone line.
The LINK-NAME field is used as an alternative name for that zone; it
has the same syntax as a zone line's NAME field.
The TARGET field should appear as the NAME field in some zone line or
as the LINK-NAME field in some link line. The LINK-NAME field is used
as an alternative name for that zone; it has the same syntax as a zone
line's NAME field. Links can chain together, although the behavior is
unspecified if a chain of one or more links does not terminate in a
Zone name. A link line can appear before the line that defines the
link target. For example:
Link Greenwich G_M_T
Link Etc/GMT Greenwich
Zone Etc/GMT 0 - GMT
The two links are chained together, and G_M_T, Greenwich, and Etc/GMT
all name the same zone.
Except for continuation lines, lines may appear in any order in the
input. However, the behavior is unspecified if multiple zone or link
lines define the same name, or if the source of one link line is the
target of another.
lines define the same name.
The file that describes leap seconds can have leap lines and an
expiration line. Leap lines have the following form:

445
zic.c
View File

@ -20,12 +20,14 @@
#include <locale.h>
#include <signal.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdio.h>
typedef int_fast64_t zic_t;
#define ZIC_MIN INT_FAST64_MIN
#define ZIC_MAX INT_FAST64_MAX
static zic_t const
ZIC_MIN = INT_FAST64_MIN,
ZIC_MAX = INT_FAST64_MAX,
ZIC32_MIN = -1 - (zic_t) 0x7fffffff,
ZIC32_MAX = 0x7fffffff;
#define SCNdZIC SCNdFAST64
#ifndef ZIC_MAX_ABBR_LEN_WO_WARN
@ -39,6 +41,10 @@ typedef int_fast64_t zic_t;
# define mkdir(name, mode) _mkdir(name)
#endif
#if HAVE_GETRANDOM
# include <sys/random.h>
#endif
#if HAVE_SYS_STAT_H
# include <sys/stat.h>
#endif
@ -53,9 +59,11 @@ typedef int_fast64_t zic_t;
static ptrdiff_t const PTRDIFF_MAX = MAXVAL(ptrdiff_t, TYPE_BIT(ptrdiff_t));
#endif
/* The minimum alignment of a type, for pre-C11 platforms. */
/* The minimum alignment of a type, for pre-C23 platforms. */
#if __STDC_VERSION__ < 201112
# define _Alignof(type) offsetof(struct { char a; type b; }, b)
# define alignof(type) offsetof(struct { char a; type b; }, b)
#elif __STDC_VERSION__ < 202311
# include <stdalign.h>
#endif
/* The maximum length of a text line, including the trailing newline. */
@ -69,7 +77,7 @@ static ptrdiff_t const PTRDIFF_MAX = MAXVAL(ptrdiff_t, TYPE_BIT(ptrdiff_t));
typedef intmax_t lineno;
struct rule {
const char * r_filename;
int r_filenum;
lineno r_linenum;
const char * r_name;
@ -105,7 +113,7 @@ enum {
};
struct zone {
const char * z_filename;
int z_filenum;
lineno z_linenum;
const char * z_name;
@ -132,17 +140,28 @@ extern char * optarg;
extern int optind;
#endif
#if ! HAVE_LINK
# define link(target, linkname) (errno = ENOTSUP, -1)
#endif
#if ! HAVE_SYMLINK
# define readlink(file, buf, size) (errno = ENOTSUP, -1)
# define symlink(target, linkname) (errno = ENOTSUP, -1)
# define S_ISLNK(m) 0
static ssize_t
readlink(char const *restrict file, char *restrict buf, size_t size)
{
errno = ENOTSUP;
return -1;
}
static int
symlink(char const *target, char const *linkname)
{
errno = ENOTSUP;
return -1;
}
#endif
#ifndef AT_SYMLINK_FOLLOW
# define linkat(targetdir, target, linknamedir, linkname, flag) \
(itssymlink(target) ? (errno = ENOTSUP, -1) : link(target, linkname))
# if HAVE_LINK
# define linkat(targetdir, target, linknamedir, linkname, flag) \
(itssymlink(target) ? (errno = ENOTSUP, -1) : link(target, linkname))
# else
# define linkat(targetdir, target, linknamedir, linkname, flag) \
(errno = ENOTSUP, -1)
# endif
#endif
static void addtt(zic_t starttime, int type);
@ -155,7 +174,7 @@ static int getfields(char *, char **, int);
static zic_t gethms(const char * string, const char * errstring);
static zic_t getsave(char *, bool *);
static void inexpires(char **, int);
static void infile(const char * filename);
static void infile(int, char const *);
static void inleap(char ** fields, int nfields);
static void inlink(char ** fields, int nfields);
static void inrule(char ** fields, int nfields);
@ -179,19 +198,10 @@ static zic_t tadd(zic_t t1, zic_t t2);
/* Bound on length of what %z can expand to. */
enum { PERCENT_Z_LEN_BOUND = sizeof "+995959" - 1 };
/* If true, work around a bug in Qt 5.6.1 and earlier, which mishandles
TZif files whose POSIX-TZ-style strings contain '<'; see
QTBUG-53071 <https://bugreports.qt.io/browse/QTBUG-53071>. This
workaround will no longer be needed when Qt 5.6.1 and earlier are
obsolete, say in the year 2021. */
#ifndef WORK_AROUND_QTBUG_53071
enum { WORK_AROUND_QTBUG_53071 = true };
#endif
static int charcnt;
static bool errors;
static bool warnings;
static const char * filename;
static int filenum;
static int leapcnt;
static bool leapseen;
static zic_t leapminyear;
@ -202,9 +212,11 @@ static int max_format_len;
static zic_t max_year;
static zic_t min_year;
static bool noise;
static const char * rfilename;
static int rfilenum;
static lineno rlinenum;
static const char * progname;
static char const * leapsec;
static char *const * main_argv;
static ptrdiff_t timecnt;
static ptrdiff_t timecnt_alloc;
static int typecnt;
@ -325,7 +337,7 @@ static ptrdiff_t nzones; /* number of zones */
static ptrdiff_t nzones_alloc;
struct link {
const char * l_filename;
int l_filenum;
lineno l_linenum;
const char * l_target;
const char * l_linkname;
@ -506,8 +518,7 @@ growalloc(void *ptr, size_t itemsize, ptrdiff_t nitems, ptrdiff_t *nitems_alloc)
if (nitems < *nitems_alloc)
return ptr;
else {
ptrdiff_t nitems_max = PTRDIFF_MAX - WORK_AROUND_QTBUG_53071;
ptrdiff_t amax = min(nitems_max, SIZE_MAX);
ptrdiff_t amax = min(PTRDIFF_MAX, SIZE_MAX);
if ((amax - 1) / 3 * 2 < *nitems_alloc)
memory_exhausted(_("integer overflow"));
*nitems_alloc += (*nitems_alloc >> 1) + 1;
@ -519,19 +530,36 @@ growalloc(void *ptr, size_t itemsize, ptrdiff_t nitems, ptrdiff_t *nitems_alloc)
** Error handling.
*/
static void
eats(char const *name, lineno num, char const *rname, lineno rnum)
/* In most of the code, an input file name is represented by its index
into the main argument vector, except that LEAPSEC_FILENUM stands
for leapsec and COMMAND_LINE_FILENUM stands for the command line. */
enum { LEAPSEC_FILENUM = -2, COMMAND_LINE_FILENUM = -1 };
/* Return the name of the Ith input file, for diagnostics. */
static char const *
filename(int i)
{
filename = name;
if (i == COMMAND_LINE_FILENUM)
return _("command line");
else {
char const *fname = i == LEAPSEC_FILENUM ? leapsec : main_argv[i];
return strcmp(fname, "-") == 0 ? _("standard input") : fname;
}
}
static void
eats(int fnum, lineno num, int rfnum, lineno rnum)
{
filenum = fnum;
linenum = num;
rfilename = rname;
rfilenum = rfnum;
rlinenum = rnum;
}
static void
eat(char const *name, lineno num)
eat(int fnum, lineno num)
{
eats(name, num, NULL, -1);
eats(fnum, num, 0, -1);
}
static void ATTRIBUTE_FORMAT((printf, 1, 0))
@ -542,12 +570,13 @@ verror(const char *const string, va_list args)
** zic ... 2>&1 | error -t "*" -v
** on BSD systems.
*/
if (filename)
fprintf(stderr, _("\"%s\", line %"PRIdMAX": "), filename, linenum);
if (filenum)
fprintf(stderr, _("\"%s\", line %"PRIdMAX": "),
filename(filenum), linenum);
vfprintf(stderr, string, args);
if (rfilename != NULL)
if (rfilenum)
fprintf(stderr, _(" (rule from \"%s\", line %"PRIdMAX")"),
rfilename, rlinenum);
filename(rfilenum), rlinenum);
fprintf(stderr, "\n");
}
@ -628,6 +657,131 @@ change_directory(char const *dir)
}
}
/* Compare the two links A and B, for a stable sort by link name. */
static int
qsort_linkcmp(void const *a, void const *b)
{
struct link const *l = a;
struct link const *m = b;
int cmp = strcmp(l->l_linkname, m->l_linkname);
if (cmp)
return cmp;
/* The link names are the same. Make the sort stable by comparing
file numbers (where subtraction cannot overflow) and possibly
line numbers (where it can). */
cmp = l->l_filenum - m->l_filenum;
if (cmp)
return cmp;
return (l->l_linenum > m->l_linenum) - (l->l_linenum < m->l_linenum);
}
/* Compare the string KEY to the link B, for bsearch. */
static int
bsearch_linkcmp(void const *key, void const *b)
{
struct link const *m = b;
return strcmp(key, m->l_linkname);
}
/* Make the links specified by the Link lines. */
static void
make_links(void)
{
ptrdiff_t i, j, nalinks, pass_size;
if (1 < nlinks)
qsort(links, nlinks, sizeof *links, qsort_linkcmp);
/* Ignore each link superseded by a later link with the same name. */
j = 0;
for (i = 0; i < nlinks; i++) {
while (i + 1 < nlinks
&& strcmp(links[i].l_linkname, links[i + 1].l_linkname) == 0)
i++;
links[j++] = links[i];
}
nlinks = pass_size = j;
/* Walk through the link array making links. However,
if a link's target has not been made yet, append a copy to the
end of the array. The end of the array will gradually fill
up with a small sorted subsequence of not-yet-made links.
nalinks counts all the links in the array, including copies.
When we reach the copied subsequence, it may still contain
a link to a not-yet-made link, so the process repeats.
At any given point in time, the link array consists of the
following subregions, where 0 <= i <= j <= nalinks and
0 <= nlinks <= nalinks:
0 .. (i - 1):
links that either have been made, or have been copied to a
later point point in the array (this later point can be in
any of the three subregions)
i .. (j - 1):
not-yet-made links for this pass
j .. (nalinks - 1):
not-yet-made links that this pass has skipped because
they were links to not-yet-made links
The first subregion might not be sorted if nlinks < i;
the other two subregions are sorted. This algorithm does
not alter entries 0 .. (nlinks - 1), which remain sorted.
If there are L links, this algorithm is O(C*L*log(L)) where
C is the length of the longest link chain. Usually C is
short (e.g., 3) though its worst-case value is L. */
j = nalinks = nlinks;
for (i = 0; i < nalinks; i++) {
struct link *l;
eat(links[i].l_filenum, links[i].l_linenum);
/* If this pass examined all its links, start the next pass. */
if (i == j) {
if (nalinks - i == pass_size) {
error(_("\"Link %s %s\" is part of a link cycle"),
links[i].l_target, links[i].l_linkname);
break;
}
j = nalinks;
pass_size = nalinks - i;
}
/* Diagnose self links, which the cycle detection algorithm would not
otherwise catch. */
if (strcmp(links[i].l_target, links[i].l_linkname) == 0) {
error(_("link %s targets itself"), links[i].l_target);
continue;
}
/* Make this link unless its target has not been made yet. */
l = bsearch(links[i].l_target, &links[i + 1], j - (i + 1),
sizeof *links, bsearch_linkcmp);
if (!l)
l = bsearch(links[i].l_target, &links[j], nalinks - j,
sizeof *links, bsearch_linkcmp);
if (!l)
dolink(links[i].l_target, links[i].l_linkname, false);
else {
/* The link target has not been made yet; copy the link to the end. */
links = growalloc(links, sizeof *links, nalinks, &nlinks_alloc);
links[nalinks++] = links[i];
}
if (noise && i < nlinks) {
if (l)
warning(_("link %s targeting link %s mishandled by pre-2023 zic"),
links[i].l_linkname, links[i].l_target);
else if (bsearch(links[i].l_target, links, nlinks, sizeof *links,
bsearch_linkcmp))
warning(_("link %s targeting link %s"),
links[i].l_linkname, links[i].l_target);
}
}
}
/* Simple signal handling: just set a flag that is checked
periodically outside critical sections. To set up the handler,
prefer sigaction if available to close a signal race. */
@ -754,7 +908,6 @@ redundant_time_option(char *opt)
static const char * psxrules;
static const char * lcltime;
static const char * directory;
static const char * leapsec;
static const char * tzdefault;
/* -1 if the TZif output file should be slim, 0 if default, 1 if the
@ -789,6 +942,7 @@ main(int argc, char **argv)
# endif /* defined TEXTDOMAINDIR */
textdomain(TZ_DOMAIN);
#endif /* HAVE_GETTEXT */
main_argv = argv;
progname = argv[0];
if (TYPE_BIT(zic_t) < 64) {
fprintf(stderr, "%s: %s\n", progname,
@ -923,12 +1077,12 @@ _("%s: invalid time range: %s\n"),
tzdefault = TZDEFAULT;
if (optind < argc && leapsec != NULL) {
infile(leapsec);
infile(LEAPSEC_FILENUM, leapsec);
adjleap();
}
for (k = optind; k < argc; k++)
infile(argv[k]);
infile(k, argv[k]);
if (errors)
return EXIT_FAILURE;
associate();
@ -942,24 +1096,13 @@ _("%s: invalid time range: %s\n"),
continue;
outzone(&zones[i], j - i);
}
/*
** Make links.
*/
for (i = 0; i < nlinks; ++i) {
eat(links[i].l_filename, links[i].l_linenum);
dolink(links[i].l_target, links[i].l_linkname, false);
if (noise)
for (j = 0; j < nlinks; ++j)
if (strcmp(links[i].l_linkname,
links[j].l_target) == 0)
warning(_("link to link"));
}
make_links();
if (lcltime != NULL) {
eat(_("command line"), 1);
eat(COMMAND_LINE_FILENUM, 1);
dolink(lcltime, tzdefault, true);
}
if (psxrules != NULL) {
eat(_("command line"), 1);
eat(COMMAND_LINE_FILENUM, 1);
dolink(psxrules, TZDEFRULES, true);
}
if (warnings && (ferror(stderr) || fclose(stderr) != 0))
@ -1038,6 +1181,63 @@ namecheck(const char *name)
return componentcheck(name, component, cp);
}
/* Return a random uint_fast64_t. */
static uint_fast64_t
get_rand_u64(void)
{
#if HAVE_GETRANDOM
static uint_fast64_t entropy_buffer[max(1, 256 / sizeof(uint_fast64_t))];
static int nwords;
if (!nwords) {
ssize_t s;
do
s = getrandom(entropy_buffer, sizeof entropy_buffer, 0);
while (s < 0 && errno == EINTR);
nwords = s < 0 ? -1 : s / sizeof *entropy_buffer;
}
if (0 < nwords)
return entropy_buffer[--nwords];
#endif
/* getrandom didn't work, so fall back on portable code that is
not the best because the seed doesn't necessarily have enough bits,
the seed isn't cryptographically random on platforms lacking
getrandom, and 'rand' might not be cryptographically secure. */
{
static bool initialized;
if (!initialized) {
unsigned seed;
#ifdef CLOCK_REALTIME
struct timespec now;
clock_gettime (CLOCK_REALTIME, &now);
seed = now.tv_sec ^ now.tv_nsec;
#else
seed = time(NULL);
#endif
srand(seed);
initialized = true;
}
}
/* Return a random number if rand() yields a random number and in
the typical case where RAND_MAX is one less than a power of two.
In other cases this code yields a sort-of-random number. */
{
uint_fast64_t
rand_max = RAND_MAX,
multiplier = rand_max + 1, /* It's OK if this overflows to 0. */
r = 0, rmax = 0;
do {
uint_fast64_t rmax1 = rmax * multiplier + rand_max;
r = r * multiplier + rand();
rmax = rmax < rmax1 ? rmax1 : UINT_FAST64_MAX;
} while (rmax < UINT_FAST64_MAX);
return r;
}
}
/* Generate a randomish name in the same directory as *NAME. If
*NAMEALLOC, put the name into *NAMEALLOC which is assumed to be
that returned by a previous call and is thus already almost set up
@ -1057,8 +1257,19 @@ random_dirent(char const **name, char **namealloc)
int suffixlen = 6;
char const *lastslash = strrchr(src, '/');
ptrdiff_t dirlen = lastslash ? lastslash + 1 - src : 0;
static unsigned short initialized;
int i;
uint_fast64_t r;
uint_fast64_t base = alphabetlen;
/* BASE**6 */
uint_fast64_t base__6 = base * base * base * base * base * base;
/* The largest uintmax_t that is a multiple of BASE**6. Any random
uintmax_t value that is this value or greater, yields a biased
remainder when divided by BASE**6. UNFAIR_MIN equals the
mathematical value of ((UINTMAX_MAX + 1) - (UINTMAX_MAX + 1) % BASE**6)
computed without overflow. */
uint_fast64_t unfair_min = - ((UINTMAX_MAX % base__6 + 1) % base__6);
if (!dst) {
dst = emalloc(dirlen + prefixlen + suffixlen + 1);
@ -1068,13 +1279,14 @@ random_dirent(char const **name, char **namealloc)
*name = *namealloc = dst;
}
/* This randomization is not the best, but is portable to C89. */
if (!initialized++) {
unsigned now = time(NULL);
srand(rand() ^ now);
do
r = get_rand_u64();
while (unfair_min <= r);
for (i = 0; i < suffixlen; i++) {
dst[dirlen + prefixlen + i] = alphabet[r % alphabetlen];
r /= alphabetlen;
}
for (i = 0; i < suffixlen; i++)
dst[dirlen + prefixlen + i] = alphabet[rand() % alphabetlen];
}
/* Prepare to write to the file *OUTNAME, using *TEMPNAME to store the
@ -1297,28 +1509,26 @@ associate(void)
register struct rule * rp;
register ptrdiff_t i, j, base, out;
if (nrules != 0) {
if (1 < nrules) {
qsort(rules, nrules, sizeof *rules, rcomp);
for (i = 0; i < nrules - 1; ++i) {
if (strcmp(rules[i].r_name,
rules[i + 1].r_name) != 0)
continue;
if (strcmp(rules[i].r_filename,
rules[i + 1].r_filename) == 0)
if (rules[i].r_filenum == rules[i + 1].r_filenum)
continue;
eat(rules[i].r_filename, rules[i].r_linenum);
eat(rules[i].r_filenum, rules[i].r_linenum);
warning(_("same rule name in multiple files"));
eat(rules[i + 1].r_filename, rules[i + 1].r_linenum);
eat(rules[i + 1].r_filenum, rules[i + 1].r_linenum);
warning(_("same rule name in multiple files"));
for (j = i + 2; j < nrules; ++j) {
if (strcmp(rules[i].r_name,
rules[j].r_name) != 0)
break;
if (strcmp(rules[i].r_filename,
rules[j].r_filename) == 0)
if (rules[i].r_filenum == rules[j].r_filenum)
continue;
if (strcmp(rules[i + 1].r_filename,
rules[j].r_filename) == 0)
if (rules[i + 1].r_filenum
== rules[j].r_filenum)
continue;
break;
}
@ -1349,7 +1559,7 @@ associate(void)
/*
** Maybe we have a local standard time offset.
*/
eat(zp->z_filename, zp->z_linenum);
eat(zp->z_filenum, zp->z_linenum);
zp->z_save = getsave(zp->z_rule, &zp->z_isdst);
/*
** Note, though, that if there's no rule,
@ -1398,7 +1608,7 @@ inputline(FILE *fp, char *buf, ptrdiff_t bufsize)
}
static void
infile(const char *name)
infile(int fnum, char const *name)
{
register FILE * fp;
register const struct lookup * lp;
@ -1406,7 +1616,6 @@ infile(const char *name)
register lineno num;
if (strcmp(name, "-") == 0) {
name = _("standard input");
fp = stdin;
} else if ((fp = fopen(name, "r")) == NULL) {
const char *e = strerror(errno);
@ -1421,7 +1630,7 @@ infile(const char *name)
char buf[_POSIX2_LINE_MAX];
int nfields;
char *fields[MAX_FIELDS];
eat(name, num);
eat(fnum, num);
linelen = inputline(fp, buf, sizeof buf);
if (linelen < 0)
break;
@ -1433,7 +1642,7 @@ infile(const char *name)
wantcont = inzcont(fields, nfields);
} else {
struct lookup const *line_codes
= name == leapsec ? leap_line_codes : zi_line_codes;
= fnum < 0 ? leap_line_codes : zi_line_codes;
lp = byword(fields[0], line_codes);
if (lp == NULL)
error(_("input line of unknown type"));
@ -1457,11 +1666,11 @@ infile(const char *name)
inexpires(fields, nfields);
wantcont = false;
break;
default: UNREACHABLE();
default: unreachable();
}
}
}
close_file(fp, NULL, filename, NULL);
close_file(fp, NULL, filename(fnum), NULL);
if (wantcont)
error(_("expected continuation line not found"));
}
@ -1564,7 +1773,7 @@ inrule(char **fields, int nfields)
error(_("Invalid rule name \"%s\""), fields[RF_NAME]);
return;
}
r.r_filename = filename;
r.r_filenum = filenum;
r.r_linenum = linenum;
r.r_save = getsave(fields[RF_SAVE], &r.r_isdst);
if (!rulesub(&r, fields[RF_LOYEAR], fields[RF_HIYEAR],
@ -1605,9 +1814,9 @@ _("\"Zone %s\" line and -p option are mutually exclusive"),
strcmp(zones[i].z_name, fields[ZF_NAME]) == 0) {
error(_("duplicate zone name %s"
" (file \"%s\", line %"PRIdMAX")"),
fields[ZF_NAME],
zones[i].z_filename,
zones[i].z_linenum);
fields[ZF_NAME],
filename(zones[i].z_filenum),
zones[i].z_linenum);
return false;
}
return inzsub(fields, nfields, false);
@ -1654,7 +1863,7 @@ inzsub(char **fields, int nfields, bool iscont)
i_untilday = ZF_TILDAY;
i_untiltime = ZF_TILTIME;
}
z.z_filename = filename;
z.z_filenum = filenum;
z.z_linenum = linenum;
z.z_stdoff = gethms(fields[i_stdoff], _("invalid UT offset"));
if ((cp = strchr(fields[i_format], '%')) != 0) {
@ -1670,7 +1879,7 @@ inzsub(char **fields, int nfields, bool iscont)
max_format_len = format_len;
hasuntil = nfields > i_untilyear;
if (hasuntil) {
z.z_untilrule.r_filename = filename;
z.z_untilrule.r_filenum = filenum;
z.z_untilrule.r_linenum = linenum;
if (!rulesub(
&z.z_untilrule,
@ -1839,7 +2048,7 @@ inlink(char **fields, int nfields)
}
if (! namecheck(fields[LF_LINKNAME]))
return;
l.l_filename = filename;
l.l_filenum = filenum;
l.l_linenum = linenum;
l.l_target = ecpyalloc(fields[LF_TARGET]);
l.l_linkname = ecpyalloc(fields[LF_LINKNAME]);
@ -1903,7 +2112,7 @@ rulesub(struct rule *rp, const char *loyearp, const char *hiyearp,
case YR_MAXIMUM:
rp->r_loyear = ZIC_MAX;
break;
default: UNREACHABLE();
default: unreachable();
} else if (sscanf(cp, "%"SCNdZIC"%c", &rp->r_loyear, &xs) != 1) {
error(_("invalid starting year"));
return false;
@ -1921,7 +2130,7 @@ rulesub(struct rule *rp, const char *loyearp, const char *hiyearp,
case YR_ONLY:
rp->r_hiyear = rp->r_loyear;
break;
default: UNREACHABLE();
default: unreachable();
} else if (sscanf(cp, "%"SCNdZIC"%c", &rp->r_hiyear, &xs) != 1) {
error(_("invalid ending year"));
return false;
@ -2092,17 +2301,14 @@ writezone(const char *const name, const char *const string, char version,
register FILE * fp;
register ptrdiff_t i, j;
register int pass;
zic_t one = 1;
zic_t y2038_boundary = one << 31;
ptrdiff_t nats = timecnt + WORK_AROUND_QTBUG_53071;
char *tempname = NULL;
char const *outname = name;
/* Allocate the ATS and TYPES arrays via a single malloc,
as this is a bit faster. */
zic_t *ats = emalloc(align_to(size_product(nats, sizeof *ats + 1),
_Alignof(zic_t)));
void *typesptr = ats + nats;
zic_t *ats = emalloc(align_to(size_product(timecnt, sizeof *ats + 1),
alignof(zic_t)));
void *typesptr = ats + timecnt;
unsigned char *types = typesptr;
struct timerange rangeall = {0}, range32, range64;
@ -2172,21 +2378,6 @@ writezone(const char *const name, const char *const string, char version,
}
}
/* Work around QTBUG-53071 for timestamps less than y2038_boundary - 1,
by inserting a no-op transition at time y2038_boundary - 1.
This works only for timestamps before the boundary, which
should be good enough in practice as QTBUG-53071 should be
long-dead by 2038. Do this after correcting for leap
seconds, as the idea is to insert a transition just before
32-bit time_t rolls around, and this occurs at a slightly
different moment if transitions are leap-second corrected. */
if (WORK_AROUND_QTBUG_53071 && timecnt != 0 && want_bloat()
&& ats[timecnt - 1] < y2038_boundary - 1 && strchr(string, '<')) {
ats[timecnt] = y2038_boundary - 1;
types[timecnt] = types[timecnt - 1];
timecnt++;
}
rangeall.defaulttype = defaulttype;
rangeall.count = timecnt;
rangeall.leapcount = leapcnt;
@ -2194,7 +2385,7 @@ writezone(const char *const name, const char *const string, char version,
max(hi_time,
redundant_time - (ZIC_MIN < redundant_time)),
ats, types);
range32 = limitrange(range64, INT32_MIN, INT32_MAX, ats, types);
range32 = limitrange(range64, ZIC32_MIN, ZIC32_MAX, ats, types);
/* TZif version 4 is needed if a no-op transition is appended to
indicate the expiration of the leap second table, or if the first
@ -2248,8 +2439,8 @@ writezone(const char *const name, const char *const string, char version,
thisleapi = range32.leapbase;
thisleapcnt = range32.leapcount;
thisleapexpiry = range32.leapexpiry;
thismin = INT32_MIN;
thismax = INT32_MAX;
thismin = ZIC32_MIN;
thismax = ZIC32_MAX;
} else {
thisdefaulttype = range64.defaulttype;
thistimei = range64.base;
@ -2282,7 +2473,7 @@ writezone(const char *const name, const char *const string, char version,
/* Arguably the default time type in the 32-bit data
should be range32.defaulttype, which is suited for
timestamps just before INT32_MIN. However, zic
timestamps just before ZIC32_MIN. However, zic
traditionally used the time type of the indefinite
past instead. Internet RFC 8532 says readers should
ignore 32-bit data, so this discrepancy matters only
@ -2434,7 +2625,7 @@ writezone(const char *const name, const char *const string, char version,
/* Output a LO_TIME transition if needed; see limitrange.
But do not go below the minimum representable value
for this pass. */
lo = pass == 1 && lo_time < INT32_MIN ? INT32_MIN : lo_time;
lo = pass == 1 && lo_time < ZIC32_MIN ? ZIC32_MIN : lo_time;
if (0 <= pretranstype)
puttzcodepass(lo, fp, pass);
@ -2977,7 +3168,7 @@ outzone(const struct zone *zpfirst, ptrdiff_t zonecount)
INITIALIZE(prevktime);
if (useuntil && zp->z_untiltime <= min_time)
continue;
eat(zp->z_filename, zp->z_linenum);
eat(zp->z_filenum, zp->z_linenum);
*startbuf = '\0';
if (zp->z_nrules == 0) {
int type;
@ -3005,8 +3196,8 @@ outzone(const struct zone *zpfirst, ptrdiff_t zonecount)
zic_t one = 1;
zic_t y2038_boundary = one << 31;
struct rule *rp = &zp->z_rules[j];
eats(zp->z_filename, zp->z_linenum,
rp->r_filename, rp->r_linenum);
eats(zp->z_filenum, zp->z_linenum,
rp->r_filenum, rp->r_linenum);
rp->r_todo = year >= rp->r_loyear &&
year <= rp->r_hiyear;
if (rp->r_todo) {
@ -3047,8 +3238,8 @@ outzone(const struct zone *zpfirst, ptrdiff_t zonecount)
struct rule *r = &zp->z_rules[j];
if (!r->r_todo)
continue;
eats(zp->z_filename, zp->z_linenum,
r->r_filename, r->r_linenum);
eats(zp->z_filenum, zp->z_linenum,
r->r_filenum, r->r_linenum);
offset = r->r_todisut ? 0 : stdoff;
if (!r->r_todisstd)
offset = oadd(offset, save);
@ -3063,12 +3254,12 @@ outzone(const struct zone *zpfirst, ptrdiff_t zonecount)
} else if (jtime == ktime) {
char const *dup_rules_msg =
_("two rules for same instant");
eats(zp->z_filename, zp->z_linenum,
r->r_filename, r->r_linenum);
eats(zp->z_filenum, zp->z_linenum,
r->r_filenum, r->r_linenum);
warning("%s", dup_rules_msg);
r = &zp->z_rules[k];
eats(zp->z_filename, zp->z_linenum,
r->r_filename, r->r_linenum);
eats(zp->z_filenum, zp->z_linenum,
r->r_filenum, r->r_linenum);
error("%s", dup_rules_msg);
}
}
@ -3110,8 +3301,8 @@ outzone(const struct zone *zpfirst, ptrdiff_t zonecount)
false);
}
}
eats(zp->z_filename, zp->z_linenum,
rp->r_filename, rp->r_linenum);
eats(zp->z_filenum, zp->z_linenum,
rp->r_filenum, rp->r_linenum);
doabbr(ab, zp, rp->r_abbrvar,
rp->r_isdst, rp->r_save, false);
offset = oadd(zp->z_stdoff, rp->r_save);
@ -3140,7 +3331,7 @@ outzone(const struct zone *zpfirst, ptrdiff_t zonecount)
if (*startbuf == '\0' && zp->z_format)
doabbr(startbuf, zp, disable_percent_s,
isdst, save, false);
eat(zp->z_filename, zp->z_linenum);
eat(zp->z_filenum, zp->z_linenum);
if (*startbuf == '\0')
error(_("can't determine time zone abbreviation to use just after until time"));
else {