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