zdump.c revision 50479
1#ifndef lint
2#ifndef NOID
3static char	elsieid[] = "@(#)zdump.c	7.28";
4#endif /* !defined NOID */
5#endif /* !defined lint */
6
7#ifndef lint
8static const char rcsid[] =
9  "$FreeBSD: head/usr.sbin/zic/zdump.c 50479 1999-08-28 01:35:59Z peter $";
10#endif /* not lint */
11
12/*
13** This code has been made independent of the rest of the time
14** conversion package to increase confidence in the verification it provides.
15** You can use this code to help in verifying other implementations.
16*/
17
18#include <err.h>
19#include <stdio.h>	/* for stdout, stderr */
20#include <stdlib.h>	/* for exit, malloc, atoi */
21#include <string.h>	/* for strcpy */
22#include <sys/types.h>	/* for time_t */
23#include <time.h>	/* for struct tm */
24#include <unistd.h>
25
26#ifndef MAX_STRING_LENGTH
27#define MAX_STRING_LENGTH	1024
28#endif /* !defined MAX_STRING_LENGTH */
29
30#ifndef TRUE
31#define TRUE		1
32#endif /* !defined TRUE */
33
34#ifndef FALSE
35#define FALSE		0
36#endif /* !defined FALSE */
37
38#ifndef EXIT_SUCCESS
39#define EXIT_SUCCESS	0
40#endif /* !defined EXIT_SUCCESS */
41
42#ifndef EXIT_FAILURE
43#define EXIT_FAILURE	1
44#endif /* !defined EXIT_FAILURE */
45
46#ifndef SECSPERMIN
47#define SECSPERMIN	60
48#endif /* !defined SECSPERMIN */
49
50#ifndef MINSPERHOUR
51#define MINSPERHOUR	60
52#endif /* !defined MINSPERHOUR */
53
54#ifndef SECSPERHOUR
55#define SECSPERHOUR	(SECSPERMIN * MINSPERHOUR)
56#endif /* !defined SECSPERHOUR */
57
58#ifndef HOURSPERDAY
59#define HOURSPERDAY	24
60#endif /* !defined HOURSPERDAY */
61
62#ifndef EPOCH_YEAR
63#define EPOCH_YEAR	1970
64#endif /* !defined EPOCH_YEAR */
65
66#ifndef TM_YEAR_BASE
67#define TM_YEAR_BASE	1900
68#endif /* !defined TM_YEAR_BASE */
69
70#ifndef DAYSPERNYEAR
71#define DAYSPERNYEAR	365
72#endif /* !defined DAYSPERNYEAR */
73
74#ifndef isleap
75#define isleap(y) ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0)
76#endif /* !defined isleap */
77
78#if HAVE_GETTEXT - 0
79#include "locale.h"	/* for setlocale */
80#include "libintl.h"
81#endif /* HAVE_GETTEXT - 0 */
82
83#ifndef GNUC_or_lint
84#ifdef lint
85#define GNUC_or_lint
86#endif /* defined lint */
87#ifndef lint
88#ifdef __GNUC__
89#define GNUC_or_lint
90#endif /* defined __GNUC__ */
91#endif /* !defined lint */
92#endif /* !defined GNUC_or_lint */
93
94#ifndef INITIALIZE
95#ifdef GNUC_or_lint
96#define INITIALIZE(x)	((x) = 0)
97#endif /* defined GNUC_or_lint */
98#ifndef GNUC_or_lint
99#define INITIALIZE(x)
100#endif /* !defined GNUC_or_lint */
101#endif /* !defined INITIALIZE */
102
103/*
104** For the benefit of GNU folk...
105** `_(MSGID)' uses the current locale's message library string for MSGID.
106** The default is to use gettext if available, and use MSGID otherwise.
107*/
108
109#ifndef _
110#if HAVE_GETTEXT - 0
111#define _(msgid) gettext(msgid)
112#else /* !(HAVE_GETTEXT - 0) */
113#define _(msgid) msgid
114#endif /* !(HAVE_GETTEXT - 0) */
115#endif /* !defined _ */
116
117#ifndef TZ_DOMAIN
118#define TZ_DOMAIN "tz"
119#endif /* !defined TZ_DOMAIN */
120
121#ifndef P
122#ifdef __STDC__
123#define P(x)	x
124#endif /* defined __STDC__ */
125#ifndef __STDC__
126#define P(x)	()
127#endif /* !defined __STDC__ */
128#endif /* !defined P */
129
130extern char **	environ;
131extern char *	tzname[2];
132
133static char *	abbr P((struct tm * tmp));
134static long	delta P((struct tm * newp, struct tm * oldp));
135static time_t	hunt P((char * name, time_t lot, time_t	hit));
136static size_t	longest;
137static char *	progname;
138static void	show P((char * zone, time_t t, int v));
139static void     usage(void);
140
141int
142main(argc, argv)
143int	argc;
144char *	argv[];
145{
146	register int		i;
147	register int		c;
148	register int		vflag;
149	register char *		cutoff;
150	register int		cutyear;
151	register long		cuttime;
152	char **			fakeenv;
153	time_t			now;
154	time_t			t;
155	time_t			newt;
156	time_t			hibit;
157	struct tm		tm;
158	struct tm		newtm;
159
160	INITIALIZE(cuttime);
161#if HAVE_GETTEXT - 0
162	(void) setlocale(LC_MESSAGES, "");
163#ifdef TZ_DOMAINDIR
164	(void) bindtextdomain(TZ_DOMAIN, TZ_DOMAINDIR);
165#endif /* defined(TEXTDOMAINDIR) */
166	(void) textdomain(TZ_DOMAIN);
167#endif /* HAVE_GETTEXT - 0 */
168	vflag = 0;
169	cutoff = NULL;
170	while ((c = getopt(argc, argv, "c:v")) == 'c' || c == 'v')
171		if (c == 'v')
172			vflag = 1;
173		else	cutoff = optarg;
174	if ((c != EOF && c != -1) ||
175		(optind == argc - 1 && strcmp(argv[optind], "=") == 0)) {
176			usage();
177	}
178	if (cutoff != NULL) {
179		int	y;
180
181		cutyear = atoi(cutoff);
182		cuttime = 0;
183		for (y = EPOCH_YEAR; y < cutyear; ++y)
184			cuttime += DAYSPERNYEAR + isleap(y);
185		cuttime *= SECSPERHOUR * HOURSPERDAY;
186	}
187	(void) time(&now);
188	longest = 0;
189	for (i = optind; i < argc; ++i)
190		if (strlen(argv[i]) > longest)
191			longest = strlen(argv[i]);
192	for (hibit = 1; (hibit << 1) != 0; hibit <<= 1)
193		continue;
194	{
195		register int	from;
196		register int	to;
197
198		for (i = 0;  environ[i] != NULL;  ++i)
199			continue;
200		fakeenv = (char **) malloc((size_t) ((i + 2) *
201			sizeof *fakeenv));
202		if (fakeenv == NULL ||
203			(fakeenv[0] = (char *) malloc((size_t) (longest +
204				4))) == NULL)
205					errx(EXIT_FAILURE,
206					     _("malloc() failed"));
207		to = 0;
208		(void) strcpy(fakeenv[to++], "TZ=");
209		for (from = 0; environ[from] != NULL; ++from)
210			if (strncmp(environ[from], "TZ=", 3) != 0)
211				fakeenv[to++] = environ[from];
212		fakeenv[to] = NULL;
213		environ = fakeenv;
214	}
215	for (i = optind; i < argc; ++i) {
216		static char	buf[MAX_STRING_LENGTH];
217
218		(void) strcpy(&fakeenv[0][3], argv[i]);
219		if (!vflag) {
220			show(argv[i], now, FALSE);
221			continue;
222		}
223		/*
224		** Get lowest value of t.
225		*/
226		t = hibit;
227		if (t > 0)		/* time_t is unsigned */
228			t = 0;
229		show(argv[i], t, TRUE);
230		t += SECSPERHOUR * HOURSPERDAY;
231		show(argv[i], t, TRUE);
232		tm = *localtime(&t);
233		(void) strncpy(buf, abbr(&tm), (sizeof buf) - 1);
234		for ( ; ; ) {
235			if (cutoff != NULL && t >= cuttime)
236				break;
237			newt = t + SECSPERHOUR * 12;
238			if (cutoff != NULL && newt >= cuttime)
239				break;
240			if (newt <= t)
241				break;
242			newtm = *localtime(&newt);
243			if (delta(&newtm, &tm) != (newt - t) ||
244				newtm.tm_isdst != tm.tm_isdst ||
245				strcmp(abbr(&newtm), buf) != 0) {
246					newt = hunt(argv[i], t, newt);
247					newtm = *localtime(&newt);
248					(void) strncpy(buf, abbr(&newtm),
249						(sizeof buf) - 1);
250			}
251			t = newt;
252			tm = newtm;
253		}
254		/*
255		** Get highest value of t.
256		*/
257		t = ~((time_t) 0);
258		if (t < 0)		/* time_t is signed */
259			t &= ~hibit;
260		t -= SECSPERHOUR * HOURSPERDAY;
261		show(argv[i], t, TRUE);
262		t += SECSPERHOUR * HOURSPERDAY;
263		show(argv[i], t, TRUE);
264	}
265	if (fflush(stdout) || ferror(stdout))
266		errx(EXIT_FAILURE, _("error writing standard output"));
267	exit(EXIT_SUCCESS);
268
269	/* gcc -Wall pacifier */
270	for ( ; ; )
271		continue;
272}
273
274static void
275usage(void)
276{
277	fprintf(stderr, _("usage: zdump [-v] [-c cutoff] zonename ...\n"));
278	exit(EXIT_FAILURE);
279}
280
281static time_t
282hunt(name, lot, hit)
283char *	name;
284time_t	lot;
285time_t	hit;
286{
287	time_t		t;
288	struct tm	lotm;
289	struct tm	tm;
290	static char	loab[MAX_STRING_LENGTH];
291
292	lotm = *localtime(&lot);
293	(void) strncpy(loab, abbr(&lotm), (sizeof loab) - 1);
294	while ((hit - lot) >= 2) {
295		t = lot / 2 + hit / 2;
296		if (t <= lot)
297			++t;
298		else if (t >= hit)
299			--t;
300		tm = *localtime(&t);
301		if (delta(&tm, &lotm) == (t - lot) &&
302			tm.tm_isdst == lotm.tm_isdst &&
303			strcmp(abbr(&tm), loab) == 0) {
304				lot = t;
305				lotm = tm;
306		} else	hit = t;
307	}
308	show(name, lot, TRUE);
309	show(name, hit, TRUE);
310	return hit;
311}
312
313/*
314** Thanks to Paul Eggert (eggert@twinsun.com) for logic used in delta.
315*/
316
317static long
318delta(newp, oldp)
319struct tm *	newp;
320struct tm *	oldp;
321{
322	long	result;
323	int	tmy;
324
325	if (newp->tm_year < oldp->tm_year)
326		return -delta(oldp, newp);
327	result = 0;
328	for (tmy = oldp->tm_year; tmy < newp->tm_year; ++tmy)
329		result += DAYSPERNYEAR + isleap(tmy + TM_YEAR_BASE);
330	result += newp->tm_yday - oldp->tm_yday;
331	result *= HOURSPERDAY;
332	result += newp->tm_hour - oldp->tm_hour;
333	result *= MINSPERHOUR;
334	result += newp->tm_min - oldp->tm_min;
335	result *= SECSPERMIN;
336	result += newp->tm_sec - oldp->tm_sec;
337	return result;
338}
339
340static void
341show(zone, t, v)
342char *	zone;
343time_t	t;
344int	v;
345{
346	struct tm *	tmp;
347
348	(void) printf("%-*s  ", (int) longest, zone);
349	if (v)
350		(void) printf("%.24s UTC = ", asctime(gmtime(&t)));
351	tmp = localtime(&t);
352	(void) printf("%.24s", asctime(tmp));
353	if (*abbr(tmp) != '\0')
354		(void) printf(" %s", abbr(tmp));
355	if (v) {
356		(void) printf(" isdst=%d", tmp->tm_isdst);
357#ifdef TM_GMTOFF
358		(void) printf(" gmtoff=%ld", tmp->TM_GMTOFF);
359#endif /* defined TM_GMTOFF */
360	}
361	(void) printf("\n");
362}
363
364static char *
365abbr(tmp)
366struct tm *	tmp;
367{
368	register char *	result;
369	static char	nada;
370
371	if (tmp->tm_isdst != 0 && tmp->tm_isdst != 1)
372		return &nada;
373	result = tzname[tmp->tm_isdst];
374	return (result == NULL) ? &nada : result;
375}
376