[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