zdump.c revision 176407
1130819Sstefanfstatic const char	elsieid[] = "@(#)zdump.c	7.31";
22702Swollman
330829Scharnier#ifndef lint
430829Scharnierstatic const char rcsid[] =
550479Speter  "$FreeBSD: head/usr.sbin/zic/zdump.c 176407 2008-02-19 07:09:19Z ru $";
630829Scharnier#endif /* not lint */
730829Scharnier
82702Swollman/*
92702Swollman** This code has been made independent of the rest of the time
102702Swollman** conversion package to increase confidence in the verification it provides.
112702Swollman** You can use this code to help in verifying other implementations.
122702Swollman*/
132702Swollman
1430829Scharnier#include <err.h>
1530829Scharnier#include <stdio.h>	/* for stdout, stderr */
1630829Scharnier#include <stdlib.h>	/* for exit, malloc, atoi */
1730829Scharnier#include <string.h>	/* for strcpy */
1830829Scharnier#include <sys/types.h>	/* for time_t */
1930829Scharnier#include <time.h>	/* for struct tm */
2030829Scharnier#include <unistd.h>
212702Swollman
222702Swollman#ifndef MAX_STRING_LENGTH
232702Swollman#define MAX_STRING_LENGTH	1024
242702Swollman#endif /* !defined MAX_STRING_LENGTH */
252702Swollman
262702Swollman#ifndef TRUE
272702Swollman#define TRUE		1
282702Swollman#endif /* !defined TRUE */
292702Swollman
302702Swollman#ifndef FALSE
312702Swollman#define FALSE		0
322702Swollman#endif /* !defined FALSE */
332702Swollman
342702Swollman#ifndef EXIT_SUCCESS
352702Swollman#define EXIT_SUCCESS	0
362702Swollman#endif /* !defined EXIT_SUCCESS */
372702Swollman
382702Swollman#ifndef EXIT_FAILURE
392702Swollman#define EXIT_FAILURE	1
402702Swollman#endif /* !defined EXIT_FAILURE */
412702Swollman
422702Swollman#ifndef SECSPERMIN
432702Swollman#define SECSPERMIN	60
442702Swollman#endif /* !defined SECSPERMIN */
452702Swollman
462702Swollman#ifndef MINSPERHOUR
472702Swollman#define MINSPERHOUR	60
482702Swollman#endif /* !defined MINSPERHOUR */
492702Swollman
502702Swollman#ifndef SECSPERHOUR
512702Swollman#define SECSPERHOUR	(SECSPERMIN * MINSPERHOUR)
522702Swollman#endif /* !defined SECSPERHOUR */
532702Swollman
542702Swollman#ifndef HOURSPERDAY
552702Swollman#define HOURSPERDAY	24
562702Swollman#endif /* !defined HOURSPERDAY */
572702Swollman
582702Swollman#ifndef EPOCH_YEAR
592702Swollman#define EPOCH_YEAR	1970
602702Swollman#endif /* !defined EPOCH_YEAR */
612702Swollman
622702Swollman#ifndef TM_YEAR_BASE
632702Swollman#define TM_YEAR_BASE	1900
642702Swollman#endif /* !defined TM_YEAR_BASE */
652702Swollman
662702Swollman#ifndef DAYSPERNYEAR
672702Swollman#define DAYSPERNYEAR	365
682702Swollman#endif /* !defined DAYSPERNYEAR */
692702Swollman
702702Swollman#ifndef isleap
712702Swollman#define isleap(y) ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0)
722702Swollman#endif /* !defined isleap */
732702Swollman
7417214Swollman#if HAVE_GETTEXT - 0
7517214Swollman#include "locale.h"	/* for setlocale */
7617214Swollman#include "libintl.h"
7717214Swollman#endif /* HAVE_GETTEXT - 0 */
7817214Swollman
799937Swollman#ifndef GNUC_or_lint
809937Swollman#ifdef lint
819937Swollman#define GNUC_or_lint
829937Swollman#endif /* defined lint */
839937Swollman#ifndef lint
849937Swollman#ifdef __GNUC__
859937Swollman#define GNUC_or_lint
869937Swollman#endif /* defined __GNUC__ */
879937Swollman#endif /* !defined lint */
889937Swollman#endif /* !defined GNUC_or_lint */
899937Swollman
909937Swollman#ifndef INITIALIZE
919937Swollman#ifdef GNUC_or_lint
929937Swollman#define INITIALIZE(x)	((x) = 0)
939937Swollman#endif /* defined GNUC_or_lint */
949937Swollman#ifndef GNUC_or_lint
959937Swollman#define INITIALIZE(x)
969937Swollman#endif /* !defined GNUC_or_lint */
979937Swollman#endif /* !defined INITIALIZE */
989937Swollman
9917214Swollman/*
10017214Swollman** For the benefit of GNU folk...
10117214Swollman** `_(MSGID)' uses the current locale's message library string for MSGID.
10217214Swollman** The default is to use gettext if available, and use MSGID otherwise.
10317214Swollman*/
10417214Swollman
10517214Swollman#ifndef _
10617214Swollman#if HAVE_GETTEXT - 0
10717214Swollman#define _(msgid) gettext(msgid)
10817214Swollman#else /* !(HAVE_GETTEXT - 0) */
10917214Swollman#define _(msgid) msgid
11017214Swollman#endif /* !(HAVE_GETTEXT - 0) */
11117214Swollman#endif /* !defined _ */
11217214Swollman
11317214Swollman#ifndef TZ_DOMAIN
11417214Swollman#define TZ_DOMAIN "tz"
11517214Swollman#endif /* !defined TZ_DOMAIN */
11617214Swollman
11742997Swollman#ifndef P
11842997Swollman#ifdef __STDC__
11942997Swollman#define P(x)	x
12042997Swollman#endif /* defined __STDC__ */
12142997Swollman#ifndef __STDC__
12242997Swollman#define P(x)	()
12342997Swollman#endif /* !defined __STDC__ */
12442997Swollman#endif /* !defined P */
12542997Swollman
1262702Swollmanextern char **	environ;
1272702Swollmanextern char *	tzname[2];
1282702Swollman
12942997Swollmanstatic char *	abbr P((struct tm * tmp));
13042997Swollmanstatic long	delta P((struct tm * newp, struct tm * oldp));
13142997Swollmanstatic time_t	hunt P((char * name, time_t lot, time_t	hit));
13242997Swollmanstatic size_t	longest;
13342997Swollmanstatic void	show P((char * zone, time_t t, int v));
13444233Seivindstatic void     usage(void);
1352702Swollman
1362702Swollmanint
1372702Swollmanmain(argc, argv)
1382702Swollmanint	argc;
1392702Swollmanchar *	argv[];
1402702Swollman{
1419937Swollman	register int		i;
1429937Swollman	register int		c;
1439937Swollman	register int		vflag;
1449937Swollman	register char *		cutoff;
1459937Swollman	register int		cutyear;
1469937Swollman	register long		cuttime;
1479937Swollman	char **			fakeenv;
1489937Swollman	time_t			now;
1499937Swollman	time_t			t;
1509937Swollman	time_t			newt;
1519937Swollman	time_t			hibit;
1529937Swollman	struct tm		tm;
1539937Swollman	struct tm		newtm;
1542702Swollman
1559937Swollman	INITIALIZE(cuttime);
15617214Swollman#if HAVE_GETTEXT - 0
15717214Swollman	(void) setlocale(LC_MESSAGES, "");
15817214Swollman#ifdef TZ_DOMAINDIR
15917214Swollman	(void) bindtextdomain(TZ_DOMAIN, TZ_DOMAINDIR);
16017214Swollman#endif /* defined(TEXTDOMAINDIR) */
16117214Swollman	(void) textdomain(TZ_DOMAIN);
16217214Swollman#endif /* HAVE_GETTEXT - 0 */
163130819Sstefanf	for (i = 1; i < argc; ++i)
164130819Sstefanf		if (strcmp(argv[i], "--version") == 0) {
165130819Sstefanf			errx(EXIT_SUCCESS, "%s", elsieid);
166130819Sstefanf		}
1672702Swollman	vflag = 0;
1682702Swollman	cutoff = NULL;
1692702Swollman	while ((c = getopt(argc, argv, "c:v")) == 'c' || c == 'v')
1702702Swollman		if (c == 'v')
1712702Swollman			vflag = 1;
1722702Swollman		else	cutoff = optarg;
173176407Sru	if ((c != -1) ||
1742702Swollman		(optind == argc - 1 && strcmp(argv[optind], "=") == 0)) {
17530829Scharnier			usage();
1762702Swollman	}
1772702Swollman	if (cutoff != NULL) {
1782702Swollman		int	y;
1792702Swollman
1802702Swollman		cutyear = atoi(cutoff);
1812702Swollman		cuttime = 0;
1822702Swollman		for (y = EPOCH_YEAR; y < cutyear; ++y)
1832702Swollman			cuttime += DAYSPERNYEAR + isleap(y);
1842702Swollman		cuttime *= SECSPERHOUR * HOURSPERDAY;
1852702Swollman	}
1862702Swollman	(void) time(&now);
1872702Swollman	longest = 0;
1882702Swollman	for (i = optind; i < argc; ++i)
1892702Swollman		if (strlen(argv[i]) > longest)
1902702Swollman			longest = strlen(argv[i]);
1912702Swollman	for (hibit = 1; (hibit << 1) != 0; hibit <<= 1)
1922702Swollman		continue;
1939937Swollman	{
1949937Swollman		register int	from;
1959937Swollman		register int	to;
1962702Swollman
1979937Swollman		for (i = 0;  environ[i] != NULL;  ++i)
1989937Swollman			continue;
1999937Swollman		fakeenv = (char **) malloc((size_t) ((i + 2) *
2009937Swollman			sizeof *fakeenv));
2019937Swollman		if (fakeenv == NULL ||
2029937Swollman			(fakeenv[0] = (char *) malloc((size_t) (longest +
20330829Scharnier				4))) == NULL)
20430829Scharnier					errx(EXIT_FAILURE,
20530829Scharnier					     _("malloc() failed"));
2069937Swollman		to = 0;
2079937Swollman		(void) strcpy(fakeenv[to++], "TZ=");
2089937Swollman		for (from = 0; environ[from] != NULL; ++from)
2099937Swollman			if (strncmp(environ[from], "TZ=", 3) != 0)
2109937Swollman				fakeenv[to++] = environ[from];
2119937Swollman		fakeenv[to] = NULL;
2122702Swollman		environ = fakeenv;
2139937Swollman	}
2149937Swollman	for (i = optind; i < argc; ++i) {
2159937Swollman		static char	buf[MAX_STRING_LENGTH];
2169937Swollman
2179937Swollman		(void) strcpy(&fakeenv[0][3], argv[i]);
21817214Swollman		if (!vflag) {
21917214Swollman			show(argv[i], now, FALSE);
2202702Swollman			continue;
22117214Swollman		}
2222702Swollman		/*
2232702Swollman		** Get lowest value of t.
2242702Swollman		*/
2252702Swollman		t = hibit;
2262702Swollman		if (t > 0)		/* time_t is unsigned */
2272702Swollman			t = 0;
2282702Swollman		show(argv[i], t, TRUE);
2292702Swollman		t += SECSPERHOUR * HOURSPERDAY;
2302702Swollman		show(argv[i], t, TRUE);
2312702Swollman		tm = *localtime(&t);
2322702Swollman		(void) strncpy(buf, abbr(&tm), (sizeof buf) - 1);
2332702Swollman		for ( ; ; ) {
2342702Swollman			if (cutoff != NULL && t >= cuttime)
2352702Swollman				break;
2362702Swollman			newt = t + SECSPERHOUR * 12;
2372702Swollman			if (cutoff != NULL && newt >= cuttime)
2382702Swollman				break;
2392702Swollman			if (newt <= t)
2402702Swollman				break;
2412702Swollman			newtm = *localtime(&newt);
2422702Swollman			if (delta(&newtm, &tm) != (newt - t) ||
2432702Swollman				newtm.tm_isdst != tm.tm_isdst ||
2442702Swollman				strcmp(abbr(&newtm), buf) != 0) {
2452702Swollman					newt = hunt(argv[i], t, newt);
2462702Swollman					newtm = *localtime(&newt);
2472702Swollman					(void) strncpy(buf, abbr(&newtm),
2482702Swollman						(sizeof buf) - 1);
2492702Swollman			}
2502702Swollman			t = newt;
2512702Swollman			tm = newtm;
2522702Swollman		}
2532702Swollman		/*
2542702Swollman		** Get highest value of t.
2552702Swollman		*/
2562702Swollman		t = ~((time_t) 0);
2572702Swollman		if (t < 0)		/* time_t is signed */
2582702Swollman			t &= ~hibit;
2592702Swollman		t -= SECSPERHOUR * HOURSPERDAY;
2602702Swollman		show(argv[i], t, TRUE);
2612702Swollman		t += SECSPERHOUR * HOURSPERDAY;
2622702Swollman		show(argv[i], t, TRUE);
2632702Swollman	}
26430829Scharnier	if (fflush(stdout) || ferror(stdout))
26530829Scharnier		errx(EXIT_FAILURE, _("error writing standard output"));
2662702Swollman	exit(EXIT_SUCCESS);
2672702Swollman
2682702Swollman	/* gcc -Wall pacifier */
2692702Swollman	for ( ; ; )
2702702Swollman		continue;
2712702Swollman}
2722702Swollman
27330829Scharnierstatic void
27444233Seivindusage(void)
27530829Scharnier{
276130819Sstefanf	fprintf(stderr,
277130819Sstefanf_("usage: zdump [--version] [-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