1
0
mirror of https://frontier.innolan.net/rainlance/amiga-tz.git synced 2026-05-06 23:58:00 +00:00

zdump now uses localtime_rz if available.

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.
This commit is contained in:
Paul Eggert
2014-08-24 23:46:36 -07:00
parent f99b8f1414
commit 61bdeb997b
3 changed files with 126 additions and 60 deletions

View File

@@ -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)

4
NEWS
View File

@@ -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.)

179
zdump.c
View File

@@ -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);
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);
/* 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);
*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.
*/