diff options
Diffstat (limited to 'timezone/zdump.c')
-rw-r--r-- | timezone/zdump.c | 327 |
1 files changed, 204 insertions, 123 deletions
diff --git a/timezone/zdump.c b/timezone/zdump.c index 9255affc16..209b79d06c 100644 --- a/timezone/zdump.c +++ b/timezone/zdump.c @@ -9,20 +9,72 @@ ** 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 */ #include "time.h" /* for struct tm */ #include "stdlib.h" /* for exit, malloc, atoi */ -#include "float.h" /* for FLT_MAX and DBL_MAX */ #include "limits.h" /* for CHAR_BIT, LLONG_MAX */ #include "ctype.h" /* for isalpha et al. */ #ifndef isascii #define isascii(x) 1 #endif /* !defined isascii */ +/* +** Substitutes for pre-C99 compilers. +** Much of this section of code is stolen from private.h. +*/ + +#ifndef HAVE_STDINT_H +# define HAVE_STDINT_H \ + (199901 <= __STDC_VERSION__ || 2 < (__GLIBC__ + (0 < __GLIBC_MINOR__))) +#endif +#if HAVE_STDINT_H +# include "stdint.h" +#endif +#ifndef HAVE_INTTYPES_H +# define HAVE_INTTYPES_H HAVE_STDINT_H +#endif +#if HAVE_INTTYPES_H +# include <inttypes.h> +#endif + +#ifndef INT_FAST32_MAX +# if INT_MAX >> 31 == 0 +typedef long int_fast32_t; +# else +typedef int int_fast32_t; +# endif +#endif + +#ifndef INTMAX_MAX +# if defined LLONG_MAX || defined __LONG_LONG_MAX__ +typedef long long intmax_t; +# define strtoimax strtoll +# define PRIdMAX "lld" +# ifdef LLONG_MAX +# define INTMAX_MAX LLONG_MAX +# else +# define INTMAX_MAX __LONG_LONG_MAX__ +# endif +# else +typedef long intmax_t; +# define strtoimax strtol +# define PRIdMAX "ld" +# define INTMAX_MAX LONG_MAX +# endif +#endif + + #ifndef ZDUMP_LO_YEAR #define ZDUMP_LO_YEAR (-500) #endif /* !defined ZDUMP_LO_YEAR */ @@ -90,9 +142,20 @@ #define isleap_sum(a, b) isleap((a) % 400 + (b) % 400) #endif /* !defined isleap_sum */ -#define SECSPERDAY ((long) SECSPERHOUR * HOURSPERDAY) +#define SECSPERDAY ((int_fast32_t) SECSPERHOUR * HOURSPERDAY) #define SECSPERNYEAR (SECSPERDAY * DAYSPERNYEAR) #define SECSPERLYEAR (SECSPERNYEAR + SECSPERDAY) +#define SECSPER400YEARS (SECSPERNYEAR * (intmax_t) (300 + 3) \ + + SECSPERLYEAR * (intmax_t) (100 - 3)) + +/* +** True if SECSPER400YEARS is known to be representable as an +** intmax_t. It's OK that SECSPER400YEARS_FITS can in theory be false +** even if SECSPER400YEARS is representable, because when that happens +** the code merely runs a bit more slowly, and this slowness doesn't +** occur on any practical platform. +*/ +enum { SECSPER400YEARS_FITS = SECSPERLYEAR <= INTMAX_MAX / 400 }; #ifndef HAVE_GETTEXT #define HAVE_GETTEXT 0 @@ -112,14 +175,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,48 +206,27 @@ 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) - : (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)) -#endif + ((time_t) -1 < 0 + ? (time_t) -1 << (CHAR_BIT * sizeof (time_t) - 1) : 0); static time_t const absolute_max_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 - : -1) - : (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))) -#endif - : (time_t) -1); + ((time_t) -1 < 0 + ? - (~ 0 < 0) - ((time_t) -1 << (CHAR_BIT * sizeof (time_t) - 1)) + : -1); static size_t longest; static char * progname; static int warned; static char * abbr(struct tm * tmp); static void abbrok(const char * abbrp, const char * zone); -static long delta(struct tm * newp, struct tm * oldp) ATTRIBUTE_PURE; +static intmax_t delta(struct tm * newp, struct tm * oldp) ATTRIBUTE_PURE; static void dumptime(const struct tm * tmp); static time_t hunt(char * name, time_t lot, time_t hit); -static void checkabsolutes(void); static void show(char * zone, time_t t, int v); static const char * tformat(void); -static time_t yeartot(long y) ATTRIBUTE_PURE; +static time_t yeartot(intmax_t y) ATTRIBUTE_PURE; #ifndef TYPECHECK #define my_localtime localtime @@ -209,7 +243,7 @@ my_localtime(time_t *tp) tm = *tmp; t = mktime(&tm); - if (t - *tp >= 1 || *tp - t >= 1) { + if (t != *tp) { (void) fflush(stdout); (void) fprintf(stderr, "\n%s: ", progname); (void) fprintf(stderr, tformat(), *tp); @@ -270,9 +304,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 +315,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 +330,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,37 +347,78 @@ 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) { + intmax_t lo; + intmax_t hi; + char *loend, *hiend; + register intmax_t cutloyear = ZDUMP_LO_YEAR; + register intmax_t cuthiyear = ZDUMP_HI_YEAR; if (cutarg != NULL) { - long lo; - long hi; - char dummy; - - if (sscanf(cutarg, "%ld%c", &hi, &dummy) == 1) { + lo = strtoimax(cutarg, &loend, 10); + if (cutarg != loend && !*loend) { + hi = lo; + cuthiyear = hi; + } else if (cutarg != loend && *loend == ',' + && (hi = strtoimax(loend + 1, &hiend, 10), + loend + 1 != hiend && !*hiend)) { + cutloyear = lo; cuthiyear = hi; - } else if (sscanf(cutarg, "%ld,%ld%c", - &lo, &hi, &dummy) == 2) { - cutloyear = lo; - cuthiyear = hi; } else { (void) fprintf(stderr, _("%s: wild -c argument %s\n"), progname, cutarg); exit(EXIT_FAILURE); } } - checkabsolutes(); - cutlotime = yeartot(cutloyear); - cuthitime = yeartot(cuthiyear); + if (cutarg != NULL || cuttimes == NULL) { + cutlotime = yeartot(cutloyear); + cuthitime = yeartot(cuthiyear); + } + if (cuttimes != NULL) { + lo = strtoimax(cuttimes, &loend, 10); + if (cuttimes != loend && !*loend) { + hi = lo; + if (hi < cuthitime) { + if (hi < absolute_min_time) + hi = absolute_min_time; + cuthitime = hi; + } + } else if (cuttimes != loend && *loend == ',' + && (hi = strtoimax(loend + 1, &hiend, 10), + loend + 1 != hiend && !*hiend)) { + 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 +449,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 += SECSPERDAY; + show(argv[i], t, TRUE); + } if (t < cutlotime) t = cutlotime; tmp = my_localtime(&t); @@ -392,9 +468,11 @@ main(int argc, char *argv[]) (void) strncpy(buf, abbr(&tm), (sizeof buf) - 1); } for ( ; ; ) { - if (t >= cuthitime || t >= cuthitime - SECSPERHOUR * 12) + newt = (t < absolute_max_time - SECSPERDAY / 2 + ? t + SECSPERDAY / 2 + : absolute_max_time); + if (cuthitime <= newt) break; - newt = t + SECSPERHOUR * 12; newtmp = localtime(&newt); if (newtmp != NULL) newtm = *newtmp; @@ -415,11 +493,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 -= SECSPERDAY; + show(argv[i], t, TRUE); + t += SECSPERDAY; + show(argv[i], t, TRUE); + } } if (fflush(stdout) || ferror(stdout)) { (void) fprintf(stderr, "%s: ", progname); @@ -431,44 +511,45 @@ main(int argc, char *argv[]) return EXIT_FAILURE; } -static void -checkabsolutes(void) -{ - if (absolute_max_time < absolute_min_time) { - (void) fprintf(stderr, -_("%s: use of -v on system with floating time_t other than float or double\n"), - progname); - exit(EXIT_FAILURE); - } -} - static time_t -yeartot(const long y) +yeartot(const intmax_t y) { - register long myy; - register long seconds; - register time_t t; + register intmax_t myy, seconds, years; + register time_t t; myy = EPOCH_YEAR; t = 0; - while (myy != y) { - if (myy < y) { + while (myy < y) { + if (SECSPER400YEARS_FITS && 400 <= y - myy) { + intmax_t diff400 = (y - myy) / 400; + if (INTMAX_MAX / SECSPER400YEARS < diff400) + return absolute_max_time; + seconds = diff400 * SECSPER400YEARS; + years = diff400 * 400; + } else { seconds = isleap(myy) ? SECSPERLYEAR : SECSPERNYEAR; - ++myy; - if (t > absolute_max_time - seconds) { - t = absolute_max_time; - break; - } - t += seconds; + years = 1; + } + myy += years; + if (t > absolute_max_time - seconds) + return absolute_max_time; + t += seconds; + } + while (y < myy) { + if (SECSPER400YEARS_FITS && y + 400 <= myy && myy < 0) { + intmax_t diff400 = (myy - y) / 400; + if (INTMAX_MAX / SECSPER400YEARS < diff400) + return absolute_min_time; + seconds = diff400 * SECSPER400YEARS; + years = diff400 * 400; } else { - --myy; - seconds = isleap(myy) ? SECSPERLYEAR : SECSPERNYEAR; - if (t < absolute_min_time + seconds) { - t = absolute_min_time; - break; - } - t -= seconds; + seconds = isleap(myy - 1) ? SECSPERLYEAR : SECSPERNYEAR; + years = 1; } + myy -= years; + if (t < absolute_min_time + seconds) + return absolute_min_time; + t -= seconds; } return t; } @@ -477,7 +558,6 @@ static time_t hunt(char *name, time_t lot, time_t hit) { time_t t; - long diff; struct tm lotm; register struct tm * lotmp; struct tm tm; @@ -490,7 +570,7 @@ hunt(char *name, time_t lot, time_t hit) (void) strncpy(loab, abbr(&lotm), (sizeof loab) - 1); } for ( ; ; ) { - diff = (long) (hit - lot); + time_t diff = hit - lot; if (diff < 2) break; t = lot; @@ -520,11 +600,11 @@ hunt(char *name, time_t lot, time_t hit) ** Thanks to Paul Eggert for logic used in delta. */ -static long +static intmax_t delta(struct tm * newp, struct tm *oldp) { - register long result; - register int tmy; + register intmax_t result; + register int tmy; if (newp->tm_year < oldp->tm_year) return -delta(oldp, newp); @@ -553,7 +633,7 @@ show(char *zone, time_t t, int v) (void) printf(tformat(), t); } else { dumptime(tmp); - (void) printf(" UTC"); + (void) printf(" UT"); } (void) printf(" = "); } @@ -594,18 +674,19 @@ abbr(struct tm *tmp) static const char * tformat(void) { - if (0.5 == (time_t) 0.5) { /* floating */ - if (sizeof (time_t) > sizeof (double)) - return "%Lg"; - return "%g"; - } if (0 > (time_t) -1) { /* signed */ + if (sizeof (time_t) == sizeof (intmax_t)) + return "%"PRIdMAX; if (sizeof (time_t) > sizeof (long)) return "%lld"; if (sizeof (time_t) > sizeof (int)) return "%ld"; return "%d"; } +#ifdef PRIuMAX + if (sizeof (time_t) == sizeof (uintmax_t)) + return "%"PRIuMAX; +#endif if (sizeof (time_t) > sizeof (unsigned long)) return "%llu"; if (sizeof (time_t) > sizeof (unsigned int)) |