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