[tz] [PROPOSED PATCH 9/9] zdump now uses localtime_rz if available.
Paul Eggert
eggert at cs.ucla.edu
Mon Aug 25 06:59:53 UTC 2014
This is significantly faster and is cleaner internally.
* Makefile, NEWS: Document this.
* zdump.c (NETBSD_INSPIRED): Default to 1.
(HAVE_LOCALTIME_RZ): New macro; defaults to NETBSD_INSPIRED && USE_LTZ.
(timezone_t) [!HAVE_LOCALTIME_RZ]: New macro, as a substitute.
(localtime_r) [!HAVE_LOCALTIME_RZ && (!HAVE_LOCALTIME_R||!HAVE_TZSET)]:
(localtime_rz, tzalloc, tzfree) [!HAVE_LOCALTIME_RZ]:
(mktime_rz) [!HAVE_LOCALTIME_RZ && TYPECHECK]:
New substitute function and macro, compatible with NetBSD.
All other uses of localtime_r changed to use localtime_rz.
(settimezone): Remove; all uses replaced by tzalloc.
(tzalloc): Use most of the code of the old settimezone function,
but don't free the old storage.
(tzfree): Free it here instead.
(my_localtime_rz): Rename from my_localtime_r, and make it
compatible with localtime_rz. All uses changed.
(saveabbr): Return the abbreviation. If HAVE_LOCALTIME_RZ
simply return the output of abbr; that's faster.
(main): Diagnose any tzalloc failure. tzfree after use.
(hunt, show): New timezone_t arg. All uses changed.
---
Makefile | 3 ++
NEWS | 4 ++
zdump.c | 183 +++++++++++++++++++++++++++++++++++++++++----------------------
3 files changed, 128 insertions(+), 62 deletions(-)
diff --git a/Makefile b/Makefile
index f4fb8cd..0fc8e2c 100644
--- a/Makefile
+++ b/Makefile
@@ -110,6 +110,9 @@ LDLIBS=
# -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_LOCALTIME_RZ=0 if you do not want zdump to use localtime_rz
+# This defaults to 1 if localtime_rz is known to be available.
+# localtime_rz can make zdump significantly faster, but is nonstandard.
# -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)
diff --git a/NEWS b/NEWS
index ce49fd2..18b6aec 100644
--- a/NEWS
+++ b/NEWS
@@ -85,6 +85,10 @@ Unreleased, experimental changes
To build zdump with the system library, use 'make CFLAGS=-DUSE_LTZ=0
TZDOBJS=zdump.o CHECK_TIME_T_ALTERNATIVES='.
+ zdump now uses localtime_rz if available, as it's significantly faster.
+ Define HAVE_LOCALTIME_RZ to 0 to suppress this. HAVE_LOCALTIME_TZ
+ defaults to 1 if NETBSD_INSPIRED && USE_LTZ.
+
tzselect -c now uses a hybrid distance measure that works better
in Africa. (Thanks to Alan Barrett for noting the problem.)
diff --git a/zdump.c b/zdump.c
index 594e5fd..7326c63 100644
--- a/zdump.c
+++ b/zdump.c
@@ -12,6 +12,9 @@
** To do this, compile with -DUSE_LTZ=0 and link without the tz library.
*/
+#ifndef NETBSD_INSPIRED
+# define NETBSD_INSPIRED 1
+#endif
#ifndef USE_LTZ
# define USE_LTZ 1
#endif
@@ -95,6 +98,10 @@ typedef long intmax_t;
# define HAVE_LOCALTIME_R 1
#endif
+#ifndef HAVE_LOCALTIME_RZ
+# define HAVE_LOCALTIME_RZ (NETBSD_INSPIRED && USE_LTZ)
+#endif
+
#ifndef HAVE_TZSET
# define HAVE_TZSET 1
#endif
@@ -213,6 +220,11 @@ enum { SECSPER400YEARS_FITS = SECSPERLYEAR <= INTMAX_MAX / 400 };
# define TZ_DOMAIN "tz"
#endif
+#if ! HAVE_LOCALTIME_RZ
+# undef timezone_t
+# define timezone_t char **
+#endif
+
extern char ** environ;
extern int getopt(int argc, char * const argv[],
const char * options);
@@ -237,8 +249,8 @@ static bool errout;
static char const *abbr(struct tm const *);
static intmax_t delta(struct tm *, struct tm *) ATTRIBUTE_PURE;
static void dumptime(struct tm const *);
-static time_t hunt(char *, time_t, time_t);
-static void show(char *, time_t, bool);
+static time_t hunt(timezone_t, char *, time_t, time_t);
+static void show(timezone_t, char *, time_t, bool);
static const char *tformat(void);
static time_t yeartot(intmax_t) ATTRIBUTE_PURE;
@@ -279,13 +291,51 @@ sumsize(size_t a, size_t b)
static void tzset(void) { }
#endif
-/* Set the global time zone to VAL, exiting on memory allocation failure. */
-static void
-settimezone(char const *val)
+#if ! HAVE_LOCALTIME_RZ
+
+# 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
+
+# undef localtime_rz
+# define localtime_rz zdump_localtime_rz
+static struct tm *
+localtime_rz(timezone_t rz, time_t *tp, struct tm *tmp)
+{
+ return localtime_r(tp, tmp);
+}
+
+# ifdef TYPECHECK
+# undef mktime_z
+# define mktime_z zdump_mktime_z
+static time_t
+mktime_z(timezone_t tz, struct tm *tmp)
+{
+ return mktime(tmp);
+}
+# endif
+
+# undef tzalloc
+# undef tzfree
+# define tzalloc zdump_tzalloc
+# define tzfree zdump_tzfree
+
+static timezone_t
+tzalloc(char const *val)
{
static char **fakeenv;
char **env = fakeenv;
- char *oldstorage = env ? env[0] : 0;
char *env0;
if (! env) {
char **e = environ;
@@ -310,38 +360,32 @@ settimezone(char const *val)
}
env[0] = strcat(strcpy(env0, "TZ="), val);
environ = fakeenv = env;
- free(oldstorage);
tzset();
+ return env;
}
-#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)
+static void
+tzfree(timezone_t env)
{
- struct tm *r = localtime(tp);
- if (r) {
- *tmp = *r;
- r = tmp;
- }
- return r;
+ environ = env + 1;
+ free(env[0]);
}
-#endif
+#endif /* ! HAVE_LOCALTIME_RZ */
#ifndef TYPECHECK
-# define my_localtime_r localtime_r
+# define my_localtime_rz localtime_rz
#else /* !defined TYPECHECK */
+
static struct tm *
-my_localtime_r(time_t *tp, struct tm *tmp)
+my_localtime_rz(timezone_t tz, time_t *tp, struct tm *tmp)
{
- tmp = localtime_r(tp, tmp);
+ tmp = localtime_rz(tz, tp, tmp);
if (tmp) {
struct tm tm;
register time_t t;
tm = *tmp;
- t = mktime(&tm);
+ t = mktime_z(tz, &tm);
if (t != *tp) {
fflush(stdout);
fprintf(stderr, "\n%s: ", progname);
@@ -399,27 +443,34 @@ abbrok(const char *const abbrp, const char *const zone)
warned = errout = true;
}
-/* Save into *BUF (of size *BUFALLOC) the time zone abbreviation of TMP.
+/* Return a time zone abbreviation. If the abbreviation needs to be
+ saved, use *BUF (of size *BUFALLOC) to save it, and return the
+ abbreviation in the possibly-reallocated *BUF. Otherwise, just
+ return the abbreviation. Get the abbreviation from TMP.
Exit on memory allocation failure. */
-static void
+static char const *
saveabbr(char **buf, size_t *bufalloc, struct tm const *tmp)
{
char const *ab = abbr(tmp);
- size_t ablen = strlen(ab);
- if (*bufalloc <= ablen) {
- free(*buf);
-
- /* Make the new buffer at least twice as long as the old,
- to avoid O(N**2) behavior on repeated calls. */
- *bufalloc = sumsize(*bufalloc, ablen + 1);
-
- *buf = malloc(*bufalloc);
- if (! *buf) {
- perror(progname);
- exit(EXIT_FAILURE);
+ if (HAVE_LOCALTIME_RZ)
+ return ab;
+ else {
+ size_t ablen = strlen(ab);
+ if (*bufalloc <= ablen) {
+ free(*buf);
+
+ /* Make the new buffer at least twice as long as the old,
+ to avoid O(N**2) behavior on repeated calls. */
+ *bufalloc = sumsize(*bufalloc, ablen + 1);
+
+ *buf = malloc(*bufalloc);
+ if (! *buf) {
+ perror(progname);
+ exit(EXIT_FAILURE);
+ }
}
+ return strcpy(*buf, ab);
}
- strcpy(*buf, ab);
}
static void
@@ -567,39 +618,45 @@ main(int argc, char *argv[])
}
for (i = optind; i < argc; ++i) {
- settimezone(argv[i]);
+ timezone_t tz = tzalloc(argv[i]);
+ char const *ab;
+ if (!tz) {
+ perror("tzalloc");
+ return EXIT_FAILURE;
+ }
if (! (vflag | Vflag)) {
- show(argv[i], now, false);
+ show(tz, argv[i], now, false);
+ tzfree(tz);
continue;
}
warned = false;
t = absolute_min_time;
if (!Vflag) {
- show(argv[i], t, true);
+ show(tz, argv[i], t, true);
t += SECSPERDAY;
- show(argv[i], t, true);
+ show(tz, argv[i], t, true);
}
if (t < cutlotime)
t = cutlotime;
- tmp = my_localtime_r(&t, &tm);
+ tmp = my_localtime_rz(tz, &t, &tm);
if (tmp)
- saveabbr(&abbrev, &abbrevsize, &tm);
+ ab = saveabbr(&abbrev, &abbrevsize, &tm);
for ( ; ; ) {
newt = (t < absolute_max_time - SECSPERDAY / 2
? t + SECSPERDAY / 2
: absolute_max_time);
if (cuthitime <= newt)
break;
- newtmp = localtime_r(&newt, &newtm);
+ newtmp = localtime_rz(tz, &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_r(&newt, &newtm);
+ strcmp(abbr(&newtm), ab) != 0)) {
+ newt = hunt(tz, argv[i], t, newt);
+ newtmp = localtime_rz(tz, &newt, &newtm);
if (newtmp)
- saveabbr(&abbrev, &abbrevsize,
- &newtm);
+ ab = saveabbr(&abbrev, &abbrevsize,
+ &newtm);
}
t = newt;
tm = newtm;
@@ -608,10 +665,11 @@ main(int argc, char *argv[])
if (!Vflag) {
t = absolute_max_time;
t -= SECSPERDAY;
- show(argv[i], t, true);
+ show(tz, argv[i], t, true);
t += SECSPERDAY;
- show(argv[i], t, true);
+ show(tz, argv[i], t, true);
}
+ tzfree(tz);
}
close_file(stdout);
if (errout && (ferror(stderr) || fclose(stderr) != 0))
@@ -663,19 +721,20 @@ yeartot(const intmax_t y)
}
static time_t
-hunt(char *name, time_t lot, time_t hit)
+hunt(timezone_t tz, char *name, time_t lot, time_t hit)
{
static char * loab;
static size_t loabsize;
+ char const * ab;
time_t t;
struct tm lotm;
register struct tm * lotmp;
struct tm tm;
register struct tm * tmp;
- lotmp = my_localtime_r(&lot, &lotm);
+ lotmp = my_localtime_rz(tz, &lot, &lotm);
if (lotmp)
- saveabbr(&loab, &loabsize, &lotm);
+ ab = saveabbr(&loab, &loabsize, &lotm);
for ( ; ; ) {
time_t diff = hit - lot;
if (diff < 2)
@@ -686,18 +745,18 @@ hunt(char *name, time_t lot, time_t hit)
++t;
else if (t >= hit)
--t;
- tmp = my_localtime_r(&t, &tm);
+ tmp = my_localtime_rz(tz, &t, &tm);
if ((lotmp == NULL || tmp == NULL) ? (lotmp == tmp) :
(delta(&tm, &lotm) == (t - lot) &&
tm.tm_isdst == lotm.tm_isdst &&
- strcmp(abbr(&tm), loab) == 0)) {
+ strcmp(abbr(&tm), ab) == 0)) {
lot = t;
lotm = tm;
lotmp = tmp;
} else hit = t;
}
- show(name, lot, true);
- show(name, hit, true);
+ show(tz, name, lot, true);
+ show(tz, name, hit, true);
return hit;
}
@@ -727,7 +786,7 @@ delta(struct tm * newp, struct tm *oldp)
}
static void
-show(char *zone, time_t t, bool v)
+show(timezone_t tz, char *zone, time_t t, bool v)
{
register struct tm * tmp;
struct tm tm;
@@ -743,7 +802,7 @@ show(char *zone, time_t t, bool v)
}
printf(" = ");
}
- tmp = my_localtime_r(&t, &tm);
+ tmp = my_localtime_rz(tz, &t, &tm);
dumptime(tmp);
if (tmp != NULL) {
if (*abbr(tmp) != '\0')
@@ -821,7 +880,7 @@ dumptime(register const struct tm *timeptr)
return;
}
/*
- ** The packaged localtime_r and gmtime never put out-of-range
+ ** The packaged localtime_rz 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