xref: /titanic_53/usr/src/cmd/zdump/zdump.c (revision 80868c5387b92f32fe0e8ea709e36cb535287e03)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
57c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate  * with the License.
87c478bd9Sstevel@tonic-gate  *
97c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate  * and limitations under the License.
137c478bd9Sstevel@tonic-gate  *
147c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate  *
207c478bd9Sstevel@tonic-gate  * CDDL HEADER END
217c478bd9Sstevel@tonic-gate  */
227c478bd9Sstevel@tonic-gate /*
23*80868c53Srobbin  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
27*80868c53Srobbin #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*80868c53Srobbin 
297c478bd9Sstevel@tonic-gate /*
307c478bd9Sstevel@tonic-gate  * zdump 7.24
317c478bd9Sstevel@tonic-gate  * Taken from elsie.nci.nih.gov to replace the existing Solaris zdump,
327c478bd9Sstevel@tonic-gate  * which was based on an earlier version of the elsie code.
337c478bd9Sstevel@tonic-gate  *
347c478bd9Sstevel@tonic-gate  * For zdump 7.24, the following changes were made to the elsie code:
357c478bd9Sstevel@tonic-gate  *   locale/textdomain/messages to match existing Solaris style.
367c478bd9Sstevel@tonic-gate  *   Solaris verbose mode is documented to display the current time first.
377c478bd9Sstevel@tonic-gate  *   cstyle cleaned code.
387c478bd9Sstevel@tonic-gate  *   removed old locale/textdomain code.
397c478bd9Sstevel@tonic-gate  */
407c478bd9Sstevel@tonic-gate 
41*80868c53Srobbin static char	elsieid[] = "@(#)zdump.c	7.68";
427c478bd9Sstevel@tonic-gate 
437c478bd9Sstevel@tonic-gate /*
447c478bd9Sstevel@tonic-gate  * This code has been made independent of the rest of the time
457c478bd9Sstevel@tonic-gate  * conversion package to increase confidence in the verification it provides.
467c478bd9Sstevel@tonic-gate  * You can use this code to help in verifying other implementations.
477c478bd9Sstevel@tonic-gate  */
487c478bd9Sstevel@tonic-gate 
497c478bd9Sstevel@tonic-gate #include "stdio.h"	/* for stdout, stderr, perror */
507c478bd9Sstevel@tonic-gate #include "string.h"	/* for strcpy */
517c478bd9Sstevel@tonic-gate #include "sys/types.h"	/* for time_t */
527c478bd9Sstevel@tonic-gate #include "time.h"	/* for struct tm */
537c478bd9Sstevel@tonic-gate #include "stdlib.h"	/* for exit, malloc, atoi */
547c478bd9Sstevel@tonic-gate #include "locale.h"	/* for setlocale, textdomain */
557c478bd9Sstevel@tonic-gate #include "libintl.h"
56*80868c53Srobbin #include <ctype.h>
577c478bd9Sstevel@tonic-gate #include "tzfile.h"	/* for defines */
58*80868c53Srobbin #include <limits.h>
59*80868c53Srobbin 
60*80868c53Srobbin #ifndef ZDUMP_LO_YEAR
61*80868c53Srobbin #define	ZDUMP_LO_YEAR	(-500)
62*80868c53Srobbin #endif /* !defined ZDUMP_LO_YEAR */
63*80868c53Srobbin 
64*80868c53Srobbin #ifndef ZDUMP_HI_YEAR
65*80868c53Srobbin #define	ZDUMP_HI_YEAR	2500
66*80868c53Srobbin #endif /* !defined ZDUMP_HI_YEAR */
677c478bd9Sstevel@tonic-gate 
687c478bd9Sstevel@tonic-gate #ifndef MAX_STRING_LENGTH
697c478bd9Sstevel@tonic-gate #define	MAX_STRING_LENGTH	1024
707c478bd9Sstevel@tonic-gate #endif /* !defined MAX_STRING_LENGTH */
717c478bd9Sstevel@tonic-gate 
727c478bd9Sstevel@tonic-gate #ifndef TRUE
737c478bd9Sstevel@tonic-gate #define	TRUE		1
747c478bd9Sstevel@tonic-gate #endif /* !defined TRUE */
757c478bd9Sstevel@tonic-gate 
767c478bd9Sstevel@tonic-gate #ifndef FALSE
777c478bd9Sstevel@tonic-gate #define	FALSE		0
787c478bd9Sstevel@tonic-gate #endif /* !defined FALSE */
797c478bd9Sstevel@tonic-gate 
80*80868c53Srobbin #ifndef isleap_sum
81*80868c53Srobbin /*
82*80868c53Srobbin  * See tzfile.h for details on isleap_sum.
83*80868c53Srobbin  */
84*80868c53Srobbin #define	isleap_sum(a, b)	isleap((a) % 400 + (b) % 400)
85*80868c53Srobbin #endif /* !defined isleap_sum */
86*80868c53Srobbin 
87*80868c53Srobbin #ifndef SECSPERDAY
88*80868c53Srobbin #define	SECSPERDAY	((long)SECSPERHOUR * HOURSPERDAY)
89*80868c53Srobbin #endif
90*80868c53Srobbin #define	SECSPERNYEAR	(SECSPERDAY * DAYSPERNYEAR)
91*80868c53Srobbin #define	SECSPERLYEAR	(SECSPERNYEAR + SECSPERDAY)
92*80868c53Srobbin 
93*80868c53Srobbin #ifndef GNUC_or_lint
947c478bd9Sstevel@tonic-gate #ifdef lint
95*80868c53Srobbin #define	GNUC_or_lint
96*80868c53Srobbin #else /* !defined lint */
97*80868c53Srobbin #ifdef __GNUC__
98*80868c53Srobbin #define	GNUC_or_lint
99*80868c53Srobbin #endif /* defined __GNUC__ */
1007c478bd9Sstevel@tonic-gate #endif /* !defined lint */
101*80868c53Srobbin #endif /* !defined GNUC_or_lint */
102*80868c53Srobbin 
103*80868c53Srobbin #ifndef INITIALIZE
104*80868c53Srobbin #ifdef	GNUC_or_lint
105*80868c53Srobbin #define	INITIALIZE(x)	((x) = 0)
106*80868c53Srobbin #else /* !defined GNUC_or_lint */
107*80868c53Srobbin #define	INITIALIZE(x)
108*80868c53Srobbin #endif /* !defined GNUC_or_lint */
1097c478bd9Sstevel@tonic-gate #endif /* !defined INITIALIZE */
1107c478bd9Sstevel@tonic-gate 
111*80868c53Srobbin static time_t	absolute_min_time;
112*80868c53Srobbin static time_t	absolute_max_time;
1137c478bd9Sstevel@tonic-gate static size_t	longest;
1147c478bd9Sstevel@tonic-gate static char	*progname;
115*80868c53Srobbin static int	warned;
116*80868c53Srobbin 
117*80868c53Srobbin static char	*abbr(struct tm *);
118*80868c53Srobbin static void	abbrok(const char *, const char *);
119*80868c53Srobbin static long	delta(struct tm *, struct tm *);
120*80868c53Srobbin static void	dumptime(const struct tm *);
121*80868c53Srobbin static time_t	hunt(char *, time_t, time_t);
122*80868c53Srobbin static void	setabsolutes(void);
1237c478bd9Sstevel@tonic-gate static void	show(char *, time_t, int);
124*80868c53Srobbin static void	usage(void);
125*80868c53Srobbin static const char	*tformat(void);
126*80868c53Srobbin static time_t	yeartot(long y);
127*80868c53Srobbin 
128*80868c53Srobbin #ifndef TYPECHECK
129*80868c53Srobbin #define	my_localtime	localtime
130*80868c53Srobbin #else /* !defined TYPECHECK */
131*80868c53Srobbin static struct tm *
132*80868c53Srobbin my_localtime(tp)
133*80868c53Srobbin time_t *tp;
134*80868c53Srobbin {
135*80868c53Srobbin 	register struct tm *tmp;
136*80868c53Srobbin 
137*80868c53Srobbin 	tmp = localtime(tp);
138*80868c53Srobbin 	if (tp != NULL && tmp != NULL) {
139*80868c53Srobbin 		struct tm	tm;
140*80868c53Srobbin 		register time_t	t;
141*80868c53Srobbin 
142*80868c53Srobbin 		tm = *tmp;
143*80868c53Srobbin 		t = mktime(&tm);
144*80868c53Srobbin 		if (t - *tp >= 1 || *tp - t >= 1) {
145*80868c53Srobbin 			(void) fflush(stdout);
146*80868c53Srobbin 			(void) fprintf(stderr, "\n%s: ", progname);
147*80868c53Srobbin 			(void) fprintf(stderr, tformat(), *tp);
148*80868c53Srobbin 			(void) fprintf(stderr, " ->");
149*80868c53Srobbin 			(void) fprintf(stderr, " year=%d", tmp->tm_year);
150*80868c53Srobbin 			(void) fprintf(stderr, " mon=%d", tmp->tm_mon);
151*80868c53Srobbin 			(void) fprintf(stderr, " mday=%d", tmp->tm_mday);
152*80868c53Srobbin 			(void) fprintf(stderr, " hour=%d", tmp->tm_hour);
153*80868c53Srobbin 			(void) fprintf(stderr, " min=%d", tmp->tm_min);
154*80868c53Srobbin 			(void) fprintf(stderr, " sec=%d", tmp->tm_sec);
155*80868c53Srobbin 			(void) fprintf(stderr, " isdst=%d", tmp->tm_isdst);
156*80868c53Srobbin 			(void) fprintf(stderr, " -> ");
157*80868c53Srobbin 			(void) fprintf(stderr, tformat(), t);
158*80868c53Srobbin 			(void) fprintf(stderr, "\n");
159*80868c53Srobbin 		}
160*80868c53Srobbin 	}
161*80868c53Srobbin 	return (tmp);
162*80868c53Srobbin }
163*80868c53Srobbin #endif /* !defined TYPECHECK */
164*80868c53Srobbin 
165*80868c53Srobbin static void
166*80868c53Srobbin abbrok(abbrp, zone)
167*80868c53Srobbin const char * const	abbrp;
168*80868c53Srobbin const char * const	zone;
169*80868c53Srobbin {
170*80868c53Srobbin 	register const char *cp;
171*80868c53Srobbin 	int error = 0;
172*80868c53Srobbin 
173*80868c53Srobbin 	if (warned)
174*80868c53Srobbin 		return;
175*80868c53Srobbin 	cp = abbrp;
176*80868c53Srobbin 	while (isascii(*cp) && isalpha((unsigned char)*cp))
177*80868c53Srobbin 		++cp;
178*80868c53Srobbin 	(void) fflush(stdout);
179*80868c53Srobbin 	if (cp - abbrp == 0) {
180*80868c53Srobbin 		/*
181*80868c53Srobbin 		 * TRANSLATION_NOTE
182*80868c53Srobbin 		 * The first %s prints for the program name (zdump),
183*80868c53Srobbin 		 * the second %s prints the timezone name, the third
184*80868c53Srobbin 		 * %s prints the timezone abbreviation (tzname[0] or
185*80868c53Srobbin 		 * tzname[1]).
186*80868c53Srobbin 		 */
187*80868c53Srobbin 		(void) fprintf(stderr, gettext("%s: warning: zone \"%s\" "
188*80868c53Srobbin 		    "abbreviation \"%s\" lacks alphabetic at start\n"),
189*80868c53Srobbin 		    progname, zone, abbrp);
190*80868c53Srobbin 		error = 1;
191*80868c53Srobbin 	} else if (cp - abbrp < 3) {
192*80868c53Srobbin 		(void) fprintf(stderr, gettext("%s: warning: zone \"%s\" "
193*80868c53Srobbin 		    "abbreviation \"%s\" has fewer than 3 alphabetics\n"),
194*80868c53Srobbin 		    progname, zone, abbrp);
195*80868c53Srobbin 		error = 1;
196*80868c53Srobbin 	} else if (cp - abbrp > 6) {
197*80868c53Srobbin 		(void) fprintf(stderr, gettext("%s: warning: zone \"%s\" "
198*80868c53Srobbin 		    "abbreviation \"%s\" has more than 6 alphabetics\n"),
199*80868c53Srobbin 		    progname, zone, abbrp);
200*80868c53Srobbin 		error = 1;
201*80868c53Srobbin 	}
202*80868c53Srobbin 	if (error == 0 && (*cp == '+' || *cp == '-')) {
203*80868c53Srobbin 		++cp;
204*80868c53Srobbin 		if (isascii(*cp) && isdigit((unsigned char)*cp))
205*80868c53Srobbin 			if (*cp++ == '1' && *cp >= '0' && *cp <= '4')
206*80868c53Srobbin 				++cp;
207*80868c53Srobbin 	}
208*80868c53Srobbin 	if (error == 0 && *cp != '\0') {
209*80868c53Srobbin 		(void) fprintf(stderr, gettext("%s: warning: zone \"%s\" "
210*80868c53Srobbin 		    "abbreviation \"%s\" differs from POSIX standard\n"),
211*80868c53Srobbin 		    progname, zone, abbrp);
212*80868c53Srobbin 		error = 1;
213*80868c53Srobbin 	}
214*80868c53Srobbin 	if (error)
215*80868c53Srobbin 		warned = TRUE;
216*80868c53Srobbin }
2177c478bd9Sstevel@tonic-gate 
2187c478bd9Sstevel@tonic-gate int
2197c478bd9Sstevel@tonic-gate main(argc, argv)
2207c478bd9Sstevel@tonic-gate int	argc;
2217c478bd9Sstevel@tonic-gate char	*argv[];
2227c478bd9Sstevel@tonic-gate {
2237c478bd9Sstevel@tonic-gate 	register int		i;
2247c478bd9Sstevel@tonic-gate 	register int		c;
2257c478bd9Sstevel@tonic-gate 	register int		vflag;
226*80868c53Srobbin 	register char		*cutarg;
227*80868c53Srobbin 	register long		cutloyear = ZDUMP_LO_YEAR;
228*80868c53Srobbin 	register long		cuthiyear = ZDUMP_HI_YEAR;
229*80868c53Srobbin 	register time_t		cutlotime;
230*80868c53Srobbin 	register time_t		cuthitime;
2317c478bd9Sstevel@tonic-gate 	time_t			now;
2327c478bd9Sstevel@tonic-gate 	time_t			t;
2337c478bd9Sstevel@tonic-gate 	time_t			newt;
2347c478bd9Sstevel@tonic-gate 	struct tm		tm;
2357c478bd9Sstevel@tonic-gate 	struct tm		newtm;
236*80868c53Srobbin 	register struct tm	*tmp;
237*80868c53Srobbin 	register struct tm	*newtmp;
2387c478bd9Sstevel@tonic-gate 
239*80868c53Srobbin 	INITIALIZE(cutlotime);
240*80868c53Srobbin 	INITIALIZE(cuthitime);
2417c478bd9Sstevel@tonic-gate 
2427c478bd9Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
2437c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)		/* Should be defined by cc -D */
2447c478bd9Sstevel@tonic-gate #define	TEXT_DOMAIN	"SYS_TEST"	/* Use this only if it weren't */
2457c478bd9Sstevel@tonic-gate #endif
2467c478bd9Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
2477c478bd9Sstevel@tonic-gate 
2487c478bd9Sstevel@tonic-gate 	progname = argv[0];
249*80868c53Srobbin 	for (i = 1; i < argc; ++i)
250*80868c53Srobbin 		if (strcmp(argv[i], "--version") == 0) {
251*80868c53Srobbin 			(void) printf("%s\n", elsieid);
252*80868c53Srobbin 			exit(EXIT_SUCCESS);
253*80868c53Srobbin 		}
2547c478bd9Sstevel@tonic-gate 	vflag = 0;
255*80868c53Srobbin 	cutarg = NULL;
2567c478bd9Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "c:v")) == 'c' || c == 'v')
2577c478bd9Sstevel@tonic-gate 		if (c == 'v')
2587c478bd9Sstevel@tonic-gate 			vflag = 1;
259*80868c53Srobbin 		else	cutarg = optarg;
2607c478bd9Sstevel@tonic-gate 	if (c != EOF ||
2617c478bd9Sstevel@tonic-gate 		(optind == argc - 1 && strcmp(argv[optind], "=") == 0)) {
262*80868c53Srobbin 			usage();
2637c478bd9Sstevel@tonic-gate 			/* NOTREACHED */
2647c478bd9Sstevel@tonic-gate 	}
265*80868c53Srobbin 	if (vflag) {
266*80868c53Srobbin 		if (cutarg != NULL) {
267*80868c53Srobbin 			long	lo;
268*80868c53Srobbin 			long	hi;
269*80868c53Srobbin 			char	dummy;
2707c478bd9Sstevel@tonic-gate 
271*80868c53Srobbin 			if (sscanf(cutarg, "%ld%c", &hi, &dummy) == 1) {
272*80868c53Srobbin 				cuthiyear = hi;
273*80868c53Srobbin 			} else if (sscanf(cutarg, "%ld,%ld%c",
274*80868c53Srobbin 				&lo, &hi, &dummy) == 2) {
275*80868c53Srobbin 					cutloyear = lo;
276*80868c53Srobbin 					cuthiyear = hi;
277*80868c53Srobbin 			} else {
278*80868c53Srobbin (void) fprintf(stderr, gettext("%s: wild -c argument %s\n"),
279*80868c53Srobbin 					progname, cutarg);
280*80868c53Srobbin 				exit(EXIT_FAILURE);
281*80868c53Srobbin 			}
282*80868c53Srobbin 		}
283*80868c53Srobbin 		setabsolutes();
284*80868c53Srobbin 		cutlotime = yeartot(cutloyear);
285*80868c53Srobbin 		cuthitime = yeartot(cuthiyear);
2867c478bd9Sstevel@tonic-gate 	}
2877c478bd9Sstevel@tonic-gate 	(void) time(&now);
2887c478bd9Sstevel@tonic-gate 	longest = 0;
2897c478bd9Sstevel@tonic-gate 	for (i = optind; i < argc; ++i)
2907c478bd9Sstevel@tonic-gate 		if (strlen(argv[i]) > longest)
2917c478bd9Sstevel@tonic-gate 			longest = strlen(argv[i]);
2927c478bd9Sstevel@tonic-gate 
2937c478bd9Sstevel@tonic-gate 	for (i = optind; i < argc; ++i) {
2947c478bd9Sstevel@tonic-gate 		static char	buf[MAX_STRING_LENGTH];
295*80868c53Srobbin 		static char	*tzp = NULL;
2967c478bd9Sstevel@tonic-gate 
297*80868c53Srobbin 		(void) unsetenv("TZ");
298*80868c53Srobbin 		if (tzp != NULL)
299*80868c53Srobbin 			free(tzp);
300*80868c53Srobbin 		if ((tzp = malloc(3 + strlen(argv[i]) + 1)) == NULL) {
301*80868c53Srobbin 			perror(progname);
302*80868c53Srobbin 			exit(EXIT_FAILURE);
303*80868c53Srobbin 		}
304*80868c53Srobbin 		(void) strcpy(tzp, "TZ=");
305*80868c53Srobbin 		(void) strcat(tzp, argv[i]);
306*80868c53Srobbin 		if (putenv(tzp) != 0) {
307*80868c53Srobbin 			perror(progname);
308*80868c53Srobbin 			exit(EXIT_FAILURE);
309*80868c53Srobbin 		}
3107c478bd9Sstevel@tonic-gate 		if (!vflag) {
3117c478bd9Sstevel@tonic-gate 			show(argv[i], now, FALSE);
3127c478bd9Sstevel@tonic-gate 			continue;
3137c478bd9Sstevel@tonic-gate 		}
3147c478bd9Sstevel@tonic-gate 
3157c478bd9Sstevel@tonic-gate #if defined(sun)
3167c478bd9Sstevel@tonic-gate 		/*
3177c478bd9Sstevel@tonic-gate 		 * We show the current time first, probably because we froze
3187c478bd9Sstevel@tonic-gate 		 * the behavior of zdump some time ago and then it got
3197c478bd9Sstevel@tonic-gate 		 * changed.
3207c478bd9Sstevel@tonic-gate 		 */
3217c478bd9Sstevel@tonic-gate 		show(argv[i], now, TRUE);
3227c478bd9Sstevel@tonic-gate #endif
323*80868c53Srobbin 		warned = FALSE;
324*80868c53Srobbin 		t = absolute_min_time;
3257c478bd9Sstevel@tonic-gate 		show(argv[i], t, TRUE);
3267c478bd9Sstevel@tonic-gate 		t += SECSPERHOUR * HOURSPERDAY;
3277c478bd9Sstevel@tonic-gate 		show(argv[i], t, TRUE);
328*80868c53Srobbin 		if (t < cutlotime)
329*80868c53Srobbin 			t = cutlotime;
330*80868c53Srobbin 		tmp = my_localtime(&t);
331*80868c53Srobbin 		if (tmp != NULL) {
332*80868c53Srobbin 			tm = *tmp;
333*80868c53Srobbin 			(void) strncpy(buf, abbr(&tm), sizeof (buf) - 1);
334*80868c53Srobbin 		}
3357c478bd9Sstevel@tonic-gate 		for (;;) {
336*80868c53Srobbin 			if (t >= cuthitime)
3377c478bd9Sstevel@tonic-gate 				break;
3387c478bd9Sstevel@tonic-gate 			newt = t + SECSPERHOUR * 12;
339*80868c53Srobbin 			if (newt >= cuthitime)
3407c478bd9Sstevel@tonic-gate 				break;
3417c478bd9Sstevel@tonic-gate 			if (newt <= t)
3427c478bd9Sstevel@tonic-gate 				break;
343*80868c53Srobbin 			newtmp = localtime(&newt);
344*80868c53Srobbin 			if (newtmp != NULL)
345*80868c53Srobbin 				newtm = *newtmp;
346*80868c53Srobbin 			if ((tmp == NULL || newtmp == NULL) ? (tmp != newtmp) :
347*80868c53Srobbin 				(delta(&newtm, &tm) != (newt - t) ||
3487c478bd9Sstevel@tonic-gate 				newtm.tm_isdst != tm.tm_isdst ||
349*80868c53Srobbin 				strcmp(abbr(&newtm), buf) != 0)) {
3507c478bd9Sstevel@tonic-gate 					newt = hunt(argv[i], t, newt);
351*80868c53Srobbin 					newtmp = localtime(&newt);
352*80868c53Srobbin 					if (newtmp != NULL) {
353*80868c53Srobbin 						newtm = *newtmp;
354*80868c53Srobbin 						(void) strncpy(buf,
355*80868c53Srobbin 							abbr(&newtm),
356*80868c53Srobbin 							sizeof (buf) - 1);
357*80868c53Srobbin 					}
3587c478bd9Sstevel@tonic-gate 			}
3597c478bd9Sstevel@tonic-gate 			t = newt;
3607c478bd9Sstevel@tonic-gate 			tm = newtm;
361*80868c53Srobbin 			tmp = newtmp;
3627c478bd9Sstevel@tonic-gate 		}
363*80868c53Srobbin 		t = absolute_max_time;
3647c478bd9Sstevel@tonic-gate #if defined(sun)
3657c478bd9Sstevel@tonic-gate 		show(argv[i], t, TRUE);
3667c478bd9Sstevel@tonic-gate 		t -= SECSPERHOUR * HOURSPERDAY;
3677c478bd9Sstevel@tonic-gate 		show(argv[i], t, TRUE);
3687c478bd9Sstevel@tonic-gate #else /* !defined(sun) */
3697c478bd9Sstevel@tonic-gate 		t -= SECSPERHOUR * HOURSPERDAY;
3707c478bd9Sstevel@tonic-gate 		show(argv[i], t, TRUE);
3717c478bd9Sstevel@tonic-gate 		t += SECSPERHOUR * HOURSPERDAY;
3727c478bd9Sstevel@tonic-gate 		show(argv[i], t, TRUE);
3737c478bd9Sstevel@tonic-gate #endif /* !defined(sun) */
3747c478bd9Sstevel@tonic-gate 	}
3757c478bd9Sstevel@tonic-gate 	if (fflush(stdout) || ferror(stdout)) {
376*80868c53Srobbin 		(void) fprintf(stderr, "%s: ", progname);
377*80868c53Srobbin 		(void) perror(gettext("Error writing standard output"));
378*80868c53Srobbin 		exit(EXIT_FAILURE);
3797c478bd9Sstevel@tonic-gate 	}
3807c478bd9Sstevel@tonic-gate 	return (EXIT_SUCCESS);
3817c478bd9Sstevel@tonic-gate }
3827c478bd9Sstevel@tonic-gate 
383*80868c53Srobbin static void
384*80868c53Srobbin setabsolutes()
385*80868c53Srobbin {
386*80868c53Srobbin #if defined(sun)
387*80868c53Srobbin 	absolute_min_time = LONG_MIN;
388*80868c53Srobbin 	absolute_max_time = LONG_MAX;
389*80868c53Srobbin #else
390*80868c53Srobbin 	if (0.5 == (time_t)0.5) {
391*80868c53Srobbin 		/*
392*80868c53Srobbin 		 * time_t is floating.
393*80868c53Srobbin 		 */
394*80868c53Srobbin 		if (sizeof (time_t) == sizeof (float)) {
395*80868c53Srobbin 			absolute_min_time = (time_t)-FLT_MAX;
396*80868c53Srobbin 			absolute_max_time = (time_t)FLT_MAX;
397*80868c53Srobbin 		} else if (sizeof (time_t) == sizeof (double)) {
398*80868c53Srobbin 			absolute_min_time = (time_t)-DBL_MAX;
399*80868c53Srobbin 			absolute_max_time = (time_t)DBL_MAX;
400*80868c53Srobbin 		} else {
401*80868c53Srobbin 			(void) fprintf(stderr, gettext("%s: use of -v on "
402*80868c53Srobbin 			    "system with floating time_t other than float "
403*80868c53Srobbin 			    "or double\n"), progname);
404*80868c53Srobbin 			exit(EXIT_FAILURE);
405*80868c53Srobbin 		}
406*80868c53Srobbin 	} else
407*80868c53Srobbin 	/*CONSTANTCONDITION*/
408*80868c53Srobbin 	if (0 > (time_t)-1) {
409*80868c53Srobbin 		/*
410*80868c53Srobbin 		 * time_t is signed.
411*80868c53Srobbin 		 */
412*80868c53Srobbin 		register time_t	hibit;
413*80868c53Srobbin 
414*80868c53Srobbin 		for (hibit = 1; (hibit * 2) != 0; hibit *= 2)
415*80868c53Srobbin 			continue;
416*80868c53Srobbin 		absolute_min_time = hibit;
417*80868c53Srobbin 		absolute_max_time = -(hibit + 1);
418*80868c53Srobbin 	} else {
419*80868c53Srobbin 		/*
420*80868c53Srobbin 		 * time_t is unsigned.
421*80868c53Srobbin 		 */
422*80868c53Srobbin 		absolute_min_time = 0;
423*80868c53Srobbin 		absolute_max_time = absolute_min_time - 1;
424*80868c53Srobbin 	}
425*80868c53Srobbin #endif
426*80868c53Srobbin }
427*80868c53Srobbin 
428*80868c53Srobbin static time_t
429*80868c53Srobbin yeartot(y)
430*80868c53Srobbin const long	y;
431*80868c53Srobbin {
432*80868c53Srobbin 	register long	myy;
433*80868c53Srobbin 	register long	seconds;
434*80868c53Srobbin 	register time_t	t;
435*80868c53Srobbin 
436*80868c53Srobbin 	myy = EPOCH_YEAR;
437*80868c53Srobbin 	t = 0;
438*80868c53Srobbin 	while (myy != y) {
439*80868c53Srobbin 		if (myy < y) {
440*80868c53Srobbin 			seconds = isleap(myy) ? SECSPERLYEAR : SECSPERNYEAR;
441*80868c53Srobbin 			++myy;
442*80868c53Srobbin 			if (t > absolute_max_time - seconds) {
443*80868c53Srobbin 				t = absolute_max_time;
444*80868c53Srobbin 				break;
445*80868c53Srobbin 			}
446*80868c53Srobbin 			t += seconds;
447*80868c53Srobbin 		} else {
448*80868c53Srobbin 			--myy;
449*80868c53Srobbin 			seconds = isleap(myy) ? SECSPERLYEAR : SECSPERNYEAR;
450*80868c53Srobbin 			if (t < absolute_min_time + seconds) {
451*80868c53Srobbin 				t = absolute_min_time;
452*80868c53Srobbin 				break;
453*80868c53Srobbin 			}
454*80868c53Srobbin 			t -= seconds;
455*80868c53Srobbin 		}
456*80868c53Srobbin 	}
457*80868c53Srobbin 	return (t);
458*80868c53Srobbin }
459*80868c53Srobbin 
4607c478bd9Sstevel@tonic-gate static time_t
4617c478bd9Sstevel@tonic-gate hunt(name, lot, hit)
4627c478bd9Sstevel@tonic-gate char	*name;
4637c478bd9Sstevel@tonic-gate time_t	lot;
4647c478bd9Sstevel@tonic-gate time_t	hit;
4657c478bd9Sstevel@tonic-gate {
4667c478bd9Sstevel@tonic-gate 	time_t			t;
467*80868c53Srobbin 	long			diff;
4687c478bd9Sstevel@tonic-gate 	struct tm		lotm;
469*80868c53Srobbin 	register struct tm	*lotmp;
4707c478bd9Sstevel@tonic-gate 	struct tm		tm;
471*80868c53Srobbin 	register struct tm	*tmp;
472*80868c53Srobbin 	char			loab[MAX_STRING_LENGTH];
4737c478bd9Sstevel@tonic-gate 
474*80868c53Srobbin 	lotmp = my_localtime(&lot);
475*80868c53Srobbin 	if (lotmp != NULL) {
476*80868c53Srobbin 		lotm = *lotmp;
477*80868c53Srobbin 		(void) strncpy(loab, abbr(&lotm), sizeof (loab) - 1);
478*80868c53Srobbin 	}
479*80868c53Srobbin 	for (;;) {
480*80868c53Srobbin 		diff = (long)(hit - lot);
481*80868c53Srobbin 		if (diff < 2)
482*80868c53Srobbin 			break;
483*80868c53Srobbin 		t = lot;
484*80868c53Srobbin 		t += diff / 2;
4857c478bd9Sstevel@tonic-gate 		if (t <= lot)
4867c478bd9Sstevel@tonic-gate 			++t;
4877c478bd9Sstevel@tonic-gate 		else if (t >= hit)
4887c478bd9Sstevel@tonic-gate 			--t;
489*80868c53Srobbin 		tmp = my_localtime(&t);
490*80868c53Srobbin 		if (tmp != NULL)
491*80868c53Srobbin 			tm = *tmp;
492*80868c53Srobbin 		if ((lotmp == NULL || tmp == NULL) ? (lotmp == tmp) :
493*80868c53Srobbin 			(delta(&tm, &lotm) == (t - lot) &&
4947c478bd9Sstevel@tonic-gate 			tm.tm_isdst == lotm.tm_isdst &&
495*80868c53Srobbin 			strcmp(abbr(&tm), loab) == 0)) {
4967c478bd9Sstevel@tonic-gate 				lot = t;
4977c478bd9Sstevel@tonic-gate 				lotm = tm;
498*80868c53Srobbin 				lotmp = tmp;
4997c478bd9Sstevel@tonic-gate 		} else	hit = t;
5007c478bd9Sstevel@tonic-gate 	}
5017c478bd9Sstevel@tonic-gate 	show(name, lot, TRUE);
5027c478bd9Sstevel@tonic-gate 	show(name, hit, TRUE);
5037c478bd9Sstevel@tonic-gate 	return (hit);
5047c478bd9Sstevel@tonic-gate }
5057c478bd9Sstevel@tonic-gate 
5067c478bd9Sstevel@tonic-gate /*
5077c478bd9Sstevel@tonic-gate  * Thanks to Paul Eggert (eggert@twinsun.com) for logic used in delta.
5087c478bd9Sstevel@tonic-gate  */
5097c478bd9Sstevel@tonic-gate 
5107c478bd9Sstevel@tonic-gate static long
5117c478bd9Sstevel@tonic-gate delta(newp, oldp)
5127c478bd9Sstevel@tonic-gate struct tm	*newp;
5137c478bd9Sstevel@tonic-gate struct tm	*oldp;
5147c478bd9Sstevel@tonic-gate {
515*80868c53Srobbin 	register long	result;
516*80868c53Srobbin 	register int	tmy;
5177c478bd9Sstevel@tonic-gate 
5187c478bd9Sstevel@tonic-gate 	if (newp->tm_year < oldp->tm_year)
5197c478bd9Sstevel@tonic-gate 		return (-delta(oldp, newp));
5207c478bd9Sstevel@tonic-gate 	result = 0;
5217c478bd9Sstevel@tonic-gate 	for (tmy = oldp->tm_year; tmy < newp->tm_year; ++tmy)
522*80868c53Srobbin 		result += DAYSPERNYEAR + isleap_sum(tmy, TM_YEAR_BASE);
5237c478bd9Sstevel@tonic-gate 	result += newp->tm_yday - oldp->tm_yday;
5247c478bd9Sstevel@tonic-gate 	result *= HOURSPERDAY;
5257c478bd9Sstevel@tonic-gate 	result += newp->tm_hour - oldp->tm_hour;
5267c478bd9Sstevel@tonic-gate 	result *= MINSPERHOUR;
5277c478bd9Sstevel@tonic-gate 	result += newp->tm_min - oldp->tm_min;
5287c478bd9Sstevel@tonic-gate 	result *= SECSPERMIN;
5297c478bd9Sstevel@tonic-gate 	result += newp->tm_sec - oldp->tm_sec;
5307c478bd9Sstevel@tonic-gate 	return (result);
5317c478bd9Sstevel@tonic-gate }
5327c478bd9Sstevel@tonic-gate 
5337c478bd9Sstevel@tonic-gate static void
5347c478bd9Sstevel@tonic-gate show(zone, t, v)
5357c478bd9Sstevel@tonic-gate char	*zone;
5367c478bd9Sstevel@tonic-gate time_t	t;
5377c478bd9Sstevel@tonic-gate int	v;
5387c478bd9Sstevel@tonic-gate {
539*80868c53Srobbin 	register struct tm	*tmp;
5407c478bd9Sstevel@tonic-gate 
5417c478bd9Sstevel@tonic-gate 	(void) printf("%-*s  ", (int)longest, zone);
542*80868c53Srobbin 	if (v) {
543*80868c53Srobbin 		tmp = gmtime(&t);
544*80868c53Srobbin 		if (tmp == NULL) {
545*80868c53Srobbin 			(void) printf(tformat(), t);
546*80868c53Srobbin 		} else {
547*80868c53Srobbin 			dumptime(tmp);
548*80868c53Srobbin 			(void) printf(" UTC");
549*80868c53Srobbin 		}
550*80868c53Srobbin 		(void) printf(" = ");
551*80868c53Srobbin 	}
552*80868c53Srobbin 	tmp = my_localtime(&t);
553*80868c53Srobbin 	dumptime(tmp);
554*80868c53Srobbin 	if (tmp != NULL) {
5557c478bd9Sstevel@tonic-gate 		if (*abbr(tmp) != '\0')
5567c478bd9Sstevel@tonic-gate 			(void) printf(" %s", abbr(tmp));
5577c478bd9Sstevel@tonic-gate 		if (v) {
5587c478bd9Sstevel@tonic-gate 			(void) printf(" isdst=%d", tmp->tm_isdst);
559*80868c53Srobbin #ifdef TM_GMTOFF
560*80868c53Srobbin 			(void) printf(" gmtoff=%ld", tmp->TM_GMTOFF);
561*80868c53Srobbin #endif /* defined TM_GMTOFF */
562*80868c53Srobbin 		}
5637c478bd9Sstevel@tonic-gate 	}
5647c478bd9Sstevel@tonic-gate 	(void) printf("\n");
565*80868c53Srobbin 	if (tmp != NULL && *abbr(tmp) != '\0')
566*80868c53Srobbin 		abbrok(abbr(tmp), zone);
5677c478bd9Sstevel@tonic-gate }
5687c478bd9Sstevel@tonic-gate 
5697c478bd9Sstevel@tonic-gate static char *
5707c478bd9Sstevel@tonic-gate abbr(tmp)
5717c478bd9Sstevel@tonic-gate struct tm	*tmp;
5727c478bd9Sstevel@tonic-gate {
5737c478bd9Sstevel@tonic-gate 	register char	*result;
5747c478bd9Sstevel@tonic-gate 	static char	nada;
5757c478bd9Sstevel@tonic-gate 
5767c478bd9Sstevel@tonic-gate 	if (tmp->tm_isdst != 0 && tmp->tm_isdst != 1)
5777c478bd9Sstevel@tonic-gate 		return (&nada);
5787c478bd9Sstevel@tonic-gate 	result = tzname[tmp->tm_isdst];
5797c478bd9Sstevel@tonic-gate 	return ((result == NULL) ? &nada : result);
5807c478bd9Sstevel@tonic-gate }
5817c478bd9Sstevel@tonic-gate 
582*80868c53Srobbin /*
583*80868c53Srobbin  * The code below can fail on certain theoretical systems;
584*80868c53Srobbin  * it works on all known real-world systems as of 2004-12-30.
585*80868c53Srobbin  */
586*80868c53Srobbin 
587*80868c53Srobbin static const char *
588*80868c53Srobbin tformat()
589*80868c53Srobbin {
590*80868c53Srobbin #if defined(sun)
591*80868c53Srobbin 	/* time_t is signed long */
592*80868c53Srobbin 	return ("%ld");
593*80868c53Srobbin #else
594*80868c53Srobbin 	/*CONSTANTCONDITION*/
595*80868c53Srobbin 	if (0.5 == (time_t)0.5) {	/* floating */
596*80868c53Srobbin 		/*CONSTANTCONDITION*/
597*80868c53Srobbin 		if (sizeof (time_t) > sizeof (double))
598*80868c53Srobbin 			return ("%Lg");
599*80868c53Srobbin 		return ("%g");
600*80868c53Srobbin 	}
601*80868c53Srobbin 	/*CONSTANTCONDITION*/
602*80868c53Srobbin 	if (0 > (time_t)-1) {		/* signed */
603*80868c53Srobbin 		/*CONSTANTCONDITION*/
604*80868c53Srobbin 		if (sizeof (time_t) > sizeof (long))
605*80868c53Srobbin 			return ("%lld");
606*80868c53Srobbin 		/*CONSTANTCONDITION*/
607*80868c53Srobbin 		if (sizeof (time_t) > sizeof (int))
608*80868c53Srobbin 			return ("%ld");
609*80868c53Srobbin 		return ("%d");
610*80868c53Srobbin 	}
611*80868c53Srobbin 	/*CONSTANTCONDITION*/
612*80868c53Srobbin 	if (sizeof (time_t) > sizeof (unsigned long))
613*80868c53Srobbin 		return ("%llu");
614*80868c53Srobbin 	/*CONSTANTCONDITION*/
615*80868c53Srobbin 	if (sizeof (time_t) > sizeof (unsigned int))
616*80868c53Srobbin 		return ("%lu");
617*80868c53Srobbin 	return ("%u");
618*80868c53Srobbin #endif
619*80868c53Srobbin }
620*80868c53Srobbin 
6217c478bd9Sstevel@tonic-gate static void
622*80868c53Srobbin dumptime(timeptr)
623*80868c53Srobbin register const struct tm	*timeptr;
624*80868c53Srobbin {
625*80868c53Srobbin 	static const char	wday_name[][3] = {
626*80868c53Srobbin 		"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
627*80868c53Srobbin 	};
628*80868c53Srobbin 	static const char	mon_name[][3] = {
629*80868c53Srobbin 		"Jan", "Feb", "Mar", "Apr", "May", "Jun",
630*80868c53Srobbin 		"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
631*80868c53Srobbin 	};
632*80868c53Srobbin 	register const char	*wn;
633*80868c53Srobbin 	register const char	*mn;
634*80868c53Srobbin 	register int		lead;
635*80868c53Srobbin 	register int		trail;
636*80868c53Srobbin 
637*80868c53Srobbin 	if (timeptr == NULL) {
638*80868c53Srobbin 		(void) printf("NULL");
639*80868c53Srobbin 		return;
640*80868c53Srobbin 	}
641*80868c53Srobbin 	/*
642*80868c53Srobbin 	 * The packaged versions of localtime and gmtime never put out-of-range
643*80868c53Srobbin 	 * values in tm_wday or tm_mon, but since this code might be compiled
644*80868c53Srobbin 	 * with other (perhaps experimental) versions, paranoia is in order.
645*80868c53Srobbin 	 */
646*80868c53Srobbin 	if (timeptr->tm_wday < 0 || timeptr->tm_wday >=
647*80868c53Srobbin 		(int)(sizeof (wday_name) / sizeof (wday_name[0])))
648*80868c53Srobbin 			wn = "???";
649*80868c53Srobbin 	else		wn = wday_name[timeptr->tm_wday];
650*80868c53Srobbin 	if (timeptr->tm_mon < 0 || timeptr->tm_mon >=
651*80868c53Srobbin 		(int)(sizeof (mon_name) / sizeof (mon_name[0])))
652*80868c53Srobbin 			mn = "???";
653*80868c53Srobbin 	else		mn = mon_name[timeptr->tm_mon];
654*80868c53Srobbin 	(void) printf("%.3s %.3s%3d %.2d:%.2d:%.2d ",
655*80868c53Srobbin 		wn, mn,
656*80868c53Srobbin 		timeptr->tm_mday, timeptr->tm_hour,
657*80868c53Srobbin 		timeptr->tm_min, timeptr->tm_sec);
658*80868c53Srobbin #define	DIVISOR	10
659*80868c53Srobbin 	trail = timeptr->tm_year % DIVISOR + TM_YEAR_BASE % DIVISOR;
660*80868c53Srobbin 	lead = timeptr->tm_year / DIVISOR + TM_YEAR_BASE / DIVISOR +
661*80868c53Srobbin 		trail / DIVISOR;
662*80868c53Srobbin 	trail %= DIVISOR;
663*80868c53Srobbin 	if (trail < 0 && lead > 0) {
664*80868c53Srobbin 		trail += DIVISOR;
665*80868c53Srobbin 		--lead;
666*80868c53Srobbin 	} else if (lead < 0 && trail > 0) {
667*80868c53Srobbin 		trail -= DIVISOR;
668*80868c53Srobbin 		++lead;
669*80868c53Srobbin 	}
670*80868c53Srobbin 	if (lead == 0)
671*80868c53Srobbin 		(void) printf("%d", trail);
672*80868c53Srobbin 	else
673*80868c53Srobbin 		(void) printf("%d%d", lead, ((trail < 0) ? -trail : trail));
674*80868c53Srobbin }
675*80868c53Srobbin 
676*80868c53Srobbin static void
677*80868c53Srobbin usage()
6787c478bd9Sstevel@tonic-gate {
6797c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext(
680*80868c53Srobbin 	    "%s: [ --version ] [ -v ] [ -c [loyear,]hiyear ] zonename ...\n"),
681*80868c53Srobbin 		progname);
682*80868c53Srobbin 	exit(EXIT_FAILURE);
6837c478bd9Sstevel@tonic-gate 	/* NOTREACHED */
6847c478bd9Sstevel@tonic-gate }
685