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:
3
Makefile
3
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)
|
||||
|
||||
4
NEWS
4
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.)
|
||||
|
||||
|
||||
179
zdump.c
179
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);
|
||||
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.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user