zdump.c revision 192625
130829Scharnier#ifndef lint 230829Scharnierstatic const char rcsid[] = 350479Speter "$FreeBSD: head/usr.sbin/zic/zdump.c 192625 2009-05-23 06:31:50Z edwin $"; 4192625Sedwinstatic char elsieid[] = "@(#)zdump.c 8.8"; 530829Scharnier#endif /* not lint */ 630829Scharnier 72702Swollman/* 82702Swollman** This code has been made independent of the rest of the time 92702Swollman** conversion package to increase confidence in the verification it provides. 102702Swollman** You can use this code to help in verifying other implementations. 112702Swollman*/ 122702Swollman 1330829Scharnier#include <err.h> 1430829Scharnier#include <stdio.h> /* for stdout, stderr */ 1530829Scharnier#include <stdlib.h> /* for exit, malloc, atoi */ 1630829Scharnier#include <string.h> /* for strcpy */ 1730829Scharnier#include <sys/types.h> /* for time_t */ 1830829Scharnier#include <time.h> /* for struct tm */ 1930829Scharnier#include <unistd.h> 20192625Sedwin#include <float.h> /* for FLT_MAX and DBL_MAX */ 21192625Sedwin#include <ctype.h> /* for isalpha et al. */ 22192625Sedwin#ifndef isascii 23192625Sedwin#define isascii(x) 1 24192625Sedwin#endif /* !defined isascii */ 252702Swollman 26192625Sedwin#ifndef ZDUMP_LO_YEAR 27192625Sedwin#define ZDUMP_LO_YEAR (-500) 28192625Sedwin#endif /* !defined ZDUMP_LO_YEAR */ 29192625Sedwin 30192625Sedwin#ifndef ZDUMP_HI_YEAR 31192625Sedwin#define ZDUMP_HI_YEAR 2500 32192625Sedwin#endif /* !defined ZDUMP_HI_YEAR */ 33192625Sedwin 342702Swollman#ifndef MAX_STRING_LENGTH 352702Swollman#define MAX_STRING_LENGTH 1024 362702Swollman#endif /* !defined MAX_STRING_LENGTH */ 372702Swollman 382702Swollman#ifndef TRUE 392702Swollman#define TRUE 1 402702Swollman#endif /* !defined TRUE */ 412702Swollman 422702Swollman#ifndef FALSE 432702Swollman#define FALSE 0 442702Swollman#endif /* !defined FALSE */ 452702Swollman 462702Swollman#ifndef EXIT_SUCCESS 472702Swollman#define EXIT_SUCCESS 0 482702Swollman#endif /* !defined EXIT_SUCCESS */ 492702Swollman 502702Swollman#ifndef EXIT_FAILURE 512702Swollman#define EXIT_FAILURE 1 522702Swollman#endif /* !defined EXIT_FAILURE */ 532702Swollman 542702Swollman#ifndef SECSPERMIN 552702Swollman#define SECSPERMIN 60 562702Swollman#endif /* !defined SECSPERMIN */ 572702Swollman 582702Swollman#ifndef MINSPERHOUR 592702Swollman#define MINSPERHOUR 60 602702Swollman#endif /* !defined MINSPERHOUR */ 612702Swollman 622702Swollman#ifndef SECSPERHOUR 632702Swollman#define SECSPERHOUR (SECSPERMIN * MINSPERHOUR) 642702Swollman#endif /* !defined SECSPERHOUR */ 652702Swollman 662702Swollman#ifndef HOURSPERDAY 672702Swollman#define HOURSPERDAY 24 682702Swollman#endif /* !defined HOURSPERDAY */ 692702Swollman 702702Swollman#ifndef EPOCH_YEAR 712702Swollman#define EPOCH_YEAR 1970 722702Swollman#endif /* !defined EPOCH_YEAR */ 732702Swollman 742702Swollman#ifndef TM_YEAR_BASE 752702Swollman#define TM_YEAR_BASE 1900 762702Swollman#endif /* !defined TM_YEAR_BASE */ 772702Swollman 782702Swollman#ifndef DAYSPERNYEAR 792702Swollman#define DAYSPERNYEAR 365 802702Swollman#endif /* !defined DAYSPERNYEAR */ 812702Swollman 822702Swollman#ifndef isleap 83192625Sedwin#define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0)) 842702Swollman#endif /* !defined isleap */ 852702Swollman 86192625Sedwin#ifndef isleap_sum 87192625Sedwin/* 88192625Sedwin** See tzfile.h for details on isleap_sum. 89192625Sedwin*/ 90192625Sedwin#define isleap_sum(a, b) isleap((a) % 400 + (b) % 400) 91192625Sedwin#endif /* !defined isleap_sum */ 92192625Sedwin 93192625Sedwin#define SECSPERDAY ((long) SECSPERHOUR * HOURSPERDAY) 94192625Sedwin#define SECSPERNYEAR (SECSPERDAY * DAYSPERNYEAR) 95192625Sedwin#define SECSPERLYEAR (SECSPERNYEAR + SECSPERDAY) 96192625Sedwin 97192625Sedwin#ifndef HAVE_GETTEXT 98192625Sedwin#define HAVE_GETTEXT 0 99192625Sedwin#endif 100192625Sedwin#if HAVE_GETTEXT 10117214Swollman#include "locale.h" /* for setlocale */ 10217214Swollman#include "libintl.h" 103192625Sedwin#endif /* HAVE_GETTEXT */ 10417214Swollman 1059937Swollman#ifndef GNUC_or_lint 1069937Swollman#ifdef lint 1079937Swollman#define GNUC_or_lint 108192625Sedwin#else /* !defined lint */ 1099937Swollman#ifdef __GNUC__ 1109937Swollman#define GNUC_or_lint 1119937Swollman#endif /* defined __GNUC__ */ 1129937Swollman#endif /* !defined lint */ 1139937Swollman#endif /* !defined GNUC_or_lint */ 1149937Swollman 1159937Swollman#ifndef INITIALIZE 1169937Swollman#ifdef GNUC_or_lint 1179937Swollman#define INITIALIZE(x) ((x) = 0) 118192625Sedwin#else /* !defined GNUC_or_lint */ 1199937Swollman#define INITIALIZE(x) 1209937Swollman#endif /* !defined GNUC_or_lint */ 1219937Swollman#endif /* !defined INITIALIZE */ 1229937Swollman 12317214Swollman/* 12417214Swollman** For the benefit of GNU folk... 12517214Swollman** `_(MSGID)' uses the current locale's message library string for MSGID. 12617214Swollman** The default is to use gettext if available, and use MSGID otherwise. 12717214Swollman*/ 12817214Swollman 12917214Swollman#ifndef _ 130192625Sedwin#if HAVE_GETTEXT 13117214Swollman#define _(msgid) gettext(msgid) 132192625Sedwin#else /* !(HAVE_GETTEXT) */ 13317214Swollman#define _(msgid) msgid 134192625Sedwin#endif /* !(HAVE_GETTEXT) */ 13517214Swollman#endif /* !defined _ */ 13617214Swollman 13717214Swollman#ifndef TZ_DOMAIN 13817214Swollman#define TZ_DOMAIN "tz" 13917214Swollman#endif /* !defined TZ_DOMAIN */ 14017214Swollman 1412702Swollmanextern char ** environ; 1422702Swollmanextern char * tzname[2]; 1432702Swollman 144192625Sedwinstatic time_t absolute_min_time; 145192625Sedwinstatic time_t absolute_max_time; 14642997Swollmanstatic size_t longest; 147192625Sedwinstatic char * progname; 148192625Sedwinstatic int warned; 1492702Swollman 150192625Sedwinstatic void usage(const char *progname, FILE *stream, int status); 151192625Sedwinstatic char * abbr(struct tm * tmp); 152192625Sedwinstatic void abbrok(const char * abbrp, const char * zone); 153192625Sedwinstatic long delta(struct tm * newp, struct tm * oldp); 154192625Sedwinstatic void dumptime(const struct tm * tmp); 155192625Sedwinstatic time_t hunt(char * name, time_t lot, time_t hit); 156192625Sedwinstatic void setabsolutes(void); 157192625Sedwinstatic void show(char * zone, time_t t, int v); 158192625Sedwinstatic const char * tformat(void); 159192625Sedwinstatic time_t yeartot(long y); 160192625Sedwin 161192625Sedwin#ifndef TYPECHECK 162192625Sedwin#define my_localtime localtime 163192625Sedwin#else /* !defined TYPECHECK */ 164192625Sedwinstatic struct tm * 165192625Sedwinmy_localtime(tp) 166192625Sedwintime_t * tp; 167192625Sedwin{ 168192625Sedwin register struct tm * tmp; 169192625Sedwin 170192625Sedwin tmp = localtime(tp); 171192625Sedwin if (tp != NULL && tmp != NULL) { 172192625Sedwin struct tm tm; 173192625Sedwin register time_t t; 174192625Sedwin 175192625Sedwin tm = *tmp; 176192625Sedwin t = mktime(&tm); 177192625Sedwin if (t - *tp >= 1 || *tp - t >= 1) { 178192625Sedwin (void) fflush(stdout); 179192625Sedwin (void) fprintf(stderr, "\n%s: ", progname); 180192625Sedwin (void) fprintf(stderr, tformat(), *tp); 181192625Sedwin (void) fprintf(stderr, " ->"); 182192625Sedwin (void) fprintf(stderr, " year=%d", tmp->tm_year); 183192625Sedwin (void) fprintf(stderr, " mon=%d", tmp->tm_mon); 184192625Sedwin (void) fprintf(stderr, " mday=%d", tmp->tm_mday); 185192625Sedwin (void) fprintf(stderr, " hour=%d", tmp->tm_hour); 186192625Sedwin (void) fprintf(stderr, " min=%d", tmp->tm_min); 187192625Sedwin (void) fprintf(stderr, " sec=%d", tmp->tm_sec); 188192625Sedwin (void) fprintf(stderr, " isdst=%d", tmp->tm_isdst); 189192625Sedwin (void) fprintf(stderr, " -> "); 190192625Sedwin (void) fprintf(stderr, tformat(), t); 191192625Sedwin (void) fprintf(stderr, "\n"); 192192625Sedwin } 193192625Sedwin } 194192625Sedwin return tmp; 195192625Sedwin} 196192625Sedwin#endif /* !defined TYPECHECK */ 197192625Sedwin 198192625Sedwinstatic void 199192625Sedwinabbrok(abbrp, zone) 200192625Sedwinconst char * const abbrp; 201192625Sedwinconst char * const zone; 202192625Sedwin{ 203192625Sedwin register const char * cp; 204192625Sedwin register char * wp; 205192625Sedwin 206192625Sedwin if (warned) 207192625Sedwin return; 208192625Sedwin cp = abbrp; 209192625Sedwin wp = NULL; 210192625Sedwin while (isascii((unsigned char) *cp) && isalpha((unsigned char) *cp)) 211192625Sedwin ++cp; 212192625Sedwin if (cp - abbrp == 0) 213192625Sedwin wp = _("lacks alphabetic at start"); 214192625Sedwin else if (cp - abbrp < 3) 215192625Sedwin wp = _("has fewer than 3 alphabetics"); 216192625Sedwin else if (cp - abbrp > 6) 217192625Sedwin wp = _("has more than 6 alphabetics"); 218192625Sedwin if (wp == NULL && (*cp == '+' || *cp == '-')) { 219192625Sedwin ++cp; 220192625Sedwin if (isascii((unsigned char) *cp) && 221192625Sedwin isdigit((unsigned char) *cp)) 222192625Sedwin if (*cp++ == '1' && *cp >= '0' && *cp <= '4') 223192625Sedwin ++cp; 224192625Sedwin if (*cp != '\0') 225192625Sedwin wp = _("differs from POSIX standard"); 226192625Sedwin } 227192625Sedwin if (wp == NULL) 228192625Sedwin return; 229192625Sedwin (void) fflush(stdout); 230192625Sedwin (void) fprintf(stderr, 231192625Sedwin _("%s: warning: zone \"%s\" abbreviation \"%s\" %s\n"), 232192625Sedwin progname, zone, abbrp, wp); 233192625Sedwin warned = TRUE; 234192625Sedwin} 235192625Sedwin 2362702Swollmanint 2372702Swollmanmain(argc, argv) 2382702Swollmanint argc; 2392702Swollmanchar * argv[]; 2402702Swollman{ 2419937Swollman register int i; 2429937Swollman register int c; 2439937Swollman register int vflag; 244192625Sedwin register char * cutarg; 245192625Sedwin register long cutloyear = ZDUMP_LO_YEAR; 246192625Sedwin register long cuthiyear = ZDUMP_HI_YEAR; 247192625Sedwin register time_t cutlotime; 248192625Sedwin register time_t cuthitime; 249192625Sedwin register char ** fakeenv; 2509937Swollman time_t now; 2519937Swollman time_t t; 2529937Swollman time_t newt; 2539937Swollman struct tm tm; 2549937Swollman struct tm newtm; 255192625Sedwin register struct tm * tmp; 256192625Sedwin register struct tm * newtmp; 2572702Swollman 258192625Sedwin INITIALIZE(cutlotime); 259192625Sedwin INITIALIZE(cuthitime); 260192625Sedwin#if HAVE_GETTEXT 26117214Swollman (void) setlocale(LC_MESSAGES, ""); 26217214Swollman#ifdef TZ_DOMAINDIR 26317214Swollman (void) bindtextdomain(TZ_DOMAIN, TZ_DOMAINDIR); 264192625Sedwin#endif /* TEXTDOMAINDIR */ 26517214Swollman (void) textdomain(TZ_DOMAIN); 266192625Sedwin#endif /* HAVE_GETTEXT */ 267130819Sstefanf for (i = 1; i < argc; ++i) 268130819Sstefanf if (strcmp(argv[i], "--version") == 0) { 269130819Sstefanf errx(EXIT_SUCCESS, "%s", elsieid); 270192625Sedwin } else if (strcmp(argv[i], "--help") == 0) { 271192625Sedwin usage(progname, stdout, EXIT_SUCCESS); 272130819Sstefanf } 2732702Swollman vflag = 0; 274192625Sedwin cutarg = NULL; 2752702Swollman while ((c = getopt(argc, argv, "c:v")) == 'c' || c == 'v') 2762702Swollman if (c == 'v') 2772702Swollman vflag = 1; 278192625Sedwin else cutarg = optarg; 279176407Sru if ((c != -1) || 2802702Swollman (optind == argc - 1 && strcmp(argv[optind], "=") == 0)) { 281192625Sedwin usage(progname, stderr, EXIT_FAILURE); 2822702Swollman } 283192625Sedwin if (vflag) { 284192625Sedwin if (cutarg != NULL) { 285192625Sedwin long lo; 286192625Sedwin long hi; 287192625Sedwin char dummy; 2882702Swollman 289192625Sedwin if (sscanf(cutarg, "%ld%c", &hi, &dummy) == 1) { 290192625Sedwin cuthiyear = hi; 291192625Sedwin } else if (sscanf(cutarg, "%ld,%ld%c", 292192625Sedwin &lo, &hi, &dummy) == 2) { 293192625Sedwin cutloyear = lo; 294192625Sedwin cuthiyear = hi; 295192625Sedwin } else { 296192625Sedwin(void) fprintf(stderr, _("%s: wild -c argument %s\n"), 297192625Sedwin progname, cutarg); 298192625Sedwin exit(EXIT_FAILURE); 299192625Sedwin } 300192625Sedwin } 301192625Sedwin setabsolutes(); 302192625Sedwin cutlotime = yeartot(cutloyear); 303192625Sedwin cuthitime = yeartot(cuthiyear); 3042702Swollman } 3052702Swollman (void) time(&now); 3062702Swollman longest = 0; 3072702Swollman for (i = optind; i < argc; ++i) 3082702Swollman if (strlen(argv[i]) > longest) 3092702Swollman longest = strlen(argv[i]); 3109937Swollman { 3119937Swollman register int from; 3129937Swollman register int to; 3132702Swollman 314192625Sedwin for (i = 0; environ[i] != NULL; ++i) 3159937Swollman continue; 3169937Swollman fakeenv = (char **) malloc((size_t) ((i + 2) * 3179937Swollman sizeof *fakeenv)); 3189937Swollman if (fakeenv == NULL || 3199937Swollman (fakeenv[0] = (char *) malloc((size_t) (longest + 32030829Scharnier 4))) == NULL) 32130829Scharnier errx(EXIT_FAILURE, 32230829Scharnier _("malloc() failed")); 3239937Swollman to = 0; 3249937Swollman (void) strcpy(fakeenv[to++], "TZ="); 3259937Swollman for (from = 0; environ[from] != NULL; ++from) 3269937Swollman if (strncmp(environ[from], "TZ=", 3) != 0) 3279937Swollman fakeenv[to++] = environ[from]; 3289937Swollman fakeenv[to] = NULL; 3292702Swollman environ = fakeenv; 3309937Swollman } 3319937Swollman for (i = optind; i < argc; ++i) { 3329937Swollman static char buf[MAX_STRING_LENGTH]; 3339937Swollman 3349937Swollman (void) strcpy(&fakeenv[0][3], argv[i]); 33517214Swollman if (!vflag) { 33617214Swollman show(argv[i], now, FALSE); 3372702Swollman continue; 33817214Swollman } 339192625Sedwin warned = FALSE; 340192625Sedwin t = absolute_min_time; 3412702Swollman show(argv[i], t, TRUE); 3422702Swollman t += SECSPERHOUR * HOURSPERDAY; 3432702Swollman show(argv[i], t, TRUE); 344192625Sedwin if (t < cutlotime) 345192625Sedwin t = cutlotime; 346192625Sedwin tmp = my_localtime(&t); 347192625Sedwin if (tmp != NULL) { 348192625Sedwin tm = *tmp; 349192625Sedwin (void) strncpy(buf, abbr(&tm), (sizeof buf) - 1); 350192625Sedwin } 3512702Swollman for ( ; ; ) { 352192625Sedwin if (t >= cuthitime || t >= cuthitime - SECSPERHOUR * 12) 3532702Swollman break; 3542702Swollman newt = t + SECSPERHOUR * 12; 355192625Sedwin newtmp = localtime(&newt); 356192625Sedwin if (newtmp != NULL) 357192625Sedwin newtm = *newtmp; 358192625Sedwin if ((tmp == NULL || newtmp == NULL) ? (tmp != newtmp) : 359192625Sedwin (delta(&newtm, &tm) != (newt - t) || 3602702Swollman newtm.tm_isdst != tm.tm_isdst || 361192625Sedwin strcmp(abbr(&newtm), buf) != 0)) { 3622702Swollman newt = hunt(argv[i], t, newt); 363192625Sedwin newtmp = localtime(&newt); 364192625Sedwin if (newtmp != NULL) { 365192625Sedwin newtm = *newtmp; 366192625Sedwin (void) strncpy(buf, 367192625Sedwin abbr(&newtm), 368192625Sedwin (sizeof buf) - 1); 369192625Sedwin } 3702702Swollman } 3712702Swollman t = newt; 3722702Swollman tm = newtm; 373192625Sedwin tmp = newtmp; 3742702Swollman } 375192625Sedwin t = absolute_max_time; 3762702Swollman t -= SECSPERHOUR * HOURSPERDAY; 3772702Swollman show(argv[i], t, TRUE); 3782702Swollman t += SECSPERHOUR * HOURSPERDAY; 3792702Swollman show(argv[i], t, TRUE); 3802702Swollman } 38130829Scharnier if (fflush(stdout) || ferror(stdout)) 38230829Scharnier errx(EXIT_FAILURE, _("error writing standard output")); 3832702Swollman exit(EXIT_SUCCESS); 384192625Sedwin /* If exit fails to exit... */ 385192625Sedwin return(EXIT_FAILURE); 386192625Sedwin} 3872702Swollman 388192625Sedwinstatic void 389192625Sedwinsetabsolutes(void) 390192625Sedwin{ 391192625Sedwin if (0.5 == (time_t) 0.5) { 392192625Sedwin /* 393192625Sedwin ** time_t is floating. 394192625Sedwin */ 395192625Sedwin if (sizeof (time_t) == sizeof (float)) { 396192625Sedwin absolute_min_time = (time_t) -FLT_MAX; 397192625Sedwin absolute_max_time = (time_t) FLT_MAX; 398192625Sedwin } else if (sizeof (time_t) == sizeof (double)) { 399192625Sedwin absolute_min_time = (time_t) -DBL_MAX; 400192625Sedwin absolute_max_time = (time_t) DBL_MAX; 401192625Sedwin } else { 402192625Sedwin (void) fprintf(stderr, 403192625Sedwin_("%s: use of -v on system with floating time_t other than float or double\n"), 404192625Sedwin progname); 405192625Sedwin exit(EXIT_FAILURE); 406192625Sedwin } 407192625Sedwin } else if (0 > (time_t) -1) { 408192625Sedwin /* 409192625Sedwin ** time_t is signed. Assume overflow wraps around. 410192625Sedwin */ 411192625Sedwin time_t t = 0; 412192625Sedwin time_t t1 = 1; 413192625Sedwin 414192625Sedwin while (t < t1) { 415192625Sedwin t = t1; 416192625Sedwin t1 = 2 * t1 + 1; 417192625Sedwin } 418192625Sedwin 419192625Sedwin absolute_max_time = t; 420192625Sedwin t = -t; 421192625Sedwin absolute_min_time = t - 1; 422192625Sedwin if (t < absolute_min_time) 423192625Sedwin absolute_min_time = t; 424192625Sedwin } else { 425192625Sedwin /* 426192625Sedwin ** time_t is unsigned. 427192625Sedwin */ 428192625Sedwin absolute_min_time = 0; 429192625Sedwin absolute_max_time = absolute_min_time - 1; 430192625Sedwin } 4312702Swollman} 4322702Swollman 433192625Sedwinstatic time_t 434192625Sedwinyeartot(y) 435192625Sedwinconst long y; 436192625Sedwin{ 437192625Sedwin register long myy; 438192625Sedwin register long seconds; 439192625Sedwin register time_t t; 440192625Sedwin 441192625Sedwin myy = EPOCH_YEAR; 442192625Sedwin t = 0; 443192625Sedwin while (myy != y) { 444192625Sedwin if (myy < y) { 445192625Sedwin seconds = isleap(myy) ? SECSPERLYEAR : SECSPERNYEAR; 446192625Sedwin ++myy; 447192625Sedwin if (t > absolute_max_time - seconds) { 448192625Sedwin t = absolute_max_time; 449192625Sedwin break; 450192625Sedwin } 451192625Sedwin t += seconds; 452192625Sedwin } else { 453192625Sedwin --myy; 454192625Sedwin seconds = isleap(myy) ? SECSPERLYEAR : SECSPERNYEAR; 455192625Sedwin if (t < absolute_min_time + seconds) { 456192625Sedwin t = absolute_min_time; 457192625Sedwin break; 458192625Sedwin } 459192625Sedwin t -= seconds; 460192625Sedwin } 461192625Sedwin } 462192625Sedwin return t; 463192625Sedwin} 464192625Sedwin 46530829Scharnierstatic void 466192625Sedwinusage(const char *progname, FILE *stream, int status) 46730829Scharnier{ 468192625Sedwin fprintf(stream, 469192625Sedwin_("usage: %s [--version] [-v] [--help] [-c [loyear,]hiyear] zonename ...\n\ 470192625Sedwin\n\ 471192625SedwinReport bugs to tz@elsie.nci.nih.gov.\n"), progname); 472192625Sedwin exit(status); 47330829Scharnier} 47430829Scharnier 4752702Swollmanstatic time_t 476192625Sedwinhunt(char *name, time_t lot, time_t hit) 4772702Swollman{ 478192625Sedwin time_t t; 479192625Sedwin long diff; 480192625Sedwin struct tm lotm; 481192625Sedwin register struct tm * lotmp; 482192625Sedwin struct tm tm; 483192625Sedwin register struct tm * tmp; 484192625Sedwin char loab[MAX_STRING_LENGTH]; 4852702Swollman 486192625Sedwin lotmp = my_localtime(&lot); 487192625Sedwin if (lotmp != NULL) { 488192625Sedwin lotm = *lotmp; 489192625Sedwin (void) strncpy(loab, abbr(&lotm), (sizeof loab) - 1); 490192625Sedwin } 491192625Sedwin for ( ; ; ) { 492192625Sedwin diff = (long) (hit - lot); 493192625Sedwin if (diff < 2) 494192625Sedwin break; 495192625Sedwin t = lot; 496192625Sedwin t += diff / 2; 4972702Swollman if (t <= lot) 4982702Swollman ++t; 4992702Swollman else if (t >= hit) 5002702Swollman --t; 501192625Sedwin tmp = my_localtime(&t); 502192625Sedwin if (tmp != NULL) 503192625Sedwin tm = *tmp; 504192625Sedwin if ((lotmp == NULL || tmp == NULL) ? (lotmp == tmp) : 505192625Sedwin (delta(&tm, &lotm) == (t - lot) && 5062702Swollman tm.tm_isdst == lotm.tm_isdst && 507192625Sedwin strcmp(abbr(&tm), loab) == 0)) { 5082702Swollman lot = t; 5092702Swollman lotm = tm; 510192625Sedwin lotmp = tmp; 5112702Swollman } else hit = t; 5122702Swollman } 5132702Swollman show(name, lot, TRUE); 5142702Swollman show(name, hit, TRUE); 5152702Swollman return hit; 5162702Swollman} 5172702Swollman 5182702Swollman/* 519192625Sedwin** Thanks to Paul Eggert for logic used in delta. 5202702Swollman*/ 5212702Swollman 5222702Swollmanstatic long 5232702Swollmandelta(newp, oldp) 5242702Swollmanstruct tm * newp; 5252702Swollmanstruct tm * oldp; 5262702Swollman{ 527192625Sedwin register long result; 528192625Sedwin register int tmy; 5292702Swollman 5302702Swollman if (newp->tm_year < oldp->tm_year) 5312702Swollman return -delta(oldp, newp); 5322702Swollman result = 0; 5332702Swollman for (tmy = oldp->tm_year; tmy < newp->tm_year; ++tmy) 534192625Sedwin result += DAYSPERNYEAR + isleap_sum(tmy, TM_YEAR_BASE); 5352702Swollman result += newp->tm_yday - oldp->tm_yday; 5362702Swollman result *= HOURSPERDAY; 5372702Swollman result += newp->tm_hour - oldp->tm_hour; 5382702Swollman result *= MINSPERHOUR; 5392702Swollman result += newp->tm_min - oldp->tm_min; 5402702Swollman result *= SECSPERMIN; 5412702Swollman result += newp->tm_sec - oldp->tm_sec; 5422702Swollman return result; 5432702Swollman} 5442702Swollman 5452702Swollmanstatic void 546192625Sedwinshow(char *zone, time_t t, int v) 5472702Swollman{ 548192625Sedwin register struct tm * tmp; 5492702Swollman 55042997Swollman (void) printf("%-*s ", (int) longest, zone); 5512702Swollman if (v) { 552192625Sedwin tmp = gmtime(&t); 553192625Sedwin if (tmp == NULL) { 554192625Sedwin (void) printf(tformat(), t); 555192625Sedwin } else { 556192625Sedwin dumptime(tmp); 557192625Sedwin (void) printf(" UTC"); 558192625Sedwin } 559192625Sedwin (void) printf(" = "); 560192625Sedwin } 561192625Sedwin tmp = my_localtime(&t); 562192625Sedwin dumptime(tmp); 563192625Sedwin if (tmp != NULL) { 564192625Sedwin if (*abbr(tmp) != '\0') 565192625Sedwin (void) printf(" %s", abbr(tmp)); 566192625Sedwin if (v) { 567192625Sedwin (void) printf(" isdst=%d", tmp->tm_isdst); 5682702Swollman#ifdef TM_GMTOFF 569192625Sedwin (void) printf(" gmtoff=%ld", tmp->TM_GMTOFF); 5702702Swollman#endif /* defined TM_GMTOFF */ 571192625Sedwin } 5722702Swollman } 5732702Swollman (void) printf("\n"); 574192625Sedwin if (tmp != NULL && *abbr(tmp) != '\0') 575192625Sedwin abbrok(abbr(tmp), zone); 5762702Swollman} 5772702Swollman 5782702Swollmanstatic char * 5792702Swollmanabbr(tmp) 5802702Swollmanstruct tm * tmp; 5812702Swollman{ 5822702Swollman register char * result; 5839937Swollman static char nada; 5842702Swollman 5852702Swollman if (tmp->tm_isdst != 0 && tmp->tm_isdst != 1) 5869937Swollman return &nada; 5872702Swollman result = tzname[tmp->tm_isdst]; 5889937Swollman return (result == NULL) ? &nada : result; 5892702Swollman} 590192625Sedwin 591192625Sedwin/* 592192625Sedwin** The code below can fail on certain theoretical systems; 593192625Sedwin** it works on all known real-world systems as of 2004-12-30. 594192625Sedwin*/ 595192625Sedwin 596192625Sedwinstatic const char * 597192625Sedwintformat(void) 598192625Sedwin{ 599192625Sedwin if (0.5 == (time_t) 0.5) { /* floating */ 600192625Sedwin if (sizeof (time_t) > sizeof (double)) 601192625Sedwin return "%Lg"; 602192625Sedwin return "%g"; 603192625Sedwin } 604192625Sedwin if (0 > (time_t) -1) { /* signed */ 605192625Sedwin if (sizeof (time_t) > sizeof (long)) 606192625Sedwin return "%lld"; 607192625Sedwin if (sizeof (time_t) > sizeof (int)) 608192625Sedwin return "%ld"; 609192625Sedwin return "%d"; 610192625Sedwin } 611192625Sedwin if (sizeof (time_t) > sizeof (unsigned long)) 612192625Sedwin return "%llu"; 613192625Sedwin if (sizeof (time_t) > sizeof (unsigned int)) 614192625Sedwin return "%lu"; 615192625Sedwin return "%u"; 616192625Sedwin} 617192625Sedwin 618192625Sedwinstatic void 619192625Sedwindumptime(timeptr) 620192625Sedwinregister const struct tm * timeptr; 621192625Sedwin{ 622192625Sedwin static const char wday_name[][3] = { 623192625Sedwin "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" 624192625Sedwin }; 625192625Sedwin static const char mon_name[][3] = { 626192625Sedwin "Jan", "Feb", "Mar", "Apr", "May", "Jun", 627192625Sedwin "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" 628192625Sedwin }; 629192625Sedwin register const char * wn; 630192625Sedwin register const char * mn; 631192625Sedwin register int lead; 632192625Sedwin register int trail; 633192625Sedwin 634192625Sedwin if (timeptr == NULL) { 635192625Sedwin (void) printf("NULL"); 636192625Sedwin return; 637192625Sedwin } 638192625Sedwin /* 639192625Sedwin ** The packaged versions of localtime and gmtime never put out-of-range 640192625Sedwin ** values in tm_wday or tm_mon, but since this code might be compiled 641192625Sedwin ** with other (perhaps experimental) versions, paranoia is in order. 642192625Sedwin */ 643192625Sedwin if (timeptr->tm_wday < 0 || timeptr->tm_wday >= 644192625Sedwin (int) (sizeof wday_name / sizeof wday_name[0])) 645192625Sedwin wn = "???"; 646192625Sedwin else wn = wday_name[timeptr->tm_wday]; 647192625Sedwin if (timeptr->tm_mon < 0 || timeptr->tm_mon >= 648192625Sedwin (int) (sizeof mon_name / sizeof mon_name[0])) 649192625Sedwin mn = "???"; 650192625Sedwin else mn = mon_name[timeptr->tm_mon]; 651192625Sedwin (void) printf("%.3s %.3s%3d %.2d:%.2d:%.2d ", 652192625Sedwin wn, mn, 653192625Sedwin timeptr->tm_mday, timeptr->tm_hour, 654192625Sedwin timeptr->tm_min, timeptr->tm_sec); 655192625Sedwin#define DIVISOR 10 656192625Sedwin trail = timeptr->tm_year % DIVISOR + TM_YEAR_BASE % DIVISOR; 657192625Sedwin lead = timeptr->tm_year / DIVISOR + TM_YEAR_BASE / DIVISOR + 658192625Sedwin trail / DIVISOR; 659192625Sedwin trail %= DIVISOR; 660192625Sedwin if (trail < 0 && lead > 0) { 661192625Sedwin trail += DIVISOR; 662192625Sedwin --lead; 663192625Sedwin } else if (lead < 0 && trail > 0) { 664192625Sedwin trail -= DIVISOR; 665192625Sedwin ++lead; 666192625Sedwin } 667192625Sedwin if (lead == 0) 668192625Sedwin (void) printf("%d", trail); 669192625Sedwin else (void) printf("%d%d", lead, ((trail < 0) ? -trail : trail)); 670192625Sedwin} 671