xref: /netbsd-src/lib/libc/time/zic.c (revision a4ddc2c8fb9af816efe3b1c375a5530aef0e89e9)
1 /*	$NetBSD: zic.c,v 1.40 2013/03/06 18:40:19 christos Exp $	*/
2 /*
3 ** This file is in the public domain, so clarified as of
4 ** 2006-07-17 by Arthur David Olson.
5 */
6 
7 #if HAVE_NBTOOL_CONFIG_H
8 #include "nbtool_config.h"
9 #endif
10 
11 #include <sys/cdefs.h>
12 #ifndef lint
13 __RCSID("$NetBSD: zic.c,v 1.40 2013/03/06 18:40:19 christos Exp $");
14 #endif /* !defined lint */
15 
16 #include "version.h"
17 #include "private.h"
18 #include "locale.h"
19 #include "tzfile.h"
20 
21 #define	ZIC_VERSION	'2'
22 
23 typedef intmax_t	zic_t;
24 #define TIME_T_BITS_IN_FILE	64
25 static const zic_t min_time = INTMAX_MIN;
26 static const zic_t max_time = INTMAX_MAX;
27 
28 
29 #ifndef ZIC_MAX_ABBR_LEN_WO_WARN
30 #define ZIC_MAX_ABBR_LEN_WO_WARN	6
31 #endif /* !defined ZIC_MAX_ABBR_LEN_WO_WARN */
32 
33 #if HAVE_SYS_STAT_H
34 #include "sys/stat.h"
35 #endif
36 #ifdef S_IRUSR
37 #define MKDIR_UMASK (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)
38 #else
39 #define MKDIR_UMASK 0755
40 #endif
41 
42 #include "unistd.h"
43 
44 /*
45 ** On some ancient hosts, predicates like `isspace(C)' are defined
46 ** only if isascii(C) || C == EOF. Modern hosts obey the C Standard,
47 ** which says they are defined only if C == ((unsigned char) C) || C == EOF.
48 ** Neither the C Standard nor Posix require that `isascii' exist.
49 ** For portability, we check both ancient and modern requirements.
50 ** If isascii is not defined, the isascii check succeeds trivially.
51 */
52 #include "ctype.h"
53 #ifndef isascii
54 #define isascii(x) 1
55 #endif
56 
57 #define end(cp)	(strchr((cp), '\0'))
58 
59 struct rule {
60 	const char *	r_filename;
61 	int		r_linenum;
62 	const char *	r_name;
63 
64 	int		r_loyear;	/* for example, 1986 */
65 	int		r_hiyear;	/* for example, 1986 */
66 	const char *	r_yrtype;
67 	int		r_lowasnum;
68 	int		r_hiwasnum;
69 
70 	int		r_month;	/* 0..11 */
71 
72 	int		r_dycode;	/* see below */
73 	int		r_dayofmonth;
74 	int		r_wday;
75 
76 	zic_t		r_tod;		/* time from midnight */
77 	int		r_todisstd;	/* above is standard time if TRUE */
78 					/* or wall clock time if FALSE */
79 	int		r_todisgmt;	/* above is GMT if TRUE */
80 					/* or local time if FALSE */
81 	zic_t		r_stdoff;	/* offset from standard time */
82 	const char *	r_abbrvar;	/* variable part of abbreviation */
83 
84 	int		r_todo;		/* a rule to do (used in outzone) */
85 	zic_t		r_temp;		/* used in outzone */
86 };
87 
88 /*
89 **	r_dycode		r_dayofmonth	r_wday
90 */
91 
92 #define DC_DOM		0	/* 1..31 */	/* unused */
93 #define DC_DOWGEQ	1	/* 1..31 */	/* 0..6 (Sun..Sat) */
94 #define DC_DOWLEQ	2	/* 1..31 */	/* 0..6 (Sun..Sat) */
95 
96 struct zone {
97 	const char *	z_filename;
98 	int		z_linenum;
99 
100 	const char *	z_name;
101 	zic_t		z_gmtoff;
102 	const char *	z_rule;
103 	const char *	z_format;
104 
105 	zic_t		z_stdoff;
106 
107 	struct rule *	z_rules;
108 	int		z_nrules;
109 
110 	struct rule	z_untilrule;
111 	zic_t		z_untiltime;
112 };
113 
114 extern int	getopt(int argc, char * const argv[],
115 			const char * options);
116 extern int	link(const char * fromname, const char * toname);
117 extern char *	optarg;
118 extern int	optind;
119 
120 static void	addtt(zic_t starttime, int type);
121 static int	addtype(zic_t gmtoff, const char * abbr, int isdst,
122 				int ttisstd, int ttisgmt);
123 static void	leapadd(zic_t t, int positive, int rolling, int count);
124 static void	adjleap(void);
125 static void	associate(void);
126 static void	dolink(const char * fromfield, const char * tofield);
127 static zic_t	eitol(int i);
128 static char **	getfields(char * buf);
129 static zic_t	gethms(const char * string, const char * errstrng,
130 			int signable);
131 static void	infile(const char * filename);
132 static void	inleap(char ** fields, int nfields);
133 static void	inlink(char ** fields, int nfields);
134 static void	inrule(char ** fields, int nfields);
135 static int	inzcont(char ** fields, int nfields);
136 static int	inzone(char ** fields, int nfields);
137 static int	inzsub(char ** fields, int nfields, int iscont);
138 static int	itsdir(const char * name);
139 static int	lowerit(int c);
140 int		main(int, char **);
141 static int	mkdirs(char * filename);
142 static void	newabbr(const char * abbr);
143 static zic_t	oadd(zic_t t1, zic_t t2);
144 static void	outzone(const struct zone * zp, int ntzones);
145 static int	rcomp(const void * leftp, const void * rightp);
146 static zic_t	rpytime(const struct rule * rp, int wantedy);
147 static void	rulesub(struct rule * rp,
148 			const char * loyearp, const char * hiyearp,
149 			const char * typep, const char * monthp,
150 			const char * dayp, const char * timep);
151 static zic_t	tadd(zic_t t1, zic_t t2);
152 static int	yearistype(int year, const char * type);
153 static int	atcomp(const void *avp, const void *bvp);
154 static void	updateminmax(int x);
155 
156 static int		charcnt;
157 static int		errors;
158 static const char *	filename;
159 static int		leapcnt;
160 static int		leapseen;
161 static int		leapminyear;
162 static int		leapmaxyear;
163 static int		linenum;
164 static size_t		max_abbrvar_len;
165 static size_t		max_format_len;
166 static int		max_year;
167 static int		min_year;
168 static int		noise;
169 static const char *	rfilename;
170 static int		rlinenum;
171 static const char *	progname;
172 static int		timecnt;
173 static int		typecnt;
174 
175 /*
176 ** Line codes.
177 */
178 
179 #define LC_RULE		0
180 #define LC_ZONE		1
181 #define LC_LINK		2
182 #define LC_LEAP		3
183 
184 /*
185 ** Which fields are which on a Zone line.
186 */
187 
188 #define ZF_NAME		1
189 #define ZF_GMTOFF	2
190 #define ZF_RULE		3
191 #define ZF_FORMAT	4
192 #define ZF_TILYEAR	5
193 #define ZF_TILMONTH	6
194 #define ZF_TILDAY	7
195 #define ZF_TILTIME	8
196 #define ZONE_MINFIELDS	5
197 #define ZONE_MAXFIELDS	9
198 
199 /*
200 ** Which fields are which on a Zone continuation line.
201 */
202 
203 #define ZFC_GMTOFF	0
204 #define ZFC_RULE	1
205 #define ZFC_FORMAT	2
206 #define ZFC_TILYEAR	3
207 #define ZFC_TILMONTH	4
208 #define ZFC_TILDAY	5
209 #define ZFC_TILTIME	6
210 #define ZONEC_MINFIELDS	3
211 #define ZONEC_MAXFIELDS	7
212 
213 /*
214 ** Which files are which on a Rule line.
215 */
216 
217 #define RF_NAME		1
218 #define RF_LOYEAR	2
219 #define RF_HIYEAR	3
220 #define RF_COMMAND	4
221 #define RF_MONTH	5
222 #define RF_DAY		6
223 #define RF_TOD		7
224 #define RF_STDOFF	8
225 #define RF_ABBRVAR	9
226 #define RULE_FIELDS	10
227 
228 /*
229 ** Which fields are which on a Link line.
230 */
231 
232 #define LF_FROM		1
233 #define LF_TO		2
234 #define LINK_FIELDS	3
235 
236 /*
237 ** Which fields are which on a Leap line.
238 */
239 
240 #define LP_YEAR		1
241 #define LP_MONTH	2
242 #define LP_DAY		3
243 #define LP_TIME		4
244 #define LP_CORR		5
245 #define LP_ROLL		6
246 #define LEAP_FIELDS	7
247 
248 /*
249 ** Year synonyms.
250 */
251 
252 #define YR_MINIMUM	0
253 #define YR_MAXIMUM	1
254 #define YR_ONLY		2
255 
256 static struct rule *	rules;
257 static int		nrules;	/* number of rules */
258 
259 static struct zone *	zones;
260 static int		nzones;	/* number of zones */
261 
262 struct link {
263 	const char *	l_filename;
264 	int		l_linenum;
265 	const char *	l_from;
266 	const char *	l_to;
267 };
268 
269 static struct link *	links;
270 static int		nlinks;
271 
272 struct lookup {
273 	const char *	l_word;
274 	const int	l_value;
275 };
276 
277 static struct lookup const *	byword(const char * string,
278 					const struct lookup * lp);
279 
280 static struct lookup const	line_codes[] = {
281 	{ "Rule",	LC_RULE },
282 	{ "Zone",	LC_ZONE },
283 	{ "Link",	LC_LINK },
284 	{ "Leap",	LC_LEAP },
285 	{ NULL,		0}
286 };
287 
288 static struct lookup const	mon_names[] = {
289 	{ "January",	TM_JANUARY },
290 	{ "February",	TM_FEBRUARY },
291 	{ "March",	TM_MARCH },
292 	{ "April",	TM_APRIL },
293 	{ "May",	TM_MAY },
294 	{ "June",	TM_JUNE },
295 	{ "July",	TM_JULY },
296 	{ "August",	TM_AUGUST },
297 	{ "September",	TM_SEPTEMBER },
298 	{ "October",	TM_OCTOBER },
299 	{ "November",	TM_NOVEMBER },
300 	{ "December",	TM_DECEMBER },
301 	{ NULL,		0 }
302 };
303 
304 static struct lookup const	wday_names[] = {
305 	{ "Sunday",	TM_SUNDAY },
306 	{ "Monday",	TM_MONDAY },
307 	{ "Tuesday",	TM_TUESDAY },
308 	{ "Wednesday",	TM_WEDNESDAY },
309 	{ "Thursday",	TM_THURSDAY },
310 	{ "Friday",	TM_FRIDAY },
311 	{ "Saturday",	TM_SATURDAY },
312 	{ NULL,		0 }
313 };
314 
315 static struct lookup const	lasts[] = {
316 	{ "last-Sunday",	TM_SUNDAY },
317 	{ "last-Monday",	TM_MONDAY },
318 	{ "last-Tuesday",	TM_TUESDAY },
319 	{ "last-Wednesday",	TM_WEDNESDAY },
320 	{ "last-Thursday",	TM_THURSDAY },
321 	{ "last-Friday",	TM_FRIDAY },
322 	{ "last-Saturday",	TM_SATURDAY },
323 	{ NULL,			0 }
324 };
325 
326 static struct lookup const	begin_years[] = {
327 	{ "minimum",	YR_MINIMUM },
328 	{ "maximum",	YR_MAXIMUM },
329 	{ NULL,		0 }
330 };
331 
332 static struct lookup const	end_years[] = {
333 	{ "minimum",	YR_MINIMUM },
334 	{ "maximum",	YR_MAXIMUM },
335 	{ "only",	YR_ONLY },
336 	{ NULL,		0 }
337 };
338 
339 static struct lookup const	leap_types[] = {
340 	{ "Rolling",	TRUE },
341 	{ "Stationary",	FALSE },
342 	{ NULL,		0 }
343 };
344 
345 static const int	len_months[2][MONSPERYEAR] = {
346 	{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
347 	{ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
348 };
349 
350 static const int	len_years[2] = {
351 	DAYSPERNYEAR, DAYSPERLYEAR
352 };
353 
354 static struct attype {
355 	zic_t		at;
356 	unsigned char	type;
357 }			attypes[TZ_MAX_TIMES];
358 static zic_t		gmtoffs[TZ_MAX_TYPES];
359 static char		isdsts[TZ_MAX_TYPES];
360 static unsigned char	abbrinds[TZ_MAX_TYPES];
361 static char		ttisstds[TZ_MAX_TYPES];
362 static char		ttisgmts[TZ_MAX_TYPES];
363 static char		chars[TZ_MAX_CHARS];
364 static zic_t		trans[TZ_MAX_LEAPS];
365 static zic_t		corr[TZ_MAX_LEAPS];
366 static char		roll[TZ_MAX_LEAPS];
367 
368 /*
369 ** Memory allocation.
370 */
371 
372 static __pure void *
373 memcheck(void *const ptr)
374 {
375 	if (ptr == NULL) {
376 		const char *e = strerror(errno);
377 
378 		(void) fprintf(stderr, _("%s: Memory exhausted: %s\n"),
379 			progname, e);
380 		exit(EXIT_FAILURE);
381 	}
382 	return ptr;
383 }
384 
385 #define emalloc(size)		memcheck(malloc(size))
386 #define erealloc(ptr, size)	memcheck(realloc((ptr), (size)))
387 #define ecpyalloc(ptr)		memcheck(icpyalloc(ptr))
388 #define ecatalloc(oldp, newp)	memcheck(icatalloc((oldp), (newp)))
389 
390 /*
391 ** Error handling.
392 */
393 
394 static void
395 eats(const char *const name, const int num, const char *const rname,
396     const int rnum)
397 {
398 	filename = name;
399 	linenum = num;
400 	rfilename = rname;
401 	rlinenum = rnum;
402 }
403 
404 static void
405 eat(const char *const name, const int num)
406 {
407 	eats(name, num, NULL, -1);
408 }
409 
410 static void
411 error(const char *const string)
412 {
413 	/*
414 	** Match the format of "cc" to allow sh users to
415 	**	zic ... 2>&1 | error -t "*" -v
416 	** on BSD systems.
417 	*/
418 	(void) fprintf(stderr, _("\"%s\", line %d: %s"),
419 		filename, linenum, string);
420 	if (rfilename != NULL)
421 		(void) fprintf(stderr, _(" (rule from \"%s\", line %d)"),
422 			rfilename, rlinenum);
423 	(void) fprintf(stderr, "\n");
424 	++errors;
425 }
426 
427 static void
428 warning(const char *const string)
429 {
430 	char *	cp;
431 
432 	cp = ecpyalloc(_("warning: "));
433 	cp = ecatalloc(cp, string);
434 	error(cp);
435 	free(cp);
436 	--errors;
437 }
438 
439 __dead static void
440 usage(FILE *stream, int status)
441 {
442 	(void) fprintf(stream, _("%s: usage is %s \
443 [ --version ] [ --help ] [ -v ] [ -l localtime ] [ -p posixrules ] \\\n\
444 \t[ -d directory ] [ -L leapseconds ] [ -y yearistype ] [ filename ... ]\n\
445 \n\
446 Report bugs to %s.\n"),
447 		       progname, progname, REPORT_BUGS_TO);
448 	exit(status);
449 }
450 
451 static const char *	psxrules;
452 static const char *	lcltime;
453 static const char *	directory;
454 static const char *	leapsec;
455 static const char *	yitcommand;
456 
457 int
458 main(int argc, char *argv[])
459 {
460 	int	i;
461 	int	j;
462 	int	c;
463 
464 #ifdef _POSIX_VERSION
465 	(void) umask(umask(S_IWGRP | S_IWOTH) | (S_IWGRP | S_IWOTH));
466 #endif /* defined _POSIX_VERSION */
467 #if HAVE_GETTEXT - 0
468 	(void) setlocale(LC_MESSAGES, "");
469 #ifdef TZ_DOMAINDIR
470 	(void) bindtextdomain(TZ_DOMAIN, TZ_DOMAINDIR);
471 #endif /* defined TEXTDOMAINDIR */
472 	(void) textdomain(TZ_DOMAIN);
473 #endif /* HAVE_GETTEXT */
474 	progname = argv[0];
475 	if (TYPE_BIT(zic_t) < 64) {
476 		(void) fprintf(stderr, "%s: %s\n", progname,
477 			_("wild compilation-time specification of zic_t"));
478 		exit(EXIT_FAILURE);
479 	}
480 	for (i = 1; i < argc; ++i)
481 		if (strcmp(argv[i], "--version") == 0) {
482 			(void) printf("zic %s%s\n", PKGVERSION, TZVERSION);
483 			exit(EXIT_SUCCESS);
484 		} else if (strcmp(argv[i], "--help") == 0) {
485 			usage(stdout, EXIT_SUCCESS);
486 		}
487 	while ((c = getopt(argc, argv, "d:l:p:L:vsy:")) != EOF && c != -1)
488 		switch (c) {
489 			default:
490 				usage(stderr, EXIT_FAILURE);
491 			case 'd':
492 				if (directory == NULL)
493 					directory = optarg;
494 				else {
495 					(void) fprintf(stderr,
496 _("%s: More than one -d option specified\n"),
497 						progname);
498 					exit(EXIT_FAILURE);
499 				}
500 				break;
501 			case 'l':
502 				if (lcltime == NULL)
503 					lcltime = optarg;
504 				else {
505 					(void) fprintf(stderr,
506 _("%s: More than one -l option specified\n"),
507 						progname);
508 					exit(EXIT_FAILURE);
509 				}
510 				break;
511 			case 'p':
512 				if (psxrules == NULL)
513 					psxrules = optarg;
514 				else {
515 					(void) fprintf(stderr,
516 _("%s: More than one -p option specified\n"),
517 						progname);
518 					exit(EXIT_FAILURE);
519 				}
520 				break;
521 			case 'y':
522 				if (yitcommand == NULL)
523 					yitcommand = optarg;
524 				else {
525 					(void) fprintf(stderr,
526 _("%s: More than one -y option specified\n"),
527 						progname);
528 					exit(EXIT_FAILURE);
529 				}
530 				break;
531 			case 'L':
532 				if (leapsec == NULL)
533 					leapsec = optarg;
534 				else {
535 					(void) fprintf(stderr,
536 _("%s: More than one -L option specified\n"),
537 						progname);
538 					exit(EXIT_FAILURE);
539 				}
540 				break;
541 			case 'v':
542 				noise = TRUE;
543 				break;
544 			case 's':
545 				(void) printf("%s: -s ignored\n", progname);
546 				break;
547 		}
548 	if (optind == argc - 1 && strcmp(argv[optind], "=") == 0)
549 		usage(stderr, EXIT_FAILURE);	/* usage message by request */
550 	if (directory == NULL)
551 		directory = TZDIR;
552 	if (yitcommand == NULL)
553 		yitcommand = "yearistype";
554 
555 	if (optind < argc && leapsec != NULL) {
556 		infile(leapsec);
557 		adjleap();
558 	}
559 
560 	for (i = optind; i < argc; ++i)
561 		infile(argv[i]);
562 	if (errors)
563 		exit(EXIT_FAILURE);
564 	associate();
565 	for (i = 0; i < nzones; i = j) {
566 		/*
567 		** Find the next non-continuation zone entry.
568 		*/
569 		for (j = i + 1; j < nzones && zones[j].z_name == NULL; ++j)
570 			continue;
571 		outzone(&zones[i], j - i);
572 	}
573 	/*
574 	** Make links.
575 	*/
576 	for (i = 0; i < nlinks; ++i) {
577 		eat(links[i].l_filename, links[i].l_linenum);
578 		dolink(links[i].l_from, links[i].l_to);
579 		if (noise)
580 			for (j = 0; j < nlinks; ++j)
581 				if (strcmp(links[i].l_to,
582 					links[j].l_from) == 0)
583 						warning(_("link to link"));
584 	}
585 	if (lcltime != NULL) {
586 		eat("command line", 1);
587 		dolink(lcltime, TZDEFAULT);
588 	}
589 	if (psxrules != NULL) {
590 		eat("command line", 1);
591 		dolink(psxrules, TZDEFRULES);
592 	}
593 	return (errors == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
594 }
595 
596 static void
597 dolink(const char *const fromfield, const char *const tofield)
598 {
599 	char *	fromname;
600 	char *	toname;
601 
602 	if (fromfield[0] == '/')
603 		fromname = ecpyalloc(fromfield);
604 	else {
605 		fromname = ecpyalloc(directory);
606 		fromname = ecatalloc(fromname, "/");
607 		fromname = ecatalloc(fromname, fromfield);
608 	}
609 	if (tofield[0] == '/')
610 		toname = ecpyalloc(tofield);
611 	else {
612 		toname = ecpyalloc(directory);
613 		toname = ecatalloc(toname, "/");
614 		toname = ecatalloc(toname, tofield);
615 	}
616 	/*
617 	** We get to be careful here since
618 	** there's a fair chance of root running us.
619 	*/
620 	if (!itsdir(toname))
621 		(void) remove(toname);
622 	if (link(fromname, toname) != 0) {
623 		int	result;
624 
625 		if (mkdirs(toname) != 0)
626 			exit(EXIT_FAILURE);
627 
628 		result = link(fromname, toname);
629 #if HAVE_SYMLINK
630 		if (result != 0 &&
631 			access(fromname, F_OK) == 0 &&
632 			!itsdir(fromname)) {
633 				const char *s = tofield;
634 				char * symlinkcontents = NULL;
635 
636 				while ((s = strchr(s+1, '/')) != NULL)
637 					symlinkcontents =
638 						ecatalloc(symlinkcontents,
639 						"../");
640 				symlinkcontents =
641 					ecatalloc(symlinkcontents,
642 					fromname);
643 				result = symlink(symlinkcontents,
644 					toname);
645 				if (result == 0)
646 warning(_("hard link failed, symbolic link used"));
647 				free(symlinkcontents);
648 		}
649 #endif /* HAVE_SYMLINK */
650 		if (result != 0) {
651 			const char *e = strerror(errno);
652 
653 			(void) fprintf(stderr,
654 				_("%s: Can't link from %s to %s: %s\n"),
655 				progname, fromname, toname, e);
656 			exit(EXIT_FAILURE);
657 		}
658 	}
659 	free(fromname);
660 	free(toname);
661 }
662 
663 static int
664 itsdir(const char *const name)
665 {
666 	char *	myname;
667 	int	accres;
668 
669 	myname = ecpyalloc(name);
670 	myname = ecatalloc(myname, "/.");
671 	accres = access(myname, F_OK);
672 	free(myname);
673 	return accres == 0;
674 }
675 
676 /*
677 ** Associate sets of rules with zones.
678 */
679 
680 /*
681 ** Sort by rule name.
682 */
683 
684 static int
685 rcomp(const void *cp1, const void *cp2)
686 {
687 	return strcmp(((const struct rule *) cp1)->r_name,
688 		((const struct rule *) cp2)->r_name);
689 }
690 
691 static void
692 associate(void)
693 {
694 	struct zone *	zp;
695 	struct rule *	rp;
696 	int		base, out;
697 	int		i, j;
698 
699 	if (nrules != 0) {
700 		(void) qsort(rules, (size_t)nrules, sizeof *rules, rcomp);
701 		for (i = 0; i < nrules - 1; ++i) {
702 			if (strcmp(rules[i].r_name,
703 				rules[i + 1].r_name) != 0)
704 					continue;
705 			if (strcmp(rules[i].r_filename,
706 				rules[i + 1].r_filename) == 0)
707 					continue;
708 			eat(rules[i].r_filename, rules[i].r_linenum);
709 			warning(_("same rule name in multiple files"));
710 			eat(rules[i + 1].r_filename, rules[i + 1].r_linenum);
711 			warning(_("same rule name in multiple files"));
712 			for (j = i + 2; j < nrules; ++j) {
713 				if (strcmp(rules[i].r_name,
714 					rules[j].r_name) != 0)
715 						break;
716 				if (strcmp(rules[i].r_filename,
717 					rules[j].r_filename) == 0)
718 						continue;
719 				if (strcmp(rules[i + 1].r_filename,
720 					rules[j].r_filename) == 0)
721 						continue;
722 				break;
723 			}
724 			i = j - 1;
725 		}
726 	}
727 	for (i = 0; i < nzones; ++i) {
728 		zp = &zones[i];
729 		zp->z_rules = NULL;
730 		zp->z_nrules = 0;
731 	}
732 	for (base = 0; base < nrules; base = out) {
733 		rp = &rules[base];
734 		for (out = base + 1; out < nrules; ++out)
735 			if (strcmp(rp->r_name, rules[out].r_name) != 0)
736 				break;
737 		for (i = 0; i < nzones; ++i) {
738 			zp = &zones[i];
739 			if (strcmp(zp->z_rule, rp->r_name) != 0)
740 				continue;
741 			zp->z_rules = rp;
742 			zp->z_nrules = out - base;
743 		}
744 	}
745 	for (i = 0; i < nzones; ++i) {
746 		zp = &zones[i];
747 		if (zp->z_nrules == 0) {
748 			/*
749 			** Maybe we have a local standard time offset.
750 			*/
751 			eat(zp->z_filename, zp->z_linenum);
752 			zp->z_stdoff = gethms(zp->z_rule, _("unruly zone"),
753 				TRUE);
754 			/*
755 			** Note, though, that if there's no rule,
756 			** a '%s' in the format is a bad thing.
757 			*/
758 			if (strchr(zp->z_format, '%') != 0)
759 				error(_("%s in ruleless zone"));
760 		}
761 	}
762 	if (errors)
763 		exit(EXIT_FAILURE);
764 }
765 
766 static void
767 infile(const char *name)
768 {
769 	FILE *			fp;
770 	char **		fields;
771 	char *			cp;
772 	const struct lookup *	lp;
773 	int			nfields;
774 	int			wantcont;
775 	int			num;
776 	char				buf[BUFSIZ];
777 
778 	if (strcmp(name, "-") == 0) {
779 		name = _("standard input");
780 		fp = stdin;
781 	} else if ((fp = fopen(name, "r")) == NULL) {
782 		const char *e = strerror(errno);
783 
784 		(void) fprintf(stderr, _("%s: Can't open %s: %s\n"),
785 			progname, name, e);
786 		exit(EXIT_FAILURE);
787 	}
788 	wantcont = FALSE;
789 	for (num = 1; ; ++num) {
790 		eat(name, num);
791 		if (fgets(buf, (int) sizeof buf, fp) != buf)
792 			break;
793 		cp = strchr(buf, '\n');
794 		if (cp == NULL) {
795 			error(_("line too long"));
796 			exit(EXIT_FAILURE);
797 		}
798 		*cp = '\0';
799 		fields = getfields(buf);
800 		nfields = 0;
801 		while (fields[nfields] != NULL) {
802 			static char	nada;
803 
804 			if (strcmp(fields[nfields], "-") == 0)
805 				fields[nfields] = &nada;
806 			++nfields;
807 		}
808 		if (nfields == 0) {
809 			/* nothing to do */
810 		} else if (wantcont) {
811 			wantcont = inzcont(fields, nfields);
812 		} else {
813 			lp = byword(fields[0], line_codes);
814 			if (lp == NULL)
815 				error(_("input line of unknown type"));
816 			else switch ((int) (lp->l_value)) {
817 				case LC_RULE:
818 					inrule(fields, nfields);
819 					wantcont = FALSE;
820 					break;
821 				case LC_ZONE:
822 					wantcont = inzone(fields, nfields);
823 					break;
824 				case LC_LINK:
825 					inlink(fields, nfields);
826 					wantcont = FALSE;
827 					break;
828 				case LC_LEAP:
829 					if (name != leapsec)
830 						(void) fprintf(stderr,
831 _("%s: Leap line in non leap seconds file %s\n"),
832 							progname, name);
833 					else	inleap(fields, nfields);
834 					wantcont = FALSE;
835 					break;
836 				default:	/* "cannot happen" */
837 					(void) fprintf(stderr,
838 _("%s: panic: Invalid l_value %d\n"),
839 						progname, lp->l_value);
840 					exit(EXIT_FAILURE);
841 			}
842 		}
843 		free(fields);
844 	}
845 	if (ferror(fp)) {
846 		(void) fprintf(stderr, _("%s: Error reading %s\n"),
847 			progname, filename);
848 		exit(EXIT_FAILURE);
849 	}
850 	if (fp != stdin && fclose(fp)) {
851 		const char *e = strerror(errno);
852 
853 		(void) fprintf(stderr, _("%s: Error closing %s: %s\n"),
854 			progname, filename, e);
855 		exit(EXIT_FAILURE);
856 	}
857 	if (wantcont)
858 		error(_("expected continuation line not found"));
859 }
860 
861 /*
862 ** Convert a string of one of the forms
863 **	h	-h	hh:mm	-hh:mm	hh:mm:ss	-hh:mm:ss
864 ** into a number of seconds.
865 ** A null string maps to zero.
866 ** Call error with errstring and return zero on errors.
867 */
868 
869 static zic_t
870 gethms(const char *string, const char *const errstring, const int signable)
871 {
872 	zic_t	hh;
873 	int	mm, ss, sign;
874 
875 	if (string == NULL || *string == '\0')
876 		return 0;
877 	if (!signable)
878 		sign = 1;
879 	else if (*string == '-') {
880 		sign = -1;
881 		++string;
882 	} else	sign = 1;
883 	if (sscanf(string, scheck(string, "%jd"), &hh) == 1)
884 		mm = ss = 0;
885 	else if (sscanf(string, scheck(string, "%jd:%d"), &hh, &mm) == 2)
886 		ss = 0;
887 	else if (sscanf(string, scheck(string, "%jd:%d:%d"),
888 		&hh, &mm, &ss) != 3) {
889 			error(errstring);
890 			return 0;
891 	}
892 	if (hh < 0 ||
893 		mm < 0 || mm >= MINSPERHOUR ||
894 		ss < 0 || ss > SECSPERMIN) {
895 			error(errstring);
896 			return 0;
897 	}
898 	if (LONG_MAX / SECSPERHOUR < hh) {
899 		error(_("time overflow"));
900 		return 0;
901 	}
902 	if (noise && hh == HOURSPERDAY && mm == 0 && ss == 0)
903 		warning(_("24:00 not handled by pre-1998 versions of zic"));
904 	if (noise && (hh > HOURSPERDAY ||
905 		(hh == HOURSPERDAY && (mm != 0 || ss != 0))))
906 warning(_("values over 24 hours not handled by pre-2007 versions of zic"));
907 	return oadd(eitol(sign) * hh * eitol(SECSPERHOUR),
908 		    eitol(sign) * (eitol(mm) * eitol(SECSPERMIN) + eitol(ss)));
909 }
910 
911 static void
912 inrule(char **const fields, const int nfields)
913 {
914 	static struct rule	r;
915 
916 	if (nfields != RULE_FIELDS) {
917 		error(_("wrong number of fields on Rule line"));
918 		return;
919 	}
920 	if (*fields[RF_NAME] == '\0') {
921 		error(_("nameless rule"));
922 		return;
923 	}
924 	r.r_filename = filename;
925 	r.r_linenum = linenum;
926 	r.r_stdoff = gethms(fields[RF_STDOFF], _("invalid saved time"), TRUE);
927 	rulesub(&r, fields[RF_LOYEAR], fields[RF_HIYEAR], fields[RF_COMMAND],
928 		fields[RF_MONTH], fields[RF_DAY], fields[RF_TOD]);
929 	r.r_name = ecpyalloc(fields[RF_NAME]);
930 	r.r_abbrvar = ecpyalloc(fields[RF_ABBRVAR]);
931 	if (max_abbrvar_len < strlen(r.r_abbrvar))
932 		max_abbrvar_len = strlen(r.r_abbrvar);
933 	rules = erealloc(rules, (nrules + 1) * sizeof *rules);
934 	rules[nrules++] = r;
935 }
936 
937 static int
938 inzone(char **const fields, const int nfields)
939 {
940 	int	i;
941 	static char *	buf;
942 
943 	if (nfields < ZONE_MINFIELDS || nfields > ZONE_MAXFIELDS) {
944 		error(_("wrong number of fields on Zone line"));
945 		return FALSE;
946 	}
947 	if (strcmp(fields[ZF_NAME], TZDEFAULT) == 0 && lcltime != NULL) {
948 		buf = erealloc(buf, 132 + strlen(TZDEFAULT));
949 		(void)sprintf(buf,	/* XXX: sprintf is safe */
950 _("\"Zone %s\" line and -l option are mutually exclusive"),
951 			TZDEFAULT);
952 		error(buf);
953 		return FALSE;
954 	}
955 	if (strcmp(fields[ZF_NAME], TZDEFRULES) == 0 && psxrules != NULL) {
956 		buf = erealloc(buf, 132 + strlen(TZDEFRULES));
957 		(void)sprintf(buf,	/* XXX: sprintf is safe */
958 _("\"Zone %s\" line and -p option are mutually exclusive"),
959 			TZDEFRULES);
960 		error(buf);
961 		return FALSE;
962 	}
963 	for (i = 0; i < nzones; ++i)
964 		if (zones[i].z_name != NULL &&
965 			strcmp(zones[i].z_name, fields[ZF_NAME]) == 0) {
966 				buf = erealloc(buf, 132 +
967 					strlen(fields[ZF_NAME]) +
968 					strlen(zones[i].z_filename));
969 				(void)sprintf(buf,	/* XXX: sprintf is safe */
970 _("duplicate zone name %s (file \"%s\", line %d)"),
971 					fields[ZF_NAME],
972 					zones[i].z_filename,
973 					zones[i].z_linenum);
974 				error(buf);
975 				return FALSE;
976 		}
977 	return inzsub(fields, nfields, FALSE);
978 }
979 
980 static int
981 inzcont(char **const fields, const int nfields)
982 {
983 	if (nfields < ZONEC_MINFIELDS || nfields > ZONEC_MAXFIELDS) {
984 		error(_("wrong number of fields on Zone continuation line"));
985 		return FALSE;
986 	}
987 	return inzsub(fields, nfields, TRUE);
988 }
989 
990 static int
991 inzsub(char **const fields, const int nfields, const int iscont)
992 {
993 	char *		cp;
994 	static struct zone	z;
995 	int		i_gmtoff, i_rule, i_format;
996 	int		i_untilyear, i_untilmonth;
997 	int		i_untilday, i_untiltime;
998 	int		hasuntil;
999 
1000 	if (iscont) {
1001 		i_gmtoff = ZFC_GMTOFF;
1002 		i_rule = ZFC_RULE;
1003 		i_format = ZFC_FORMAT;
1004 		i_untilyear = ZFC_TILYEAR;
1005 		i_untilmonth = ZFC_TILMONTH;
1006 		i_untilday = ZFC_TILDAY;
1007 		i_untiltime = ZFC_TILTIME;
1008 		z.z_name = NULL;
1009 	} else {
1010 		i_gmtoff = ZF_GMTOFF;
1011 		i_rule = ZF_RULE;
1012 		i_format = ZF_FORMAT;
1013 		i_untilyear = ZF_TILYEAR;
1014 		i_untilmonth = ZF_TILMONTH;
1015 		i_untilday = ZF_TILDAY;
1016 		i_untiltime = ZF_TILTIME;
1017 		z.z_name = ecpyalloc(fields[ZF_NAME]);
1018 	}
1019 	z.z_filename = filename;
1020 	z.z_linenum = linenum;
1021 	z.z_gmtoff = gethms(fields[i_gmtoff], _("invalid UTC offset"), TRUE);
1022 	if ((cp = strchr(fields[i_format], '%')) != 0) {
1023 		if (*++cp != 's' || strchr(cp, '%') != 0) {
1024 			error(_("invalid abbreviation format"));
1025 			return FALSE;
1026 		}
1027 	}
1028 	z.z_rule = ecpyalloc(fields[i_rule]);
1029 	z.z_format = ecpyalloc(fields[i_format]);
1030 	if (max_format_len < strlen(z.z_format))
1031 		max_format_len = strlen(z.z_format);
1032 	hasuntil = nfields > i_untilyear;
1033 	if (hasuntil) {
1034 		z.z_untilrule.r_filename = filename;
1035 		z.z_untilrule.r_linenum = linenum;
1036 		rulesub(&z.z_untilrule,
1037 			fields[i_untilyear],
1038 			"only",
1039 			"",
1040 			(nfields > i_untilmonth) ?
1041 			fields[i_untilmonth] : "Jan",
1042 			(nfields > i_untilday) ? fields[i_untilday] : "1",
1043 			(nfields > i_untiltime) ? fields[i_untiltime] : "0");
1044 		z.z_untiltime = rpytime(&z.z_untilrule,
1045 			z.z_untilrule.r_loyear);
1046 		if (iscont && nzones > 0 &&
1047 			z.z_untiltime > min_time &&
1048 			z.z_untiltime < max_time &&
1049 			zones[nzones - 1].z_untiltime > min_time &&
1050 			zones[nzones - 1].z_untiltime < max_time &&
1051 			zones[nzones - 1].z_untiltime >= z.z_untiltime) {
1052 				error(_(
1053 "Zone continuation line end time is not after end time of previous line"
1054 					));
1055 				return FALSE;
1056 		}
1057 	}
1058 	zones = erealloc(zones, (nzones + 1) * sizeof *zones);
1059 	zones[nzones++] = z;
1060 	/*
1061 	** If there was an UNTIL field on this line,
1062 	** there's more information about the zone on the next line.
1063 	*/
1064 	return hasuntil;
1065 }
1066 
1067 static void
1068 inleap(char **const fields, const int nfields)
1069 {
1070 	const char *		cp;
1071 	const struct lookup *	lp;
1072 	int			i, j;
1073 	int				year, month, day;
1074 	zic_t				dayoff, tod;
1075 	zic_t				t;
1076 
1077 	if (nfields != LEAP_FIELDS) {
1078 		error(_("wrong number of fields on Leap line"));
1079 		return;
1080 	}
1081 	dayoff = 0;
1082 	cp = fields[LP_YEAR];
1083 	if (sscanf(cp, scheck(cp, "%d"), &year) != 1) {
1084 		/*
1085 		** Leapin' Lizards!
1086 		*/
1087 		error(_("invalid leaping year"));
1088 		return;
1089 	}
1090 	if (!leapseen || leapmaxyear < year)
1091 		leapmaxyear = year;
1092 	if (!leapseen || leapminyear > year)
1093 		leapminyear = year;
1094 	leapseen = TRUE;
1095 	j = EPOCH_YEAR;
1096 	while (j != year) {
1097 		if (year > j) {
1098 			i = len_years[isleap(j)];
1099 			++j;
1100 		} else {
1101 			--j;
1102 			i = -len_years[isleap(j)];
1103 		}
1104 		dayoff = oadd(dayoff, eitol(i));
1105 	}
1106 	if ((lp = byword(fields[LP_MONTH], mon_names)) == NULL) {
1107 		error(_("invalid month name"));
1108 		return;
1109 	}
1110 	month = lp->l_value;
1111 	j = TM_JANUARY;
1112 	while (j != month) {
1113 		i = len_months[isleap(year)][j];
1114 		dayoff = oadd(dayoff, eitol(i));
1115 		++j;
1116 	}
1117 	cp = fields[LP_DAY];
1118 	if (sscanf(cp, scheck(cp, "%d"), &day) != 1 ||
1119 		day <= 0 || day > len_months[isleap(year)][month]) {
1120 			error(_("invalid day of month"));
1121 			return;
1122 	}
1123 	dayoff = oadd(dayoff, eitol(day - 1));
1124 	if (dayoff < 0 && !TYPE_SIGNED(zic_t)) {
1125 		error(_("time before zero"));
1126 		return;
1127 	}
1128 	if (dayoff < min_time / SECSPERDAY) {
1129 		error(_("time too small"));
1130 		return;
1131 	}
1132 	if (dayoff > max_time / SECSPERDAY) {
1133 		error(_("time too large"));
1134 		return;
1135 	}
1136 	t = (zic_t) dayoff * SECSPERDAY;
1137 	tod = gethms(fields[LP_TIME], _("invalid time of day"), FALSE);
1138 	cp = fields[LP_CORR];
1139 	{
1140 		int	positive;
1141 		int		count;
1142 
1143 		if (strcmp(cp, "") == 0) { /* infile() turns "-" into "" */
1144 			positive = FALSE;
1145 			count = 1;
1146 		} else if (strcmp(cp, "--") == 0) {
1147 			positive = FALSE;
1148 			count = 2;
1149 		} else if (strcmp(cp, "+") == 0) {
1150 			positive = TRUE;
1151 			count = 1;
1152 		} else if (strcmp(cp, "++") == 0) {
1153 			positive = TRUE;
1154 			count = 2;
1155 		} else {
1156 			error(_("illegal CORRECTION field on Leap line"));
1157 			return;
1158 		}
1159 		if ((lp = byword(fields[LP_ROLL], leap_types)) == NULL) {
1160 			error(_(
1161 				"illegal Rolling/Stationary field on Leap line"
1162 				));
1163 			return;
1164 		}
1165 		leapadd(tadd(t, tod), positive, lp->l_value, count);
1166 	}
1167 }
1168 
1169 static void
1170 inlink(char **const fields, const int nfields)
1171 {
1172 	struct link	l;
1173 
1174 	if (nfields != LINK_FIELDS) {
1175 		error(_("wrong number of fields on Link line"));
1176 		return;
1177 	}
1178 	if (*fields[LF_FROM] == '\0') {
1179 		error(_("blank FROM field on Link line"));
1180 		return;
1181 	}
1182 	if (*fields[LF_TO] == '\0') {
1183 		error(_("blank TO field on Link line"));
1184 		return;
1185 	}
1186 	l.l_filename = filename;
1187 	l.l_linenum = linenum;
1188 	l.l_from = ecpyalloc(fields[LF_FROM]);
1189 	l.l_to = ecpyalloc(fields[LF_TO]);
1190 	links = erealloc(links, (nlinks + 1) * sizeof *links);
1191 	links[nlinks++] = l;
1192 }
1193 
1194 static void
1195 rulesub(struct rule *const rp, const char *const loyearp,
1196     const char *const hiyearp, const char *const typep,
1197     const char *const monthp, const char *const dayp, const char *const timep)
1198 {
1199 	const struct lookup *	lp;
1200 	const char *		cp;
1201 	char *			dp;
1202 	char *			ep;
1203 
1204 	if ((lp = byword(monthp, mon_names)) == NULL) {
1205 		error(_("invalid month name"));
1206 		return;
1207 	}
1208 	rp->r_month = lp->l_value;
1209 	rp->r_todisstd = FALSE;
1210 	rp->r_todisgmt = FALSE;
1211 	dp = ecpyalloc(timep);
1212 	if (*dp != '\0') {
1213 		ep = dp + strlen(dp) - 1;
1214 		switch (lowerit(*ep)) {
1215 			case 's':	/* Standard */
1216 				rp->r_todisstd = TRUE;
1217 				rp->r_todisgmt = FALSE;
1218 				*ep = '\0';
1219 				break;
1220 			case 'w':	/* Wall */
1221 				rp->r_todisstd = FALSE;
1222 				rp->r_todisgmt = FALSE;
1223 				*ep = '\0';
1224 				break;
1225 			case 'g':	/* Greenwich */
1226 			case 'u':	/* Universal */
1227 			case 'z':	/* Zulu */
1228 				rp->r_todisstd = TRUE;
1229 				rp->r_todisgmt = TRUE;
1230 				*ep = '\0';
1231 				break;
1232 		}
1233 	}
1234 	rp->r_tod = gethms(dp, _("invalid time of day"), FALSE);
1235 	free(dp);
1236 	/*
1237 	** Year work.
1238 	*/
1239 	cp = loyearp;
1240 	lp = byword(cp, begin_years);
1241 	rp->r_lowasnum = lp == NULL;
1242 	if (!rp->r_lowasnum) switch ((int) lp->l_value) {
1243 		case YR_MINIMUM:
1244 			rp->r_loyear = INT_MIN;
1245 			break;
1246 		case YR_MAXIMUM:
1247 			rp->r_loyear = INT_MAX;
1248 			break;
1249 		default:	/* "cannot happen" */
1250 			(void) fprintf(stderr,
1251 				_("%s: panic: Invalid l_value %d\n"),
1252 				progname, lp->l_value);
1253 			exit(EXIT_FAILURE);
1254 	} else if (sscanf(cp, scheck(cp, "%d"), &rp->r_loyear) != 1) {
1255 		error(_("invalid starting year"));
1256 		return;
1257 	}
1258 	cp = hiyearp;
1259 	lp = byword(cp, end_years);
1260 	rp->r_hiwasnum = lp == NULL;
1261 	if (!rp->r_hiwasnum) switch ((int) lp->l_value) {
1262 		case YR_MINIMUM:
1263 			rp->r_hiyear = INT_MIN;
1264 			break;
1265 		case YR_MAXIMUM:
1266 			rp->r_hiyear = INT_MAX;
1267 			break;
1268 		case YR_ONLY:
1269 			rp->r_hiyear = rp->r_loyear;
1270 			break;
1271 		default:	/* "cannot happen" */
1272 			(void) fprintf(stderr,
1273 				_("%s: panic: Invalid l_value %d\n"),
1274 				progname, lp->l_value);
1275 			exit(EXIT_FAILURE);
1276 	} else if (sscanf(cp, scheck(cp, "%d"), &rp->r_hiyear) != 1) {
1277 		error(_("invalid ending year"));
1278 		return;
1279 	}
1280 	if (rp->r_loyear > rp->r_hiyear) {
1281 		error(_("starting year greater than ending year"));
1282 		return;
1283 	}
1284 	if (*typep == '\0')
1285 		rp->r_yrtype = NULL;
1286 	else {
1287 		if (rp->r_loyear == rp->r_hiyear) {
1288 			error(_("typed single year"));
1289 			return;
1290 		}
1291 		rp->r_yrtype = ecpyalloc(typep);
1292 	}
1293 	/*
1294 	** Day work.
1295 	** Accept things such as:
1296 	**	1
1297 	**	last-Sunday
1298 	**	Sun<=20
1299 	**	Sun>=7
1300 	*/
1301 	dp = ecpyalloc(dayp);
1302 	if ((lp = byword(dp, lasts)) != NULL) {
1303 		rp->r_dycode = DC_DOWLEQ;
1304 		rp->r_wday = lp->l_value;
1305 		rp->r_dayofmonth = len_months[1][rp->r_month];
1306 	} else {
1307 		if ((ep = strchr(dp, '<')) != 0)
1308 			rp->r_dycode = DC_DOWLEQ;
1309 		else if ((ep = strchr(dp, '>')) != 0)
1310 			rp->r_dycode = DC_DOWGEQ;
1311 		else {
1312 			ep = dp;
1313 			rp->r_dycode = DC_DOM;
1314 		}
1315 		if (rp->r_dycode != DC_DOM) {
1316 			*ep++ = 0;
1317 			if (*ep++ != '=') {
1318 				error(_("invalid day of month"));
1319 				free(dp);
1320 				return;
1321 			}
1322 			if ((lp = byword(dp, wday_names)) == NULL) {
1323 				error(_("invalid weekday name"));
1324 				free(dp);
1325 				return;
1326 			}
1327 			rp->r_wday = lp->l_value;
1328 		}
1329 		if (sscanf(ep, scheck(ep, "%d"), &rp->r_dayofmonth) != 1 ||
1330 			rp->r_dayofmonth <= 0 ||
1331 			(rp->r_dayofmonth > len_months[1][rp->r_month])) {
1332 				error(_("invalid day of month"));
1333 				free(dp);
1334 				return;
1335 		}
1336 	}
1337 	free(dp);
1338 }
1339 
1340 static void
1341 convert(const zic_t val, char *const buf)
1342 {
1343 	int	i;
1344 	int	shift;
1345 	unsigned char *const b = (unsigned char *) buf;
1346 
1347 	for (i = 0, shift = 24; i < 4; ++i, shift -= 8)
1348 		b[i] = val >> shift;
1349 }
1350 
1351 static void
1352 convert64(const zic_t val, char *const buf)
1353 {
1354 	int	i;
1355 	int	shift;
1356 	unsigned char *const b = (unsigned char *) buf;
1357 
1358 	for (i = 0, shift = 56; i < 8; ++i, shift -= 8)
1359 		b[i] = val >> shift;
1360 }
1361 
1362 static void
1363 puttzcode(const zic_t val, FILE *const fp)
1364 {
1365 	char	buf[4];
1366 
1367 	convert(val, buf);
1368 	(void) fwrite(buf, sizeof buf, (size_t) 1, fp);
1369 }
1370 
1371 static void
1372 puttzcode64(const zic_t val, FILE *const fp)
1373 {
1374 	char	buf[8];
1375 
1376 	convert64(val, buf);
1377 	(void) fwrite(buf, sizeof buf, (size_t) 1, fp);
1378 }
1379 
1380 static int
1381 atcomp(const void *avp, const void *bvp)
1382 {
1383 	const zic_t	a = ((const struct attype *) avp)->at;
1384 	const zic_t	b = ((const struct attype *) bvp)->at;
1385 
1386 	return (a < b) ? -1 : (a > b);
1387 }
1388 
1389 static int
1390 is32(const zic_t x)
1391 {
1392 	return INT32_MIN <= x && x <= INT32_MAX;
1393 }
1394 
1395 static void
1396 writezone(const char *const name, const char *const string)
1397 {
1398 	FILE *			fp;
1399 	int			i, j;
1400 	int			leapcnt32, leapi32;
1401 	int			timecnt32, timei32;
1402 	int			pass;
1403 	static char *			fullname;
1404 	static const struct tzhead	tzh0;
1405 	static struct tzhead		tzh;
1406 	zic_t				ats[TZ_MAX_TIMES];
1407 	unsigned char			types[TZ_MAX_TIMES];
1408 
1409 	/*
1410 	** Sort.
1411 	*/
1412 	if (timecnt > 1)
1413 		(void) qsort(attypes, (size_t) timecnt, sizeof *attypes,
1414 		    atcomp);
1415 	/*
1416 	** Optimize.
1417 	*/
1418 	{
1419 		int	fromi;
1420 		int	toi;
1421 
1422 		toi = 0;
1423 		fromi = 0;
1424 		while (fromi < timecnt && attypes[fromi].at < min_time)
1425 			++fromi;
1426 		if (isdsts[0] == 0)
1427 			while (fromi < timecnt && attypes[fromi].type == 0)
1428 				++fromi;	/* handled by default rule */
1429 		for ( ; fromi < timecnt; ++fromi) {
1430 			if (toi != 0 && ((attypes[fromi].at +
1431 				gmtoffs[attypes[toi - 1].type]) <=
1432 				(attypes[toi - 1].at + gmtoffs[toi == 1 ? 0
1433 				: attypes[toi - 2].type]))) {
1434 					attypes[toi - 1].type =
1435 						attypes[fromi].type;
1436 					continue;
1437 			}
1438 			if (toi == 0 ||
1439 				attypes[toi - 1].type != attypes[fromi].type)
1440 					attypes[toi++] = attypes[fromi];
1441 		}
1442 		timecnt = toi;
1443 	}
1444 	/*
1445 	** Transfer.
1446 	*/
1447 	for (i = 0; i < timecnt; ++i) {
1448 		ats[i] = attypes[i].at;
1449 		types[i] = attypes[i].type;
1450 	}
1451 	/*
1452 	** Correct for leap seconds.
1453 	*/
1454 	for (i = 0; i < timecnt; ++i) {
1455 		j = leapcnt;
1456 		while (--j >= 0)
1457 			if (ats[i] > trans[j] - corr[j]) {
1458 				ats[i] = tadd(ats[i], corr[j]);
1459 				break;
1460 			}
1461 	}
1462 	/*
1463 	** Figure out 32-bit-limited starts and counts.
1464 	*/
1465 	timecnt32 = timecnt;
1466 	timei32 = 0;
1467 	leapcnt32 = leapcnt;
1468 	leapi32 = 0;
1469 	while (timecnt32 > 0 && !is32(ats[timecnt32 - 1]))
1470 		--timecnt32;
1471 	while (timecnt32 > 0 && !is32(ats[timei32])) {
1472 		--timecnt32;
1473 		++timei32;
1474 	}
1475 	while (leapcnt32 > 0 && !is32(trans[leapcnt32 - 1]))
1476 		--leapcnt32;
1477 	while (leapcnt32 > 0 && !is32(trans[leapi32])) {
1478 		--leapcnt32;
1479 		++leapi32;
1480 	}
1481 	fullname = erealloc(fullname,
1482 	    strlen(directory) + 1 + strlen(name) + 1);
1483 	(void) sprintf(fullname, "%s/%s", directory, name);	/* XXX: sprintf is safe */
1484 	/*
1485 	** Remove old file, if any, to snap links.
1486 	*/
1487 	if (!itsdir(fullname) && remove(fullname) != 0 && errno != ENOENT) {
1488 		const char *e = strerror(errno);
1489 
1490 		(void) fprintf(stderr, _("%s: Can't remove %s: %s\n"),
1491 			progname, fullname, e);
1492 		exit(EXIT_FAILURE);
1493 	}
1494 	if ((fp = fopen(fullname, "wb")) == NULL) {
1495 		if (mkdirs(fullname) != 0)
1496 			exit(EXIT_FAILURE);
1497 		if ((fp = fopen(fullname, "wb")) == NULL) {
1498 			const char *e = strerror(errno);
1499 
1500 			(void) fprintf(stderr, _("%s: Can't create %s: %s\n"),
1501 				progname, fullname, e);
1502 			exit(EXIT_FAILURE);
1503 		}
1504 	}
1505 	for (pass = 1; pass <= 2; ++pass) {
1506 		int	thistimei, thistimecnt;
1507 		int	thisleapi, thisleapcnt;
1508 		int	thistimelim, thisleaplim;
1509 		int		writetype[TZ_MAX_TIMES];
1510 		int		typemap[TZ_MAX_TYPES];
1511 		int	thistypecnt;
1512 		char		thischars[TZ_MAX_CHARS];
1513 		char		thischarcnt;
1514 		int 		indmap[TZ_MAX_CHARS];
1515 
1516 		if (pass == 1) {
1517 			thistimei = timei32;
1518 			thistimecnt = timecnt32;
1519 			thisleapi = leapi32;
1520 			thisleapcnt = leapcnt32;
1521 		} else {
1522 			thistimei = 0;
1523 			thistimecnt = timecnt;
1524 			thisleapi = 0;
1525 			thisleapcnt = leapcnt;
1526 		}
1527 		thistimelim = thistimei + thistimecnt;
1528 		thisleaplim = thisleapi + thisleapcnt;
1529 		for (i = 0; i < typecnt; ++i)
1530 			writetype[i] = thistimecnt == timecnt;
1531 		if (thistimecnt == 0) {
1532 			/*
1533 			** No transition times fall in the current
1534 			** (32- or 64-bit) window.
1535 			*/
1536 			if (typecnt != 0)
1537 				writetype[typecnt - 1] = TRUE;
1538 		} else {
1539 			for (i = thistimei - 1; i < thistimelim; ++i)
1540 				if (i >= 0)
1541 					writetype[types[i]] = TRUE;
1542 			/*
1543 			** For America/Godthab and Antarctica/Palmer
1544 			*/
1545 			if (thistimei == 0)
1546 				writetype[0] = TRUE;
1547 		}
1548 #ifndef LEAVE_SOME_PRE_2011_SYSTEMS_IN_THE_LURCH
1549 		/*
1550 		** For some pre-2011 systems: if the last-to-be-written
1551 		** standard (or daylight) type has an offset different from the
1552 		** most recently used offset,
1553 		** append an (unused) copy of the most recently used type
1554 		** (to help get global "altzone" and "timezone" variables
1555 		** set correctly).
1556 		*/
1557 		{
1558 			int	mrudst, mrustd, hidst, histd, type;
1559 
1560 			hidst = histd = mrudst = mrustd = -1;
1561 			for (i = thistimei; i < thistimelim; ++i)
1562 				if (isdsts[types[i]])
1563 					mrudst = types[i];
1564 				else	mrustd = types[i];
1565 			for (i = 0; i < typecnt; ++i)
1566 				if (writetype[i]) {
1567 					if (isdsts[i])
1568 						hidst = i;
1569 					else	histd = i;
1570 				}
1571 			if (hidst >= 0 && mrudst >= 0 && hidst != mrudst &&
1572 				gmtoffs[hidst] != gmtoffs[mrudst]) {
1573 					isdsts[mrudst] = -1;
1574 					type = addtype(gmtoffs[mrudst],
1575 						&chars[abbrinds[mrudst]],
1576 						TRUE,
1577 						ttisstds[mrudst],
1578 						ttisgmts[mrudst]);
1579 					isdsts[mrudst] = TRUE;
1580 					writetype[type] = TRUE;
1581 			}
1582 			if (histd >= 0 && mrustd >= 0 && histd != mrustd &&
1583 				gmtoffs[histd] != gmtoffs[mrustd]) {
1584 					isdsts[mrustd] = -1;
1585 					type = addtype(gmtoffs[mrustd],
1586 						&chars[abbrinds[mrustd]],
1587 						FALSE,
1588 						ttisstds[mrustd],
1589 						ttisgmts[mrustd]);
1590 					isdsts[mrustd] = FALSE;
1591 					writetype[type] = TRUE;
1592 			}
1593 		}
1594 #endif /* !defined LEAVE_SOME_PRE_2011_SYSTEMS_IN_THE_LURCH */
1595 		thistypecnt = 0;
1596 		for (i = 0; i < typecnt; ++i)
1597 			typemap[i] = writetype[i] ?  thistypecnt++ : -1;
1598 		for (i = 0; i < (int)(sizeof indmap / sizeof indmap[0]); ++i)
1599 			indmap[i] = -1;
1600 		thischarcnt = 0;
1601 		for (i = 0; i < typecnt; ++i) {
1602 			char *	thisabbr;
1603 
1604 			if (!writetype[i])
1605 				continue;
1606 			if (indmap[abbrinds[i]] >= 0)
1607 				continue;
1608 			thisabbr = &chars[abbrinds[i]];
1609 			for (j = 0; j < thischarcnt; ++j)
1610 				if (strcmp(&thischars[j], thisabbr) == 0)
1611 					break;
1612 			if (j == thischarcnt) {
1613 				(void) strcpy(&thischars[(int) thischarcnt],
1614 					thisabbr);
1615 				thischarcnt += strlen(thisabbr) + 1;
1616 			}
1617 			indmap[abbrinds[i]] = j;
1618 		}
1619 #define DO(field)	(void) fwrite(tzh.field, \
1620 				sizeof tzh.field, (size_t) 1, fp)
1621 		tzh = tzh0;
1622 		(void) strncpy(tzh.tzh_magic, TZ_MAGIC, sizeof tzh.tzh_magic);
1623 		tzh.tzh_version[0] = ZIC_VERSION;
1624 		convert(eitol(thistypecnt), tzh.tzh_ttisgmtcnt);
1625 		convert(eitol(thistypecnt), tzh.tzh_ttisstdcnt);
1626 		convert(eitol(thisleapcnt), tzh.tzh_leapcnt);
1627 		convert(eitol(thistimecnt), tzh.tzh_timecnt);
1628 		convert(eitol(thistypecnt), tzh.tzh_typecnt);
1629 		convert(eitol(thischarcnt), tzh.tzh_charcnt);
1630 		DO(tzh_magic);
1631 		DO(tzh_version);
1632 		DO(tzh_reserved);
1633 		DO(tzh_ttisgmtcnt);
1634 		DO(tzh_ttisstdcnt);
1635 		DO(tzh_leapcnt);
1636 		DO(tzh_timecnt);
1637 		DO(tzh_typecnt);
1638 		DO(tzh_charcnt);
1639 #undef DO
1640 		for (i = thistimei; i < thistimelim; ++i)
1641 			if (pass == 1)
1642 				puttzcode(ats[i], fp);
1643 			else	puttzcode64(ats[i], fp);
1644 		for (i = thistimei; i < thistimelim; ++i) {
1645 			unsigned char	uc;
1646 
1647 			uc = typemap[types[i]];
1648 			(void) fwrite(&uc, sizeof uc, (size_t) 1, fp);
1649 		}
1650 		for (i = 0; i < typecnt; ++i)
1651 			if (writetype[i]) {
1652 				puttzcode(gmtoffs[i], fp);
1653 				(void) putc(isdsts[i], fp);
1654 				(void) putc((unsigned char) indmap[abbrinds[i]], fp);
1655 			}
1656 		if (thischarcnt != 0)
1657 			(void) fwrite(thischars, sizeof thischars[0],
1658 				(size_t) thischarcnt, fp);
1659 		for (i = thisleapi; i < thisleaplim; ++i) {
1660 			zic_t	todo;
1661 
1662 			if (roll[i]) {
1663 				if (timecnt == 0 || trans[i] < ats[0]) {
1664 					j = 0;
1665 					while (isdsts[j])
1666 						if (++j >= typecnt) {
1667 							j = 0;
1668 							break;
1669 						}
1670 				} else {
1671 					j = 1;
1672 					while (j < timecnt &&
1673 						trans[i] >= ats[j])
1674 							++j;
1675 					j = types[j - 1];
1676 				}
1677 				todo = tadd(trans[i], -gmtoffs[j]);
1678 			} else	todo = trans[i];
1679 			if (pass == 1)
1680 				puttzcode((zic_t) todo, fp);
1681 			else	puttzcode64(todo, fp);
1682 			puttzcode(corr[i], fp);
1683 		}
1684 		for (i = 0; i < typecnt; ++i)
1685 			if (writetype[i])
1686 				(void) putc(ttisstds[i], fp);
1687 		for (i = 0; i < typecnt; ++i)
1688 			if (writetype[i])
1689 				(void) putc(ttisgmts[i], fp);
1690 	}
1691 	(void) fprintf(fp, "\n%s\n", string);
1692 	if (ferror(fp) || fclose(fp)) {
1693 		(void) fprintf(stderr, _("%s: Error writing %s\n"),
1694 			progname, fullname);
1695 		exit(EXIT_FAILURE);
1696 	}
1697 }
1698 
1699 static void
1700 doabbr(char *const abbr, const int abbrlen, const char *const format,
1701     const char *const letters, const int isdst, const int doquotes)
1702 {
1703 	char *	cp;
1704 	char *	slashp;
1705 	int	len;
1706 
1707 	slashp = strchr(format, '/');
1708 	if (slashp == NULL) {
1709 		if (letters == NULL)
1710 			(void) strlcpy(abbr, format, abbrlen);
1711 		else	(void) snprintf(abbr, abbrlen, format, letters);
1712 	} else if (isdst) {
1713 		(void) strlcpy(abbr, slashp + 1, abbrlen);
1714 	} else {
1715 		if (slashp > format)
1716 			(void) strncpy(abbr, format, (size_t)(slashp - format));
1717 		abbr[slashp - format] = '\0';
1718 	}
1719 	if (!doquotes)
1720 		return;
1721 	for (cp = abbr; *cp != '\0'; ++cp)
1722 		if (strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZ", *cp) == NULL &&
1723 			strchr("abcdefghijklmnopqrstuvwxyz", *cp) == NULL)
1724 				break;
1725 	len = strlen(abbr);
1726 	if (len > 0 && *cp == '\0')
1727 		return;
1728 	abbr[len + 2] = '\0';
1729 	abbr[len + 1] = '>';
1730 	for ( ; len > 0; --len)
1731 		abbr[len] = abbr[len - 1];
1732 	abbr[0] = '<';
1733 }
1734 
1735 static void
1736 updateminmax(const int x)
1737 {
1738 	if (min_year > x)
1739 		min_year = x;
1740 	if (max_year < x)
1741 		max_year = x;
1742 }
1743 
1744 static int
1745 stringoffset(char *result, zic_t offset)
1746 {
1747 	int	hours;
1748 	int	minutes;
1749 	int	seconds;
1750 
1751 	result[0] = '\0';
1752 	if (offset < 0) {
1753 		(void) strcpy(result, "-");
1754 		offset = -offset;
1755 	}
1756 	seconds = offset % SECSPERMIN;
1757 	offset /= SECSPERMIN;
1758 	minutes = offset % MINSPERHOUR;
1759 	offset /= MINSPERHOUR;
1760 	hours = offset;
1761 	if (hours > HOURSPERDAY) {
1762 		result[0] = '\0';
1763 		return -1;
1764 	}
1765 	(void) sprintf(end(result), "%d", hours);
1766 	if (minutes != 0 || seconds != 0) {
1767 		(void) sprintf(end(result), ":%02d", minutes);
1768 		if (seconds != 0)
1769 			(void) sprintf(end(result), ":%02d", seconds);
1770 	}
1771 	return 0;
1772 }
1773 
1774 static int
1775 stringrule(char *result, const struct rule *const rp, const zic_t dstoff,
1776     const zic_t gmtoff)
1777 {
1778 	zic_t	tod;
1779 
1780 	result = end(result);
1781 	if (rp->r_dycode == DC_DOM) {
1782 		int	month, total;
1783 
1784 		if (rp->r_dayofmonth == 29 && rp->r_month == TM_FEBRUARY)
1785 			return -1;
1786 		total = 0;
1787 		for (month = 0; month < rp->r_month; ++month)
1788 			total += len_months[0][month];
1789 		(void) sprintf(result, "J%d", total + rp->r_dayofmonth);
1790 	} else {
1791 		int	week;
1792 
1793 		if (rp->r_dycode == DC_DOWGEQ) {
1794 			if ((rp->r_dayofmonth % DAYSPERWEEK) != 1)
1795 				return -1;
1796 			week = 1 + rp->r_dayofmonth / DAYSPERWEEK;
1797 		} else if (rp->r_dycode == DC_DOWLEQ) {
1798 			if (rp->r_dayofmonth == len_months[1][rp->r_month])
1799 				week = 5;
1800 			else {
1801 				if ((rp->r_dayofmonth % DAYSPERWEEK) != 0)
1802 					return -1;
1803 				week = rp->r_dayofmonth / DAYSPERWEEK;
1804 			}
1805 		} else	return -1;	/* "cannot happen" */
1806 		(void) sprintf(result, "M%d.%d.%d",
1807 			rp->r_month + 1, week, rp->r_wday);
1808 	}
1809 	tod = rp->r_tod;
1810 	if (rp->r_todisgmt)
1811 		tod += gmtoff;
1812 	if (rp->r_todisstd && rp->r_stdoff == 0)
1813 		tod += dstoff;
1814 	if (tod < 0) {
1815 		result[0] = '\0';
1816 		return -1;
1817 	}
1818 	if (tod != 2 * SECSPERMIN * MINSPERHOUR) {
1819 		(void) strcat(result, "/");
1820 		if (stringoffset(end(result), tod) != 0)
1821 			return -1;
1822 	}
1823 	return 0;
1824 }
1825 
1826 static void
1827 stringzone(char *result, const int resultlen, const struct zone *const zpfirst,
1828     const int zonecount)
1829 {
1830 	const struct zone *	zp;
1831 	struct rule *		rp;
1832 	struct rule *		stdrp;
1833 	struct rule *		dstrp;
1834 	int			i;
1835 	const char *		abbrvar;
1836 
1837 	result[0] = '\0';
1838 	zp = zpfirst + zonecount - 1;
1839 	stdrp = dstrp = NULL;
1840 	for (i = 0; i < zp->z_nrules; ++i) {
1841 		rp = &zp->z_rules[i];
1842 		if (rp->r_hiwasnum || rp->r_hiyear != INT_MAX)
1843 			continue;
1844 		if (rp->r_yrtype != NULL)
1845 			continue;
1846 		if (rp->r_stdoff == 0) {
1847 			if (stdrp == NULL)
1848 				stdrp = rp;
1849 			else	return;
1850 		} else {
1851 			if (dstrp == NULL)
1852 				dstrp = rp;
1853 			else	return;
1854 		}
1855 	}
1856 	if (stdrp == NULL && dstrp == NULL) {
1857 		/*
1858 		** There are no rules running through "max".
1859 		** Let's find the latest rule.
1860 		*/
1861 		for (i = 0; i < zp->z_nrules; ++i) {
1862 			rp = &zp->z_rules[i];
1863 			if (stdrp == NULL || rp->r_hiyear > stdrp->r_hiyear ||
1864 				(rp->r_hiyear == stdrp->r_hiyear &&
1865 				(rp->r_month > stdrp->r_month ||
1866 				(rp->r_month == stdrp->r_month &&
1867 				rp->r_dayofmonth > stdrp->r_dayofmonth))))
1868 					stdrp = rp;
1869 		}
1870 		if (stdrp != NULL && stdrp->r_stdoff != 0)
1871 			return;	/* We end up in DST (a POSIX no-no). */
1872 		/*
1873 		** Horrid special case: if year is 2037,
1874 		** presume this is a zone handled on a year-by-year basis;
1875 		** do not try to apply a rule to the zone.
1876 		*/
1877 		if (stdrp != NULL && stdrp->r_hiyear == 2037)
1878 			return;
1879 	}
1880 	if (stdrp == NULL && (zp->z_nrules != 0 || zp->z_stdoff != 0))
1881 		return;
1882 	abbrvar = (stdrp == NULL) ? "" : stdrp->r_abbrvar;
1883 	doabbr(result, resultlen, zp->z_format, abbrvar, FALSE, TRUE);
1884 	if (stringoffset(end(result), -zp->z_gmtoff) != 0) {
1885 		result[0] = '\0';
1886 		return;
1887 	}
1888 	if (dstrp == NULL)
1889 		return;
1890 	doabbr(end(result), resultlen - strlen(result),
1891 		zp->z_format, dstrp->r_abbrvar, TRUE, TRUE);
1892 	if (dstrp->r_stdoff != SECSPERMIN * MINSPERHOUR)
1893 		if (stringoffset(end(result),
1894 			-(zp->z_gmtoff + dstrp->r_stdoff)) != 0) {
1895 				result[0] = '\0';
1896 				return;
1897 		}
1898 	(void) strcat(result, ",");
1899 	if (stringrule(result, dstrp, dstrp->r_stdoff, zp->z_gmtoff) != 0) {
1900 		result[0] = '\0';
1901 		return;
1902 	}
1903 	(void) strcat(result, ",");
1904 	if (stringrule(result, stdrp, dstrp->r_stdoff, zp->z_gmtoff) != 0) {
1905 		result[0] = '\0';
1906 		return;
1907 	}
1908 }
1909 
1910 static void
1911 outzone(const struct zone *const zpfirst, const int zonecount)
1912 {
1913 	const struct zone *	zp;
1914 	struct rule *		rp;
1915 	int			i, j;
1916 	int			usestart, useuntil;
1917 	zic_t			starttime, untiltime;
1918 	zic_t			gmtoff;
1919 	zic_t			stdoff;
1920 	int			year;
1921 	zic_t			startoff;
1922 	int			startttisstd;
1923 	int			startttisgmt;
1924 	int			type;
1925 	char *			startbuf;
1926 	char *			ab;
1927 	char *			envvar;
1928 	size_t			max_abbr_len;
1929 	size_t			max_envvar_len;
1930 	int			prodstic; /* all rules are min to max */
1931 
1932 	max_abbr_len = 2 + max_format_len + max_abbrvar_len;
1933 	max_envvar_len = 2 * max_abbr_len + 5 * 9;
1934 	startbuf = emalloc(max_abbr_len + 1);
1935 	ab = emalloc(max_abbr_len + 1);
1936 	envvar = emalloc(max_envvar_len + 1);
1937 	INITIALIZE(untiltime);
1938 	INITIALIZE(starttime);
1939 	/*
1940 	** Now. . .finally. . .generate some useful data!
1941 	*/
1942 	timecnt = 0;
1943 	typecnt = 0;
1944 	charcnt = 0;
1945 	prodstic = zonecount == 1;
1946 	/*
1947 	** Thanks to Earl Chew
1948 	** for noting the need to unconditionally initialize startttisstd.
1949 	*/
1950 	startttisstd = FALSE;
1951 	startttisgmt = FALSE;
1952 	min_year = max_year = EPOCH_YEAR;
1953 	if (leapseen) {
1954 		updateminmax(leapminyear);
1955 		updateminmax(leapmaxyear + (leapmaxyear < INT_MAX));
1956 	}
1957 	for (i = 0; i < zonecount; ++i) {
1958 		zp = &zpfirst[i];
1959 		if (i < zonecount - 1)
1960 			updateminmax(zp->z_untilrule.r_loyear);
1961 		for (j = 0; j < zp->z_nrules; ++j) {
1962 			rp = &zp->z_rules[j];
1963 			if (rp->r_lowasnum)
1964 				updateminmax(rp->r_loyear);
1965 			if (rp->r_hiwasnum)
1966 				updateminmax(rp->r_hiyear);
1967 		}
1968 	}
1969 	/*
1970 	** Generate lots of data if a rule can't cover all future times.
1971 	*/
1972 	stringzone(envvar, max_envvar_len+1, zpfirst, zonecount);
1973 	if (noise && envvar[0] == '\0') {
1974 		char *	wp;
1975 
1976 		wp = ecpyalloc(_("no POSIX environment variable for zone"));
1977 		wp = ecatalloc(wp, " ");
1978 		wp = ecatalloc(wp, zpfirst->z_name);
1979 		warning(wp);
1980 		free(wp);
1981 	}
1982 	if (envvar[0] == '\0') {
1983 		if (min_year >= INT_MIN + YEARSPERREPEAT)
1984 			min_year -= YEARSPERREPEAT;
1985 		else	min_year = INT_MIN;
1986 		if (max_year <= INT_MAX - YEARSPERREPEAT)
1987 			max_year += YEARSPERREPEAT;
1988 		else	max_year = INT_MAX;
1989 		/*
1990 		** Regardless of any of the above,
1991 		** for a "proDSTic" zone which specifies that its rules
1992 		** always have and always will be in effect,
1993 		** we only need one cycle to define the zone.
1994 		*/
1995 		if (prodstic) {
1996 			min_year = 1900;
1997 			max_year = min_year + YEARSPERREPEAT;
1998 		}
1999 	}
2000 	/*
2001 	** For the benefit of older systems,
2002 	** generate data from 1900 through 2037.
2003 	*/
2004 	if (min_year > 1900)
2005 		min_year = 1900;
2006 	if (max_year < 2037)
2007 		max_year = 2037;
2008 	for (i = 0; i < zonecount; ++i) {
2009 		/*
2010 		** A guess that may well be corrected later.
2011 		*/
2012 		stdoff = 0;
2013 		zp = &zpfirst[i];
2014 		usestart = i > 0 && (zp - 1)->z_untiltime > min_time;
2015 		useuntil = i < (zonecount - 1);
2016 		if (useuntil && zp->z_untiltime <= min_time)
2017 			continue;
2018 		gmtoff = zp->z_gmtoff;
2019 		eat(zp->z_filename, zp->z_linenum);
2020 		*startbuf = '\0';
2021 		startoff = zp->z_gmtoff;
2022 		if (zp->z_nrules == 0) {
2023 			stdoff = zp->z_stdoff;
2024 			doabbr(startbuf, max_abbr_len + 1, zp->z_format,
2025 			        NULL, stdoff != 0, FALSE);
2026 			type = addtype(oadd(zp->z_gmtoff, stdoff),
2027 				startbuf, stdoff != 0, startttisstd,
2028 				startttisgmt);
2029 			if (usestart) {
2030 				addtt(starttime, type);
2031 				usestart = FALSE;
2032 			} else if (stdoff != 0)
2033 				addtt(min_time, type);
2034 		} else for (year = min_year; year <= max_year; ++year) {
2035 			if (useuntil && year > zp->z_untilrule.r_hiyear)
2036 				break;
2037 			/*
2038 			** Mark which rules to do in the current year.
2039 			** For those to do, calculate rpytime(rp, year);
2040 			*/
2041 			for (j = 0; j < zp->z_nrules; ++j) {
2042 				rp = &zp->z_rules[j];
2043 				eats(zp->z_filename, zp->z_linenum,
2044 					rp->r_filename, rp->r_linenum);
2045 				rp->r_todo = year >= rp->r_loyear &&
2046 						year <= rp->r_hiyear &&
2047 						yearistype(year, rp->r_yrtype);
2048 				if (rp->r_todo)
2049 					rp->r_temp = rpytime(rp, year);
2050 			}
2051 			for ( ; ; ) {
2052 				int	k;
2053 				zic_t	jtime, ktime;
2054 				zic_t	offset;
2055 
2056 				INITIALIZE(ktime);
2057 				if (useuntil) {
2058 					/*
2059 					** Turn untiltime into UTC
2060 					** assuming the current gmtoff and
2061 					** stdoff values.
2062 					*/
2063 					untiltime = zp->z_untiltime;
2064 					if (!zp->z_untilrule.r_todisgmt)
2065 						untiltime = tadd(untiltime,
2066 							-gmtoff);
2067 					if (!zp->z_untilrule.r_todisstd)
2068 						untiltime = tadd(untiltime,
2069 							-stdoff);
2070 				}
2071 				/*
2072 				** Find the rule (of those to do, if any)
2073 				** that takes effect earliest in the year.
2074 				*/
2075 				k = -1;
2076 				for (j = 0; j < zp->z_nrules; ++j) {
2077 					rp = &zp->z_rules[j];
2078 					if (!rp->r_todo)
2079 						continue;
2080 					eats(zp->z_filename, zp->z_linenum,
2081 						rp->r_filename, rp->r_linenum);
2082 					offset = rp->r_todisgmt ? 0 : gmtoff;
2083 					if (!rp->r_todisstd)
2084 						offset = oadd(offset, stdoff);
2085 					jtime = rp->r_temp;
2086 					if (jtime == min_time ||
2087 						jtime == max_time)
2088 							continue;
2089 					jtime = tadd(jtime, -offset);
2090 					if (k < 0 || jtime < ktime) {
2091 						k = j;
2092 						ktime = jtime;
2093 					}
2094 				}
2095 				if (k < 0)
2096 					break;	/* go on to next year */
2097 				rp = &zp->z_rules[k];
2098 				rp->r_todo = FALSE;
2099 				if (useuntil && ktime >= untiltime)
2100 					break;
2101 				stdoff = rp->r_stdoff;
2102 				if (usestart && ktime == starttime)
2103 					usestart = FALSE;
2104 				if (usestart) {
2105 					if (ktime < starttime) {
2106 						startoff = oadd(zp->z_gmtoff,
2107 							stdoff);
2108 						doabbr(startbuf,
2109 							max_abbr_len + 1,
2110 							zp->z_format,
2111 							rp->r_abbrvar,
2112 							rp->r_stdoff != 0,
2113 							FALSE);
2114 						continue;
2115 					}
2116 					if (*startbuf == '\0' &&
2117 						startoff == oadd(zp->z_gmtoff,
2118 						stdoff)) {
2119 							doabbr(startbuf,
2120 								max_abbr_len + 1,
2121 								zp->z_format,
2122 								rp->r_abbrvar,
2123 								rp->r_stdoff !=
2124 								0,
2125 								FALSE);
2126 					}
2127 				}
2128 				eats(zp->z_filename, zp->z_linenum,
2129 					rp->r_filename, rp->r_linenum);
2130 				doabbr(ab, max_abbr_len+1, zp->z_format, rp->r_abbrvar,
2131 					rp->r_stdoff != 0, FALSE);
2132 				offset = oadd(zp->z_gmtoff, rp->r_stdoff);
2133 				type = addtype(offset, ab, rp->r_stdoff != 0,
2134 					rp->r_todisstd, rp->r_todisgmt);
2135 				addtt(ktime, type);
2136 			}
2137 		}
2138 		if (usestart) {
2139 			if (*startbuf == '\0' &&
2140 				zp->z_format != NULL &&
2141 				strchr(zp->z_format, '%') == NULL &&
2142 				strchr(zp->z_format, '/') == NULL)
2143 					(void)strncpy(startbuf, zp->z_format,
2144 					    max_abbr_len + 1 - 1);
2145 			eat(zp->z_filename, zp->z_linenum);
2146 			if (*startbuf == '\0')
2147 error(_("can't determine time zone abbreviation to use just after until time"));
2148 			else	addtt(starttime,
2149 					addtype(startoff, startbuf,
2150 						startoff != zp->z_gmtoff,
2151 						startttisstd,
2152 						startttisgmt));
2153 		}
2154 		/*
2155 		** Now we may get to set starttime for the next zone line.
2156 		*/
2157 		if (useuntil) {
2158 			startttisstd = zp->z_untilrule.r_todisstd;
2159 			startttisgmt = zp->z_untilrule.r_todisgmt;
2160 			starttime = zp->z_untiltime;
2161 			if (!startttisstd)
2162 				starttime = tadd(starttime, -stdoff);
2163 			if (!startttisgmt)
2164 				starttime = tadd(starttime, -gmtoff);
2165 		}
2166 	}
2167 	writezone(zpfirst->z_name, envvar);
2168 	free(startbuf);
2169 	free(ab);
2170 	free(envvar);
2171 }
2172 
2173 static void
2174 addtt(const zic_t starttime, int type)
2175 {
2176 	if (starttime <= min_time ||
2177 		(timecnt == 1 && attypes[0].at < min_time)) {
2178 		gmtoffs[0] = gmtoffs[type];
2179 		isdsts[0] = isdsts[type];
2180 		ttisstds[0] = ttisstds[type];
2181 		ttisgmts[0] = ttisgmts[type];
2182 		if (abbrinds[type] != 0)
2183 			(void) strcpy(chars, &chars[abbrinds[type]]);
2184 		abbrinds[0] = 0;
2185 		charcnt = strlen(chars) + 1;
2186 		typecnt = 1;
2187 		timecnt = 0;
2188 		type = 0;
2189 	}
2190 	if (timecnt >= TZ_MAX_TIMES) {
2191 		error(_("too many transitions?!"));
2192 		exit(EXIT_FAILURE);
2193 	}
2194 	attypes[timecnt].at = starttime;
2195 	attypes[timecnt].type = type;
2196 	++timecnt;
2197 }
2198 
2199 static int
2200 addtype(const zic_t gmtoff, const char *const abbr, const int isdst,
2201     const int ttisstd, const int ttisgmt)
2202 {
2203 	int	i, j;
2204 
2205 	if (isdst != TRUE && isdst != FALSE) {
2206 		error(_("internal error - addtype called with bad isdst"));
2207 		exit(EXIT_FAILURE);
2208 	}
2209 	if (ttisstd != TRUE && ttisstd != FALSE) {
2210 		error(_("internal error - addtype called with bad ttisstd"));
2211 		exit(EXIT_FAILURE);
2212 	}
2213 	if (ttisgmt != TRUE && ttisgmt != FALSE) {
2214 		error(_("internal error - addtype called with bad ttisgmt"));
2215 		exit(EXIT_FAILURE);
2216 	}
2217 	/*
2218 	** See if there's already an entry for this zone type.
2219 	** If so, just return its index.
2220 	*/
2221 	for (i = 0; i < typecnt; ++i) {
2222 		if (gmtoff == gmtoffs[i] && isdst == isdsts[i] &&
2223 			strcmp(abbr, &chars[abbrinds[i]]) == 0 &&
2224 			ttisstd == ttisstds[i] &&
2225 			ttisgmt == ttisgmts[i])
2226 				return i;
2227 	}
2228 	/*
2229 	** There isn't one; add a new one, unless there are already too
2230 	** many.
2231 	*/
2232 	if (typecnt >= TZ_MAX_TYPES) {
2233 		error(_("too many local time types"));
2234 		exit(EXIT_FAILURE);
2235 	}
2236 	if (! (-1L - 2147483647L <= gmtoff && gmtoff <= 2147483647L)) {
2237 		error(_("UTC offset out of range"));
2238 		exit(EXIT_FAILURE);
2239 	}
2240 	gmtoffs[i] = gmtoff;
2241 	isdsts[i] = isdst;
2242 	ttisstds[i] = ttisstd;
2243 	ttisgmts[i] = ttisgmt;
2244 
2245 	for (j = 0; j < charcnt; ++j)
2246 		if (strcmp(&chars[j], abbr) == 0)
2247 			break;
2248 	if (j == charcnt)
2249 		newabbr(abbr);
2250 	abbrinds[i] = j;
2251 	++typecnt;
2252 	return i;
2253 }
2254 
2255 static void
2256 leapadd(const zic_t t, const int positive, const int rolling, int count)
2257 {
2258 	int	i, j;
2259 
2260 	if (leapcnt + (positive ? count : 1) > TZ_MAX_LEAPS) {
2261 		error(_("too many leap seconds"));
2262 		exit(EXIT_FAILURE);
2263 	}
2264 	for (i = 0; i < leapcnt; ++i)
2265 		if (t <= trans[i]) {
2266 			if (t == trans[i]) {
2267 				error(_("repeated leap second moment"));
2268 				exit(EXIT_FAILURE);
2269 			}
2270 			break;
2271 		}
2272 	do {
2273 		for (j = leapcnt; j > i; --j) {
2274 			trans[j] = trans[j - 1];
2275 			corr[j] = corr[j - 1];
2276 			roll[j] = roll[j - 1];
2277 		}
2278 		trans[i] = t;
2279 		corr[i] = positive ? 1L : eitol(-count);
2280 		roll[i] = rolling;
2281 		++leapcnt;
2282 	} while (positive && --count != 0);
2283 }
2284 
2285 static void
2286 adjleap(void)
2287 {
2288 	int	i;
2289 	zic_t	last = 0;
2290 
2291 	/*
2292 	** propagate leap seconds forward
2293 	*/
2294 	for (i = 0; i < leapcnt; ++i) {
2295 		trans[i] = tadd(trans[i], last);
2296 		last = corr[i] += last;
2297 	}
2298 }
2299 
2300 static int
2301 yearistype(const int year, const char *const type)
2302 {
2303 	static char *	buf;
2304 	int		result;
2305 
2306 	if (type == NULL || *type == '\0')
2307 		return TRUE;
2308 	buf = erealloc(buf, 132 + strlen(yitcommand) + strlen(type));
2309 	(void)sprintf(buf, "%s %d %s", yitcommand, year, type); /* XXX: sprintf is safe */
2310 	result = system(buf);
2311 	if (WIFEXITED(result)) switch (WEXITSTATUS(result)) {
2312 		case 0:
2313 			return TRUE;
2314 		case 1:
2315 			return FALSE;
2316 	}
2317 	error(_("Wild result from command execution"));
2318 	(void) fprintf(stderr, _("%s: command was '%s', result was %d\n"),
2319 		progname, buf, result);
2320 	for ( ; ; )
2321 		exit(EXIT_FAILURE);
2322 }
2323 
2324 static int
2325 lowerit(int a)
2326 {
2327 	a = (unsigned char) a;
2328 	return (isascii(a) && isupper(a)) ? tolower(a) : a;
2329 }
2330 
2331 /* case-insensitive equality */
2332 static __pure int
2333 ciequal(const char *ap, const char *bp)
2334 {
2335 	while (lowerit(*ap) == lowerit(*bp++))
2336 		if (*ap++ == '\0')
2337 			return TRUE;
2338 	return FALSE;
2339 }
2340 
2341 static __pure int
2342 itsabbr(const char *abbr, const char *word)
2343 {
2344 	if (lowerit(*abbr) != lowerit(*word))
2345 		return FALSE;
2346 	++word;
2347 	while (*++abbr != '\0')
2348 		do {
2349 			if (*word == '\0')
2350 				return FALSE;
2351 		} while (lowerit(*word++) != lowerit(*abbr));
2352 	return TRUE;
2353 }
2354 
2355 static __pure const struct lookup *
2356 byword(const char *const word, const struct lookup *const table)
2357 {
2358 	const struct lookup *	foundlp;
2359 	const struct lookup *	lp;
2360 
2361 	if (word == NULL || table == NULL)
2362 		return NULL;
2363 	/*
2364 	** Look for exact match.
2365 	*/
2366 	for (lp = table; lp->l_word != NULL; ++lp)
2367 		if (ciequal(word, lp->l_word))
2368 			return lp;
2369 	/*
2370 	** Look for inexact match.
2371 	*/
2372 	foundlp = NULL;
2373 	for (lp = table; lp->l_word != NULL; ++lp)
2374 		if (itsabbr(word, lp->l_word)) {
2375 			if (foundlp == NULL)
2376 				foundlp = lp;
2377 			else	return NULL;	/* multiple inexact matches */
2378 		}
2379 	return foundlp;
2380 }
2381 
2382 static char **
2383 getfields(char *cp)
2384 {
2385 	char *	dp;
2386 	char **	array;
2387 	int	nsubs;
2388 
2389 	if (cp == NULL)
2390 		return NULL;
2391 	array = emalloc((strlen(cp) + 1) * sizeof *array);
2392 	nsubs = 0;
2393 	for ( ; ; ) {
2394 		while (isascii((unsigned char) *cp) &&
2395 			isspace((unsigned char) *cp))
2396 				++cp;
2397 		if (*cp == '\0' || *cp == '#')
2398 			break;
2399 		array[nsubs++] = dp = cp;
2400 		do {
2401 			if ((*dp = *cp++) != '"')
2402 				++dp;
2403 			else while ((*dp = *cp++) != '"')
2404 				if (*dp != '\0')
2405 					++dp;
2406 				else {
2407 					error(_(
2408 						"Odd number of quotation marks"
2409 						));
2410 					exit(1);
2411 				}
2412 		} while (*cp != '\0' && *cp != '#' &&
2413 			(!isascii(*cp) || !isspace((unsigned char) *cp)));
2414 		if (isascii(*cp) && isspace((unsigned char) *cp))
2415 			++cp;
2416 		*dp = '\0';
2417 	}
2418 	array[nsubs] = NULL;
2419 	return array;
2420 }
2421 
2422 static __pure zic_t
2423 oadd(const zic_t t1, const zic_t t2)
2424 {
2425 	if (t1 < 0 ? t2 < LONG_MIN - t1 : LONG_MAX - t1 < t2) {
2426 		error(_("time overflow"));
2427 		exit(EXIT_FAILURE);
2428 	}
2429 	return t1 + t2;
2430 }
2431 
2432 static zic_t
2433 tadd(const zic_t t1, const zic_t t2)
2434 {
2435 	if (t1 == max_time && t2 > 0)
2436 		return max_time;
2437 	if (t1 == min_time && t2 < 0)
2438 		return min_time;
2439 	if (t1 < 0 ? t2 < min_time - t1 : max_time - t1 < t2) {
2440 		error(_("time overflow"));
2441 		exit(EXIT_FAILURE);
2442 	}
2443 	return t1 + t2;
2444 }
2445 
2446 /*
2447 ** Given a rule, and a year, compute the date - in seconds since January 1,
2448 ** 1970, 00:00 LOCAL time - in that year that the rule refers to.
2449 */
2450 
2451 static zic_t
2452 rpytime(const struct rule *const rp, const int wantedy)
2453 {
2454 	int	y, m, i;
2455 	zic_t	dayoff;			/* with a nod to Margaret O. */
2456 	zic_t	t;
2457 
2458 	if (wantedy == INT_MIN)
2459 		return min_time;
2460 	if (wantedy == INT_MAX)
2461 		return max_time;
2462 	dayoff = 0;
2463 	m = TM_JANUARY;
2464 	y = EPOCH_YEAR;
2465 	while (wantedy != y) {
2466 		if (wantedy > y) {
2467 			i = len_years[isleap(y)];
2468 			++y;
2469 		} else {
2470 			--y;
2471 			i = -len_years[isleap(y)];
2472 		}
2473 		dayoff = oadd(dayoff, eitol(i));
2474 	}
2475 	while (m != rp->r_month) {
2476 		i = len_months[isleap(y)][m];
2477 		dayoff = oadd(dayoff, eitol(i));
2478 		++m;
2479 	}
2480 	i = rp->r_dayofmonth;
2481 	if (m == TM_FEBRUARY && i == 29 && !isleap(y)) {
2482 		if (rp->r_dycode == DC_DOWLEQ)
2483 			--i;
2484 		else {
2485 			error(_("use of 2/29 in non leap-year"));
2486 			exit(EXIT_FAILURE);
2487 		}
2488 	}
2489 	--i;
2490 	dayoff = oadd(dayoff, eitol(i));
2491 	if (rp->r_dycode == DC_DOWGEQ || rp->r_dycode == DC_DOWLEQ) {
2492 		zic_t	wday;
2493 
2494 #define LDAYSPERWEEK	((zic_t) DAYSPERWEEK)
2495 		wday = eitol(EPOCH_WDAY);
2496 		/*
2497 		** Don't trust mod of negative numbers.
2498 		*/
2499 		if (dayoff >= 0)
2500 			wday = (wday + dayoff) % LDAYSPERWEEK;
2501 		else {
2502 			wday -= ((-dayoff) % LDAYSPERWEEK);
2503 			if (wday < 0)
2504 				wday += LDAYSPERWEEK;
2505 		}
2506 		while (wday != eitol(rp->r_wday))
2507 			if (rp->r_dycode == DC_DOWGEQ) {
2508 				dayoff = oadd(dayoff, (zic_t) 1);
2509 				if (++wday >= LDAYSPERWEEK)
2510 					wday = 0;
2511 				++i;
2512 			} else {
2513 				dayoff = oadd(dayoff, (zic_t) -1);
2514 				if (--wday < 0)
2515 					wday = LDAYSPERWEEK - 1;
2516 				--i;
2517 			}
2518 		if (i < 0 || i >= len_months[isleap(y)][m]) {
2519 			if (noise)
2520 				warning(_("rule goes past start/end of month--\
2521 will not work with pre-2004 versions of zic"));
2522 		}
2523 	}
2524 	if (dayoff < min_time / SECSPERDAY)
2525 		return min_time;
2526 	if (dayoff > max_time / SECSPERDAY)
2527 		return max_time;
2528 	t = (zic_t) dayoff * SECSPERDAY;
2529 	return tadd(t, rp->r_tod);
2530 }
2531 
2532 static void
2533 newabbr(const char *const string)
2534 {
2535 	int	i;
2536 
2537 	if (strcmp(string, GRANDPARENTED) != 0) {
2538 		const char *	cp;
2539 		const char *	mp;
2540 
2541 		/*
2542 		** Want one to ZIC_MAX_ABBR_LEN_WO_WARN alphabetics
2543 		** optionally followed by a + or - and a number from 1 to 14.
2544 		*/
2545 		cp = string;
2546 		mp = NULL;
2547 		while (isascii((unsigned char) *cp) &&
2548 			isalpha((unsigned char) *cp))
2549 				++cp;
2550 		if (cp - string == 0)
2551 mp = _("time zone abbreviation lacks alphabetic at start");
2552 		if (noise && cp - string < 3)
2553 mp = _("time zone abbreviation has fewer than 3 alphabetics");
2554 		if (cp - string > ZIC_MAX_ABBR_LEN_WO_WARN)
2555 mp = _("time zone abbreviation has too many alphabetics");
2556 		if (mp == NULL && (*cp == '+' || *cp == '-')) {
2557 			++cp;
2558 			if (isascii((unsigned char) *cp) &&
2559 				isdigit((unsigned char) *cp))
2560 					if (*cp++ == '1' &&
2561 						*cp >= '0' && *cp <= '4')
2562 							++cp;
2563 		}
2564 		if (*cp != '\0')
2565 mp = _("time zone abbreviation differs from POSIX standard");
2566 		if (mp != NULL) {
2567 			char *wp = ecpyalloc(mp);
2568 			wp = ecatalloc(wp, " (");
2569 			wp = ecatalloc(wp, string);
2570 			wp = ecatalloc(wp, ")");
2571 			warning(wp);
2572 			free(wp);
2573 		}
2574 	}
2575 	i = strlen(string) + 1;
2576 	if (charcnt + i > TZ_MAX_CHARS) {
2577 		error(_("too many, or too long, time zone abbreviations"));
2578 		exit(EXIT_FAILURE);
2579 	}
2580 	(void)strncpy(&chars[charcnt], string, sizeof(chars) - charcnt - 1);
2581 	charcnt += eitol(i);
2582 }
2583 
2584 static int
2585 mkdirs(char *argname)
2586 {
2587 	char *	name;
2588 	char *	cp;
2589 
2590 	if (argname == NULL || *argname == '\0')
2591 		return 0;
2592 	cp = name = ecpyalloc(argname);
2593 	while ((cp = strchr(cp + 1, '/')) != 0) {
2594 		*cp = '\0';
2595 #ifndef __NetBSD__
2596 		/*
2597 		** DOS drive specifier?
2598 		*/
2599 		if (isalpha((unsigned char) name[0]) &&
2600 			name[1] == ':' && name[2] == '\0') {
2601 				*cp = '/';
2602 				continue;
2603 		}
2604 #endif /* !defined __NetBSD__ */
2605 		if (!itsdir(name)) {
2606 			/*
2607 			** It doesn't seem to exist, so we try to create it.
2608 			** Creation may fail because of the directory being
2609 			** created by some other multiprocessor, so we get
2610 			** to do extra checking.
2611 			*/
2612 			if (mkdir(name, MKDIR_UMASK) != 0) {
2613 				const char *e = strerror(errno);
2614 
2615 				if (errno != EEXIST || !itsdir(name)) {
2616 					(void) fprintf(stderr,
2617 _("%s: Can't create directory %s: %s\n"),
2618 						progname, name, e);
2619 					free(name);
2620 					return -1;
2621 				}
2622 			}
2623 		}
2624 		*cp = '/';
2625 	}
2626 	free(name);
2627 	return 0;
2628 }
2629 
2630 static zic_t
2631 eitol(const int i)
2632 {
2633 	zic_t	l;
2634 
2635 	l = i;
2636 	if ((i < 0 && l >= 0) || (i == 0 && l != 0) || (i > 0 && l <= 0)) {
2637 		(void) fprintf(stderr,
2638 			_("%s: %d did not sign extend correctly\n"),
2639 			progname, i);
2640 		exit(EXIT_FAILURE);
2641 	}
2642 	return l;
2643 }
2644 
2645 /*
2646 ** UNIX was a registered trademark of The Open Group in 2003.
2647 */
2648