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