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