1192890Sedwin/* 2192890Sedwin** This file is in the public domain, so clarified as of 3192890Sedwin** 2009-05-17 by Arthur David Olson. 4192890Sedwin*/ 5192890Sedwin 630829Scharnier#ifndef lint 730829Scharnierstatic const char rcsid[] = 850479Speter "$FreeBSD: stable/10/contrib/tzcode/zic/zdump.c 307359 2016-10-15 12:38:21Z bapt $"; 9198831Sedwinstatic char elsieid[] = "@(#)zdump.c 8.10"; 1030829Scharnier#endif /* not lint */ 1130829Scharnier 122702Swollman/* 132702Swollman** This code has been made independent of the rest of the time 142702Swollman** conversion package to increase confidence in the verification it provides. 152702Swollman** You can use this code to help in verifying other implementations. 162702Swollman*/ 172702Swollman 1830829Scharnier#include <err.h> 1930829Scharnier#include <stdio.h> /* for stdout, stderr */ 2030829Scharnier#include <stdlib.h> /* for exit, malloc, atoi */ 2130829Scharnier#include <string.h> /* for strcpy */ 2230829Scharnier#include <sys/types.h> /* for time_t */ 2330829Scharnier#include <time.h> /* for struct tm */ 2430829Scharnier#include <unistd.h> 25192625Sedwin#include <float.h> /* for FLT_MAX and DBL_MAX */ 26192625Sedwin#include <ctype.h> /* for isalpha et al. */ 27192625Sedwin#ifndef isascii 28192625Sedwin#define isascii(x) 1 29192625Sedwin#endif /* !defined isascii */ 302702Swollman 31192625Sedwin#ifndef ZDUMP_LO_YEAR 32192625Sedwin#define ZDUMP_LO_YEAR (-500) 33192625Sedwin#endif /* !defined ZDUMP_LO_YEAR */ 34192625Sedwin 35192625Sedwin#ifndef ZDUMP_HI_YEAR 36192625Sedwin#define ZDUMP_HI_YEAR 2500 37192625Sedwin#endif /* !defined ZDUMP_HI_YEAR */ 38192625Sedwin 392702Swollman#ifndef MAX_STRING_LENGTH 402702Swollman#define MAX_STRING_LENGTH 1024 412702Swollman#endif /* !defined MAX_STRING_LENGTH */ 422702Swollman 432702Swollman#ifndef TRUE 442702Swollman#define TRUE 1 452702Swollman#endif /* !defined TRUE */ 462702Swollman 472702Swollman#ifndef FALSE 482702Swollman#define FALSE 0 492702Swollman#endif /* !defined FALSE */ 502702Swollman 512702Swollman#ifndef EXIT_SUCCESS 522702Swollman#define EXIT_SUCCESS 0 532702Swollman#endif /* !defined EXIT_SUCCESS */ 542702Swollman 552702Swollman#ifndef EXIT_FAILURE 562702Swollman#define EXIT_FAILURE 1 572702Swollman#endif /* !defined EXIT_FAILURE */ 582702Swollman 592702Swollman#ifndef SECSPERMIN 602702Swollman#define SECSPERMIN 60 612702Swollman#endif /* !defined SECSPERMIN */ 622702Swollman 632702Swollman#ifndef MINSPERHOUR 642702Swollman#define MINSPERHOUR 60 652702Swollman#endif /* !defined MINSPERHOUR */ 662702Swollman 672702Swollman#ifndef SECSPERHOUR 682702Swollman#define SECSPERHOUR (SECSPERMIN * MINSPERHOUR) 692702Swollman#endif /* !defined SECSPERHOUR */ 702702Swollman 712702Swollman#ifndef HOURSPERDAY 722702Swollman#define HOURSPERDAY 24 732702Swollman#endif /* !defined HOURSPERDAY */ 742702Swollman 752702Swollman#ifndef EPOCH_YEAR 762702Swollman#define EPOCH_YEAR 1970 772702Swollman#endif /* !defined EPOCH_YEAR */ 782702Swollman 792702Swollman#ifndef TM_YEAR_BASE 802702Swollman#define TM_YEAR_BASE 1900 812702Swollman#endif /* !defined TM_YEAR_BASE */ 822702Swollman 832702Swollman#ifndef DAYSPERNYEAR 842702Swollman#define DAYSPERNYEAR 365 852702Swollman#endif /* !defined DAYSPERNYEAR */ 862702Swollman 872702Swollman#ifndef isleap 88192625Sedwin#define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0)) 892702Swollman#endif /* !defined isleap */ 902702Swollman 91192625Sedwin#ifndef isleap_sum 92192625Sedwin/* 93192625Sedwin** See tzfile.h for details on isleap_sum. 94192625Sedwin*/ 95192625Sedwin#define isleap_sum(a, b) isleap((a) % 400 + (b) % 400) 96192625Sedwin#endif /* !defined isleap_sum */ 97192625Sedwin 98192625Sedwin#define SECSPERDAY ((long) SECSPERHOUR * HOURSPERDAY) 99192625Sedwin#define SECSPERNYEAR (SECSPERDAY * DAYSPERNYEAR) 100192625Sedwin#define SECSPERLYEAR (SECSPERNYEAR + SECSPERDAY) 101192625Sedwin 102192625Sedwin#ifndef HAVE_GETTEXT 103192625Sedwin#define HAVE_GETTEXT 0 104192625Sedwin#endif 105192625Sedwin#if HAVE_GETTEXT 10617214Swollman#include "locale.h" /* for setlocale */ 10717214Swollman#include "libintl.h" 108192625Sedwin#endif /* HAVE_GETTEXT */ 10917214Swollman 1109937Swollman#ifndef GNUC_or_lint 1119937Swollman#ifdef lint 1129937Swollman#define GNUC_or_lint 113192625Sedwin#else /* !defined lint */ 1149937Swollman#ifdef __GNUC__ 1159937Swollman#define GNUC_or_lint 1169937Swollman#endif /* defined __GNUC__ */ 1179937Swollman#endif /* !defined lint */ 1189937Swollman#endif /* !defined GNUC_or_lint */ 1199937Swollman 1209937Swollman#ifndef INITIALIZE 1219937Swollman#ifdef GNUC_or_lint 1229937Swollman#define INITIALIZE(x) ((x) = 0) 123192625Sedwin#else /* !defined GNUC_or_lint */ 1249937Swollman#define INITIALIZE(x) 1259937Swollman#endif /* !defined GNUC_or_lint */ 1269937Swollman#endif /* !defined INITIALIZE */ 1279937Swollman 12817214Swollman/* 12917214Swollman** For the benefit of GNU folk... 13017214Swollman** `_(MSGID)' uses the current locale's message library string for MSGID. 13117214Swollman** The default is to use gettext if available, and use MSGID otherwise. 13217214Swollman*/ 13317214Swollman 13417214Swollman#ifndef _ 135192625Sedwin#if HAVE_GETTEXT 13617214Swollman#define _(msgid) gettext(msgid) 137192625Sedwin#else /* !(HAVE_GETTEXT) */ 13817214Swollman#define _(msgid) msgid 139192625Sedwin#endif /* !(HAVE_GETTEXT) */ 14017214Swollman#endif /* !defined _ */ 14117214Swollman 14217214Swollman#ifndef TZ_DOMAIN 14317214Swollman#define TZ_DOMAIN "tz" 14417214Swollman#endif /* !defined TZ_DOMAIN */ 14517214Swollman 1462702Swollmanextern char ** environ; 1472702Swollmanextern char * tzname[2]; 1482702Swollman 149192625Sedwinstatic time_t absolute_min_time; 150192625Sedwinstatic time_t absolute_max_time; 15142997Swollmanstatic size_t longest; 152192625Sedwinstatic char * progname; 153192625Sedwinstatic int warned; 1542702Swollman 155198831Sedwinstatic void usage(FILE *stream, int status); 156192625Sedwinstatic char * abbr(struct tm * tmp); 157192625Sedwinstatic void abbrok(const char * abbrp, const char * zone); 158192625Sedwinstatic long delta(struct tm * newp, struct tm * oldp); 159192625Sedwinstatic void dumptime(const struct tm * tmp); 160192625Sedwinstatic time_t hunt(char * name, time_t lot, time_t hit); 161192625Sedwinstatic void setabsolutes(void); 162192625Sedwinstatic void show(char * zone, time_t t, int v); 163192625Sedwinstatic const char * tformat(void); 164192625Sedwinstatic time_t yeartot(long y); 165192625Sedwin 166192625Sedwin#ifndef TYPECHECK 167192625Sedwin#define my_localtime localtime 168192625Sedwin#else /* !defined TYPECHECK */ 169192625Sedwinstatic struct tm * 170192625Sedwinmy_localtime(tp) 171192625Sedwintime_t * tp; 172192625Sedwin{ 173192625Sedwin register struct tm * tmp; 174192625Sedwin 175192625Sedwin tmp = localtime(tp); 176192625Sedwin if (tp != NULL && tmp != NULL) { 177192625Sedwin struct tm tm; 178192625Sedwin register time_t t; 179192625Sedwin 180192625Sedwin tm = *tmp; 181192625Sedwin t = mktime(&tm); 182192625Sedwin if (t - *tp >= 1 || *tp - t >= 1) { 183192625Sedwin (void) fflush(stdout); 184192625Sedwin (void) fprintf(stderr, "\n%s: ", progname); 185192625Sedwin (void) fprintf(stderr, tformat(), *tp); 186192625Sedwin (void) fprintf(stderr, " ->"); 187192625Sedwin (void) fprintf(stderr, " year=%d", tmp->tm_year); 188192625Sedwin (void) fprintf(stderr, " mon=%d", tmp->tm_mon); 189192625Sedwin (void) fprintf(stderr, " mday=%d", tmp->tm_mday); 190192625Sedwin (void) fprintf(stderr, " hour=%d", tmp->tm_hour); 191192625Sedwin (void) fprintf(stderr, " min=%d", tmp->tm_min); 192192625Sedwin (void) fprintf(stderr, " sec=%d", tmp->tm_sec); 193192625Sedwin (void) fprintf(stderr, " isdst=%d", tmp->tm_isdst); 194192625Sedwin (void) fprintf(stderr, " -> "); 195192625Sedwin (void) fprintf(stderr, tformat(), t); 196192625Sedwin (void) fprintf(stderr, "\n"); 197192625Sedwin } 198192625Sedwin } 199192625Sedwin return tmp; 200192625Sedwin} 201192625Sedwin#endif /* !defined TYPECHECK */ 202192625Sedwin 203192625Sedwinstatic void 204192625Sedwinabbrok(abbrp, zone) 205192625Sedwinconst char * const abbrp; 206192625Sedwinconst char * const zone; 207192625Sedwin{ 208192625Sedwin register const char * cp; 209192625Sedwin register char * wp; 210192625Sedwin 211192625Sedwin if (warned) 212192625Sedwin return; 213192625Sedwin cp = abbrp; 214192625Sedwin wp = NULL; 215307359Sbapt while (isascii((unsigned char) *cp) && 216307359Sbapt (isalnum((unsigned char)*cp) || *cp == '-' || *cp == '+')) 217192625Sedwin ++cp; 218307359Sbapt if (cp - abbrp < 3) 219307359Sbapt wp = _("has fewer than 3 characters"); 220192625Sedwin else if (cp - abbrp > 6) 221307359Sbapt wp = _("has more than 6 characters"); 222307359Sbapt else if (*cp) 223307359Sbapt wp = "has characters other than ASCII alphanumerics, '-' or '+'"; 224307359Sbapt else 225192625Sedwin return; 226192625Sedwin (void) fflush(stdout); 227192625Sedwin (void) fprintf(stderr, 228192625Sedwin _("%s: warning: zone \"%s\" abbreviation \"%s\" %s\n"), 229192625Sedwin progname, zone, abbrp, wp); 230192625Sedwin warned = TRUE; 231192625Sedwin} 232192625Sedwin 2332702Swollmanint 2342702Swollmanmain(argc, argv) 2352702Swollmanint argc; 2362702Swollmanchar * argv[]; 2372702Swollman{ 2389937Swollman register int i; 2399937Swollman register int c; 2409937Swollman register int vflag; 241192625Sedwin register char * cutarg; 242192625Sedwin register long cutloyear = ZDUMP_LO_YEAR; 243192625Sedwin register long cuthiyear = ZDUMP_HI_YEAR; 244192625Sedwin register time_t cutlotime; 245192625Sedwin register time_t cuthitime; 246192625Sedwin register char ** fakeenv; 2479937Swollman time_t now; 2489937Swollman time_t t; 2499937Swollman time_t newt; 2509937Swollman struct tm tm; 2519937Swollman struct tm newtm; 252192625Sedwin register struct tm * tmp; 253192625Sedwin register struct tm * newtmp; 2542702Swollman 255228342Seadler progname=argv[0]; 256192625Sedwin INITIALIZE(cutlotime); 257192625Sedwin INITIALIZE(cuthitime); 258192625Sedwin#if HAVE_GETTEXT 25917214Swollman (void) setlocale(LC_MESSAGES, ""); 26017214Swollman#ifdef TZ_DOMAINDIR 26117214Swollman (void) bindtextdomain(TZ_DOMAIN, TZ_DOMAINDIR); 262192625Sedwin#endif /* TEXTDOMAINDIR */ 26317214Swollman (void) textdomain(TZ_DOMAIN); 264192625Sedwin#endif /* HAVE_GETTEXT */ 265130819Sstefanf for (i = 1; i < argc; ++i) 266130819Sstefanf if (strcmp(argv[i], "--version") == 0) { 267130819Sstefanf errx(EXIT_SUCCESS, "%s", elsieid); 268192625Sedwin } else if (strcmp(argv[i], "--help") == 0) { 269198831Sedwin usage(stdout, EXIT_SUCCESS); 270130819Sstefanf } 2712702Swollman vflag = 0; 272192625Sedwin cutarg = NULL; 2732702Swollman while ((c = getopt(argc, argv, "c:v")) == 'c' || c == 'v') 2742702Swollman if (c == 'v') 2752702Swollman vflag = 1; 276192625Sedwin else cutarg = optarg; 277176407Sru if ((c != -1) || 2782702Swollman (optind == argc - 1 && strcmp(argv[optind], "=") == 0)) { 279198831Sedwin usage(stderr, EXIT_FAILURE); 2802702Swollman } 281192625Sedwin if (vflag) { 282192625Sedwin if (cutarg != NULL) { 283192625Sedwin long lo; 284192625Sedwin long hi; 285192625Sedwin char dummy; 2862702Swollman 287192625Sedwin if (sscanf(cutarg, "%ld%c", &hi, &dummy) == 1) { 288192625Sedwin cuthiyear = hi; 289192625Sedwin } else if (sscanf(cutarg, "%ld,%ld%c", 290192625Sedwin &lo, &hi, &dummy) == 2) { 291192625Sedwin cutloyear = lo; 292192625Sedwin cuthiyear = hi; 293192625Sedwin } else { 294192625Sedwin(void) fprintf(stderr, _("%s: wild -c argument %s\n"), 295192625Sedwin progname, cutarg); 296192625Sedwin exit(EXIT_FAILURE); 297192625Sedwin } 298192625Sedwin } 299192625Sedwin setabsolutes(); 300192625Sedwin cutlotime = yeartot(cutloyear); 301192625Sedwin cuthitime = yeartot(cuthiyear); 3022702Swollman } 3032702Swollman (void) time(&now); 3042702Swollman longest = 0; 3052702Swollman for (i = optind; i < argc; ++i) 3062702Swollman if (strlen(argv[i]) > longest) 3072702Swollman longest = strlen(argv[i]); 3089937Swollman { 3099937Swollman register int from; 3109937Swollman register int to; 3112702Swollman 312192625Sedwin for (i = 0; environ[i] != NULL; ++i) 3139937Swollman continue; 3149937Swollman fakeenv = (char **) malloc((size_t) ((i + 2) * 3159937Swollman sizeof *fakeenv)); 3169937Swollman if (fakeenv == NULL || 3179937Swollman (fakeenv[0] = (char *) malloc((size_t) (longest + 31830829Scharnier 4))) == NULL) 31930829Scharnier errx(EXIT_FAILURE, 32030829Scharnier _("malloc() failed")); 3219937Swollman to = 0; 3229937Swollman (void) strcpy(fakeenv[to++], "TZ="); 3239937Swollman for (from = 0; environ[from] != NULL; ++from) 3249937Swollman if (strncmp(environ[from], "TZ=", 3) != 0) 3259937Swollman fakeenv[to++] = environ[from]; 3269937Swollman fakeenv[to] = NULL; 3272702Swollman environ = fakeenv; 3289937Swollman } 3299937Swollman for (i = optind; i < argc; ++i) { 3309937Swollman static char buf[MAX_STRING_LENGTH]; 3319937Swollman 3329937Swollman (void) strcpy(&fakeenv[0][3], argv[i]); 33317214Swollman if (!vflag) { 33417214Swollman show(argv[i], now, FALSE); 3352702Swollman continue; 33617214Swollman } 337192625Sedwin warned = FALSE; 338192625Sedwin t = absolute_min_time; 3392702Swollman show(argv[i], t, TRUE); 3402702Swollman t += SECSPERHOUR * HOURSPERDAY; 3412702Swollman show(argv[i], t, TRUE); 342192625Sedwin if (t < cutlotime) 343192625Sedwin t = cutlotime; 344192625Sedwin tmp = my_localtime(&t); 345192625Sedwin if (tmp != NULL) { 346192625Sedwin tm = *tmp; 347192625Sedwin (void) strncpy(buf, abbr(&tm), (sizeof buf) - 1); 348192625Sedwin } 3492702Swollman for ( ; ; ) { 350192625Sedwin if (t >= cuthitime || t >= cuthitime - SECSPERHOUR * 12) 3512702Swollman break; 3522702Swollman newt = t + SECSPERHOUR * 12; 353192625Sedwin newtmp = localtime(&newt); 354192625Sedwin if (newtmp != NULL) 355192625Sedwin newtm = *newtmp; 356192625Sedwin if ((tmp == NULL || newtmp == NULL) ? (tmp != newtmp) : 357192625Sedwin (delta(&newtm, &tm) != (newt - t) || 3582702Swollman newtm.tm_isdst != tm.tm_isdst || 359192625Sedwin strcmp(abbr(&newtm), buf) != 0)) { 3602702Swollman newt = hunt(argv[i], t, newt); 361192625Sedwin newtmp = localtime(&newt); 362192625Sedwin if (newtmp != NULL) { 363192625Sedwin newtm = *newtmp; 364192625Sedwin (void) strncpy(buf, 365192625Sedwin abbr(&newtm), 366192625Sedwin (sizeof buf) - 1); 367192625Sedwin } 3682702Swollman } 3692702Swollman t = newt; 3702702Swollman tm = newtm; 371192625Sedwin tmp = newtmp; 3722702Swollman } 373192625Sedwin t = absolute_max_time; 3742702Swollman t -= SECSPERHOUR * HOURSPERDAY; 3752702Swollman show(argv[i], t, TRUE); 3762702Swollman t += SECSPERHOUR * HOURSPERDAY; 3772702Swollman show(argv[i], t, TRUE); 3782702Swollman } 37930829Scharnier if (fflush(stdout) || ferror(stdout)) 38030829Scharnier errx(EXIT_FAILURE, _("error writing standard output")); 3812702Swollman exit(EXIT_SUCCESS); 382192625Sedwin /* If exit fails to exit... */ 383192625Sedwin return(EXIT_FAILURE); 384192625Sedwin} 3852702Swollman 386192625Sedwinstatic void 387192625Sedwinsetabsolutes(void) 388192625Sedwin{ 389192625Sedwin if (0.5 == (time_t) 0.5) { 390192625Sedwin /* 391192625Sedwin ** time_t is floating. 392192625Sedwin */ 393192625Sedwin if (sizeof (time_t) == sizeof (float)) { 394192625Sedwin absolute_min_time = (time_t) -FLT_MAX; 395192625Sedwin absolute_max_time = (time_t) FLT_MAX; 396192625Sedwin } else if (sizeof (time_t) == sizeof (double)) { 397192625Sedwin absolute_min_time = (time_t) -DBL_MAX; 398192625Sedwin absolute_max_time = (time_t) DBL_MAX; 399192625Sedwin } else { 400192625Sedwin (void) fprintf(stderr, 401192625Sedwin_("%s: use of -v on system with floating time_t other than float or double\n"), 402192625Sedwin progname); 403192625Sedwin exit(EXIT_FAILURE); 404192625Sedwin } 405192625Sedwin } else if (0 > (time_t) -1) { 406192625Sedwin /* 407192625Sedwin ** time_t is signed. Assume overflow wraps around. 408192625Sedwin */ 409192625Sedwin time_t t = 0; 410192625Sedwin time_t t1 = 1; 411192625Sedwin 412192625Sedwin while (t < t1) { 413192625Sedwin t = t1; 414192625Sedwin t1 = 2 * t1 + 1; 415192625Sedwin } 416192625Sedwin 417192625Sedwin absolute_max_time = t; 418192625Sedwin t = -t; 419192625Sedwin absolute_min_time = t - 1; 420192625Sedwin if (t < absolute_min_time) 421192625Sedwin absolute_min_time = t; 422192625Sedwin } else { 423192625Sedwin /* 424192625Sedwin ** time_t is unsigned. 425192625Sedwin */ 426192625Sedwin absolute_min_time = 0; 427192625Sedwin absolute_max_time = absolute_min_time - 1; 428192625Sedwin } 4292702Swollman} 4302702Swollman 431192625Sedwinstatic time_t 432192625Sedwinyeartot(y) 433192625Sedwinconst long y; 434192625Sedwin{ 435192625Sedwin register long myy; 436192625Sedwin register long seconds; 437192625Sedwin register time_t t; 438192625Sedwin 439192625Sedwin myy = EPOCH_YEAR; 440192625Sedwin t = 0; 441192625Sedwin while (myy != y) { 442192625Sedwin if (myy < y) { 443192625Sedwin seconds = isleap(myy) ? SECSPERLYEAR : SECSPERNYEAR; 444192625Sedwin ++myy; 445192625Sedwin if (t > absolute_max_time - seconds) { 446192625Sedwin t = absolute_max_time; 447192625Sedwin break; 448192625Sedwin } 449192625Sedwin t += seconds; 450192625Sedwin } else { 451192625Sedwin --myy; 452192625Sedwin seconds = isleap(myy) ? SECSPERLYEAR : SECSPERNYEAR; 453192625Sedwin if (t < absolute_min_time + seconds) { 454192625Sedwin t = absolute_min_time; 455192625Sedwin break; 456192625Sedwin } 457192625Sedwin t -= seconds; 458192625Sedwin } 459192625Sedwin } 460192625Sedwin return t; 461192625Sedwin} 462192625Sedwin 46330829Scharnierstatic void 464198831Sedwinusage(FILE *stream, int status) 46530829Scharnier{ 466192625Sedwin fprintf(stream, 467192625Sedwin_("usage: %s [--version] [-v] [--help] [-c [loyear,]hiyear] zonename ...\n\ 468192625Sedwin\n\ 469192625SedwinReport bugs to tz@elsie.nci.nih.gov.\n"), progname); 470192625Sedwin exit(status); 47130829Scharnier} 47230829Scharnier 4732702Swollmanstatic time_t 474192625Sedwinhunt(char *name, time_t lot, time_t hit) 4752702Swollman{ 476192625Sedwin time_t t; 477192625Sedwin long diff; 478192625Sedwin struct tm lotm; 479192625Sedwin register struct tm * lotmp; 480192625Sedwin struct tm tm; 481192625Sedwin register struct tm * tmp; 482192625Sedwin char loab[MAX_STRING_LENGTH]; 4832702Swollman 484192625Sedwin lotmp = my_localtime(&lot); 485192625Sedwin if (lotmp != NULL) { 486192625Sedwin lotm = *lotmp; 487192625Sedwin (void) strncpy(loab, abbr(&lotm), (sizeof loab) - 1); 488192625Sedwin } 489192625Sedwin for ( ; ; ) { 490192625Sedwin diff = (long) (hit - lot); 491192625Sedwin if (diff < 2) 492192625Sedwin break; 493192625Sedwin t = lot; 494192625Sedwin t += diff / 2; 4952702Swollman if (t <= lot) 4962702Swollman ++t; 4972702Swollman else if (t >= hit) 4982702Swollman --t; 499192625Sedwin tmp = my_localtime(&t); 500192625Sedwin if (tmp != NULL) 501192625Sedwin tm = *tmp; 502192625Sedwin if ((lotmp == NULL || tmp == NULL) ? (lotmp == tmp) : 503192625Sedwin (delta(&tm, &lotm) == (t - lot) && 5042702Swollman tm.tm_isdst == lotm.tm_isdst && 505192625Sedwin strcmp(abbr(&tm), loab) == 0)) { 5062702Swollman lot = t; 5072702Swollman lotm = tm; 508192625Sedwin lotmp = tmp; 5092702Swollman } else hit = t; 5102702Swollman } 5112702Swollman show(name, lot, TRUE); 5122702Swollman show(name, hit, TRUE); 5132702Swollman return hit; 5142702Swollman} 5152702Swollman 5162702Swollman/* 517192625Sedwin** Thanks to Paul Eggert for logic used in delta. 5182702Swollman*/ 5192702Swollman 5202702Swollmanstatic long 5212702Swollmandelta(newp, oldp) 5222702Swollmanstruct tm * newp; 5232702Swollmanstruct tm * oldp; 5242702Swollman{ 525192625Sedwin register long result; 526192625Sedwin register int tmy; 5272702Swollman 5282702Swollman if (newp->tm_year < oldp->tm_year) 5292702Swollman return -delta(oldp, newp); 5302702Swollman result = 0; 5312702Swollman for (tmy = oldp->tm_year; tmy < newp->tm_year; ++tmy) 532192625Sedwin result += DAYSPERNYEAR + isleap_sum(tmy, TM_YEAR_BASE); 5332702Swollman result += newp->tm_yday - oldp->tm_yday; 5342702Swollman result *= HOURSPERDAY; 5352702Swollman result += newp->tm_hour - oldp->tm_hour; 5362702Swollman result *= MINSPERHOUR; 5372702Swollman result += newp->tm_min - oldp->tm_min; 5382702Swollman result *= SECSPERMIN; 5392702Swollman result += newp->tm_sec - oldp->tm_sec; 5402702Swollman return result; 5412702Swollman} 5422702Swollman 5432702Swollmanstatic void 544192625Sedwinshow(char *zone, time_t t, int v) 5452702Swollman{ 546192625Sedwin register struct tm * tmp; 5472702Swollman 54842997Swollman (void) printf("%-*s ", (int) longest, zone); 5492702Swollman if (v) { 550192625Sedwin tmp = gmtime(&t); 551192625Sedwin if (tmp == NULL) { 552192625Sedwin (void) printf(tformat(), t); 553192625Sedwin } else { 554192625Sedwin dumptime(tmp); 555192625Sedwin (void) printf(" UTC"); 556192625Sedwin } 557192625Sedwin (void) printf(" = "); 558192625Sedwin } 559192625Sedwin tmp = my_localtime(&t); 560192625Sedwin dumptime(tmp); 561192625Sedwin if (tmp != NULL) { 562192625Sedwin if (*abbr(tmp) != '\0') 563192625Sedwin (void) printf(" %s", abbr(tmp)); 564192625Sedwin if (v) { 565192625Sedwin (void) printf(" isdst=%d", tmp->tm_isdst); 5662702Swollman#ifdef TM_GMTOFF 567192625Sedwin (void) printf(" gmtoff=%ld", tmp->TM_GMTOFF); 5682702Swollman#endif /* defined TM_GMTOFF */ 569192625Sedwin } 5702702Swollman } 5712702Swollman (void) printf("\n"); 572192625Sedwin if (tmp != NULL && *abbr(tmp) != '\0') 573192625Sedwin abbrok(abbr(tmp), zone); 5742702Swollman} 5752702Swollman 5762702Swollmanstatic char * 5772702Swollmanabbr(tmp) 5782702Swollmanstruct tm * tmp; 5792702Swollman{ 5802702Swollman register char * result; 5819937Swollman static char nada; 5822702Swollman 5832702Swollman if (tmp->tm_isdst != 0 && tmp->tm_isdst != 1) 5849937Swollman return &nada; 5852702Swollman result = tzname[tmp->tm_isdst]; 5869937Swollman return (result == NULL) ? &nada : result; 5872702Swollman} 588192625Sedwin 589192625Sedwin/* 590192625Sedwin** The code below can fail on certain theoretical systems; 591192625Sedwin** it works on all known real-world systems as of 2004-12-30. 592192625Sedwin*/ 593192625Sedwin 594192625Sedwinstatic const char * 595192625Sedwintformat(void) 596192625Sedwin{ 597192625Sedwin if (0.5 == (time_t) 0.5) { /* floating */ 598192625Sedwin if (sizeof (time_t) > sizeof (double)) 599192625Sedwin return "%Lg"; 600192625Sedwin return "%g"; 601192625Sedwin } 602192625Sedwin if (0 > (time_t) -1) { /* signed */ 603192625Sedwin if (sizeof (time_t) > sizeof (long)) 604192625Sedwin return "%lld"; 605192625Sedwin if (sizeof (time_t) > sizeof (int)) 606192625Sedwin return "%ld"; 607192625Sedwin return "%d"; 608192625Sedwin } 609192625Sedwin if (sizeof (time_t) > sizeof (unsigned long)) 610192625Sedwin return "%llu"; 611192625Sedwin if (sizeof (time_t) > sizeof (unsigned int)) 612192625Sedwin return "%lu"; 613192625Sedwin return "%u"; 614192625Sedwin} 615192625Sedwin 616192625Sedwinstatic void 617192625Sedwindumptime(timeptr) 618192625Sedwinregister const struct tm * timeptr; 619192625Sedwin{ 620192625Sedwin static const char wday_name[][3] = { 621192625Sedwin "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" 622192625Sedwin }; 623192625Sedwin static const char mon_name[][3] = { 624192625Sedwin "Jan", "Feb", "Mar", "Apr", "May", "Jun", 625192625Sedwin "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" 626192625Sedwin }; 627192625Sedwin register const char * wn; 628192625Sedwin register const char * mn; 629192625Sedwin register int lead; 630192625Sedwin register int trail; 631192625Sedwin 632192625Sedwin if (timeptr == NULL) { 633192625Sedwin (void) printf("NULL"); 634192625Sedwin return; 635192625Sedwin } 636192625Sedwin /* 637192625Sedwin ** The packaged versions of localtime and gmtime never put out-of-range 638192625Sedwin ** values in tm_wday or tm_mon, but since this code might be compiled 639192625Sedwin ** with other (perhaps experimental) versions, paranoia is in order. 640192625Sedwin */ 641192625Sedwin if (timeptr->tm_wday < 0 || timeptr->tm_wday >= 642192625Sedwin (int) (sizeof wday_name / sizeof wday_name[0])) 643192625Sedwin wn = "???"; 644192625Sedwin else wn = wday_name[timeptr->tm_wday]; 645192625Sedwin if (timeptr->tm_mon < 0 || timeptr->tm_mon >= 646192625Sedwin (int) (sizeof mon_name / sizeof mon_name[0])) 647192625Sedwin mn = "???"; 648192625Sedwin else mn = mon_name[timeptr->tm_mon]; 649192625Sedwin (void) printf("%.3s %.3s%3d %.2d:%.2d:%.2d ", 650192625Sedwin wn, mn, 651192625Sedwin timeptr->tm_mday, timeptr->tm_hour, 652192625Sedwin timeptr->tm_min, timeptr->tm_sec); 653192625Sedwin#define DIVISOR 10 654192625Sedwin trail = timeptr->tm_year % DIVISOR + TM_YEAR_BASE % DIVISOR; 655192625Sedwin lead = timeptr->tm_year / DIVISOR + TM_YEAR_BASE / DIVISOR + 656192625Sedwin trail / DIVISOR; 657192625Sedwin trail %= DIVISOR; 658192625Sedwin if (trail < 0 && lead > 0) { 659192625Sedwin trail += DIVISOR; 660192625Sedwin --lead; 661192625Sedwin } else if (lead < 0 && trail > 0) { 662192625Sedwin trail -= DIVISOR; 663192625Sedwin ++lead; 664192625Sedwin } 665192625Sedwin if (lead == 0) 666192625Sedwin (void) printf("%d", trail); 667192625Sedwin else (void) printf("%d%d", lead, ((trail < 0) ? -trail : trail)); 668192625Sedwin} 669