Wed, 31 Dec 2014 07:22:50 +0100
Correct previous dual key logic pending first delivery installment.
michael@0 | 1 | static char elsieid[] = "@(#)zdump.c 8.8"; |
michael@0 | 2 | |
michael@0 | 3 | /* |
michael@0 | 4 | ** This code has been made independent of the rest of the time |
michael@0 | 5 | ** conversion package to increase confidence in the verification it provides. |
michael@0 | 6 | ** You can use this code to help in verifying other implementations. |
michael@0 | 7 | */ |
michael@0 | 8 | |
michael@0 | 9 | /* |
michael@0 | 10 | * ICU note: Mr. Arthur David Olson (olsona@dc37a.nci.nih.gov) stated that |
michael@0 | 11 | * "zdump.c is indeed in the public domain" in e-mail on Feb 22, 2007. |
michael@0 | 12 | * This version of zdump.c is modified by ICU team to change output format |
michael@0 | 13 | * and some additional options. |
michael@0 | 14 | */ |
michael@0 | 15 | |
michael@0 | 16 | |
michael@0 | 17 | #include "stdio.h" /* for stdout, stderr, perror */ |
michael@0 | 18 | #include "string.h" /* for strcpy */ |
michael@0 | 19 | #include "sys/types.h" /* for time_t */ |
michael@0 | 20 | #include "time.h" /* for struct tm */ |
michael@0 | 21 | #include "stdlib.h" /* for exit, malloc, atoi */ |
michael@0 | 22 | #include "float.h" /* for FLT_MAX and DBL_MAX */ |
michael@0 | 23 | #include "ctype.h" /* for isalpha et al. */ |
michael@0 | 24 | |
michael@0 | 25 | /* Enable extensions and modifications for ICU. */ |
michael@0 | 26 | #define ICU |
michael@0 | 27 | |
michael@0 | 28 | #ifdef ICU |
michael@0 | 29 | #include "dirent.h" |
michael@0 | 30 | #endif |
michael@0 | 31 | |
michael@0 | 32 | #ifndef isascii |
michael@0 | 33 | #define isascii(x) 1 |
michael@0 | 34 | #endif /* !defined isascii */ |
michael@0 | 35 | |
michael@0 | 36 | #ifndef ZDUMP_LO_YEAR |
michael@0 | 37 | #define ZDUMP_LO_YEAR (-500) |
michael@0 | 38 | #endif /* !defined ZDUMP_LO_YEAR */ |
michael@0 | 39 | |
michael@0 | 40 | #ifndef ZDUMP_HI_YEAR |
michael@0 | 41 | #define ZDUMP_HI_YEAR 2500 |
michael@0 | 42 | #endif /* !defined ZDUMP_HI_YEAR */ |
michael@0 | 43 | |
michael@0 | 44 | #ifndef MAX_STRING_LENGTH |
michael@0 | 45 | #define MAX_STRING_LENGTH 1024 |
michael@0 | 46 | #endif /* !defined MAX_STRING_LENGTH */ |
michael@0 | 47 | |
michael@0 | 48 | #ifndef TRUE |
michael@0 | 49 | #define TRUE 1 |
michael@0 | 50 | #endif /* !defined TRUE */ |
michael@0 | 51 | |
michael@0 | 52 | #ifndef FALSE |
michael@0 | 53 | #define FALSE 0 |
michael@0 | 54 | #endif /* !defined FALSE */ |
michael@0 | 55 | |
michael@0 | 56 | #ifndef EXIT_SUCCESS |
michael@0 | 57 | #define EXIT_SUCCESS 0 |
michael@0 | 58 | #endif /* !defined EXIT_SUCCESS */ |
michael@0 | 59 | |
michael@0 | 60 | #ifndef EXIT_FAILURE |
michael@0 | 61 | #define EXIT_FAILURE 1 |
michael@0 | 62 | #endif /* !defined EXIT_FAILURE */ |
michael@0 | 63 | |
michael@0 | 64 | #ifndef SECSPERMIN |
michael@0 | 65 | #define SECSPERMIN 60 |
michael@0 | 66 | #endif /* !defined SECSPERMIN */ |
michael@0 | 67 | |
michael@0 | 68 | #ifndef MINSPERHOUR |
michael@0 | 69 | #define MINSPERHOUR 60 |
michael@0 | 70 | #endif /* !defined MINSPERHOUR */ |
michael@0 | 71 | |
michael@0 | 72 | #ifndef SECSPERHOUR |
michael@0 | 73 | #define SECSPERHOUR (SECSPERMIN * MINSPERHOUR) |
michael@0 | 74 | #endif /* !defined SECSPERHOUR */ |
michael@0 | 75 | |
michael@0 | 76 | #ifndef HOURSPERDAY |
michael@0 | 77 | #define HOURSPERDAY 24 |
michael@0 | 78 | #endif /* !defined HOURSPERDAY */ |
michael@0 | 79 | |
michael@0 | 80 | #ifndef EPOCH_YEAR |
michael@0 | 81 | #define EPOCH_YEAR 1970 |
michael@0 | 82 | #endif /* !defined EPOCH_YEAR */ |
michael@0 | 83 | |
michael@0 | 84 | #ifndef TM_YEAR_BASE |
michael@0 | 85 | #define TM_YEAR_BASE 1900 |
michael@0 | 86 | #endif /* !defined TM_YEAR_BASE */ |
michael@0 | 87 | |
michael@0 | 88 | #ifndef DAYSPERNYEAR |
michael@0 | 89 | #define DAYSPERNYEAR 365 |
michael@0 | 90 | #endif /* !defined DAYSPERNYEAR */ |
michael@0 | 91 | |
michael@0 | 92 | #ifndef isleap |
michael@0 | 93 | #define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0)) |
michael@0 | 94 | #endif /* !defined isleap */ |
michael@0 | 95 | |
michael@0 | 96 | #ifndef isleap_sum |
michael@0 | 97 | /* |
michael@0 | 98 | ** See tzfile.h for details on isleap_sum. |
michael@0 | 99 | */ |
michael@0 | 100 | #define isleap_sum(a, b) isleap((a) % 400 + (b) % 400) |
michael@0 | 101 | #endif /* !defined isleap_sum */ |
michael@0 | 102 | |
michael@0 | 103 | #define SECSPERDAY ((long) SECSPERHOUR * HOURSPERDAY) |
michael@0 | 104 | #define SECSPERNYEAR (SECSPERDAY * DAYSPERNYEAR) |
michael@0 | 105 | #define SECSPERLYEAR (SECSPERNYEAR + SECSPERDAY) |
michael@0 | 106 | |
michael@0 | 107 | #ifndef HAVE_GETTEXT |
michael@0 | 108 | #define HAVE_GETTEXT 0 |
michael@0 | 109 | #endif |
michael@0 | 110 | #if HAVE_GETTEXT |
michael@0 | 111 | #include "locale.h" /* for setlocale */ |
michael@0 | 112 | #include "libintl.h" |
michael@0 | 113 | #endif /* HAVE_GETTEXT */ |
michael@0 | 114 | |
michael@0 | 115 | #ifndef GNUC_or_lint |
michael@0 | 116 | #ifdef lint |
michael@0 | 117 | #define GNUC_or_lint |
michael@0 | 118 | #else /* !defined lint */ |
michael@0 | 119 | #ifdef __GNUC__ |
michael@0 | 120 | #define GNUC_or_lint |
michael@0 | 121 | #endif /* defined __GNUC__ */ |
michael@0 | 122 | #endif /* !defined lint */ |
michael@0 | 123 | #endif /* !defined GNUC_or_lint */ |
michael@0 | 124 | |
michael@0 | 125 | #ifndef INITIALIZE |
michael@0 | 126 | #ifdef GNUC_or_lint |
michael@0 | 127 | #define INITIALIZE(x) ((x) = 0) |
michael@0 | 128 | #else /* !defined GNUC_or_lint */ |
michael@0 | 129 | #define INITIALIZE(x) |
michael@0 | 130 | #endif /* !defined GNUC_or_lint */ |
michael@0 | 131 | #endif /* !defined INITIALIZE */ |
michael@0 | 132 | |
michael@0 | 133 | /* |
michael@0 | 134 | ** For the benefit of GNU folk... |
michael@0 | 135 | ** `_(MSGID)' uses the current locale's message library string for MSGID. |
michael@0 | 136 | ** The default is to use gettext if available, and use MSGID otherwise. |
michael@0 | 137 | */ |
michael@0 | 138 | |
michael@0 | 139 | #ifndef _ |
michael@0 | 140 | #if HAVE_GETTEXT |
michael@0 | 141 | #define _(msgid) gettext(msgid) |
michael@0 | 142 | #else /* !HAVE_GETTEXT */ |
michael@0 | 143 | #define _(msgid) msgid |
michael@0 | 144 | #endif /* !HAVE_GETTEXT */ |
michael@0 | 145 | #endif /* !defined _ */ |
michael@0 | 146 | |
michael@0 | 147 | #ifndef TZ_DOMAIN |
michael@0 | 148 | #define TZ_DOMAIN "tz" |
michael@0 | 149 | #endif /* !defined TZ_DOMAIN */ |
michael@0 | 150 | |
michael@0 | 151 | extern char ** environ; |
michael@0 | 152 | extern int getopt(int argc, char * const argv[], |
michael@0 | 153 | const char * options); |
michael@0 | 154 | extern char * optarg; |
michael@0 | 155 | extern int optind; |
michael@0 | 156 | extern char * tzname[2]; |
michael@0 | 157 | |
michael@0 | 158 | static time_t absolute_min_time; |
michael@0 | 159 | static time_t absolute_max_time; |
michael@0 | 160 | static size_t longest; |
michael@0 | 161 | static char * progname; |
michael@0 | 162 | static int warned; |
michael@0 | 163 | |
michael@0 | 164 | static char * abbr(struct tm * tmp); |
michael@0 | 165 | static void abbrok(const char * abbrp, const char * zone); |
michael@0 | 166 | static long delta(struct tm * newp, struct tm * oldp); |
michael@0 | 167 | static void dumptime(const struct tm * tmp); |
michael@0 | 168 | static time_t hunt(char * name, time_t lot, time_t hit); |
michael@0 | 169 | static void setabsolutes(void); |
michael@0 | 170 | static void show(char * zone, time_t t, int v); |
michael@0 | 171 | static const char * tformat(void); |
michael@0 | 172 | static time_t yeartot(long y); |
michael@0 | 173 | #ifdef ICU |
michael@0 | 174 | typedef struct listentry { |
michael@0 | 175 | char * name; |
michael@0 | 176 | struct listentry * next; |
michael@0 | 177 | } listentry; |
michael@0 | 178 | |
michael@0 | 179 | static time_t huntICU(char * name, time_t lot, time_t hit, FILE *fp); |
michael@0 | 180 | static void dumptimeICU(FILE * fp, time_t t); |
michael@0 | 181 | static void showICU(FILE * fp, char * zone, time_t t1, time_t t2); |
michael@0 | 182 | static int getall(struct listentry ** namelist); |
michael@0 | 183 | static void getzones(char * basedir, char * subdir, struct listentry ** last, int * count); |
michael@0 | 184 | #endif |
michael@0 | 185 | |
michael@0 | 186 | #ifndef TYPECHECK |
michael@0 | 187 | #define my_localtime localtime |
michael@0 | 188 | #else /* !defined TYPECHECK */ |
michael@0 | 189 | static struct tm * |
michael@0 | 190 | my_localtime(tp) |
michael@0 | 191 | time_t * tp; |
michael@0 | 192 | { |
michael@0 | 193 | register struct tm * tmp; |
michael@0 | 194 | |
michael@0 | 195 | tmp = localtime(tp); |
michael@0 | 196 | if (tp != NULL && tmp != NULL) { |
michael@0 | 197 | struct tm tm; |
michael@0 | 198 | register time_t t; |
michael@0 | 199 | |
michael@0 | 200 | tm = *tmp; |
michael@0 | 201 | t = mktime(&tm); |
michael@0 | 202 | if (t - *tp >= 1 || *tp - t >= 1) { |
michael@0 | 203 | (void) fflush(stdout); |
michael@0 | 204 | (void) fprintf(stderr, "\n%s: ", progname); |
michael@0 | 205 | (void) fprintf(stderr, tformat(), *tp); |
michael@0 | 206 | (void) fprintf(stderr, " ->"); |
michael@0 | 207 | (void) fprintf(stderr, " year=%d", tmp->tm_year); |
michael@0 | 208 | (void) fprintf(stderr, " mon=%d", tmp->tm_mon); |
michael@0 | 209 | (void) fprintf(stderr, " mday=%d", tmp->tm_mday); |
michael@0 | 210 | (void) fprintf(stderr, " hour=%d", tmp->tm_hour); |
michael@0 | 211 | (void) fprintf(stderr, " min=%d", tmp->tm_min); |
michael@0 | 212 | (void) fprintf(stderr, " sec=%d", tmp->tm_sec); |
michael@0 | 213 | (void) fprintf(stderr, " isdst=%d", tmp->tm_isdst); |
michael@0 | 214 | (void) fprintf(stderr, " -> "); |
michael@0 | 215 | (void) fprintf(stderr, tformat(), t); |
michael@0 | 216 | (void) fprintf(stderr, "\n"); |
michael@0 | 217 | } |
michael@0 | 218 | } |
michael@0 | 219 | return tmp; |
michael@0 | 220 | } |
michael@0 | 221 | #endif /* !defined TYPECHECK */ |
michael@0 | 222 | |
michael@0 | 223 | static void |
michael@0 | 224 | abbrok(abbrp, zone) |
michael@0 | 225 | const char * const abbrp; |
michael@0 | 226 | const char * const zone; |
michael@0 | 227 | { |
michael@0 | 228 | register const char * cp; |
michael@0 | 229 | register char * wp; |
michael@0 | 230 | |
michael@0 | 231 | if (warned) |
michael@0 | 232 | return; |
michael@0 | 233 | cp = abbrp; |
michael@0 | 234 | wp = NULL; |
michael@0 | 235 | while (isascii((unsigned char) *cp) && isalpha((unsigned char) *cp)) |
michael@0 | 236 | ++cp; |
michael@0 | 237 | if (cp - abbrp == 0) |
michael@0 | 238 | wp = _("lacks alphabetic at start"); |
michael@0 | 239 | else if (cp - abbrp < 3) |
michael@0 | 240 | wp = _("has fewer than 3 alphabetics"); |
michael@0 | 241 | else if (cp - abbrp > 6) |
michael@0 | 242 | wp = _("has more than 6 alphabetics"); |
michael@0 | 243 | if (wp == NULL && (*cp == '+' || *cp == '-')) { |
michael@0 | 244 | ++cp; |
michael@0 | 245 | if (isascii((unsigned char) *cp) && |
michael@0 | 246 | isdigit((unsigned char) *cp)) |
michael@0 | 247 | if (*cp++ == '1' && *cp >= '0' && *cp <= '4') |
michael@0 | 248 | ++cp; |
michael@0 | 249 | if (*cp != '\0') |
michael@0 | 250 | wp = _("differs from POSIX standard"); |
michael@0 | 251 | } |
michael@0 | 252 | if (wp == NULL) |
michael@0 | 253 | return; |
michael@0 | 254 | (void) fflush(stdout); |
michael@0 | 255 | (void) fprintf(stderr, |
michael@0 | 256 | _("%s: warning: zone \"%s\" abbreviation \"%s\" %s\n"), |
michael@0 | 257 | progname, zone, abbrp, wp); |
michael@0 | 258 | warned = TRUE; |
michael@0 | 259 | } |
michael@0 | 260 | |
michael@0 | 261 | static void |
michael@0 | 262 | usage(const char *progname, FILE *stream, int status) |
michael@0 | 263 | { |
michael@0 | 264 | (void) fprintf(stream, |
michael@0 | 265 | _("%s: usage is %s [ --version ] [ --help ] [ -v ] [ -c [loyear,]hiyear ] zonename ...\n\ |
michael@0 | 266 | \n\ |
michael@0 | 267 | Report bugs to tz@elsie.nci.nih.gov.\n"), |
michael@0 | 268 | progname, progname); |
michael@0 | 269 | exit(status); |
michael@0 | 270 | } |
michael@0 | 271 | |
michael@0 | 272 | int |
michael@0 | 273 | main(argc, argv) |
michael@0 | 274 | int argc; |
michael@0 | 275 | char * argv[]; |
michael@0 | 276 | { |
michael@0 | 277 | register int i; |
michael@0 | 278 | register int c; |
michael@0 | 279 | register int vflag; |
michael@0 | 280 | register char * cutarg; |
michael@0 | 281 | register long cutloyear = ZDUMP_LO_YEAR; |
michael@0 | 282 | register long cuthiyear = ZDUMP_HI_YEAR; |
michael@0 | 283 | register time_t cutlotime; |
michael@0 | 284 | register time_t cuthitime; |
michael@0 | 285 | register char ** fakeenv; |
michael@0 | 286 | time_t now; |
michael@0 | 287 | time_t t; |
michael@0 | 288 | time_t newt; |
michael@0 | 289 | struct tm tm; |
michael@0 | 290 | struct tm newtm; |
michael@0 | 291 | register struct tm * tmp; |
michael@0 | 292 | register struct tm * newtmp; |
michael@0 | 293 | #ifdef ICU |
michael@0 | 294 | int nextopt; |
michael@0 | 295 | char * dirarg; |
michael@0 | 296 | int aflag; |
michael@0 | 297 | int iflag; |
michael@0 | 298 | listentry * namelist = NULL; |
michael@0 | 299 | FILE * fp = stdout; |
michael@0 | 300 | #endif |
michael@0 | 301 | |
michael@0 | 302 | INITIALIZE(cutlotime); |
michael@0 | 303 | INITIALIZE(cuthitime); |
michael@0 | 304 | #if HAVE_GETTEXT |
michael@0 | 305 | (void) setlocale(LC_ALL, ""); |
michael@0 | 306 | #ifdef TZ_DOMAINDIR |
michael@0 | 307 | (void) bindtextdomain(TZ_DOMAIN, TZ_DOMAINDIR); |
michael@0 | 308 | #endif /* defined TEXTDOMAINDIR */ |
michael@0 | 309 | (void) textdomain(TZ_DOMAIN); |
michael@0 | 310 | #endif /* HAVE_GETTEXT */ |
michael@0 | 311 | progname = argv[0]; |
michael@0 | 312 | for (i = 1; i < argc; ++i) |
michael@0 | 313 | if (strcmp(argv[i], "--version") == 0) { |
michael@0 | 314 | (void) printf("%s\n", elsieid); |
michael@0 | 315 | exit(EXIT_SUCCESS); |
michael@0 | 316 | } else if (strcmp(argv[i], "--help") == 0) { |
michael@0 | 317 | usage(progname, stdout, EXIT_SUCCESS); |
michael@0 | 318 | } |
michael@0 | 319 | vflag = 0; |
michael@0 | 320 | cutarg = NULL; |
michael@0 | 321 | #ifdef ICU |
michael@0 | 322 | aflag = 0; |
michael@0 | 323 | iflag = 0; |
michael@0 | 324 | dirarg = NULL; |
michael@0 | 325 | nextopt = 1; |
michael@0 | 326 | while(nextopt) { |
michael@0 | 327 | c = getopt(argc, argv, "ac:d:iv"); |
michael@0 | 328 | switch(c) { |
michael@0 | 329 | case 'a': |
michael@0 | 330 | aflag = 1; |
michael@0 | 331 | break; |
michael@0 | 332 | case 'c': |
michael@0 | 333 | cutarg = optarg; |
michael@0 | 334 | break; |
michael@0 | 335 | case 'd': |
michael@0 | 336 | dirarg = optarg; |
michael@0 | 337 | break; |
michael@0 | 338 | case 'i': |
michael@0 | 339 | iflag = 1; |
michael@0 | 340 | break; |
michael@0 | 341 | case 'v': |
michael@0 | 342 | vflag = 1; |
michael@0 | 343 | break; |
michael@0 | 344 | default: |
michael@0 | 345 | nextopt = 0; |
michael@0 | 346 | break; |
michael@0 | 347 | } |
michael@0 | 348 | } |
michael@0 | 349 | if ((c != EOF && c != -1) || |
michael@0 | 350 | (optind == argc - 1 && strcmp(argv[optind], "=") == 0)) { |
michael@0 | 351 | (void) fprintf(stderr, |
michael@0 | 352 | _("%s: usage is %s [ --version ] [ -a ] [ -v ] [ -i ] [ -c [loyear,]hiyear ] [ -d dir ] [ zonename ... ]\n"), |
michael@0 | 353 | progname, progname); |
michael@0 | 354 | exit(EXIT_FAILURE); |
michael@0 | 355 | } |
michael@0 | 356 | |
michael@0 | 357 | if (dirarg != NULL) { |
michael@0 | 358 | DIR * dp; |
michael@0 | 359 | /* create the output directory */ |
michael@0 | 360 | mkdir(dirarg, 0777); |
michael@0 | 361 | if ((dp = opendir(dirarg)) == NULL) { |
michael@0 | 362 | fprintf(stderr, "cannot create the target directory"); |
michael@0 | 363 | exit(EXIT_FAILURE); |
michael@0 | 364 | } |
michael@0 | 365 | closedir(dp); |
michael@0 | 366 | } |
michael@0 | 367 | #else |
michael@0 | 368 | while ((c = getopt(argc, argv, "c:v")) == 'c' || c == 'v') |
michael@0 | 369 | if (c == 'v') |
michael@0 | 370 | vflag = 1; |
michael@0 | 371 | else cutarg = optarg; |
michael@0 | 372 | if ((c != EOF && c != -1) || |
michael@0 | 373 | (optind == argc - 1 && strcmp(argv[optind], "=") == 0)) { |
michael@0 | 374 | usage(progname, stderr, EXIT_FAILURE); |
michael@0 | 375 | } |
michael@0 | 376 | #endif |
michael@0 | 377 | if (vflag) { |
michael@0 | 378 | if (cutarg != NULL) { |
michael@0 | 379 | long lo; |
michael@0 | 380 | long hi; |
michael@0 | 381 | char dummy; |
michael@0 | 382 | |
michael@0 | 383 | if (sscanf(cutarg, "%ld%c", &hi, &dummy) == 1) { |
michael@0 | 384 | cuthiyear = hi; |
michael@0 | 385 | } else if (sscanf(cutarg, "%ld,%ld%c", |
michael@0 | 386 | &lo, &hi, &dummy) == 2) { |
michael@0 | 387 | cutloyear = lo; |
michael@0 | 388 | cuthiyear = hi; |
michael@0 | 389 | } else { |
michael@0 | 390 | (void) fprintf(stderr, _("%s: wild -c argument %s\n"), |
michael@0 | 391 | progname, cutarg); |
michael@0 | 392 | exit(EXIT_FAILURE); |
michael@0 | 393 | } |
michael@0 | 394 | } |
michael@0 | 395 | setabsolutes(); |
michael@0 | 396 | cutlotime = yeartot(cutloyear); |
michael@0 | 397 | cuthitime = yeartot(cuthiyear); |
michael@0 | 398 | } |
michael@0 | 399 | |
michael@0 | 400 | #ifdef ICU |
michael@0 | 401 | if (aflag) { |
michael@0 | 402 | /* get all available zones */ |
michael@0 | 403 | char ** fakeargv; |
michael@0 | 404 | int i; |
michael@0 | 405 | int count; |
michael@0 | 406 | |
michael@0 | 407 | count = getall(&namelist); |
michael@0 | 408 | |
michael@0 | 409 | fakeargv = (char **) malloc((size_t) (argc + count) * sizeof *argv); |
michael@0 | 410 | /* |
michael@0 | 411 | if ((fakeargv = (char **) malloc((size_t) (argc + count) * sizeof *argv)) == NULL) { |
michael@0 | 412 | exit(EXIT_FAILURE); |
michael@0 | 413 | } |
michael@0 | 414 | */ |
michael@0 | 415 | for (i = 0; i < argc; i++) { |
michael@0 | 416 | fakeargv[i] = argv[i]; |
michael@0 | 417 | } |
michael@0 | 418 | for (i = 0; i < count; i++) { |
michael@0 | 419 | fakeargv[i + argc] = namelist->name; |
michael@0 | 420 | namelist = namelist->next; |
michael@0 | 421 | } |
michael@0 | 422 | argv = fakeargv; |
michael@0 | 423 | argc += count; |
michael@0 | 424 | } |
michael@0 | 425 | #endif |
michael@0 | 426 | (void) time(&now); |
michael@0 | 427 | longest = 0; |
michael@0 | 428 | for (i = optind; i < argc; ++i) |
michael@0 | 429 | if (strlen(argv[i]) > longest) |
michael@0 | 430 | longest = strlen(argv[i]); |
michael@0 | 431 | { |
michael@0 | 432 | register int from; |
michael@0 | 433 | register int to; |
michael@0 | 434 | |
michael@0 | 435 | for (i = 0; environ[i] != NULL; ++i) |
michael@0 | 436 | continue; |
michael@0 | 437 | fakeenv = (char **) malloc((size_t) ((i + 2) * |
michael@0 | 438 | sizeof *fakeenv)); |
michael@0 | 439 | if (fakeenv == NULL || |
michael@0 | 440 | (fakeenv[0] = (char *) malloc(longest + 4)) == NULL) { |
michael@0 | 441 | (void) perror(progname); |
michael@0 | 442 | exit(EXIT_FAILURE); |
michael@0 | 443 | } |
michael@0 | 444 | to = 0; |
michael@0 | 445 | (void) strcpy(fakeenv[to++], "TZ="); |
michael@0 | 446 | for (from = 0; environ[from] != NULL; ++from) |
michael@0 | 447 | if (strncmp(environ[from], "TZ=", 3) != 0) |
michael@0 | 448 | fakeenv[to++] = environ[from]; |
michael@0 | 449 | fakeenv[to] = NULL; |
michael@0 | 450 | environ = fakeenv; |
michael@0 | 451 | } |
michael@0 | 452 | for (i = optind; i < argc; ++i) { |
michael@0 | 453 | static char buf[MAX_STRING_LENGTH]; |
michael@0 | 454 | |
michael@0 | 455 | (void) strcpy(&fakeenv[0][3], argv[i]); |
michael@0 | 456 | if (!vflag) { |
michael@0 | 457 | show(argv[i], now, FALSE); |
michael@0 | 458 | continue; |
michael@0 | 459 | } |
michael@0 | 460 | #ifdef ICU |
michael@0 | 461 | fp = NULL; |
michael@0 | 462 | if (iflag) { |
michael@0 | 463 | if (dirarg == NULL) { |
michael@0 | 464 | /* we want to display a zone name here */ |
michael@0 | 465 | if (i != optind) { |
michael@0 | 466 | printf("\n"); |
michael@0 | 467 | } |
michael@0 | 468 | printf("ZONE: %s\n", argv[i]); |
michael@0 | 469 | } else { |
michael@0 | 470 | int zstart; |
michael@0 | 471 | char path[FILENAME_MAX + 1]; |
michael@0 | 472 | strcpy(path, dirarg); |
michael@0 | 473 | strcat(path, "/"); |
michael@0 | 474 | zstart = strlen(path); |
michael@0 | 475 | strcat(path, argv[i]); |
michael@0 | 476 | /* replace '/' with '-' */ |
michael@0 | 477 | while(path[++zstart] != 0) { |
michael@0 | 478 | if (path[zstart] == '/') { |
michael@0 | 479 | path[zstart] = '-'; |
michael@0 | 480 | } |
michael@0 | 481 | } |
michael@0 | 482 | if ((fp = fopen(path, "w")) == NULL) { |
michael@0 | 483 | fprintf(stderr, "cannot create output file %s\n", path); |
michael@0 | 484 | exit(EXIT_FAILURE); |
michael@0 | 485 | } |
michael@0 | 486 | } |
michael@0 | 487 | } |
michael@0 | 488 | #endif |
michael@0 | 489 | warned = FALSE; |
michael@0 | 490 | t = absolute_min_time; |
michael@0 | 491 | #ifdef ICU |
michael@0 | 492 | /* skip displaying info for the lowest time, which is actually not |
michael@0 | 493 | * a transition when -i option is set */ |
michael@0 | 494 | if (!iflag) { |
michael@0 | 495 | #endif |
michael@0 | 496 | show(argv[i], t, TRUE); |
michael@0 | 497 | t += SECSPERHOUR * HOURSPERDAY; |
michael@0 | 498 | show(argv[i], t, TRUE); |
michael@0 | 499 | #ifdef ICU |
michael@0 | 500 | } |
michael@0 | 501 | #endif |
michael@0 | 502 | if (t < cutlotime) |
michael@0 | 503 | t = cutlotime; |
michael@0 | 504 | tmp = my_localtime(&t); |
michael@0 | 505 | if (tmp != NULL) { |
michael@0 | 506 | tm = *tmp; |
michael@0 | 507 | (void) strncpy(buf, abbr(&tm), (sizeof buf) - 1); |
michael@0 | 508 | } |
michael@0 | 509 | for ( ; ; ) { |
michael@0 | 510 | if (t >= cuthitime || t >= cuthitime - SECSPERHOUR * 12) |
michael@0 | 511 | break; |
michael@0 | 512 | newt = t + SECSPERHOUR * 12; |
michael@0 | 513 | newtmp = localtime(&newt); |
michael@0 | 514 | if (newtmp != NULL) |
michael@0 | 515 | newtm = *newtmp; |
michael@0 | 516 | #ifdef ICU |
michael@0 | 517 | if (iflag) { |
michael@0 | 518 | /* We do not want to capture transitions just for |
michael@0 | 519 | * abbreviated zone name changes */ |
michael@0 | 520 | if ((tmp == NULL || newtmp == NULL) ? (tmp != newtmp) : |
michael@0 | 521 | (delta(&newtm, &tm) != (newt - t) || |
michael@0 | 522 | newtm.tm_isdst != tm.tm_isdst)) { |
michael@0 | 523 | newt = huntICU(argv[i], t, newt, fp); |
michael@0 | 524 | newtmp = localtime(&newt); |
michael@0 | 525 | if (newtmp != NULL) { |
michael@0 | 526 | newtm = *newtmp; |
michael@0 | 527 | (void) strncpy(buf, |
michael@0 | 528 | abbr(&newtm), |
michael@0 | 529 | (sizeof buf) - 1); |
michael@0 | 530 | } |
michael@0 | 531 | } |
michael@0 | 532 | } else { |
michael@0 | 533 | #endif |
michael@0 | 534 | if ((tmp == NULL || newtmp == NULL) ? (tmp != newtmp) : |
michael@0 | 535 | (delta(&newtm, &tm) != (newt - t) || |
michael@0 | 536 | newtm.tm_isdst != tm.tm_isdst || |
michael@0 | 537 | strcmp(abbr(&newtm), buf) != 0)) { |
michael@0 | 538 | newt = hunt(argv[i], t, newt); |
michael@0 | 539 | newtmp = localtime(&newt); |
michael@0 | 540 | if (newtmp != NULL) { |
michael@0 | 541 | newtm = *newtmp; |
michael@0 | 542 | (void) strncpy(buf, |
michael@0 | 543 | abbr(&newtm), |
michael@0 | 544 | (sizeof buf) - 1); |
michael@0 | 545 | } |
michael@0 | 546 | } |
michael@0 | 547 | #ifdef ICU |
michael@0 | 548 | } |
michael@0 | 549 | #endif |
michael@0 | 550 | t = newt; |
michael@0 | 551 | tm = newtm; |
michael@0 | 552 | tmp = newtmp; |
michael@0 | 553 | } |
michael@0 | 554 | #ifdef ICU |
michael@0 | 555 | if (!iflag) { |
michael@0 | 556 | /* skip displaying info for the highest time, which is actually not |
michael@0 | 557 | * a transition when -i option is used*/ |
michael@0 | 558 | #endif |
michael@0 | 559 | t = absolute_max_time; |
michael@0 | 560 | t -= SECSPERHOUR * HOURSPERDAY; |
michael@0 | 561 | show(argv[i], t, TRUE); |
michael@0 | 562 | t += SECSPERHOUR * HOURSPERDAY; |
michael@0 | 563 | show(argv[i], t, TRUE); |
michael@0 | 564 | |
michael@0 | 565 | #ifdef ICU |
michael@0 | 566 | } |
michael@0 | 567 | /* close file */ |
michael@0 | 568 | if (fp != NULL) { |
michael@0 | 569 | fclose(fp); |
michael@0 | 570 | } |
michael@0 | 571 | #endif |
michael@0 | 572 | } |
michael@0 | 573 | if (fflush(stdout) || ferror(stdout)) { |
michael@0 | 574 | (void) fprintf(stderr, "%s: ", progname); |
michael@0 | 575 | (void) perror(_("Error writing to standard output")); |
michael@0 | 576 | exit(EXIT_FAILURE); |
michael@0 | 577 | } |
michael@0 | 578 | #ifdef ICU |
michael@0 | 579 | if (aflag) { |
michael@0 | 580 | struct listentry * entry = namelist; |
michael@0 | 581 | struct listentry * next; |
michael@0 | 582 | while (entry != NULL) { |
michael@0 | 583 | free(entry->name); |
michael@0 | 584 | next = entry->next; |
michael@0 | 585 | free(entry); |
michael@0 | 586 | entry = next; |
michael@0 | 587 | } |
michael@0 | 588 | } |
michael@0 | 589 | #endif |
michael@0 | 590 | exit(EXIT_SUCCESS); |
michael@0 | 591 | /* If exit fails to exit... */ |
michael@0 | 592 | return EXIT_FAILURE; |
michael@0 | 593 | } |
michael@0 | 594 | |
michael@0 | 595 | static void |
michael@0 | 596 | setabsolutes(void) |
michael@0 | 597 | { |
michael@0 | 598 | if (0.5 == (time_t) 0.5) { |
michael@0 | 599 | /* |
michael@0 | 600 | ** time_t is floating. |
michael@0 | 601 | */ |
michael@0 | 602 | if (sizeof (time_t) == sizeof (float)) { |
michael@0 | 603 | absolute_min_time = (time_t) -FLT_MAX; |
michael@0 | 604 | absolute_max_time = (time_t) FLT_MAX; |
michael@0 | 605 | } else if (sizeof (time_t) == sizeof (double)) { |
michael@0 | 606 | absolute_min_time = (time_t) -DBL_MAX; |
michael@0 | 607 | absolute_max_time = (time_t) DBL_MAX; |
michael@0 | 608 | } else { |
michael@0 | 609 | (void) fprintf(stderr, |
michael@0 | 610 | _("%s: use of -v on system with floating time_t other than float or double\n"), |
michael@0 | 611 | progname); |
michael@0 | 612 | exit(EXIT_FAILURE); |
michael@0 | 613 | } |
michael@0 | 614 | } else if (0 > (time_t) -1) { |
michael@0 | 615 | /* |
michael@0 | 616 | ** time_t is signed. Assume overflow wraps around. |
michael@0 | 617 | */ |
michael@0 | 618 | time_t t = 0; |
michael@0 | 619 | time_t t1 = 1; |
michael@0 | 620 | |
michael@0 | 621 | while (t < t1) { |
michael@0 | 622 | t = t1; |
michael@0 | 623 | t1 = 2 * t1 + 1; |
michael@0 | 624 | } |
michael@0 | 625 | |
michael@0 | 626 | absolute_max_time = t; |
michael@0 | 627 | t = -t; |
michael@0 | 628 | absolute_min_time = t - 1; |
michael@0 | 629 | if (t < absolute_min_time) |
michael@0 | 630 | absolute_min_time = t; |
michael@0 | 631 | } else { |
michael@0 | 632 | /* |
michael@0 | 633 | ** time_t is unsigned. |
michael@0 | 634 | */ |
michael@0 | 635 | absolute_min_time = 0; |
michael@0 | 636 | absolute_max_time = absolute_min_time - 1; |
michael@0 | 637 | } |
michael@0 | 638 | } |
michael@0 | 639 | |
michael@0 | 640 | static time_t |
michael@0 | 641 | yeartot(y) |
michael@0 | 642 | const long y; |
michael@0 | 643 | { |
michael@0 | 644 | register long myy; |
michael@0 | 645 | register long seconds; |
michael@0 | 646 | register time_t t; |
michael@0 | 647 | |
michael@0 | 648 | myy = EPOCH_YEAR; |
michael@0 | 649 | t = 0; |
michael@0 | 650 | while (myy != y) { |
michael@0 | 651 | if (myy < y) { |
michael@0 | 652 | seconds = isleap(myy) ? SECSPERLYEAR : SECSPERNYEAR; |
michael@0 | 653 | ++myy; |
michael@0 | 654 | if (t > absolute_max_time - seconds) { |
michael@0 | 655 | t = absolute_max_time; |
michael@0 | 656 | break; |
michael@0 | 657 | } |
michael@0 | 658 | t += seconds; |
michael@0 | 659 | } else { |
michael@0 | 660 | --myy; |
michael@0 | 661 | seconds = isleap(myy) ? SECSPERLYEAR : SECSPERNYEAR; |
michael@0 | 662 | if (t < absolute_min_time + seconds) { |
michael@0 | 663 | t = absolute_min_time; |
michael@0 | 664 | break; |
michael@0 | 665 | } |
michael@0 | 666 | t -= seconds; |
michael@0 | 667 | } |
michael@0 | 668 | } |
michael@0 | 669 | return t; |
michael@0 | 670 | } |
michael@0 | 671 | |
michael@0 | 672 | static time_t |
michael@0 | 673 | hunt(char *name, time_t lot, time_t hit) |
michael@0 | 674 | { |
michael@0 | 675 | time_t t; |
michael@0 | 676 | long diff; |
michael@0 | 677 | struct tm lotm; |
michael@0 | 678 | register struct tm * lotmp; |
michael@0 | 679 | struct tm tm; |
michael@0 | 680 | register struct tm * tmp; |
michael@0 | 681 | char loab[MAX_STRING_LENGTH]; |
michael@0 | 682 | |
michael@0 | 683 | lotmp = my_localtime(&lot); |
michael@0 | 684 | if (lotmp != NULL) { |
michael@0 | 685 | lotm = *lotmp; |
michael@0 | 686 | (void) strncpy(loab, abbr(&lotm), (sizeof loab) - 1); |
michael@0 | 687 | } |
michael@0 | 688 | for ( ; ; ) { |
michael@0 | 689 | diff = (long) (hit - lot); |
michael@0 | 690 | if (diff < 2) |
michael@0 | 691 | break; |
michael@0 | 692 | t = lot; |
michael@0 | 693 | t += diff / 2; |
michael@0 | 694 | if (t <= lot) |
michael@0 | 695 | ++t; |
michael@0 | 696 | else if (t >= hit) |
michael@0 | 697 | --t; |
michael@0 | 698 | tmp = my_localtime(&t); |
michael@0 | 699 | if (tmp != NULL) |
michael@0 | 700 | tm = *tmp; |
michael@0 | 701 | if ((lotmp == NULL || tmp == NULL) ? (lotmp == tmp) : |
michael@0 | 702 | (delta(&tm, &lotm) == (t - lot) && |
michael@0 | 703 | tm.tm_isdst == lotm.tm_isdst && |
michael@0 | 704 | strcmp(abbr(&tm), loab) == 0)) { |
michael@0 | 705 | lot = t; |
michael@0 | 706 | lotm = tm; |
michael@0 | 707 | lotmp = tmp; |
michael@0 | 708 | } else hit = t; |
michael@0 | 709 | } |
michael@0 | 710 | show(name, lot, TRUE); |
michael@0 | 711 | show(name, hit, TRUE); |
michael@0 | 712 | return hit; |
michael@0 | 713 | } |
michael@0 | 714 | |
michael@0 | 715 | /* |
michael@0 | 716 | ** Thanks to Paul Eggert for logic used in delta. |
michael@0 | 717 | */ |
michael@0 | 718 | |
michael@0 | 719 | static long |
michael@0 | 720 | delta(newp, oldp) |
michael@0 | 721 | struct tm * newp; |
michael@0 | 722 | struct tm * oldp; |
michael@0 | 723 | { |
michael@0 | 724 | register long result; |
michael@0 | 725 | register int tmy; |
michael@0 | 726 | |
michael@0 | 727 | if (newp->tm_year < oldp->tm_year) |
michael@0 | 728 | return -delta(oldp, newp); |
michael@0 | 729 | result = 0; |
michael@0 | 730 | for (tmy = oldp->tm_year; tmy < newp->tm_year; ++tmy) |
michael@0 | 731 | result += DAYSPERNYEAR + isleap_sum(tmy, TM_YEAR_BASE); |
michael@0 | 732 | result += newp->tm_yday - oldp->tm_yday; |
michael@0 | 733 | result *= HOURSPERDAY; |
michael@0 | 734 | result += newp->tm_hour - oldp->tm_hour; |
michael@0 | 735 | result *= MINSPERHOUR; |
michael@0 | 736 | result += newp->tm_min - oldp->tm_min; |
michael@0 | 737 | result *= SECSPERMIN; |
michael@0 | 738 | result += newp->tm_sec - oldp->tm_sec; |
michael@0 | 739 | return result; |
michael@0 | 740 | } |
michael@0 | 741 | |
michael@0 | 742 | static void |
michael@0 | 743 | show(char *zone, time_t t, int v) |
michael@0 | 744 | { |
michael@0 | 745 | register struct tm * tmp; |
michael@0 | 746 | |
michael@0 | 747 | (void) printf("%-*s ", (int) longest, zone); |
michael@0 | 748 | if (v) { |
michael@0 | 749 | tmp = gmtime(&t); |
michael@0 | 750 | if (tmp == NULL) { |
michael@0 | 751 | (void) printf(tformat(), t); |
michael@0 | 752 | } else { |
michael@0 | 753 | dumptime(tmp); |
michael@0 | 754 | (void) printf(" UTC"); |
michael@0 | 755 | } |
michael@0 | 756 | (void) printf(" = "); |
michael@0 | 757 | } |
michael@0 | 758 | tmp = my_localtime(&t); |
michael@0 | 759 | dumptime(tmp); |
michael@0 | 760 | if (tmp != NULL) { |
michael@0 | 761 | if (*abbr(tmp) != '\0') |
michael@0 | 762 | (void) printf(" %s", abbr(tmp)); |
michael@0 | 763 | if (v) { |
michael@0 | 764 | (void) printf(" isdst=%d", tmp->tm_isdst); |
michael@0 | 765 | #ifdef TM_GMTOFF |
michael@0 | 766 | (void) printf(" gmtoff=%ld", tmp->TM_GMTOFF); |
michael@0 | 767 | #endif /* defined TM_GMTOFF */ |
michael@0 | 768 | } |
michael@0 | 769 | } |
michael@0 | 770 | (void) printf("\n"); |
michael@0 | 771 | if (tmp != NULL && *abbr(tmp) != '\0') |
michael@0 | 772 | abbrok(abbr(tmp), zone); |
michael@0 | 773 | } |
michael@0 | 774 | |
michael@0 | 775 | static char * |
michael@0 | 776 | abbr(tmp) |
michael@0 | 777 | struct tm * tmp; |
michael@0 | 778 | { |
michael@0 | 779 | register char * result; |
michael@0 | 780 | static char nada; |
michael@0 | 781 | |
michael@0 | 782 | if (tmp->tm_isdst != 0 && tmp->tm_isdst != 1) |
michael@0 | 783 | return &nada; |
michael@0 | 784 | result = tzname[tmp->tm_isdst]; |
michael@0 | 785 | return (result == NULL) ? &nada : result; |
michael@0 | 786 | } |
michael@0 | 787 | |
michael@0 | 788 | /* |
michael@0 | 789 | ** The code below can fail on certain theoretical systems; |
michael@0 | 790 | ** it works on all known real-world systems as of 2004-12-30. |
michael@0 | 791 | */ |
michael@0 | 792 | |
michael@0 | 793 | static const char * |
michael@0 | 794 | tformat(void) |
michael@0 | 795 | { |
michael@0 | 796 | if (0.5 == (time_t) 0.5) { /* floating */ |
michael@0 | 797 | if (sizeof (time_t) > sizeof (double)) |
michael@0 | 798 | return "%Lg"; |
michael@0 | 799 | return "%g"; |
michael@0 | 800 | } |
michael@0 | 801 | if (0 > (time_t) -1) { /* signed */ |
michael@0 | 802 | if (sizeof (time_t) > sizeof (long)) |
michael@0 | 803 | return "%lld"; |
michael@0 | 804 | if (sizeof (time_t) > sizeof (int)) |
michael@0 | 805 | return "%ld"; |
michael@0 | 806 | return "%d"; |
michael@0 | 807 | } |
michael@0 | 808 | if (sizeof (time_t) > sizeof (unsigned long)) |
michael@0 | 809 | return "%llu"; |
michael@0 | 810 | if (sizeof (time_t) > sizeof (unsigned int)) |
michael@0 | 811 | return "%lu"; |
michael@0 | 812 | return "%u"; |
michael@0 | 813 | } |
michael@0 | 814 | |
michael@0 | 815 | static void |
michael@0 | 816 | dumptime(timeptr) |
michael@0 | 817 | register const struct tm * timeptr; |
michael@0 | 818 | { |
michael@0 | 819 | static const char wday_name[][3] = { |
michael@0 | 820 | "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" |
michael@0 | 821 | }; |
michael@0 | 822 | static const char mon_name[][3] = { |
michael@0 | 823 | "Jan", "Feb", "Mar", "Apr", "May", "Jun", |
michael@0 | 824 | "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" |
michael@0 | 825 | }; |
michael@0 | 826 | register const char * wn; |
michael@0 | 827 | register const char * mn; |
michael@0 | 828 | register int lead; |
michael@0 | 829 | register int trail; |
michael@0 | 830 | |
michael@0 | 831 | if (timeptr == NULL) { |
michael@0 | 832 | (void) printf("NULL"); |
michael@0 | 833 | return; |
michael@0 | 834 | } |
michael@0 | 835 | /* |
michael@0 | 836 | ** The packaged versions of localtime and gmtime never put out-of-range |
michael@0 | 837 | ** values in tm_wday or tm_mon, but since this code might be compiled |
michael@0 | 838 | ** with other (perhaps experimental) versions, paranoia is in order. |
michael@0 | 839 | */ |
michael@0 | 840 | if (timeptr->tm_wday < 0 || timeptr->tm_wday >= |
michael@0 | 841 | (int) (sizeof wday_name / sizeof wday_name[0])) |
michael@0 | 842 | wn = "???"; |
michael@0 | 843 | else wn = wday_name[timeptr->tm_wday]; |
michael@0 | 844 | if (timeptr->tm_mon < 0 || timeptr->tm_mon >= |
michael@0 | 845 | (int) (sizeof mon_name / sizeof mon_name[0])) |
michael@0 | 846 | mn = "???"; |
michael@0 | 847 | else mn = mon_name[timeptr->tm_mon]; |
michael@0 | 848 | (void) printf("%.3s %.3s%3d %.2d:%.2d:%.2d ", |
michael@0 | 849 | wn, mn, |
michael@0 | 850 | timeptr->tm_mday, timeptr->tm_hour, |
michael@0 | 851 | timeptr->tm_min, timeptr->tm_sec); |
michael@0 | 852 | #define DIVISOR 10 |
michael@0 | 853 | trail = timeptr->tm_year % DIVISOR + TM_YEAR_BASE % DIVISOR; |
michael@0 | 854 | lead = timeptr->tm_year / DIVISOR + TM_YEAR_BASE / DIVISOR + |
michael@0 | 855 | trail / DIVISOR; |
michael@0 | 856 | trail %= DIVISOR; |
michael@0 | 857 | if (trail < 0 && lead > 0) { |
michael@0 | 858 | trail += DIVISOR; |
michael@0 | 859 | --lead; |
michael@0 | 860 | } else if (lead < 0 && trail > 0) { |
michael@0 | 861 | trail -= DIVISOR; |
michael@0 | 862 | ++lead; |
michael@0 | 863 | } |
michael@0 | 864 | if (lead == 0) |
michael@0 | 865 | (void) printf("%d", trail); |
michael@0 | 866 | else (void) printf("%d%d", lead, ((trail < 0) ? -trail : trail)); |
michael@0 | 867 | } |
michael@0 | 868 | |
michael@0 | 869 | #ifdef ICU |
michael@0 | 870 | static time_t |
michael@0 | 871 | huntICU(char *name, time_t lot, time_t hit, FILE * fp) |
michael@0 | 872 | { |
michael@0 | 873 | time_t t; |
michael@0 | 874 | long diff; |
michael@0 | 875 | struct tm lotm; |
michael@0 | 876 | register struct tm * lotmp; |
michael@0 | 877 | struct tm tm; |
michael@0 | 878 | register struct tm * tmp; |
michael@0 | 879 | char loab[MAX_STRING_LENGTH]; |
michael@0 | 880 | |
michael@0 | 881 | lotmp = my_localtime(&lot); |
michael@0 | 882 | if (lotmp != NULL) { |
michael@0 | 883 | lotm = *lotmp; |
michael@0 | 884 | (void) strncpy(loab, abbr(&lotm), (sizeof loab) - 1); |
michael@0 | 885 | } |
michael@0 | 886 | for ( ; ; ) { |
michael@0 | 887 | diff = (long) (hit - lot); |
michael@0 | 888 | if (diff < 2) |
michael@0 | 889 | break; |
michael@0 | 890 | t = lot; |
michael@0 | 891 | t += diff / 2; |
michael@0 | 892 | if (t <= lot) |
michael@0 | 893 | ++t; |
michael@0 | 894 | else if (t >= hit) |
michael@0 | 895 | --t; |
michael@0 | 896 | tmp = my_localtime(&t); |
michael@0 | 897 | if (tmp != NULL) |
michael@0 | 898 | tm = *tmp; |
michael@0 | 899 | /* We do not want to capture transitions just for |
michael@0 | 900 | * abbreviated zone name changes */ |
michael@0 | 901 | if ((lotmp == NULL || tmp == NULL) ? (lotmp == tmp) : |
michael@0 | 902 | (delta(&tm, &lotm) == (t - lot) && |
michael@0 | 903 | tm.tm_isdst == lotm.tm_isdst)) { |
michael@0 | 904 | lot = t; |
michael@0 | 905 | lotm = tm; |
michael@0 | 906 | lotmp = tmp; |
michael@0 | 907 | } else hit = t; |
michael@0 | 908 | } |
michael@0 | 909 | showICU(fp, name, lot, hit); |
michael@0 | 910 | return hit; |
michael@0 | 911 | } |
michael@0 | 912 | |
michael@0 | 913 | static void showICU(FILE * fp, char *zone, time_t t1, time_t t2) |
michael@0 | 914 | { |
michael@0 | 915 | if (fp == NULL) { |
michael@0 | 916 | fp = stdout; |
michael@0 | 917 | } |
michael@0 | 918 | dumptimeICU(fp, t1); |
michael@0 | 919 | fprintf(fp, " > "); |
michael@0 | 920 | dumptimeICU(fp, t2); |
michael@0 | 921 | fprintf(fp, "\n"); |
michael@0 | 922 | } |
michael@0 | 923 | |
michael@0 | 924 | static void dumptimeICU(FILE * fp, time_t t) |
michael@0 | 925 | { |
michael@0 | 926 | static const char wday_name[][3] = { |
michael@0 | 927 | "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" |
michael@0 | 928 | }; |
michael@0 | 929 | struct tm gmt; |
michael@0 | 930 | struct tm loc; |
michael@0 | 931 | register int lead; |
michael@0 | 932 | register int trail; |
michael@0 | 933 | long offset; |
michael@0 | 934 | long hour, min, sec; |
michael@0 | 935 | |
michael@0 | 936 | loc = *my_localtime(&t); |
michael@0 | 937 | |
michael@0 | 938 | trail = loc.tm_year % DIVISOR + TM_YEAR_BASE % DIVISOR; |
michael@0 | 939 | lead = loc.tm_year / DIVISOR + TM_YEAR_BASE / DIVISOR + trail / DIVISOR; |
michael@0 | 940 | trail %= DIVISOR; |
michael@0 | 941 | if (trail < 0 && lead > 0) { |
michael@0 | 942 | trail += DIVISOR; |
michael@0 | 943 | --lead; |
michael@0 | 944 | } else if (lead < 0 && trail > 0) { |
michael@0 | 945 | trail -= DIVISOR; |
michael@0 | 946 | ++lead; |
michael@0 | 947 | } |
michael@0 | 948 | |
michael@0 | 949 | fprintf(fp, "%04d-%02d-%02d", lead * DIVISOR + trail, loc.tm_mon + 1, loc.tm_mday); |
michael@0 | 950 | fprintf(fp, " %.3s ", wday_name[loc.tm_wday]); |
michael@0 | 951 | fprintf(fp, "%02d:%02d:%02d", loc.tm_hour, loc.tm_min, loc.tm_sec); |
michael@0 | 952 | |
michael@0 | 953 | gmt = *gmtime(&t); |
michael@0 | 954 | offset = delta(&loc, &gmt); |
michael@0 | 955 | if (offset < 0) { |
michael@0 | 956 | offset = -offset; |
michael@0 | 957 | fprintf(fp, "-"); |
michael@0 | 958 | } else { |
michael@0 | 959 | fprintf(fp, "+"); |
michael@0 | 960 | } |
michael@0 | 961 | |
michael@0 | 962 | sec = offset % 60; |
michael@0 | 963 | offset = (offset - sec) / 60; |
michael@0 | 964 | min = offset % 60; |
michael@0 | 965 | hour = offset / 60; |
michael@0 | 966 | |
michael@0 | 967 | fprintf(fp, "%02d", hour); |
michael@0 | 968 | fprintf(fp, "%02d", min); |
michael@0 | 969 | fprintf(fp, "%02d", sec); |
michael@0 | 970 | fprintf(fp, "[DST=%d]", loc.tm_isdst); |
michael@0 | 971 | } |
michael@0 | 972 | |
michael@0 | 973 | static int getall(struct listentry ** namelist) { |
michael@0 | 974 | int count = 0; |
michael@0 | 975 | struct listentry dummyentry; |
michael@0 | 976 | struct listentry * last = &dummyentry; |
michael@0 | 977 | |
michael@0 | 978 | getzones(TZDIR, NULL, &last, &count); |
michael@0 | 979 | if (count > 0) { |
michael@0 | 980 | *namelist = dummyentry.next; |
michael@0 | 981 | } |
michael@0 | 982 | |
michael@0 | 983 | return count; |
michael@0 | 984 | } |
michael@0 | 985 | |
michael@0 | 986 | static void getzones(char * basedir, char * relpath, struct listentry ** last, int * count) { |
michael@0 | 987 | char path[FILENAME_MAX + 1]; |
michael@0 | 988 | struct dirent * dir; |
michael@0 | 989 | DIR * dp; |
michael@0 | 990 | |
michael@0 | 991 | strcpy(path, basedir); |
michael@0 | 992 | if (relpath != NULL) { |
michael@0 | 993 | strcat(path, "/"); |
michael@0 | 994 | strcat(path, relpath); |
michael@0 | 995 | } |
michael@0 | 996 | |
michael@0 | 997 | if ((dp = opendir(path)) == NULL) { |
michael@0 | 998 | /* file */ |
michael@0 | 999 | if (strstr(relpath, ".tab") == NULL && strcmp(relpath, "Etc/Unknown") != 0) { |
michael@0 | 1000 | char * pzonename; |
michael@0 | 1001 | listentry * pentry; |
michael@0 | 1002 | |
michael@0 | 1003 | if ((pzonename = malloc(strlen(relpath) + 1)) == NULL) { |
michael@0 | 1004 | exit(EXIT_FAILURE); |
michael@0 | 1005 | } |
michael@0 | 1006 | strcpy(pzonename, relpath); |
michael@0 | 1007 | |
michael@0 | 1008 | if ((pentry = malloc(sizeof(listentry))) == NULL) { |
michael@0 | 1009 | exit(EXIT_FAILURE); |
michael@0 | 1010 | } |
michael@0 | 1011 | |
michael@0 | 1012 | pentry->name = pzonename; |
michael@0 | 1013 | pentry->next = NULL; |
michael@0 | 1014 | (*last)->next = pentry; |
michael@0 | 1015 | *last = pentry; |
michael@0 | 1016 | (*count)++; |
michael@0 | 1017 | } |
michael@0 | 1018 | } else { |
michael@0 | 1019 | /* directory */ |
michael@0 | 1020 | while ((dir = readdir(dp)) != NULL) { |
michael@0 | 1021 | char subpath[FILENAME_MAX + 1]; |
michael@0 | 1022 | |
michael@0 | 1023 | if (strcmp(dir->d_name, ".") == 0 |
michael@0 | 1024 | || strcmp(dir->d_name, "..") == 0) { |
michael@0 | 1025 | continue; |
michael@0 | 1026 | } |
michael@0 | 1027 | if (relpath != NULL) { |
michael@0 | 1028 | strcpy(subpath, relpath); |
michael@0 | 1029 | strcat(subpath, "/"); |
michael@0 | 1030 | strcat(subpath, dir->d_name); |
michael@0 | 1031 | } else { |
michael@0 | 1032 | strcpy(subpath, dir->d_name); |
michael@0 | 1033 | } |
michael@0 | 1034 | getzones(basedir, subpath, last, count); |
michael@0 | 1035 | } |
michael@0 | 1036 | closedir(dp); |
michael@0 | 1037 | } |
michael@0 | 1038 | } |
michael@0 | 1039 | #endif |