zdump.c revision 42997
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	"$Id: zdump.c,v 1.5 1999/01/21 17:12:49 wollman Exp $";
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));
139
140int
141main(argc, argv)
142int	argc;
143char *	argv[];
144{
145	register int		i;
146	register int		c;
147	register int		vflag;
148	register char *		cutoff;
149	register int		cutyear;
150	register long		cuttime;
151	char **			fakeenv;
152	time_t			now;
153	time_t			t;
154	time_t			newt;
155	time_t			hibit;
156	struct tm		tm;
157	struct tm		newtm;
158
159	INITIALIZE(cuttime);
160#if HAVE_GETTEXT - 0
161	(void) setlocale(LC_MESSAGES, "");
162#ifdef TZ_DOMAINDIR
163	(void) bindtextdomain(TZ_DOMAIN, TZ_DOMAINDIR);
164#endif /* defined(TEXTDOMAINDIR) */
165	(void) textdomain(TZ_DOMAIN);
166#endif /* HAVE_GETTEXT - 0 */
167	vflag = 0;
168	cutoff = NULL;
169	while ((c = getopt(argc, argv, "c:v")) == 'c' || c == 'v')
170		if (c == 'v')
171			vflag = 1;
172		else	cutoff = optarg;
173	if ((c != EOF && c != -1) ||
174		(optind == argc - 1 && strcmp(argv[optind], "=") == 0)) {
175			usage();
176	}
177	if (cutoff != NULL) {
178		int	y;
179
180		cutyear = atoi(cutoff);
181		cuttime = 0;
182		for (y = EPOCH_YEAR; y < cutyear; ++y)
183			cuttime += DAYSPERNYEAR + isleap(y);
184		cuttime *= SECSPERHOUR * HOURSPERDAY;
185	}
186	(void) time(&now);
187	longest = 0;
188	for (i = optind; i < argc; ++i)
189		if (strlen(argv[i]) > longest)
190			longest = strlen(argv[i]);
191	for (hibit = 1; (hibit << 1) != 0; hibit <<= 1)
192		continue;
193	{
194		register int	from;
195		register int	to;
196
197		for (i = 0;  environ[i] != NULL;  ++i)
198			continue;
199		fakeenv = (char **) malloc((size_t) ((i + 2) *
200			sizeof *fakeenv));
201		if (fakeenv == NULL ||
202			(fakeenv[0] = (char *) malloc((size_t) (longest +
203				4))) == NULL)
204					errx(EXIT_FAILURE,
205					     _("malloc() failed"));
206		to = 0;
207		(void) strcpy(fakeenv[to++], "TZ=");
208		for (from = 0; environ[from] != NULL; ++from)
209			if (strncmp(environ[from], "TZ=", 3) != 0)
210				fakeenv[to++] = environ[from];
211		fakeenv[to] = NULL;
212		environ = fakeenv;
213	}
214	for (i = optind; i < argc; ++i) {
215		static char	buf[MAX_STRING_LENGTH];
216
217		(void) strcpy(&fakeenv[0][3], argv[i]);
218		if (!vflag) {
219			show(argv[i], now, FALSE);
220			continue;
221		}
222		/*
223		** Get lowest value of t.
224		*/
225		t = hibit;
226		if (t > 0)		/* time_t is unsigned */
227			t = 0;
228		show(argv[i], t, TRUE);
229		t += SECSPERHOUR * HOURSPERDAY;
230		show(argv[i], t, TRUE);
231		tm = *localtime(&t);
232		(void) strncpy(buf, abbr(&tm), (sizeof buf) - 1);
233		for ( ; ; ) {
234			if (cutoff != NULL && t >= cuttime)
235				break;
236			newt = t + SECSPERHOUR * 12;
237			if (cutoff != NULL && newt >= cuttime)
238				break;
239			if (newt <= t)
240				break;
241			newtm = *localtime(&newt);
242			if (delta(&newtm, &tm) != (newt - t) ||
243				newtm.tm_isdst != tm.tm_isdst ||
244				strcmp(abbr(&newtm), buf) != 0) {
245					newt = hunt(argv[i], t, newt);
246					newtm = *localtime(&newt);
247					(void) strncpy(buf, abbr(&newtm),
248						(sizeof buf) - 1);
249			}
250			t = newt;
251			tm = newtm;
252		}
253		/*
254		** Get highest value of t.
255		*/
256		t = ~((time_t) 0);
257		if (t < 0)		/* time_t is signed */
258			t &= ~hibit;
259		t -= SECSPERHOUR * HOURSPERDAY;
260		show(argv[i], t, TRUE);
261		t += SECSPERHOUR * HOURSPERDAY;
262		show(argv[i], t, TRUE);
263	}
264	if (fflush(stdout) || ferror(stdout))
265		errx(EXIT_FAILURE, _("error writing standard output"));
266	exit(EXIT_SUCCESS);
267
268	/* gcc -Wall pacifier */
269	for ( ; ; )
270		continue;
271}
272
273static void
274usage()
275{
276	fprintf(stderr, _("usage: zdump [-v] [-c cutoff] zonename ...\n"));
277	exit(EXIT_FAILURE);
278}
279
280static time_t
281hunt(name, lot, hit)
282char *	name;
283time_t	lot;
284time_t	hit;
285{
286	time_t		t;
287	struct tm	lotm;
288	struct tm	tm;
289	static char	loab[MAX_STRING_LENGTH];
290
291	lotm = *localtime(&lot);
292	(void) strncpy(loab, abbr(&lotm), (sizeof loab) - 1);
293	while ((hit - lot) >= 2) {
294		t = lot / 2 + hit / 2;
295		if (t <= lot)
296			++t;
297		else if (t >= hit)
298			--t;
299		tm = *localtime(&t);
300		if (delta(&tm, &lotm) == (t - lot) &&
301			tm.tm_isdst == lotm.tm_isdst &&
302			strcmp(abbr(&tm), loab) == 0) {
303				lot = t;
304				lotm = tm;
305		} else	hit = t;
306	}
307	show(name, lot, TRUE);
308	show(name, hit, TRUE);
309	return hit;
310}
311
312/*
313** Thanks to Paul Eggert (eggert@twinsun.com) for logic used in delta.
314*/
315
316static long
317delta(newp, oldp)
318struct tm *	newp;
319struct tm *	oldp;
320{
321	long	result;
322	int	tmy;
323
324	if (newp->tm_year < oldp->tm_year)
325		return -delta(oldp, newp);
326	result = 0;
327	for (tmy = oldp->tm_year; tmy < newp->tm_year; ++tmy)
328		result += DAYSPERNYEAR + isleap(tmy + TM_YEAR_BASE);
329	result += newp->tm_yday - oldp->tm_yday;
330	result *= HOURSPERDAY;
331	result += newp->tm_hour - oldp->tm_hour;
332	result *= MINSPERHOUR;
333	result += newp->tm_min - oldp->tm_min;
334	result *= SECSPERMIN;
335	result += newp->tm_sec - oldp->tm_sec;
336	return result;
337}
338
339static void
340show(zone, t, v)
341char *	zone;
342time_t	t;
343int	v;
344{
345	struct tm *	tmp;
346
347	(void) printf("%-*s  ", (int) longest, zone);
348	if (v)
349		(void) printf("%.24s UTC = ", asctime(gmtime(&t)));
350	tmp = localtime(&t);
351	(void) printf("%.24s", asctime(tmp));
352	if (*abbr(tmp) != '\0')
353		(void) printf(" %s", abbr(tmp));
354	if (v) {
355		(void) printf(" isdst=%d", tmp->tm_isdst);
356#ifdef TM_GMTOFF
357		(void) printf(" gmtoff=%ld", tmp->TM_GMTOFF);
358#endif /* defined TM_GMTOFF */
359	}
360	(void) printf("\n");
361}
362
363static char *
364abbr(tmp)
365struct tm *	tmp;
366{
367	register char *	result;
368	static char	nada;
369
370	if (tmp->tm_isdst != 0 && tmp->tm_isdst != 1)
371		return &nada;
372	result = tzname[tmp->tm_isdst];
373	return (result == NULL) ? &nada : result;
374}
375