zdump.c revision 9937
12702Swollman#ifndef lint
22702Swollman#ifndef NOID
39937Swollmanstatic char	elsieid[] = "@(#)zdump.c	7.20";
42702Swollman#endif /* !defined NOID */
52702Swollman#endif /* !defined lint */
62702Swollman
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
139937Swollman#include "stdio.h"	/* for stdout, stderr, perror */
142702Swollman#include "string.h"	/* for strcpy */
152702Swollman#include "sys/types.h"	/* for time_t */
162702Swollman#include "time.h"	/* for struct tm */
179937Swollman#include "stdlib.h"	/* for exit, malloc, atoi */
182702Swollman
192702Swollman#ifndef MAX_STRING_LENGTH
202702Swollman#define MAX_STRING_LENGTH	1024
212702Swollman#endif /* !defined MAX_STRING_LENGTH */
222702Swollman
232702Swollman#ifndef TRUE
242702Swollman#define TRUE		1
252702Swollman#endif /* !defined TRUE */
262702Swollman
272702Swollman#ifndef FALSE
282702Swollman#define FALSE		0
292702Swollman#endif /* !defined FALSE */
302702Swollman
312702Swollman#ifndef EXIT_SUCCESS
322702Swollman#define EXIT_SUCCESS	0
332702Swollman#endif /* !defined EXIT_SUCCESS */
342702Swollman
352702Swollman#ifndef EXIT_FAILURE
362702Swollman#define EXIT_FAILURE	1
372702Swollman#endif /* !defined EXIT_FAILURE */
382702Swollman
392702Swollman#ifndef SECSPERMIN
402702Swollman#define SECSPERMIN	60
412702Swollman#endif /* !defined SECSPERMIN */
422702Swollman
432702Swollman#ifndef MINSPERHOUR
442702Swollman#define MINSPERHOUR	60
452702Swollman#endif /* !defined MINSPERHOUR */
462702Swollman
472702Swollman#ifndef SECSPERHOUR
482702Swollman#define SECSPERHOUR	(SECSPERMIN * MINSPERHOUR)
492702Swollman#endif /* !defined SECSPERHOUR */
502702Swollman
512702Swollman#ifndef HOURSPERDAY
522702Swollman#define HOURSPERDAY	24
532702Swollman#endif /* !defined HOURSPERDAY */
542702Swollman
552702Swollman#ifndef EPOCH_YEAR
562702Swollman#define EPOCH_YEAR	1970
572702Swollman#endif /* !defined EPOCH_YEAR */
582702Swollman
592702Swollman#ifndef TM_YEAR_BASE
602702Swollman#define TM_YEAR_BASE	1900
612702Swollman#endif /* !defined TM_YEAR_BASE */
622702Swollman
632702Swollman#ifndef DAYSPERNYEAR
642702Swollman#define DAYSPERNYEAR	365
652702Swollman#endif /* !defined DAYSPERNYEAR */
662702Swollman
672702Swollman#ifndef isleap
682702Swollman#define isleap(y) ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0)
692702Swollman#endif /* !defined isleap */
702702Swollman
719937Swollman#ifndef GNUC_or_lint
729937Swollman#ifdef lint
739937Swollman#define GNUC_or_lint
749937Swollman#endif /* defined lint */
759937Swollman#ifndef lint
769937Swollman#ifdef __GNUC__
779937Swollman#define GNUC_or_lint
789937Swollman#endif /* defined __GNUC__ */
799937Swollman#endif /* !defined lint */
809937Swollman#endif /* !defined GNUC_or_lint */
819937Swollman
829937Swollman#ifndef INITIALIZE
839937Swollman#ifdef GNUC_or_lint
849937Swollman#define INITIALIZE(x)	((x) = 0)
859937Swollman#endif /* defined GNUC_or_lint */
869937Swollman#ifndef GNUC_or_lint
879937Swollman#define INITIALIZE(x)
889937Swollman#endif /* !defined GNUC_or_lint */
899937Swollman#endif /* !defined INITIALIZE */
909937Swollman
912702Swollmanextern char **	environ;
922702Swollmanextern int	getopt();
932702Swollmanextern char *	optarg;
942702Swollmanextern int	optind;
952702Swollmanextern time_t	time();
962702Swollmanextern char *	tzname[2];
972702Swollman
982702Swollmanstatic char *	abbr();
992702Swollmanstatic long	delta();
1002702Swollmanstatic time_t	hunt();
1012702Swollmanstatic int	longest;
1022702Swollmanstatic char *	progname;
1032702Swollmanstatic void	show();
1042702Swollman
1052702Swollmanint
1062702Swollmanmain(argc, argv)
1072702Swollmanint	argc;
1082702Swollmanchar *	argv[];
1092702Swollman{
1109937Swollman	register int		i;
1119937Swollman	register int		c;
1129937Swollman	register int		vflag;
1139937Swollman	register char *		cutoff;
1149937Swollman	register int		cutyear;
1159937Swollman	register long		cuttime;
1169937Swollman	char **			fakeenv;
1179937Swollman	time_t			now;
1189937Swollman	time_t			t;
1199937Swollman	time_t			newt;
1209937Swollman	time_t			hibit;
1219937Swollman	struct tm		tm;
1229937Swollman	struct tm		newtm;
1232702Swollman
1249937Swollman	INITIALIZE(cuttime);
1252702Swollman	progname = argv[0];
1262702Swollman	vflag = 0;
1272702Swollman	cutoff = NULL;
1282702Swollman	while ((c = getopt(argc, argv, "c:v")) == 'c' || c == 'v')
1292702Swollman		if (c == 'v')
1302702Swollman			vflag = 1;
1312702Swollman		else	cutoff = optarg;
1322702Swollman	if (c != EOF ||
1332702Swollman		(optind == argc - 1 && strcmp(argv[optind], "=") == 0)) {
1342702Swollman			(void) fprintf(stderr,
1352702Swollman"%s: usage is %s [ -v ] [ -c cutoff ] zonename ...\n",
1362702Swollman				argv[0], argv[0]);
1372702Swollman			(void) exit(EXIT_FAILURE);
1382702Swollman	}
1392702Swollman	if (cutoff != NULL) {
1402702Swollman		int	y;
1412702Swollman
1422702Swollman		cutyear = atoi(cutoff);
1432702Swollman		cuttime = 0;
1442702Swollman		for (y = EPOCH_YEAR; y < cutyear; ++y)
1452702Swollman			cuttime += DAYSPERNYEAR + isleap(y);
1462702Swollman		cuttime *= SECSPERHOUR * HOURSPERDAY;
1472702Swollman	}
1482702Swollman	(void) time(&now);
1492702Swollman	longest = 0;
1502702Swollman	for (i = optind; i < argc; ++i)
1512702Swollman		if (strlen(argv[i]) > longest)
1522702Swollman			longest = strlen(argv[i]);
1532702Swollman	for (hibit = 1; (hibit << 1) != 0; hibit <<= 1)
1542702Swollman		continue;
1559937Swollman	{
1569937Swollman		register int	from;
1579937Swollman		register int	to;
1582702Swollman
1599937Swollman		for (i = 0;  environ[i] != NULL;  ++i)
1609937Swollman			continue;
1619937Swollman		fakeenv = (char **) malloc((size_t) ((i + 2) *
1629937Swollman			sizeof *fakeenv));
1639937Swollman		if (fakeenv == NULL ||
1649937Swollman			(fakeenv[0] = (char *) malloc((size_t) (longest +
1659937Swollman				4))) == NULL) {
1669937Swollman					(void) perror(progname);
1679937Swollman					(void) exit(EXIT_FAILURE);
1682702Swollman		}
1699937Swollman		to = 0;
1709937Swollman		(void) strcpy(fakeenv[to++], "TZ=");
1719937Swollman		for (from = 0; environ[from] != NULL; ++from)
1729937Swollman			if (strncmp(environ[from], "TZ=", 3) != 0)
1739937Swollman				fakeenv[to++] = environ[from];
1749937Swollman		fakeenv[to] = NULL;
1752702Swollman		environ = fakeenv;
1769937Swollman	}
1779937Swollman	for (i = optind; i < argc; ++i) {
1789937Swollman		static char	buf[MAX_STRING_LENGTH];
1799937Swollman
1809937Swollman		(void) strcpy(&fakeenv[0][3], argv[i]);
1812702Swollman		show(argv[i], now, FALSE);
1822702Swollman		if (!vflag)
1832702Swollman			continue;
1842702Swollman		/*
1852702Swollman		** Get lowest value of t.
1862702Swollman		*/
1872702Swollman		t = hibit;
1882702Swollman		if (t > 0)		/* time_t is unsigned */
1892702Swollman			t = 0;
1902702Swollman		show(argv[i], t, TRUE);
1912702Swollman		t += SECSPERHOUR * HOURSPERDAY;
1922702Swollman		show(argv[i], t, TRUE);
1932702Swollman		tm = *localtime(&t);
1942702Swollman		(void) strncpy(buf, abbr(&tm), (sizeof buf) - 1);
1952702Swollman		for ( ; ; ) {
1962702Swollman			if (cutoff != NULL && t >= cuttime)
1972702Swollman				break;
1982702Swollman			newt = t + SECSPERHOUR * 12;
1992702Swollman			if (cutoff != NULL && newt >= cuttime)
2002702Swollman				break;
2012702Swollman			if (newt <= t)
2022702Swollman				break;
2032702Swollman			newtm = *localtime(&newt);
2042702Swollman			if (delta(&newtm, &tm) != (newt - t) ||
2052702Swollman				newtm.tm_isdst != tm.tm_isdst ||
2062702Swollman				strcmp(abbr(&newtm), buf) != 0) {
2072702Swollman					newt = hunt(argv[i], t, newt);
2082702Swollman					newtm = *localtime(&newt);
2092702Swollman					(void) strncpy(buf, abbr(&newtm),
2102702Swollman						(sizeof buf) - 1);
2112702Swollman			}
2122702Swollman			t = newt;
2132702Swollman			tm = newtm;
2142702Swollman		}
2152702Swollman		/*
2162702Swollman		** Get highest value of t.
2172702Swollman		*/
2182702Swollman		t = ~((time_t) 0);
2192702Swollman		if (t < 0)		/* time_t is signed */
2202702Swollman			t &= ~hibit;
2212702Swollman		t -= SECSPERHOUR * HOURSPERDAY;
2222702Swollman		show(argv[i], t, TRUE);
2232702Swollman		t += SECSPERHOUR * HOURSPERDAY;
2242702Swollman		show(argv[i], t, TRUE);
2252702Swollman	}
2262702Swollman	if (fflush(stdout) || ferror(stdout)) {
2272702Swollman		(void) fprintf(stderr, "%s: Error writing standard output ",
2282702Swollman			argv[0]);
2292702Swollman		(void) perror("standard output");
2302702Swollman		(void) exit(EXIT_FAILURE);
2312702Swollman	}
2322702Swollman	exit(EXIT_SUCCESS);
2332702Swollman
2342702Swollman	/* gcc -Wall pacifier */
2352702Swollman	for ( ; ; )
2362702Swollman		continue;
2372702Swollman}
2382702Swollman
2392702Swollmanstatic time_t
2402702Swollmanhunt(name, lot, hit)
2412702Swollmanchar *	name;
2422702Swollmantime_t	lot;
2432702Swollmantime_t	hit;
2442702Swollman{
2452702Swollman	time_t		t;
2462702Swollman	struct tm	lotm;
2472702Swollman	struct tm	tm;
2482702Swollman	static char	loab[MAX_STRING_LENGTH];
2492702Swollman
2502702Swollman	lotm = *localtime(&lot);
2512702Swollman	(void) strncpy(loab, abbr(&lotm), (sizeof loab) - 1);
2522702Swollman	while ((hit - lot) >= 2) {
2532702Swollman		t = lot / 2 + hit / 2;
2542702Swollman		if (t <= lot)
2552702Swollman			++t;
2562702Swollman		else if (t >= hit)
2572702Swollman			--t;
2582702Swollman		tm = *localtime(&t);
2592702Swollman		if (delta(&tm, &lotm) == (t - lot) &&
2602702Swollman			tm.tm_isdst == lotm.tm_isdst &&
2612702Swollman			strcmp(abbr(&tm), loab) == 0) {
2622702Swollman				lot = t;
2632702Swollman				lotm = tm;
2642702Swollman		} else	hit = t;
2652702Swollman	}
2662702Swollman	show(name, lot, TRUE);
2672702Swollman	show(name, hit, TRUE);
2682702Swollman	return hit;
2692702Swollman}
2702702Swollman
2712702Swollman/*
2722702Swollman** Thanks to Paul Eggert (eggert@twinsun.com) for logic used in delta.
2732702Swollman*/
2742702Swollman
2752702Swollmanstatic long
2762702Swollmandelta(newp, oldp)
2772702Swollmanstruct tm *	newp;
2782702Swollmanstruct tm *	oldp;
2792702Swollman{
2802702Swollman	long	result;
2812702Swollman	int	tmy;
2822702Swollman
2832702Swollman	if (newp->tm_year < oldp->tm_year)
2842702Swollman		return -delta(oldp, newp);
2852702Swollman	result = 0;
2862702Swollman	for (tmy = oldp->tm_year; tmy < newp->tm_year; ++tmy)
2872702Swollman		result += DAYSPERNYEAR + isleap(tmy + TM_YEAR_BASE);
2882702Swollman	result += newp->tm_yday - oldp->tm_yday;
2892702Swollman	result *= HOURSPERDAY;
2902702Swollman	result += newp->tm_hour - oldp->tm_hour;
2912702Swollman	result *= MINSPERHOUR;
2922702Swollman	result += newp->tm_min - oldp->tm_min;
2932702Swollman	result *= SECSPERMIN;
2942702Swollman	result += newp->tm_sec - oldp->tm_sec;
2952702Swollman	return result;
2962702Swollman}
2972702Swollman
2989937Swollmanextern struct tm *	localtime();
2999937Swollman
3002702Swollmanstatic void
3012702Swollmanshow(zone, t, v)
3022702Swollmanchar *	zone;
3032702Swollmantime_t	t;
3042702Swollmanint	v;
3052702Swollman{
3069937Swollman	struct tm *	tmp;
3072702Swollman
3082702Swollman	(void) printf("%-*s  ", longest, zone);
3092702Swollman	if (v)
3102702Swollman		(void) printf("%.24s GMT = ", asctime(gmtime(&t)));
3112702Swollman	tmp = localtime(&t);
3122702Swollman	(void) printf("%.24s", asctime(tmp));
3132702Swollman	if (*abbr(tmp) != '\0')
3142702Swollman		(void) printf(" %s", abbr(tmp));
3152702Swollman	if (v) {
3162702Swollman		(void) printf(" isdst=%d", tmp->tm_isdst);
3172702Swollman#ifdef TM_GMTOFF
3182702Swollman		(void) printf(" gmtoff=%ld", tmp->TM_GMTOFF);
3192702Swollman#endif /* defined TM_GMTOFF */
3202702Swollman	}
3212702Swollman	(void) printf("\n");
3222702Swollman}
3232702Swollman
3242702Swollmanstatic char *
3252702Swollmanabbr(tmp)
3262702Swollmanstruct tm *	tmp;
3272702Swollman{
3282702Swollman	register char *	result;
3299937Swollman	static char	nada;
3302702Swollman
3312702Swollman	if (tmp->tm_isdst != 0 && tmp->tm_isdst != 1)
3329937Swollman		return &nada;
3332702Swollman	result = tzname[tmp->tm_isdst];
3349937Swollman	return (result == NULL) ? &nada : result;
3352702Swollman}
336