[tz] [PROPOSED PATCH 1/3] Remove need for ialloc.c

Paul Eggert eggert at cs.ucla.edu
Mon Apr 20 06:13:12 UTC 2015


One of its functions, icpyalloc, duplicates the now-standard
function strdup, and we might as well use the standard function.
Its other function, icatalloc, is used only in O(N**2) algorithms
that can be rewritten to be O(N).
* Makefile: Mention HAVE_STRDUP in commentary.
(TZCOBJS): Remove ialloc.o.
(NONLIBSRCS): Remove ialloc.c.
(ialloc.o): Remove.
* ialloc.c: Remove.
* private.h (HAVE_STRDUP): New macro, defaulting to 1.
(icatalloc, icpyalloc): Remove decls.
* zic.c (end): Remove.
(strdup) [!HAVE_STRDUP]: New function.
(memcheck): Arg is no longer a const pointer, since the
result isn't.
(emalloc, erealloc, ecpyalloc): Now functions, not macros.
(ecpyalloc): Use strdup, not icpyalloc.
(ecatalloc): Remove.  All callers changed.
(componentcheck): Check that file name components are nonempty;
otherwise, relname might return nonsense.
(relname): New function.
(dolink, itsdir, writezone): Use it.
(dolink, stringrule, stringzone):
Rewrite to avoid O(N**2) algorithm involving 'strcat' and 'end'.
(writezone): Use local, not static, to store fullname,
and free it before returning.
(doabbr, stringoffset): Return strlen of result.
---
 Makefile  |   6 +--
 ialloc.c  |  32 ------------
 private.h |   6 ++-
 zic.c     | 175 +++++++++++++++++++++++++++++++++++++-------------------------
 4 files changed, 113 insertions(+), 106 deletions(-)
 delete mode 100644 ialloc.c

diff --git a/Makefile b/Makefile
index 9a571e5..af52b36 100644
--- a/Makefile
+++ b/Makefile
@@ -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"
@@ -330,13 +331,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 scheck.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 scheck.c
 NEWUCBSRCS=	date.c strftime.c
 SOURCES=	$(HEADERS) $(LIBSRCS) $(NONLIBSRCS) $(NEWUCBSRCS) \
 			tzselect.ksh workman.sh
@@ -654,7 +655,6 @@ 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
diff --git a/ialloc.c b/ialloc.c
deleted file mode 100644
index e228db5..0000000
--- a/ialloc.c
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
-** This file is in the public domain, so clarified as of
-** 2006-07-17 by Arthur David Olson.
-*/
-
-/*LINTLIBRARY*/
-
-#include "private.h"
-
-char *
-icatalloc(char *const old, const char *const new)
-{
-	register char *	result;
-	register int	oldsize, newsize;
-
-	newsize = (new == NULL) ? 0 : strlen(new);
-	if (old == NULL)
-		oldsize = 0;
-	else if (newsize == 0)
-		return old;
-	else	oldsize = strlen(old);
-	if ((result = realloc(old, oldsize + newsize + 1)) != NULL)
-		if (new != NULL)
-			strcpy(result + oldsize, new);
-	return result;
-}
-
-char *
-icpyalloc(const char *const string)
-{
-	return icatalloc(NULL, string);
-}
diff --git a/private.h b/private.h
index de9c13e..05316a1 100644
--- a/private.h
+++ b/private.h
@@ -42,6 +42,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 */
@@ -452,8 +456,6 @@ time_t time2posix_z(timezone_t, time_t) ATTRIBUTE_PURE;
 ** Private function declarations.
 */
 
-char *		icatalloc(char * old, const char * new);
-char *		icpyalloc(const char * string);
 const char *	scheck(const char * string, const char * format);
 
 /*
diff --git a/zic.c b/zic.c
index 5d0501d..b28d5c3 100644
--- a/zic.c
+++ b/zic.c
@@ -31,8 +31,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;
@@ -368,18 +366,40 @@ size_product(size_t nitems, size_t itemsize)
 	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 *
+emalloc(size_t size)
+{
+  return memcheck(malloc(size));
+}
+
+static void *
+erealloc(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)
@@ -634,6 +654,11 @@ componentcheck(char const *name, char const *component,
 {
 	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"
@@ -686,6 +711,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 = emalloc(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)
 {
@@ -694,20 +734,8 @@ dolink(const char *const fromfield, const char *const tofield)
 	register 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.
@@ -731,6 +759,8 @@ dolink(const char *const fromfield, const char *const tofield)
 		if (result != 0) {
 				const char *s = fromfield;
 				const char *t;
+				char *p;
+				size_t dotdots = 0;
 				register char * symlinkcontents = NULL;
 
 				do
@@ -739,13 +769,13 @@ dolink(const char *const fromfield, const char *const tofield)
 				       && ! 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
+				  = emalloc(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"));
@@ -828,7 +858,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;
@@ -1547,7 +1577,7 @@ writezone(const char *const name, const char *const string, char version)
 	register int			leapcnt32, leapi32;
 	register int			timecnt32, timei32;
 	register 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));
@@ -1633,9 +1663,7 @@ writezone(const char *const name, const char *const string, char version)
 		--leapcnt32;
 		++leapi32;
 	}
-	fullname = erealloc(fullname,
-			    strlen(directory) + 1 + strlen(name) + 1);
-	sprintf(fullname, "%s/%s", directory, name);
+	fullname = relname(directory, name);
 	/*
 	** Remove old file, if any, to snap links.
 	*/
@@ -1850,15 +1878,16 @@ writezone(const char *const name, const char *const string, char version)
 	fprintf(fp, "\n%s\n", string);
 	close_file(fp, fullname);
 	free(ats);
+	free(fullname);
 }
 
-static void
+static size_t
 doabbr(char *const abbr, const char *const format, const char *const letters,
        bool isdst, bool doquotes)
 {
 	register char *	cp;
 	register char *	slashp;
-	register int	len;
+	register size_t	len;
 
 	slashp = strchr(format, '/');
 	if (slashp == NULL) {
@@ -1871,18 +1900,18 @@ doabbr(char *const abbr, const char *const format, const char *const letters,
 		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
@@ -1894,17 +1923,18 @@ updateminmax(const zic_t x)
 		max_year = x;
 }
 
-static bool
+static int
 stringoffset(char *result, zic_t offset)
 {
 	register int	hours;
 	register int	minutes;
 	register 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;
@@ -1913,15 +1943,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
@@ -1931,7 +1961,6 @@ stringrule(char *result, const struct rule *const rp, const zic_t dstoff,
 	register zic_t	tod = rp->r_tod;
 	register int	compat = 0;
 
-	result = end(result);
 	if (rp->r_dycode == DC_DOM) {
 		register int	month, total;
 
@@ -1942,9 +1971,9 @@ stringrule(char *result, const struct rule *const rp, const zic_t dstoff,
 			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 {
 		register int	week;
 		register int	wday = rp->r_wday;
@@ -1971,16 +2000,16 @@ stringrule(char *result, const struct rule *const rp, const zic_t dstoff,
 		} 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)
@@ -2020,6 +2049,8 @@ stringzone(char *result, const struct zone *const zpfirst, const int zonecount)
 	register const char *		abbrvar;
 	register int			compat = 0;
 	register int			c;
+	size_t				len;
+	int				offsetlen;
 	struct rule			stdr, dstr;
 
 	result[0] = '\0';
@@ -2087,30 +2118,36 @@ stringzone(char *result, const struct zone *const zpfirst, const int zonecount)
 	if (stdrp == NULL && (zp->z_nrules != 0 || zp->z_stdoff != 0))
 		return -1;
 	abbrvar = (stdrp == NULL) ? "" : stdrp->r_abbrvar;
-	doabbr(result, zp->z_format, abbrvar, false, true);
-	if (! stringoffset(end(result), -zp->z_gmtoff)) {
+	len = doabbr(result, 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), zp->z_format, dstrp->r_abbrvar, true, true);
-	if (dstrp->r_stdoff != SECSPERMIN * MINSPERHOUR)
-		if (! stringoffset(end(result),
-				   -(zp->z_gmtoff + dstrp->r_stdoff))) {
-				result[0] = '\0';
-				return -1;
-		}
-	strcat(result, ",");
-	c = stringrule(result, dstrp, dstrp->r_stdoff, zp->z_gmtoff);
+	len += doabbr(result + 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;
+	  }
+	  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;
-- 
2.1.0



More information about the tz mailing list