xref: /netbsd-src/lib/libc/time/zic.c (revision 53b02e147d4ed531c0d2a5ca9b3e8026ba3e99b5)
1 /*	$NetBSD: zic.c,v 1.79 2021/10/22 14:26:04 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 /* Compile .zi time zone data into TZif binary files.  */
7 
8 #if HAVE_NBTOOL_CONFIG_H
9 #include "nbtool_config.h"
10 #endif
11 
12 #include <sys/cdefs.h>
13 #ifndef lint
14 __RCSID("$NetBSD: zic.c,v 1.79 2021/10/22 14:26:04 christos Exp $");
15 #endif /* !defined lint */
16 
17 /* Use the system 'time' function, instead of any private replacement.
18    This avoids creating an unnecessary dependency on localtime.c.  */
19 #undef EPOCH_LOCAL
20 #undef EPOCH_OFFSET
21 #undef RESERVE_STD_EXT_IDS
22 #undef time_tz
23 
24 #include "private.h"
25 #include "tzfile.h"
26 
27 #include <fcntl.h>
28 #include <locale.h>
29 #include <signal.h>
30 #include <stdarg.h>
31 #include <stddef.h>
32 #include <stdio.h>
33 #include <unistd.h>
34 #include <util.h>
35 
36 typedef int_fast64_t	zic_t;
37 #define ZIC_MIN INT_FAST64_MIN
38 #define ZIC_MAX INT_FAST64_MAX
39 #define SCNdZIC SCNdFAST64
40 
41 #ifndef ZIC_MAX_ABBR_LEN_WO_WARN
42 #define ZIC_MAX_ABBR_LEN_WO_WARN	6
43 #endif /* !defined ZIC_MAX_ABBR_LEN_WO_WARN */
44 
45 #ifdef HAVE_DIRECT_H
46 # include <direct.h>
47 # include <io.h>
48 # undef mkdir
49 # define mkdir(name, mode) _mkdir(name)
50 #endif
51 
52 #if HAVE_SYS_STAT_H
53 #include <sys/stat.h>
54 #endif
55 #ifdef S_IRUSR
56 #define MKDIR_UMASK (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)
57 #else
58 #define MKDIR_UMASK 0755
59 #endif
60 
61 /* The maximum ptrdiff_t value, for pre-C99 platforms.  */
62 #ifndef PTRDIFF_MAX
63 static ptrdiff_t const PTRDIFF_MAX = MAXVAL(ptrdiff_t, TYPE_BIT(ptrdiff_t));
64 #endif
65 
66 /* The minimum alignment of a type, for pre-C11 platforms.  */
67 #if __STDC_VERSION__ < 201112
68 # define _Alignof(type) offsetof(struct { char a; type b; }, b)
69 #endif
70 
71 /* The type for line numbers.  Use PRIdMAX to format them; formerly
72    there was also "#define PRIdLINENO PRIdMAX" and formats used
73    PRIdLINENO, but xgettext cannot grok that.  */
74 typedef intmax_t lineno;
75 
76 struct rule {
77 	const char *	r_filename;
78 	lineno		r_linenum;
79 	const char *	r_name;
80 
81 	zic_t		r_loyear;	/* for example, 1986 */
82 	zic_t		r_hiyear;	/* for example, 1986 */
83 	bool		r_lowasnum;
84 	bool		r_hiwasnum;
85 
86 	int		r_month;	/* 0..11 */
87 
88 	int		r_dycode;	/* see below */
89 	int		r_dayofmonth;
90 	int		r_wday;
91 
92 	zic_t		r_tod;		/* time from midnight */
93 	bool		r_todisstd;	/* is r_tod standard time? */
94 	bool		r_todisut;	/* is r_tod UT? */
95 	bool		r_isdst;	/* is this daylight saving time? */
96 	zic_t		r_save;		/* offset from standard time */
97 	const char *	r_abbrvar;	/* variable part of abbreviation */
98 
99 	bool		r_todo;		/* a rule to do (used in outzone) */
100 	zic_t		r_temp;		/* used in outzone */
101 };
102 
103 /*
104 **	r_dycode		r_dayofmonth	r_wday
105 */
106 
107 #define DC_DOM		0	/* 1..31 */	/* unused */
108 #define DC_DOWGEQ	1	/* 1..31 */	/* 0..6 (Sun..Sat) */
109 #define DC_DOWLEQ	2	/* 1..31 */	/* 0..6 (Sun..Sat) */
110 
111 struct zone {
112 	const char *	z_filename;
113 	lineno		z_linenum;
114 
115 	const char *	z_name;
116 	zic_t		z_stdoff;
117 	char *		z_rule;
118 	const char *	z_format;
119 	char		z_format_specifier;
120 
121 	bool		z_isdst;
122 	zic_t		z_save;
123 
124 	struct rule *	z_rules;
125 	ptrdiff_t	z_nrules;
126 
127 	struct rule	z_untilrule;
128 	zic_t		z_untiltime;
129 };
130 
131 #if !HAVE_POSIX_DECLS
132 extern int	getopt(int argc, char * const argv[],
133 			const char * options);
134 extern int	link(const char * target, const char * linkname);
135 extern char *	optarg;
136 extern int	optind;
137 #endif
138 
139 #if ! HAVE_LINK
140 # define link(target, linkname) (errno = ENOTSUP, -1)
141 #endif
142 #if ! HAVE_SYMLINK
143 # define readlink(file, buf, size) (errno = ENOTSUP, -1)
144 # define symlink(target, linkname) (errno = ENOTSUP, -1)
145 # define S_ISLNK(m) 0
146 #endif
147 #ifndef AT_SYMLINK_FOLLOW
148 # define linkat(targetdir, target, linknamedir, linkname, flag) \
149     (itssymlink(target) ? (errno = ENOTSUP, -1) : link(target, linkname))
150 #endif
151 
152 static void	addtt(zic_t starttime, int type);
153 static int	addtype(zic_t, char const *, bool, bool, bool);
154 static void	leapadd(zic_t, int, int);
155 static void	adjleap(void);
156 static void	associate(void);
157 static void	dolink(const char *, const char *, bool);
158 static char **	getfields(char * buf);
159 static zic_t	gethms(const char * string, const char * errstring);
160 static zic_t	getsave(char *, bool *);
161 static void	inexpires(char **, int);
162 static void	infile(const char * filename);
163 static void	inleap(char ** fields, int nfields);
164 static void	inlink(char ** fields, int nfields);
165 static void	inrule(char ** fields, int nfields);
166 static bool	inzcont(char ** fields, int nfields);
167 static bool	inzone(char ** fields, int nfields);
168 static bool	inzsub(char **, int, bool);
169 static bool	itssymlink(char const *);
170 static bool	is_alpha(char a);
171 static char	lowerit(char);
172 static void	mkdirs(char const *, bool);
173 static void	newabbr(const char * abbr);
174 static zic_t	oadd(zic_t t1, zic_t t2);
175 static void	outzone(const struct zone * zp, ptrdiff_t ntzones);
176 static zic_t	rpytime(const struct rule * rp, zic_t wantedy);
177 static bool	rulesub(struct rule * rp,
178 			const char * loyearp, const char * hiyearp,
179 			const char * typep, const char * monthp,
180 			const char * dayp, const char * timep);
181 static zic_t	tadd(zic_t t1, zic_t t2);
182 
183 /* Bound on length of what %z can expand to.  */
184 enum { PERCENT_Z_LEN_BOUND = sizeof "+995959" - 1 };
185 
186 /* If true, work around a bug in Qt 5.6.1 and earlier, which mishandles
187    TZif files whose POSIX-TZ-style strings contain '<'; see
188    QTBUG-53071 <https://bugreports.qt.io/browse/QTBUG-53071>.  This
189    workaround will no longer be needed when Qt 5.6.1 and earlier are
190    obsolete, say in the year 2021.  */
191 #ifndef WORK_AROUND_QTBUG_53071
192 enum { WORK_AROUND_QTBUG_53071 = true };
193 #endif
194 
195 static int		charcnt;
196 static bool		errors;
197 static bool		warnings;
198 static const char *	filename;
199 static int		leapcnt;
200 static bool		leapseen;
201 static zic_t		leapminyear;
202 static zic_t		leapmaxyear;
203 static lineno		linenum;
204 static size_t		max_abbrvar_len = PERCENT_Z_LEN_BOUND;
205 static size_t		max_format_len;
206 static zic_t		max_year;
207 static zic_t		min_year;
208 static bool		noise;
209 static const char *	rfilename;
210 static lineno		rlinenum;
211 static const char *	progname;
212 static ptrdiff_t	timecnt;
213 static ptrdiff_t	timecnt_alloc;
214 static int		typecnt;
215 static int		unspecifiedtype;
216 
217 /*
218 ** Line codes.
219 */
220 
221 #define LC_RULE		0
222 #define LC_ZONE		1
223 #define LC_LINK		2
224 #define LC_LEAP		3
225 #define LC_EXPIRES	4
226 
227 /*
228 ** Which fields are which on a Zone line.
229 */
230 
231 #define ZF_NAME		1
232 #define ZF_STDOFF	2
233 #define ZF_RULE		3
234 #define ZF_FORMAT	4
235 #define ZF_TILYEAR	5
236 #define ZF_TILMONTH	6
237 #define ZF_TILDAY	7
238 #define ZF_TILTIME	8
239 #define ZONE_MINFIELDS	5
240 #define ZONE_MAXFIELDS	9
241 
242 /*
243 ** Which fields are which on a Zone continuation line.
244 */
245 
246 #define ZFC_STDOFF	0
247 #define ZFC_RULE	1
248 #define ZFC_FORMAT	2
249 #define ZFC_TILYEAR	3
250 #define ZFC_TILMONTH	4
251 #define ZFC_TILDAY	5
252 #define ZFC_TILTIME	6
253 #define ZONEC_MINFIELDS	3
254 #define ZONEC_MAXFIELDS	7
255 
256 /*
257 ** Which files are which on a Rule line.
258 */
259 
260 #define RF_NAME		1
261 #define RF_LOYEAR	2
262 #define RF_HIYEAR	3
263 #define RF_COMMAND	4
264 #define RF_MONTH	5
265 #define RF_DAY		6
266 #define RF_TOD		7
267 #define RF_SAVE		8
268 #define RF_ABBRVAR	9
269 #define RULE_FIELDS	10
270 
271 /*
272 ** Which fields are which on a Link line.
273 */
274 
275 #define LF_TARGET	1
276 #define LF_LINKNAME	2
277 #define LINK_FIELDS	3
278 
279 /*
280 ** Which fields are which on a Leap line.
281 */
282 
283 #define LP_YEAR		1
284 #define LP_MONTH	2
285 #define LP_DAY		3
286 #define LP_TIME		4
287 #define LP_CORR		5
288 #define LP_ROLL		6
289 #define LEAP_FIELDS	7
290 
291 /* Expires lines are like Leap lines, except without CORR and ROLL fields.  */
292 #define EXPIRES_FIELDS	5
293 
294 /*
295 ** Year synonyms.
296 */
297 
298 #define YR_MINIMUM	0
299 #define YR_MAXIMUM	1
300 #define YR_ONLY		2
301 
302 static struct rule *	rules;
303 static ptrdiff_t	nrules;	/* number of rules */
304 static ptrdiff_t	nrules_alloc;
305 
306 static struct zone *	zones;
307 static ptrdiff_t	nzones;	/* number of zones */
308 static ptrdiff_t	nzones_alloc;
309 
310 struct link {
311 	const char *	l_filename;
312 	lineno		l_linenum;
313 	const char *	l_target;
314 	const char *	l_linkname;
315 };
316 
317 static struct link *	links;
318 static ptrdiff_t	nlinks;
319 static ptrdiff_t	nlinks_alloc;
320 
321 struct lookup {
322 	const char *	l_word;
323 	const int	l_value;
324 };
325 
326 static struct lookup const *	byword(const char * string,
327 					const struct lookup * lp);
328 
329 static struct lookup const zi_line_codes[] = {
330 	{ "Rule",	LC_RULE },
331 	{ "Zone",	LC_ZONE },
332 	{ "Link",	LC_LINK },
333 	{ NULL,		0 }
334 };
335 static struct lookup const leap_line_codes[] = {
336 	{ "Leap",	LC_LEAP },
337 	{ "Expires",	LC_EXPIRES },
338 	{ NULL,		0}
339 };
340 
341 static struct lookup const	mon_names[] = {
342 	{ "January",	TM_JANUARY },
343 	{ "February",	TM_FEBRUARY },
344 	{ "March",	TM_MARCH },
345 	{ "April",	TM_APRIL },
346 	{ "May",	TM_MAY },
347 	{ "June",	TM_JUNE },
348 	{ "July",	TM_JULY },
349 	{ "August",	TM_AUGUST },
350 	{ "September",	TM_SEPTEMBER },
351 	{ "October",	TM_OCTOBER },
352 	{ "November",	TM_NOVEMBER },
353 	{ "December",	TM_DECEMBER },
354 	{ NULL,		0 }
355 };
356 
357 static struct lookup const	wday_names[] = {
358 	{ "Sunday",	TM_SUNDAY },
359 	{ "Monday",	TM_MONDAY },
360 	{ "Tuesday",	TM_TUESDAY },
361 	{ "Wednesday",	TM_WEDNESDAY },
362 	{ "Thursday",	TM_THURSDAY },
363 	{ "Friday",	TM_FRIDAY },
364 	{ "Saturday",	TM_SATURDAY },
365 	{ NULL,		0 }
366 };
367 
368 static struct lookup const	lasts[] = {
369 	{ "last-Sunday",	TM_SUNDAY },
370 	{ "last-Monday",	TM_MONDAY },
371 	{ "last-Tuesday",	TM_TUESDAY },
372 	{ "last-Wednesday",	TM_WEDNESDAY },
373 	{ "last-Thursday",	TM_THURSDAY },
374 	{ "last-Friday",	TM_FRIDAY },
375 	{ "last-Saturday",	TM_SATURDAY },
376 	{ NULL,			0 }
377 };
378 
379 static struct lookup const	begin_years[] = {
380 	{ "minimum",	YR_MINIMUM },
381 	{ "maximum",	YR_MAXIMUM },
382 	{ NULL,		0 }
383 };
384 
385 static struct lookup const	end_years[] = {
386 	{ "minimum",	YR_MINIMUM },
387 	{ "maximum",	YR_MAXIMUM },
388 	{ "only",	YR_ONLY },
389 	{ NULL,		0 }
390 };
391 
392 static struct lookup const	leap_types[] = {
393 	{ "Rolling",	true },
394 	{ "Stationary",	false },
395 	{ NULL,		0 }
396 };
397 
398 static const int	len_months[2][MONSPERYEAR] = {
399 	{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
400 	{ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
401 };
402 
403 static const int	len_years[2] = {
404 	DAYSPERNYEAR, DAYSPERLYEAR
405 };
406 
407 static struct attype {
408 	zic_t		at;
409 	bool		dontmerge;
410 	unsigned char	type;
411 } *			attypes;
412 static zic_t		utoffs[TZ_MAX_TYPES];
413 static char		isdsts[TZ_MAX_TYPES];
414 static unsigned char	desigidx[TZ_MAX_TYPES];
415 static bool		ttisstds[TZ_MAX_TYPES];
416 static bool		ttisuts[TZ_MAX_TYPES];
417 static char		chars[TZ_MAX_CHARS];
418 static zic_t		trans[TZ_MAX_LEAPS];
419 static zic_t		corr[TZ_MAX_LEAPS];
420 static char		roll[TZ_MAX_LEAPS];
421 
422 /*
423 ** Memory allocation.
424 */
425 
426 static _Noreturn void
427 memory_exhausted(const char *msg)
428 {
429 	fprintf(stderr, _("%s: Memory exhausted: %s\n"), progname, msg);
430 	exit(EXIT_FAILURE);
431 }
432 
433 static ATTRIBUTE_PURE size_t
434 size_product(size_t nitems, size_t itemsize)
435 {
436 	if (SIZE_MAX / itemsize < nitems)
437 		memory_exhausted(_("size overflow"));
438 	return nitems * itemsize;
439 }
440 
441 static ATTRIBUTE_PURE size_t
442 align_to(size_t size, size_t alignment)
443 {
444   size_t aligned_size = size + alignment - 1;
445   aligned_size -= aligned_size % alignment;
446   if (aligned_size < size)
447     memory_exhausted(_("alignment overflow"));
448   return aligned_size;
449 }
450 
451 #if !HAVE_STRDUP
452 static char *
453 strdup(char const *str)
454 {
455 	char *result = malloc(strlen(str) + 1);
456 	return result ? strcpy(result, str) : result;
457 }
458 #endif
459 
460 static void *
461 memcheck(void *ptr)
462 {
463 	if (ptr == NULL)
464 	  memory_exhausted(strerror(HAVE_MALLOC_ERRNO ? errno : ENOMEM));
465 	return ptr;
466 }
467 
468 static void * ATTRIBUTE_MALLOC
469 zic_malloc(size_t size)
470 {
471 	return memcheck(malloc(size));
472 }
473 
474 static void *
475 zic_realloc(void *ptr, size_t size)
476 {
477 	return memcheck(realloc(ptr, size));
478 }
479 
480 static char * ATTRIBUTE_MALLOC
481 ecpyalloc(char const *str)
482 {
483 	return memcheck(strdup(str));
484 }
485 
486 static void *
487 growalloc(void *ptr, size_t itemsize, ptrdiff_t nitems, ptrdiff_t *nitems_alloc)
488 {
489 	if (nitems < *nitems_alloc)
490 		return ptr;
491 	else {
492 		ptrdiff_t nitems_max = PTRDIFF_MAX - WORK_AROUND_QTBUG_53071;
493 		ptrdiff_t amax = (ptrdiff_t)((size_t)nitems_max < SIZE_MAX ?
494 		    (size_t)nitems_max : SIZE_MAX);
495 		if ((amax - 1) / 3 * 2 < *nitems_alloc)
496 			memory_exhausted(_("integer overflow"));
497 		*nitems_alloc += (*nitems_alloc >> 1) + 1;
498 		return zic_realloc(ptr, size_product(*nitems_alloc, itemsize));
499 	}
500 }
501 
502 /*
503 ** Error handling.
504 */
505 
506 static void
507 eats(char const *name, lineno num, char const *rname, lineno rnum)
508 {
509 	filename = name;
510 	linenum = num;
511 	rfilename = rname;
512 	rlinenum = rnum;
513 }
514 
515 static void
516 eat(char const *name, lineno num)
517 {
518 	eats(name, num, NULL, -1);
519 }
520 
521 static void ATTRIBUTE_FORMAT((printf, 1, 0))
522 verror(const char *const string, va_list args)
523 {
524 	/*
525 	** Match the format of "cc" to allow sh users to
526 	**	zic ... 2>&1 | error -t "*" -v
527 	** on BSD systems.
528 	*/
529 	if (filename)
530 	  fprintf(stderr, _("\"%s\", line %"PRIdMAX": "), filename, linenum);
531 	vfprintf(stderr, string, args);
532 	if (rfilename != NULL)
533 		fprintf(stderr, _(" (rule from \"%s\", line %"PRIdMAX")"),
534 			rfilename, rlinenum);
535 	fprintf(stderr, "\n");
536 }
537 
538 static void ATTRIBUTE_FORMAT((printf, 1, 2))
539 error(const char *const string, ...)
540 {
541 	va_list args;
542 	va_start(args, string);
543 	verror(string, args);
544 	va_end(args);
545 	errors = true;
546 }
547 
548 static void ATTRIBUTE_FORMAT((printf, 1, 2))
549 warning(const char *const string, ...)
550 {
551 	va_list args;
552 	fprintf(stderr, _("warning: "));
553 	va_start(args, string);
554 	verror(string, args);
555 	va_end(args);
556 	warnings = true;
557 }
558 
559 /* Close STREAM.  If it had an I/O error, report it against DIR/NAME,
560    remove TEMPNAME if nonnull, and then exit.  */
561 static void
562 close_file(FILE *stream, char const *dir, char const *name,
563 	   char const *tempname)
564 {
565   char const *e = (ferror(stream) ? _("I/O error")
566 		   : fclose(stream) != 0 ? strerror(errno) : NULL);
567   if (e) {
568     fprintf(stderr, "%s: %s%s%s%s%s\n", progname,
569 	    dir ? dir : "", dir ? "/" : "",
570 	    name ? name : "", name ? ": " : "",
571 	    e);
572     if (tempname)
573       remove(tempname);
574     exit(EXIT_FAILURE);
575   }
576 }
577 
578 static _Noreturn void
579 usage(FILE *stream, int status)
580 {
581   fprintf(stream,
582 	  _("%s: usage is %s [ --version ] [ --help ] [ -v ] \\\n"
583 	    "\t[ -b {slim|fat} ] [ -d directory ] [ -l localtime ]"
584 	    " [ -L leapseconds ] \\\n"
585 	    "\t[ -p posixrules ] [ -r '[@lo][/@hi]' ] [ -t localtime-link ] \\\n"
586 	    "\t[ filename ... ]\n\n"
587 	    "Report bugs to %s.\n"),
588 	  progname, progname, REPORT_BUGS_TO);
589   if (status == EXIT_SUCCESS)
590     close_file(stream, NULL, NULL, NULL);
591   exit(status);
592 }
593 
594 /* Change the working directory to DIR, possibly creating DIR and its
595    ancestors.  After this is done, all files are accessed with names
596    relative to DIR.  */
597 static void
598 change_directory(char const *dir)
599 {
600   if (chdir(dir) != 0) {
601     int chdir_errno = errno;
602     if (chdir_errno == ENOENT) {
603       mkdirs(dir, false);
604       chdir_errno = chdir(dir) == 0 ? 0 : errno;
605     }
606     if (chdir_errno != 0) {
607       fprintf(stderr, _("%s: Can't chdir to %s: %s\n"),
608 	      progname, dir, strerror(chdir_errno));
609       exit(EXIT_FAILURE);
610     }
611   }
612 }
613 
614 /* Simple signal handling: just set a flag that is checked
615    periodically outside critical sections.  To set up the handler,
616    prefer sigaction if available to close a signal race.  */
617 
618 static sig_atomic_t got_signal;
619 
620 static void
621 signal_handler(int sig)
622 {
623 #ifndef SA_SIGINFO
624   signal(sig, signal_handler);
625 #endif
626   got_signal = sig;
627 }
628 
629 /* Arrange for SIGINT etc. to be caught by the handler.  */
630 static void
631 catch_signals(void)
632 {
633   static int const signals[] = {
634 #ifdef SIGHUP
635     SIGHUP,
636 #endif
637     SIGINT,
638 #ifdef SIGPIPE
639     SIGPIPE,
640 #endif
641     SIGTERM
642   };
643   size_t i;
644   for (i = 0; i < sizeof signals / sizeof signals[0]; i++) {
645 #ifdef SA_SIGINFO
646     struct sigaction act0, act;
647     act.sa_handler = signal_handler;
648     sigemptyset(&act.sa_mask);
649     act.sa_flags = 0;
650     if (sigaction(signals[i], &act, &act0) == 0
651 	&& ! (act0.sa_flags & SA_SIGINFO) && act0.sa_handler == SIG_IGN) {
652       sigaction(signals[i], &act0, NULL);
653       got_signal = 0;
654     }
655 #else
656     if (signal(signals[i], signal_handler) == SIG_IGN) {
657       signal(signals[i], SIG_IGN);
658       got_signal = 0;
659     }
660 #endif
661   }
662 }
663 
664 /* If a signal has arrived, terminate zic with appropriate status.  */
665 static void
666 check_for_signal(void)
667 {
668   int sig = got_signal;
669   if (sig) {
670     signal(sig, SIG_DFL);
671     raise(sig);
672     abort(); /* A bug in 'raise'.  */
673   }
674 }
675 
676 #define TIME_T_BITS_IN_FILE 64
677 
678 /* The minimum and maximum values representable in a TZif file.  */
679 static zic_t const min_time = MINVAL(zic_t, TIME_T_BITS_IN_FILE);
680 static zic_t const max_time = MAXVAL(zic_t, TIME_T_BITS_IN_FILE);
681 
682 /* The minimum, and one less than the maximum, values specified by
683    the -r option.  These default to MIN_TIME and MAX_TIME.  */
684 static zic_t lo_time = MINVAL(zic_t, TIME_T_BITS_IN_FILE);
685 static zic_t hi_time = MAXVAL(zic_t, TIME_T_BITS_IN_FILE);
686 
687 /* The time specified by an Expires line, or negative if no such line.  */
688 static zic_t leapexpires = -1;
689 
690 /* Set the time range of the output to TIMERANGE.
691    Return true if successful.  */
692 static bool
693 timerange_option(char *timerange)
694 {
695   intmax_t lo = min_time, hi = max_time;
696   char *lo_end = timerange, *hi_end;
697   if (*timerange == '@') {
698     errno = 0;
699     lo = strtoimax(timerange + 1, &lo_end, 10);
700     if (lo_end == timerange + 1 || (lo == INTMAX_MAX && errno == ERANGE))
701       return false;
702   }
703   hi_end = lo_end;
704   if (lo_end[0] == '/' && lo_end[1] == '@') {
705     errno = 0;
706     hi = strtoimax(lo_end + 2, &hi_end, 10);
707     if (hi_end == lo_end + 2 || hi == INTMAX_MIN)
708       return false;
709     hi -= ! (hi == INTMAX_MAX && errno == ERANGE);
710   }
711   if (*hi_end || hi < lo || max_time < lo || hi < min_time)
712     return false;
713   lo_time = lo < min_time ? min_time : lo;
714   hi_time = max_time < hi ? max_time : hi;
715   return true;
716 }
717 
718 static const char *	psxrules;
719 static const char *	lcltime;
720 static const char *	directory;
721 static const char *	leapsec;
722 static const char *	tzdefault;
723 
724 /* -1 if the TZif output file should be slim, 0 if default, 1 if the
725    output should be fat for backward compatibility.  ZIC_BLOAT_DEFAULT
726    determines the default.  */
727 static int bloat;
728 
729 static bool
730 want_bloat(void)
731 {
732   return 0 <= bloat;
733 }
734 
735 #ifndef ZIC_BLOAT_DEFAULT
736 # define ZIC_BLOAT_DEFAULT "slim"
737 #endif
738 
739 int
740 main(int argc, char **argv)
741 {
742 	int	c, k;
743 	ptrdiff_t	i, j;
744 	bool timerange_given = false;
745 
746 #ifdef S_IWGRP
747 	umask(umask(S_IWGRP | S_IWOTH) | (S_IWGRP | S_IWOTH));
748 #endif
749 #if HAVE_GETTEXT
750 	setlocale(LC_MESSAGES, "");
751 #ifdef TZ_DOMAINDIR
752 	bindtextdomain(TZ_DOMAIN, TZ_DOMAINDIR);
753 #endif /* defined TEXTDOMAINDIR */
754 	textdomain(TZ_DOMAIN);
755 #endif /* HAVE_GETTEXT */
756 	progname = argv[0];
757 	if (TYPE_BIT(zic_t) < 64) {
758 		fprintf(stderr, "%s: %s\n", progname,
759 			_("wild compilation-time specification of zic_t"));
760 		return EXIT_FAILURE;
761 	}
762 	for (k = 1; k < argc; k++)
763 		if (strcmp(argv[k], "--version") == 0) {
764 			printf("zic %s%s\n", PKGVERSION, TZVERSION);
765 			close_file(stdout, NULL, NULL, NULL);
766 			return EXIT_SUCCESS;
767 		} else if (strcmp(argv[k], "--help") == 0) {
768 			usage(stdout, EXIT_SUCCESS);
769 		}
770 	while ((c = getopt(argc, argv, "b:d:l:L:p:r:st:vy:")) != EOF && c != -1)
771 		switch (c) {
772 			default:
773 				usage(stderr, EXIT_FAILURE);
774 			case 'b':
775 				if (strcmp(optarg, "slim") == 0) {
776 				  if (0 < bloat)
777 				    error(_("incompatible -b options"));
778 				  bloat = -1;
779 				} else if (strcmp(optarg, "fat") == 0) {
780 				  if (bloat < 0)
781 				    error(_("incompatible -b options"));
782 				  bloat = 1;
783 				} else
784 				  error(_("invalid option: -b '%s'"), optarg);
785 				break;
786 			case 'd':
787 				if (directory == NULL)
788 					directory = optarg;
789 				else {
790 					fprintf(stderr,
791 _("%s: More than one -d option specified\n"),
792 						progname);
793 					return EXIT_FAILURE;
794 				}
795 				break;
796 			case 'l':
797 				if (lcltime == NULL)
798 					lcltime = optarg;
799 				else {
800 					fprintf(stderr,
801 _("%s: More than one -l option specified\n"),
802 						progname);
803 					return EXIT_FAILURE;
804 				}
805 				break;
806 			case 'p':
807 				if (psxrules == NULL)
808 					psxrules = optarg;
809 				else {
810 					fprintf(stderr,
811 _("%s: More than one -p option specified\n"),
812 						progname);
813 					return EXIT_FAILURE;
814 				}
815 				break;
816 			case 't':
817 				if (tzdefault != NULL) {
818 				  fprintf(stderr,
819 					  _("%s: More than one -t option"
820 					    " specified\n"),
821 					  progname);
822 				  return EXIT_FAILURE;
823 				}
824 				tzdefault = optarg;
825 				break;
826 			case 'y':
827 				warning(_("-y ignored"));
828 				break;
829 			case 'L':
830 				if (leapsec == NULL)
831 					leapsec = optarg;
832 				else {
833 					fprintf(stderr,
834 _("%s: More than one -L option specified\n"),
835 						progname);
836 					return EXIT_FAILURE;
837 				}
838 				break;
839 			case 'v':
840 				noise = true;
841 				break;
842 			case 'r':
843 				if (timerange_given) {
844 				  fprintf(stderr,
845 _("%s: More than one -r option specified\n"),
846 					  progname);
847 				  return EXIT_FAILURE;
848 				}
849 				if (! timerange_option(optarg)) {
850 				  fprintf(stderr,
851 _("%s: invalid time range: %s\n"),
852 					  progname, optarg);
853 				  return EXIT_FAILURE;
854 				}
855 				timerange_given = true;
856 				break;
857 			case 's':
858 				warning(_("-s ignored"));
859 				break;
860 		}
861 	if (optind == argc - 1 && strcmp(argv[optind], "=") == 0)
862 		usage(stderr, EXIT_FAILURE);	/* usage message by request */
863 	if (bloat == 0) {
864 	  static char const bloat_default[] = ZIC_BLOAT_DEFAULT;
865 	  if (strcmp(bloat_default, "slim") == 0)
866 	    bloat = -1;
867 	  else if (strcmp(bloat_default, "fat") == 0)
868 	    bloat = 1;
869 	  else
870 	    abort(); /* Configuration error.  */
871 	}
872 	if (directory == NULL)
873 		directory = TZDIR;
874 	if (tzdefault == NULL)
875 		tzdefault = TZDEFAULT;
876 
877 	if (optind < argc && leapsec != NULL) {
878 		infile(leapsec);
879 		adjleap();
880 	}
881 
882 	for (k = optind; k < argc; k++)
883 		infile(argv[k]);
884 	if (errors)
885 		return EXIT_FAILURE;
886 	associate();
887 	change_directory(directory);
888 	catch_signals();
889 	for (i = 0; i < nzones; i = j) {
890 		/*
891 		** Find the next non-continuation zone entry.
892 		*/
893 		for (j = i + 1; j < nzones && zones[j].z_name == NULL; ++j)
894 			continue;
895 		outzone(&zones[i], j - i);
896 	}
897 	/*
898 	** Make links.
899 	*/
900 	for (i = 0; i < nlinks; ++i) {
901 		eat(links[i].l_filename, links[i].l_linenum);
902 		dolink(links[i].l_target, links[i].l_linkname, false);
903 		if (noise)
904 			for (j = 0; j < nlinks; ++j)
905 				if (strcmp(links[i].l_linkname,
906 					links[j].l_target) == 0)
907 						warning(_("link to link"));
908 	}
909 	if (lcltime != NULL) {
910 		eat(_("command line"), 1);
911 		dolink(lcltime, tzdefault, true);
912 	}
913 	if (psxrules != NULL) {
914 		eat(_("command line"), 1);
915 		dolink(psxrules, TZDEFRULES, true);
916 	}
917 	if (warnings && (ferror(stderr) || fclose(stderr) != 0))
918 	  return EXIT_FAILURE;
919 	return errors ? EXIT_FAILURE : EXIT_SUCCESS;
920 }
921 
922 static bool
923 componentcheck(char const *name, char const *component,
924 	       char const *component_end)
925 {
926 	enum { component_len_max = 14 };
927 	ptrdiff_t component_len = component_end - component;
928 	if (component_len == 0) {
929 	  if (!*name)
930 	    error(_("empty file name"));
931 	  else
932 	    error(_(component == name
933 		     ? "file name '%s' begins with '/'"
934 		     : *component_end
935 		     ? "file name '%s' contains '//'"
936 		     : "file name '%s' ends with '/'"),
937 		   name);
938 	  return false;
939 	}
940 	if (0 < component_len && component_len <= 2
941 	    && component[0] == '.' && component_end[-1] == '.') {
942 	  int len = component_len;
943 	  error(_("file name '%s' contains '%.*s' component"),
944 		name, len, component);
945 	  return false;
946 	}
947 	if (noise) {
948 	  if (0 < component_len && component[0] == '-')
949 	    warning(_("file name '%s' component contains leading '-'"),
950 		    name);
951 	  if (component_len_max < component_len)
952 	    warning(_("file name '%s' contains overlength component"
953 		      " '%.*s...'"),
954 		    name, component_len_max, component);
955 	}
956 	return true;
957 }
958 
959 static bool
960 namecheck(const char *name)
961 {
962 	char const *cp;
963 
964 	/* Benign characters in a portable file name.  */
965 	static char const benign[] =
966 	  "-/_"
967 	  "abcdefghijklmnopqrstuvwxyz"
968 	  "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
969 
970 	/* Non-control chars in the POSIX portable character set,
971 	   excluding the benign characters.  */
972 	static char const printable_and_not_benign[] =
973 	  " !\"#$%&'()*+,.0123456789:;<=>?@[\\]^`{|}~";
974 
975 	char const *component = name;
976 	for (cp = name; *cp; cp++) {
977 		unsigned char c = *cp;
978 		if (noise && !strchr(benign, c)) {
979 			warning((strchr(printable_and_not_benign, c)
980 				 ? _("file name '%s' contains byte '%c'")
981 				 : _("file name '%s' contains byte '\\%o'")),
982 				name, c);
983 		}
984 		if (c == '/') {
985 			if (!componentcheck(name, component, cp))
986 			  return false;
987 			component = cp + 1;
988 		}
989 	}
990 	return componentcheck(name, component, cp);
991 }
992 
993 /* Generate a randomish name in the same directory as *NAME.  If
994    *NAMEALLOC, put the name into *NAMEALLOC which is assumed to be
995    that returned by a previous call and is thus already almost set up
996    and equal to *NAME; otherwise, allocate a new name and put its
997    address into both *NAMEALLOC and *NAME.  */
998 static void
999 random_dirent(char const **name, char **namealloc)
1000 {
1001   char const *src = *name;
1002   char *dst = *namealloc;
1003   static char const prefix[] = ".zic";
1004   static char const alphabet[] = ("abcdefghijklmnopqrstuvwxyz"
1005 				  "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
1006 				  "0123456789");
1007   enum { prefixlen = sizeof prefix - 1, alphabetlen = sizeof alphabet - 1 };
1008   int suffixlen = 6;
1009   char const *lastslash = strrchr(src, '/');
1010   ptrdiff_t dirlen = lastslash ? lastslash + 1 - src : 0;
1011   static unsigned short initialized;
1012   int i;
1013 
1014   if (!dst) {
1015     dst = emalloc(dirlen + prefixlen + suffixlen + 1);
1016     memcpy(dst, src, dirlen);
1017     memcpy(dst + dirlen, prefix, prefixlen);
1018     dst[dirlen + prefixlen + suffixlen] = '\0';
1019     *name = *namealloc = dst;
1020   }
1021 
1022   /* This randomization is not the best, but is portable to C89.  */
1023   if (!initialized++) {
1024     unsigned now = time(NULL);
1025     srand(rand() ^ now);
1026   }
1027   for (i = 0; i < suffixlen; i++)
1028     dst[dirlen + prefixlen + i] = alphabet[rand() % alphabetlen];
1029 }
1030 
1031 /* Prepare to write to the file *OUTNAME, using *TEMPNAME to store the
1032    name of the temporary file that will eventually be renamed to
1033    *OUTNAME.  Assign the temporary file's name to both *OUTNAME and
1034    *TEMPNAME.  If *TEMPNAME is null, allocate the name of any such
1035    temporary file; otherwise, reuse *TEMPNAME's storage, which is
1036    already set up and only needs its trailing suffix updated.  */
1037 static FILE *
1038 open_outfile(char const **outname, char **tempname)
1039 {
1040 #if __STDC_VERSION__ < 201112
1041   static char const fopen_mode[] = "wb";
1042 #else
1043   static char const fopen_mode[] = "wbx";
1044 #endif
1045 
1046   FILE *fp;
1047   bool dirs_made = false;
1048   if (!*tempname)
1049     random_dirent(outname, tempname);
1050 
1051   while (! (fp = fopen(*outname, fopen_mode))) {
1052     int fopen_errno = errno;
1053     if (fopen_errno == ENOENT && !dirs_made) {
1054       mkdirs(*outname, true);
1055       dirs_made = true;
1056     } else if (fopen_errno == EEXIST)
1057       random_dirent(outname, tempname);
1058     else {
1059       fprintf(stderr, _("%s: Can't create %s/%s: %s\n"),
1060 	      progname, directory, *outname, strerror(fopen_errno));
1061       exit(EXIT_FAILURE);
1062     }
1063   }
1064 
1065   return fp;
1066 }
1067 
1068 /* If TEMPNAME, the result is in the temporary file TEMPNAME even
1069    though the user wanted it in NAME, so rename TEMPNAME to NAME.
1070    Report an error and exit if there is trouble.  Also, free TEMPNAME.  */
1071 static void
1072 rename_dest(char *tempname, char const *name)
1073 {
1074   if (tempname) {
1075     if (rename(tempname, name) != 0) {
1076       int rename_errno = errno;
1077       remove(tempname);
1078       fprintf(stderr, _("%s: rename to %s/%s: %s\n"),
1079 	      progname, directory, name, strerror(rename_errno));
1080       exit(EXIT_FAILURE);
1081     }
1082     free(tempname);
1083   }
1084 }
1085 
1086 /* Create symlink contents suitable for symlinking FROM to TO, as a
1087    freshly allocated string.  FROM should be a relative file name, and
1088    is relative to the global variable DIRECTORY.  TO can be either
1089    relative or absolute.  */
1090 static char *
1091 relname(char const *target, char const *linkname)
1092 {
1093   size_t i, taillen, dotdotetcsize;
1094   size_t dir_len = 0, dotdots = 0, linksize = SIZE_MAX;
1095   char const *f = target;
1096   char *result = NULL;
1097   if (*linkname == '/') {
1098     /* Make F absolute too.  */
1099     size_t len = strlen(directory);
1100     bool needslash = len && directory[len - 1] != '/';
1101     linksize = len + needslash + strlen(target) + 1;
1102     f = result = emalloc(linksize);
1103     strcpy(result, directory);
1104     result[len] = '/';
1105     strcpy(result + len + needslash, target);
1106   }
1107   for (i = 0; f[i] && f[i] == linkname[i]; i++)
1108     if (f[i] == '/')
1109       dir_len = i + 1;
1110   for (; linkname[i]; i++)
1111     dotdots += linkname[i] == '/' && linkname[i - 1] != '/';
1112   taillen = strlen(f + dir_len);
1113   dotdotetcsize = 3 * dotdots + taillen + 1;
1114   if (dotdotetcsize <= linksize) {
1115     if (!result)
1116       result = emalloc(dotdotetcsize);
1117     for (i = 0; i < dotdots; i++)
1118       memcpy(result + 3 * i, "../", 3);
1119     memmove(result + 3 * dotdots, f + dir_len, taillen + 1);
1120   }
1121   return result;
1122 }
1123 
1124 static void
1125 dolink(char const *target, char const *linkname, bool staysymlink)
1126 {
1127 	bool linkdirs_made = false;
1128 	int link_errno;
1129 	char *tempname = NULL;
1130 	char const *outname = linkname;
1131 
1132 	check_for_signal();
1133 
1134 	if (strcmp(target, "-") == 0) {
1135 	  if (remove(linkname) == 0 || errno == ENOENT || errno == ENOTDIR)
1136 	    return;
1137 	  else {
1138 	    char const *e = strerror(errno);
1139 	    fprintf(stderr, _("%s: Can't remove %s/%s: %s\n"),
1140 		    progname, directory, linkname, e);
1141 	    exit(EXIT_FAILURE);
1142 	  }
1143 	}
1144 
1145 	while (true) {
1146 	  if (linkat(AT_FDCWD, target, AT_FDCWD, outname, AT_SYMLINK_FOLLOW)
1147 	      == 0) {
1148 	    link_errno = 0;
1149 	    break;
1150 	  }
1151 	  link_errno = errno;
1152 	  if (link_errno == EXDEV || link_errno == ENOTSUP)
1153 	    break;
1154 
1155 	  if (link_errno == EEXIST) {
1156 	    staysymlink &= !tempname;
1157 	    random_dirent(&outname, &tempname);
1158 	    if (staysymlink && itssymlink(linkname))
1159 	      break;
1160 	  } else if (link_errno == ENOENT && !linkdirs_made) {
1161 	    mkdirs(linkname, true);
1162 	    linkdirs_made = true;
1163 	  } else {
1164 	    fprintf(stderr, _("%s: Can't link %s/%s to %s/%s: %s\n"),
1165 		    progname, directory, target, directory, outname,
1166 		    strerror(link_errno));
1167 	    exit(EXIT_FAILURE);
1168 	  }
1169 	}
1170 	if (link_errno != 0) {
1171 	  bool absolute = *target == '/';
1172 	  char *linkalloc = absolute ? NULL : relname(target, linkname);
1173 	  char const *contents = absolute ? target : linkalloc;
1174 	  int symlink_errno;
1175 
1176 	  while (true) {
1177 	    if (symlink(contents, outname) == 0) {
1178 	      symlink_errno = 0;
1179 	      break;
1180 	    }
1181 	    symlink_errno = errno;
1182 	    if (symlink_errno == EEXIST)
1183 	      random_dirent(&outname, &tempname);
1184 	    else if (symlink_errno == ENOENT && !linkdirs_made) {
1185 	      mkdirs(linkname, true);
1186 	      linkdirs_made = true;
1187 	    } else
1188 	      break;
1189 	  }
1190 	  free(linkalloc);
1191 	  if (symlink_errno == 0) {
1192 	    if (link_errno != ENOTSUP && link_errno != EEXIST)
1193 	      warning(_("symbolic link used because hard link failed: %s"),
1194 		      strerror(link_errno));
1195 	  } else {
1196 	    FILE *fp, *tp;
1197 	    int c;
1198 	    fp = fopen(target, "rb");
1199 	    if (!fp) {
1200 	      char const *e = strerror(errno);
1201 	      fprintf(stderr, _("%s: Can't read %s/%s: %s\n"),
1202 		      progname, directory, target, e);
1203 	      exit(EXIT_FAILURE);
1204 	    }
1205 	    tp = open_outfile(&outname, &tempname);
1206 	    while ((c = getc(fp)) != EOF)
1207 	      putc(c, tp);
1208 	    close_file(tp, directory, linkname, tempname);
1209 	    close_file(fp, directory, target, NULL);
1210 	    if (link_errno != ENOTSUP)
1211 	      warning(_("copy used because hard link failed: %s"),
1212 		      strerror(link_errno));
1213 	    else if (symlink_errno != ENOTSUP)
1214 	      warning(_("copy used because symbolic link failed: %s"),
1215 		      strerror(symlink_errno));
1216 	  }
1217 	}
1218 	rename_dest(tempname, linkname);
1219 }
1220 
1221 /* Return true if NAME is a symbolic link.  */
1222 static bool
1223 itssymlink(char const *name)
1224 {
1225   char c;
1226   return 0 <= readlink(name, &c, 1);
1227 }
1228 
1229 /*
1230 ** Associate sets of rules with zones.
1231 */
1232 
1233 /*
1234 ** Sort by rule name.
1235 */
1236 
1237 static int
1238 rcomp(const void *cp1, const void *cp2)
1239 {
1240   struct rule const *r1 = cp1, *r2 = cp2;
1241   return strcmp(r1->r_name, r2->r_name);
1242 }
1243 
1244 static void
1245 associate(void)
1246 {
1247 	struct zone *	zp;
1248 	struct rule *	rp;
1249 	ptrdiff_t	i, j, base, out;
1250 
1251 	if (nrules != 0) {
1252 		qsort(rules, (size_t)nrules, sizeof *rules, rcomp);
1253 		for (i = 0; i < nrules - 1; ++i) {
1254 			if (strcmp(rules[i].r_name,
1255 				rules[i + 1].r_name) != 0)
1256 					continue;
1257 			if (strcmp(rules[i].r_filename,
1258 				rules[i + 1].r_filename) == 0)
1259 					continue;
1260 			eat(rules[i].r_filename, rules[i].r_linenum);
1261 			warning(_("same rule name in multiple files"));
1262 			eat(rules[i + 1].r_filename, rules[i + 1].r_linenum);
1263 			warning(_("same rule name in multiple files"));
1264 			for (j = i + 2; j < nrules; ++j) {
1265 				if (strcmp(rules[i].r_name,
1266 					rules[j].r_name) != 0)
1267 						break;
1268 				if (strcmp(rules[i].r_filename,
1269 					rules[j].r_filename) == 0)
1270 						continue;
1271 				if (strcmp(rules[i + 1].r_filename,
1272 					rules[j].r_filename) == 0)
1273 						continue;
1274 				break;
1275 			}
1276 			i = j - 1;
1277 		}
1278 	}
1279 	for (i = 0; i < nzones; ++i) {
1280 		zp = &zones[i];
1281 		zp->z_rules = NULL;
1282 		zp->z_nrules = 0;
1283 	}
1284 	for (base = 0; base < nrules; base = out) {
1285 		rp = &rules[base];
1286 		for (out = base + 1; out < nrules; ++out)
1287 			if (strcmp(rp->r_name, rules[out].r_name) != 0)
1288 				break;
1289 		for (i = 0; i < nzones; ++i) {
1290 			zp = &zones[i];
1291 			if (strcmp(zp->z_rule, rp->r_name) != 0)
1292 				continue;
1293 			zp->z_rules = rp;
1294 			zp->z_nrules = out - base;
1295 		}
1296 	}
1297 	for (i = 0; i < nzones; ++i) {
1298 		zp = &zones[i];
1299 		if (zp->z_nrules == 0) {
1300 			/*
1301 			** Maybe we have a local standard time offset.
1302 			*/
1303 			eat(zp->z_filename, zp->z_linenum);
1304 			zp->z_save = getsave(zp->z_rule, &zp->z_isdst);
1305 			/*
1306 			** Note, though, that if there's no rule,
1307 			** a '%s' in the format is a bad thing.
1308 			*/
1309 			if (zp->z_format_specifier == 's')
1310 				error("%s", _("%s in ruleless zone"));
1311 		}
1312 	}
1313 	if (errors)
1314 		exit(EXIT_FAILURE);
1315 }
1316 
1317 static void
1318 infile(const char *name)
1319 {
1320 	FILE *			fp;
1321 	char **		fields;
1322 	char *			cp;
1323 	const struct lookup *	lp;
1324 	int			nfields;
1325 	bool			wantcont;
1326 	lineno			num;
1327 	char				buf[BUFSIZ];
1328 
1329 	if (strcmp(name, "-") == 0) {
1330 		name = _("standard input");
1331 		fp = stdin;
1332 	} else if ((fp = fopen(name, "r")) == NULL) {
1333 		const char *e = strerror(errno);
1334 
1335 		fprintf(stderr, _("%s: Can't open %s: %s\n"),
1336 			progname, name, e);
1337 		exit(EXIT_FAILURE);
1338 	}
1339 	wantcont = false;
1340 	for (num = 1; ; ++num) {
1341 		eat(name, num);
1342 		if (fgets(buf, (int) sizeof buf, fp) != buf)
1343 			break;
1344 		cp = strchr(buf, '\n');
1345 		if (cp == NULL) {
1346 			error(_("line too long"));
1347 			exit(EXIT_FAILURE);
1348 		}
1349 		*cp = '\0';
1350 		fields = getfields(buf);
1351 		nfields = 0;
1352 		while (fields[nfields] != NULL) {
1353 			static char	nada;
1354 
1355 			if (strcmp(fields[nfields], "-") == 0)
1356 				fields[nfields] = &nada;
1357 			++nfields;
1358 		}
1359 		if (nfields == 0) {
1360 			/* nothing to do */
1361 		} else if (wantcont) {
1362 			wantcont = inzcont(fields, nfields);
1363 		} else {
1364 			struct lookup const *line_codes
1365 			  = name == leapsec ? leap_line_codes : zi_line_codes;
1366 			lp = byword(fields[0], line_codes);
1367 			if (lp == NULL)
1368 				error(_("input line of unknown type"));
1369 			else switch (lp->l_value) {
1370 				case LC_RULE:
1371 					inrule(fields, nfields);
1372 					wantcont = false;
1373 					break;
1374 				case LC_ZONE:
1375 					wantcont = inzone(fields, nfields);
1376 					break;
1377 				case LC_LINK:
1378 					inlink(fields, nfields);
1379 					wantcont = false;
1380 					break;
1381 				case LC_LEAP:
1382 					inleap(fields, nfields);
1383 					wantcont = false;
1384 					break;
1385 				case LC_EXPIRES:
1386 					inexpires(fields, nfields);
1387 					wantcont = false;
1388 					break;
1389 				default: UNREACHABLE();
1390 			}
1391 		}
1392 		free(fields);
1393 	}
1394 	close_file(fp, NULL, filename, NULL);
1395 	if (wantcont)
1396 		error(_("expected continuation line not found"));
1397 }
1398 
1399 /*
1400 ** Convert a string of one of the forms
1401 **	h	-h	hh:mm	-hh:mm	hh:mm:ss	-hh:mm:ss
1402 ** into a number of seconds.
1403 ** A null string maps to zero.
1404 ** Call error with errstring and return zero on errors.
1405 */
1406 
1407 static zic_t
1408 gethms(char const *string, char const *errstring)
1409 {
1410 	zic_t	hh;
1411 	int sign, mm = 0, ss = 0;
1412 	char hhx, mmx, ssx, xr = '0', xs;
1413 	int tenths = 0;
1414 	bool ok = true;
1415 
1416 	if (string == NULL || *string == '\0')
1417 		return 0;
1418 	if (*string == '-') {
1419 		sign = -1;
1420 		++string;
1421 	} else	sign = 1;
1422 	switch (sscanf(string,
1423 		       "%"SCNdZIC"%c%d%c%d%c%1d%*[0]%c%*[0123456789]%c",
1424 		       &hh, &hhx, &mm, &mmx, &ss, &ssx, &tenths, &xr, &xs)) {
1425 	  default: ok = false; break;
1426 	  case 8:
1427 	    ok = '0' <= xr && xr <= '9';
1428 	    /* fallthrough */
1429 	  case 7:
1430 	    ok &= ssx == '.';
1431 	    if (ok && noise)
1432 	      warning(_("fractional seconds rejected by"
1433 			" pre-2018 versions of zic"));
1434 	    /* fallthrough */
1435 	  case 5: ok &= mmx == ':'; /* fallthrough */
1436 	  case 3: ok &= hhx == ':'; /* fallthrough */
1437 	  case 1: break;
1438 	}
1439 	if (!ok) {
1440 			error("%s", errstring);
1441 			return 0;
1442 	}
1443 	if (hh < 0 ||
1444 		mm < 0 || mm >= MINSPERHOUR ||
1445 		ss < 0 || ss > SECSPERMIN) {
1446 			error("%s", errstring);
1447 			return 0;
1448 	}
1449 	if (ZIC_MAX / SECSPERHOUR < hh) {
1450 		error(_("time overflow"));
1451 		return 0;
1452 	}
1453 	ss += 5 + ((ss ^ 1) & (xr == '0')) <= tenths; /* Round to even.  */
1454 	if (noise && (hh > HOURSPERDAY ||
1455 		(hh == HOURSPERDAY && (mm != 0 || ss != 0))))
1456 warning(_("values over 24 hours not handled by pre-2007 versions of zic"));
1457 	return oadd(sign * hh * SECSPERHOUR,
1458 		    sign * (mm * SECSPERMIN + ss));
1459 }
1460 
1461 static zic_t
1462 getsave(char *field, bool *isdst)
1463 {
1464   int dst = -1;
1465   zic_t save;
1466   size_t fieldlen = strlen(field);
1467   if (fieldlen != 0) {
1468     char *ep = field + fieldlen - 1;
1469     switch (*ep) {
1470       case 'd': dst = 1; *ep = '\0'; break;
1471       case 's': dst = 0; *ep = '\0'; break;
1472     }
1473   }
1474   save = gethms(field, _("invalid saved time"));
1475   *isdst = dst < 0 ? save != 0 : dst;
1476   return save;
1477 }
1478 
1479 static void
1480 inrule(char **fields, int nfields)
1481 {
1482 	struct rule r;
1483 
1484 	if (nfields != RULE_FIELDS) {
1485 		error(_("wrong number of fields on Rule line"));
1486 		return;
1487 	}
1488 	switch (*fields[RF_NAME]) {
1489 	  case '\0':
1490 	  case ' ': case '\f': case '\n': case '\r': case '\t': case '\v':
1491 	  case '+': case '-':
1492 	  case '0': case '1': case '2': case '3': case '4':
1493 	  case '5': case '6': case '7': case '8': case '9':
1494 		error(_("Invalid rule name \"%s\""), fields[RF_NAME]);
1495 		return;
1496 	}
1497 	r.r_filename = filename;
1498 	r.r_linenum = linenum;
1499 	r.r_save = getsave(fields[RF_SAVE], &r.r_isdst);
1500 	if (!rulesub(&r, fields[RF_LOYEAR], fields[RF_HIYEAR],
1501 		     fields[RF_COMMAND], fields[RF_MONTH], fields[RF_DAY],
1502 		     fields[RF_TOD]))
1503 	  return;
1504 	r.r_name = ecpyalloc(fields[RF_NAME]);
1505 	r.r_abbrvar = ecpyalloc(fields[RF_ABBRVAR]);
1506 	if (max_abbrvar_len < strlen(r.r_abbrvar))
1507 		max_abbrvar_len = strlen(r.r_abbrvar);
1508 	rules = growalloc(rules, sizeof *rules, nrules, &nrules_alloc);
1509 	rules[nrules++] = r;
1510 }
1511 
1512 static bool
1513 inzone(char **fields, int nfields)
1514 {
1515 	ptrdiff_t	i;
1516 
1517 	if (nfields < ZONE_MINFIELDS || nfields > ZONE_MAXFIELDS) {
1518 		error(_("wrong number of fields on Zone line"));
1519 		return false;
1520 	}
1521 	if (lcltime != NULL && strcmp(fields[ZF_NAME], tzdefault) == 0) {
1522 		error(
1523 _("\"Zone %s\" line and -l option are mutually exclusive"),
1524 			tzdefault);
1525 		return false;
1526 	}
1527 	if (strcmp(fields[ZF_NAME], TZDEFRULES) == 0 && psxrules != NULL) {
1528 		error(
1529 _("\"Zone %s\" line and -p option are mutually exclusive"),
1530 			TZDEFRULES);
1531 		return false;
1532 	}
1533 	for (i = 0; i < nzones; ++i)
1534 		if (zones[i].z_name != NULL &&
1535 		    strcmp(zones[i].z_name, fields[ZF_NAME]) == 0) {
1536 			error(_("duplicate zone name %s"
1537 				" (file \"%s\", line %"PRIdMAX")"),
1538 				fields[ZF_NAME],
1539 				zones[i].z_filename,
1540 				zones[i].z_linenum);
1541 			return false;
1542 		}
1543 	return inzsub(fields, nfields, false);
1544 }
1545 
1546 static bool
1547 inzcont(char **fields, int nfields)
1548 {
1549 	if (nfields < ZONEC_MINFIELDS || nfields > ZONEC_MAXFIELDS) {
1550 		error(_("wrong number of fields on Zone continuation line"));
1551 		return false;
1552 	}
1553 	return inzsub(fields, nfields, true);
1554 }
1555 
1556 static bool
1557 inzsub(char **fields, int nfields, bool iscont)
1558 {
1559 	char *		cp;
1560 	char *		cp1;
1561 	struct zone	z;
1562 	size_t format_len;
1563 	int		i_stdoff, i_rule, i_format;
1564 	int		i_untilyear, i_untilmonth;
1565 	int		i_untilday, i_untiltime;
1566 	bool		hasuntil;
1567 
1568 	if (iscont) {
1569 		i_stdoff = ZFC_STDOFF;
1570 		i_rule = ZFC_RULE;
1571 		i_format = ZFC_FORMAT;
1572 		i_untilyear = ZFC_TILYEAR;
1573 		i_untilmonth = ZFC_TILMONTH;
1574 		i_untilday = ZFC_TILDAY;
1575 		i_untiltime = ZFC_TILTIME;
1576 	} else if (!namecheck(fields[ZF_NAME]))
1577 		return false;
1578 	else {
1579 		i_stdoff = ZF_STDOFF;
1580 		i_rule = ZF_RULE;
1581 		i_format = ZF_FORMAT;
1582 		i_untilyear = ZF_TILYEAR;
1583 		i_untilmonth = ZF_TILMONTH;
1584 		i_untilday = ZF_TILDAY;
1585 		i_untiltime = ZF_TILTIME;
1586 	}
1587 	z.z_filename = filename;
1588 	z.z_linenum = linenum;
1589 	z.z_stdoff = gethms(fields[i_stdoff], _("invalid UT offset"));
1590 	if ((cp = strchr(fields[i_format], '%')) != 0) {
1591 		if ((*++cp != 's' && *cp != 'z') || strchr(cp, '%')
1592 		    || strchr(fields[i_format], '/')) {
1593 			error(_("invalid abbreviation format"));
1594 			return false;
1595 		}
1596 	}
1597 	z.z_format_specifier = cp ? *cp : '\0';
1598 	format_len = strlen(fields[i_format]);
1599 	if (max_format_len < format_len)
1600 	  max_format_len = format_len;
1601 	hasuntil = nfields > i_untilyear;
1602 	if (hasuntil) {
1603 		z.z_untilrule.r_filename = filename;
1604 		z.z_untilrule.r_linenum = linenum;
1605 		if (!rulesub(
1606 			&z.z_untilrule,
1607 			fields[i_untilyear],
1608 			"only",
1609 			"",
1610 			(nfields > i_untilmonth) ?
1611 			fields[i_untilmonth] : "Jan",
1612 			(nfields > i_untilday) ? fields[i_untilday] : "1",
1613 			(nfields > i_untiltime) ? fields[i_untiltime] : "0"))
1614 		  return false;
1615 		z.z_untiltime = rpytime(&z.z_untilrule,
1616 			z.z_untilrule.r_loyear);
1617 		if (iscont && nzones > 0 &&
1618 			z.z_untiltime > min_time &&
1619 			z.z_untiltime < max_time &&
1620 			zones[nzones - 1].z_untiltime > min_time &&
1621 			zones[nzones - 1].z_untiltime < max_time &&
1622 			zones[nzones - 1].z_untiltime >= z.z_untiltime) {
1623 				error(_(
1624 "Zone continuation line end time is not after end time of previous line"
1625 					));
1626 				return false;
1627 		}
1628 	}
1629 	z.z_name = iscont ? NULL : ecpyalloc(fields[ZF_NAME]);
1630 	z.z_rule = ecpyalloc(fields[i_rule]);
1631 	z.z_format = cp1 = ecpyalloc(fields[i_format]);
1632 	if (z.z_format_specifier == 'z') {
1633 	  cp1[cp - fields[i_format]] = 's';
1634 	  if (noise)
1635 	    warning(_("format '%s' not handled by pre-2015 versions of zic"),
1636 		    fields[i_format]);
1637 	}
1638 	zones = growalloc(zones, sizeof *zones, nzones, &nzones_alloc);
1639 	zones[nzones++] = z;
1640 	/*
1641 	** If there was an UNTIL field on this line,
1642 	** there's more information about the zone on the next line.
1643 	*/
1644 	return hasuntil;
1645 }
1646 
1647 static zic_t
1648 getleapdatetime(char **fields, int nfields, bool expire_line)
1649 {
1650 	const char *		cp;
1651 	const struct lookup *	lp;
1652 	zic_t			i, j;
1653 	zic_t			year;
1654 	int			month, day;
1655 	zic_t			dayoff, tod;
1656 	zic_t			t;
1657 	char			xs;
1658 
1659 	dayoff = 0;
1660 	cp = fields[LP_YEAR];
1661 	if (sscanf(cp, "%"SCNdZIC"%c", &year, &xs) != 1) {
1662 		/*
1663 		** Leapin' Lizards!
1664 		*/
1665 		error(_("invalid leaping year"));
1666 		return -1;
1667 	}
1668 	if (!expire_line) {
1669 	    if (!leapseen || leapmaxyear < year)
1670 		leapmaxyear = year;
1671 	    if (!leapseen || leapminyear > year)
1672 		leapminyear = year;
1673 	    leapseen = true;
1674 	}
1675 	j = EPOCH_YEAR;
1676 	while (j != year) {
1677 		if (year > j) {
1678 			i = len_years[isleap(j)];
1679 			++j;
1680 		} else {
1681 			--j;
1682 			i = -len_years[isleap(j)];
1683 		}
1684 		dayoff = oadd(dayoff, i);
1685 	}
1686 	if ((lp = byword(fields[LP_MONTH], mon_names)) == NULL) {
1687 		error(_("invalid month name"));
1688 		return -1;
1689 	}
1690 	month = lp->l_value;
1691 	j = TM_JANUARY;
1692 	while (j != month) {
1693 		i = len_months[isleap(year)][j];
1694 		dayoff = oadd(dayoff, i);
1695 		++j;
1696 	}
1697 	cp = fields[LP_DAY];
1698 	if (sscanf(cp, "%d%c", &day, &xs) != 1 ||
1699 		day <= 0 || day > len_months[isleap(year)][month]) {
1700 			error(_("invalid day of month"));
1701 			return -1;
1702 	}
1703 	dayoff = oadd(dayoff, day - 1);
1704 	if (dayoff < min_time / SECSPERDAY) {
1705 		error(_("time too small"));
1706 		return -1;
1707 	}
1708 	if (dayoff > max_time / SECSPERDAY) {
1709 		error(_("time too large"));
1710 		return -1;
1711 	}
1712 	t = dayoff * SECSPERDAY;
1713 	tod = gethms(fields[LP_TIME], _("invalid time of day"));
1714 	t = tadd(t, tod);
1715 	if (t < 0)
1716 	  error(_("leap second precedes Epoch"));
1717 	return t;
1718 }
1719 
1720 static void
1721 inleap(char **fields, int nfields)
1722 {
1723   if (nfields != LEAP_FIELDS)
1724     error(_("wrong number of fields on Leap line"));
1725   else {
1726     zic_t t = getleapdatetime(fields, nfields, false);
1727     if (0 <= t) {
1728       struct lookup const *lp = byword(fields[LP_ROLL], leap_types);
1729       if (!lp)
1730 	error(_("invalid Rolling/Stationary field on Leap line"));
1731       else {
1732 	int correction = 0;
1733 	if (!fields[LP_CORR][0]) /* infile() turns "-" into "".  */
1734 	  correction = -1;
1735 	else if (strcmp(fields[LP_CORR], "+") == 0)
1736 	  correction = 1;
1737 	else
1738 	  error(_("invalid CORRECTION field on Leap line"));
1739 	if (correction)
1740 	  leapadd(t, correction, lp->l_value);
1741       }
1742     }
1743   }
1744 }
1745 
1746 static void
1747 inexpires(char **fields, int nfields)
1748 {
1749   if (nfields != EXPIRES_FIELDS)
1750     error(_("wrong number of fields on Expires line"));
1751   else if (0 <= leapexpires)
1752     error(_("multiple Expires lines"));
1753   else
1754     leapexpires = getleapdatetime(fields, nfields, true);
1755 }
1756 
1757 static void
1758 inlink(char **fields, int nfields)
1759 {
1760 	struct link	l;
1761 
1762 	if (nfields != LINK_FIELDS) {
1763 		error(_("wrong number of fields on Link line"));
1764 		return;
1765 	}
1766 	if (*fields[LF_TARGET] == '\0') {
1767 		error(_("blank TARGET field on Link line"));
1768 		return;
1769 	}
1770 	if (! namecheck(fields[LF_LINKNAME]))
1771 	  return;
1772 	l.l_filename = filename;
1773 	l.l_linenum = linenum;
1774 	l.l_target = ecpyalloc(fields[LF_TARGET]);
1775 	l.l_linkname = ecpyalloc(fields[LF_LINKNAME]);
1776 	links = growalloc(links, sizeof *links, nlinks, &nlinks_alloc);
1777 	links[nlinks++] = l;
1778 }
1779 
1780 static bool
1781 rulesub(struct rule *rp, const char *loyearp, const char *hiyearp,
1782     const char *typep, const char *monthp, const char *dayp,
1783     const char *timep)
1784 {
1785 	const struct lookup *	lp;
1786 	const char *		cp;
1787 	char *			dp;
1788 	char *			ep;
1789 	char			xs;
1790 
1791 	if ((lp = byword(monthp, mon_names)) == NULL) {
1792 		error(_("invalid month name"));
1793 		return false;
1794 	}
1795 	rp->r_month = lp->l_value;
1796 	rp->r_todisstd = false;
1797 	rp->r_todisut = false;
1798 	dp = ecpyalloc(timep);
1799 	if (*dp != '\0') {
1800 		ep = dp + strlen(dp) - 1;
1801 		switch (lowerit(*ep)) {
1802 			case 's':	/* Standard */
1803 				rp->r_todisstd = true;
1804 				rp->r_todisut = false;
1805 				*ep = '\0';
1806 				break;
1807 			case 'w':	/* Wall */
1808 				rp->r_todisstd = false;
1809 				rp->r_todisut = false;
1810 				*ep = '\0';
1811 				break;
1812 			case 'g':	/* Greenwich */
1813 			case 'u':	/* Universal */
1814 			case 'z':	/* Zulu */
1815 				rp->r_todisstd = true;
1816 				rp->r_todisut = true;
1817 				*ep = '\0';
1818 				break;
1819 		}
1820 	}
1821 	rp->r_tod = gethms(dp, _("invalid time of day"));
1822 	free(dp);
1823 	/*
1824 	** Year work.
1825 	*/
1826 	cp = loyearp;
1827 	lp = byword(cp, begin_years);
1828 	rp->r_lowasnum = lp == NULL;
1829 	if (!rp->r_lowasnum) switch (lp->l_value) {
1830 		case YR_MINIMUM:
1831 			rp->r_loyear = ZIC_MIN;
1832 			break;
1833 		case YR_MAXIMUM:
1834 			rp->r_loyear = ZIC_MAX;
1835 			break;
1836 		default: UNREACHABLE();
1837 	} else if (sscanf(cp, "%"SCNdZIC"%c", &rp->r_loyear, &xs) != 1) {
1838 		error(_("invalid starting year"));
1839 		return false;
1840 	}
1841 	cp = hiyearp;
1842 	lp = byword(cp, end_years);
1843 	rp->r_hiwasnum = lp == NULL;
1844 	if (!rp->r_hiwasnum) switch (lp->l_value) {
1845 		case YR_MINIMUM:
1846 			rp->r_hiyear = ZIC_MIN;
1847 			break;
1848 		case YR_MAXIMUM:
1849 			rp->r_hiyear = ZIC_MAX;
1850 			break;
1851 		case YR_ONLY:
1852 			rp->r_hiyear = rp->r_loyear;
1853 			break;
1854 		default: UNREACHABLE();
1855 	} else if (sscanf(cp, "%"SCNdZIC"%c", &rp->r_hiyear, &xs) != 1) {
1856 		error(_("invalid ending year"));
1857 		return false;
1858 	}
1859 	if (rp->r_loyear > rp->r_hiyear) {
1860 		error(_("starting year greater than ending year"));
1861 		return false;
1862 	}
1863 	if (*typep != '\0') {
1864 		error(_("year type \"%s\" is unsupported; use \"-\" instead"),
1865 			typep);
1866 		return false;
1867 	}
1868 	/*
1869 	** Day work.
1870 	** Accept things such as:
1871 	**	1
1872 	**	lastSunday
1873 	**	last-Sunday (undocumented; warn about this)
1874 	**	Sun<=20
1875 	**	Sun>=7
1876 	*/
1877 	dp = ecpyalloc(dayp);
1878 	if ((lp = byword(dp, lasts)) != NULL) {
1879 		rp->r_dycode = DC_DOWLEQ;
1880 		rp->r_wday = lp->l_value;
1881 		rp->r_dayofmonth = len_months[1][rp->r_month];
1882 	} else {
1883 		if ((ep = strchr(dp, '<')) != 0)
1884 			rp->r_dycode = DC_DOWLEQ;
1885 		else if ((ep = strchr(dp, '>')) != 0)
1886 			rp->r_dycode = DC_DOWGEQ;
1887 		else {
1888 			ep = dp;
1889 			rp->r_dycode = DC_DOM;
1890 		}
1891 		if (rp->r_dycode != DC_DOM) {
1892 			*ep++ = 0;
1893 			if (*ep++ != '=') {
1894 				error(_("invalid day of month"));
1895 				free(dp);
1896 				return false;
1897 			}
1898 			if ((lp = byword(dp, wday_names)) == NULL) {
1899 				error(_("invalid weekday name"));
1900 				free(dp);
1901 				return false;
1902 			}
1903 			rp->r_wday = lp->l_value;
1904 		}
1905 		if (sscanf(ep, "%d%c", &rp->r_dayofmonth, &xs) != 1 ||
1906 			rp->r_dayofmonth <= 0 ||
1907 			(rp->r_dayofmonth > len_months[1][rp->r_month])) {
1908 				error(_("invalid day of month"));
1909 				free(dp);
1910 				return false;
1911 		}
1912 	}
1913 	free(dp);
1914 	return true;
1915 }
1916 
1917 static void
1918 convert(uint_fast32_t val, char *buf)
1919 {
1920 	int	i;
1921 	int	shift;
1922 	unsigned char *const b = (unsigned char *) buf;
1923 
1924 	for (i = 0, shift = 24; i < 4; ++i, shift -= 8)
1925 		b[i] = (val >> shift) & 0xff;
1926 }
1927 
1928 static void
1929 convert64(uint_fast64_t val, char *buf)
1930 {
1931 	int	i;
1932 	int	shift;
1933 	unsigned char *const b = (unsigned char *) buf;
1934 
1935 	for (i = 0, shift = 56; i < 8; ++i, shift -= 8)
1936 		b[i] = (val >> shift) & 0xff;
1937 }
1938 
1939 static void
1940 puttzcode(const int_fast32_t val, FILE *const fp)
1941 {
1942 	char	buf[4];
1943 
1944 	convert(val, buf);
1945 	fwrite(buf, sizeof buf, (size_t) 1, fp);
1946 }
1947 
1948 static void
1949 puttzcodepass(zic_t val, FILE *fp, int pass)
1950 {
1951   if (pass == 1)
1952     puttzcode(val, fp);
1953   else {
1954 	char	buf[8];
1955 
1956 	convert64(val, buf);
1957 	fwrite(buf, sizeof buf, (size_t) 1, fp);
1958     }
1959 }
1960 
1961 static int
1962 atcomp(const void *avp, const void *bvp)
1963 {
1964   struct attype const *ap = avp, *bp = bvp;
1965   zic_t a = ap->at, b = bp->at;
1966   return a < b ? -1 : a > b;
1967 }
1968 
1969 struct timerange {
1970   int defaulttype;
1971   ptrdiff_t base, count;
1972   int leapbase, leapcount;
1973   bool pretrans, leapexpiry;
1974 };
1975 
1976 static struct timerange
1977 limitrange(struct timerange r, bool locut, zic_t lo, zic_t hi,
1978 	   zic_t const *ats, unsigned char const *types)
1979 {
1980   /* Omit ordinary transitions < LO.  */
1981   while (0 < r.count && ats[r.base] < lo) {
1982     r.defaulttype = types[r.base];
1983     r.count--;
1984     r.base++;
1985   }
1986 
1987   /* "-00" before any -r low cutoff.  */
1988   if (min_time < lo_time)
1989     r.defaulttype = unspecifiedtype;
1990 
1991   /* Omit as many initial leap seconds as possible, such that the
1992      first leap second in the truncated list is <= LO, and is a
1993      positive leap second if and only if it has a positive correction.
1994      This supports common TZif readers that assume that the first leap
1995      second is positive if and only if its correction is positive.  */
1996   while (1 < r.leapcount && trans[r.leapbase + 1] <= lo) {
1997     r.leapcount--;
1998     r.leapbase++;
1999   }
2000   while (0 < r.leapbase
2001 	 && ((corr[r.leapbase - 1] < corr[r.leapbase])
2002 	     != (0 < corr[r.leapbase]))) {
2003     r.leapcount++;
2004     r.leapbase--;
2005   }
2006 
2007 
2008   /* Omit ordinary and leap second transitions greater than HI + 1.  */
2009   if (hi < max_time) {
2010     while (0 < r.count && hi + 1 < ats[r.base + r.count - 1])
2011       r.count--;
2012     while (0 < r.leapcount && hi + 1 < trans[r.leapbase + r.leapcount - 1])
2013       r.leapcount--;
2014   }
2015 
2016   /* Determine whether to keep the last too-low transition if no
2017      transition is exactly at LO.  The kept transition will be output
2018      as a LO "transition"; see "Output a LO_TIME transition" below.
2019      This is needed when the output is truncated at the start, and is
2020      also useful when catering to buggy 32-bit clients that do not use
2021      time type 0 for timestamps before the first transition.  */
2022   r.pretrans = locut && r.base && ! (r.count && ats[r.base] == lo);
2023 
2024   /* Determine whether to append an expiration to the leap second table.  */
2025   r.leapexpiry = 0 <= leapexpires && leapexpires - 1 <= hi;
2026 
2027   return r;
2028 }
2029 
2030 static void
2031 writezone(const char *const name, const char *const string, char version,
2032 	int defaulttype)
2033 {
2034 	FILE *			fp;
2035 	ptrdiff_t		i, j;
2036 	int			pass;
2037 	zic_t one = 1;
2038 	zic_t y2038_boundary = one << 31;
2039 	ptrdiff_t nats = timecnt + WORK_AROUND_QTBUG_53071;
2040 	char *tempname = NULL;
2041 	char const *outname = name;
2042 
2043 	/* Allocate the ATS and TYPES arrays via a single malloc,
2044 	   as this is a bit faster.  */
2045 	zic_t *ats = zic_malloc(align_to(size_product(nats, sizeof *ats + 1),
2046 				_Alignof(zic_t)));
2047 	void *typesptr = ats + nats;
2048 	unsigned char *types = typesptr;
2049 	struct timerange rangeall, range32, range64;
2050 
2051 	/*
2052 	** Sort.
2053 	*/
2054 	if (timecnt > 1)
2055 		qsort(attypes, (size_t) timecnt, sizeof *attypes, atcomp);
2056 	/*
2057 	** Optimize.
2058 	*/
2059 	{
2060 		ptrdiff_t fromi, toi;
2061 
2062 		toi = 0;
2063 		fromi = 0;
2064 		for ( ; fromi < timecnt; ++fromi) {
2065 			if (toi != 0
2066 			    && ((attypes[fromi].at
2067 				 + utoffs[attypes[toi - 1].type])
2068 				<= (attypes[toi - 1].at
2069 				    + utoffs[toi == 1 ? 0
2070 					     : attypes[toi - 2].type]))) {
2071 					attypes[toi - 1].type =
2072 						attypes[fromi].type;
2073 					continue;
2074 			}
2075 			if (toi == 0
2076 			    || attypes[fromi].dontmerge
2077 			    || (utoffs[attypes[toi - 1].type]
2078 				!= utoffs[attypes[fromi].type])
2079 			    || (isdsts[attypes[toi - 1].type]
2080 				!= isdsts[attypes[fromi].type])
2081 			    || (desigidx[attypes[toi - 1].type]
2082 				!= desigidx[attypes[fromi].type]))
2083 					attypes[toi++] = attypes[fromi];
2084 		}
2085 		timecnt = toi;
2086 	}
2087 
2088 	if (noise && timecnt > 1200) {
2089 	  if (timecnt > TZ_MAX_TIMES)
2090 		warning(_("reference clients mishandle"
2091 			  " more than %d transition times"),
2092 			TZ_MAX_TIMES);
2093 	  else
2094 		warning(_("pre-2014 clients may mishandle"
2095 			  " more than 1200 transition times"));
2096 	}
2097 	/*
2098 	** Transfer.
2099 	*/
2100 	for (i = 0; i < timecnt; ++i) {
2101 		ats[i] = attypes[i].at;
2102 		types[i] = attypes[i].type;
2103 	}
2104 
2105 	/*
2106 	** Correct for leap seconds.
2107 	*/
2108 	for (i = 0; i < timecnt; ++i) {
2109 		j = leapcnt;
2110 		while (--j >= 0)
2111 			if (ats[i] > trans[j] - corr[j]) {
2112 				ats[i] = tadd(ats[i], corr[j]);
2113 				break;
2114 			}
2115 	}
2116 
2117 	/* Work around QTBUG-53071 for timestamps less than y2038_boundary - 1,
2118 	   by inserting a no-op transition at time y2038_boundary - 1.
2119 	   This works only for timestamps before the boundary, which
2120 	   should be good enough in practice as QTBUG-53071 should be
2121 	   long-dead by 2038.  Do this after correcting for leap
2122 	   seconds, as the idea is to insert a transition just before
2123 	   32-bit time_t rolls around, and this occurs at a slightly
2124 	   different moment if transitions are leap-second corrected.  */
2125 	if (WORK_AROUND_QTBUG_53071 && timecnt != 0 && want_bloat()
2126 	    && ats[timecnt - 1] < y2038_boundary - 1 && strchr(string, '<')) {
2127 	  ats[timecnt] = y2038_boundary - 1;
2128 	  types[timecnt] = types[timecnt - 1];
2129 	  timecnt++;
2130 	}
2131 
2132 	rangeall.defaulttype = defaulttype;
2133 	rangeall.base = rangeall.leapbase = 0;
2134 	rangeall.count = timecnt;
2135 	rangeall.leapcount = leapcnt;
2136 	rangeall.pretrans = rangeall.leapexpiry = false;
2137 	range64 = limitrange(rangeall, min_time < lo_time,
2138 			     lo_time, hi_time, ats, types);
2139 	range32 = limitrange(range64, true,
2140 			     INT32_MIN, INT32_MAX, ats, types);
2141 
2142 	/* TZif version 4 is needed if a no-op transition is appended to
2143 	   indicate the expiration of the leap second table, or if the first
2144 	   leap second transition is not to a +1 or -1 correction.  */
2145 	for (pass = 1; pass <= 2; pass++) {
2146 	  struct timerange const *r = pass == 1 ? &range32 : &range64;
2147 	  if (pass == 1 && !want_bloat())
2148 	    continue;
2149 	  if (r->leapexpiry) {
2150 	    if (noise)
2151 	      warning(_("%s: pre-2021b clients may mishandle"
2152 			" leap second expiry"),
2153 		      name);
2154 	    version = '4';
2155 	  }
2156 	  if (0 < r->leapcount
2157 	      && corr[r->leapbase] != 1 && corr[r->leapbase] != -1) {
2158 	    if (noise)
2159 	      warning(_("%s: pre-2021b clients may mishandle"
2160 			" leap second table truncation"),
2161 		      name);
2162 	    version = '4';
2163 	  }
2164 	  if (version == '4')
2165 	    break;
2166  	}
2167 
2168 	fp = open_outfile(&outname, &tempname);
2169 
2170 	for (pass = 1; pass <= 2; ++pass) {
2171 		ptrdiff_t	thistimei, thistimecnt, thistimelim;
2172 		int	thisleapi, thisleapcnt, thisleaplim;
2173 		struct tzhead tzh;
2174 		int thisdefaulttype;
2175 		bool hicut, pretrans, thisleapexpiry;
2176 		zic_t lo;
2177 		int old0;
2178 		char		omittype[TZ_MAX_TYPES];
2179 		int		typemap[TZ_MAX_TYPES];
2180 		int		thistypecnt, stdcnt, utcnt;
2181 		char		thischars[TZ_MAX_CHARS];
2182 		int		thischarcnt;
2183 		bool		toomanytimes;
2184 		int		indmap[TZ_MAX_CHARS];
2185 
2186 		if (pass == 1) {
2187 			/* Arguably the default time type in the 32-bit data
2188 			   should be range32.defaulttype, which is suited for
2189 			   timestamps just before INT32_MIN.  However, zic
2190 			   traditionally used the time type of the indefinite
2191 			   past instead.  Internet RFC 8532 says readers should
2192 			   ignore 32-bit data, so this discrepancy matters only
2193 			   to obsolete readers where the traditional type might
2194 			   be more appropriate even if it's "wrong".  So, use
2195 			   the historical zic value, unless -r specifies a low
2196 			   cutoff that excludes some 32-bit timestamps.  */
2197 			thisdefaulttype = (lo_time <= INT32_MIN
2198 					   ? range64.defaulttype
2199 					   : range32.defaulttype);
2200 
2201 			thistimei = range32.base;
2202 			thistimecnt = range32.count;
2203 			toomanytimes = thistimecnt >> 31 >> 1 != 0;
2204 			thisleapi = range32.leapbase;
2205 			thisleapcnt = range32.leapcount;
2206 			pretrans = range32.pretrans;
2207 			thisleapexpiry = range32.leapexpiry;
2208 			hicut = hi_time < INT32_MAX;
2209 		} else {
2210 			thisdefaulttype = range64.defaulttype;
2211 			thistimei = range64.base;
2212 			thistimecnt = range64.count;
2213 			toomanytimes = thistimecnt >> 31 >> 31 >> 2 != 0;
2214 			thisleapi = range64.leapbase;
2215 			thisleapcnt = range64.leapcount;
2216 			pretrans = range64.pretrans;
2217 			thisleapexpiry = range64.leapexpiry;
2218 			hicut = hi_time < max_time;
2219 		}
2220 		if (toomanytimes)
2221 		  error(_("too many transition times"));
2222 
2223 		thistimelim = thistimei + thistimecnt;
2224 		memset(omittype, true, typecnt);
2225 		omittype[thisdefaulttype] = false;
2226 		for (i = thistimei - pretrans; i < thistimelim; i++)
2227 		  omittype[types[i]] = false;
2228 		if (hicut)
2229 		  omittype[unspecifiedtype] = false;
2230 
2231 		/* Reorder types to make THISDEFAULTTYPE type 0.
2232 		   Use TYPEMAP to swap OLD0 and THISDEFAULTTYPE so that
2233 		   THISDEFAULTTYPE appears as type 0 in the output instead
2234 		   of OLD0.  TYPEMAP also omits unused types.  */
2235 		old0 = strlen(omittype);
2236 
2237 #ifndef LEAVE_SOME_PRE_2011_SYSTEMS_IN_THE_LURCH
2238 		/*
2239 		** For some pre-2011 systems: if the last-to-be-written
2240 		** standard (or daylight) type has an offset different from the
2241 		** most recently used offset,
2242 		** append an (unused) copy of the most recently used type
2243 		** (to help get global "altzone" and "timezone" variables
2244 		** set correctly).
2245 		*/
2246 		if (want_bloat()) {
2247 			int	mrudst, mrustd, hidst, histd, type;
2248 
2249 			hidst = histd = mrudst = mrustd = -1;
2250 			for (i = thistimei - pretrans; i < thistimelim; ++i)
2251 				if (isdsts[types[i]])
2252 					mrudst = types[i];
2253 				else	mrustd = types[i];
2254 			for (i = old0; i < typecnt; i++) {
2255 			  int h = (i == old0 ? thisdefaulttype
2256 				   : i == thisdefaulttype ? old0 : i);
2257 			  if (!omittype[h]) {
2258 			    if (isdsts[h])
2259 			      hidst = i;
2260 			    else
2261 			      histd = i;
2262 			  }
2263 			}
2264 			if (hidst >= 0 && mrudst >= 0 && hidst != mrudst &&
2265 				utoffs[hidst] != utoffs[mrudst]) {
2266 					isdsts[mrudst] = -1;
2267 					type = addtype(utoffs[mrudst],
2268 						&chars[desigidx[mrudst]],
2269 						true,
2270 						ttisstds[mrudst],
2271 						ttisuts[mrudst]);
2272 					isdsts[mrudst] = 1;
2273 					omittype[type] = false;
2274 			}
2275 			if (histd >= 0 && mrustd >= 0 && histd != mrustd &&
2276 				utoffs[histd] != utoffs[mrustd]) {
2277 					isdsts[mrustd] = -1;
2278 					type = addtype(utoffs[mrustd],
2279 						&chars[desigidx[mrustd]],
2280 						false,
2281 						ttisstds[mrustd],
2282 						ttisuts[mrustd]);
2283 					isdsts[mrustd] = 0;
2284 					omittype[type] = false;
2285 			}
2286 		}
2287 #endif /* !defined LEAVE_SOME_PRE_2011_SYSTEMS_IN_THE_LURCH */
2288  		thistypecnt = 0;
2289 		for (i = old0; i < typecnt; i++)
2290 		  if (!omittype[i])
2291 		    typemap[i == old0 ? thisdefaulttype
2292 			    : i == thisdefaulttype ? old0 : i]
2293 		      = thistypecnt++;
2294 
2295 		for (i = 0; i < (int)(sizeof indmap / sizeof indmap[0]); ++i)
2296 			indmap[i] = -1;
2297 		thischarcnt = stdcnt = utcnt = 0;
2298 		for (i = old0; i < typecnt; i++) {
2299 			char *	thisabbr;
2300 
2301 			if (omittype[i])
2302 				continue;
2303 			if (ttisstds[i])
2304 			  stdcnt = thistypecnt;
2305 			if (ttisuts[i])
2306 			  utcnt = thistypecnt;
2307 			if (indmap[desigidx[i]] >= 0)
2308 				continue;
2309 			thisabbr = &chars[desigidx[i]];
2310 			for (j = 0; j < thischarcnt; ++j)
2311 				if (strcmp(&thischars[j], thisabbr) == 0)
2312 					break;
2313 			if (j == thischarcnt) {
2314 				strcpy(&thischars[thischarcnt], thisabbr);
2315 				thischarcnt += strlen(thisabbr) + 1;
2316 			}
2317 			indmap[desigidx[i]] = j;
2318 		}
2319 		if (pass == 1 && !want_bloat()) {
2320 		  pretrans = hicut = thisleapexpiry = false;
2321 		  thistimecnt = thisleapcnt = 0;
2322 		  thistypecnt = thischarcnt = 1;
2323 		}
2324 #define DO(field)	fwrite(tzh.field, sizeof tzh.field, (size_t) 1, fp)
2325 		memcpy(tzh.tzh_magic, TZ_MAGIC, sizeof tzh.tzh_magic);
2326 		tzh.tzh_version[0] = version;
2327 		convert(utcnt, tzh.tzh_ttisutcnt);
2328 		convert(stdcnt, tzh.tzh_ttisstdcnt);
2329 		convert(thisleapcnt + thisleapexpiry, tzh.tzh_leapcnt);
2330 		convert(pretrans + thistimecnt + hicut, tzh.tzh_timecnt);
2331 		convert(thistypecnt, tzh.tzh_typecnt);
2332 		convert(thischarcnt, tzh.tzh_charcnt);
2333 		DO(tzh_magic);
2334 		DO(tzh_version);
2335 		DO(tzh_reserved);
2336 		DO(tzh_ttisutcnt);
2337 		DO(tzh_ttisstdcnt);
2338 		DO(tzh_leapcnt);
2339 		DO(tzh_timecnt);
2340 		DO(tzh_typecnt);
2341 		DO(tzh_charcnt);
2342 #undef DO
2343 		if (pass == 1 && !want_bloat()) {
2344 		  /* Output a minimal data block with just one time type.  */
2345 		  puttzcode(0, fp);	/* utoff */
2346 		  putc(0, fp);		/* dst */
2347 		  putc(0, fp);		/* index of abbreviation */
2348 		  putc(0, fp);		/* empty-string abbreviation */
2349 		  continue;
2350 		}
2351 
2352 		/* Output a LO_TIME transition if needed; see limitrange.
2353 		   But do not go below the minimum representable value
2354 		   for this pass.  */
2355 		lo = pass == 1 && lo_time < INT32_MIN ? INT32_MIN : lo_time;
2356 
2357 		if (pretrans)
2358 		  puttzcodepass(lo, fp, pass);
2359 		for (i = thistimei; i < thistimelim; ++i) {
2360 		  puttzcodepass(ats[i], fp, pass);
2361 		}
2362 		if (hicut)
2363 		  puttzcodepass(hi_time + 1, fp, pass);
2364 		for (i = thistimei - pretrans; i < thistimelim; ++i)
2365 		  putc(typemap[types[i]], fp);
2366 		if (hicut)
2367 		  putc(typemap[unspecifiedtype], fp);
2368 
2369 		for (i = old0; i < typecnt; i++) {
2370 		  int h = (i == old0 ? thisdefaulttype
2371 			   : i == thisdefaulttype ? old0 : i);
2372 		  if (!omittype[h]) {
2373 		    puttzcode(utoffs[h], fp);
2374 		    putc(isdsts[h], fp);
2375 		    putc(indmap[desigidx[h]], fp);
2376 		  }
2377 		}
2378 		if (thischarcnt != 0)
2379 			fwrite(thischars, sizeof thischars[0],
2380 				(size_t) thischarcnt, fp);
2381 		thisleaplim = thisleapi + thisleapcnt;
2382 		for (i = thisleapi; i < thisleaplim; ++i) {
2383 			zic_t	todo;
2384 
2385 			if (roll[i]) {
2386 				if (timecnt == 0 || trans[i] < ats[0]) {
2387 					j = 0;
2388 					while (isdsts[j])
2389 						if (++j >= typecnt) {
2390 							j = 0;
2391 							break;
2392 						}
2393 				} else {
2394 					j = 1;
2395 					while (j < timecnt &&
2396 						trans[i] >= ats[j])
2397 							++j;
2398 					j = types[j - 1];
2399 				}
2400 				todo = tadd(trans[i], -utoffs[j]);
2401 			} else	todo = trans[i];
2402 			puttzcodepass(todo, fp, pass);
2403 			puttzcode(corr[i], fp);
2404 		}
2405 		if (thisleapexpiry) {
2406 		  /* Append a no-op leap correction indicating when the leap
2407 		     second table expires.  Although this does not conform to
2408 		     Internet RFC 8536, most clients seem to accept this and
2409 		     the plan is to amend the RFC to allow this in version 4
2410 		     TZif files.  */
2411 		  puttzcodepass(leapexpires, fp, pass);
2412 		  puttzcode(thisleaplim ? corr[thisleaplim - 1] : 0, fp);
2413 		}
2414 		if (stdcnt != 0)
2415 		  for (i = old0; i < typecnt; i++)
2416 			if (!omittype[i])
2417 				putc(ttisstds[i], fp);
2418 		if (utcnt != 0)
2419 		  for (i = old0; i < typecnt; i++)
2420 			if (!omittype[i])
2421 				putc(ttisuts[i], fp);
2422 	}
2423 	fprintf(fp, "\n%s\n", string);
2424 	close_file(fp, directory, name, tempname);
2425 	rename_dest(tempname, name);
2426 	free(ats);
2427 }
2428 
2429 static char const *
2430 abbroffset(char *buf, zic_t offset)
2431 {
2432 	char sign = '+';
2433 	int seconds, minutes;
2434 
2435 	if (offset < 0) {
2436 		offset = -offset;
2437 		sign = '-';
2438 	}
2439 
2440 	seconds = offset % SECSPERMIN;
2441 	offset /= SECSPERMIN;
2442 	minutes = offset % MINSPERHOUR;
2443 	offset /= MINSPERHOUR;
2444 	if (100 <= offset) {
2445 		error(_("%%z UT offset magnitude exceeds 99:59:59"));
2446 		return "%z";
2447 	} else {
2448 		char *p = buf;
2449 		*p++ = sign;
2450 		*p++ = '0' + offset / 10;
2451 		*p++ = '0' + offset % 10;
2452 		if (minutes | seconds) {
2453 			*p++ = '0' + minutes / 10;
2454 			*p++ = '0' + minutes % 10;
2455 			if (seconds) {
2456 				*p++ = '0' + seconds / 10;
2457 				*p++ = '0' + seconds % 10;
2458 			}
2459 		}
2460 		*p = '\0';
2461 		return buf;
2462 	}
2463 }
2464 
2465 static size_t
2466 doabbr(char *abbr, size_t abbrlen, struct zone const *zp, const char *letters,
2467     bool isdst, zic_t save, bool doquotes)
2468 {
2469 	char *	cp;
2470 	char *	slashp;
2471 	size_t	len;
2472 	char const *format = zp->z_format;
2473 
2474 	slashp = strchr(format, '/');
2475 	if (slashp == NULL) {
2476 		char letterbuf[PERCENT_Z_LEN_BOUND + 1];
2477 		if (zp->z_format_specifier == 'z')
2478 			letters = abbroffset(letterbuf, zp->z_stdoff + save);
2479 		else if (!letters)
2480 			letters = "%s";
2481 		snprintf(abbr, abbrlen, format, letters);
2482 	} else if (isdst) {
2483 		strlcpy(abbr, slashp + 1, abbrlen);
2484 	} else {
2485 		memcpy(abbr, format, slashp - format);
2486 		abbr[slashp - format] = '\0';
2487 	}
2488 	len = strlen(abbr);
2489 	if (!doquotes)
2490 		return len;
2491 	for (cp = abbr; is_alpha(*cp); cp++)
2492 		continue;
2493 	if (len > 0 && *cp == '\0')
2494 		return len;
2495 	abbr[len + 2] = '\0';
2496 	abbr[len + 1] = '>';
2497 	memmove(abbr + 1, abbr, len);
2498 	abbr[0] = '<';
2499 	return len + 2;
2500 }
2501 
2502 static void
2503 updateminmax(const zic_t x)
2504 {
2505 	if (min_year > x)
2506 		min_year = x;
2507 	if (max_year < x)
2508 		max_year = x;
2509 }
2510 
2511 static int
2512 stringoffset(char *result, int resultlen, zic_t offset)
2513 {
2514 	int	hours;
2515 	int	minutes;
2516 	int	seconds;
2517 	bool negative = offset < 0;
2518 	int len = negative;
2519 
2520 	if (negative) {
2521 		offset = -offset;
2522 		result[0] = '-';
2523 	}
2524 	seconds = offset % SECSPERMIN;
2525 	offset /= SECSPERMIN;
2526 	minutes = offset % MINSPERHOUR;
2527 	offset /= MINSPERHOUR;
2528 	hours = offset;
2529 	if (hours >= HOURSPERDAY * DAYSPERWEEK) {
2530 		result[0] = '\0';
2531 		return 0;
2532 	}
2533 	len += snprintf(result + len, resultlen - len, "%d", hours);
2534 	if (minutes != 0 || seconds != 0) {
2535 		len += snprintf(result + len, resultlen - len,
2536 		    ":%02d", minutes);
2537 		if (seconds != 0)
2538 			len += snprintf(result + len, resultlen - len,
2539 			    ":%02d", seconds);
2540 	}
2541 	return len;
2542 }
2543 
2544 static int
2545 stringrule(char *result, int resultlen, struct rule *const rp, zic_t save, const zic_t stdoff)
2546 {
2547 	zic_t	tod = rp->r_tod;
2548 	int	compat = 0, len = 0;
2549 
2550 	if (rp->r_dycode == DC_DOM) {
2551 		int	month, total;
2552 
2553 		if (rp->r_dayofmonth == 29 && rp->r_month == TM_FEBRUARY)
2554 			return -1;
2555 		total = 0;
2556 		for (month = 0; month < rp->r_month; ++month)
2557 			total += len_months[0][month];
2558 		/* Omit the "J" in Jan and Feb, as that's shorter.  */
2559 		if (rp->r_month <= 1)
2560 		  len += snprintf(result + len, resultlen - len, "%d", total + rp->r_dayofmonth - 1);
2561 		else
2562 		  len += snprintf(result + len, resultlen - len, "J%d", total + rp->r_dayofmonth);
2563 	} else {
2564 		int	week;
2565 		int	wday = rp->r_wday;
2566 		int	wdayoff;
2567 
2568 		if (rp->r_dycode == DC_DOWGEQ) {
2569 			wdayoff = (rp->r_dayofmonth - 1) % DAYSPERWEEK;
2570 			if (wdayoff)
2571 				compat = 2013;
2572 			wday -= wdayoff;
2573 			tod += wdayoff * SECSPERDAY;
2574 			week = 1 + (rp->r_dayofmonth - 1) / DAYSPERWEEK;
2575 		} else if (rp->r_dycode == DC_DOWLEQ) {
2576 			if (rp->r_dayofmonth == len_months[1][rp->r_month])
2577 				week = 5;
2578 			else {
2579 				wdayoff = rp->r_dayofmonth % DAYSPERWEEK;
2580 				if (wdayoff)
2581 					compat = 2013;
2582 				wday -= wdayoff;
2583 				tod += wdayoff * SECSPERDAY;
2584 				week = rp->r_dayofmonth / DAYSPERWEEK;
2585 			}
2586 		} else	return -1;	/* "cannot happen" */
2587 		if (wday < 0)
2588 			wday += DAYSPERWEEK;
2589 		len += snprintf(result + len, resultlen - len, "M%d.%d.%d",
2590 				  rp->r_month + 1, week, wday);
2591 	}
2592 	if (rp->r_todisut)
2593 	  tod += stdoff;
2594 	if (rp->r_todisstd && !rp->r_isdst)
2595 	  tod += save;
2596 	if (tod != 2 * SECSPERMIN * MINSPERHOUR) {
2597 		if (len + 1 < resultlen)
2598 		    result[len++] = '/';
2599 		if (! stringoffset(result + len, resultlen - len, tod))
2600 			return -1;
2601 		if (tod < 0) {
2602 			if (compat < 2013)
2603 				compat = 2013;
2604 		} else if (SECSPERDAY <= tod) {
2605 			if (compat < 1994)
2606 				compat = 1994;
2607 		}
2608 	}
2609 	return compat;
2610 }
2611 
2612 static int
2613 rule_cmp(struct rule const *a, struct rule const *b)
2614 {
2615 	if (!a)
2616 		return -!!b;
2617 	if (!b)
2618 		return 1;
2619 	if (a->r_hiyear != b->r_hiyear)
2620 		return a->r_hiyear < b->r_hiyear ? -1 : 1;
2621 	if (a->r_hiyear == ZIC_MAX)
2622 		return 0;
2623 	if (a->r_month - b->r_month != 0)
2624 		return a->r_month - b->r_month;
2625 	return a->r_dayofmonth - b->r_dayofmonth;
2626 }
2627 
2628 static int
2629 stringzone(char *result, int resultlen, const struct zone *const zpfirst,
2630     const int zonecount)
2631 {
2632 	const struct zone *	zp;
2633 	struct rule *		rp;
2634 	struct rule *		stdrp;
2635 	struct rule *		dstrp;
2636 	ptrdiff_t	i;
2637 	int			compat = 0;
2638 	int			c;
2639 	size_t			len;
2640 	int			offsetlen;
2641 	struct rule		stdr, dstr;
2642 	int dstcmp;
2643 	struct rule *lastrp[2] = { NULL, NULL };
2644 	struct zone zstr[2];
2645 	struct zone const *stdzp;
2646 	struct zone const *dstzp;
2647 
2648 	result[0] = '\0';
2649 
2650 	/* Internet RFC 8536 section 5.1 says to use an empty TZ string if
2651 	   future timestamps are truncated.  */
2652 	if (hi_time < max_time)
2653 	  return -1;
2654 
2655 	zp = zpfirst + zonecount - 1;
2656 	for (i = 0; i < zp->z_nrules; ++i) {
2657 		struct rule **last;
2658 		int cmp;
2659 		rp = &zp->z_rules[i];
2660 		last = &lastrp[rp->r_isdst];
2661 		cmp = rule_cmp(*last, rp);
2662 		if (cmp < 0)
2663 		  *last = rp;
2664 		else if (cmp == 0)
2665 		  return -1;
2666 	}
2667 	stdrp = lastrp[false];
2668 	dstrp = lastrp[true];
2669 	dstcmp = zp->z_nrules ? rule_cmp(dstrp, stdrp) : zp->z_isdst ? 1 : -1;
2670 	stdzp = dstzp = zp;
2671 
2672 	if (dstcmp < 0) {
2673 	  /* Standard time all year.  */
2674 	  dstrp = NULL;
2675 	} else if (0 < dstcmp) {
2676 	  /* DST all year.  Use an abbreviation like
2677 	     "XXX3EDT4,0/0,J365/23" for EDT (-04) all year.  */
2678 	  zic_t save = dstrp ? dstrp->r_save : zp->z_save;
2679 	  if (0 <= save)
2680 	    {
2681 	      /* Positive DST, the typical case for all-year DST.
2682 		 Fake a timezone with negative DST.  */
2683 	      stdzp = &zstr[0];
2684 	      dstzp = &zstr[1];
2685 	      zstr[0].z_stdoff = zp->z_stdoff + 2 * save;
2686 	      zstr[0].z_format = "XXX";  /* Any 3 letters will do.  */
2687 	      zstr[0].z_format_specifier = 0;
2688 	      zstr[1].z_stdoff = zstr[0].z_stdoff;
2689 	      zstr[1].z_format = zp->z_format;
2690 	      zstr[1].z_format_specifier = zp->z_format_specifier;
2691 	    }
2692 	  dstr.r_month = TM_JANUARY;
2693 	  dstr.r_dycode = DC_DOM;
2694 	  dstr.r_dayofmonth = 1;
2695 	  dstr.r_tod = 0;
2696 	  dstr.r_todisstd = dstr.r_todisut = false;
2697 	  dstr.r_isdst = true;
2698 	  dstr.r_save = save < 0 ? save : -save;
2699 	  dstr.r_abbrvar = dstrp ? dstrp->r_abbrvar : NULL;
2700 	  stdr.r_month = TM_DECEMBER;
2701 	  stdr.r_dycode = DC_DOM;
2702 	  stdr.r_dayofmonth = 31;
2703 	  stdr.r_tod = SECSPERDAY + dstr.r_save;
2704 	  stdr.r_todisstd = stdr.r_todisut = false;
2705 	  stdr.r_isdst = false;
2706 	  stdr.r_save = 0;
2707 	  stdr.r_abbrvar = save < 0 && stdrp ? stdrp->r_abbrvar : NULL;
2708 	  dstrp = &dstr;
2709 	  stdrp = &stdr;
2710 	}
2711 	len = doabbr(result, resultlen, stdzp, stdrp ? stdrp->r_abbrvar : NULL,
2712 		     false, 0, true);
2713 	offsetlen = stringoffset(result + len, resultlen - len,
2714 	    -stdzp->z_stdoff);
2715 	if (! offsetlen) {
2716 		result[0] = '\0';
2717 		return -1;
2718 	}
2719 	len += offsetlen;
2720 	if (dstrp == NULL)
2721 		return compat;
2722 	len += doabbr(result + len, resultlen - len, dstzp, dstrp->r_abbrvar,
2723 		      dstrp->r_isdst, dstrp->r_save, true);
2724 	if (dstrp->r_save != SECSPERMIN * MINSPERHOUR) {
2725 		offsetlen = stringoffset(result + len, resultlen - len,
2726 				   - (dstzp->z_stdoff + dstrp->r_save));
2727 		if (! offsetlen) {
2728 			result[0] = '\0';
2729 			return -1;
2730 		}
2731 		len += offsetlen;
2732 	}
2733 	result[len++] = ',';
2734 	c = stringrule(result + len, resultlen - len, dstrp, dstrp->r_save, stdzp->z_stdoff);
2735 	if (c < 0) {
2736 		result[0] = '\0';
2737 		return -1;
2738 	}
2739 	if (compat < c)
2740 		compat = c;
2741 	len += strlen(result + len);
2742 	result[len++] = ',';
2743 	c = stringrule(result + len, resultlen - len, stdrp, dstrp->r_save, stdzp->z_stdoff);
2744 	if (c < 0) {
2745 		result[0] = '\0';
2746 		return -1;
2747 	}
2748 	if (compat < c)
2749 		compat = c;
2750 	return compat;
2751 }
2752 
2753 static void
2754 outzone(const struct zone *zpfirst, ptrdiff_t zonecount)
2755 {
2756 	const struct zone *	zp;
2757 	struct rule *		rp;
2758 	ptrdiff_t		i, j;
2759 	bool			usestart, useuntil;
2760 	zic_t			starttime, untiltime;
2761 	zic_t			stdoff;
2762 	zic_t			save;
2763 	zic_t			year;
2764 	zic_t			startoff;
2765 	bool			startttisstd;
2766 	bool			startttisut;
2767 	int			type;
2768 	char *			startbuf;
2769 	char *			ab;
2770 	char *			envvar;
2771 	size_t			max_abbr_len;
2772 	size_t			max_envvar_len;
2773 	bool			prodstic; /* all rules are min to max */
2774 	int			compat;
2775 	bool			do_extend;
2776 	char			version;
2777 	ptrdiff_t lastatmax = -1;
2778 	zic_t one = 1;
2779 	zic_t y2038_boundary = one << 31;
2780 	zic_t max_year0;
2781 	int defaulttype = -1;
2782 
2783 	check_for_signal();
2784 
2785 	max_abbr_len = 2 + max_format_len + max_abbrvar_len;
2786 	max_envvar_len = 2 * max_abbr_len + 5 * 9;
2787 	startbuf = zic_malloc(max_abbr_len + 1);
2788 	ab = zic_malloc(max_abbr_len + 1);
2789 	envvar = zic_malloc(max_envvar_len + 1);
2790 	INITIALIZE(untiltime);
2791 	INITIALIZE(starttime);
2792 	/*
2793 	** Now. . .finally. . .generate some useful data!
2794 	*/
2795 	timecnt = 0;
2796 	typecnt = 0;
2797 	charcnt = 0;
2798 	prodstic = zonecount == 1;
2799 	/*
2800 	** Thanks to Earl Chew
2801 	** for noting the need to unconditionally initialize startttisstd.
2802 	*/
2803 	startttisstd = false;
2804 	startttisut = false;
2805 	min_year = max_year = EPOCH_YEAR;
2806 	if (leapseen) {
2807 		updateminmax(leapminyear);
2808 		updateminmax(leapmaxyear + (leapmaxyear < ZIC_MAX));
2809 	}
2810 	for (i = 0; i < zonecount; ++i) {
2811 		zp = &zpfirst[i];
2812 		if (i < zonecount - 1)
2813 			updateminmax(zp->z_untilrule.r_loyear);
2814 		for (j = 0; j < zp->z_nrules; ++j) {
2815 			rp = &zp->z_rules[j];
2816 			if (rp->r_lowasnum)
2817 				updateminmax(rp->r_loyear);
2818 			if (rp->r_hiwasnum)
2819 				updateminmax(rp->r_hiyear);
2820 			if (rp->r_lowasnum || rp->r_hiwasnum)
2821 				prodstic = false;
2822 		}
2823 	}
2824 	/*
2825 	** Generate lots of data if a rule can't cover all future times.
2826 	*/
2827 	compat = stringzone(envvar, max_envvar_len + 1, zpfirst, zonecount);
2828 	version = compat < 2013 ? '2' : '3';
2829 	do_extend = compat < 0;
2830 	if (noise) {
2831 		if (!*envvar)
2832 			warning("%s %s",
2833 				_("no POSIX environment variable for zone"),
2834 				zpfirst->z_name);
2835 		else if (compat != 0) {
2836 			/* Circa-COMPAT clients, and earlier clients, might
2837 			   not work for this zone when given dates before
2838 			   1970 or after 2038.  */
2839 			warning(_("%s: pre-%d clients may mishandle"
2840 				  " distant timestamps"),
2841 				zpfirst->z_name, compat);
2842 		}
2843 	}
2844 	if (do_extend) {
2845 		/*
2846 		** Search through a couple of extra years past the obvious
2847 		** 400, to avoid edge cases.  For example, suppose a non-POSIX
2848 		** rule applies from 2012 onwards and has transitions in March
2849 		** and September, plus some one-off transitions in November
2850 		** 2013.  If zic looked only at the last 400 years, it would
2851 		** set max_year=2413, with the intent that the 400 years 2014
2852 		** through 2413 will be repeated.  The last transition listed
2853 		** in the tzfile would be in 2413-09, less than 400 years
2854 		** after the last one-off transition in 2013-11.  Two years
2855 		** might be overkill, but with the kind of edge cases
2856 		** available we're not sure that one year would suffice.
2857 		*/
2858 		enum { years_of_observations = YEARSPERREPEAT + 2 };
2859 
2860 		if (min_year >= ZIC_MIN + years_of_observations)
2861 			min_year -= years_of_observations;
2862 		else	min_year = ZIC_MIN;
2863 		if (max_year <= ZIC_MAX - years_of_observations)
2864 			max_year += years_of_observations;
2865 		else	max_year = ZIC_MAX;
2866 		/*
2867 		** Regardless of any of the above,
2868 		** for a "proDSTic" zone which specifies that its rules
2869 		** always have and always will be in effect,
2870 		** we only need one cycle to define the zone.
2871 		*/
2872 		if (prodstic) {
2873 			min_year = 1900;
2874 			max_year = min_year + years_of_observations;
2875 		}
2876 	}
2877 	max_year0 = max_year;
2878 	if (want_bloat()) {
2879 	  /* For the benefit of older systems,
2880 	     generate data from 1900 through 2038.  */
2881 	  if (min_year > 1900)
2882 		min_year = 1900;
2883 	  if (max_year < 2038)
2884 		max_year = 2038;
2885 	}
2886 
2887 	if (min_time < lo_time || hi_time < max_time)
2888 	  unspecifiedtype = addtype(0, "-00", false, false, false);
2889 
2890 	for (i = 0; i < zonecount; ++i) {
2891 		struct rule *prevrp = NULL;
2892 		zic_t prevktime;
2893 		INITIALIZE(prevktime);
2894 		/*
2895 		** A guess that may well be corrected later.
2896 		*/
2897 		save = 0;
2898 		zp = &zpfirst[i];
2899 		usestart = i > 0 && (zp - 1)->z_untiltime > min_time;
2900 		useuntil = i < (zonecount - 1);
2901 		if (useuntil && zp->z_untiltime <= min_time)
2902 			continue;
2903 		stdoff = zp->z_stdoff;
2904 		eat(zp->z_filename, zp->z_linenum);
2905 		*startbuf = '\0';
2906 		startoff = zp->z_stdoff;
2907 		if (zp->z_nrules == 0) {
2908 			save = zp->z_save;
2909 			doabbr(startbuf, max_abbr_len + 1,
2910 			    zp, NULL, zp->z_isdst, save, false);
2911 			type = addtype(oadd(zp->z_stdoff, save),
2912 				startbuf, zp->z_isdst, startttisstd,
2913 				startttisut);
2914 			if (usestart) {
2915 				addtt(starttime, type);
2916 				usestart = false;
2917 			} else
2918 				defaulttype = type;
2919 		} else for (year = min_year; year <= max_year; ++year) {
2920 			if (useuntil && year > zp->z_untilrule.r_hiyear)
2921 				break;
2922 			/*
2923 			** Mark which rules to do in the current year.
2924 			** For those to do, calculate rpytime(rp, year);
2925 			** The former TYPE field was also considered here.
2926 			*/
2927 			for (j = 0; j < zp->z_nrules; ++j) {
2928 				rp = &zp->z_rules[j];
2929 				eats(zp->z_filename, zp->z_linenum,
2930 					rp->r_filename, rp->r_linenum);
2931 				rp->r_todo = year >= rp->r_loyear &&
2932 						year <= rp->r_hiyear;
2933 				if (rp->r_todo) {
2934 					rp->r_temp = rpytime(rp, year);
2935 					rp->r_todo
2936 					  = (rp->r_temp < y2038_boundary
2937 					     || year <= max_year0);
2938 				}
2939 			}
2940 			for ( ; ; ) {
2941 				ptrdiff_t	k;
2942 				zic_t	jtime, ktime;
2943 				zic_t	offset;
2944 
2945 				INITIALIZE(ktime);
2946 				if (useuntil) {
2947 					/*
2948 					** Turn untiltime into UT
2949 					** assuming the current stdoff and
2950 					** save values.
2951 					*/
2952 					untiltime = zp->z_untiltime;
2953 					if (!zp->z_untilrule.r_todisut)
2954 						untiltime = tadd(untiltime,
2955 								 -stdoff);
2956 					if (!zp->z_untilrule.r_todisstd)
2957 						untiltime = tadd(untiltime,
2958 								 -save);
2959 				}
2960 				/*
2961 				** Find the rule (of those to do, if any)
2962 				** that takes effect earliest in the year.
2963 				*/
2964 				k = -1;
2965 				for (j = 0; j < zp->z_nrules; ++j) {
2966 					rp = &zp->z_rules[j];
2967 					if (!rp->r_todo)
2968 						continue;
2969 					eats(zp->z_filename, zp->z_linenum,
2970 						rp->r_filename, rp->r_linenum);
2971 					offset = rp->r_todisut ? 0 : stdoff;
2972 					if (!rp->r_todisstd)
2973 						offset = oadd(offset, save);
2974 					jtime = rp->r_temp;
2975 					if (jtime == min_time ||
2976 						jtime == max_time)
2977 							continue;
2978 					jtime = tadd(jtime, -offset);
2979 					if (k < 0 || jtime < ktime) {
2980 						k = j;
2981 						ktime = jtime;
2982 					} else if (jtime == ktime) {
2983 					  char const *dup_rules_msg =
2984 					    _("two rules for same instant");
2985 					  eats(zp->z_filename, zp->z_linenum,
2986 					       rp->r_filename, rp->r_linenum);
2987 					  warning("%s", dup_rules_msg);
2988 					  rp = &zp->z_rules[k];
2989 					  eats(zp->z_filename, zp->z_linenum,
2990 					       rp->r_filename, rp->r_linenum);
2991 					  error("%s", dup_rules_msg);
2992 					}
2993 				}
2994 				if (k < 0)
2995 					break;	/* go on to next year */
2996 				rp = &zp->z_rules[k];
2997 				rp->r_todo = false;
2998 				if (useuntil && ktime >= untiltime)
2999 					break;
3000 				save = rp->r_save;
3001 				if (usestart && ktime == starttime)
3002 					usestart = false;
3003 				if (usestart) {
3004 					if (ktime < starttime) {
3005 						startoff = oadd(zp->z_stdoff,
3006 								save);
3007 						doabbr(startbuf,
3008 							max_abbr_len + 1,
3009 							zp,
3010 							rp->r_abbrvar,
3011 							rp->r_isdst,
3012 							rp->r_save,
3013 							false);
3014 						continue;
3015 					}
3016 					if (*startbuf == '\0'
3017 					    && startoff == oadd(zp->z_stdoff,
3018 								save)) {
3019 							doabbr(startbuf,
3020 								max_abbr_len + 1,
3021 								zp,
3022 								rp->r_abbrvar,
3023 								rp->r_isdst,
3024 								rp->r_save,
3025 								false);
3026 					}
3027 				}
3028 				eats(zp->z_filename, zp->z_linenum,
3029 					rp->r_filename, rp->r_linenum);
3030 				doabbr(ab, max_abbr_len + 1, zp, rp->r_abbrvar,
3031 				       rp->r_isdst, rp->r_save, false);
3032 				offset = oadd(zp->z_stdoff, rp->r_save);
3033 				if (!want_bloat() && !useuntil && !do_extend
3034 				    && prevrp && lo_time <= prevktime
3035 				    && rp->r_hiyear == ZIC_MAX
3036 				    && prevrp->r_hiyear == ZIC_MAX)
3037 				  break;
3038 				type = addtype(offset, ab, rp->r_isdst,
3039 					rp->r_todisstd, rp->r_todisut);
3040 				if (defaulttype < 0 && !rp->r_isdst)
3041 				  defaulttype = type;
3042 				if (rp->r_hiyear == ZIC_MAX
3043 				    && ! (0 <= lastatmax
3044 					  && ktime < attypes[lastatmax].at))
3045 				  lastatmax = timecnt;
3046 				addtt(ktime, type);
3047 				prevrp = rp;
3048 				prevktime = ktime;
3049 			}
3050 		}
3051 		if (usestart) {
3052 			if (*startbuf == '\0' &&
3053 				zp->z_format != NULL &&
3054 				strchr(zp->z_format, '%') == NULL &&
3055 				strchr(zp->z_format, '/') == NULL)
3056 					strncpy(startbuf, zp->z_format,
3057 					    max_abbr_len + 1 - 1);
3058 			eat(zp->z_filename, zp->z_linenum);
3059 			if (*startbuf == '\0')
3060 error(_("can't determine time zone abbreviation to use just after until time"));
3061 			else {
3062 			  bool isdst = startoff != zp->z_stdoff;
3063 			  type = addtype(startoff, startbuf, isdst,
3064 					 startttisstd, startttisut);
3065 			  if (defaulttype < 0 && !isdst)
3066 			    defaulttype = type;
3067 			  addtt(starttime, type);
3068 			}
3069 		}
3070 		/*
3071 		** Now we may get to set starttime for the next zone line.
3072 		*/
3073 		if (useuntil) {
3074 			startttisstd = zp->z_untilrule.r_todisstd;
3075 			startttisut = zp->z_untilrule.r_todisut;
3076 			starttime = zp->z_untiltime;
3077 			if (!startttisstd)
3078 			  starttime = tadd(starttime, -save);
3079 			if (!startttisut)
3080 			  starttime = tadd(starttime, -stdoff);
3081 		}
3082 	}
3083 	if (defaulttype < 0)
3084 	  defaulttype = 0;
3085 	if (0 <= lastatmax)
3086 	  attypes[lastatmax].dontmerge = true;
3087 	if (do_extend) {
3088 		/*
3089 		** If we're extending the explicitly listed observations
3090 		** for 400 years because we can't fill the POSIX-TZ field,
3091 		** check whether we actually ended up explicitly listing
3092 		** observations through that period.  If there aren't any
3093 		** near the end of the 400-year period, add a redundant
3094 		** one at the end of the final year, to make it clear
3095 		** that we are claiming to have definite knowledge of
3096 		** the lack of transitions up to that point.
3097 		*/
3098 		struct rule xr;
3099 		struct attype *lastat;
3100 		memset(&xr, 0, sizeof(xr));
3101 		xr.r_month = TM_JANUARY;
3102 		xr.r_dycode = DC_DOM;
3103 		xr.r_dayofmonth = 1;
3104 		xr.r_tod = 0;
3105 		for (lastat = attypes, i = 1; i < timecnt; i++)
3106 			if (attypes[i].at > lastat->at)
3107 				lastat = &attypes[i];
3108 		if (!lastat || lastat->at < rpytime(&xr, max_year - 1)) {
3109 			addtt(rpytime(&xr, max_year + 1),
3110 			      lastat ? lastat->type : defaulttype);
3111 			attypes[timecnt - 1].dontmerge = true;
3112 		}
3113 	}
3114 	writezone(zpfirst->z_name, envvar, version, defaulttype);
3115 	free(startbuf);
3116 	free(ab);
3117 	free(envvar);
3118 }
3119 
3120 static void
3121 addtt(zic_t starttime, int type)
3122 {
3123 	attypes = growalloc(attypes, sizeof *attypes, timecnt, &timecnt_alloc);
3124 	attypes[timecnt].at = starttime;
3125 	attypes[timecnt].dontmerge = false;
3126 	attypes[timecnt].type = type;
3127 	++timecnt;
3128 }
3129 
3130 static int
3131 addtype(zic_t utoff, char const *abbr, bool isdst, bool ttisstd, bool ttisut)
3132 {
3133 	int	i, j;
3134 
3135 	if (! (-1L - 2147483647L <= utoff && utoff <= 2147483647L)) {
3136 		error(_("UT offset out of range"));
3137 		exit(EXIT_FAILURE);
3138 	}
3139 	if (!want_bloat())
3140 	  ttisstd = ttisut = false;
3141 
3142 	for (j = 0; j < charcnt; ++j)
3143 		if (strcmp(&chars[j], abbr) == 0)
3144 			break;
3145 	if (j == charcnt)
3146 		newabbr(abbr);
3147 	else {
3148 	  /* If there's already an entry, return its index.  */
3149 	  for (i = 0; i < typecnt; i++)
3150 	    if (utoff == utoffs[i] && isdst == isdsts[i] && j == desigidx[i]
3151 		&& ttisstd == ttisstds[i] && ttisut == ttisuts[i])
3152 	      return i;
3153 	}
3154 	/*
3155 	** There isn't one; add a new one, unless there are already too
3156 	** many.
3157 	*/
3158 	if (typecnt >= TZ_MAX_TYPES) {
3159 		error(_("too many local time types"));
3160 		exit(EXIT_FAILURE);
3161 	}
3162 	i = typecnt++;
3163 	utoffs[i] = utoff;
3164 	isdsts[i] = isdst;
3165 	ttisstds[i] = ttisstd;
3166 	ttisuts[i] = ttisut;
3167 	desigidx[i] = j;
3168 	return i;
3169 }
3170 
3171 static void
3172 leapadd(zic_t t, int correction, int rolling)
3173 {
3174 	int	i;
3175 
3176 	if (TZ_MAX_LEAPS <= leapcnt) {
3177 		error(_("too many leap seconds"));
3178 		exit(EXIT_FAILURE);
3179 	}
3180 	if (rolling && (lo_time != min_time || hi_time != max_time)) {
3181 	  error(_("Rolling leap seconds not supported with -r"));
3182 	  exit(EXIT_FAILURE);
3183 	}
3184 	for (i = 0; i < leapcnt; ++i)
3185 		if (t <= trans[i])
3186 			break;
3187 	memmove(&trans[i + 1], &trans[i], (leapcnt - i) * sizeof *trans);
3188 	memmove(&corr[i + 1], &corr[i], (leapcnt - i) * sizeof *corr);
3189 	memmove(&roll[i + 1], &roll[i], (leapcnt - i) * sizeof *roll);
3190 	trans[i] = t;
3191 	corr[i] = correction;
3192 	roll[i] = rolling;
3193 	++leapcnt;
3194 }
3195 
3196 static void
3197 adjleap(void)
3198 {
3199 	int	i;
3200 	zic_t	last = 0;
3201 	zic_t	prevtrans = 0;
3202 
3203 	/*
3204 	** propagate leap seconds forward
3205 	*/
3206 	for (i = 0; i < leapcnt; ++i) {
3207 		if (trans[i] - prevtrans < 28 * SECSPERDAY) {
3208 			error(_("Leap seconds too close together"));
3209 			exit(EXIT_FAILURE);
3210 		}
3211 		prevtrans = trans[i];
3212 		trans[i] = tadd(trans[i], last);
3213 		last = corr[i] += last;
3214 	}
3215 
3216 	if (0 <= leapexpires) {
3217 	  leapexpires = oadd(leapexpires, last);
3218 	  if (! (leapcnt == 0 || (trans[leapcnt - 1] < leapexpires))) {
3219 	    error(_("last Leap time does not precede Expires time"));
3220 	    exit(EXIT_FAILURE);
3221 	  }
3222 	}
3223 }
3224 
3225 /* Is A a space character in the C locale?  */
3226 static bool
3227 is_space(char a)
3228 {
3229 	switch (a) {
3230 	  default:
3231 		return false;
3232 	  case ' ': case '\f': case '\n': case '\r': case '\t': case '\v':
3233 	  	return true;
3234 	}
3235 }
3236 
3237 /* Is A an alphabetic character in the C locale?  */
3238 static bool
3239 is_alpha(char a)
3240 {
3241 	switch (a) {
3242 	  default:
3243 		return false;
3244 	  case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G':
3245 	  case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N':
3246 	  case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U':
3247 	  case 'V': case 'W': case 'X': case 'Y': case 'Z':
3248 	  case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g':
3249 	  case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n':
3250 	  case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u':
3251 	  case 'v': case 'w': case 'x': case 'y': case 'z':
3252 		return true;
3253 	}
3254 }
3255 
3256 /* If A is an uppercase character in the C locale, return its lowercase
3257    counterpart.  Otherwise, return A.  */
3258 static char
3259 lowerit(char a)
3260 {
3261 	switch (a) {
3262 	  default: return a;
3263 	  case 'A': return 'a'; case 'B': return 'b'; case 'C': return 'c';
3264 	  case 'D': return 'd'; case 'E': return 'e'; case 'F': return 'f';
3265 	  case 'G': return 'g'; case 'H': return 'h'; case 'I': return 'i';
3266 	  case 'J': return 'j'; case 'K': return 'k'; case 'L': return 'l';
3267 	  case 'M': return 'm'; case 'N': return 'n'; case 'O': return 'o';
3268 	  case 'P': return 'p'; case 'Q': return 'q'; case 'R': return 'r';
3269 	  case 'S': return 's'; case 'T': return 't'; case 'U': return 'u';
3270 	  case 'V': return 'v'; case 'W': return 'w'; case 'X': return 'x';
3271 	  case 'Y': return 'y'; case 'Z': return 'z';
3272 	}
3273 }
3274 
3275 /* case-insensitive equality */
3276 static ATTRIBUTE_PURE bool
3277 ciequal(const char *ap, const char *bp)
3278 {
3279 	while (lowerit(*ap) == lowerit(*bp++))
3280 		if (*ap++ == '\0')
3281 			return true;
3282 	return false;
3283 }
3284 
3285 static ATTRIBUTE_PURE bool
3286 itsabbr(const char *abbr, const char *word)
3287 {
3288 	if (lowerit(*abbr) != lowerit(*word))
3289 		return false;
3290 	++word;
3291 	while (*++abbr != '\0')
3292 		do {
3293 			if (*word == '\0')
3294 				return false;
3295 		} while (lowerit(*word++) != lowerit(*abbr));
3296 	return true;
3297 }
3298 
3299 /* Return true if ABBR is an initial prefix of WORD, ignoring ASCII case.  */
3300 
3301 static ATTRIBUTE_PURE bool
3302 ciprefix(char const *abbr, char const *word)
3303 {
3304   do
3305     if (!*abbr)
3306       return true;
3307   while (lowerit(*abbr++) == lowerit(*word++));
3308 
3309   return false;
3310 }
3311 
3312 static const struct lookup *
3313 byword(const char *word, const struct lookup *table)
3314 {
3315 	const struct lookup *	foundlp;
3316 	const struct lookup *	lp;
3317 
3318 	if (word == NULL || table == NULL)
3319 		return NULL;
3320 
3321 	/* If TABLE is LASTS and the word starts with "last" followed
3322 	   by a non-'-', skip the "last" and look in WDAY_NAMES instead.
3323 	   Warn about any usage of the undocumented prefix "last-".  */
3324 	if (table == lasts && ciprefix("last", word) && word[4]) {
3325 	  if (word[4] == '-')
3326 	    warning(_("\"%s\" is undocumented; use \"last%s\" instead"),
3327 		    word, word + 5);
3328 	  else {
3329 	    word += 4;
3330 	    table = wday_names;
3331 	  }
3332 	}
3333 
3334 	/*
3335 	** Look for exact match.
3336 	*/
3337 	for (lp = table; lp->l_word != NULL; ++lp)
3338 		if (ciequal(word, lp->l_word))
3339 			return lp;
3340 	/*
3341 	** Look for inexact match.
3342 	*/
3343 	foundlp = NULL;
3344 	for (lp = table; lp->l_word != NULL; ++lp)
3345 		if (ciprefix(word, lp->l_word)) {
3346 			if (foundlp == NULL)
3347 				foundlp = lp;
3348 			else	return NULL;	/* multiple inexact matches */
3349 		}
3350 
3351 	if (foundlp && noise) {
3352 	  /* Warn about any backward-compatibility issue with pre-2017c zic.  */
3353 	  bool pre_2017c_match = false;
3354 	  for (lp = table; lp->l_word; lp++)
3355 	    if (itsabbr(word, lp->l_word)) {
3356 	      if (pre_2017c_match) {
3357 		warning(_("\"%s\" is ambiguous in pre-2017c zic"), word);
3358 		break;
3359 	      }
3360 	      pre_2017c_match = true;
3361 	    }
3362 	}
3363 
3364 	return foundlp;
3365 }
3366 
3367 static char **
3368 getfields(char *cp)
3369 {
3370 	char *	dp;
3371 	char **	array;
3372 	int	nsubs;
3373 
3374 	if (cp == NULL)
3375 		return NULL;
3376 	array = zic_malloc(size_product(strlen(cp) + 1, sizeof *array));
3377 	nsubs = 0;
3378 	for ( ; ; ) {
3379 		while (is_space(*cp))
3380 				++cp;
3381 		if (*cp == '\0' || *cp == '#')
3382 			break;
3383 		array[nsubs++] = dp = cp;
3384 		do {
3385 			if ((*dp = *cp++) != '"')
3386 				++dp;
3387 			else while ((*dp = *cp++) != '"')
3388 				if (*dp != '\0')
3389 					++dp;
3390 				else {
3391 				  error(_("Odd number of quotation marks"));
3392 				  exit(EXIT_FAILURE);
3393 				}
3394 		} while (*cp && *cp != '#' && !is_space(*cp));
3395 		if (is_space(*cp))
3396 			++cp;
3397 		*dp = '\0';
3398 	}
3399 	array[nsubs] = NULL;
3400 	return array;
3401 }
3402 
3403 static _Noreturn void
3404 time_overflow(void)
3405 {
3406 	error(_("time overflow"));
3407 	exit(EXIT_FAILURE);
3408 }
3409 
3410 static ATTRIBUTE_PURE zic_t
3411 oadd(zic_t t1, zic_t t2)
3412 {
3413 	if (t1 < 0 ? t2 < ZIC_MIN - t1 : ZIC_MAX - t1 < t2)
3414 		time_overflow();
3415 	return t1 + t2;
3416 }
3417 
3418 static ATTRIBUTE_PURE zic_t
3419 tadd(zic_t t1, zic_t t2)
3420 {
3421 	if (t1 < 0) {
3422 		if (t2 < min_time - t1) {
3423 			if (t1 != min_time)
3424 				time_overflow();
3425 			return min_time;
3426 		}
3427 	} else {
3428 		if (max_time - t1 < t2) {
3429 			if (t1 != max_time)
3430 				time_overflow();
3431 			return max_time;
3432 		}
3433 	}
3434 	return t1 + t2;
3435 }
3436 
3437 /*
3438 ** Given a rule, and a year, compute the date (in seconds since January 1,
3439 ** 1970, 00:00 LOCAL time) in that year that the rule refers to.
3440 */
3441 
3442 static zic_t
3443 rpytime(const struct rule *rp, zic_t wantedy)
3444 {
3445 	int	m, i;
3446 	zic_t	dayoff;			/* with a nod to Margaret O. */
3447 	zic_t	t, y;
3448 	int yrem;
3449 
3450 	if (wantedy == ZIC_MIN)
3451 		return min_time;
3452 	if (wantedy == ZIC_MAX)
3453 		return max_time;
3454 	m = TM_JANUARY;
3455 	y = EPOCH_YEAR;
3456 
3457 	/* dayoff = floor((wantedy - y) / YEARSPERREPEAT) * DAYSPERREPEAT,
3458 	   sans overflow.  */
3459 	yrem = wantedy % YEARSPERREPEAT - y % YEARSPERREPEAT;
3460 	dayoff = ((wantedy / YEARSPERREPEAT - y / YEARSPERREPEAT
3461 		   + yrem / YEARSPERREPEAT - (yrem % YEARSPERREPEAT < 0))
3462 		  * DAYSPERREPEAT);
3463 	/* wantedy = y + ((wantedy - y) mod YEARSPERREPEAT), sans overflow.  */
3464 	wantedy = y + (yrem + 2 * YEARSPERREPEAT) % YEARSPERREPEAT;
3465 
3466 	while (wantedy != y) {
3467 		i = len_years[isleap(y)];
3468 		dayoff = oadd(dayoff, i);
3469 		y++;
3470 	}
3471 	while (m != rp->r_month) {
3472 		i = len_months[isleap(y)][m];
3473 		dayoff = oadd(dayoff, i);
3474 		++m;
3475 	}
3476 	i = rp->r_dayofmonth;
3477 	if (m == TM_FEBRUARY && i == 29 && !isleap(y)) {
3478 		if (rp->r_dycode == DC_DOWLEQ)
3479 			--i;
3480 		else {
3481 			error(_("use of 2/29 in non leap-year"));
3482 			exit(EXIT_FAILURE);
3483 		}
3484 	}
3485 	--i;
3486 	dayoff = oadd(dayoff, i);
3487 	if (rp->r_dycode == DC_DOWGEQ || rp->r_dycode == DC_DOWLEQ) {
3488 		/*
3489 		** Don't trust mod of negative numbers.
3490 		*/
3491 		zic_t wday = ((EPOCH_WDAY + dayoff % DAYSPERWEEK + DAYSPERWEEK)
3492 			      % DAYSPERWEEK);
3493 		while (wday != rp->r_wday)
3494 			if (rp->r_dycode == DC_DOWGEQ) {
3495 				dayoff = oadd(dayoff, (zic_t) 1);
3496 				if (++wday >= DAYSPERWEEK)
3497 					wday = 0;
3498 				++i;
3499 			} else {
3500 				dayoff = oadd(dayoff, (zic_t) -1);
3501 				if (--wday < 0)
3502 					wday = DAYSPERWEEK - 1;
3503 				--i;
3504 			}
3505 		if (i < 0 || i >= len_months[isleap(y)][m]) {
3506 			if (noise)
3507 				warning(_("rule goes past start/end of month; \
3508 will not work with pre-2004 versions of zic"));
3509 		}
3510 	}
3511 	if (dayoff < min_time / SECSPERDAY)
3512 		return min_time;
3513 	if (dayoff > max_time / SECSPERDAY)
3514 		return max_time;
3515 	t = (zic_t) dayoff * SECSPERDAY;
3516 	return tadd(t, rp->r_tod);
3517 }
3518 
3519 static void
3520 newabbr(const char *string)
3521 {
3522 	int	i;
3523 
3524 	if (strcmp(string, GRANDPARENTED) != 0) {
3525 		const char *	cp;
3526 		const char *	mp;
3527 
3528 		cp = string;
3529 		mp = NULL;
3530 		while (is_alpha(*cp) || ('0' <= *cp && *cp <= '9')
3531 		       || *cp == '-' || *cp == '+')
3532 				++cp;
3533 		if (noise && cp - string < 3)
3534 		  mp = _("time zone abbreviation has fewer than 3 characters");
3535 		if (cp - string > ZIC_MAX_ABBR_LEN_WO_WARN)
3536 		  mp = _("time zone abbreviation has too many characters");
3537 		if (*cp != '\0')
3538 mp = _("time zone abbreviation differs from POSIX standard");
3539 		if (mp != NULL)
3540 			warning("%s (%s)", mp, string);
3541 	}
3542 	i = strlen(string) + 1;
3543 	if (charcnt + i > TZ_MAX_CHARS) {
3544 		error(_("too many, or too long, time zone abbreviations"));
3545 		exit(EXIT_FAILURE);
3546 	}
3547 	strncpy(&chars[charcnt], string, sizeof(chars) - charcnt - 1);
3548 	charcnt += i;
3549 }
3550 
3551 /* Ensure that the directories of ARGNAME exist, by making any missing
3552    ones.  If ANCESTORS, do this only for ARGNAME's ancestors; otherwise,
3553    do it for ARGNAME too.  Exit with failure if there is trouble.
3554    Do not consider an existing file to be trouble.  */
3555 static void
3556 mkdirs(char const *argname, bool ancestors)
3557 {
3558 	char *	name;
3559 	char *	cp;
3560 
3561 	cp = name = ecpyalloc(argname);
3562 
3563 	/* On MS-Windows systems, do not worry about drive letters or
3564 	   backslashes, as this should suffice in practice.  Time zone
3565 	   names do not use drive letters and backslashes.  If the -d
3566 	   option of zic does not name an already-existing directory,
3567 	   it can use slashes to separate the already-existing
3568 	   ancestor prefix from the to-be-created subdirectories.  */
3569 
3570 	/* Do not mkdir a root directory, as it must exist.  */
3571 	while (*cp == '/')
3572 	  cp++;
3573 
3574 	while (cp && ((cp = strchr(cp, '/')) || !ancestors)) {
3575 		if (cp)
3576 		  *cp = '\0';
3577 		/*
3578 		** Try to create it.  It's OK if creation fails because
3579 		** the directory already exists, perhaps because some
3580 		** other process just created it.  For simplicity do
3581 		** not check first whether it already exists, as that
3582 		** is checked anyway if the mkdir fails.
3583 		*/
3584 		if (mkdir(name, MKDIR_UMASK) != 0) {
3585 			/* Do not report an error if err == EEXIST, because
3586 			   some other process might have made the directory
3587 			   in the meantime.  */
3588 			int err = errno;
3589 			if (err != EEXIST) {
3590 				error(_("%s: Can't create directory %s: %s"),
3591 				      progname, name, strerror(err));
3592 				exit(EXIT_FAILURE);
3593 			}
3594 		}
3595 		if (cp)
3596 		  *cp++ = '/';
3597 	}
3598 	free(name);
3599 }
3600