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