mirror of
https://git.FreeBSD.org/src.git
synced 2026-06-02 11:24:32 +00:00
Import tzcode 2026b
This commit is contained in:
@@ -1,10 +1,47 @@
|
||||
News for the tz database
|
||||
|
||||
Release 2026b - 2026-04-22 23:06:43 -0700
|
||||
|
||||
Briefly:
|
||||
British Columbia moved to permanent -07 on 2026-03-09.
|
||||
Some more overflow bugs have been fixed in zic.
|
||||
|
||||
Changes to future timestamps
|
||||
|
||||
British Columbia’s 2026-03-08 spring forward was its last
|
||||
foreseeable clock change, as it moved to permanent -07 thereafter.
|
||||
(Thanks to Arthur David Olson.) Although the change to permanent
|
||||
-07 legally took place on 2026-03-09, temporarily model the change
|
||||
to occur on 2026-11-01 at 02:00 instead. This works around a
|
||||
limitation in CLDR v48.2 (2026-03-17). This temporary hack is
|
||||
planned to be removed after CLDR is fixed.
|
||||
|
||||
Changes to code
|
||||
|
||||
zic no longer mishandles a last transition to a new time type.
|
||||
|
||||
zic no longer overflows a buffer when generating a TZ string like
|
||||
"PST-167:59:58PDT-167:59:59,M11.5.6/-167:59:59,M12.5.6/-167:59:59",
|
||||
which can occur with adversarial input. (Thanks to Naveed Khan.)
|
||||
|
||||
zic no longer generates a longer TZif file than necessary when
|
||||
an earlier time zone abbreviation is a suffix of a later one.
|
||||
As a nice side effect, zic no longer overflows a buffer when given
|
||||
a long series of abbreviations, each a suffix of the next.
|
||||
(Buffer overflow reported by Arthur Chan.)
|
||||
|
||||
zic no longer overflows an int when processing input like ‘Zone
|
||||
Ouch 2147483648:00:00 - LMT’. The int overflow can lead to buffer
|
||||
overflow in adversarial cases. (Thanks to Naveed Khan.)
|
||||
|
||||
zic now checks for signals more often.
|
||||
|
||||
|
||||
Release 2026a - 2026-03-01 22:59:49 -0800
|
||||
|
||||
Briefly:
|
||||
Moldova has used EU transition times since 2022.
|
||||
The "right" TZif files are no longer installed by default.
|
||||
The “right” TZif files are no longer installed by default.
|
||||
-DTZ_RUNTIME_LEAPS=0 disables runtime support for leap seconds.
|
||||
TZif files are no longer limited to 50 bytes of abbreviations.
|
||||
zic is no longer limited to 50 leap seconds.
|
||||
@@ -25,23 +62,23 @@ Release 2026a - 2026-03-01 22:59:49 -0800
|
||||
|
||||
The Makefile no longer by default installs an alternate set
|
||||
of TZif files for system clocks that count leap seconds.
|
||||
Install with 'make REDO=posix_right' to get the old default,
|
||||
Install with ‘make REDO=posix_right’ to get the old default,
|
||||
which is rarely used in major downstream distributions.
|
||||
If your system clock counts leap seconds (contrary to POSIX),
|
||||
it is better to install with 'make REDO=right_only'.
|
||||
it is better to install with ‘make REDO=right_only’.
|
||||
This change does not affect the leapseconds file, which is still
|
||||
installed as before.
|
||||
|
||||
The Makefile's POSIXRULES option, which was declared obsolete in
|
||||
release 2019b, has been removed. The Makefile's build procedure
|
||||
The Makefile’s POSIXRULES option, which was declared obsolete in
|
||||
release 2019b, has been removed. The Makefile’s build procedure
|
||||
thus no longer optionally installs the obsolete posixrules file.
|
||||
|
||||
Changes to code
|
||||
|
||||
Compiling with the new option -DTZ_RUNTIME_LEAPS=0 disables
|
||||
runtime support for leap seconds. Although this conforms to
|
||||
POSIX, shrinks tzcode's attack surface, and is more efficient,
|
||||
it fails to support Internet RFC 9636's leap seconds.
|
||||
POSIX, shrinks tzcode’s attack surface, and is more efficient,
|
||||
it fails to support Internet RFC 9636’s leap seconds.
|
||||
|
||||
zic now can generate, and localtime.c can now use, TZif files that
|
||||
hold up to 256 bytes of abbreviations, counting trailing NULs.
|
||||
@@ -51,7 +88,7 @@ Release 2026a - 2026-03-01 22:59:49 -0800
|
||||
|
||||
zic -L can now generate TZif files with more than 50 leap seconds.
|
||||
This helps test TZif readers not limited to 50 leap seconds, as
|
||||
tzcode's localtime.c is; it has little immediate need for
|
||||
tzcode’s localtime.c is; it has little immediate need for
|
||||
practical timekeeping as there have been only 27 leap seconds and
|
||||
possibly there will be no more, due to planned changes to UTC.
|
||||
zic -v warns if its output exceeds the old 50-second limit.
|
||||
|
||||
+1
-1
@@ -446,7 +446,7 @@ Includes the song “Does Anybody Really Know What Time It Is?”.
|
||||
</li>
|
||||
<li>
|
||||
Emanuele Arciuli,
|
||||
<a href="https://neumarecords.org/ols/products/william-duckworth-the-time-curve-preludes"><em>The Time Curve Preludes</em></a> (2023).
|
||||
<a href="https://williamduckworth.bandcamp.com/album/the-time-curve-preludes"><em>The Time Curve Preludes</em></a> (2023).
|
||||
Neuma 174, 44:46.
|
||||
The title piece, composed by
|
||||
<a href="https://en.wikipedia.org/wiki/William_Duckworth_(composer)">William
|
||||
|
||||
+15
-7
@@ -441,7 +441,7 @@ transition in the <code><abbr>tz</abbr></code> database.</li>
|
||||
Database Parser</a> is a
|
||||
<a href="https://en.wikipedia.org/wiki/C++">C++</a> parser and
|
||||
runtime library with a <a
|
||||
href="https://en.cppreference.com/w/cpp/chrono.html"><code>std::chrono</code> API</a>
|
||||
href="https://en.cppreference.com/cpp/chrono"><code>std::chrono</code> API</a>
|
||||
that is a standard part of C++.
|
||||
It is freely available under the
|
||||
<abbr title="Massachusetts Institute of Technology">MIT</abbr> license.</li>
|
||||
@@ -1135,8 +1135,7 @@ Network Time Protocol Best Current Practices</a>
|
||||
applications requiring accurate <abbr>UTC</abbr> or civil time,
|
||||
and is intended for use only in single, well-controlled environments.</li>
|
||||
<li>The <a
|
||||
href="https://pairlist6.pair.net/mailman/listinfo/leapsecs">Leap
|
||||
Second Discussion List</a> covers <a
|
||||
href="https://groups.io/g/LEAPSECS">LEAPSECS List</a> covers <a
|
||||
href="https://gge.ext.unb.ca/Resources/gpsworld.november99.pdf">McCarthy
|
||||
and Klepczynski’s 1999 proposal to discontinue leap seconds</a>,
|
||||
discussed further in
|
||||
@@ -1146,21 +1145,30 @@ leap second: its history and possible future</a>.
|
||||
might be redefined
|
||||
without Leap Seconds</a> gives pointers on this
|
||||
contentious issue.
|
||||
The General Conference on Weights and Measures
|
||||
The General Conference on Weights and Measures (CGPM)
|
||||
<a href="https://www.bipm.org/en/cgpm-2022/resolution-4">decided in 2022</a>
|
||||
to discontinue the use of leap seconds by 2035, and requested that no
|
||||
discontinuous adjustments be made to UTC for at least a century.
|
||||
The World Radiocommunication Conference <a
|
||||
href="https://www.itu.int/dms_pub/itu-r/opb/act/R-ACT-WRC.15-2023-PDF-E.pdf">resolved
|
||||
in 2023</a> to cooperate with this process. One proposal to implement this
|
||||
in 2023</a> to cooperate with this process. A draft <a
|
||||
href="https://www.bipm.org/documents/d/guest/cgpm-2026-draft-resolutions">Resolution
|
||||
C to make continuous UTC effective on 2027-05-20</a>,
|
||||
and thereby discontinue leap seconds,
|
||||
has been scheduled for the 28th CGPM starting 2026-10-13 in Paris.
|
||||
One proposal to implement this
|
||||
would replace leap seconds with seven 13-second leap smears occurring once per
|
||||
decade until 2100, with leap smears after that gradually increasing in size.
|
||||
See:
|
||||
<ul>
|
||||
<li>Levine J. <a href="https://www.preprints.org/manuscript/202406.0043">A
|
||||
<li>Levine J. <a href="https://tf.nist.gov/general/pdf/3242.pdf">A
|
||||
proposal to change the leap-second adjustments to
|
||||
coordinated universal time</a>. <em>Metrologia.</em> 2024;61(5):055002. doi:<a
|
||||
href="https://doi.org/10.1088/1681-7575/ad6266">10.1088/1681-7575/ad6266</a>.</li>
|
||||
href="https://doi.org/10.1088/1681-7575/ad6266">10.1088/1681-7575/ad6266</a>
|
||||
with followups in doi:<a
|
||||
href="https://doi.org/10.1088/1681-7575/ade314">10.1088/1681-7575/ade314</a>
|
||||
and doi:<a
|
||||
href="https://doi.org/10.1088/1681-7575/ade315">10.1088/1681-7575/ade315</a>.</li>
|
||||
</ul>
|
||||
However, there is still no consensus on whether this is the best way
|
||||
to replace leap seconds.
|
||||
|
||||
@@ -253,11 +253,13 @@ symlink(char const *target, char const *linkname)
|
||||
(errno = ENOTSUP, -1)
|
||||
#endif
|
||||
|
||||
static int addabbr(char[TZ_MAX_CHARS], int *, char const *);
|
||||
static void addtt(zic_t starttime, int type);
|
||||
static int addtype(zic_t, char const *, bool, bool, bool);
|
||||
static void leapadd(zic_t, int, int);
|
||||
static void adjleap(void);
|
||||
static void associate(void);
|
||||
static void checkabbr(char const *);
|
||||
static void check_for_signal(void);
|
||||
static void dolink(const char *, const char *, bool);
|
||||
static int getfields(char *, char **, int);
|
||||
static zic_t gethms(const char * string, const char * errstring);
|
||||
@@ -270,11 +272,11 @@ static void inrule(char ** fields, int nfields);
|
||||
static bool inzcont(char ** fields, int nfields);
|
||||
static bool inzone(char ** fields, int nfields);
|
||||
static bool inzsub(char **, int, bool);
|
||||
static int itssymlink(char const *, int *);
|
||||
static bool is_alpha(char a);
|
||||
static int itssymlink(char const *, int *);
|
||||
static void leapadd(zic_t, int, int);
|
||||
static char lowerit(char);
|
||||
static void mkdirs(char const *, bool);
|
||||
static void newabbr(const char * abbr);
|
||||
static zic_t oadd(zic_t t1, zic_t t2);
|
||||
static zic_t omul(zic_t, zic_t);
|
||||
static void outzone(const struct zone * zp, ptrdiff_t ntzones);
|
||||
@@ -704,6 +706,7 @@ eat(int fnum, lineno num)
|
||||
ATTRIBUTE_FORMAT((printf, 1, 0)) static void
|
||||
verror(const char *const string, va_list args)
|
||||
{
|
||||
check_for_signal();
|
||||
/*
|
||||
** Match the format of "cc" to allow sh users to
|
||||
** zic ... 2>&1 | error -t "*" -v
|
||||
@@ -1074,6 +1077,7 @@ make_links(void)
|
||||
warning(_("link %s targeting link %s"),
|
||||
links[i].l_linkname, links[i].l_target);
|
||||
}
|
||||
check_for_signal();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1391,6 +1395,7 @@ main(int argc, char **argv)
|
||||
for (j = i + 1; j < nzones && zones[j].z_name == NULL; ++j)
|
||||
continue;
|
||||
outzone(&zones[i], j - i);
|
||||
check_for_signal();
|
||||
}
|
||||
make_links();
|
||||
if (lcltime != NULL) {
|
||||
@@ -1486,9 +1491,11 @@ get_rand_u64(void)
|
||||
static int nwords;
|
||||
if (!nwords) {
|
||||
ssize_t s;
|
||||
do
|
||||
for (;; check_for_signal()) {
|
||||
s = getrandom(entropy_buffer, sizeof entropy_buffer, 0);
|
||||
while (s < 0 && errno == EINTR);
|
||||
if (! (s < 0 && errno == EINTR))
|
||||
break;
|
||||
}
|
||||
|
||||
nwords = s < 0 ? -1 : s / sizeof *entropy_buffer;
|
||||
}
|
||||
@@ -1516,7 +1523,7 @@ get_rand_u64(void)
|
||||
rmod = INT_MAX < UINT_FAST64_MAX ? 0 : UINT_FAST64_MAX / nrand + 1,
|
||||
r = 0, rmax = 0;
|
||||
|
||||
do {
|
||||
for (;; check_for_signal()) {
|
||||
uint_fast64_t rmax1 = rmax;
|
||||
if (rmod) {
|
||||
/* Avoid signed integer overflow on theoretical platforms
|
||||
@@ -1527,7 +1534,9 @@ get_rand_u64(void)
|
||||
rmax1 = nrand * rmax1 + rand_max;
|
||||
r = nrand * r + rand();
|
||||
rmax = rmax < rmax1 ? rmax1 : UINT_FAST64_MAX;
|
||||
} while (rmax < UINT_FAST64_MAX);
|
||||
if (UINT_FAST64_MAX <= rmax)
|
||||
break;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
@@ -1574,9 +1583,11 @@ random_dirent(char const **name, char **namealloc)
|
||||
*name = *namealloc = dst;
|
||||
}
|
||||
|
||||
do
|
||||
for (;; check_for_signal()) {
|
||||
r = get_rand_u64();
|
||||
while (unfair_min <= r);
|
||||
if (r < unfair_min)
|
||||
break;
|
||||
}
|
||||
|
||||
for (i = 0; i < suffixlen; i++) {
|
||||
dst[dirlen + prefixlen + i] = alphabet[r % alphabetlen];
|
||||
@@ -1611,7 +1622,7 @@ open_outfile(char const **outname, char **tempname)
|
||||
if (!*tempname)
|
||||
random_dirent(outname, tempname);
|
||||
|
||||
while (true) {
|
||||
for (;; check_for_signal()) {
|
||||
int oflags = O_WRONLY | O_BINARY | O_CREAT | O_EXCL;
|
||||
int fd = open(*outname, oflags, creat_perms);
|
||||
int err;
|
||||
@@ -1725,8 +1736,6 @@ dolink(char const *target, char const *linkname, bool staysymlink)
|
||||
char const *outname = linkname;
|
||||
int targetissym = -2, linknameissym = -2;
|
||||
|
||||
check_for_signal();
|
||||
|
||||
if (strcmp(target, "-") == 0) {
|
||||
if (remove(linkname) == 0 || errno == ENOENT || errno == ENOTDIR)
|
||||
return;
|
||||
@@ -1739,7 +1748,7 @@ dolink(char const *target, char const *linkname, bool staysymlink)
|
||||
}
|
||||
}
|
||||
|
||||
while (true) {
|
||||
for (;; check_for_signal()) {
|
||||
if (linkat(AT_FDCWD, target, AT_FDCWD, outname, AT_SYMLINK_FOLLOW)
|
||||
== 0) {
|
||||
link_errno = 0;
|
||||
@@ -1791,7 +1800,7 @@ dolink(char const *target, char const *linkname, bool staysymlink)
|
||||
int symlink_errno = -1;
|
||||
|
||||
if (contents) {
|
||||
while (true) {
|
||||
for (;; check_for_signal()) {
|
||||
if (symlink(contents, outname) == 0) {
|
||||
symlink_errno = 0;
|
||||
break;
|
||||
@@ -1822,7 +1831,7 @@ dolink(char const *target, char const *linkname, bool staysymlink)
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
tp = open_outfile(&outname, &tempname);
|
||||
while ((c = getc(fp)) != EOF)
|
||||
for (; (c = getc(fp)) != EOF; check_for_signal())
|
||||
putc(c, tp);
|
||||
close_file(tp, directory, linkname, tempname);
|
||||
close_file(fp, directory, target, NULL);
|
||||
@@ -1946,7 +1955,7 @@ static bool
|
||||
inputline(FILE *fp, char *buf, ptrdiff_t bufsize)
|
||||
{
|
||||
ptrdiff_t linelen = 0, ch;
|
||||
while ((ch = getc(fp)) != '\n') {
|
||||
for (; (ch = getc(fp)) != '\n'; check_for_signal()) {
|
||||
if (ch < 0) {
|
||||
if (ferror(fp)) {
|
||||
error(_("input error"));
|
||||
@@ -2033,6 +2042,7 @@ infile(int fnum, char const *name)
|
||||
default: unreachable();
|
||||
}
|
||||
}
|
||||
check_for_signal();
|
||||
}
|
||||
close_file(fp, NULL, filename(fnum), NULL);
|
||||
if (wantcont)
|
||||
@@ -2927,30 +2937,27 @@ writezone(const char *const name, const char *const string, char version,
|
||||
: i == thisdefaulttype ? old0 : i]
|
||||
= thistypecnt++;
|
||||
|
||||
for (i = 0; i < sizeof indmap / sizeof indmap[0]; ++i)
|
||||
indmap[i] = -1;
|
||||
thischarcnt = stdcnt = utcnt = 0;
|
||||
for (i = old0; i < typecnt; i++) {
|
||||
register char * thisabbr;
|
||||
|
||||
if (omittype[i])
|
||||
continue;
|
||||
if (ttisstds[i])
|
||||
stdcnt = thistypecnt;
|
||||
if (ttisuts[i])
|
||||
utcnt = thistypecnt;
|
||||
if (indmap[desigidx[i]] >= 0)
|
||||
continue;
|
||||
thisabbr = &chars[desigidx[i]];
|
||||
for (j = 0; j < thischarcnt; ++j)
|
||||
if (strcmp(&thischars[j], thisabbr) == 0)
|
||||
break;
|
||||
if (j == thischarcnt) {
|
||||
strcpy(&thischars[thischarcnt], thisabbr);
|
||||
thischarcnt += strlen(thisabbr) + 1;
|
||||
}
|
||||
indmap[desigidx[i]] = j;
|
||||
addabbr(thischars, &thischarcnt, &chars[desigidx[i]]);
|
||||
}
|
||||
|
||||
/* Now that all abbrevs have been added to THISCHARS,
|
||||
it is safe to set INDMAP without worrying about
|
||||
whether the abbrevs might move later. */
|
||||
for (i = 0; i < TZ_MAX_CHARS; i++)
|
||||
indmap[i] = -1;
|
||||
for (i = old0; i < typecnt; i++)
|
||||
if (!omittype[i] && indmap[desigidx[i]] < 0)
|
||||
indmap[desigidx[i]] = addabbr(thischars, &thischarcnt,
|
||||
&chars[desigidx[i]]);
|
||||
|
||||
if (pass == 1 && !want_bloat()) {
|
||||
hicut = thisleapexpiry = false;
|
||||
pretranstype = -1;
|
||||
@@ -3173,11 +3180,11 @@ stringoffset(char *result, zic_t offset)
|
||||
offset /= SECSPERMIN;
|
||||
minutes = offset % MINSPERHOUR;
|
||||
offset /= MINSPERHOUR;
|
||||
hours = offset;
|
||||
if (hours >= HOURSPERDAY * DAYSPERWEEK) {
|
||||
if (offset >= HOURSPERDAY * DAYSPERWEEK) {
|
||||
result[0] = '\0';
|
||||
return 0;
|
||||
}
|
||||
hours = offset;
|
||||
len += sprintf(result + len, "%d", hours);
|
||||
if (minutes != 0 || seconds != 0) {
|
||||
len += sprintf(result + len, ":%02d", minutes);
|
||||
@@ -3416,12 +3423,16 @@ outzone(const struct zone *zpfirst, ptrdiff_t zonecount)
|
||||
int nonTZlimtype = -1;
|
||||
zic_t max_year0;
|
||||
int defaulttype = -1;
|
||||
int max_stringoffset_len = sizeof "-167:59:59" - 1;
|
||||
int max_comma_stringrule_len = (sizeof ",M12.5.6/" - 1
|
||||
+ max_stringoffset_len);
|
||||
|
||||
check_for_signal();
|
||||
|
||||
/* This cannot overflow; see FORMAT_LEN_GROWTH_BOUND. */
|
||||
max_abbr_len = 2 + max_format_len + max_abbrvar_len;
|
||||
max_envvar_len = 2 * max_abbr_len + 5 * 9;
|
||||
max_envvar_len = 2 * (max_abbr_len + max_stringoffset_len
|
||||
+ max_comma_stringrule_len);
|
||||
|
||||
startbuf = xmalloc(max_abbr_len + 1);
|
||||
ab = xmalloc(max_abbr_len + 1);
|
||||
@@ -3522,7 +3533,7 @@ outzone(const struct zone *zpfirst, ptrdiff_t zonecount)
|
||||
startttisut);
|
||||
if (usestart) {
|
||||
addtt(starttime, type);
|
||||
if (useuntil && nonTZlimtime < starttime) {
|
||||
if (nonTZlimtime < starttime) {
|
||||
nonTZlimtime = starttime;
|
||||
nonTZlimtype = type;
|
||||
}
|
||||
@@ -3769,6 +3780,7 @@ static int
|
||||
addtype(zic_t utoff, char const *abbr, bool isdst, bool ttisstd, bool ttisut)
|
||||
{
|
||||
register int i, j;
|
||||
int charcnt0;
|
||||
|
||||
/* RFC 9636 section 3.2 specifies this range for utoff. */
|
||||
if (! (-TWO_31_MINUS_1 <= utoff && utoff <= TWO_31_MINUS_1)) {
|
||||
@@ -3778,12 +3790,18 @@ addtype(zic_t utoff, char const *abbr, bool isdst, bool ttisstd, bool ttisut)
|
||||
if (!want_bloat())
|
||||
ttisstd = ttisut = false;
|
||||
|
||||
for (j = 0; j < charcnt; ++j)
|
||||
if (strcmp(&chars[j], abbr) == 0)
|
||||
break;
|
||||
if (j == charcnt)
|
||||
newabbr(abbr);
|
||||
else {
|
||||
checkabbr(abbr);
|
||||
|
||||
charcnt0 = charcnt;
|
||||
j = addabbr(chars, &charcnt, abbr);
|
||||
if (charcnt0 < charcnt) {
|
||||
/* If an abbreviation was inserted, increment indexes no
|
||||
earlier than the insert by the size of the insertion,
|
||||
so that they continue to point to the same contents. */
|
||||
for (i = 0; i < typecnt; i++)
|
||||
if (j <= desigidx[i])
|
||||
desigidx[i] += charcnt - charcnt0;
|
||||
} else {
|
||||
/* If there's already an entry, return its index. */
|
||||
for (i = 0; i < typecnt; i++)
|
||||
if (utoff == utoffs[i] && isdst == isdsts[i] && j == desigidx[i]
|
||||
@@ -4168,10 +4186,8 @@ will not work with pre-2004 versions of zic"));
|
||||
}
|
||||
|
||||
static void
|
||||
newabbr(const char *string)
|
||||
checkabbr(char const *string)
|
||||
{
|
||||
register int i;
|
||||
|
||||
if (strcmp(string, GRANDPARENTED) != 0) {
|
||||
register const char * cp;
|
||||
const char * mp;
|
||||
@@ -4190,13 +4206,50 @@ mp = _("time zone abbreviation differs from POSIX standard");
|
||||
if (mp != NULL)
|
||||
warning("%s (%s)", mp, string);
|
||||
}
|
||||
i = strnlen(string, TZ_MAX_CHARS - charcnt) + 1;
|
||||
if (charcnt + i > TZ_MAX_CHARS) {
|
||||
error(_("too many, or too long, time zone abbreviations"));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
strcpy(&chars[charcnt], string);
|
||||
charcnt += i;
|
||||
}
|
||||
|
||||
/* Put into CHS, which currently contains *PNCHS bytes containing
|
||||
NUL-terminated abbreviations none of which are suffixes of another,
|
||||
the abbreviation ABBR including its trailing NUL.
|
||||
If ABBR does not already appear in CHS,
|
||||
possibly as a suffix of an existing abbreviation,
|
||||
add ABBR to CHS, remove from CHS any abbreviation
|
||||
that is a suffix of ABBR, and increment *PNCHS accordingly.
|
||||
Return the index of ABBR after any modifications to CHS are made.
|
||||
|
||||
If all abbreviations have already been added, this function
|
||||
lets the caller look up the index of an existing abbreviation. */
|
||||
static int
|
||||
addabbr(char chs[TZ_MAX_CHARS], int *pnchs, char const *abbr)
|
||||
{
|
||||
int nchs = *pnchs;
|
||||
int alen = strlen(abbr), nchs_incr = alen + 1;
|
||||
int i;
|
||||
for (i = 0; i < nchs; ) {
|
||||
int clen = strlen(&chs[i]);
|
||||
if (alen <= clen) {
|
||||
/* If ABBR is a suffix of an abbreviation in CHS,
|
||||
return the index of ABBR in CHS. */
|
||||
int isuff = i + (clen - alen);
|
||||
if (memcmp(&chs[isuff], abbr, alen) == 0)
|
||||
return isuff;
|
||||
} else if (memcmp(&chs[i], &abbr[alen - clen], clen) == 0) {
|
||||
/* An abbreviation in CHS is a substring of ABBR.
|
||||
Replace it with ABBR, instead of the more-common
|
||||
actions of appending ABBR or doing nothing. */
|
||||
nchs_incr = alen - clen;
|
||||
break;
|
||||
}
|
||||
i += clen + 1;
|
||||
}
|
||||
if (TZ_MAX_CHARS < nchs + nchs_incr) {
|
||||
error(_("too many, or too long, time zone abbreviations"));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
memmove(&chs[i + nchs_incr], &chs[i], nchs - i);
|
||||
memcpy(&chs[i], abbr, nchs_incr);
|
||||
*pnchs = nchs + nchs_incr;
|
||||
return i;
|
||||
}
|
||||
|
||||
/* Ensure that the directories of ARGNAME exist, by making any missing
|
||||
|
||||
Reference in New Issue
Block a user