X-Git-Url: https://git.saurik.com/apple/icu.git/blobdiff_plain/4162bf987dca731f631c28df29ad400b78d50ea9..5ea0322b6ab2af986e4c764284141380031dd014:/icuSources/tools/tzcode/zdump.c diff --git a/icuSources/tools/tzcode/zdump.c b/icuSources/tools/tzcode/zdump.c index c7199acb..c47c180c 100644 --- a/icuSources/tools/tzcode/zdump.c +++ b/icuSources/tools/tzcode/zdump.c @@ -1,25 +1,29 @@ -static char elsieid[] = "@(#)zdump.c 8.3"; +/* +** This file is in the public domain, so clarified as of +** 2009-05-17 by Arthur David Olson. +*/ + +#include "version.h" /* ** 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. */ -/* - * ICU note: Mr. Arthur David Olson (olsona@dc37a.nci.nih.gov) stated that - * "zdump.c is indeed in the public domain" in e-mail on Feb 22, 2007. - * This version of zdump.c is modified by ICU team to change output format - * and some additional options. - */ - +#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. */ /* Enable extensions and modifications for ICU. */ @@ -33,6 +37,52 @@ static char elsieid[] = "@(#)zdump.c 8.3"; #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 +#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 */ @@ -100,10 +150,24 @@ static char elsieid[] = "@(#)zdump.c 8.3"; #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 +#endif #if HAVE_GETTEXT #include "locale.h" /* for setlocale */ #include "libintl.h" @@ -119,13 +183,11 @@ static char elsieid[] = "@(#)zdump.c 8.3"; #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 +# define ATTRIBUTE_PURE /* empty */ +#endif /* ** For the benefit of GNU folk... @@ -145,51 +207,52 @@ static char elsieid[] = "@(#)zdump.c 8.3"; #define TZ_DOMAIN "tz" #endif /* !defined TZ_DOMAIN */ -#ifndef P -#define P(x) x -#endif /* !defined P */ - extern char ** environ; -extern int getopt P((int argc, char * const argv[], - const char * options)); +extern int getopt(int argc, char * const argv[], + const char * options); extern char * optarg; extern int optind; extern char * tzname[2]; -static time_t absolute_min_time; -static time_t absolute_max_time; +/* The minimum and maximum finite time values. */ +static time_t const absolute_min_time = + ((time_t) -1 < 0 + ? (time_t) -1 << (CHAR_BIT * sizeof (time_t) - 1) + : 0); +static time_t const absolute_max_time = + ((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 P((struct tm * tmp)); -static void abbrok P((const char * abbrp, const char * zone)); -static long delta P((struct tm * newp, struct tm * oldp)); -static void dumptime P((const struct tm * tmp)); -static time_t hunt P((char * name, time_t lot, time_t hit)); -static void setabsolutes P((void)); -static void show P((char * zone, time_t t, int v)); -static const char * tformat P((void)); -static time_t yeartot P((long y)); +static char * abbr(struct tm * tmp); +static void abbrok(const char * abbrp, const char * zone); +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 show(char * zone, time_t t, int v); +static const char * tformat(void); +static time_t yeartot(intmax_t y) ATTRIBUTE_PURE; #ifdef ICU typedef struct listentry { char * name; struct listentry * next; } listentry; -static time_t huntICU P((char * name, time_t lot, time_t hit, FILE *fp)); -static void dumptimeICU P((FILE * fp, time_t t)); -static void showICU P((FILE * fp, char * zone, time_t t1, time_t t2)); -static int getall P((struct listentry ** namelist)); -static void getzones P((char * basedir, char * subdir, struct listentry ** last, int * count)); +static time_t huntICU(char * name, time_t lot, time_t hit, FILE *fp); +static void dumptimeICU(FILE * fp, time_t t); +static void showICU(FILE * fp, char * zone, time_t t1, time_t t2); +static int getall(struct listentry ** namelist); +static void getzones(char * basedir, char * subdir, struct listentry ** last, int * count); #endif #ifndef TYPECHECK #define my_localtime localtime #else /* !defined TYPECHECK */ static struct tm * -my_localtime(tp) -time_t * tp; +my_localtime(time_t *tp) { register struct tm * tmp; @@ -200,7 +263,7 @@ 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); @@ -222,12 +285,10 @@ time_t * tp; #endif /* !defined TYPECHECK */ static void -abbrok(abbrp, zone) -const char * const abbrp; -const char * const zone; +abbrok(const char *const abbrp, const char *const zone) { register const char * cp; - register char * wp; + register const char * wp; if (warned) return; @@ -259,17 +320,25 @@ const char * const zone; warned = TRUE; } +static void +usage(FILE * const stream, const int status) +{ + (void) fprintf(stream, +_("%s: usage: %s [--version] [--help] [-{vV}] [-{ct} [lo,]hi] zonename ...\n" + "\n" + "Report bugs to %s.\n"), + progname, progname, REPORT_BUGS_TO); + exit(status); +} + int -main(argc, argv) -int argc; -char * argv[]; +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; @@ -289,8 +358,8 @@ char * argv[]; FILE * fp = stdout; #endif - INITIALIZE(cutlotime); - INITIALIZE(cuthitime); + cutlotime = absolute_min_time; + cuthitime = absolute_max_time; #if HAVE_GETTEXT (void) setlocale(LC_ALL, ""); #ifdef TZ_DOMAINDIR @@ -301,47 +370,54 @@ char * argv[]; progname = argv[0]; for (i = 1; i < argc; ++i) if (strcmp(argv[i], "--version") == 0) { - (void) printf("%s\n", elsieid); + (void) printf("zdump %s%s\n", PKGVERSION, TZVERSION); exit(EXIT_SUCCESS); + } else if (strcmp(argv[i], "--help") == 0) { + usage(stdout, EXIT_SUCCESS); } - vflag = 0; - cutarg = NULL; + vflag = Vflag = 0; + cutarg = cuttimes = NULL; #ifdef ICU aflag = 0; iflag = 0; dirarg = NULL; - nextopt = 1; - while(nextopt) { - c = getopt(argc, argv, "ac:d:iv"); - switch(c) { - case 'a': - aflag = 1; - break; - case 'c': - cutarg = optarg; - break; - case 'd': - dirarg = optarg; - break; - case 'i': - iflag = 1; - break; - case 'v': - vflag = 1; - break; + for (;;) + switch(getopt(argc, argv, "ac:d:it:vV")) { + case 'a': aflag = 1; break; + case 'c': cutarg = optarg; break; + case 'd': dirarg = optarg; break; + case 'i': iflag = 1; 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: - nextopt = 0; - break; - } - } - if ((c != EOF && c != -1) || - (optind == argc - 1 && strcmp(argv[optind], "=") == 0)) { (void) fprintf(stderr, - _("%s: usage is %s [ --version ] [ -a ] [ -v ] [ -i ] [ -c [loyear,]hiyear ] [ -d dir ] [ zonename ... ]\n"), + _("%s: usage is %s [ --version ] [ -a ] [ -v ] [ -V ] [ -i ] [ -c [loyear,]hiyear ] [ -t [lotime,]hitime] ][ -d dir ] [ zonename ... ]\n"), progname, progname); exit(EXIT_FAILURE); - } + } +#else + 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); + } +#endif + arg_processing_done:; +#ifdef ICU if (dirarg != NULL) { DIR * dp; /* create the output directory */ @@ -352,40 +428,63 @@ char * argv[]; } closedir(dp); } -#else - 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)) { - (void) fprintf(stderr, -_("%s: usage is %s [ --version ] [ -v ] [ -c [loyear,]hiyear ] zonename ...\n"), - progname, progname); - exit(EXIT_FAILURE); - } -#endif - if (vflag) { +#endif ICU + + 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); } } - setabsolutes(); - 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); + } + } } #ifdef ICU @@ -425,10 +524,9 @@ _("%s: usage is %s [ --version ] [ -v ] [ -c [loyear,]hiyear ] zonename ...\n"), for (i = 0; environ[i] != NULL; ++i) continue; - fakeenv = (char **) malloc((size_t) ((i + 2) * - sizeof *fakeenv)); - if (fakeenv == NULL || - (fakeenv[0] = (char *) malloc(longest + 4)) == NULL) { + fakeenv = malloc((i + 2) * sizeof *fakeenv); + if (fakeenv == NULL + || (fakeenv[0] = malloc(longest + 4)) == NULL) { (void) perror(progname); exit(EXIT_FAILURE); } @@ -444,7 +542,7 @@ _("%s: usage is %s [ --version ] [ -v ] [ -c [loyear,]hiyear ] zonename ...\n"), static char buf[MAX_STRING_LENGTH]; (void) strcpy(&fakeenv[0][3], argv[i]); - if (!vflag) { + if (! (vflag | Vflag)) { show(argv[i], now, FALSE); continue; } @@ -484,9 +582,11 @@ _("%s: usage is %s [ --version ] [ -v ] [ -c [loyear,]hiyear ] zonename ...\n"), * a transition when -i option is set */ if (!iflag) { #endif - 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); + } #ifdef ICU } #endif @@ -498,12 +598,10 @@ _("%s: usage is %s [ --version ] [ -v ] [ -c [loyear,]hiyear ] zonename ...\n"), (void) strncpy(buf, abbr(&tm), (sizeof buf) - 1); } for ( ; ; ) { - if (t >= cuthitime) - break; - newt = t + SECSPERHOUR * 12; - if (newt >= cuthitime) - break; - if (newt <= t) + newt = (t < absolute_max_time - SECSPERDAY / 2 + ? t + SECSPERDAY / 2 + : absolute_max_time); + if (cuthitime <= newt) break; newtmp = localtime(&newt); if (newtmp != NULL) @@ -551,12 +649,13 @@ _("%s: usage is %s [ --version ] [ -v ] [ -c [loyear,]hiyear ] zonename ...\n"), /* skip displaying info for the highest time, which is actually not * a transition when -i option is used*/ #endif - 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); + } #ifdef ICU } /* close file */ @@ -587,79 +686,45 @@ _("%s: usage is %s [ --version ] [ -v ] [ -c [loyear,]hiyear ] zonename ...\n"), return EXIT_FAILURE; } -static void -setabsolutes() -{ - if (0.5 == (time_t) 0.5) { - /* - ** time_t is floating. - */ - if (sizeof (time_t) == sizeof (float)) { - absolute_min_time = (time_t) -FLT_MAX; - absolute_max_time = (time_t) FLT_MAX; - } else if (sizeof (time_t) == sizeof (double)) { - absolute_min_time = (time_t) -DBL_MAX; - absolute_max_time = (time_t) DBL_MAX; - } else { - (void) fprintf(stderr, -_("%s: use of -v on system with floating time_t other than float or double\n"), - progname); - exit(EXIT_FAILURE); - } - } else if (0 > (time_t) -1) { - /* - ** time_t is signed. Assume overflow wraps around. - */ - time_t t = 0; - time_t t1 = 1; - - while (t < t1) { - t = t1; - t1 = 2 * t1 + 1; - } - - absolute_max_time = t; - t = -t; - absolute_min_time = t - 1; - if (t < absolute_min_time) - absolute_min_time = t; - } else { - /* - ** time_t is unsigned. - */ - absolute_min_time = 0; - absolute_max_time = absolute_min_time - 1; - } -} - static time_t -yeartot(y) -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; } @@ -668,7 +733,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; @@ -681,7 +745,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; @@ -711,13 +775,11 @@ hunt(char *name, time_t lot, time_t hit) ** Thanks to Paul Eggert for logic used in delta. */ -static long -delta(newp, oldp) -struct tm * newp; -struct tm * oldp; +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); @@ -746,7 +808,7 @@ show(char *zone, time_t t, int v) (void) printf(tformat(), t); } else { dumptime(tmp); - (void) printf(" UTC"); + (void) printf(" UT"); } (void) printf(" = "); } @@ -768,8 +830,7 @@ show(char *zone, time_t t, int v) } static char * -abbr(tmp) -struct tm * tmp; +abbr(struct tm *tmp) { register char * result; static char nada; @@ -786,20 +847,21 @@ struct tm * tmp; */ static const char * -tformat() +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)) @@ -808,8 +870,7 @@ tformat() } static void -dumptime(timeptr) -register const struct tm * timeptr; +dumptime(register const struct tm *timeptr) { static const char wday_name[][3] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" @@ -991,7 +1052,7 @@ static void getzones(char * basedir, char * relpath, struct listentry ** last, i if ((dp = opendir(path)) == NULL) { /* file */ - if (strstr(relpath, ".tab") == NULL) { + if (strstr(relpath, ".tab") == NULL && strcmp(relpath, "Etc/Unknown") != 0) { char * pzonename; listentry * pentry;