zdump.c revision 2702
12702Swollman#ifndef lint
22702Swollman#ifndef NOID
32702Swollmanstatic char	elsieid[] = "@(#)zdump.c	7.10";
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
132702Swollman#include "stdio.h"	/* for stdout, stderr */
142702Swollman#include "string.h"	/* for strcpy */
152702Swollman#include "sys/types.h"	/* for time_t */
162702Swollman#include "time.h"	/* for struct tm */
172702Swollman
182702Swollman#ifndef MAX_STRING_LENGTH
192702Swollman#define MAX_STRING_LENGTH	1024
202702Swollman#endif /* !defined MAX_STRING_LENGTH */
212702Swollman
222702Swollman#ifndef TRUE
232702Swollman#define TRUE		1
242702Swollman#endif /* !defined TRUE */
252702Swollman
262702Swollman#ifndef FALSE
272702Swollman#define FALSE		0
282702Swollman#endif /* !defined FALSE */
292702Swollman
302702Swollman#ifndef EXIT_SUCCESS
312702Swollman#define EXIT_SUCCESS	0
322702Swollman#endif /* !defined EXIT_SUCCESS */
332702Swollman
342702Swollman#ifndef EXIT_FAILURE
352702Swollman#define EXIT_FAILURE	1
362702Swollman#endif /* !defined EXIT_FAILURE */
372702Swollman
382702Swollman#ifndef SECSPERMIN
392702Swollman#define SECSPERMIN	60
402702Swollman#endif /* !defined SECSPERMIN */
412702Swollman
422702Swollman#ifndef MINSPERHOUR
432702Swollman#define MINSPERHOUR	60
442702Swollman#endif /* !defined MINSPERHOUR */
452702Swollman
462702Swollman#ifndef SECSPERHOUR
472702Swollman#define SECSPERHOUR	(SECSPERMIN * MINSPERHOUR)
482702Swollman#endif /* !defined SECSPERHOUR */
492702Swollman
502702Swollman#ifndef HOURSPERDAY
512702Swollman#define HOURSPERDAY	24
522702Swollman#endif /* !defined HOURSPERDAY */
532702Swollman
542702Swollman#ifndef EPOCH_YEAR
552702Swollman#define EPOCH_YEAR	1970
562702Swollman#endif /* !defined EPOCH_YEAR */
572702Swollman
582702Swollman#ifndef TM_YEAR_BASE
592702Swollman#define TM_YEAR_BASE	1900
602702Swollman#endif /* !defined TM_YEAR_BASE */
612702Swollman
622702Swollman#ifndef DAYSPERNYEAR
632702Swollman#define DAYSPERNYEAR	365
642702Swollman#endif /* !defined DAYSPERNYEAR */
652702Swollman
662702Swollman#ifndef isleap
672702Swollman#define isleap(y) ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0)
682702Swollman#endif /* !defined isleap */
692702Swollman
702702Swollmanextern char **	environ;
712702Swollmanextern int	getopt();
722702Swollmanextern char *	optarg;
732702Swollmanextern int	optind;
742702Swollmanextern time_t	time();
752702Swollmanextern char *	tzname[2];
762702Swollmanextern void	tzset();
772702Swollman
782702Swollman#ifdef USG
792702Swollmanextern void	exit();
802702Swollmanextern void	perror();
812702Swollman#endif /* defined USG */
822702Swollman
832702Swollmanstatic char *	abbr();
842702Swollmanstatic long	delta();
852702Swollmanstatic time_t	hunt();
862702Swollmanstatic int	longest;
872702Swollmanstatic char *	progname;
882702Swollmanstatic void	show();
892702Swollman
902702Swollmanint
912702Swollmanmain(argc, argv)
922702Swollmanint	argc;
932702Swollmanchar *	argv[];
942702Swollman{
952702Swollman	register int	i, c;
962702Swollman	register int	vflag;
972702Swollman	register char *	cutoff;
982702Swollman	register int	cutyear;
992702Swollman	register long	cuttime;
1002702Swollman	time_t		now;
1012702Swollman	time_t		t, newt;
1022702Swollman	time_t		hibit;
1032702Swollman	struct tm	tm, newtm;
1042702Swollman
1052702Swollman	progname = argv[0];
1062702Swollman	vflag = 0;
1072702Swollman	cutoff = NULL;
1082702Swollman	while ((c = getopt(argc, argv, "c:v")) == 'c' || c == 'v')
1092702Swollman		if (c == 'v')
1102702Swollman			vflag = 1;
1112702Swollman		else	cutoff = optarg;
1122702Swollman	if (c != EOF ||
1132702Swollman		(optind == argc - 1 && strcmp(argv[optind], "=") == 0)) {
1142702Swollman			(void) fprintf(stderr,
1152702Swollman"%s: usage is %s [ -v ] [ -c cutoff ] zonename ...\n",
1162702Swollman				argv[0], argv[0]);
1172702Swollman			(void) exit(EXIT_FAILURE);
1182702Swollman	}
1192702Swollman	if (cutoff != NULL) {
1202702Swollman		int	y;
1212702Swollman
1222702Swollman		cutyear = atoi(cutoff);
1232702Swollman		cuttime = 0;
1242702Swollman		for (y = EPOCH_YEAR; y < cutyear; ++y)
1252702Swollman			cuttime += DAYSPERNYEAR + isleap(y);
1262702Swollman		cuttime *= SECSPERHOUR * HOURSPERDAY;
1272702Swollman	}
1282702Swollman	(void) time(&now);
1292702Swollman	longest = 0;
1302702Swollman	for (i = optind; i < argc; ++i)
1312702Swollman		if (strlen(argv[i]) > longest)
1322702Swollman			longest = strlen(argv[i]);
1332702Swollman	for (hibit = 1; (hibit << 1) != 0; hibit <<= 1)
1342702Swollman		continue;
1352702Swollman	for (i = optind; i < argc; ++i) {
1362702Swollman		register char **	saveenv;
1372702Swollman		static char		buf[MAX_STRING_LENGTH];
1382702Swollman		char *			fakeenv[2];
1392702Swollman
1402702Swollman		if (strlen(argv[i]) + 4 > sizeof buf) {
1412702Swollman			(void) fflush(stdout);
1422702Swollman			(void) fprintf(stderr, "%s: argument too long -- %s\n",
1432702Swollman				progname, argv[i]);
1442702Swollman			(void) exit(EXIT_FAILURE);
1452702Swollman		}
1462702Swollman		(void) strcpy(buf, "TZ=");
1472702Swollman		(void) strcat(buf, argv[i]);
1482702Swollman		fakeenv[0] = buf;
1492702Swollman		fakeenv[1] = NULL;
1502702Swollman		saveenv = environ;
1512702Swollman		environ = fakeenv;
1522702Swollman		(void) tzset();
1532702Swollman		environ = saveenv;
1542702Swollman		show(argv[i], now, FALSE);
1552702Swollman		if (!vflag)
1562702Swollman			continue;
1572702Swollman		/*
1582702Swollman		** Get lowest value of t.
1592702Swollman		*/
1602702Swollman		t = hibit;
1612702Swollman		if (t > 0)		/* time_t is unsigned */
1622702Swollman			t = 0;
1632702Swollman		show(argv[i], t, TRUE);
1642702Swollman		t += SECSPERHOUR * HOURSPERDAY;
1652702Swollman		show(argv[i], t, TRUE);
1662702Swollman		tm = *localtime(&t);
1672702Swollman		(void) strncpy(buf, abbr(&tm), (sizeof buf) - 1);
1682702Swollman		for ( ; ; ) {
1692702Swollman			if (cutoff != NULL && t >= cuttime)
1702702Swollman				break;
1712702Swollman			newt = t + SECSPERHOUR * 12;
1722702Swollman			if (cutoff != NULL && newt >= cuttime)
1732702Swollman				break;
1742702Swollman			if (newt <= t)
1752702Swollman				break;
1762702Swollman			newtm = *localtime(&newt);
1772702Swollman			if (delta(&newtm, &tm) != (newt - t) ||
1782702Swollman				newtm.tm_isdst != tm.tm_isdst ||
1792702Swollman				strcmp(abbr(&newtm), buf) != 0) {
1802702Swollman					newt = hunt(argv[i], t, newt);
1812702Swollman					newtm = *localtime(&newt);
1822702Swollman					(void) strncpy(buf, abbr(&newtm),
1832702Swollman						(sizeof buf) - 1);
1842702Swollman			}
1852702Swollman			t = newt;
1862702Swollman			tm = newtm;
1872702Swollman		}
1882702Swollman		/*
1892702Swollman		** Get highest value of t.
1902702Swollman		*/
1912702Swollman		t = ~((time_t) 0);
1922702Swollman		if (t < 0)		/* time_t is signed */
1932702Swollman			t &= ~hibit;
1942702Swollman		t -= SECSPERHOUR * HOURSPERDAY;
1952702Swollman		show(argv[i], t, TRUE);
1962702Swollman		t += SECSPERHOUR * HOURSPERDAY;
1972702Swollman		show(argv[i], t, TRUE);
1982702Swollman	}
1992702Swollman	if (fflush(stdout) || ferror(stdout)) {
2002702Swollman		(void) fprintf(stderr, "%s: Error writing standard output ",
2012702Swollman			argv[0]);
2022702Swollman		(void) perror("standard output");
2032702Swollman		(void) exit(EXIT_FAILURE);
2042702Swollman	}
2052702Swollman	exit(EXIT_SUCCESS);
2062702Swollman
2072702Swollman	/* gcc -Wall pacifier */
2082702Swollman	for ( ; ; )
2092702Swollman		continue;
2102702Swollman}
2112702Swollman
2122702Swollmanstatic time_t
2132702Swollmanhunt(name, lot, hit)
2142702Swollmanchar *	name;
2152702Swollmantime_t	lot;
2162702Swollmantime_t	hit;
2172702Swollman{
2182702Swollman	time_t		t;
2192702Swollman	struct tm	lotm;
2202702Swollman	struct tm	tm;
2212702Swollman	static char	loab[MAX_STRING_LENGTH];
2222702Swollman
2232702Swollman	lotm = *localtime(&lot);
2242702Swollman	(void) strncpy(loab, abbr(&lotm), (sizeof loab) - 1);
2252702Swollman	while ((hit - lot) >= 2) {
2262702Swollman		t = lot / 2 + hit / 2;
2272702Swollman		if (t <= lot)
2282702Swollman			++t;
2292702Swollman		else if (t >= hit)
2302702Swollman			--t;
2312702Swollman		tm = *localtime(&t);
2322702Swollman		if (delta(&tm, &lotm) == (t - lot) &&
2332702Swollman			tm.tm_isdst == lotm.tm_isdst &&
2342702Swollman			strcmp(abbr(&tm), loab) == 0) {
2352702Swollman				lot = t;
2362702Swollman				lotm = tm;
2372702Swollman		} else	hit = t;
2382702Swollman	}
2392702Swollman	show(name, lot, TRUE);
2402702Swollman	show(name, hit, TRUE);
2412702Swollman	return hit;
2422702Swollman}
2432702Swollman
2442702Swollman/*
2452702Swollman** Thanks to Paul Eggert (eggert@twinsun.com) for logic used in delta.
2462702Swollman*/
2472702Swollman
2482702Swollmanstatic long
2492702Swollmandelta(newp, oldp)
2502702Swollmanstruct tm *	newp;
2512702Swollmanstruct tm *	oldp;
2522702Swollman{
2532702Swollman	long	result;
2542702Swollman	int	tmy;
2552702Swollman
2562702Swollman	if (newp->tm_year < oldp->tm_year)
2572702Swollman		return -delta(oldp, newp);
2582702Swollman	result = 0;
2592702Swollman	for (tmy = oldp->tm_year; tmy < newp->tm_year; ++tmy)
2602702Swollman		result += DAYSPERNYEAR + isleap(tmy + TM_YEAR_BASE);
2612702Swollman	result += newp->tm_yday - oldp->tm_yday;
2622702Swollman	result *= HOURSPERDAY;
2632702Swollman	result += newp->tm_hour - oldp->tm_hour;
2642702Swollman	result *= MINSPERHOUR;
2652702Swollman	result += newp->tm_min - oldp->tm_min;
2662702Swollman	result *= SECSPERMIN;
2672702Swollman	result += newp->tm_sec - oldp->tm_sec;
2682702Swollman	return result;
2692702Swollman}
2702702Swollman
2712702Swollmanstatic void
2722702Swollmanshow(zone, t, v)
2732702Swollmanchar *	zone;
2742702Swollmantime_t	t;
2752702Swollmanint	v;
2762702Swollman{
2772702Swollman	struct tm *		tmp;
2782702Swollman	extern struct tm *	localtime();
2792702Swollman
2802702Swollman	(void) printf("%-*s  ", longest, zone);
2812702Swollman	if (v)
2822702Swollman		(void) printf("%.24s GMT = ", asctime(gmtime(&t)));
2832702Swollman	tmp = localtime(&t);
2842702Swollman	(void) printf("%.24s", asctime(tmp));
2852702Swollman	if (*abbr(tmp) != '\0')
2862702Swollman		(void) printf(" %s", abbr(tmp));
2872702Swollman	if (v) {
2882702Swollman		(void) printf(" isdst=%d", tmp->tm_isdst);
2892702Swollman#ifdef TM_GMTOFF
2902702Swollman		(void) printf(" gmtoff=%ld", tmp->TM_GMTOFF);
2912702Swollman#endif /* defined TM_GMTOFF */
2922702Swollman	}
2932702Swollman	(void) printf("\n");
2942702Swollman}
2952702Swollman
2962702Swollmanstatic char *
2972702Swollmanabbr(tmp)
2982702Swollmanstruct tm *	tmp;
2992702Swollman{
3002702Swollman	register char *	result;
3012702Swollman	static char	nada[1];
3022702Swollman
3032702Swollman	if (tmp->tm_isdst != 0 && tmp->tm_isdst != 1)
3042702Swollman		return nada;
3052702Swollman	result = tzname[tmp->tm_isdst];
3062702Swollman	return (result == NULL) ? nada : result;
3072702Swollman}
308