intl/icu/source/tools/tzcode/zdump.c

Wed, 31 Dec 2014 07:22:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 07:22:50 +0100
branch
TOR_BUG_3246
changeset 4
fc2d59ddac77
permissions
-rw-r--r--

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

mercurial