zdump.c revision 44233
12702Swollman#ifndef lint 22702Swollman#ifndef NOID 342997Swollmanstatic char elsieid[] = "@(#)zdump.c 7.28"; 42702Swollman#endif /* !defined NOID */ 52702Swollman#endif /* !defined lint */ 62702Swollman 730829Scharnier#ifndef lint 830829Scharnierstatic const char rcsid[] = 944233Seivind "$Id: zdump.c,v 1.5 1999/01/21 17:46:19 wollman Exp $"; 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> 252702Swollman 262702Swollman#ifndef MAX_STRING_LENGTH 272702Swollman#define MAX_STRING_LENGTH 1024 282702Swollman#endif /* !defined MAX_STRING_LENGTH */ 292702Swollman 302702Swollman#ifndef TRUE 312702Swollman#define TRUE 1 322702Swollman#endif /* !defined TRUE */ 332702Swollman 342702Swollman#ifndef FALSE 352702Swollman#define FALSE 0 362702Swollman#endif /* !defined FALSE */ 372702Swollman 382702Swollman#ifndef EXIT_SUCCESS 392702Swollman#define EXIT_SUCCESS 0 402702Swollman#endif /* !defined EXIT_SUCCESS */ 412702Swollman 422702Swollman#ifndef EXIT_FAILURE 432702Swollman#define EXIT_FAILURE 1 442702Swollman#endif /* !defined EXIT_FAILURE */ 452702Swollman 462702Swollman#ifndef SECSPERMIN 472702Swollman#define SECSPERMIN 60 482702Swollman#endif /* !defined SECSPERMIN */ 492702Swollman 502702Swollman#ifndef MINSPERHOUR 512702Swollman#define MINSPERHOUR 60 522702Swollman#endif /* !defined MINSPERHOUR */ 532702Swollman 542702Swollman#ifndef SECSPERHOUR 552702Swollman#define SECSPERHOUR (SECSPERMIN * MINSPERHOUR) 562702Swollman#endif /* !defined SECSPERHOUR */ 572702Swollman 582702Swollman#ifndef HOURSPERDAY 592702Swollman#define HOURSPERDAY 24 602702Swollman#endif /* !defined HOURSPERDAY */ 612702Swollman 622702Swollman#ifndef EPOCH_YEAR 632702Swollman#define EPOCH_YEAR 1970 642702Swollman#endif /* !defined EPOCH_YEAR */ 652702Swollman 662702Swollman#ifndef TM_YEAR_BASE 672702Swollman#define TM_YEAR_BASE 1900 682702Swollman#endif /* !defined TM_YEAR_BASE */ 692702Swollman 702702Swollman#ifndef DAYSPERNYEAR 712702Swollman#define DAYSPERNYEAR 365 722702Swollman#endif /* !defined DAYSPERNYEAR */ 732702Swollman 742702Swollman#ifndef isleap 752702Swollman#define isleap(y) ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0) 762702Swollman#endif /* !defined isleap */ 772702Swollman 7817214Swollman#if HAVE_GETTEXT - 0 7917214Swollman#include "locale.h" /* for setlocale */ 8017214Swollman#include "libintl.h" 8117214Swollman#endif /* HAVE_GETTEXT - 0 */ 8217214Swollman 839937Swollman#ifndef GNUC_or_lint 849937Swollman#ifdef lint 859937Swollman#define GNUC_or_lint 869937Swollman#endif /* defined lint */ 879937Swollman#ifndef lint 889937Swollman#ifdef __GNUC__ 899937Swollman#define GNUC_or_lint 909937Swollman#endif /* defined __GNUC__ */ 919937Swollman#endif /* !defined lint */ 929937Swollman#endif /* !defined GNUC_or_lint */ 939937Swollman 949937Swollman#ifndef INITIALIZE 959937Swollman#ifdef GNUC_or_lint 969937Swollman#define INITIALIZE(x) ((x) = 0) 979937Swollman#endif /* defined GNUC_or_lint */ 989937Swollman#ifndef GNUC_or_lint 999937Swollman#define INITIALIZE(x) 1009937Swollman#endif /* !defined GNUC_or_lint */ 1019937Swollman#endif /* !defined INITIALIZE */ 1029937Swollman 10317214Swollman/* 10417214Swollman** For the benefit of GNU folk... 10517214Swollman** `_(MSGID)' uses the current locale's message library string for MSGID. 10617214Swollman** The default is to use gettext if available, and use MSGID otherwise. 10717214Swollman*/ 10817214Swollman 10917214Swollman#ifndef _ 11017214Swollman#if HAVE_GETTEXT - 0 11117214Swollman#define _(msgid) gettext(msgid) 11217214Swollman#else /* !(HAVE_GETTEXT - 0) */ 11317214Swollman#define _(msgid) msgid 11417214Swollman#endif /* !(HAVE_GETTEXT - 0) */ 11517214Swollman#endif /* !defined _ */ 11617214Swollman 11717214Swollman#ifndef TZ_DOMAIN 11817214Swollman#define TZ_DOMAIN "tz" 11917214Swollman#endif /* !defined TZ_DOMAIN */ 12017214Swollman 12142997Swollman#ifndef P 12242997Swollman#ifdef __STDC__ 12342997Swollman#define P(x) x 12442997Swollman#endif /* defined __STDC__ */ 12542997Swollman#ifndef __STDC__ 12642997Swollman#define P(x) () 12742997Swollman#endif /* !defined __STDC__ */ 12842997Swollman#endif /* !defined P */ 12942997Swollman 1302702Swollmanextern char ** environ; 1312702Swollmanextern char * tzname[2]; 1322702Swollman 13342997Swollmanstatic char * abbr P((struct tm * tmp)); 13442997Swollmanstatic long delta P((struct tm * newp, struct tm * oldp)); 13542997Swollmanstatic time_t hunt P((char * name, time_t lot, time_t hit)); 13642997Swollmanstatic size_t longest; 13742997Swollmanstatic char * progname; 13842997Swollmanstatic void show P((char * zone, time_t t, int v)); 13944233Seivindstatic void usage(void); 1402702Swollman 1412702Swollmanint 1422702Swollmanmain(argc, argv) 1432702Swollmanint argc; 1442702Swollmanchar * argv[]; 1452702Swollman{ 1469937Swollman register int i; 1479937Swollman register int c; 1489937Swollman register int vflag; 1499937Swollman register char * cutoff; 1509937Swollman register int cutyear; 1519937Swollman register long cuttime; 1529937Swollman char ** fakeenv; 1539937Swollman time_t now; 1549937Swollman time_t t; 1559937Swollman time_t newt; 1569937Swollman time_t hibit; 1579937Swollman struct tm tm; 1589937Swollman struct tm newtm; 1592702Swollman 1609937Swollman INITIALIZE(cuttime); 16117214Swollman#if HAVE_GETTEXT - 0 16217214Swollman (void) setlocale(LC_MESSAGES, ""); 16317214Swollman#ifdef TZ_DOMAINDIR 16417214Swollman (void) bindtextdomain(TZ_DOMAIN, TZ_DOMAINDIR); 16517214Swollman#endif /* defined(TEXTDOMAINDIR) */ 16617214Swollman (void) textdomain(TZ_DOMAIN); 16717214Swollman#endif /* HAVE_GETTEXT - 0 */ 1682702Swollman vflag = 0; 1692702Swollman cutoff = NULL; 1702702Swollman while ((c = getopt(argc, argv, "c:v")) == 'c' || c == 'v') 1712702Swollman if (c == 'v') 1722702Swollman vflag = 1; 1732702Swollman else cutoff = optarg; 17442997Swollman if ((c != EOF && c != -1) || 1752702Swollman (optind == argc - 1 && strcmp(argv[optind], "=") == 0)) { 17630829Scharnier usage(); 1772702Swollman } 1782702Swollman if (cutoff != NULL) { 1792702Swollman int y; 1802702Swollman 1812702Swollman cutyear = atoi(cutoff); 1822702Swollman cuttime = 0; 1832702Swollman for (y = EPOCH_YEAR; y < cutyear; ++y) 1842702Swollman cuttime += DAYSPERNYEAR + isleap(y); 1852702Swollman cuttime *= SECSPERHOUR * HOURSPERDAY; 1862702Swollman } 1872702Swollman (void) time(&now); 1882702Swollman longest = 0; 1892702Swollman for (i = optind; i < argc; ++i) 1902702Swollman if (strlen(argv[i]) > longest) 1912702Swollman longest = strlen(argv[i]); 1922702Swollman for (hibit = 1; (hibit << 1) != 0; hibit <<= 1) 1932702Swollman continue; 1949937Swollman { 1959937Swollman register int from; 1969937Swollman register int to; 1972702Swollman 1989937Swollman for (i = 0; environ[i] != NULL; ++i) 1999937Swollman continue; 2009937Swollman fakeenv = (char **) malloc((size_t) ((i + 2) * 2019937Swollman sizeof *fakeenv)); 2029937Swollman if (fakeenv == NULL || 2039937Swollman (fakeenv[0] = (char *) malloc((size_t) (longest + 20430829Scharnier 4))) == NULL) 20530829Scharnier errx(EXIT_FAILURE, 20630829Scharnier _("malloc() failed")); 2079937Swollman to = 0; 2089937Swollman (void) strcpy(fakeenv[to++], "TZ="); 2099937Swollman for (from = 0; environ[from] != NULL; ++from) 2109937Swollman if (strncmp(environ[from], "TZ=", 3) != 0) 2119937Swollman fakeenv[to++] = environ[from]; 2129937Swollman fakeenv[to] = NULL; 2132702Swollman environ = fakeenv; 2149937Swollman } 2159937Swollman for (i = optind; i < argc; ++i) { 2169937Swollman static char buf[MAX_STRING_LENGTH]; 2179937Swollman 2189937Swollman (void) strcpy(&fakeenv[0][3], argv[i]); 21917214Swollman if (!vflag) { 22017214Swollman show(argv[i], now, FALSE); 2212702Swollman continue; 22217214Swollman } 2232702Swollman /* 2242702Swollman ** Get lowest value of t. 2252702Swollman */ 2262702Swollman t = hibit; 2272702Swollman if (t > 0) /* time_t is unsigned */ 2282702Swollman t = 0; 2292702Swollman show(argv[i], t, TRUE); 2302702Swollman t += SECSPERHOUR * HOURSPERDAY; 2312702Swollman show(argv[i], t, TRUE); 2322702Swollman tm = *localtime(&t); 2332702Swollman (void) strncpy(buf, abbr(&tm), (sizeof buf) - 1); 2342702Swollman for ( ; ; ) { 2352702Swollman if (cutoff != NULL && t >= cuttime) 2362702Swollman break; 2372702Swollman newt = t + SECSPERHOUR * 12; 2382702Swollman if (cutoff != NULL && newt >= cuttime) 2392702Swollman break; 2402702Swollman if (newt <= t) 2412702Swollman break; 2422702Swollman newtm = *localtime(&newt); 2432702Swollman if (delta(&newtm, &tm) != (newt - t) || 2442702Swollman newtm.tm_isdst != tm.tm_isdst || 2452702Swollman strcmp(abbr(&newtm), buf) != 0) { 2462702Swollman newt = hunt(argv[i], t, newt); 2472702Swollman newtm = *localtime(&newt); 2482702Swollman (void) strncpy(buf, abbr(&newtm), 2492702Swollman (sizeof buf) - 1); 2502702Swollman } 2512702Swollman t = newt; 2522702Swollman tm = newtm; 2532702Swollman } 2542702Swollman /* 2552702Swollman ** Get highest value of t. 2562702Swollman */ 2572702Swollman t = ~((time_t) 0); 2582702Swollman if (t < 0) /* time_t is signed */ 2592702Swollman t &= ~hibit; 2602702Swollman t -= SECSPERHOUR * HOURSPERDAY; 2612702Swollman show(argv[i], t, TRUE); 2622702Swollman t += SECSPERHOUR * HOURSPERDAY; 2632702Swollman show(argv[i], t, TRUE); 2642702Swollman } 26530829Scharnier if (fflush(stdout) || ferror(stdout)) 26630829Scharnier errx(EXIT_FAILURE, _("error writing standard output")); 2672702Swollman exit(EXIT_SUCCESS); 2682702Swollman 2692702Swollman /* gcc -Wall pacifier */ 2702702Swollman for ( ; ; ) 2712702Swollman continue; 2722702Swollman} 2732702Swollman 27430829Scharnierstatic void 27544233Seivindusage(void) 27630829Scharnier{ 27730829Scharnier fprintf(stderr, _("usage: zdump [-v] [-c cutoff] zonename ...\n")); 27830829Scharnier exit(EXIT_FAILURE); 27930829Scharnier} 28030829Scharnier 2812702Swollmanstatic time_t 2822702Swollmanhunt(name, lot, hit) 2832702Swollmanchar * name; 2842702Swollmantime_t lot; 2852702Swollmantime_t hit; 2862702Swollman{ 2872702Swollman time_t t; 2882702Swollman struct tm lotm; 2892702Swollman struct tm tm; 2902702Swollman static char loab[MAX_STRING_LENGTH]; 2912702Swollman 2922702Swollman lotm = *localtime(&lot); 2932702Swollman (void) strncpy(loab, abbr(&lotm), (sizeof loab) - 1); 2942702Swollman while ((hit - lot) >= 2) { 2952702Swollman t = lot / 2 + hit / 2; 2962702Swollman if (t <= lot) 2972702Swollman ++t; 2982702Swollman else if (t >= hit) 2992702Swollman --t; 3002702Swollman tm = *localtime(&t); 3012702Swollman if (delta(&tm, &lotm) == (t - lot) && 3022702Swollman tm.tm_isdst == lotm.tm_isdst && 3032702Swollman strcmp(abbr(&tm), loab) == 0) { 3042702Swollman lot = t; 3052702Swollman lotm = tm; 3062702Swollman } else hit = t; 3072702Swollman } 3082702Swollman show(name, lot, TRUE); 3092702Swollman show(name, hit, TRUE); 3102702Swollman return hit; 3112702Swollman} 3122702Swollman 3132702Swollman/* 3142702Swollman** Thanks to Paul Eggert (eggert@twinsun.com) for logic used in delta. 3152702Swollman*/ 3162702Swollman 3172702Swollmanstatic long 3182702Swollmandelta(newp, oldp) 3192702Swollmanstruct tm * newp; 3202702Swollmanstruct tm * oldp; 3212702Swollman{ 3222702Swollman long result; 3232702Swollman int tmy; 3242702Swollman 3252702Swollman if (newp->tm_year < oldp->tm_year) 3262702Swollman return -delta(oldp, newp); 3272702Swollman result = 0; 3282702Swollman for (tmy = oldp->tm_year; tmy < newp->tm_year; ++tmy) 3292702Swollman result += DAYSPERNYEAR + isleap(tmy + TM_YEAR_BASE); 3302702Swollman result += newp->tm_yday - oldp->tm_yday; 3312702Swollman result *= HOURSPERDAY; 3322702Swollman result += newp->tm_hour - oldp->tm_hour; 3332702Swollman result *= MINSPERHOUR; 3342702Swollman result += newp->tm_min - oldp->tm_min; 3352702Swollman result *= SECSPERMIN; 3362702Swollman result += newp->tm_sec - oldp->tm_sec; 3372702Swollman return result; 3382702Swollman} 3392702Swollman 3402702Swollmanstatic void 3412702Swollmanshow(zone, t, v) 3422702Swollmanchar * zone; 3432702Swollmantime_t t; 3442702Swollmanint v; 3452702Swollman{ 3469937Swollman struct tm * tmp; 3472702Swollman 34842997Swollman (void) printf("%-*s ", (int) longest, zone); 3492702Swollman if (v) 35042997Swollman (void) printf("%.24s UTC = ", asctime(gmtime(&t))); 3512702Swollman tmp = localtime(&t); 3522702Swollman (void) printf("%.24s", asctime(tmp)); 3532702Swollman if (*abbr(tmp) != '\0') 3542702Swollman (void) printf(" %s", abbr(tmp)); 3552702Swollman if (v) { 3562702Swollman (void) printf(" isdst=%d", tmp->tm_isdst); 3572702Swollman#ifdef TM_GMTOFF 3582702Swollman (void) printf(" gmtoff=%ld", tmp->TM_GMTOFF); 3592702Swollman#endif /* defined TM_GMTOFF */ 3602702Swollman } 3612702Swollman (void) printf("\n"); 3622702Swollman} 3632702Swollman 3642702Swollmanstatic char * 3652702Swollmanabbr(tmp) 3662702Swollmanstruct tm * tmp; 3672702Swollman{ 3682702Swollman register char * result; 3699937Swollman static char nada; 3702702Swollman 3712702Swollman if (tmp->tm_isdst != 0 && tmp->tm_isdst != 1) 3729937Swollman return &nada; 3732702Swollman result = tzname[tmp->tm_isdst]; 3749937Swollman return (result == NULL) ? &nada : result; 3752702Swollman} 376