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