 2fe8fb192f
			
		
	
	
		2fe8fb192f
		
	
	
	
	
		
			
			There is important information about booting non-ack images in docs/UPDATING. ack/aout-format images can't be built any more, and booting clang/ELF-format ones is a little different. Updating to the new boot monitor is recommended. Changes in this commit: . drop boot monitor -> allowing dropping ack support . facility to copy ELF boot files to /boot so that old boot monitor can still boot fairly easily, see UPDATING . no more ack-format libraries -> single-case libraries . some cleanup of OBJECT_FMT, COMPILER_TYPE, etc cases . drop several ack toolchain commands, but not all support commands (e.g. aal is gone but acksize is not yet). . a few libc files moved to netbsd libc dir . new /bin/date as minix date used code in libc/ . test compile fix . harmonize includes . /usr/lib is no longer special: without ack, /usr/lib plays no kind of special bootstrapping role any more and bootstrapping is done exclusively through packages, so releases depend even less on the state of the machine making them now. . rename nbsd_lib* to lib* . reduce mtree
		
			
				
	
	
		
			686 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			686 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*	$NetBSD: zdump.c,v 1.19 2011/01/15 12:31:57 martin Exp $	*/
 | |
| /*
 | |
| ** This file is in the public domain, so clarified as of
 | |
| ** 2009-05-17 by Arthur David Olson.
 | |
| */
 | |
| 
 | |
| #include <sys/cdefs.h>
 | |
| #ifndef lint
 | |
| #ifndef NOID
 | |
| __RCSID("$NetBSD: zdump.c,v 1.19 2011/01/15 12:31:57 martin Exp $");
 | |
| #endif /* !defined NOID */
 | |
| #endif /* !defined lint */
 | |
| 
 | |
| static char	elsieid[] = "@(#)zdump.c	8.9";
 | |
| 
 | |
| /*
 | |
| ** This code has been made independent of the rest of the time
 | |
| ** conversion package to increase confidence in the verification it provides.
 | |
| ** You can use this code to help in verifying other implementations.
 | |
| */
 | |
| 
 | |
| #include "stdio.h"	/* for stdout, stderr */
 | |
| #include "string.h"	/* for strcpy */
 | |
| #include "sys/types.h"	/* for time_t */
 | |
| #include "time.h"	/* for struct tm */
 | |
| #include "stdlib.h"	/* for exit, malloc, atoi */
 | |
| #include <err.h>
 | |
| #include "float.h"	/* for FLT_MAX and DBL_MAX */
 | |
| #include "ctype.h"	/* for isalpha et al. */
 | |
| #ifndef isascii
 | |
| #define isascii(x) 1
 | |
| #endif /* !defined isascii */
 | |
| 
 | |
| #ifndef ZDUMP_LO_YEAR
 | |
| #define ZDUMP_LO_YEAR	(-500)
 | |
| #endif /* !defined ZDUMP_LO_YEAR */
 | |
| 
 | |
| #ifndef ZDUMP_HI_YEAR
 | |
| #define ZDUMP_HI_YEAR	2500
 | |
| #endif /* !defined ZDUMP_HI_YEAR */
 | |
| 
 | |
| #ifndef MAX_STRING_LENGTH
 | |
| #define MAX_STRING_LENGTH	1024
 | |
| #endif /* !defined MAX_STRING_LENGTH */
 | |
| 
 | |
| #ifndef TRUE
 | |
| #define TRUE		1
 | |
| #endif /* !defined TRUE */
 | |
| 
 | |
| #ifndef FALSE
 | |
| #define FALSE		0
 | |
| #endif /* !defined FALSE */
 | |
| 
 | |
| #ifndef EXIT_SUCCESS
 | |
| #define EXIT_SUCCESS	0
 | |
| #endif /* !defined EXIT_SUCCESS */
 | |
| 
 | |
| #ifndef EXIT_FAILURE
 | |
| #define EXIT_FAILURE	1
 | |
| #endif /* !defined EXIT_FAILURE */
 | |
| 
 | |
| #ifndef SECSPERMIN
 | |
| #define SECSPERMIN	60
 | |
| #endif /* !defined SECSPERMIN */
 | |
| 
 | |
| #ifndef MINSPERHOUR
 | |
| #define MINSPERHOUR	60
 | |
| #endif /* !defined MINSPERHOUR */
 | |
| 
 | |
| #ifndef SECSPERHOUR
 | |
| #define SECSPERHOUR	(SECSPERMIN * MINSPERHOUR)
 | |
| #endif /* !defined SECSPERHOUR */
 | |
| 
 | |
| #ifndef HOURSPERDAY
 | |
| #define HOURSPERDAY	24
 | |
| #endif /* !defined HOURSPERDAY */
 | |
| 
 | |
| #ifndef EPOCH_YEAR
 | |
| #define EPOCH_YEAR	1970
 | |
| #endif /* !defined EPOCH_YEAR */
 | |
| 
 | |
| #ifndef TM_YEAR_BASE
 | |
| #define TM_YEAR_BASE	1900
 | |
| #endif /* !defined TM_YEAR_BASE */
 | |
| 
 | |
| #ifndef DAYSPERNYEAR
 | |
| #define DAYSPERNYEAR	365
 | |
| #endif /* !defined DAYSPERNYEAR */
 | |
| 
 | |
| #ifndef isleap
 | |
| #define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0))
 | |
| #endif /* !defined isleap */
 | |
| 
 | |
| #ifndef isleap_sum
 | |
| /*
 | |
| ** See tzfile.h for details on isleap_sum.
 | |
| */
 | |
| #define isleap_sum(a, b)	isleap((a) % 400 + (b) % 400)
 | |
| #endif /* !defined isleap_sum */
 | |
| 
 | |
| #define SECSPERDAY	((long) SECSPERHOUR * HOURSPERDAY)
 | |
| #define SECSPERNYEAR	(SECSPERDAY * DAYSPERNYEAR)
 | |
| #define SECSPERLYEAR	(SECSPERNYEAR + SECSPERDAY)
 | |
| 
 | |
| #ifndef HAVE_GETTEXT
 | |
| #define HAVE_GETTEXT 0
 | |
| #endif
 | |
| #if HAVE_GETTEXT
 | |
| #include "locale.h"	/* for setlocale */
 | |
| #include "libintl.h"
 | |
| #endif /* HAVE_GETTEXT */
 | |
| 
 | |
| #ifndef GNUC_or_lint
 | |
| #ifdef lint
 | |
| #define GNUC_or_lint
 | |
| #else /* !defined lint */
 | |
| #ifdef __GNUC__
 | |
| #define GNUC_or_lint
 | |
| #endif /* defined __GNUC__ */
 | |
| #endif /* !defined lint */
 | |
| #endif /* !defined GNUC_or_lint */
 | |
| 
 | |
| #ifndef INITIALIZE
 | |
| #ifdef GNUC_or_lint
 | |
| #define INITIALIZE(x)	((x) = 0)
 | |
| #else /* !defined GNUC_or_lint */
 | |
| #define INITIALIZE(x)
 | |
| #endif /* !defined GNUC_or_lint */
 | |
| #endif /* !defined INITIALIZE */
 | |
| 
 | |
| /*
 | |
| ** For the benefit of GNU folk...
 | |
| ** `_(MSGID)' uses the current locale's message library string for MSGID.
 | |
| ** The default is to use gettext if available, and use MSGID otherwise.
 | |
| */
 | |
| 
 | |
| #ifndef _
 | |
| #if HAVE_GETTEXT
 | |
| #define _(msgid) gettext(msgid)
 | |
| #else /* !HAVE_GETTEXT */
 | |
| #define _(msgid) __UNCONST(msgid)
 | |
| #endif /* !HAVE_GETTEXT */
 | |
| #endif /* !defined _ */
 | |
| 
 | |
| #ifndef TZ_DOMAIN
 | |
| #define TZ_DOMAIN "tz"
 | |
| #endif /* !defined TZ_DOMAIN */
 | |
| 
 | |
| extern char **	environ;
 | |
| extern int	getopt(int argc, char * const argv[],
 | |
| 			const char * options);
 | |
| extern char *	optarg;
 | |
| extern int	optind;
 | |
| 
 | |
| static time_t	absolute_min_time;
 | |
| static time_t	absolute_max_time;
 | |
| static size_t	longest;
 | |
| static char *	progname;
 | |
| static int	warned;
 | |
| 
 | |
| static const char *	abbr(struct tm * tmp);
 | |
| static void	abbrok(const char * abbrp, const char * zone);
 | |
| static long	delta(struct tm * newp, struct tm * oldp);
 | |
| static void	dumptime(const struct tm * tmp);
 | |
| static time_t	hunt(char * name, time_t lot, time_t	hit);
 | |
| int		main(int, char **);
 | |
| static void	setabsolutes(void);
 | |
| static void	show(char * zone, time_t t, int v);
 | |
| static const char *	tformat(void);
 | |
| static time_t	yeartot(long y);
 | |
| 
 | |
| #ifndef TYPECHECK
 | |
| #define my_localtime	localtime
 | |
| #else /* !defined TYPECHECK */
 | |
| static struct tm *
 | |
| my_localtime(tp)
 | |
| time_t *	tp;
 | |
| {
 | |
| 	register struct tm *	tmp;
 | |
| 
 | |
| 	tmp = localtime(tp);
 | |
| 	if (tp != NULL && tmp != NULL) {
 | |
| 		struct tm	tm;
 | |
| 		register time_t	t;
 | |
| 
 | |
| 		tm = *tmp;
 | |
| 		t = mktime(&tm);
 | |
| 		if (t - *tp >= 1 || *tp - t >= 1) {
 | |
| 			(void) fflush(stdout);
 | |
| 			(void) fprintf(stderr, "\n%s: ", progname);
 | |
| 			(void) fprintf(stderr, tformat(), *tp);
 | |
| 			(void) fprintf(stderr, " ->");
 | |
| 			(void) fprintf(stderr, " year=%d", tmp->tm_year);
 | |
| 			(void) fprintf(stderr, " mon=%d", tmp->tm_mon);
 | |
| 			(void) fprintf(stderr, " mday=%d", tmp->tm_mday);
 | |
| 			(void) fprintf(stderr, " hour=%d", tmp->tm_hour);
 | |
| 			(void) fprintf(stderr, " min=%d", tmp->tm_min);
 | |
| 			(void) fprintf(stderr, " sec=%d", tmp->tm_sec);
 | |
| 			(void) fprintf(stderr, " isdst=%d", tmp->tm_isdst);
 | |
| 			(void) fprintf(stderr, " -> ");
 | |
| 			(void) fprintf(stderr, tformat(), t);
 | |
| 			(void) fprintf(stderr, "\n");
 | |
| 		}
 | |
| 	}
 | |
| 	return tmp;
 | |
| }
 | |
| #endif /* !defined TYPECHECK */
 | |
| 
 | |
| static void
 | |
| abbrok(abbrp, zone)
 | |
| const char * const	abbrp;
 | |
| const char * const	zone;
 | |
| {
 | |
| 	register const char *	cp;
 | |
| 	register char *		wp;
 | |
| 
 | |
| 	if (warned)
 | |
| 		return;
 | |
| 	cp = abbrp;
 | |
| 	wp = NULL;
 | |
| 	while (isascii((unsigned char) *cp) && isalpha((unsigned char) *cp))
 | |
| 		++cp;
 | |
| 	if (cp - abbrp == 0)
 | |
| 		wp = _("lacks alphabetic at start");
 | |
| 	else if (cp - abbrp < 3)
 | |
| 		wp = _("has fewer than 3 alphabetics");
 | |
| 	else if (cp - abbrp > 6)
 | |
| 		wp = _("has more than 6 alphabetics");
 | |
| 	if (wp == NULL && (*cp == '+' || *cp == '-')) {
 | |
| 		++cp;
 | |
| 		if (isascii((unsigned char) *cp) &&
 | |
| 			isdigit((unsigned char) *cp))
 | |
| 				if (*cp++ == '1' && *cp >= '0' && *cp <= '4')
 | |
| 					++cp;
 | |
| 		if (*cp != '\0')
 | |
| 			wp = _("differs from POSIX standard");
 | |
| 	}
 | |
| 	if (wp == NULL)
 | |
| 		return;
 | |
| 	(void) fflush(stdout);
 | |
| 	(void) fprintf(stderr,
 | |
| 		_("%s: warning: zone \"%s\" abbreviation \"%s\" %s\n"),
 | |
| 		progname, zone, abbrp, wp);
 | |
| 	warned = TRUE;
 | |
| }
 | |
| 
 | |
| static void
 | |
| usage(const char *xprogname, FILE *stream, int status)
 | |
| {
 | |
| 	(void) fprintf(stream,
 | |
| _("%s: usage is %s [ --version ] [ --help ] [ -v ] [ -c [loyear,]hiyear ] zonename ...\n\
 | |
| \n\
 | |
| Report bugs to tz@elsie.nci.nih.gov.\n"),
 | |
| 		       xprogname, xprogname);
 | |
| 	exit(status);
 | |
| }
 | |
| 
 | |
| int
 | |
| main(argc, argv)
 | |
| int	argc;
 | |
| char *	argv[];
 | |
| {
 | |
| 	register int		i;
 | |
| 	register int		c;
 | |
| 	register int		vflag;
 | |
| 	register char *		cutarg;
 | |
| 	register long		cutloyear = ZDUMP_LO_YEAR;
 | |
| 	register long		cuthiyear = ZDUMP_HI_YEAR;
 | |
| 	register time_t		cutlotime;
 | |
| 	register time_t		cuthitime;
 | |
| 	register char **	fakeenv;
 | |
| 	time_t			now;
 | |
| 	time_t			t;
 | |
| 	time_t			newt;
 | |
| 	struct tm		tm;
 | |
| 	struct tm		newtm;
 | |
| 	register struct tm *	tmp;
 | |
| 	register struct tm *	newtmp;
 | |
| 
 | |
| 	INITIALIZE(cutlotime);
 | |
| 	INITIALIZE(cuthitime);
 | |
| #if HAVE_GETTEXT
 | |
| 	(void) setlocale(LC_ALL, "");
 | |
| #ifdef TZ_DOMAINDIR
 | |
| 	(void) bindtextdomain(TZ_DOMAIN, TZ_DOMAINDIR);
 | |
| #endif /* defined TEXTDOMAINDIR */
 | |
| 	(void) textdomain(TZ_DOMAIN);
 | |
| #endif /* HAVE_GETTEXT */
 | |
| 	progname = argv[0];
 | |
| 	for (i = 1; i < argc; ++i)
 | |
| 		if (strcmp(argv[i], "--version") == 0) {
 | |
| 			(void) printf("%s\n", elsieid);
 | |
| 			exit(EXIT_SUCCESS);
 | |
| 		} else if (strcmp(argv[i], "--help") == 0) {
 | |
| 			usage(progname, stdout, EXIT_SUCCESS);
 | |
| 		}
 | |
| 	vflag = 0;
 | |
| 	cutarg = NULL;
 | |
| 	while ((c = getopt(argc, argv, "c:v")) == 'c' || c == 'v')
 | |
| 		if (c == 'v')
 | |
| 			vflag = 1;
 | |
| 		else	cutarg = optarg;
 | |
| 	if ((c != EOF && c != -1) ||
 | |
| 		(optind == argc - 1 && strcmp(argv[optind], "=") == 0)) {
 | |
| 			usage(progname, stderr, EXIT_FAILURE);
 | |
| 	}
 | |
| 	if (vflag) {
 | |
| 		if (cutarg != NULL) {
 | |
| 			long	lo;
 | |
| 			long	hi;
 | |
| 			char	dummy;
 | |
| 
 | |
| 			if (sscanf(cutarg, "%ld%c", &hi, &dummy) == 1) {
 | |
| 				cuthiyear = hi;
 | |
| 			} else if (sscanf(cutarg, "%ld,%ld%c",
 | |
| 				&lo, &hi, &dummy) == 2) {
 | |
| 					cutloyear = lo;
 | |
| 					cuthiyear = hi;
 | |
| 			} else {
 | |
| (void) fprintf(stderr, _("%s: wild -c argument %s\n"),
 | |
| 					progname, cutarg);
 | |
| 				exit(EXIT_FAILURE);
 | |
| 			}
 | |
| 		}
 | |
| 		setabsolutes();
 | |
| 		cutlotime = yeartot(cutloyear);
 | |
| 		cuthitime = yeartot(cuthiyear);
 | |
| 	}
 | |
| 	(void) time(&now);
 | |
| 	longest = 0;
 | |
| 	for (i = optind; i < argc; ++i)
 | |
| 		if (strlen(argv[i]) > longest)
 | |
| 			longest = strlen(argv[i]);
 | |
| 	{
 | |
| 		register int	from;
 | |
| 		register int	to;
 | |
| 
 | |
| 		for (i = 0; environ[i] != NULL; ++i)
 | |
| 			continue;
 | |
| 		fakeenv = (char **) malloc((size_t) ((i + 2) *
 | |
| 			sizeof *fakeenv));
 | |
| 		if (fakeenv == NULL ||
 | |
| 			(fakeenv[0] = (char *) malloc(longest + 4)) == NULL) {
 | |
| 			err(EXIT_FAILURE, "Can't allocated %zu bytes",
 | |
| 			    longest + 4);
 | |
| 		}
 | |
| 		to = 0;
 | |
| 		(void)strcpy(fakeenv[to++], "TZ=");	/* XXX strcpy is safe */
 | |
| 		for (from = 0; environ[from] != NULL; ++from)
 | |
| 			if (strncmp(environ[from], "TZ=", 3) != 0)
 | |
| 				fakeenv[to++] = environ[from];
 | |
| 		fakeenv[to] = NULL;
 | |
| 		environ = fakeenv;
 | |
| 	}
 | |
| 	for (i = optind; i < argc; ++i) {
 | |
| 		static char	buf[MAX_STRING_LENGTH];
 | |
| 
 | |
| 		(void) strcpy(&fakeenv[0][3], argv[i]);	/* XXX strcpy is safe */
 | |
| 		if (!vflag) {
 | |
| 			show(argv[i], now, FALSE);
 | |
| 			continue;
 | |
| 		}
 | |
| 		warned = FALSE;
 | |
| 		t = absolute_min_time;
 | |
| 		show(argv[i], t, TRUE);
 | |
| 		t += SECSPERHOUR * HOURSPERDAY;
 | |
| 		show(argv[i], t, TRUE);
 | |
| 		if (t < cutlotime)
 | |
| 			t = cutlotime;
 | |
| 		tmp = my_localtime(&t);
 | |
| 		if (tmp != NULL) {
 | |
| 			tm = *tmp;
 | |
| 			(void) strncpy(buf, abbr(&tm), (sizeof buf) - 1);
 | |
| 		}
 | |
| 		for ( ; ; ) {
 | |
| 			if (t >= cuthitime || t >= cuthitime - SECSPERHOUR * 12)
 | |
| 				break;
 | |
| 			newt = t + SECSPERHOUR * 12;
 | |
| 			newtmp = localtime(&newt);
 | |
| 			if (newtmp != NULL)
 | |
| 				newtm = *newtmp;
 | |
| 			if ((tmp == NULL || newtmp == NULL) ? (tmp != newtmp) :
 | |
| 				(delta(&newtm, &tm) != (newt - t) ||
 | |
| 				newtm.tm_isdst != tm.tm_isdst ||
 | |
| 				strcmp(abbr(&newtm), buf) != 0)) {
 | |
| 					newt = hunt(argv[i], t, newt);
 | |
| 					newtmp = localtime(&newt);
 | |
| 					if (newtmp != NULL) {
 | |
| 						newtm = *newtmp;
 | |
| 						(void) strncpy(buf,
 | |
| 							abbr(&newtm),
 | |
| 							(sizeof buf) - 1);
 | |
| 					}
 | |
| 			}
 | |
| 			t = newt;
 | |
| 			tm = newtm;
 | |
| 			tmp = newtmp;
 | |
| 		}
 | |
| 		t = absolute_max_time;
 | |
| 		t -= SECSPERHOUR * HOURSPERDAY;
 | |
| 		show(argv[i], t, TRUE);
 | |
| 		t += SECSPERHOUR * HOURSPERDAY;
 | |
| 		show(argv[i], t, TRUE);
 | |
| 	}
 | |
| 	if (fflush(stdout) || ferror(stdout)) {
 | |
| 		err(EXIT_FAILURE, _("Error writing standard output"));
 | |
| 	}
 | |
| 	exit(EXIT_SUCCESS);
 | |
| 	/* If exit fails to exit... */
 | |
| 	return EXIT_FAILURE;
 | |
| }
 | |
| 
 | |
| static void
 | |
| setabsolutes(void)
 | |
| {
 | |
| 	if (0.5 == (time_t) 0.5) {
 | |
| 		/*
 | |
| 		** time_t is floating.
 | |
| 		*/
 | |
| 		if (sizeof (time_t) == sizeof (float)) {
 | |
| 			absolute_min_time = (time_t) -FLT_MAX;
 | |
| 			absolute_max_time = (time_t) FLT_MAX;
 | |
| 		} else if (sizeof (time_t) == sizeof (double)) {
 | |
| 			absolute_min_time = (time_t) -DBL_MAX;
 | |
| 			absolute_max_time = (time_t) DBL_MAX;
 | |
| 		} else {
 | |
| 			(void) fprintf(stderr,
 | |
| _("%s: use of -v on system with floating time_t other than float or double\n"),
 | |
| 				progname);
 | |
| 			exit(EXIT_FAILURE);
 | |
| 		}
 | |
| 	} else if (0 > (time_t) -1) {
 | |
| 		/*
 | |
| 		** time_t is signed.  Assume overflow wraps around.
 | |
| 		*/
 | |
| 		time_t t = 0;
 | |
| 		time_t t1 = 1;
 | |
| 
 | |
| 		while (t < t1) {
 | |
| 			t = t1;
 | |
| 			t1 = 2 * t1 + 1;
 | |
| 		}
 | |
| 
 | |
| 		absolute_max_time = t;
 | |
| 		t = -t;
 | |
| 		absolute_min_time = t - 1;
 | |
| 		if (t < absolute_min_time)
 | |
| 			absolute_min_time = t;
 | |
| 	} else {
 | |
| 		/*
 | |
| 		** time_t is unsigned.
 | |
| 		*/
 | |
| 		absolute_min_time = 0;
 | |
| 		absolute_max_time = absolute_min_time - 1;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| static time_t
 | |
| yeartot(y)
 | |
| const long	y;
 | |
| {
 | |
| 	register long	myy;
 | |
| 	register long	seconds;
 | |
| 	register time_t	t;
 | |
| 
 | |
| 	myy = EPOCH_YEAR;
 | |
| 	t = 0;
 | |
| 	while (myy != y) {
 | |
| 		if (myy < y) {
 | |
| 			seconds = isleap(myy) ? SECSPERLYEAR : SECSPERNYEAR;
 | |
| 			++myy;
 | |
| 			if (t > absolute_max_time - seconds) {
 | |
| 				t = absolute_max_time;
 | |
| 				break;
 | |
| 			}
 | |
| 			t += seconds;
 | |
| 		} else {
 | |
| 			--myy;
 | |
| 			seconds = isleap(myy) ? SECSPERLYEAR : SECSPERNYEAR;
 | |
| 			if (t < absolute_min_time + seconds) {
 | |
| 				t = absolute_min_time;
 | |
| 				break;
 | |
| 			}
 | |
| 			t -= seconds;
 | |
| 		}
 | |
| 	}
 | |
| 	return t;
 | |
| }
 | |
| 
 | |
| static time_t
 | |
| hunt(char *name, time_t lot, time_t hit)
 | |
| {
 | |
| 	time_t			t;
 | |
| 	long			diff;
 | |
| 	struct tm		lotm;
 | |
| 	register struct tm *	lotmp;
 | |
| 	struct tm		tm;
 | |
| 	register struct tm *	tmp;
 | |
| 	char			loab[MAX_STRING_LENGTH];
 | |
| 
 | |
| 	lotmp = my_localtime(&lot);
 | |
| 	if (lotmp != NULL) {
 | |
| 		lotm = *lotmp;
 | |
| 		(void) strncpy(loab, abbr(&lotm), (sizeof loab) - 1);
 | |
| 	}
 | |
| 	for ( ; ; ) {
 | |
| 		diff = (long) (hit - lot);
 | |
| 		if (diff < 2)
 | |
| 			break;
 | |
| 		t = lot;
 | |
| 		t += diff / 2;
 | |
| 		if (t <= lot)
 | |
| 			++t;
 | |
| 		else if (t >= hit)
 | |
| 			--t;
 | |
| 		tmp = my_localtime(&t);
 | |
| 		if (tmp != NULL)
 | |
| 			tm = *tmp;
 | |
| 		if ((lotmp == NULL || tmp == NULL) ? (lotmp == tmp) :
 | |
| 			(delta(&tm, &lotm) == (t - lot) &&
 | |
| 			tm.tm_isdst == lotm.tm_isdst &&
 | |
| 			strcmp(abbr(&tm), loab) == 0)) {
 | |
| 				lot = t;
 | |
| 				lotm = tm;
 | |
| 				lotmp = tmp;
 | |
| 		} else	hit = t;
 | |
| 	}
 | |
| 	show(name, lot, TRUE);
 | |
| 	show(name, hit, TRUE);
 | |
| 	return hit;
 | |
| }
 | |
| 
 | |
| /*
 | |
| ** Thanks to Paul Eggert for logic used in delta.
 | |
| */
 | |
| 
 | |
| static long
 | |
| delta(newp, oldp)
 | |
| struct tm *	newp;
 | |
| struct tm *	oldp;
 | |
| {
 | |
| 	register long	result;
 | |
| 	register int	tmy;
 | |
| 
 | |
| 	if (newp->tm_year < oldp->tm_year)
 | |
| 		return -delta(oldp, newp);
 | |
| 	result = 0;
 | |
| 	for (tmy = oldp->tm_year; tmy < newp->tm_year; ++tmy)
 | |
| 		result += DAYSPERNYEAR + isleap_sum(tmy, TM_YEAR_BASE);
 | |
| 	result += newp->tm_yday - oldp->tm_yday;
 | |
| 	result *= HOURSPERDAY;
 | |
| 	result += newp->tm_hour - oldp->tm_hour;
 | |
| 	result *= MINSPERHOUR;
 | |
| 	result += newp->tm_min - oldp->tm_min;
 | |
| 	result *= SECSPERMIN;
 | |
| 	result += newp->tm_sec - oldp->tm_sec;
 | |
| 	return result;
 | |
| }
 | |
| 
 | |
| static void
 | |
| show(char *zone, time_t t, int v)
 | |
| {
 | |
| 	register struct tm *	tmp;
 | |
| 
 | |
| 	(void) printf("%-*s  ", (int) longest, zone);
 | |
| 	if (v) {
 | |
| 		tmp = gmtime(&t);
 | |
| 		if (tmp == NULL) {
 | |
| 			(void) printf(tformat(), t);
 | |
| 		} else {
 | |
| 			dumptime(tmp);
 | |
| 			(void) printf(" UTC");
 | |
| 		}
 | |
| 		(void) printf(" = ");
 | |
| 	}
 | |
| 	tmp = my_localtime(&t);
 | |
| 	dumptime(tmp);
 | |
| 	if (tmp != NULL) {
 | |
| 		if (*abbr(tmp) != '\0')
 | |
| 			(void) printf(" %s", abbr(tmp));
 | |
| 		if (v) {
 | |
| 			(void) printf(" isdst=%d", tmp->tm_isdst);
 | |
| #ifdef TM_GMTOFF
 | |
| 			(void) printf(" gmtoff=%ld", tmp->TM_GMTOFF);
 | |
| #endif /* defined TM_GMTOFF */
 | |
| 		}
 | |
| 	}
 | |
| 	(void) printf("\n");
 | |
| 	if (tmp != NULL && *abbr(tmp) != '\0')
 | |
| 		abbrok(abbr(tmp), zone);
 | |
| }
 | |
| 
 | |
| static const char *
 | |
| abbr(tmp)
 | |
| struct tm *	tmp;
 | |
| {
 | |
| 	register const char *	result;
 | |
| 	static const char	nada;
 | |
| 
 | |
| 	if (tmp->tm_isdst != 0 && tmp->tm_isdst != 1)
 | |
| 		return &nada;
 | |
| 	result = tzname[tmp->tm_isdst];
 | |
| 	return (result == NULL) ? &nada : result;
 | |
| }
 | |
| 
 | |
| /*
 | |
| ** The code below can fail on certain theoretical systems;
 | |
| ** it works on all known real-world systems as of 2004-12-30.
 | |
| */
 | |
| 
 | |
| static const char *
 | |
| tformat(void)
 | |
| {
 | |
| 	if (0.5 == (time_t) 0.5) {	/* floating */
 | |
| 		if (sizeof (time_t) > sizeof (double))
 | |
| 			return "%Lg";
 | |
| 		return "%g";
 | |
| 	}
 | |
| 	if (0 > (time_t) -1) {		/* signed */
 | |
| 		if (sizeof (time_t) > sizeof (long))
 | |
| 			return "%lld";
 | |
| 		if (sizeof (time_t) > sizeof (int))
 | |
| 			return "%ld";
 | |
| 		return "%d";
 | |
| 	}
 | |
| 	if (sizeof (time_t) > sizeof (unsigned long))
 | |
| 		return "%llu";
 | |
| 	if (sizeof (time_t) > sizeof (unsigned int))
 | |
| 		return "%lu";
 | |
| 	return "%u";
 | |
| }
 | |
| 
 | |
| static void
 | |
| dumptime(timeptr)
 | |
| register const struct tm *	timeptr;
 | |
| {
 | |
| 	static const char	wday_name[][3] = {
 | |
| 		"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
 | |
| 	};
 | |
| 	static const char	mon_name[][3] = {
 | |
| 		"Jan", "Feb", "Mar", "Apr", "May", "Jun",
 | |
| 		"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
 | |
| 	};
 | |
| 	register const char *	wn;
 | |
| 	register const char *	mn;
 | |
| 	register int		lead;
 | |
| 	register int		trail;
 | |
| 
 | |
| 	if (timeptr == NULL) {
 | |
| 		(void) printf("NULL");
 | |
| 		return;
 | |
| 	}
 | |
| 	/*
 | |
| 	** The packaged versions of localtime and gmtime never put out-of-range
 | |
| 	** values in tm_wday or tm_mon, but since this code might be compiled
 | |
| 	** with other (perhaps experimental) versions, paranoia is in order.
 | |
| 	*/
 | |
| 	if (timeptr->tm_wday < 0 || timeptr->tm_wday >=
 | |
| 		(int) (sizeof wday_name / sizeof wday_name[0]))
 | |
| 			wn = "???";
 | |
| 	else		wn = wday_name[timeptr->tm_wday];
 | |
| 	if (timeptr->tm_mon < 0 || timeptr->tm_mon >=
 | |
| 		(int) (sizeof mon_name / sizeof mon_name[0]))
 | |
| 			mn = "???";
 | |
| 	else		mn = mon_name[timeptr->tm_mon];
 | |
| 	(void) printf("%.3s %.3s%3d %.2d:%.2d:%.2d ",
 | |
| 		wn, mn,
 | |
| 		timeptr->tm_mday, timeptr->tm_hour,
 | |
| 		timeptr->tm_min, timeptr->tm_sec);
 | |
| #define DIVISOR	10
 | |
| 	trail = timeptr->tm_year % DIVISOR + TM_YEAR_BASE % DIVISOR;
 | |
| 	lead = timeptr->tm_year / DIVISOR + TM_YEAR_BASE / DIVISOR +
 | |
| 		trail / DIVISOR;
 | |
| 	trail %= DIVISOR;
 | |
| 	if (trail < 0 && lead > 0) {
 | |
| 		trail += DIVISOR;
 | |
| 		--lead;
 | |
| 	} else if (lead < 0 && trail > 0) {
 | |
| 		trail -= DIVISOR;
 | |
| 		++lead;
 | |
| 	}
 | |
| 	if (lead == 0)
 | |
| 		(void) printf("%d", trail);
 | |
| 	else	(void) printf("%d%d", lead, ((trail < 0) ? -trail : trail));
 | |
| }
 |