Module Name:    src
Committed By:   christos
Date:           Tue Apr 28 17:00:24 UTC 2015

Modified Files:
        src/lib/libc/time: Makefile NEWS private.h tz-link.htm zic.c
Removed Files:
        src/lib/libc/time: ialloc.c scheck.c

Log Message:
welcome to tzcode 2015d (zic performance improvements and cleanups)


To generate a diff of this commit:
cvs rdiff -u -r1.27 -r1.28 src/lib/libc/time/Makefile
cvs rdiff -u -r1.10 -r1.11 src/lib/libc/time/NEWS
cvs rdiff -u -r1.9 -r0 src/lib/libc/time/ialloc.c
cvs rdiff -u -r1.39 -r1.40 src/lib/libc/time/private.h
cvs rdiff -u -r1.12 -r0 src/lib/libc/time/scheck.c
cvs rdiff -u -r1.21 -r1.22 src/lib/libc/time/tz-link.htm
cvs rdiff -u -r1.52 -r1.53 src/lib/libc/time/zic.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/lib/libc/time/Makefile
diff -u src/lib/libc/time/Makefile:1.27 src/lib/libc/time/Makefile:1.28
--- src/lib/libc/time/Makefile:1.27	Tue Mar 24 16:01:18 2015
+++ src/lib/libc/time/Makefile	Tue Apr 28 13:00:24 2015
@@ -5,7 +5,7 @@
 PACKAGE=	tzcode
 
 # Version numbers of the code and data distributions.
-VERSION=	2015b
+VERSION=	2015d
 
 # Email address for bug reports.
 BUGEMAIL=	t...@iana.org
@@ -120,6 +120,7 @@ LDLIBS=
 #  -DHAVE_STDINT_H=1 if you have a pre-C99 compiler with "stdint.h"
 #  -DHAVE_STRFTIME_L=1 if <time.h> declares locale_t and strftime_l
 #	This defaults to 0 if _POSIX_VERSION < 200809, 1 otherwise.
+#  -DHAVE_STRDUP=0 if your system lacks the strdup 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_WAIT_H=0 if your compiler lacks a "sys/wait.h"
@@ -150,18 +151,18 @@ LDLIBS=
 #  $(GCC_DEBUG_FLAGS) if you are using GCC and want lots of checking
 GCC_DEBUG_FLAGS = -Dlint -g3 -O3 -fno-common -fstrict-aliasing \
 	-Wall -Wextra \
-	-Wbad-function-cast -Wcast-align -Wcast-qual \
+	-Wbad-function-cast -Wcast-align -Wdate-time \
 	-Wdeclaration-after-statement \
+	-Wdouble-promotion \
 	-Wformat=2 -Winit-self -Wjump-misses-init \
-	-Wmissing-declarations -Wmissing-noreturn -Wmissing-prototypes \
-	-Wnested-externs -Wno-address -Wno-cast-qual \
-	-Wno-format-nonliteral -Wno-sign-compare -Wno-sign-conversion \
-	-Wno-type-limits \
-	-Wno-unused-parameter -Woverlength-strings -Wpointer-arith \
+	-Wlogical-op -Wmissing-prototypes -Wnested-externs \
+	-Wold-style-definition -Woverlength-strings -Wpointer-arith \
 	-Wshadow -Wstrict-prototypes -Wsuggest-attribute=const \
 	-Wsuggest-attribute=format -Wsuggest-attribute=noreturn \
 	-Wsuggest-attribute=pure -Wtrampolines \
-	-Wwrite-strings
+	-Wunused -Wwrite-strings \
+	-Wno-address -Wno-format-nonliteral -Wno-sign-compare \
+	-Wno-type-limits -Wno-unused-parameter
 #
 # If you want to use System V compatibility code, add
 #	-DUSG_COMPAT
@@ -331,13 +332,13 @@ AR=		ar
 # ':' on typical hosts; 'ranlib' on the ancient hosts that still need ranlib.
 RANLIB=		:
 
-TZCOBJS=	zic.o scheck.o ialloc.o
+TZCOBJS=	zic.o
 TZDOBJS=	zdump.o localtime.o asctime.o
 DATEOBJS=	date.o localtime.o strftime.o asctime.o
 LIBSRCS=	localtime.c asctime.c difftime.c
 LIBOBJS=	localtime.o asctime.o difftime.o
 HEADERS=	tzfile.h private.h
-NONLIBSRCS=	zic.c zdump.c scheck.c ialloc.c
+NONLIBSRCS=	zic.c zdump.c
 NEWUCBSRCS=	date.c strftime.c
 SOURCES=	$(HEADERS) $(LIBSRCS) $(NONLIBSRCS) $(NEWUCBSRCS) \
 			tzselect.ksh workman.sh
@@ -655,9 +656,7 @@ zonenames:	$(TDATA)
 asctime.o:	private.h tzfile.h
 date.o:		private.h
 difftime.o:	private.h
-ialloc.o:	private.h
 localtime.o:	private.h tzfile.h
-scheck.o:	private.h
 strftime.o:	private.h tzfile.h
 zdump.o:	version.h
 zic.o:		private.h tzfile.h version.h

Index: src/lib/libc/time/NEWS
diff -u src/lib/libc/time/NEWS:1.10 src/lib/libc/time/NEWS:1.11
--- src/lib/libc/time/NEWS:1.10	Tue Mar 24 16:01:18 2015
+++ src/lib/libc/time/NEWS	Tue Apr 28 13:00:24 2015
@@ -1,5 +1,79 @@
 News for the tz database
 
+Release 2015d - 2015-04-24 08:09:46 -0700
+
+  Changes affecting future time stamps
+
+    Egypt will not observe DST in 2015 and will consider canceling it
+    permanently.  For now, assume no DST indefinitely.
+    (Thanks to Ahmed Nazmy and Tim Parenti.)
+
+  Changes affecting past time stamps
+
+    America/Whitehorse switched from UTC-9 to UTC-8 on 1967-05-28, not
+    1966-07-01.  Also, Yukon's time zone history is documented better.
+    (Thanks to Brian Inglis and Dennis Ferguson.)
+
+  Change affecting past and future time zone abbreviations
+
+    The abbreviations for Hawaii-Aleutian standard and daylight times
+    have been changed from HAST/HADT to HST/HDT, as per US Government
+    Printing Office style.  This affects only America/Adak since 1983,
+    as America/Honolulu was already using the new style.
+
+  Changes affecting code
+
+   zic has some minor performance improvements.
+
+
+Release 2015c - 2015-04-11 08:55:55 -0700
+
+  Changes affecting future time stamps
+
+    Egypt's spring-forward transition is at 24:00 on April's last Thursday,
+    not 00:00 on April's last Friday.  2015's transition will therefore be on
+    Thursday, April 30 at 24:00, not Friday, April 24 at 00:00.  Similar fixes
+    apply to 2026, 2037, 2043, etc.  (Thanks to Steffen Thorsen.)
+
+  Changes affecting past time stamps
+
+    The following changes affect some pre-1991 Chile-related time stamps
+    in America/Santiago, Antarctica/Palmer, and Pacific/Easter.
+
+      The 1910 transition was January 10, not January 1.
+
+      The 1918 transition was September 10, not September 1.
+
+      The UTC-4 time observed from 1932 to 1942 is now considered to be
+      standard time, not year-round DST.
+
+      Santiago observed DST (UTC-3) from 1946-07-15 through 1946-08-31,
+      then reverted to standard time, then switched its time zone to
+      UTC-5 on 1947-04-01.
+
+      Assume transitions before 1968 were at 00:00, since we have no data
+      saying otherwise.
+
+      The spring 1988 transition was 1988-10-09, not 1988-10-02.
+      The fall 1990 transition was 1990-03-11, not 1990-03-18.
+
+      Assume no UTC offset change for Pacific/Easter on 1890-01-01,
+      and omit all transitions on Pacific/Easter from 1942 through 1946
+      since we have no data suggesting that they existed.
+
+    One more zone has been turned into a link, as it differed
+    from an existing zone only for older time stamps.  As usual,
+    this change affects UTC offsets in pre-1970 time stamps only.
+    The zone's old contents have been moved to the 'backzone' file.
+    The affected zone is America/Montreal.
+
+  Changes affecting commentary
+
+    Mention the TZUpdater tool.
+
+    Mention "The Time Now".  (Thanks to Brandon Ramsey.)
+
+
 Release 2015b - 2015-03-19 23:28:11 -0700
 
   Changes affecting future time stamps

Index: src/lib/libc/time/private.h
diff -u src/lib/libc/time/private.h:1.39 src/lib/libc/time/private.h:1.40
--- src/lib/libc/time/private.h:1.39	Tue Mar 24 16:01:18 2015
+++ src/lib/libc/time/private.h	Tue Apr 28 13:00:24 2015
@@ -1,4 +1,4 @@
-/*	$NetBSD: private.h,v 1.39 2015/03/24 20:01:18 christos Exp $	*/
+/*	$NetBSD: private.h,v 1.40 2015/04/28 17:00:24 christos Exp $	*/
 
 #ifndef PRIVATE_H
 #define PRIVATE_H
@@ -54,6 +54,10 @@
 #define HAVE_SETTIMEOFDAY	3
 #endif /* !defined HAVE_SETTIMEOFDAY */
 
+#ifndef HAVE_STRDUP
+#define HAVE_STRDUP 1
+#endif
+
 #ifndef HAVE_SYMLINK
 #define HAVE_SYMLINK		1
 #endif /* !defined HAVE_SYMLINK */
@@ -467,14 +471,6 @@ time_t time2posix_z(timezone_t __restric
 #endif
 
 /*
-** Private function declarations.
-*/
-
-char *		icatalloc(char * old, const char * new);
-char *		icpyalloc(const char * string);
-const char *	scheck(const char * string, const char * format);
-
-/*
 ** Finally, some convenience items.
 */
 

Index: src/lib/libc/time/tz-link.htm
diff -u src/lib/libc/time/tz-link.htm:1.21 src/lib/libc/time/tz-link.htm:1.22
--- src/lib/libc/time/tz-link.htm:1.21	Sat Jan 31 13:55:17 2015
+++ src/lib/libc/time/tz-link.htm	Tue Apr 28 13:00:24 2015
@@ -8,7 +8,7 @@
 <meta http-equiv="Content-type" content='text/html; charset="UTF-8"'>
 <meta name="DC.Creator" content="Eggert, Paul">
 <meta name="DC.Contributor" content="Olson, Arthur David">
-<meta name="DC.Date" content="2015-01-29">
+<meta name="DC.Date" content="2015-03-25">
 <meta name="DC.Description"
  content="Sources of information about time zones and daylight saving time">
 <meta name="DC.Identifier"
@@ -194,6 +194,7 @@ multiple time zones.</li>
 <li><a href="http://www.zeitverschiebung.net/en/";>Time Difference</a>
 calculates the current time difference between locations.</li>
 <li><a href="http://www.wx-now.com";>Weather Now</a> lists the weather too.</li>
+<li><a href="http://www.thetimenow.com";>The Time Now</a> also lists weather.</li>
 <li><a href="http://worldtime.io";>worldtime.io</a>
 also contains data about time zone boundaries; it supports queries via place
 names and shows location maps.</li>
@@ -282,6 +283,10 @@ and from <abbr title="Common Locale Data
 into an <abbr>ICU</abbr>-specific format.
 <abbr>ICU</abbr> is freely available under a
 <abbr>BSD</abbr>-style license.</li>
+<li>The <a
+href="http://www.oracle.com/technetwork/java/javase/tzupdater-readme-136440.html";>TZUpdater
+tool</a> compiles <code><abbr>tz</abbr></code> source into the format used by
+Oracle Java.</li>
 <li><a href="http://www.joda.org/joda-time/";>Joda-Time &ndash; Java date
 and time <abbr title="Application Program Interface">API</abbr></a>
 contains a class

Index: src/lib/libc/time/zic.c
diff -u src/lib/libc/time/zic.c:1.52 src/lib/libc/time/zic.c:1.53
--- src/lib/libc/time/zic.c:1.52	Tue Oct  7 18:14:46 2014
+++ src/lib/libc/time/zic.c	Tue Apr 28 13:00:24 2015
@@ -1,4 +1,4 @@
-/*	$NetBSD: zic.c,v 1.52 2014/10/07 22:14:46 christos Exp $	*/
+/*	$NetBSD: zic.c,v 1.53 2015/04/28 17:00:24 christos Exp $	*/
 /*
 ** This file is in the public domain, so clarified as of
 ** 2006-07-17 by Arthur David Olson.
@@ -10,7 +10,7 @@
 
 #include <sys/cdefs.h>
 #ifndef lint
-__RCSID("$NetBSD: zic.c,v 1.52 2014/10/07 22:14:46 christos Exp $");
+__RCSID("$NetBSD: zic.c,v 1.53 2015/04/28 17:00:24 christos Exp $");
 #endif /* !defined lint */
 
 #include "private.h"
@@ -41,8 +41,6 @@ typedef int_fast64_t	zic_t;
 #define MKDIR_UMASK 0755
 #endif
 
-#define end(cp)	(strchr((cp), '\0'))
-
 struct rule {
 	const char *	r_filename;
 	int		r_linenum;
@@ -381,18 +379,40 @@ size_product(size_t nitems, size_t items
 	return nitems * itemsize;
 }
 
+#if !HAVE_STRDUP
+static char *
+strdup(char const *str)
+{
+	char *result = malloc(strlen(str) + 1);
+	return result ? strcpy(result, str) : result;
+}
+#endif
+
 static ATTRIBUTE_PURE void *
-memcheck(void *const ptr)
+memcheck(void *ptr)
 {
 	if (ptr == NULL)
 		memory_exhausted(strerror(errno));
 	return ptr;
 }
 
-#define emalloc(size)		memcheck(malloc(size))
-#define erealloc(ptr, size)	memcheck(realloc((ptr), (size)))
-#define ecpyalloc(ptr)		memcheck(icpyalloc(ptr))
-#define ecatalloc(oldp, newp)	memcheck(icatalloc((oldp), (newp)))
+static void *
+zic_malloc(size_t size)
+{
+	return memcheck(malloc(size));
+}
+
+static void *
+zic_realloc(void *ptr, size_t size)
+{
+	return memcheck(realloc(ptr, size));
+}
+
+static char *
+ecpyalloc(char const *str)
+{
+	return memcheck(strdup(str));
+}
 
 static void *
 growalloc(void *ptr, size_t itemsize, int nitems, int *nitems_alloc)
@@ -404,7 +424,7 @@ growalloc(void *ptr, size_t itemsize, in
 		if ((amax - 1) / 3 * 2 < *nitems_alloc)
 			memory_exhausted(_("int overflow"));
 		*nitems_alloc = *nitems_alloc + (*nitems_alloc >> 1) + 1;
-		return erealloc(ptr, size_product(*nitems_alloc, itemsize));
+		return zic_realloc(ptr, size_product(*nitems_alloc, itemsize));
 	}
 }
 
@@ -647,6 +667,11 @@ componentcheck(char const *name, char co
 {
 	enum { component_len_max = 14 };
 	size_t component_len = component_end - component;
+	if (component_len == 0) {
+		fprintf(stderr, _("%s: file name '%s' contains empty component"),
+			progname, name);
+		exit(EXIT_FAILURE);
+	}
 	if (0 < component_len && component_len <= 2
 	    && component[0] == '.' && component_end[-1] == '.') {
 		fprintf(stderr, _("%s: file name '%s' contains"
@@ -699,6 +724,21 @@ namecheck(const char *name)
 	componentcheck(name, component, cp);
 }
 
+static char *
+relname(char const *dir, char const *base)
+{
+	if (*base == '/')
+		return ecpyalloc(base);
+	else {
+		size_t dir_len = strlen(dir);
+		bool needs_slash = dir_len && dir[dir_len - 1] != '/';
+		char *result = zic_malloc(dir_len + needs_slash + strlen(base) + 1);
+		result[dir_len] = '/';
+		strcpy(result + dir_len + needs_slash, base);
+		return memcpy(result, dir, dir_len);
+	}
+}
+
 static void
 dolink(const char *const fromfield, const char *const tofield)
 {
@@ -707,20 +747,8 @@ dolink(const char *const fromfield, cons
 	int fromisdir;
 
 	namecheck(tofield);
-	if (fromfield[0] == '/')
-		fromname = ecpyalloc(fromfield);
-	else {
-		fromname = ecpyalloc(directory);
-		fromname = ecatalloc(fromname, "/");
-		fromname = ecatalloc(fromname, fromfield);
-	}
-	if (tofield[0] == '/')
-		toname = ecpyalloc(tofield);
-	else {
-		toname = ecpyalloc(directory);
-		toname = ecatalloc(toname, "/");
-		toname = ecatalloc(toname, tofield);
-	}
+	fromname = relname(directory, fromfield);
+	toname = relname(directory, tofield);
 	/*
 	** We get to be careful here since
 	** there's a fair chance of root running us.
@@ -744,6 +772,8 @@ dolink(const char *const fromfield, cons
 		if (result != 0) {
 				const char *s = fromfield;
 				const char *t;
+				char *p;
+				size_t dotdots = 0;
 				char * symlinkcontents = NULL;
 
 				do
@@ -752,16 +782,16 @@ dolink(const char *const fromfield, cons
 				       && ! strncmp (fromfield, tofield,
 						     ++s - fromfield));
 
-				for (s = tofield + (t - fromfield);
-				     (s = strchr(s, '/'));
-				     s++)
-					symlinkcontents =
-						ecatalloc(symlinkcontents,
-						"../");
-				symlinkcontents = ecatalloc(symlinkcontents, t);
+				for (s = tofield + (t - fromfield); *s; s++)
+					dotdots += *s == '/';
+				symlinkcontents
+				    = zic_malloc(3 * dotdots + strlen(t) + 1);
+				for (p = symlinkcontents; dotdots-- != 0; p += 3)
+					memcpy(p, "../", 3);
+				strcpy(p, t);
 				result = symlink(symlinkcontents, toname);
 				if (result == 0)
-warning(_("hard link failed, symbolic link used"));
+					warning(_("hard link failed, symbolic link used"));
 				free(symlinkcontents);
 		}
 		if (result != 0) {
@@ -841,7 +871,7 @@ itsdir(const char *const name)
 	return S_ISDIR(st.st_mode) != 0;
 #else
 	{
-		char *nameslashdot = ecatalloc(ecpyalloc(name), "/.");
+		char *nameslashdot = relname(name, ".");
 		res = stat(nameslashdot, &st);
 		free(nameslashdot);
 		return res == 0;
@@ -1036,6 +1066,7 @@ gethms(char const *string, char const *e
 {
 	zic_t	hh;
 	int	mm, ss, sign;
+	char	xs;
 
 	if (string == NULL || *string == '\0')
 		return 0;
@@ -1045,12 +1076,12 @@ gethms(char const *string, char const *e
 		sign = -1;
 		++string;
 	} else	sign = 1;
-	if (sscanf(string, scheck(string, "%"SCNdZIC), &hh) == 1)
+	if (sscanf(string, "%"SCNdZIC"%c", &hh, &xs) == 1)
 		mm = ss = 0;
-	else if (sscanf(string, scheck(string, "%"SCNdZIC":%d"), &hh, &mm) == 2)
+	else if (sscanf(string, "%"SCNdZIC":%d%c", &hh, &mm, &xs) == 2)
 		ss = 0;
-	else if (sscanf(string, scheck(string, "%"SCNdZIC":%d:%d"),
-		&hh, &mm, &ss) != 3) {
+	else if (sscanf(string, "%"SCNdZIC":%d:%d%c", &hh, &mm, &ss, &xs)
+		 != 3) {
 			error("%s", errstring);
 			return 0;
 	}
@@ -1228,6 +1259,7 @@ inleap(char **const fields, const int nf
 	int			month, day;
 	zic_t			dayoff, tod;
 	zic_t			t;
+	char			xs;
 
 	if (nfields != LEAP_FIELDS) {
 		error(_("wrong number of fields on Leap line"));
@@ -1235,7 +1267,7 @@ inleap(char **const fields, const int nf
 	}
 	dayoff = 0;
 	cp = fields[LP_YEAR];
-	if (sscanf(cp, scheck(cp, "%"SCNdZIC), &year) != 1) {
+	if (sscanf(cp, "%"SCNdZIC"%c", &year, &xs) != 1) {
 		/*
 		** Leapin' Lizards!
 		*/
@@ -1270,7 +1302,7 @@ inleap(char **const fields, const int nf
 		++j;
 	}
 	cp = fields[LP_DAY];
-	if (sscanf(cp, scheck(cp, "%d"), &day) != 1 ||
+	if (sscanf(cp, "%d%c", &day, &xs) != 1 ||
 		day <= 0 || day > len_months[isleap(year)][month]) {
 			error(_("invalid day of month"));
 			return;
@@ -1356,6 +1388,7 @@ rulesub(struct rule *const rp, const cha
 	const char *		cp;
 	char *			dp;
 	char *			ep;
+	char			xs;
 
 	if ((lp = byword(monthp, mon_names)) == NULL) {
 		error(_("invalid month name"));
@@ -1407,7 +1440,7 @@ rulesub(struct rule *const rp, const cha
 				_("%s: panic: Invalid l_value %d\n"),
 				progname, lp->l_value);
 			exit(EXIT_FAILURE);
-	} else if (sscanf(cp, scheck(cp, "%"SCNdZIC), &rp->r_loyear) != 1) {
+	} else if (sscanf(cp, "%"SCNdZIC"%c", &rp->r_loyear, &xs) != 1) {
 		error(_("invalid starting year"));
 		return;
 	}
@@ -1429,7 +1462,7 @@ rulesub(struct rule *const rp, const cha
 				_("%s: panic: Invalid l_value %d\n"),
 				progname, lp->l_value);
 			exit(EXIT_FAILURE);
-	} else if (sscanf(cp, scheck(cp, "%"SCNdZIC), &rp->r_hiyear) != 1) {
+	} else if (sscanf(cp, "%"SCNdZIC"%c", &rp->r_hiyear, &xs) != 1) {
 		error(_("invalid ending year"));
 		return;
 	}
@@ -1482,7 +1515,7 @@ rulesub(struct rule *const rp, const cha
 			}
 			rp->r_wday = lp->l_value;
 		}
-		if (sscanf(ep, scheck(ep, "%d"), &rp->r_dayofmonth) != 1 ||
+		if (sscanf(ep, "%d%c", &rp->r_dayofmonth, &xs) != 1 ||
 			rp->r_dayofmonth <= 0 ||
 			(rp->r_dayofmonth > len_months[1][rp->r_month])) {
 				error(_("invalid day of month"));
@@ -1556,10 +1589,10 @@ writezone(const char *const name, const 
 	int			leapcnt32, leapi32;
 	int			timecnt32, timei32;
 	int			pass;
-	static char *			fullname;
+	char *			fullname;
 	static const struct tzhead	tzh0;
 	static struct tzhead		tzh;
-	zic_t *ats = emalloc(size_product(timecnt, sizeof *ats + 1));
+	zic_t *ats = zic_malloc(size_product(timecnt, sizeof *ats + 1));
 	void *typesptr = ats + timecnt;
 	unsigned char *types = typesptr;
 
@@ -1643,9 +1676,7 @@ writezone(const char *const name, const 
 		--leapcnt32;
 		++leapi32;
 	}
-	fullname = erealloc(fullname,
-	    strlen(directory) + 1 + strlen(name) + 1);
-	(void) sprintf(fullname, "%s/%s", directory, name);	/* XXX: sprintf is safe */
+	fullname = relname(directory, name);
 	/*
 	** Remove old file, if any, to snap links.
 	*/
@@ -1864,15 +1895,16 @@ writezone(const char *const name, const 
 	(void) fprintf(fp, "\n%s\n", string);
 	close_file(fp, fullname);
 	free(ats);
+	free(fullname);
 }
 
-static void
+static size_t
 doabbr(char *const abbr, const int abbrlen, const char *const format,
     const char *const letters, bool isdst, bool doquotes)
 {
 	char *	cp;
 	char *	slashp;
-	int	len;
+	size_t	len;
 
 	slashp = strchr(format, '/');
 	if (slashp == NULL) {
@@ -1885,18 +1917,18 @@ doabbr(char *const abbr, const int abbrl
 		(void) memcpy(abbr, format, slashp - format);
 		abbr[slashp - format] = '\0';
 	}
+	len = strlen(abbr);
 	if (!doquotes)
-		return;
+		return len;
 	for (cp = abbr; is_alpha(*cp); cp++)
 		continue;
-	len = strlen(abbr);
 	if (len > 0 && *cp == '\0')
-		return;
+		return len;
 	abbr[len + 2] = '\0';
 	abbr[len + 1] = '>';
-	for ( ; len > 0; --len)
-		abbr[len] = abbr[len - 1];
+	memmove(abbr + 1, abbr, len);
 	abbr[0] = '<';
+	return len + 2;
 }
 
 static void
@@ -1908,17 +1940,18 @@ updateminmax(const zic_t x)
 		max_year = x;
 }
 
-static bool
+static int
 stringoffset(char *result, zic_t offset)
 {
 	int	hours;
 	int	minutes;
 	int	seconds;
+	bool negative = offset < 0;
+	int len = negative;
 
-	result[0] = '\0';
-	if (offset < 0) {
-		strcpy(result, "-");
+	if (negative) {
 		offset = -offset;
+		result[0] = '-';
 	}
 	seconds = offset % SECSPERMIN;
 	offset /= SECSPERMIN;
@@ -1927,15 +1960,15 @@ stringoffset(char *result, zic_t offset)
 	hours = offset;
 	if (hours >= HOURSPERDAY * DAYSPERWEEK) {
 		result[0] = '\0';
-		return false;
+		return 0;
 	}
-	sprintf(end(result), "%d", hours);
+	len += sprintf(result + len, "%d", hours);
 	if (minutes != 0 || seconds != 0) {
-		sprintf(end(result), ":%02d", minutes);
+		len += sprintf(result + len, ":%02d", minutes);
 		if (seconds != 0)
-			sprintf(end(result), ":%02d", seconds);
+			len += sprintf(result + len, ":%02d", seconds);
 	}
-	return true;
+	return len;
 }
 
 static int
@@ -1945,7 +1978,6 @@ stringrule(char *result, const struct ru
 	zic_t	tod = rp->r_tod;
 	int	compat = 0;
 
-	result = end(result);
 	if (rp->r_dycode == DC_DOM) {
 		int	month, total;
 
@@ -1956,9 +1988,9 @@ stringrule(char *result, const struct ru
 			total += len_months[0][month];
 		/* Omit the "J" in Jan and Feb, as that's shorter.  */
 		if (rp->r_month <= 1)
-		  sprintf(result, "%d", total + rp->r_dayofmonth - 1);
+		  result += sprintf(result, "%d", total + rp->r_dayofmonth - 1);
 		else
-		  sprintf(result, "J%d", total + rp->r_dayofmonth);
+		  result += sprintf(result, "J%d", total + rp->r_dayofmonth);
 	} else {
 		int	week;
 		int	wday = rp->r_wday;
@@ -1985,16 +2017,16 @@ stringrule(char *result, const struct ru
 		} else	return -1;	/* "cannot happen" */
 		if (wday < 0)
 			wday += DAYSPERWEEK;
-		sprintf(result, "M%d.%d.%d",
-			rp->r_month + 1, week, wday);
+		result += sprintf(result, "M%d.%d.%d",
+				  rp->r_month + 1, week, wday);
 	}
 	if (rp->r_todisgmt)
 		tod += gmtoff;
 	if (rp->r_todisstd && rp->r_stdoff == 0)
 		tod += dstoff;
 	if (tod != 2 * SECSPERMIN * MINSPERHOUR) {
-		strcat(result, "/");
-		if (! stringoffset(end(result), tod))
+		*result++ = '/';
+		if (! stringoffset(result, tod))
 			return -1;
 		if (tod < 0) {
 			if (compat < 2013)
@@ -2035,6 +2067,8 @@ stringzone(char *result, const int resul
 	const char *		abbrvar;
 	int			compat = 0;
 	int			c;
+	size_t			len;
+	int			offsetlen;
 	struct rule		stdr, dstr;
 
 	result[0] = '\0';
@@ -2102,31 +2136,37 @@ stringzone(char *result, const int resul
 	if (stdrp == NULL && (zp->z_nrules != 0 || zp->z_stdoff != 0))
 		return -1;
 	abbrvar = (stdrp == NULL) ? "" : stdrp->r_abbrvar;
-	doabbr(result, resultlen, zp->z_format, abbrvar, false, true);
-	if (! stringoffset(end(result), -zp->z_gmtoff)) {
+	len = doabbr(result, resultlen, zp->z_format, abbrvar, false, true);
+	offsetlen = stringoffset(result + len, -zp->z_gmtoff);
+	if (! offsetlen) {
 		result[0] = '\0';
 		return -1;
 	}
+	len += offsetlen;
 	if (dstrp == NULL)
 		return compat;
-	doabbr(end(result), resultlen - strlen(result),
-		zp->z_format, dstrp->r_abbrvar, true, true);
-	if (dstrp->r_stdoff != SECSPERMIN * MINSPERHOUR)
-		if (! stringoffset(end(result),
-				   -(zp->z_gmtoff + dstrp->r_stdoff))) {
+	len += doabbr(result + len, resultlen - len, zp->z_format,
+	    dstrp->r_abbrvar, true, true);
+	if (dstrp->r_stdoff != SECSPERMIN * MINSPERHOUR) {
+		offsetlen = stringoffset(result + len,
+		    -(zp->z_gmtoff + dstrp->r_stdoff));
+		if (! offsetlen) {
 			result[0] = '\0';
 			return -1;
 		}
-	(void) strcat(result, ",");
-	c = stringrule(result, dstrp, dstrp->r_stdoff, zp->z_gmtoff);
+		len += offsetlen;
+	}
+	result[len++] = ',';
+	c = stringrule(result + len, dstrp, dstrp->r_stdoff, zp->z_gmtoff);
 	if (c < 0) {
 		result[0] = '\0';
 		return -1;
 	}
 	if (compat < c)
 		compat = c;
-	strcat(result, ",");
-	c = stringrule(result, stdrp, dstrp->r_stdoff, zp->z_gmtoff);
+	len += strlen(result + len);
+	result[len++] = ',';
+	c = stringrule(result + len, stdrp, dstrp->r_stdoff, zp->z_gmtoff);
 	if (c < 0) {
 		result[0] = '\0';
 		return -1;
@@ -2163,9 +2203,9 @@ outzone(const struct zone *const zpfirst
 
 	max_abbr_len = 2 + max_format_len + max_abbrvar_len;
 	max_envvar_len = 2 * max_abbr_len + 5 * 9;
-	startbuf = emalloc(max_abbr_len + 1);
-	ab = emalloc(max_abbr_len + 1);
-	envvar = emalloc(max_envvar_len + 1);
+	startbuf = zic_malloc(max_abbr_len + 1);
+	ab = zic_malloc(max_abbr_len + 1);
+	envvar = zic_malloc(max_envvar_len + 1);
 	INITIALIZE(untiltime);
 	INITIALIZE(starttime);
 	/*
@@ -2582,7 +2622,7 @@ yearistype(const int year, const char *c
 
 	if (type == NULL || *type == '\0')
 		return true;
-	buf = erealloc(buf, 132 + strlen(yitcommand) + strlen(type));
+	buf = zic_realloc(buf, 132 + strlen(yitcommand) + strlen(type));
 	(void)sprintf(buf, "%s %d %s", yitcommand, year, type); /* XXX: sprintf is safe */
 	result = system(buf);
 	if (WIFEXITED(result)) switch (WEXITSTATUS(result)) {
@@ -2708,7 +2748,7 @@ getfields(char *cp)
 
 	if (cp == NULL)
 		return NULL;
-	array = emalloc(size_product(strlen(cp) + 1, sizeof *array));
+	array = zic_malloc(size_product(strlen(cp) + 1, sizeof *array));
 	nsubs = 0;
 	for ( ; ; ) {
 		while (is_space(*cp))
@@ -2737,26 +2777,36 @@ getfields(char *cp)
 	return array;
 }
 
+static _Noreturn void
+time_overflow(void)
+{
+	error(_("time overflow"));
+	exit(EXIT_FAILURE);
+}
+
 static ATTRIBUTE_PURE zic_t
 oadd(const zic_t t1, const zic_t t2)
 {
-	if (t1 < 0 ? t2 < ZIC_MIN - t1 : ZIC_MAX - t1 < t2) {
-		error(_("time overflow"));
-		exit(EXIT_FAILURE);
-	}
+	if (t1 < 0 ? t2 < ZIC_MIN - t1 : ZIC_MAX - t1 < t2)
+		time_overflow();
 	return t1 + t2;
 }
 
 static ATTRIBUTE_PURE zic_t
 tadd(const zic_t t1, const zic_t t2)
 {
-	if (t1 == max_time && t2 > 0)
-		return max_time;
-	if (t1 == min_time && t2 < 0)
-		return min_time;
-	if (t1 < 0 ? t2 < min_time - t1 : max_time - t1 < t2) {
-		error(_("time overflow"));
-		exit(EXIT_FAILURE);
+	if (t1 < 0) {
+		if (t2 < min_time - t1) {
+			if (t1 != min_time)
+				time_overflow();
+			return min_time;
+		}
+	} else {
+		if (max_time - t1 < t2) {
+			if (t1 != max_time)
+				time_overflow();
+			return max_time;
+		}
 	}
 	return t1 + t2;
 }

Reply via email to