[tz] [PATCH 1/2] Add support for testing time_t types other than the, system's.

Paul Eggert eggert at cs.ucla.edu
Mon May 27 22:00:41 UTC 2013


This makes it easier to test on (say) Debian, even if we're
testing the time_t type on (say) NetBSD.  NetBSD uses 64-bit
time_t on 32-bit hosts, and this lets us test a NetBSD-style
implementation (32-bit 'long', 64-bit time_t) on a 32-bit Debian host.
* Makefile: Update comments to talk about TIME_T_FLOATING and time_tz.
Sort the comments.
* private.h (restrict): Define to empty with older compilers.
'restrict' is now needed, to define gmtime_r and localtime_r in
standard ways when time_tz is defined.
Make the following changes if time_tz is defined:
(sys_time, time): New static functions.  The former is the system
'time' function that applies to the system time_t, the latter
our function that applies to our time_t.
(time_t, ctime, ctime_r, difftime, gmtime, gmtime_r, localtime)
(localtime_r, mktime): Rename to tz_time_t, tz_ctime, etc.,
via macros.  Declare the renamed versions.
* zdump.8: Document new options -V, -t.
* zdump.c: Include private.h if time_tz is defined.
(INITIALIZE): Remove; no longer needed.
(absolute_min_time, absolute_max_time): Work even if time_t
is wider than intmax_t, which can be true with GCC and __int128_t.
Use the new TIME_T_FLOATING macro for this.
(usage): Document new flags.
(main): Support them.
---
 Makefile  |  16 +++----
 private.h |  56 +++++++++++++++++++++++++
 zdump.8   |  17 +++++++-
 zdump.c   | 140 ++++++++++++++++++++++++++++++++++++++------------------------
 4 files changed, 166 insertions(+), 63 deletions(-)

diff --git a/Makefile b/Makefile
index 0d6df64..cca817c 100644
--- a/Makefile
+++ b/Makefile
@@ -109,21 +109,23 @@ 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"
-#  -DLOCALE_HOME=\"path\" if locales are in "path", not "/usr/lib/locale"
 #  -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"
-#  -DTZDEFRULESTRING=\",date/time,date/time\" to default to the specified
-#	DST transitions if the time zone files cannot be accessed
-#  -DTZ_DOMAIN=\"foo\" to use "foo" for gettext domain name; default is "tz"
-#  -TTZ_DOMAINDIR=\"/path\" to use "/path" for gettext directory;
-#	the default is system-supplied, typically "/usr/lib/locale"
-#  $(GCC_DEBUG_FLAGS) if you are using GCC and want lots of checking
+#  -DLOCALE_HOME=\"path\" if locales are in "path", not "/usr/lib/locale"
 #  -DNO_RUN_TIME_WARNINGS_ABOUT_YEAR_2000_PROBLEMS_THANK_YOU=1
 #	if you do not want run time warnings about formats that may cause
 #	year 2000 grief
+#  -DTIME_T_FLOATING=1 if your time_t (or time_tz) is floating point
+#  -Dtime_tz=\"T\" to use T as the time_t type, rather than the system time_t
+#  -DTZ_DOMAIN=\"foo\" to use "foo" for gettext domain name; default is "tz"
+#  -TTZ_DOMAINDIR=\"/path\" to use "/path" for gettext directory;
+#	the default is system-supplied, typically "/usr/lib/locale"
+#  -DTZDEFRULESTRING=\",date/time,date/time\" to default to the specified
+#	DST transitions if the time zone files cannot be accessed
 #  -DZIC_MAX_ABBR_LEN_WO_WARN=3
 #	(or some other number) to set the maximum time zone abbreviation length
 #	that zic will accept without a warning (the default is 6)
+#  $(GCC_DEBUG_FLAGS) if you are using GCC and want lots of checking
 GCC_DEBUG_FLAGS = -Dlint -g3 -O3 -fno-common -fstrict-aliasing \
 	-Wall -Wextra \
 	-Wbad-function-cast -Wcast-align -Wcast-qual \
diff --git a/private.h b/private.h
index 1d1d391..05ddba0 100644
--- a/private.h
+++ b/private.h
@@ -150,6 +150,10 @@ typedef long		int_fast64_t;
 # define ATTRIBUTE_PURE /* empty */
 #endif
 
+#if __STDC_VERSION__ < 199901 && !defined restrict
+# define restrict /* empty */
+#endif
+
 /*
 ** Workarounds for compilers/systems.
 */
@@ -165,6 +169,58 @@ extern char *	asctime_r(struct tm const *, char *);
 #endif
 
 /*
+** Compile with -Dtime_tz=T to build the tz package with a private
+** time_t type equivalent to T rather than the system-supplied time_t.
+** This debugging feature can test unusual design decisions
+** (e.g., time_t wider than 'long', or unsigned time_t) even on
+** typical platforms.
+*/
+#ifdef time_tz
+static time_t sys_time(time_t *x) { return time(x); }
+
+# undef  ctime
+# define ctime tz_ctime
+# undef  ctime_r
+# define ctime_r tz_ctime_r
+# undef  difftime
+# define difftime tz_difftime
+# undef  gmtime
+# define gmtime tz_gmtime
+# undef  gmtime_r
+# define gmtime_r tz_gmtime_r
+# undef  localtime
+# define localtime tz_localtime
+# undef  localtime_r
+# define localtime_r tz_localtime_r
+# undef  mktime
+# define mktime tz_mktime
+# undef  time
+# define time tz_time
+# undef  time_t
+# define time_t tz_time_t
+
+typedef time_tz time_t;
+
+char *ctime(time_t const *);
+char *ctime_r(time_t const *, char *);
+double difftime(time_t, time_t);
+struct tm *gmtime(time_t const *);
+struct tm *gmtime_r(time_t const *restrict, struct tm *restrict);
+struct tm *localtime(time_t const *);
+struct tm *localtime_r(time_t const *restrict, struct tm *restrict);
+time_t mktime(struct tm *);
+
+static time_t
+time(time_t *p)
+{
+	time_t r = sys_time(0);
+	if (p)
+		*p = r;
+	return r;
+}
+#endif
+
+/*
 ** Private function declarations.
 */
 
diff --git a/zdump.8 b/zdump.8
index 63349e4..85e9641 100644
--- a/zdump.8
+++ b/zdump.8
@@ -37,15 +37,28 @@ Each line ends with
 if the given time is Daylight Saving Time or
 .B isdst=0
 otherwise.
+.B \-V
+Like
+.BR \-v ,
+except omit the times relative to the extreme time values.
+This generates output that is easier to compare to that of
+implementations with different time representations.
 .TP
 .BI "\-c " [loyear,]hiyear
 Cut off verbose output near the start of the given year(s).
+.TP
+.BI "\-t " [lotime,]hitime
+Cut off verbose output at the start of the given time(s),
+given in seconds since 1970-01-01 00:00:00 UTC.
 By default,
-the program cuts off verbose output near the starts of the years -500 and 2500.
+the program cuts off verbose output near the starts of the years
+\-500 and 2500.
 .SH LIMITATIONS
 The
 .B \-v
-option may not be used on systems with floating-point time_t values
+and
+.B \-V
+options may not be used on systems with floating-point time_t values
 that are neither float nor double.
 .PP
 Time discontinuities are found by sampling the results returned by localtime
diff --git a/zdump.c b/zdump.c
index 9255aff..8118091 100644
--- a/zdump.c
+++ b/zdump.c
@@ -9,8 +9,15 @@
 ** This code has been made independent of the rest of the time
 ** conversion package to increase confidence in the verification it provides.
 ** You can use this code to help in verifying other implementations.
+**
+** However, include private.h when debugging, so that it overrides
+** time_t consistently with the rest of the package.
 */
 
+#ifdef time_tz
+# include "private.h"
+#endif
+
 #include "stdio.h"	/* for stdout, stderr, perror */
 #include "string.h"	/* for strcpy */
 #include "sys/types.h"	/* for time_t */
@@ -112,14 +119,6 @@
 #endif /* !defined lint */
 #endif /* !defined GNUC_or_lint */
 
-#ifndef INITIALIZE
-#ifdef GNUC_or_lint
-#define INITIALIZE(x)	((x) = 0)
-#else /* !defined GNUC_or_lint */
-#define INITIALIZE(x)
-#endif /* !defined GNUC_or_lint */
-#endif /* !defined INITIALIZE */
-
 #if 2 < __GNUC__ || (__GNUC__ == 2 && 96 <= __GNUC_MINOR__)
 # define ATTRIBUTE_PURE __attribute__ ((__pure__))
 #else
@@ -151,20 +150,16 @@ extern char *	optarg;
 extern int	optind;
 extern char *	tzname[2];
 
-/* The minimum and maximum finite time values.  Shift 'long long' or
-   'long' instead of 'time_t'; this avoids compile-time errors when
-   time_t is floating-point.  In practice, 'long long' is wide enough.  */
+/* The minimum and maximum finite time values.  */
 static time_t const absolute_min_time =
   ((time_t) 0.5 == 0.5
    ? (sizeof (time_t) == sizeof (float) ? (time_t) -FLT_MAX
       : sizeof (time_t) == sizeof (double) ? (time_t) -DBL_MAX
       : sizeof (time_t) == sizeof (long double) ? (time_t) -LDBL_MAX
       : 0)
+#ifndef TIME_T_FLOATING
    : (time_t) -1 < 0
-#ifdef LLONG_MAX
-   ? (time_t) ((long long) -1 << (CHAR_BIT * sizeof (time_t) - 1))
-#else
-   ? (time_t) ((long) -1 << (CHAR_BIT * sizeof (time_t) - 1))
+   ? (time_t) -1 << (CHAR_BIT * sizeof (time_t) - 1)
 #endif
    : 0);
 static time_t const absolute_max_time =
@@ -173,13 +168,11 @@ static time_t const absolute_max_time =
       : sizeof (time_t) == sizeof (double) ? (time_t) DBL_MAX
       : sizeof (time_t) == sizeof (long double) ? (time_t) LDBL_MAX
       : -1)
+#ifndef TIME_T_FLOATING
    : (time_t) -1 < 0
-#ifdef LLONG_MAX
-   ? (time_t) (- (~ 0 < 0) - ((long long) -1 << (CHAR_BIT * sizeof (time_t) - 1)))
-#else
-   ? (time_t) (- (~ 0 < 0) - ((long) -1 << (CHAR_BIT * sizeof (time_t) - 1)))
+   ? - (~ 0 < 0) - ((time_t) -1 << (CHAR_BIT * sizeof (time_t) - 1))
 #endif
-   : (time_t) -1);
+   : -1);
 static size_t	longest;
 static char *	progname;
 static int	warned;
@@ -270,9 +263,9 @@ static void
 usage(FILE * const stream, const int status)
 {
 	(void) fprintf(stream,
-_("%s: usage is %s [ --version ] [ --help ] [ -v ] [ -c [loyear,]hiyear ] zonename ...\n\
-\n\
-Report bugs to %s.\n"),
+_("%s: usage: %s [--version] [--help] [-{vV}] [-{ct} [lo,]hi] zonename ...\n"
+  "\n"
+  "Report bugs to %s.\n"),
 		       progname, progname, REPORT_BUGS_TO);
 	exit(status);
 }
@@ -281,11 +274,10 @@ int
 main(int argc, char *argv[])
 {
 	register int		i;
-	register int		c;
 	register int		vflag;
+	register int		Vflag;
 	register char *		cutarg;
-	register long		cutloyear = ZDUMP_LO_YEAR;
-	register long		cuthiyear = ZDUMP_HI_YEAR;
+	register char *		cuttimes;
 	register time_t		cutlotime;
 	register time_t		cuthitime;
 	register char **	fakeenv;
@@ -297,8 +289,8 @@ main(int argc, char *argv[])
 	register struct tm *	tmp;
 	register struct tm *	newtmp;
 
-	INITIALIZE(cutlotime);
-	INITIALIZE(cuthitime);
+	cutlotime = absolute_min_time;
+	cuthitime = absolute_max_time;
 #if HAVE_GETTEXT
 	(void) setlocale(LC_ALL, "");
 #ifdef TZ_DOMAINDIR
@@ -314,22 +306,30 @@ main(int argc, char *argv[])
 		} else if (strcmp(argv[i], "--help") == 0) {
 			usage(stdout, EXIT_SUCCESS);
 		}
-	vflag = 0;
-	cutarg = NULL;
-	while ((c = getopt(argc, argv, "c:v")) == 'c' || c == 'v')
-		if (c == 'v')
-			vflag = 1;
-		else	cutarg = optarg;
-	if ((c != EOF && c != -1) ||
-		(optind == argc - 1 && strcmp(argv[optind], "=") == 0)) {
-			usage(stderr, EXIT_FAILURE);
-	}
-	if (vflag) {
+	vflag = Vflag = 0;
+	cutarg = cuttimes = NULL;
+	for (;;)
+	  switch (getopt(argc, argv, "c:t:vV")) {
+	  case 'c': cutarg = optarg; break;
+	  case 't': cuttimes = optarg; break;
+	  case 'v': vflag = 1; break;
+	  case 'V': Vflag = 1; break;
+	  case -1:
+	    if (! (optind == argc - 1 && strcmp(argv[optind], "=") == 0))
+	      goto arg_processing_done;
+	    /* Fall through.  */
+	  default:
+	    usage(stderr, EXIT_FAILURE);
+	  }
+ arg_processing_done:;
+
+	if (vflag | Vflag) {
+		long	lo;
+		long	hi;
+		char	dummy;
+		register long cutloyear = ZDUMP_LO_YEAR;
+		register long cuthiyear = ZDUMP_HI_YEAR;
 		if (cutarg != NULL) {
-			long	lo;
-			long	hi;
-			char	dummy;
-
 			if (sscanf(cutarg, "%ld%c", &hi, &dummy) == 1) {
 				cuthiyear = hi;
 			} else if (sscanf(cutarg, "%ld,%ld%c",
@@ -343,8 +343,36 @@ main(int argc, char *argv[])
 			}
 		}
 		checkabsolutes();
-		cutlotime = yeartot(cutloyear);
-		cuthitime = yeartot(cuthiyear);
+		if (cutarg != NULL || cuttimes == NULL) {
+			cutlotime = yeartot(cutloyear);
+			cuthitime = yeartot(cuthiyear);
+		}
+		if (cuttimes != NULL) {
+			if (sscanf(cuttimes, "%ld%c", &hi, &dummy) == 1) {
+				if (hi < cuthitime) {
+					if (hi < absolute_min_time)
+						hi = absolute_min_time;
+					cuthitime = hi;
+				}
+			} else if (sscanf(cuttimes, "%ld,%ld%c",
+					  &lo, &hi, &dummy) == 2) {
+				if (cutlotime < lo) {
+					if (absolute_max_time < lo)
+						lo = absolute_max_time;
+					cutlotime = lo;
+				}
+				if (hi < cuthitime) {
+					if (hi < absolute_min_time)
+						hi = absolute_min_time;
+					cuthitime = hi;
+				}
+			} else {
+				(void) fprintf(stderr,
+					_("%s: wild -t argument %s\n"),
+					progname, cuttimes);
+				exit(EXIT_FAILURE);
+			}
+		}
 	}
 	(void) time(&now);
 	longest = 0;
@@ -375,15 +403,17 @@ main(int argc, char *argv[])
 		static char	buf[MAX_STRING_LENGTH];
 
 		(void) strcpy(&fakeenv[0][3], argv[i]);
-		if (!vflag) {
+		if (! (vflag | Vflag)) {
 			show(argv[i], now, FALSE);
 			continue;
 		}
 		warned = FALSE;
 		t = absolute_min_time;
-		show(argv[i], t, TRUE);
-		t += SECSPERHOUR * HOURSPERDAY;
-		show(argv[i], t, TRUE);
+		if (!Vflag) {
+			show(argv[i], t, TRUE);
+			t += SECSPERHOUR * HOURSPERDAY;
+			show(argv[i], t, TRUE);
+		}
 		if (t < cutlotime)
 			t = cutlotime;
 		tmp = my_localtime(&t);
@@ -415,11 +445,13 @@ main(int argc, char *argv[])
 			tm = newtm;
 			tmp = newtmp;
 		}
-		t = absolute_max_time;
-		t -= SECSPERHOUR * HOURSPERDAY;
-		show(argv[i], t, TRUE);
-		t += SECSPERHOUR * HOURSPERDAY;
-		show(argv[i], t, TRUE);
+		if (!Vflag) {
+			t = absolute_max_time;
+			t -= SECSPERHOUR * HOURSPERDAY;
+			show(argv[i], t, TRUE);
+			t += SECSPERHOUR * HOURSPERDAY;
+			show(argv[i], t, TRUE);
+		}
 	}
 	if (fflush(stdout) || ferror(stdout)) {
 		(void) fprintf(stderr, "%s: ", progname);
-- 
1.8.1.2




More information about the tz mailing list