xref: /onnv-gate/usr/src/cmd/zdump/zdump.c (revision 1138)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
50Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
70Sstevel@tonic-gate  * with the License.
80Sstevel@tonic-gate  *
90Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate  * See the License for the specific language governing permissions
120Sstevel@tonic-gate  * and limitations under the License.
130Sstevel@tonic-gate  *
140Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate  *
200Sstevel@tonic-gate  * CDDL HEADER END
210Sstevel@tonic-gate  */
220Sstevel@tonic-gate /*
23*1138Srobbin  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
27*1138Srobbin #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*1138Srobbin 
290Sstevel@tonic-gate /*
300Sstevel@tonic-gate  * zdump 7.24
310Sstevel@tonic-gate  * Taken from elsie.nci.nih.gov to replace the existing Solaris zdump,
320Sstevel@tonic-gate  * which was based on an earlier version of the elsie code.
330Sstevel@tonic-gate  *
340Sstevel@tonic-gate  * For zdump 7.24, the following changes were made to the elsie code:
350Sstevel@tonic-gate  *   locale/textdomain/messages to match existing Solaris style.
360Sstevel@tonic-gate  *   Solaris verbose mode is documented to display the current time first.
370Sstevel@tonic-gate  *   cstyle cleaned code.
380Sstevel@tonic-gate  *   removed old locale/textdomain code.
390Sstevel@tonic-gate  */
400Sstevel@tonic-gate 
41*1138Srobbin static char	elsieid[] = "@(#)zdump.c	7.68";
420Sstevel@tonic-gate 
430Sstevel@tonic-gate /*
440Sstevel@tonic-gate  * This code has been made independent of the rest of the time
450Sstevel@tonic-gate  * conversion package to increase confidence in the verification it provides.
460Sstevel@tonic-gate  * You can use this code to help in verifying other implementations.
470Sstevel@tonic-gate  */
480Sstevel@tonic-gate 
490Sstevel@tonic-gate #include "stdio.h"	/* for stdout, stderr, perror */
500Sstevel@tonic-gate #include "string.h"	/* for strcpy */
510Sstevel@tonic-gate #include "sys/types.h"	/* for time_t */
520Sstevel@tonic-gate #include "time.h"	/* for struct tm */
530Sstevel@tonic-gate #include "stdlib.h"	/* for exit, malloc, atoi */
540Sstevel@tonic-gate #include "locale.h"	/* for setlocale, textdomain */
550Sstevel@tonic-gate #include "libintl.h"
56*1138Srobbin #include <ctype.h>
570Sstevel@tonic-gate #include "tzfile.h"	/* for defines */
58*1138Srobbin #include <limits.h>
59*1138Srobbin 
60*1138Srobbin #ifndef ZDUMP_LO_YEAR
61*1138Srobbin #define	ZDUMP_LO_YEAR	(-500)
62*1138Srobbin #endif /* !defined ZDUMP_LO_YEAR */
63*1138Srobbin 
64*1138Srobbin #ifndef ZDUMP_HI_YEAR
65*1138Srobbin #define	ZDUMP_HI_YEAR	2500
66*1138Srobbin #endif /* !defined ZDUMP_HI_YEAR */
670Sstevel@tonic-gate 
680Sstevel@tonic-gate #ifndef MAX_STRING_LENGTH
690Sstevel@tonic-gate #define	MAX_STRING_LENGTH	1024
700Sstevel@tonic-gate #endif /* !defined MAX_STRING_LENGTH */
710Sstevel@tonic-gate 
720Sstevel@tonic-gate #ifndef TRUE
730Sstevel@tonic-gate #define	TRUE		1
740Sstevel@tonic-gate #endif /* !defined TRUE */
750Sstevel@tonic-gate 
760Sstevel@tonic-gate #ifndef FALSE
770Sstevel@tonic-gate #define	FALSE		0
780Sstevel@tonic-gate #endif /* !defined FALSE */
790Sstevel@tonic-gate 
80*1138Srobbin #ifndef isleap_sum
81*1138Srobbin /*
82*1138Srobbin  * See tzfile.h for details on isleap_sum.
83*1138Srobbin  */
84*1138Srobbin #define	isleap_sum(a, b)	isleap((a) % 400 + (b) % 400)
85*1138Srobbin #endif /* !defined isleap_sum */
86*1138Srobbin 
87*1138Srobbin #ifndef SECSPERDAY
88*1138Srobbin #define	SECSPERDAY	((long)SECSPERHOUR * HOURSPERDAY)
89*1138Srobbin #endif
90*1138Srobbin #define	SECSPERNYEAR	(SECSPERDAY * DAYSPERNYEAR)
91*1138Srobbin #define	SECSPERLYEAR	(SECSPERNYEAR + SECSPERDAY)
92*1138Srobbin 
93*1138Srobbin #ifndef GNUC_or_lint
94*1138Srobbin #ifdef lint
95*1138Srobbin #define	GNUC_or_lint
96*1138Srobbin #else /* !defined lint */
97*1138Srobbin #ifdef __GNUC__
98*1138Srobbin #define	GNUC_or_lint
99*1138Srobbin #endif /* defined __GNUC__ */
100*1138Srobbin #endif /* !defined lint */
101*1138Srobbin #endif /* !defined GNUC_or_lint */
102*1138Srobbin 
1030Sstevel@tonic-gate #ifndef INITIALIZE
104*1138Srobbin #ifdef	GNUC_or_lint
1050Sstevel@tonic-gate #define	INITIALIZE(x)	((x) = 0)
106*1138Srobbin #else /* !defined GNUC_or_lint */
1070Sstevel@tonic-gate #define	INITIALIZE(x)
108*1138Srobbin #endif /* !defined GNUC_or_lint */
1090Sstevel@tonic-gate #endif /* !defined INITIALIZE */
1100Sstevel@tonic-gate 
111*1138Srobbin static time_t	absolute_min_time;
112*1138Srobbin static time_t	absolute_max_time;
113*1138Srobbin static size_t	longest;
114*1138Srobbin static char	*progname;
115*1138Srobbin static int	warned;
1160Sstevel@tonic-gate 
117*1138Srobbin static char	*abbr(struct tm *);
118*1138Srobbin static void	abbrok(const char *, const char *);
1190Sstevel@tonic-gate static long	delta(struct tm *, struct tm *);
120*1138Srobbin static void	dumptime(const struct tm *);
1210Sstevel@tonic-gate static time_t	hunt(char *, time_t, time_t);
122*1138Srobbin static void	setabsolutes(void);
1230Sstevel@tonic-gate static void	show(char *, time_t, int);
124*1138Srobbin static void	usage(void);
125*1138Srobbin static const char	*tformat(void);
126*1138Srobbin static time_t	yeartot(long y);
127*1138Srobbin 
128*1138Srobbin #ifndef TYPECHECK
129*1138Srobbin #define	my_localtime	localtime
130*1138Srobbin #else /* !defined TYPECHECK */
131*1138Srobbin static struct tm *
132*1138Srobbin my_localtime(tp)
133*1138Srobbin time_t *tp;
134*1138Srobbin {
135*1138Srobbin 	register struct tm *tmp;
136*1138Srobbin 
137*1138Srobbin 	tmp = localtime(tp);
138*1138Srobbin 	if (tp != NULL && tmp != NULL) {
139*1138Srobbin 		struct tm	tm;
140*1138Srobbin 		register time_t	t;
141*1138Srobbin 
142*1138Srobbin 		tm = *tmp;
143*1138Srobbin 		t = mktime(&tm);
144*1138Srobbin 		if (t - *tp >= 1 || *tp - t >= 1) {
145*1138Srobbin 			(void) fflush(stdout);
146*1138Srobbin 			(void) fprintf(stderr, "\n%s: ", progname);
147*1138Srobbin 			(void) fprintf(stderr, tformat(), *tp);
148*1138Srobbin 			(void) fprintf(stderr, " ->");
149*1138Srobbin 			(void) fprintf(stderr, " year=%d", tmp->tm_year);
150*1138Srobbin 			(void) fprintf(stderr, " mon=%d", tmp->tm_mon);
151*1138Srobbin 			(void) fprintf(stderr, " mday=%d", tmp->tm_mday);
152*1138Srobbin 			(void) fprintf(stderr, " hour=%d", tmp->tm_hour);
153*1138Srobbin 			(void) fprintf(stderr, " min=%d", tmp->tm_min);
154*1138Srobbin 			(void) fprintf(stderr, " sec=%d", tmp->tm_sec);
155*1138Srobbin 			(void) fprintf(stderr, " isdst=%d", tmp->tm_isdst);
156*1138Srobbin 			(void) fprintf(stderr, " -> ");
157*1138Srobbin 			(void) fprintf(stderr, tformat(), t);
158*1138Srobbin 			(void) fprintf(stderr, "\n");
159*1138Srobbin 		}
160*1138Srobbin 	}
161*1138Srobbin 	return (tmp);
162*1138Srobbin }
163*1138Srobbin #endif /* !defined TYPECHECK */
164*1138Srobbin 
165*1138Srobbin static void
166*1138Srobbin abbrok(abbrp, zone)
167*1138Srobbin const char * const	abbrp;
168*1138Srobbin const char * const	zone;
169*1138Srobbin {
170*1138Srobbin 	register const char *cp;
171*1138Srobbin 	int error = 0;
172*1138Srobbin 
173*1138Srobbin 	if (warned)
174*1138Srobbin 		return;
175*1138Srobbin 	cp = abbrp;
176*1138Srobbin 	while (isascii(*cp) && isalpha((unsigned char)*cp))
177*1138Srobbin 		++cp;
178*1138Srobbin 	(void) fflush(stdout);
179*1138Srobbin 	if (cp - abbrp == 0) {
180*1138Srobbin 		/*
181*1138Srobbin 		 * TRANSLATION_NOTE
182*1138Srobbin 		 * The first %s prints for the program name (zdump),
183*1138Srobbin 		 * the second %s prints the timezone name, the third
184*1138Srobbin 		 * %s prints the timezone abbreviation (tzname[0] or
185*1138Srobbin 		 * tzname[1]).
186*1138Srobbin 		 */
187*1138Srobbin 		(void) fprintf(stderr, gettext("%s: warning: zone \"%s\" "
188*1138Srobbin 		    "abbreviation \"%s\" lacks alphabetic at start\n"),
189*1138Srobbin 		    progname, zone, abbrp);
190*1138Srobbin 		error = 1;
191*1138Srobbin 	} else if (cp - abbrp < 3) {
192*1138Srobbin 		(void) fprintf(stderr, gettext("%s: warning: zone \"%s\" "
193*1138Srobbin 		    "abbreviation \"%s\" has fewer than 3 alphabetics\n"),
194*1138Srobbin 		    progname, zone, abbrp);
195*1138Srobbin 		error = 1;
196*1138Srobbin 	} else if (cp - abbrp > 6) {
197*1138Srobbin 		(void) fprintf(stderr, gettext("%s: warning: zone \"%s\" "
198*1138Srobbin 		    "abbreviation \"%s\" has more than 6 alphabetics\n"),
199*1138Srobbin 		    progname, zone, abbrp);
200*1138Srobbin 		error = 1;
201*1138Srobbin 	}
202*1138Srobbin 	if (error == 0 && (*cp == '+' || *cp == '-')) {
203*1138Srobbin 		++cp;
204*1138Srobbin 		if (isascii(*cp) && isdigit((unsigned char)*cp))
205*1138Srobbin 			if (*cp++ == '1' && *cp >= '0' && *cp <= '4')
206*1138Srobbin 				++cp;
207*1138Srobbin 	}
208*1138Srobbin 	if (error == 0 && *cp != '\0') {
209*1138Srobbin 		(void) fprintf(stderr, gettext("%s: warning: zone \"%s\" "
210*1138Srobbin 		    "abbreviation \"%s\" differs from POSIX standard\n"),
211*1138Srobbin 		    progname, zone, abbrp);
212*1138Srobbin 		error = 1;
213*1138Srobbin 	}
214*1138Srobbin 	if (error)
215*1138Srobbin 		warned = TRUE;
216*1138Srobbin }
2170Sstevel@tonic-gate 
2180Sstevel@tonic-gate int
2190Sstevel@tonic-gate main(argc, argv)
2200Sstevel@tonic-gate int	argc;
221*1138Srobbin char	*argv[];
2220Sstevel@tonic-gate {
2230Sstevel@tonic-gate 	register int		i;
2240Sstevel@tonic-gate 	register int		c;
2250Sstevel@tonic-gate 	register int		vflag;
226*1138Srobbin 	register char		*cutarg;
227*1138Srobbin 	register long		cutloyear = ZDUMP_LO_YEAR;
228*1138Srobbin 	register long		cuthiyear = ZDUMP_HI_YEAR;
229*1138Srobbin 	register time_t		cutlotime;
230*1138Srobbin 	register time_t		cuthitime;
2310Sstevel@tonic-gate 	time_t			now;
2320Sstevel@tonic-gate 	time_t			t;
2330Sstevel@tonic-gate 	time_t			newt;
2340Sstevel@tonic-gate 	struct tm		tm;
2350Sstevel@tonic-gate 	struct tm		newtm;
236*1138Srobbin 	register struct tm	*tmp;
237*1138Srobbin 	register struct tm	*newtmp;
2380Sstevel@tonic-gate 
239*1138Srobbin 	INITIALIZE(cutlotime);
240*1138Srobbin 	INITIALIZE(cuthitime);
2410Sstevel@tonic-gate 
2420Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
2430Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)		/* Should be defined by cc -D */
2440Sstevel@tonic-gate #define	TEXT_DOMAIN	"SYS_TEST"	/* Use this only if it weren't */
2450Sstevel@tonic-gate #endif
2460Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
2470Sstevel@tonic-gate 
2480Sstevel@tonic-gate 	progname = argv[0];
249*1138Srobbin 	for (i = 1; i < argc; ++i)
250*1138Srobbin 		if (strcmp(argv[i], "--version") == 0) {
251*1138Srobbin 			(void) printf("%s\n", elsieid);
252*1138Srobbin 			exit(EXIT_SUCCESS);
253*1138Srobbin 		}
2540Sstevel@tonic-gate 	vflag = 0;
255*1138Srobbin 	cutarg = NULL;
2560Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "c:v")) == 'c' || c == 'v')
2570Sstevel@tonic-gate 		if (c == 'v')
2580Sstevel@tonic-gate 			vflag = 1;
259*1138Srobbin 		else	cutarg = optarg;
2600Sstevel@tonic-gate 	if (c != EOF ||
2610Sstevel@tonic-gate 		(optind == argc - 1 && strcmp(argv[optind], "=") == 0)) {
262*1138Srobbin 			usage();
2630Sstevel@tonic-gate 			/* NOTREACHED */
2640Sstevel@tonic-gate 	}
265*1138Srobbin 	if (vflag) {
266*1138Srobbin 		if (cutarg != NULL) {
267*1138Srobbin 			long	lo;
268*1138Srobbin 			long	hi;
269*1138Srobbin 			char	dummy;
2700Sstevel@tonic-gate 
271*1138Srobbin 			if (sscanf(cutarg, "%ld%c", &hi, &dummy) == 1) {
272*1138Srobbin 				cuthiyear = hi;
273*1138Srobbin 			} else if (sscanf(cutarg, "%ld,%ld%c",
274*1138Srobbin 				&lo, &hi, &dummy) == 2) {
275*1138Srobbin 					cutloyear = lo;
276*1138Srobbin 					cuthiyear = hi;
277*1138Srobbin 			} else {
278*1138Srobbin (void) fprintf(stderr, gettext("%s: wild -c argument %s\n"),
279*1138Srobbin 					progname, cutarg);
280*1138Srobbin 				exit(EXIT_FAILURE);
281*1138Srobbin 			}
282*1138Srobbin 		}
283*1138Srobbin 		setabsolutes();
284*1138Srobbin 		cutlotime = yeartot(cutloyear);
285*1138Srobbin 		cuthitime = yeartot(cuthiyear);
2860Sstevel@tonic-gate 	}
2870Sstevel@tonic-gate 	(void) time(&now);
2880Sstevel@tonic-gate 	longest = 0;
2890Sstevel@tonic-gate 	for (i = optind; i < argc; ++i)
2900Sstevel@tonic-gate 		if (strlen(argv[i]) > longest)
2910Sstevel@tonic-gate 			longest = strlen(argv[i]);
2920Sstevel@tonic-gate 
2930Sstevel@tonic-gate 	for (i = optind; i < argc; ++i) {
2940Sstevel@tonic-gate 		static char	buf[MAX_STRING_LENGTH];
295*1138Srobbin 		static char	*tzp = NULL;
2960Sstevel@tonic-gate 
297*1138Srobbin 		(void) unsetenv("TZ");
298*1138Srobbin 		if (tzp != NULL)
299*1138Srobbin 			free(tzp);
300*1138Srobbin 		if ((tzp = malloc(3 + strlen(argv[i]) + 1)) == NULL) {
301*1138Srobbin 			perror(progname);
302*1138Srobbin 			exit(EXIT_FAILURE);
303*1138Srobbin 		}
304*1138Srobbin 		(void) strcpy(tzp, "TZ=");
305*1138Srobbin 		(void) strcat(tzp, argv[i]);
306*1138Srobbin 		if (putenv(tzp) != 0) {
307*1138Srobbin 			perror(progname);
308*1138Srobbin 			exit(EXIT_FAILURE);
309*1138Srobbin 		}
3100Sstevel@tonic-gate 		if (!vflag) {
3110Sstevel@tonic-gate 			show(argv[i], now, FALSE);
3120Sstevel@tonic-gate 			continue;
3130Sstevel@tonic-gate 		}
3140Sstevel@tonic-gate 
3150Sstevel@tonic-gate #if defined(sun)
3160Sstevel@tonic-gate 		/*
3170Sstevel@tonic-gate 		 * We show the current time first, probably because we froze
3180Sstevel@tonic-gate 		 * the behavior of zdump some time ago and then it got
3190Sstevel@tonic-gate 		 * changed.
3200Sstevel@tonic-gate 		 */
3210Sstevel@tonic-gate 		show(argv[i], now, TRUE);
3220Sstevel@tonic-gate #endif
323*1138Srobbin 		warned = FALSE;
324*1138Srobbin 		t = absolute_min_time;
3250Sstevel@tonic-gate 		show(argv[i], t, TRUE);
3260Sstevel@tonic-gate 		t += SECSPERHOUR * HOURSPERDAY;
3270Sstevel@tonic-gate 		show(argv[i], t, TRUE);
328*1138Srobbin 		if (t < cutlotime)
329*1138Srobbin 			t = cutlotime;
330*1138Srobbin 		tmp = my_localtime(&t);
331*1138Srobbin 		if (tmp != NULL) {
332*1138Srobbin 			tm = *tmp;
333*1138Srobbin 			(void) strncpy(buf, abbr(&tm), sizeof (buf) - 1);
334*1138Srobbin 		}
3350Sstevel@tonic-gate 		for (;;) {
336*1138Srobbin 			if (t >= cuthitime)
3370Sstevel@tonic-gate 				break;
3380Sstevel@tonic-gate 			newt = t + SECSPERHOUR * 12;
339*1138Srobbin 			if (newt >= cuthitime)
3400Sstevel@tonic-gate 				break;
3410Sstevel@tonic-gate 			if (newt <= t)
3420Sstevel@tonic-gate 				break;
343*1138Srobbin 			newtmp = localtime(&newt);
344*1138Srobbin 			if (newtmp != NULL)
345*1138Srobbin 				newtm = *newtmp;
346*1138Srobbin 			if ((tmp == NULL || newtmp == NULL) ? (tmp != newtmp) :
347*1138Srobbin 				(delta(&newtm, &tm) != (newt - t) ||
3480Sstevel@tonic-gate 				newtm.tm_isdst != tm.tm_isdst ||
349*1138Srobbin 				strcmp(abbr(&newtm), buf) != 0)) {
3500Sstevel@tonic-gate 					newt = hunt(argv[i], t, newt);
351*1138Srobbin 					newtmp = localtime(&newt);
352*1138Srobbin 					if (newtmp != NULL) {
353*1138Srobbin 						newtm = *newtmp;
354*1138Srobbin 						(void) strncpy(buf,
355*1138Srobbin 							abbr(&newtm),
356*1138Srobbin 							sizeof (buf) - 1);
357*1138Srobbin 					}
3580Sstevel@tonic-gate 			}
3590Sstevel@tonic-gate 			t = newt;
3600Sstevel@tonic-gate 			tm = newtm;
361*1138Srobbin 			tmp = newtmp;
3620Sstevel@tonic-gate 		}
363*1138Srobbin 		t = absolute_max_time;
3640Sstevel@tonic-gate #if defined(sun)
3650Sstevel@tonic-gate 		show(argv[i], t, TRUE);
3660Sstevel@tonic-gate 		t -= SECSPERHOUR * HOURSPERDAY;
3670Sstevel@tonic-gate 		show(argv[i], t, TRUE);
3680Sstevel@tonic-gate #else /* !defined(sun) */
3690Sstevel@tonic-gate 		t -= SECSPERHOUR * HOURSPERDAY;
3700Sstevel@tonic-gate 		show(argv[i], t, TRUE);
3710Sstevel@tonic-gate 		t += SECSPERHOUR * HOURSPERDAY;
3720Sstevel@tonic-gate 		show(argv[i], t, TRUE);
3730Sstevel@tonic-gate #endif /* !defined(sun) */
3740Sstevel@tonic-gate 	}
3750Sstevel@tonic-gate 	if (fflush(stdout) || ferror(stdout)) {
376*1138Srobbin 		(void) fprintf(stderr, "%s: ", progname);
377*1138Srobbin 		(void) perror(gettext("Error writing standard output"));
378*1138Srobbin 		exit(EXIT_FAILURE);
3790Sstevel@tonic-gate 	}
3800Sstevel@tonic-gate 	return (EXIT_SUCCESS);
3810Sstevel@tonic-gate }
3820Sstevel@tonic-gate 
383*1138Srobbin static void
384*1138Srobbin setabsolutes()
385*1138Srobbin {
386*1138Srobbin #if defined(sun)
387*1138Srobbin 	absolute_min_time = LONG_MIN;
388*1138Srobbin 	absolute_max_time = LONG_MAX;
389*1138Srobbin #else
390*1138Srobbin 	if (0.5 == (time_t)0.5) {
391*1138Srobbin 		/*
392*1138Srobbin 		 * time_t is floating.
393*1138Srobbin 		 */
394*1138Srobbin 		if (sizeof (time_t) == sizeof (float)) {
395*1138Srobbin 			absolute_min_time = (time_t)-FLT_MAX;
396*1138Srobbin 			absolute_max_time = (time_t)FLT_MAX;
397*1138Srobbin 		} else if (sizeof (time_t) == sizeof (double)) {
398*1138Srobbin 			absolute_min_time = (time_t)-DBL_MAX;
399*1138Srobbin 			absolute_max_time = (time_t)DBL_MAX;
400*1138Srobbin 		} else {
401*1138Srobbin 			(void) fprintf(stderr, gettext("%s: use of -v on "
402*1138Srobbin 			    "system with floating time_t other than float "
403*1138Srobbin 			    "or double\n"), progname);
404*1138Srobbin 			exit(EXIT_FAILURE);
405*1138Srobbin 		}
406*1138Srobbin 	} else
407*1138Srobbin 	/*CONSTANTCONDITION*/
408*1138Srobbin 	if (0 > (time_t)-1) {
409*1138Srobbin 		/*
410*1138Srobbin 		 * time_t is signed.
411*1138Srobbin 		 */
412*1138Srobbin 		register time_t	hibit;
413*1138Srobbin 
414*1138Srobbin 		for (hibit = 1; (hibit * 2) != 0; hibit *= 2)
415*1138Srobbin 			continue;
416*1138Srobbin 		absolute_min_time = hibit;
417*1138Srobbin 		absolute_max_time = -(hibit + 1);
418*1138Srobbin 	} else {
419*1138Srobbin 		/*
420*1138Srobbin 		 * time_t is unsigned.
421*1138Srobbin 		 */
422*1138Srobbin 		absolute_min_time = 0;
423*1138Srobbin 		absolute_max_time = absolute_min_time - 1;
424*1138Srobbin 	}
425*1138Srobbin #endif
426*1138Srobbin }
427*1138Srobbin 
428*1138Srobbin static time_t
429*1138Srobbin yeartot(y)
430*1138Srobbin const long	y;
431*1138Srobbin {
432*1138Srobbin 	register long	myy;
433*1138Srobbin 	register long	seconds;
434*1138Srobbin 	register time_t	t;
435*1138Srobbin 
436*1138Srobbin 	myy = EPOCH_YEAR;
437*1138Srobbin 	t = 0;
438*1138Srobbin 	while (myy != y) {
439*1138Srobbin 		if (myy < y) {
440*1138Srobbin 			seconds = isleap(myy) ? SECSPERLYEAR : SECSPERNYEAR;
441*1138Srobbin 			++myy;
442*1138Srobbin 			if (t > absolute_max_time - seconds) {
443*1138Srobbin 				t = absolute_max_time;
444*1138Srobbin 				break;
445*1138Srobbin 			}
446*1138Srobbin 			t += seconds;
447*1138Srobbin 		} else {
448*1138Srobbin 			--myy;
449*1138Srobbin 			seconds = isleap(myy) ? SECSPERLYEAR : SECSPERNYEAR;
450*1138Srobbin 			if (t < absolute_min_time + seconds) {
451*1138Srobbin 				t = absolute_min_time;
452*1138Srobbin 				break;
453*1138Srobbin 			}
454*1138Srobbin 			t -= seconds;
455*1138Srobbin 		}
456*1138Srobbin 	}
457*1138Srobbin 	return (t);
458*1138Srobbin }
459*1138Srobbin 
4600Sstevel@tonic-gate static time_t
4610Sstevel@tonic-gate hunt(name, lot, hit)
462*1138Srobbin char	*name;
4630Sstevel@tonic-gate time_t	lot;
4640Sstevel@tonic-gate time_t	hit;
4650Sstevel@tonic-gate {
466*1138Srobbin 	time_t			t;
467*1138Srobbin 	long			diff;
468*1138Srobbin 	struct tm		lotm;
469*1138Srobbin 	register struct tm	*lotmp;
470*1138Srobbin 	struct tm		tm;
471*1138Srobbin 	register struct tm	*tmp;
472*1138Srobbin 	char			loab[MAX_STRING_LENGTH];
4730Sstevel@tonic-gate 
474*1138Srobbin 	lotmp = my_localtime(&lot);
475*1138Srobbin 	if (lotmp != NULL) {
476*1138Srobbin 		lotm = *lotmp;
477*1138Srobbin 		(void) strncpy(loab, abbr(&lotm), sizeof (loab) - 1);
478*1138Srobbin 	}
479*1138Srobbin 	for (;;) {
480*1138Srobbin 		diff = (long)(hit - lot);
481*1138Srobbin 		if (diff < 2)
482*1138Srobbin 			break;
483*1138Srobbin 		t = lot;
484*1138Srobbin 		t += diff / 2;
4850Sstevel@tonic-gate 		if (t <= lot)
4860Sstevel@tonic-gate 			++t;
4870Sstevel@tonic-gate 		else if (t >= hit)
4880Sstevel@tonic-gate 			--t;
489*1138Srobbin 		tmp = my_localtime(&t);
490*1138Srobbin 		if (tmp != NULL)
491*1138Srobbin 			tm = *tmp;
492*1138Srobbin 		if ((lotmp == NULL || tmp == NULL) ? (lotmp == tmp) :
493*1138Srobbin 			(delta(&tm, &lotm) == (t - lot) &&
4940Sstevel@tonic-gate 			tm.tm_isdst == lotm.tm_isdst &&
495*1138Srobbin 			strcmp(abbr(&tm), loab) == 0)) {
4960Sstevel@tonic-gate 				lot = t;
4970Sstevel@tonic-gate 				lotm = tm;
498*1138Srobbin 				lotmp = tmp;
4990Sstevel@tonic-gate 		} else	hit = t;
5000Sstevel@tonic-gate 	}
5010Sstevel@tonic-gate 	show(name, lot, TRUE);
5020Sstevel@tonic-gate 	show(name, hit, TRUE);
5030Sstevel@tonic-gate 	return (hit);
5040Sstevel@tonic-gate }
5050Sstevel@tonic-gate 
5060Sstevel@tonic-gate /*
5070Sstevel@tonic-gate  * Thanks to Paul Eggert (eggert@twinsun.com) for logic used in delta.
5080Sstevel@tonic-gate  */
5090Sstevel@tonic-gate 
5100Sstevel@tonic-gate static long
5110Sstevel@tonic-gate delta(newp, oldp)
512*1138Srobbin struct tm	*newp;
513*1138Srobbin struct tm	*oldp;
5140Sstevel@tonic-gate {
515*1138Srobbin 	register long	result;
516*1138Srobbin 	register int	tmy;
5170Sstevel@tonic-gate 
5180Sstevel@tonic-gate 	if (newp->tm_year < oldp->tm_year)
5190Sstevel@tonic-gate 		return (-delta(oldp, newp));
5200Sstevel@tonic-gate 	result = 0;
5210Sstevel@tonic-gate 	for (tmy = oldp->tm_year; tmy < newp->tm_year; ++tmy)
522*1138Srobbin 		result += DAYSPERNYEAR + isleap_sum(tmy, TM_YEAR_BASE);
5230Sstevel@tonic-gate 	result += newp->tm_yday - oldp->tm_yday;
5240Sstevel@tonic-gate 	result *= HOURSPERDAY;
5250Sstevel@tonic-gate 	result += newp->tm_hour - oldp->tm_hour;
5260Sstevel@tonic-gate 	result *= MINSPERHOUR;
5270Sstevel@tonic-gate 	result += newp->tm_min - oldp->tm_min;
5280Sstevel@tonic-gate 	result *= SECSPERMIN;
5290Sstevel@tonic-gate 	result += newp->tm_sec - oldp->tm_sec;
5300Sstevel@tonic-gate 	return (result);
5310Sstevel@tonic-gate }
5320Sstevel@tonic-gate 
5330Sstevel@tonic-gate static void
5340Sstevel@tonic-gate show(zone, t, v)
535*1138Srobbin char	*zone;
5360Sstevel@tonic-gate time_t	t;
5370Sstevel@tonic-gate int	v;
5380Sstevel@tonic-gate {
539*1138Srobbin 	register struct tm	*tmp;
5400Sstevel@tonic-gate 
5410Sstevel@tonic-gate 	(void) printf("%-*s  ", (int)longest, zone);
5420Sstevel@tonic-gate 	if (v) {
543*1138Srobbin 		tmp = gmtime(&t);
544*1138Srobbin 		if (tmp == NULL) {
545*1138Srobbin 			(void) printf(tformat(), t);
546*1138Srobbin 		} else {
547*1138Srobbin 			dumptime(tmp);
548*1138Srobbin 			(void) printf(" UTC");
549*1138Srobbin 		}
550*1138Srobbin 		(void) printf(" = ");
551*1138Srobbin 	}
552*1138Srobbin 	tmp = my_localtime(&t);
553*1138Srobbin 	dumptime(tmp);
554*1138Srobbin 	if (tmp != NULL) {
555*1138Srobbin 		if (*abbr(tmp) != '\0')
556*1138Srobbin 			(void) printf(" %s", abbr(tmp));
557*1138Srobbin 		if (v) {
558*1138Srobbin 			(void) printf(" isdst=%d", tmp->tm_isdst);
559*1138Srobbin #ifdef TM_GMTOFF
560*1138Srobbin 			(void) printf(" gmtoff=%ld", tmp->TM_GMTOFF);
561*1138Srobbin #endif /* defined TM_GMTOFF */
562*1138Srobbin 		}
5630Sstevel@tonic-gate 	}
5640Sstevel@tonic-gate 	(void) printf("\n");
565*1138Srobbin 	if (tmp != NULL && *abbr(tmp) != '\0')
566*1138Srobbin 		abbrok(abbr(tmp), zone);
5670Sstevel@tonic-gate }
5680Sstevel@tonic-gate 
5690Sstevel@tonic-gate static char *
5700Sstevel@tonic-gate abbr(tmp)
571*1138Srobbin struct tm	*tmp;
5720Sstevel@tonic-gate {
573*1138Srobbin 	register char	*result;
5740Sstevel@tonic-gate 	static char	nada;
5750Sstevel@tonic-gate 
5760Sstevel@tonic-gate 	if (tmp->tm_isdst != 0 && tmp->tm_isdst != 1)
5770Sstevel@tonic-gate 		return (&nada);
5780Sstevel@tonic-gate 	result = tzname[tmp->tm_isdst];
5790Sstevel@tonic-gate 	return ((result == NULL) ? &nada : result);
5800Sstevel@tonic-gate }
5810Sstevel@tonic-gate 
582*1138Srobbin /*
583*1138Srobbin  * The code below can fail on certain theoretical systems;
584*1138Srobbin  * it works on all known real-world systems as of 2004-12-30.
585*1138Srobbin  */
586*1138Srobbin 
587*1138Srobbin static const char *
588*1138Srobbin tformat()
589*1138Srobbin {
590*1138Srobbin #if defined(sun)
591*1138Srobbin 	/* time_t is signed long */
592*1138Srobbin 	return ("%ld");
593*1138Srobbin #else
594*1138Srobbin 	/*CONSTANTCONDITION*/
595*1138Srobbin 	if (0.5 == (time_t)0.5) {	/* floating */
596*1138Srobbin 		/*CONSTANTCONDITION*/
597*1138Srobbin 		if (sizeof (time_t) > sizeof (double))
598*1138Srobbin 			return ("%Lg");
599*1138Srobbin 		return ("%g");
600*1138Srobbin 	}
601*1138Srobbin 	/*CONSTANTCONDITION*/
602*1138Srobbin 	if (0 > (time_t)-1) {		/* signed */
603*1138Srobbin 		/*CONSTANTCONDITION*/
604*1138Srobbin 		if (sizeof (time_t) > sizeof (long))
605*1138Srobbin 			return ("%lld");
606*1138Srobbin 		/*CONSTANTCONDITION*/
607*1138Srobbin 		if (sizeof (time_t) > sizeof (int))
608*1138Srobbin 			return ("%ld");
609*1138Srobbin 		return ("%d");
610*1138Srobbin 	}
611*1138Srobbin 	/*CONSTANTCONDITION*/
612*1138Srobbin 	if (sizeof (time_t) > sizeof (unsigned long))
613*1138Srobbin 		return ("%llu");
614*1138Srobbin 	/*CONSTANTCONDITION*/
615*1138Srobbin 	if (sizeof (time_t) > sizeof (unsigned int))
616*1138Srobbin 		return ("%lu");
617*1138Srobbin 	return ("%u");
618*1138Srobbin #endif
619*1138Srobbin }
620*1138Srobbin 
6210Sstevel@tonic-gate static void
622*1138Srobbin dumptime(timeptr)
623*1138Srobbin register const struct tm	*timeptr;
624*1138Srobbin {
625*1138Srobbin 	static const char	wday_name[][3] = {
626*1138Srobbin 		"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
627*1138Srobbin 	};
628*1138Srobbin 	static const char	mon_name[][3] = {
629*1138Srobbin 		"Jan", "Feb", "Mar", "Apr", "May", "Jun",
630*1138Srobbin 		"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
631*1138Srobbin 	};
632*1138Srobbin 	register const char	*wn;
633*1138Srobbin 	register const char	*mn;
634*1138Srobbin 	register int		lead;
635*1138Srobbin 	register int		trail;
636*1138Srobbin 
637*1138Srobbin 	if (timeptr == NULL) {
638*1138Srobbin 		(void) printf("NULL");
639*1138Srobbin 		return;
640*1138Srobbin 	}
641*1138Srobbin 	/*
642*1138Srobbin 	 * The packaged versions of localtime and gmtime never put out-of-range
643*1138Srobbin 	 * values in tm_wday or tm_mon, but since this code might be compiled
644*1138Srobbin 	 * with other (perhaps experimental) versions, paranoia is in order.
645*1138Srobbin 	 */
646*1138Srobbin 	if (timeptr->tm_wday < 0 || timeptr->tm_wday >=
647*1138Srobbin 		(int)(sizeof (wday_name) / sizeof (wday_name[0])))
648*1138Srobbin 			wn = "???";
649*1138Srobbin 	else		wn = wday_name[timeptr->tm_wday];
650*1138Srobbin 	if (timeptr->tm_mon < 0 || timeptr->tm_mon >=
651*1138Srobbin 		(int)(sizeof (mon_name) / sizeof (mon_name[0])))
652*1138Srobbin 			mn = "???";
653*1138Srobbin 	else		mn = mon_name[timeptr->tm_mon];
654*1138Srobbin 	(void) printf("%.3s %.3s%3d %.2d:%.2d:%.2d ",
655*1138Srobbin 		wn, mn,
656*1138Srobbin 		timeptr->tm_mday, timeptr->tm_hour,
657*1138Srobbin 		timeptr->tm_min, timeptr->tm_sec);
658*1138Srobbin #define	DIVISOR	10
659*1138Srobbin 	trail = timeptr->tm_year % DIVISOR + TM_YEAR_BASE % DIVISOR;
660*1138Srobbin 	lead = timeptr->tm_year / DIVISOR + TM_YEAR_BASE / DIVISOR +
661*1138Srobbin 		trail / DIVISOR;
662*1138Srobbin 	trail %= DIVISOR;
663*1138Srobbin 	if (trail < 0 && lead > 0) {
664*1138Srobbin 		trail += DIVISOR;
665*1138Srobbin 		--lead;
666*1138Srobbin 	} else if (lead < 0 && trail > 0) {
667*1138Srobbin 		trail -= DIVISOR;
668*1138Srobbin 		++lead;
669*1138Srobbin 	}
670*1138Srobbin 	if (lead == 0)
671*1138Srobbin 		(void) printf("%d", trail);
672*1138Srobbin 	else
673*1138Srobbin 		(void) printf("%d%d", lead, ((trail < 0) ? -trail : trail));
674*1138Srobbin }
675*1138Srobbin 
676*1138Srobbin static void
677*1138Srobbin usage()
6780Sstevel@tonic-gate {
6790Sstevel@tonic-gate 	(void) fprintf(stderr, gettext(
680*1138Srobbin 	    "%s: [ --version ] [ -v ] [ -c [loyear,]hiyear ] zonename ...\n"),
681*1138Srobbin 		progname);
682*1138Srobbin 	exit(EXIT_FAILURE);
6830Sstevel@tonic-gate 	/* NOTREACHED */
6840Sstevel@tonic-gate }
685