[tz] [PROPOSED PATCH 3/9] zdump: use localtime_r if available

Paul Eggert eggert at cs.ucla.edu
Mon Aug 25 06:59:47 UTC 2014


This is a bit cleaner and faster.
* zdump.c (HAVE_LOCALTIME_R, HAVE_TZSET): Default to 1.
(tzset) [!HAVE_TZSET]:
(localtime_r) [!HAVE_LOCALTIME_R]: Provide a replacement.
(settimezone): Call tzset after changing environ.
(my_localtime_r): Rename from my_localtime, and change API to
be compatible with localtime_r, not localtime.  All uses changed.
* Makefile, NEWS: Document this.
---
 Makefile |  2 ++
 NEWS     |  4 ++++
 zdump.c  | 70 ++++++++++++++++++++++++++++++++++++++++------------------------
 3 files changed, 50 insertions(+), 26 deletions(-)

diff --git a/Makefile b/Makefile
index 09f614c..26e8ab7 100644
--- a/Makefile
+++ b/Makefile
@@ -109,6 +109,7 @@ LDLIBS=
 #	ctime_r and asctime_r incompatibly with the POSIX standard (Solaris 8).
 #  -DHAVE_INTTYPES_H=1 if you have a pre-C99 compiler with "inttypes.h"
 #  -DHAVE_LINK=0 if your system lacks a link function
+#  -DHAVE_LOCALTIME_R=0 if your system lacks a localtime_r function
 #  -DHAVE_SETTIMEOFDAY=0 if settimeofday does not exist (SVR0?)
 #  -DHAVE_SETTIMEOFDAY=1 if settimeofday has just 1 arg (SVR4)
 #  -DHAVE_SETTIMEOFDAY=2 if settimeofday uses 2nd arg (4.3BSD)
@@ -117,6 +118,7 @@ LDLIBS=
 #  -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"
+#  -DHAVE_TZSET=0 if your system lacks a tzset function
 #  -DHAVE_UNISTD_H=0 if your compiler lacks a "unistd.h" (Microsoft C++ 7?)
 #  -DHAVE_UTMPX_H=1 if your compiler has a "utmpx.h"
 #  -DLOCALE_HOME=\"path\" if locales are in "path", not "/usr/lib/locale"
diff --git a/NEWS b/NEWS
index a14929b..9912856 100644
--- a/NEWS
+++ b/NEWS
@@ -51,6 +51,10 @@ Unreleased, experimental changes
     Although not needed for tz's own applications, which are single-threaded,
     this supports POSIX better if the tz library is used in multithreaded apps.
 
+    zdump now uses localtime_r and tzset if available, as this is a
+    bit cleaner and faster than plain localtime.  Compile with
+    -DHAVE_LOCALTIME_R=0 and/or -DHAVE_TZSET=0 if your system lacks them.
+
     The tz code now attempts to infer TM_GMTOFF and TM_ZONE if not
     already defined, to make it easier to configure on common platforms.
     Define NO_TM_GMTOFF and NO_TM_ZONE to suppress this.
diff --git a/zdump.c b/zdump.c
index 3dde5e8..c417b20 100644
--- a/zdump.c
+++ b/zdump.c
@@ -89,6 +89,13 @@ typedef long intmax_t;
 # endif
 #endif
 
+#ifndef HAVE_LOCALTIME_R
+# define HAVE_LOCALTIME_R 1
+#endif
+
+#ifndef HAVE_TZSET
+# define HAVE_TZSET 1
+#endif
 
 #ifndef ZDUMP_LO_YEAR
 #define ZDUMP_LO_YEAR	(-500)
@@ -264,6 +271,12 @@ sumsize(size_t a, size_t b)
   return sum;
 }
 
+#if ! HAVE_TZSET
+# undef tzset
+# define tzset zdump_tzset
+static void tzset(void) { }
+#endif
+
 /* Set the global time zone to VAL, exiting on memory allocation failure.  */
 static void
 settimezone(char const *val)
@@ -296,18 +309,32 @@ settimezone(char const *val)
   env[0] = strcat(strcpy(env0, "TZ="), val);
   environ = fakeenv = env;
   free(oldstorage);
+  tzset();
 }
 
+#if ! HAVE_LOCALTIME_R || ! HAVE_TZSET
+# undef localtime_r
+# define localtime_r zdump_localtime_r
+static struct tm *
+localtime_r(time_t *tp, struct tm *tmp)
+{
+  struct tm *r = localtime(tp);
+  if (r) {
+    *tmp = *r;
+    r = tmp;
+  }
+  return r;
+}
+#endif
+
 #ifndef TYPECHECK
-#define my_localtime	localtime
+# define my_localtime_r localtime_r
 #else /* !defined TYPECHECK */
 static struct tm *
-my_localtime(time_t *tp)
+my_localtime_r(time_t *tp, struct tm *tmp)
 {
-	register struct tm *	tmp;
-
-	tmp = localtime(tp);
-	if (tp != NULL && tmp != NULL) {
+	tmp = localtime_r(tp, tmp);
+	if (tmp) {
 		struct tm	tm;
 		register time_t	t;
 
@@ -552,31 +579,25 @@ main(int argc, char *argv[])
 		}
 		if (t < cutlotime)
 			t = cutlotime;
-		tmp = my_localtime(&t);
-		if (tmp != NULL) {
-			tm = *tmp;
+		tmp = my_localtime_r(&t, &tm);
+		if (tmp)
 			saveabbr(&abbrev, &abbrevsize, &tm);
-		}
 		for ( ; ; ) {
 			newt = (t < absolute_max_time - SECSPERDAY / 2
 				? t + SECSPERDAY / 2
 				: absolute_max_time);
 			if (cuthitime <= newt)
 				break;
-			newtmp = localtime(&newt);
-			if (newtmp != NULL)
-				newtm = *newtmp;
+			newtmp = localtime_r(&newt, &newtm);
 			if ((tmp == NULL || newtmp == NULL) ? (tmp != newtmp) :
 				(delta(&newtm, &tm) != (newt - t) ||
 				newtm.tm_isdst != tm.tm_isdst ||
 				strcmp(abbr(&newtm), abbrev) != 0)) {
 					newt = hunt(argv[i], t, newt);
-					newtmp = localtime(&newt);
-					if (newtmp != NULL) {
-						newtm = *newtmp;
+					newtmp = localtime_r(&newt, &newtm);
+					if (newtmp)
 						saveabbr(&abbrev, &abbrevsize,
 							 &newtm);
-					}
 			}
 			t = newt;
 			tm = newtm;
@@ -650,11 +671,9 @@ hunt(char *name, time_t lot, time_t hit)
 	struct tm		tm;
 	register struct tm *	tmp;
 
-	lotmp = my_localtime(&lot);
-	if (lotmp != NULL) {
-		lotm = *lotmp;
+	lotmp = my_localtime_r(&lot, &lotm);
+	if (lotmp)
 		saveabbr(&loab, &loabsize, &lotm);
-	}
 	for ( ; ; ) {
 		time_t diff = hit - lot;
 		if (diff < 2)
@@ -665,9 +684,7 @@ hunt(char *name, time_t lot, time_t hit)
 			++t;
 		else if (t >= hit)
 			--t;
-		tmp = my_localtime(&t);
-		if (tmp != NULL)
-			tm = *tmp;
+		tmp = my_localtime_r(&t, &tm);
 		if ((lotmp == NULL || tmp == NULL) ? (lotmp == tmp) :
 			(delta(&tm, &lotm) == (t - lot) &&
 			tm.tm_isdst == lotm.tm_isdst &&
@@ -711,6 +728,7 @@ static void
 show(char *zone, time_t t, bool v)
 {
 	register struct tm *	tmp;
+	struct tm tm;
 
 	printf("%-*s  ", longest, zone);
 	if (v) {
@@ -723,7 +741,7 @@ show(char *zone, time_t t, bool v)
 		}
 		printf(" = ");
 	}
-	tmp = my_localtime(&t);
+	tmp = my_localtime_r(&t, &tm);
 	dumptime(tmp);
 	if (tmp != NULL) {
 		if (*abbr(tmp) != '\0')
@@ -801,7 +819,7 @@ dumptime(register const struct tm *timeptr)
 		return;
 	}
 	/*
-	** The packaged versions of localtime and gmtime never put out-of-range
+	** The packaged localtime_r and gmtime never put out-of-range
 	** values in tm_wday or tm_mon, but since this code might be compiled
 	** with other (perhaps experimental) versions, paranoia is in order.
 	*/
-- 
1.9.1



More information about the tz mailing list