Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 30 Apr 2026 15:04:12 +0000
From:      Dag-Erling=?utf-8?Q? Sm=C3=B8rg?=rav <des@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org
Subject:   git: b72580fcb0a7 - stable/15 - tzcode: Update to 2026b
Message-ID:  <69f36f6c.3fb61.643fa71c@gitrepo.freebsd.org>

index | next in thread | raw e-mail

The branch stable/15 has been updated by des:

URL: https://cgit.FreeBSD.org/src/commit/?id=b72580fcb0a7647dcc2b18861ac02eb9cfcf5835

commit b72580fcb0a7647dcc2b18861ac02eb9cfcf5835
Author:     Dag-Erling Smørgrav <des@FreeBSD.org>
AuthorDate: 2026-04-24 20:07:20 +0000
Commit:     Dag-Erling Smørgrav <des@FreeBSD.org>
CommitDate: 2026-04-30 15:02:03 +0000

    tzcode: Update to 2026b
    
    MFC after:      1 week
    
    (cherry picked from commit 76f642310d55b1d3892c1b1626c427d12f97de3a)
---
 contrib/tzcode/NEWS         |  53 ++++++++++++---
 contrib/tzcode/tz-art.html  |   2 +-
 contrib/tzcode/tz-link.html |  22 +++++--
 contrib/tzcode/version      |   2 +-
 contrib/tzcode/zic.c        | 156 +++++++++++++++++++++++++++++---------------
 5 files changed, 166 insertions(+), 69 deletions(-)

diff --git a/contrib/tzcode/NEWS b/contrib/tzcode/NEWS
index acd22280cb3a..ea52e67e804a 100644
--- a/contrib/tzcode/NEWS
+++ b/contrib/tzcode/NEWS
@@ -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.
diff --git a/contrib/tzcode/tz-art.html b/contrib/tzcode/tz-art.html
index 1bd1bf781166..7870a6187390 100644
--- a/contrib/tzcode/tz-art.html
+++ b/contrib/tzcode/tz-art.html
@@ -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
diff --git a/contrib/tzcode/tz-link.html b/contrib/tzcode/tz-link.html
index 5f1989f014b3..4d2c12b09452 100644
--- a/contrib/tzcode/tz-link.html
+++ b/contrib/tzcode/tz-link.html
@@ -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.
diff --git a/contrib/tzcode/version b/contrib/tzcode/version
index 5d9126009e7f..75d34ee38931 100644
--- a/contrib/tzcode/version
+++ b/contrib/tzcode/version
@@ -1 +1 @@
-2026a
+2026b
diff --git a/contrib/tzcode/zic.c b/contrib/tzcode/zic.c
index d1084b4a25e9..f4c1aa6d54e6 100644
--- a/contrib/tzcode/zic.c
+++ b/contrib/tzcode/zic.c
@@ -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;
+    }
 
     if (s < 0)
       nwords = -1;
@@ -1519,7 +1526,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
@@ -1530,7 +1537,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;
   }
@@ -1577,9 +1586,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];
@@ -1622,7 +1633,7 @@ open_outfile(char const **outname, char **tempname)
     exit(EXIT_FAILURE);
   }
 
-  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;
@@ -1736,8 +1747,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;
@@ -1750,7 +1759,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;
@@ -1802,7 +1811,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;
@@ -1833,7 +1842,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);
@@ -1957,7 +1966,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"));
@@ -2044,6 +2053,7 @@ infile(int fnum, char const *name)
 				default: unreachable();
 			}
 		}
+		check_for_signal();
 	}
 	close_file(fp, NULL, filename(fnum), NULL);
 	if (wantcont)
@@ -2657,7 +2667,6 @@ writezone(const char *const name, const char *const string, char version,
 {
 	register FILE *			fp;
 	register ptrdiff_t		i, j;
-	register size_t			u;
 	register int			pass;
 	char *tempname = NULL;
 	char const *outname = name;
@@ -2939,30 +2948,27 @@ writezone(const char *const name, const char *const string, char version,
 			    : i == thisdefaulttype ? old0 : i]
 		      = thistypecnt++;
 
-		for (u = 0; u < sizeof indmap / sizeof indmap[0]; ++u)
-			indmap[u] = -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;
@@ -3185,11 +3191,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);
@@ -3428,12 +3434,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);
@@ -3534,7 +3544,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;
 				}
@@ -3781,6 +3791,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)) {
@@ -3790,12 +3801,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]
@@ -4180,10 +4197,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;
@@ -4202,13 +4217,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


home | help

Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?69f36f6c.3fb61.643fa71c>