xref: /onnv-gate/usr/src/cmd/zdump/zdump.c (revision 3196:5515489edfe7)
10Sstevel@tonic-gate /*
21442Srobbin  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
30Sstevel@tonic-gate  * Use is subject to license terms.
40Sstevel@tonic-gate  */
50Sstevel@tonic-gate 
61138Srobbin #pragma ident	"%Z%%M%	%I%	%E% SMI"
71138Srobbin 
80Sstevel@tonic-gate /*
90Sstevel@tonic-gate  * zdump 7.24
100Sstevel@tonic-gate  * Taken from elsie.nci.nih.gov to replace the existing Solaris zdump,
110Sstevel@tonic-gate  * which was based on an earlier version of the elsie code.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * For zdump 7.24, the following changes were made to the elsie code:
140Sstevel@tonic-gate  *   locale/textdomain/messages to match existing Solaris style.
150Sstevel@tonic-gate  *   Solaris verbose mode is documented to display the current time first.
160Sstevel@tonic-gate  *   cstyle cleaned code.
170Sstevel@tonic-gate  *   removed old locale/textdomain code.
180Sstevel@tonic-gate  */
190Sstevel@tonic-gate 
201442Srobbin static char	elsieid[] = "@(#)zdump.c	7.74";
210Sstevel@tonic-gate 
220Sstevel@tonic-gate /*
230Sstevel@tonic-gate  * This code has been made independent of the rest of the time
240Sstevel@tonic-gate  * conversion package to increase confidence in the verification it provides.
250Sstevel@tonic-gate  * You can use this code to help in verifying other implementations.
260Sstevel@tonic-gate  */
270Sstevel@tonic-gate 
280Sstevel@tonic-gate #include "stdio.h"	/* for stdout, stderr, perror */
290Sstevel@tonic-gate #include "string.h"	/* for strcpy */
300Sstevel@tonic-gate #include "sys/types.h"	/* for time_t */
310Sstevel@tonic-gate #include "time.h"	/* for struct tm */
320Sstevel@tonic-gate #include "stdlib.h"	/* for exit, malloc, atoi */
330Sstevel@tonic-gate #include "locale.h"	/* for setlocale, textdomain */
340Sstevel@tonic-gate #include "libintl.h"
351138Srobbin #include <ctype.h>
360Sstevel@tonic-gate #include "tzfile.h"	/* for defines */
371138Srobbin #include <limits.h>
381138Srobbin 
391138Srobbin #ifndef ZDUMP_LO_YEAR
401138Srobbin #define	ZDUMP_LO_YEAR	(-500)
411138Srobbin #endif /* !defined ZDUMP_LO_YEAR */
421138Srobbin 
431138Srobbin #ifndef ZDUMP_HI_YEAR
441138Srobbin #define	ZDUMP_HI_YEAR	2500
451138Srobbin #endif /* !defined ZDUMP_HI_YEAR */
460Sstevel@tonic-gate 
470Sstevel@tonic-gate #ifndef MAX_STRING_LENGTH
480Sstevel@tonic-gate #define	MAX_STRING_LENGTH	1024
490Sstevel@tonic-gate #endif /* !defined MAX_STRING_LENGTH */
500Sstevel@tonic-gate 
510Sstevel@tonic-gate #ifndef TRUE
520Sstevel@tonic-gate #define	TRUE		1
530Sstevel@tonic-gate #endif /* !defined TRUE */
540Sstevel@tonic-gate 
550Sstevel@tonic-gate #ifndef FALSE
560Sstevel@tonic-gate #define	FALSE		0
570Sstevel@tonic-gate #endif /* !defined FALSE */
580Sstevel@tonic-gate 
591138Srobbin #ifndef isleap_sum
601138Srobbin /*
611138Srobbin  * See tzfile.h for details on isleap_sum.
621138Srobbin  */
631138Srobbin #define	isleap_sum(a, b)	isleap((a) % 400 + (b) % 400)
641138Srobbin #endif /* !defined isleap_sum */
651138Srobbin 
661138Srobbin #ifndef SECSPERDAY
671138Srobbin #define	SECSPERDAY	((long)SECSPERHOUR * HOURSPERDAY)
681138Srobbin #endif
691138Srobbin #define	SECSPERNYEAR	(SECSPERDAY * DAYSPERNYEAR)
701138Srobbin #define	SECSPERLYEAR	(SECSPERNYEAR + SECSPERDAY)
711138Srobbin 
721138Srobbin #ifndef GNUC_or_lint
731138Srobbin #ifdef lint
741138Srobbin #define	GNUC_or_lint
751138Srobbin #else /* !defined lint */
761138Srobbin #ifdef __GNUC__
771138Srobbin #define	GNUC_or_lint
781138Srobbin #endif /* defined __GNUC__ */
791138Srobbin #endif /* !defined lint */
801138Srobbin #endif /* !defined GNUC_or_lint */
811138Srobbin 
820Sstevel@tonic-gate #ifndef INITIALIZE
831138Srobbin #ifdef	GNUC_or_lint
840Sstevel@tonic-gate #define	INITIALIZE(x)	((x) = 0)
851138Srobbin #else /* !defined GNUC_or_lint */
860Sstevel@tonic-gate #define	INITIALIZE(x)
871138Srobbin #endif /* !defined GNUC_or_lint */
880Sstevel@tonic-gate #endif /* !defined INITIALIZE */
890Sstevel@tonic-gate 
901138Srobbin static time_t	absolute_min_time;
911138Srobbin static time_t	absolute_max_time;
921138Srobbin static size_t	longest;
931138Srobbin static char	*progname;
941138Srobbin static int	warned;
950Sstevel@tonic-gate 
961138Srobbin static char	*abbr(struct tm *);
971138Srobbin static void	abbrok(const char *, const char *);
980Sstevel@tonic-gate static long	delta(struct tm *, struct tm *);
991138Srobbin static void	dumptime(const struct tm *);
1000Sstevel@tonic-gate static time_t	hunt(char *, time_t, time_t);
1011138Srobbin static void	setabsolutes(void);
1020Sstevel@tonic-gate static void	show(char *, time_t, int);
1031138Srobbin static void	usage(void);
1041138Srobbin static const char	*tformat(void);
1051138Srobbin static time_t	yeartot(long y);
1061138Srobbin 
1071138Srobbin #ifndef TYPECHECK
1081138Srobbin #define	my_localtime	localtime
1091138Srobbin #else /* !defined TYPECHECK */
1101138Srobbin static struct tm *
my_localtime(tp)1111138Srobbin my_localtime(tp)
1121138Srobbin time_t *tp;
1131138Srobbin {
1141138Srobbin 	register struct tm *tmp;
1151138Srobbin 
1161138Srobbin 	tmp = localtime(tp);
1171138Srobbin 	if (tp != NULL && tmp != NULL) {
1181138Srobbin 		struct tm	tm;
1191138Srobbin 		register time_t	t;
1201138Srobbin 
1211138Srobbin 		tm = *tmp;
1221138Srobbin 		t = mktime(&tm);
1231138Srobbin 		if (t - *tp >= 1 || *tp - t >= 1) {
1241138Srobbin 			(void) fflush(stdout);
1251138Srobbin 			(void) fprintf(stderr, "\n%s: ", progname);
1261138Srobbin 			(void) fprintf(stderr, tformat(), *tp);
1271138Srobbin 			(void) fprintf(stderr, " ->");
1281138Srobbin 			(void) fprintf(stderr, " year=%d", tmp->tm_year);
1291138Srobbin 			(void) fprintf(stderr, " mon=%d", tmp->tm_mon);
1301138Srobbin 			(void) fprintf(stderr, " mday=%d", tmp->tm_mday);
1311138Srobbin 			(void) fprintf(stderr, " hour=%d", tmp->tm_hour);
1321138Srobbin 			(void) fprintf(stderr, " min=%d", tmp->tm_min);
1331138Srobbin 			(void) fprintf(stderr, " sec=%d", tmp->tm_sec);
1341138Srobbin 			(void) fprintf(stderr, " isdst=%d", tmp->tm_isdst);
1351138Srobbin 			(void) fprintf(stderr, " -> ");
1361138Srobbin 			(void) fprintf(stderr, tformat(), t);
1371138Srobbin 			(void) fprintf(stderr, "\n");
1381138Srobbin 		}
1391138Srobbin 	}
1401138Srobbin 	return (tmp);
1411138Srobbin }
1421138Srobbin #endif /* !defined TYPECHECK */
1431138Srobbin 
1441138Srobbin static void
abbrok(abbrp,zone)1451138Srobbin abbrok(abbrp, zone)
1461138Srobbin const char * const	abbrp;
1471138Srobbin const char * const	zone;
1481138Srobbin {
1491138Srobbin 	register const char *cp;
1501138Srobbin 	int error = 0;
1511138Srobbin 
1521138Srobbin 	if (warned)
1531138Srobbin 		return;
1541138Srobbin 	cp = abbrp;
1551138Srobbin 	while (isascii(*cp) && isalpha((unsigned char)*cp))
1561138Srobbin 		++cp;
1571138Srobbin 	(void) fflush(stdout);
1581138Srobbin 	if (cp - abbrp == 0) {
1591138Srobbin 		/*
1601138Srobbin 		 * TRANSLATION_NOTE
1611138Srobbin 		 * The first %s prints for the program name (zdump),
1621138Srobbin 		 * the second %s prints the timezone name, the third
1631138Srobbin 		 * %s prints the timezone abbreviation (tzname[0] or
1641138Srobbin 		 * tzname[1]).
1651138Srobbin 		 */
1661138Srobbin 		(void) fprintf(stderr, gettext("%s: warning: zone \"%s\" "
1671138Srobbin 		    "abbreviation \"%s\" lacks alphabetic at start\n"),
1681138Srobbin 		    progname, zone, abbrp);
1691138Srobbin 		error = 1;
1701138Srobbin 	} else if (cp - abbrp < 3) {
1711138Srobbin 		(void) fprintf(stderr, gettext("%s: warning: zone \"%s\" "
1721138Srobbin 		    "abbreviation \"%s\" has fewer than 3 alphabetics\n"),
1731138Srobbin 		    progname, zone, abbrp);
1741138Srobbin 		error = 1;
1751138Srobbin 	} else if (cp - abbrp > 6) {
1761138Srobbin 		(void) fprintf(stderr, gettext("%s: warning: zone \"%s\" "
1771138Srobbin 		    "abbreviation \"%s\" has more than 6 alphabetics\n"),
1781138Srobbin 		    progname, zone, abbrp);
1791138Srobbin 		error = 1;
1801138Srobbin 	}
1811138Srobbin 	if (error == 0 && (*cp == '+' || *cp == '-')) {
1821138Srobbin 		++cp;
1831138Srobbin 		if (isascii(*cp) && isdigit((unsigned char)*cp))
1841138Srobbin 			if (*cp++ == '1' && *cp >= '0' && *cp <= '4')
1851138Srobbin 				++cp;
1861442Srobbin 		if (*cp != '\0') {
1871442Srobbin 			(void) fprintf(stderr, gettext("%s: warning: "
1881442Srobbin 			    "zone \"%s\" abbreviation \"%s\" differs from "
1891442Srobbin 			    "POSIX standard\n"), progname, zone, abbrp);
1901442Srobbin 			error = 1;
1911442Srobbin 		}
1921138Srobbin 	}
1931138Srobbin 	if (error)
1941138Srobbin 		warned = TRUE;
1951138Srobbin }
1960Sstevel@tonic-gate 
1970Sstevel@tonic-gate int
main(argc,argv)1980Sstevel@tonic-gate main(argc, argv)
1990Sstevel@tonic-gate int	argc;
2001138Srobbin char	*argv[];
2010Sstevel@tonic-gate {
2020Sstevel@tonic-gate 	register int		i;
2030Sstevel@tonic-gate 	register int		c;
2040Sstevel@tonic-gate 	register int		vflag;
2051138Srobbin 	register char		*cutarg;
2061138Srobbin 	register long		cutloyear = ZDUMP_LO_YEAR;
2071138Srobbin 	register long		cuthiyear = ZDUMP_HI_YEAR;
2081138Srobbin 	register time_t		cutlotime;
2091138Srobbin 	register time_t		cuthitime;
2100Sstevel@tonic-gate 	time_t			now;
2110Sstevel@tonic-gate 	time_t			t;
2120Sstevel@tonic-gate 	time_t			newt;
2130Sstevel@tonic-gate 	struct tm		tm;
2140Sstevel@tonic-gate 	struct tm		newtm;
2151138Srobbin 	register struct tm	*tmp;
2161138Srobbin 	register struct tm	*newtmp;
2170Sstevel@tonic-gate 
2181138Srobbin 	INITIALIZE(cutlotime);
2191138Srobbin 	INITIALIZE(cuthitime);
2200Sstevel@tonic-gate 
2210Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
2220Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)		/* Should be defined by cc -D */
2230Sstevel@tonic-gate #define	TEXT_DOMAIN	"SYS_TEST"	/* Use this only if it weren't */
2240Sstevel@tonic-gate #endif
2250Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
2260Sstevel@tonic-gate 
2270Sstevel@tonic-gate 	progname = argv[0];
2281138Srobbin 	for (i = 1; i < argc; ++i)
2291138Srobbin 		if (strcmp(argv[i], "--version") == 0) {
2301138Srobbin 			(void) printf("%s\n", elsieid);
2311138Srobbin 			exit(EXIT_SUCCESS);
2321138Srobbin 		}
2330Sstevel@tonic-gate 	vflag = 0;
2341138Srobbin 	cutarg = NULL;
2350Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "c:v")) == 'c' || c == 'v')
2360Sstevel@tonic-gate 		if (c == 'v')
2370Sstevel@tonic-gate 			vflag = 1;
2381138Srobbin 		else	cutarg = optarg;
2390Sstevel@tonic-gate 	if (c != EOF ||
2400Sstevel@tonic-gate 		(optind == argc - 1 && strcmp(argv[optind], "=") == 0)) {
2411138Srobbin 			usage();
2420Sstevel@tonic-gate 			/* NOTREACHED */
2430Sstevel@tonic-gate 	}
2441138Srobbin 	if (vflag) {
2451138Srobbin 		if (cutarg != NULL) {
2461138Srobbin 			long	lo;
2471138Srobbin 			long	hi;
2481138Srobbin 			char	dummy;
2490Sstevel@tonic-gate 
2501138Srobbin 			if (sscanf(cutarg, "%ld%c", &hi, &dummy) == 1) {
2511138Srobbin 				cuthiyear = hi;
2521138Srobbin 			} else if (sscanf(cutarg, "%ld,%ld%c",
2531138Srobbin 				&lo, &hi, &dummy) == 2) {
2541138Srobbin 					cutloyear = lo;
2551138Srobbin 					cuthiyear = hi;
2561138Srobbin 			} else {
2571138Srobbin (void) fprintf(stderr, gettext("%s: wild -c argument %s\n"),
2581138Srobbin 					progname, cutarg);
2591138Srobbin 				exit(EXIT_FAILURE);
2601138Srobbin 			}
2611138Srobbin 		}
2621138Srobbin 		setabsolutes();
2631138Srobbin 		cutlotime = yeartot(cutloyear);
2641138Srobbin 		cuthitime = yeartot(cuthiyear);
2650Sstevel@tonic-gate 	}
2660Sstevel@tonic-gate 	(void) time(&now);
2670Sstevel@tonic-gate 	longest = 0;
2680Sstevel@tonic-gate 	for (i = optind; i < argc; ++i)
2690Sstevel@tonic-gate 		if (strlen(argv[i]) > longest)
2700Sstevel@tonic-gate 			longest = strlen(argv[i]);
2710Sstevel@tonic-gate 
2720Sstevel@tonic-gate 	for (i = optind; i < argc; ++i) {
2730Sstevel@tonic-gate 		static char	buf[MAX_STRING_LENGTH];
2741138Srobbin 		static char	*tzp = NULL;
2750Sstevel@tonic-gate 
2761138Srobbin 		(void) unsetenv("TZ");
2771138Srobbin 		if (tzp != NULL)
2781138Srobbin 			free(tzp);
2791138Srobbin 		if ((tzp = malloc(3 + strlen(argv[i]) + 1)) == NULL) {
2801138Srobbin 			perror(progname);
2811138Srobbin 			exit(EXIT_FAILURE);
2821138Srobbin 		}
2831138Srobbin 		(void) strcpy(tzp, "TZ=");
2841138Srobbin 		(void) strcat(tzp, argv[i]);
2851138Srobbin 		if (putenv(tzp) != 0) {
2861138Srobbin 			perror(progname);
2871138Srobbin 			exit(EXIT_FAILURE);
2881138Srobbin 		}
2890Sstevel@tonic-gate 		if (!vflag) {
2900Sstevel@tonic-gate 			show(argv[i], now, FALSE);
2910Sstevel@tonic-gate 			continue;
2920Sstevel@tonic-gate 		}
2930Sstevel@tonic-gate 
2940Sstevel@tonic-gate #if defined(sun)
2950Sstevel@tonic-gate 		/*
2960Sstevel@tonic-gate 		 * We show the current time first, probably because we froze
2970Sstevel@tonic-gate 		 * the behavior of zdump some time ago and then it got
2980Sstevel@tonic-gate 		 * changed.
2990Sstevel@tonic-gate 		 */
3000Sstevel@tonic-gate 		show(argv[i], now, TRUE);
3010Sstevel@tonic-gate #endif
3021138Srobbin 		warned = FALSE;
3031138Srobbin 		t = absolute_min_time;
3040Sstevel@tonic-gate 		show(argv[i], t, TRUE);
3050Sstevel@tonic-gate 		t += SECSPERHOUR * HOURSPERDAY;
3060Sstevel@tonic-gate 		show(argv[i], t, TRUE);
3071138Srobbin 		if (t < cutlotime)
3081138Srobbin 			t = cutlotime;
3091138Srobbin 		tmp = my_localtime(&t);
3101138Srobbin 		if (tmp != NULL) {
3111138Srobbin 			tm = *tmp;
3121138Srobbin 			(void) strncpy(buf, abbr(&tm), sizeof (buf) - 1);
3131138Srobbin 		}
3140Sstevel@tonic-gate 		for (;;) {
3151138Srobbin 			if (t >= cuthitime)
3160Sstevel@tonic-gate 				break;
317*3196Srobbin 			/* check if newt will overrun maximum time_t value */
318*3196Srobbin 			if (t > LONG_MAX - (SECSPERHOUR * 12))
319*3196Srobbin 				break;
3200Sstevel@tonic-gate 			newt = t + SECSPERHOUR * 12;
3211138Srobbin 			if (newt >= cuthitime)
3220Sstevel@tonic-gate 				break;
3231138Srobbin 			newtmp = localtime(&newt);
3241138Srobbin 			if (newtmp != NULL)
3251138Srobbin 				newtm = *newtmp;
3261138Srobbin 			if ((tmp == NULL || newtmp == NULL) ? (tmp != newtmp) :
3271138Srobbin 				(delta(&newtm, &tm) != (newt - t) ||
3280Sstevel@tonic-gate 				newtm.tm_isdst != tm.tm_isdst ||
3291138Srobbin 				strcmp(abbr(&newtm), buf) != 0)) {
3300Sstevel@tonic-gate 					newt = hunt(argv[i], t, newt);
3311138Srobbin 					newtmp = localtime(&newt);
3321138Srobbin 					if (newtmp != NULL) {
3331138Srobbin 						newtm = *newtmp;
3341138Srobbin 						(void) strncpy(buf,
3351138Srobbin 							abbr(&newtm),
3361138Srobbin 							sizeof (buf) - 1);
3371138Srobbin 					}
3380Sstevel@tonic-gate 			}
3390Sstevel@tonic-gate 			t = newt;
3400Sstevel@tonic-gate 			tm = newtm;
3411138Srobbin 			tmp = newtmp;
3420Sstevel@tonic-gate 		}
3431138Srobbin 		t = absolute_max_time;
3440Sstevel@tonic-gate #if defined(sun)
3450Sstevel@tonic-gate 		show(argv[i], t, TRUE);
3460Sstevel@tonic-gate 		t -= SECSPERHOUR * HOURSPERDAY;
3470Sstevel@tonic-gate 		show(argv[i], t, TRUE);
3480Sstevel@tonic-gate #else /* !defined(sun) */
3490Sstevel@tonic-gate 		t -= SECSPERHOUR * HOURSPERDAY;
3500Sstevel@tonic-gate 		show(argv[i], t, TRUE);
3510Sstevel@tonic-gate 		t += SECSPERHOUR * HOURSPERDAY;
3520Sstevel@tonic-gate 		show(argv[i], t, TRUE);
3530Sstevel@tonic-gate #endif /* !defined(sun) */
3540Sstevel@tonic-gate 	}
3550Sstevel@tonic-gate 	if (fflush(stdout) || ferror(stdout)) {
3561138Srobbin 		(void) fprintf(stderr, "%s: ", progname);
3571138Srobbin 		(void) perror(gettext("Error writing standard output"));
3581138Srobbin 		exit(EXIT_FAILURE);
3590Sstevel@tonic-gate 	}
3600Sstevel@tonic-gate 	return (EXIT_SUCCESS);
3610Sstevel@tonic-gate }
3620Sstevel@tonic-gate 
3631138Srobbin static void
setabsolutes()3641138Srobbin setabsolutes()
3651138Srobbin {
3661138Srobbin #if defined(sun)
3671138Srobbin 	absolute_min_time = LONG_MIN;
3681138Srobbin 	absolute_max_time = LONG_MAX;
3691138Srobbin #else
3701138Srobbin 	if (0.5 == (time_t)0.5) {
3711138Srobbin 		/*
3721138Srobbin 		 * time_t is floating.
3731138Srobbin 		 */
3741138Srobbin 		if (sizeof (time_t) == sizeof (float)) {
3751138Srobbin 			absolute_min_time = (time_t)-FLT_MAX;
3761138Srobbin 			absolute_max_time = (time_t)FLT_MAX;
3771138Srobbin 		} else if (sizeof (time_t) == sizeof (double)) {
3781138Srobbin 			absolute_min_time = (time_t)-DBL_MAX;
3791138Srobbin 			absolute_max_time = (time_t)DBL_MAX;
3801138Srobbin 		} else {
3811138Srobbin 			(void) fprintf(stderr, gettext("%s: use of -v on "
3821138Srobbin 			    "system with floating time_t other than float "
3831138Srobbin 			    "or double\n"), progname);
3841138Srobbin 			exit(EXIT_FAILURE);
3851138Srobbin 		}
3861138Srobbin 	} else
3871138Srobbin 	/*CONSTANTCONDITION*/
3881138Srobbin 	if (0 > (time_t)-1) {
3891138Srobbin 		/*
3901138Srobbin 		 * time_t is signed.
3911138Srobbin 		 */
3921138Srobbin 		register time_t	hibit;
3931138Srobbin 
3941138Srobbin 		for (hibit = 1; (hibit * 2) != 0; hibit *= 2)
3951138Srobbin 			continue;
3961138Srobbin 		absolute_min_time = hibit;
3971138Srobbin 		absolute_max_time = -(hibit + 1);
3981138Srobbin 	} else {
3991138Srobbin 		/*
4001138Srobbin 		 * time_t is unsigned.
4011138Srobbin 		 */
4021138Srobbin 		absolute_min_time = 0;
4031138Srobbin 		absolute_max_time = absolute_min_time - 1;
4041138Srobbin 	}
4051138Srobbin #endif
4061138Srobbin }
4071138Srobbin 
4081138Srobbin static time_t
yeartot(y)4091138Srobbin yeartot(y)
4101138Srobbin const long	y;
4111138Srobbin {
4121138Srobbin 	register long	myy;
4131138Srobbin 	register long	seconds;
4141138Srobbin 	register time_t	t;
4151138Srobbin 
4161138Srobbin 	myy = EPOCH_YEAR;
4171138Srobbin 	t = 0;
4181138Srobbin 	while (myy != y) {
4191138Srobbin 		if (myy < y) {
4201138Srobbin 			seconds = isleap(myy) ? SECSPERLYEAR : SECSPERNYEAR;
4211138Srobbin 			++myy;
4221138Srobbin 			if (t > absolute_max_time - seconds) {
4231138Srobbin 				t = absolute_max_time;
4241138Srobbin 				break;
4251138Srobbin 			}
4261138Srobbin 			t += seconds;
4271138Srobbin 		} else {
4281138Srobbin 			--myy;
4291138Srobbin 			seconds = isleap(myy) ? SECSPERLYEAR : SECSPERNYEAR;
4301138Srobbin 			if (t < absolute_min_time + seconds) {
4311138Srobbin 				t = absolute_min_time;
4321138Srobbin 				break;
4331138Srobbin 			}
4341138Srobbin 			t -= seconds;
4351138Srobbin 		}
4361138Srobbin 	}
4371138Srobbin 	return (t);
4381138Srobbin }
4391138Srobbin 
4400Sstevel@tonic-gate static time_t
hunt(name,lot,hit)4410Sstevel@tonic-gate hunt(name, lot, hit)
4421138Srobbin char	*name;
4430Sstevel@tonic-gate time_t	lot;
4440Sstevel@tonic-gate time_t	hit;
4450Sstevel@tonic-gate {
4461138Srobbin 	time_t			t;
4471138Srobbin 	long			diff;
4481138Srobbin 	struct tm		lotm;
4491138Srobbin 	register struct tm	*lotmp;
4501138Srobbin 	struct tm		tm;
4511138Srobbin 	register struct tm	*tmp;
4521138Srobbin 	char			loab[MAX_STRING_LENGTH];
4530Sstevel@tonic-gate 
4541138Srobbin 	lotmp = my_localtime(&lot);
4551138Srobbin 	if (lotmp != NULL) {
4561138Srobbin 		lotm = *lotmp;
4571138Srobbin 		(void) strncpy(loab, abbr(&lotm), sizeof (loab) - 1);
4581138Srobbin 	}
4591138Srobbin 	for (;;) {
4601138Srobbin 		diff = (long)(hit - lot);
4611138Srobbin 		if (diff < 2)
4621138Srobbin 			break;
4631138Srobbin 		t = lot;
4641138Srobbin 		t += diff / 2;
4650Sstevel@tonic-gate 		if (t <= lot)
4660Sstevel@tonic-gate 			++t;
4670Sstevel@tonic-gate 		else if (t >= hit)
4680Sstevel@tonic-gate 			--t;
4691138Srobbin 		tmp = my_localtime(&t);
4701138Srobbin 		if (tmp != NULL)
4711138Srobbin 			tm = *tmp;
4721138Srobbin 		if ((lotmp == NULL || tmp == NULL) ? (lotmp == tmp) :
4731138Srobbin 			(delta(&tm, &lotm) == (t - lot) &&
4740Sstevel@tonic-gate 			tm.tm_isdst == lotm.tm_isdst &&
4751138Srobbin 			strcmp(abbr(&tm), loab) == 0)) {
4760Sstevel@tonic-gate 				lot = t;
4770Sstevel@tonic-gate 				lotm = tm;
4781138Srobbin 				lotmp = tmp;
4790Sstevel@tonic-gate 		} else	hit = t;
4800Sstevel@tonic-gate 	}
4810Sstevel@tonic-gate 	show(name, lot, TRUE);
4820Sstevel@tonic-gate 	show(name, hit, TRUE);
4830Sstevel@tonic-gate 	return (hit);
4840Sstevel@tonic-gate }
4850Sstevel@tonic-gate 
4860Sstevel@tonic-gate /*
4871442Srobbin  * Thanks to Paul Eggert for logic used in delta.
4880Sstevel@tonic-gate  */
4890Sstevel@tonic-gate 
4900Sstevel@tonic-gate static long
delta(newp,oldp)4910Sstevel@tonic-gate delta(newp, oldp)
4921138Srobbin struct tm	*newp;
4931138Srobbin struct tm	*oldp;
4940Sstevel@tonic-gate {
4951138Srobbin 	register long	result;
4961138Srobbin 	register int	tmy;
4970Sstevel@tonic-gate 
4980Sstevel@tonic-gate 	if (newp->tm_year < oldp->tm_year)
4990Sstevel@tonic-gate 		return (-delta(oldp, newp));
5000Sstevel@tonic-gate 	result = 0;
5010Sstevel@tonic-gate 	for (tmy = oldp->tm_year; tmy < newp->tm_year; ++tmy)
5021138Srobbin 		result += DAYSPERNYEAR + isleap_sum(tmy, TM_YEAR_BASE);
5030Sstevel@tonic-gate 	result += newp->tm_yday - oldp->tm_yday;
5040Sstevel@tonic-gate 	result *= HOURSPERDAY;
5050Sstevel@tonic-gate 	result += newp->tm_hour - oldp->tm_hour;
5060Sstevel@tonic-gate 	result *= MINSPERHOUR;
5070Sstevel@tonic-gate 	result += newp->tm_min - oldp->tm_min;
5080Sstevel@tonic-gate 	result *= SECSPERMIN;
5090Sstevel@tonic-gate 	result += newp->tm_sec - oldp->tm_sec;
5100Sstevel@tonic-gate 	return (result);
5110Sstevel@tonic-gate }
5120Sstevel@tonic-gate 
5130Sstevel@tonic-gate static void
show(zone,t,v)5140Sstevel@tonic-gate show(zone, t, v)
5151138Srobbin char	*zone;
5160Sstevel@tonic-gate time_t	t;
5170Sstevel@tonic-gate int	v;
5180Sstevel@tonic-gate {
5191138Srobbin 	register struct tm	*tmp;
5200Sstevel@tonic-gate 
5210Sstevel@tonic-gate 	(void) printf("%-*s  ", (int)longest, zone);
5220Sstevel@tonic-gate 	if (v) {
5231138Srobbin 		tmp = gmtime(&t);
5241138Srobbin 		if (tmp == NULL) {
5251138Srobbin 			(void) printf(tformat(), t);
5261138Srobbin 		} else {
5271138Srobbin 			dumptime(tmp);
5281138Srobbin 			(void) printf(" UTC");
5291138Srobbin 		}
5301138Srobbin 		(void) printf(" = ");
5311138Srobbin 	}
5321138Srobbin 	tmp = my_localtime(&t);
5331138Srobbin 	dumptime(tmp);
5341138Srobbin 	if (tmp != NULL) {
5351138Srobbin 		if (*abbr(tmp) != '\0')
5361138Srobbin 			(void) printf(" %s", abbr(tmp));
5371138Srobbin 		if (v) {
5381138Srobbin 			(void) printf(" isdst=%d", tmp->tm_isdst);
5391138Srobbin #ifdef TM_GMTOFF
5401138Srobbin 			(void) printf(" gmtoff=%ld", tmp->TM_GMTOFF);
5411138Srobbin #endif /* defined TM_GMTOFF */
5421138Srobbin 		}
5430Sstevel@tonic-gate 	}
5440Sstevel@tonic-gate 	(void) printf("\n");
5451138Srobbin 	if (tmp != NULL && *abbr(tmp) != '\0')
5461138Srobbin 		abbrok(abbr(tmp), zone);
5470Sstevel@tonic-gate }
5480Sstevel@tonic-gate 
5490Sstevel@tonic-gate static char *
abbr(tmp)5500Sstevel@tonic-gate abbr(tmp)
5511138Srobbin struct tm	*tmp;
5520Sstevel@tonic-gate {
5531138Srobbin 	register char	*result;
5540Sstevel@tonic-gate 	static char	nada;
5550Sstevel@tonic-gate 
5560Sstevel@tonic-gate 	if (tmp->tm_isdst != 0 && tmp->tm_isdst != 1)
5570Sstevel@tonic-gate 		return (&nada);
5580Sstevel@tonic-gate 	result = tzname[tmp->tm_isdst];
5590Sstevel@tonic-gate 	return ((result == NULL) ? &nada : result);
5600Sstevel@tonic-gate }
5610Sstevel@tonic-gate 
5621138Srobbin /*
5631138Srobbin  * The code below can fail on certain theoretical systems;
5641138Srobbin  * it works on all known real-world systems as of 2004-12-30.
5651138Srobbin  */
5661138Srobbin 
5671138Srobbin static const char *
tformat()5681138Srobbin tformat()
5691138Srobbin {
5701138Srobbin #if defined(sun)
5711138Srobbin 	/* time_t is signed long */
5721138Srobbin 	return ("%ld");
5731138Srobbin #else
5741138Srobbin 	/*CONSTANTCONDITION*/
5751138Srobbin 	if (0.5 == (time_t)0.5) {	/* floating */
5761138Srobbin 		/*CONSTANTCONDITION*/
5771138Srobbin 		if (sizeof (time_t) > sizeof (double))
5781138Srobbin 			return ("%Lg");
5791138Srobbin 		return ("%g");
5801138Srobbin 	}
5811138Srobbin 	/*CONSTANTCONDITION*/
5821138Srobbin 	if (0 > (time_t)-1) {		/* signed */
5831138Srobbin 		/*CONSTANTCONDITION*/
5841138Srobbin 		if (sizeof (time_t) > sizeof (long))
5851138Srobbin 			return ("%lld");
5861138Srobbin 		/*CONSTANTCONDITION*/
5871138Srobbin 		if (sizeof (time_t) > sizeof (int))
5881138Srobbin 			return ("%ld");
5891138Srobbin 		return ("%d");
5901138Srobbin 	}
5911138Srobbin 	/*CONSTANTCONDITION*/
5921138Srobbin 	if (sizeof (time_t) > sizeof (unsigned long))
5931138Srobbin 		return ("%llu");
5941138Srobbin 	/*CONSTANTCONDITION*/
5951138Srobbin 	if (sizeof (time_t) > sizeof (unsigned int))
5961138Srobbin 		return ("%lu");
5971138Srobbin 	return ("%u");
5981138Srobbin #endif
5991138Srobbin }
6001138Srobbin 
6010Sstevel@tonic-gate static void
dumptime(timeptr)6021138Srobbin dumptime(timeptr)
6031138Srobbin register const struct tm	*timeptr;
6041138Srobbin {
6051138Srobbin 	static const char	wday_name[][3] = {
6061138Srobbin 		"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
6071138Srobbin 	};
6081138Srobbin 	static const char	mon_name[][3] = {
6091138Srobbin 		"Jan", "Feb", "Mar", "Apr", "May", "Jun",
6101138Srobbin 		"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
6111138Srobbin 	};
6121138Srobbin 	register const char	*wn;
6131138Srobbin 	register const char	*mn;
6141138Srobbin 	register int		lead;
6151138Srobbin 	register int		trail;
6161138Srobbin 
6171138Srobbin 	if (timeptr == NULL) {
6181138Srobbin 		(void) printf("NULL");
6191138Srobbin 		return;
6201138Srobbin 	}
6211138Srobbin 	/*
6221138Srobbin 	 * The packaged versions of localtime and gmtime never put out-of-range
6231138Srobbin 	 * values in tm_wday or tm_mon, but since this code might be compiled
6241138Srobbin 	 * with other (perhaps experimental) versions, paranoia is in order.
6251138Srobbin 	 */
6261138Srobbin 	if (timeptr->tm_wday < 0 || timeptr->tm_wday >=
6271138Srobbin 		(int)(sizeof (wday_name) / sizeof (wday_name[0])))
6281138Srobbin 			wn = "???";
6291138Srobbin 	else		wn = wday_name[timeptr->tm_wday];
6301138Srobbin 	if (timeptr->tm_mon < 0 || timeptr->tm_mon >=
6311138Srobbin 		(int)(sizeof (mon_name) / sizeof (mon_name[0])))
6321138Srobbin 			mn = "???";
6331138Srobbin 	else		mn = mon_name[timeptr->tm_mon];
6341138Srobbin 	(void) printf("%.3s %.3s%3d %.2d:%.2d:%.2d ",
6351138Srobbin 		wn, mn,
6361138Srobbin 		timeptr->tm_mday, timeptr->tm_hour,
6371138Srobbin 		timeptr->tm_min, timeptr->tm_sec);
6381138Srobbin #define	DIVISOR	10
6391138Srobbin 	trail = timeptr->tm_year % DIVISOR + TM_YEAR_BASE % DIVISOR;
6401138Srobbin 	lead = timeptr->tm_year / DIVISOR + TM_YEAR_BASE / DIVISOR +
6411138Srobbin 		trail / DIVISOR;
6421138Srobbin 	trail %= DIVISOR;
6431138Srobbin 	if (trail < 0 && lead > 0) {
6441138Srobbin 		trail += DIVISOR;
6451138Srobbin 		--lead;
6461138Srobbin 	} else if (lead < 0 && trail > 0) {
6471138Srobbin 		trail -= DIVISOR;
6481138Srobbin 		++lead;
6491138Srobbin 	}
6501138Srobbin 	if (lead == 0)
6511138Srobbin 		(void) printf("%d", trail);
6521138Srobbin 	else
6531138Srobbin 		(void) printf("%d%d", lead, ((trail < 0) ? -trail : trail));
6541138Srobbin }
6551138Srobbin 
6561138Srobbin static void
usage()6571138Srobbin usage()
6580Sstevel@tonic-gate {
6590Sstevel@tonic-gate 	(void) fprintf(stderr, gettext(
6601138Srobbin 	    "%s: [ --version ] [ -v ] [ -c [loyear,]hiyear ] zonename ...\n"),
6611138Srobbin 		progname);
6621138Srobbin 	exit(EXIT_FAILURE);
6630Sstevel@tonic-gate 	/* NOTREACHED */
6640Sstevel@tonic-gate }
665