xref: /netbsd-src/lib/libc/time/zic.c (revision dd3ee07da436799d8de85f3055253118b76bf345)
1 /*	$NetBSD: zic.c,v 1.81 2022/03/22 17:48:39 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.81 2022/03/22 17:48:39 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[] =
1005     "abcdefghijklmnopqrstuvwxyz"
1006     "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
1007     "0123456789";
1008   enum { prefixlen = sizeof prefix - 1, alphabetlen = sizeof alphabet - 1 };
1009   int suffixlen = 6;
1010   char const *lastslash = strrchr(src, '/');
1011   ptrdiff_t dirlen = lastslash ? lastslash + 1 - src : 0;
1012   static unsigned short initialized;
1013   int i;
1014 
1015   if (!dst) {
1016     dst = emalloc(dirlen + prefixlen + suffixlen + 1);
1017     memcpy(dst, src, dirlen);
1018     memcpy(dst + dirlen, prefix, prefixlen);
1019     dst[dirlen + prefixlen + suffixlen] = '\0';
1020     *name = *namealloc = dst;
1021   }
1022 
1023   /* This randomization is not the best, but is portable to C89.  */
1024   if (!initialized++) {
1025     unsigned now = time(NULL);
1026     srand(rand() ^ now);
1027   }
1028   for (i = 0; i < suffixlen; i++)
1029     dst[dirlen + prefixlen + i] = alphabet[rand() % alphabetlen];
1030 }
1031 
1032 /* Prepare to write to the file *OUTNAME, using *TEMPNAME to store the
1033    name of the temporary file that will eventually be renamed to
1034    *OUTNAME.  Assign the temporary file's name to both *OUTNAME and
1035    *TEMPNAME.  If *TEMPNAME is null, allocate the name of any such
1036    temporary file; otherwise, reuse *TEMPNAME's storage, which is
1037    already set up and only needs its trailing suffix updated.  */
1038 static FILE *
1039 open_outfile(char const **outname, char **tempname)
1040 {
1041 #if __STDC_VERSION__ < 201112
1042   static char const fopen_mode[] = "wb";
1043 #else
1044   static char const fopen_mode[] = "wbx";
1045 #endif
1046 
1047   FILE *fp;
1048   bool dirs_made = false;
1049   if (!*tempname)
1050     random_dirent(outname, tempname);
1051 
1052   while (! (fp = fopen(*outname, fopen_mode))) {
1053     int fopen_errno = errno;
1054     if (fopen_errno == ENOENT && !dirs_made) {
1055       mkdirs(*outname, true);
1056       dirs_made = true;
1057     } else if (fopen_errno == EEXIST)
1058       random_dirent(outname, tempname);
1059     else {
1060       fprintf(stderr, _("%s: Can't create %s/%s: %s\n"),
1061 	      progname, directory, *outname, strerror(fopen_errno));
1062       exit(EXIT_FAILURE);
1063     }
1064   }
1065 
1066   return fp;
1067 }
1068 
1069 /* If TEMPNAME, the result is in the temporary file TEMPNAME even
1070    though the user wanted it in NAME, so rename TEMPNAME to NAME.
1071    Report an error and exit if there is trouble.  Also, free TEMPNAME.  */
1072 static void
1073 rename_dest(char *tempname, char const *name)
1074 {
1075   if (tempname) {
1076     if (rename(tempname, name) != 0) {
1077       int rename_errno = errno;
1078       remove(tempname);
1079       fprintf(stderr, _("%s: rename to %s/%s: %s\n"),
1080 	      progname, directory, name, strerror(rename_errno));
1081       exit(EXIT_FAILURE);
1082     }
1083     free(tempname);
1084   }
1085 }
1086 
1087 /* Create symlink contents suitable for symlinking FROM to TO, as a
1088    freshly allocated string.  FROM should be a relative file name, and
1089    is relative to the global variable DIRECTORY.  TO can be either
1090    relative or absolute.  */
1091 static char *
1092 relname(char const *target, char const *linkname)
1093 {
1094   size_t i, taillen, dotdotetcsize;
1095   size_t dir_len = 0, dotdots = 0, linksize = SIZE_MAX;
1096   char const *f = target;
1097   char *result = NULL;
1098   if (*linkname == '/') {
1099     /* Make F absolute too.  */
1100     size_t len = strlen(directory);
1101     bool needslash = len && directory[len - 1] != '/';
1102     linksize = len + needslash + strlen(target) + 1;
1103     f = result = emalloc(linksize);
1104     strcpy(result, directory);
1105     result[len] = '/';
1106     strcpy(result + len + needslash, target);
1107   }
1108   for (i = 0; f[i] && f[i] == linkname[i]; i++)
1109     if (f[i] == '/')
1110       dir_len = i + 1;
1111   for (; linkname[i]; i++)
1112     dotdots += linkname[i] == '/' && linkname[i - 1] != '/';
1113   taillen = strlen(f + dir_len);
1114   dotdotetcsize = 3 * dotdots + taillen + 1;
1115   if (dotdotetcsize <= linksize) {
1116     if (!result)
1117       result = emalloc(dotdotetcsize);
1118     for (i = 0; i < dotdots; i++)
1119       memcpy(result + 3 * i, "../", 3);
1120     memmove(result + 3 * dotdots, f + dir_len, taillen + 1);
1121   }
1122   return result;
1123 }
1124 
1125 static void
1126 dolink(char const *target, char const *linkname, bool staysymlink)
1127 {
1128 	bool linkdirs_made = false;
1129 	int link_errno;
1130 	char *tempname = NULL;
1131 	char const *outname = linkname;
1132 
1133 	check_for_signal();
1134 
1135 	if (strcmp(target, "-") == 0) {
1136 	  if (remove(linkname) == 0 || errno == ENOENT || errno == ENOTDIR)
1137 	    return;
1138 	  else {
1139 	    char const *e = strerror(errno);
1140 	    fprintf(stderr, _("%s: Can't remove %s/%s: %s\n"),
1141 		    progname, directory, linkname, e);
1142 	    exit(EXIT_FAILURE);
1143 	  }
1144 	}
1145 
1146 	while (true) {
1147 	  if (linkat(AT_FDCWD, target, AT_FDCWD, outname, AT_SYMLINK_FOLLOW)
1148 	      == 0) {
1149 	    link_errno = 0;
1150 	    break;
1151 	  }
1152 	  link_errno = errno;
1153 	  if (link_errno == EXDEV || link_errno == ENOTSUP)
1154 	    break;
1155 
1156 	  if (link_errno == EEXIST) {
1157 	    staysymlink &= !tempname;
1158 	    random_dirent(&outname, &tempname);
1159 	    if (staysymlink && itssymlink(linkname))
1160 	      break;
1161 	  } else if (link_errno == ENOENT && !linkdirs_made) {
1162 	    mkdirs(linkname, true);
1163 	    linkdirs_made = true;
1164 	  } else {
1165 	    fprintf(stderr, _("%s: Can't link %s/%s to %s/%s: %s\n"),
1166 		    progname, directory, target, directory, outname,
1167 		    strerror(link_errno));
1168 	    exit(EXIT_FAILURE);
1169 	  }
1170 	}
1171 	if (link_errno != 0) {
1172 	  bool absolute = *target == '/';
1173 	  char *linkalloc = absolute ? NULL : relname(target, linkname);
1174 	  char const *contents = absolute ? target : linkalloc;
1175 	  int symlink_errno;
1176 
1177 	  while (true) {
1178 	    if (symlink(contents, outname) == 0) {
1179 	      symlink_errno = 0;
1180 	      break;
1181 	    }
1182 	    symlink_errno = errno;
1183 	    if (symlink_errno == EEXIST)
1184 	      random_dirent(&outname, &tempname);
1185 	    else if (symlink_errno == ENOENT && !linkdirs_made) {
1186 	      mkdirs(linkname, true);
1187 	      linkdirs_made = true;
1188 	    } else
1189 	      break;
1190 	  }
1191 	  free(linkalloc);
1192 	  if (symlink_errno == 0) {
1193 	    if (link_errno != ENOTSUP && link_errno != EEXIST)
1194 	      warning(_("symbolic link used because hard link failed: %s"),
1195 		      strerror(link_errno));
1196 	  } else {
1197 	    FILE *fp, *tp;
1198 	    int c;
1199 	    fp = fopen(target, "rb");
1200 	    if (!fp) {
1201 	      char const *e = strerror(errno);
1202 	      fprintf(stderr, _("%s: Can't read %s/%s: %s\n"),
1203 		      progname, directory, target, e);
1204 	      exit(EXIT_FAILURE);
1205 	    }
1206 	    tp = open_outfile(&outname, &tempname);
1207 	    while ((c = getc(fp)) != EOF)
1208 	      putc(c, tp);
1209 	    close_file(tp, directory, linkname, tempname);
1210 	    close_file(fp, directory, target, NULL);
1211 	    if (link_errno != ENOTSUP)
1212 	      warning(_("copy used because hard link failed: %s"),
1213 		      strerror(link_errno));
1214 	    else if (symlink_errno != ENOTSUP)
1215 	      warning(_("copy used because symbolic link failed: %s"),
1216 		      strerror(symlink_errno));
1217 	  }
1218 	}
1219 	rename_dest(tempname, linkname);
1220 }
1221 
1222 /* Return true if NAME is a symbolic link.  */
1223 static bool
1224 itssymlink(char const *name)
1225 {
1226   char c;
1227   return 0 <= readlink(name, &c, 1);
1228 }
1229 
1230 /*
1231 ** Associate sets of rules with zones.
1232 */
1233 
1234 /*
1235 ** Sort by rule name.
1236 */
1237 
1238 static int
1239 rcomp(const void *cp1, const void *cp2)
1240 {
1241   struct rule const *r1 = cp1, *r2 = cp2;
1242   return strcmp(r1->r_name, r2->r_name);
1243 }
1244 
1245 static void
1246 associate(void)
1247 {
1248 	struct zone *	zp;
1249 	struct rule *	rp;
1250 	ptrdiff_t	i, j, base, out;
1251 
1252 	if (nrules != 0) {
1253 		qsort(rules, (size_t)nrules, sizeof *rules, rcomp);
1254 		for (i = 0; i < nrules - 1; ++i) {
1255 			if (strcmp(rules[i].r_name,
1256 				rules[i + 1].r_name) != 0)
1257 					continue;
1258 			if (strcmp(rules[i].r_filename,
1259 				rules[i + 1].r_filename) == 0)
1260 					continue;
1261 			eat(rules[i].r_filename, rules[i].r_linenum);
1262 			warning(_("same rule name in multiple files"));
1263 			eat(rules[i + 1].r_filename, rules[i + 1].r_linenum);
1264 			warning(_("same rule name in multiple files"));
1265 			for (j = i + 2; j < nrules; ++j) {
1266 				if (strcmp(rules[i].r_name,
1267 					rules[j].r_name) != 0)
1268 						break;
1269 				if (strcmp(rules[i].r_filename,
1270 					rules[j].r_filename) == 0)
1271 						continue;
1272 				if (strcmp(rules[i + 1].r_filename,
1273 					rules[j].r_filename) == 0)
1274 						continue;
1275 				break;
1276 			}
1277 			i = j - 1;
1278 		}
1279 	}
1280 	for (i = 0; i < nzones; ++i) {
1281 		zp = &zones[i];
1282 		zp->z_rules = NULL;
1283 		zp->z_nrules = 0;
1284 	}
1285 	for (base = 0; base < nrules; base = out) {
1286 		rp = &rules[base];
1287 		for (out = base + 1; out < nrules; ++out)
1288 			if (strcmp(rp->r_name, rules[out].r_name) != 0)
1289 				break;
1290 		for (i = 0; i < nzones; ++i) {
1291 			zp = &zones[i];
1292 			if (strcmp(zp->z_rule, rp->r_name) != 0)
1293 				continue;
1294 			zp->z_rules = rp;
1295 			zp->z_nrules = out - base;
1296 		}
1297 	}
1298 	for (i = 0; i < nzones; ++i) {
1299 		zp = &zones[i];
1300 		if (zp->z_nrules == 0) {
1301 			/*
1302 			** Maybe we have a local standard time offset.
1303 			*/
1304 			eat(zp->z_filename, zp->z_linenum);
1305 			zp->z_save = getsave(zp->z_rule, &zp->z_isdst);
1306 			/*
1307 			** Note, though, that if there's no rule,
1308 			** a '%s' in the format is a bad thing.
1309 			*/
1310 			if (zp->z_format_specifier == 's')
1311 				error("%s", _("%s in ruleless zone"));
1312 		}
1313 	}
1314 	if (errors)
1315 		exit(EXIT_FAILURE);
1316 }
1317 
1318 static void
1319 infile(const char *name)
1320 {
1321 	FILE *			fp;
1322 	char **		fields;
1323 	char *			cp;
1324 	const struct lookup *	lp;
1325 	int			nfields;
1326 	bool			wantcont;
1327 	lineno			num;
1328 	char				buf[BUFSIZ];
1329 
1330 	if (strcmp(name, "-") == 0) {
1331 		name = _("standard input");
1332 		fp = stdin;
1333 	} else if ((fp = fopen(name, "r")) == NULL) {
1334 		const char *e = strerror(errno);
1335 
1336 		fprintf(stderr, _("%s: Can't open %s: %s\n"),
1337 			progname, name, e);
1338 		exit(EXIT_FAILURE);
1339 	}
1340 	wantcont = false;
1341 	for (num = 1; ; ++num) {
1342 		eat(name, num);
1343 		if (fgets(buf, (int) sizeof buf, fp) != buf)
1344 			break;
1345 		cp = strchr(buf, '\n');
1346 		if (cp == NULL) {
1347 			error(_("line too long"));
1348 			exit(EXIT_FAILURE);
1349 		}
1350 		*cp = '\0';
1351 		fields = getfields(buf);
1352 		nfields = 0;
1353 		while (fields[nfields] != NULL) {
1354 			static char	nada;
1355 
1356 			if (strcmp(fields[nfields], "-") == 0)
1357 				fields[nfields] = &nada;
1358 			++nfields;
1359 		}
1360 		if (nfields == 0) {
1361 			/* nothing to do */
1362 		} else if (wantcont) {
1363 			wantcont = inzcont(fields, nfields);
1364 		} else {
1365 			struct lookup const *line_codes
1366 			  = name == leapsec ? leap_line_codes : zi_line_codes;
1367 			lp = byword(fields[0], line_codes);
1368 			if (lp == NULL)
1369 				error(_("input line of unknown type"));
1370 			else switch (lp->l_value) {
1371 				case LC_RULE:
1372 					inrule(fields, nfields);
1373 					wantcont = false;
1374 					break;
1375 				case LC_ZONE:
1376 					wantcont = inzone(fields, nfields);
1377 					break;
1378 				case LC_LINK:
1379 					inlink(fields, nfields);
1380 					wantcont = false;
1381 					break;
1382 				case LC_LEAP:
1383 					inleap(fields, nfields);
1384 					wantcont = false;
1385 					break;
1386 				case LC_EXPIRES:
1387 					inexpires(fields, nfields);
1388 					wantcont = false;
1389 					break;
1390 				default: UNREACHABLE();
1391 			}
1392 		}
1393 		free(fields);
1394 	}
1395 	close_file(fp, NULL, filename, NULL);
1396 	if (wantcont)
1397 		error(_("expected continuation line not found"));
1398 }
1399 
1400 /*
1401 ** Convert a string of one of the forms
1402 **	h	-h	hh:mm	-hh:mm	hh:mm:ss	-hh:mm:ss
1403 ** into a number of seconds.
1404 ** A null string maps to zero.
1405 ** Call error with errstring and return zero on errors.
1406 */
1407 
1408 static zic_t
1409 gethms(char const *string, char const *errstring)
1410 {
1411 	zic_t	hh;
1412 	int sign, mm = 0, ss = 0;
1413 	char hhx, mmx, ssx, xr = '0', xs;
1414 	int tenths = 0;
1415 	bool ok = true;
1416 
1417 	if (string == NULL || *string == '\0')
1418 		return 0;
1419 	if (*string == '-') {
1420 		sign = -1;
1421 		++string;
1422 	} else	sign = 1;
1423 	switch (sscanf(string,
1424 		       "%"SCNdZIC"%c%d%c%d%c%1d%*[0]%c%*[0123456789]%c",
1425 		       &hh, &hhx, &mm, &mmx, &ss, &ssx, &tenths, &xr, &xs)) {
1426 	  default: ok = false; break;
1427 	  case 8:
1428 	    ok = '0' <= xr && xr <= '9';
1429 	    /* fallthrough */
1430 	  case 7:
1431 	    ok &= ssx == '.';
1432 	    if (ok && noise)
1433 	      warning(_("fractional seconds rejected by"
1434 			" pre-2018 versions of zic"));
1435 	    /* fallthrough */
1436 	  case 5: ok &= mmx == ':'; /* fallthrough */
1437 	  case 3: ok &= hhx == ':'; /* fallthrough */
1438 	  case 1: break;
1439 	}
1440 	if (!ok) {
1441 			error("%s", errstring);
1442 			return 0;
1443 	}
1444 	if (hh < 0 ||
1445 		mm < 0 || mm >= MINSPERHOUR ||
1446 		ss < 0 || ss > SECSPERMIN) {
1447 			error("%s", errstring);
1448 			return 0;
1449 	}
1450 	if (ZIC_MAX / SECSPERHOUR < hh) {
1451 		error(_("time overflow"));
1452 		return 0;
1453 	}
1454 	ss += 5 + ((ss ^ 1) & (xr == '0')) <= tenths; /* Round to even.  */
1455 	if (noise && (hh > HOURSPERDAY ||
1456 		(hh == HOURSPERDAY && (mm != 0 || ss != 0))))
1457 warning(_("values over 24 hours not handled by pre-2007 versions of zic"));
1458 	return oadd(sign * hh * SECSPERHOUR,
1459 		    sign * (mm * SECSPERMIN + ss));
1460 }
1461 
1462 static zic_t
1463 getsave(char *field, bool *isdst)
1464 {
1465   int dst = -1;
1466   zic_t save;
1467   size_t fieldlen = strlen(field);
1468   if (fieldlen != 0) {
1469     char *ep = field + fieldlen - 1;
1470     switch (*ep) {
1471       case 'd': dst = 1; *ep = '\0'; break;
1472       case 's': dst = 0; *ep = '\0'; break;
1473     }
1474   }
1475   save = gethms(field, _("invalid saved time"));
1476   *isdst = dst < 0 ? save != 0 : dst;
1477   return save;
1478 }
1479 
1480 static void
1481 inrule(char **fields, int nfields)
1482 {
1483 	struct rule r;
1484 
1485 	if (nfields != RULE_FIELDS) {
1486 		error(_("wrong number of fields on Rule line"));
1487 		return;
1488 	}
1489 	switch (*fields[RF_NAME]) {
1490 	  case '\0':
1491 	  case ' ': case '\f': case '\n': case '\r': case '\t': case '\v':
1492 	  case '+': case '-':
1493 	  case '0': case '1': case '2': case '3': case '4':
1494 	  case '5': case '6': case '7': case '8': case '9':
1495 		error(_("Invalid rule name \"%s\""), fields[RF_NAME]);
1496 		return;
1497 	}
1498 	r.r_filename = filename;
1499 	r.r_linenum = linenum;
1500 	r.r_save = getsave(fields[RF_SAVE], &r.r_isdst);
1501 	if (!rulesub(&r, fields[RF_LOYEAR], fields[RF_HIYEAR],
1502 		     fields[RF_COMMAND], fields[RF_MONTH], fields[RF_DAY],
1503 		     fields[RF_TOD]))
1504 	  return;
1505 	r.r_name = ecpyalloc(fields[RF_NAME]);
1506 	r.r_abbrvar = ecpyalloc(fields[RF_ABBRVAR]);
1507 	if (max_abbrvar_len < strlen(r.r_abbrvar))
1508 		max_abbrvar_len = strlen(r.r_abbrvar);
1509 	rules = growalloc(rules, sizeof *rules, nrules, &nrules_alloc);
1510 	rules[nrules++] = r;
1511 }
1512 
1513 static bool
1514 inzone(char **fields, int nfields)
1515 {
1516 	ptrdiff_t	i;
1517 
1518 	if (nfields < ZONE_MINFIELDS || nfields > ZONE_MAXFIELDS) {
1519 		error(_("wrong number of fields on Zone line"));
1520 		return false;
1521 	}
1522 	if (lcltime != NULL && strcmp(fields[ZF_NAME], tzdefault) == 0) {
1523 		error(
1524 _("\"Zone %s\" line and -l option are mutually exclusive"),
1525 			tzdefault);
1526 		return false;
1527 	}
1528 	if (strcmp(fields[ZF_NAME], TZDEFRULES) == 0 && psxrules != NULL) {
1529 		error(
1530 _("\"Zone %s\" line and -p option are mutually exclusive"),
1531 			TZDEFRULES);
1532 		return false;
1533 	}
1534 	for (i = 0; i < nzones; ++i)
1535 		if (zones[i].z_name != NULL &&
1536 		    strcmp(zones[i].z_name, fields[ZF_NAME]) == 0) {
1537 			error(_("duplicate zone name %s"
1538 				" (file \"%s\", line %"PRIdMAX")"),
1539 				fields[ZF_NAME],
1540 				zones[i].z_filename,
1541 				zones[i].z_linenum);
1542 			return false;
1543 		}
1544 	return inzsub(fields, nfields, false);
1545 }
1546 
1547 static bool
1548 inzcont(char **fields, int nfields)
1549 {
1550 	if (nfields < ZONEC_MINFIELDS || nfields > ZONEC_MAXFIELDS) {
1551 		error(_("wrong number of fields on Zone continuation line"));
1552 		return false;
1553 	}
1554 	return inzsub(fields, nfields, true);
1555 }
1556 
1557 static bool
1558 inzsub(char **fields, int nfields, bool iscont)
1559 {
1560 	char *		cp;
1561 	char *		cp1;
1562 	struct zone	z;
1563 	size_t format_len;
1564 	int		i_stdoff, i_rule, i_format;
1565 	int		i_untilyear, i_untilmonth;
1566 	int		i_untilday, i_untiltime;
1567 	bool		hasuntil;
1568 
1569 	if (iscont) {
1570 		i_stdoff = ZFC_STDOFF;
1571 		i_rule = ZFC_RULE;
1572 		i_format = ZFC_FORMAT;
1573 		i_untilyear = ZFC_TILYEAR;
1574 		i_untilmonth = ZFC_TILMONTH;
1575 		i_untilday = ZFC_TILDAY;
1576 		i_untiltime = ZFC_TILTIME;
1577 	} else if (!namecheck(fields[ZF_NAME]))
1578 		return false;
1579 	else {
1580 		i_stdoff = ZF_STDOFF;
1581 		i_rule = ZF_RULE;
1582 		i_format = ZF_FORMAT;
1583 		i_untilyear = ZF_TILYEAR;
1584 		i_untilmonth = ZF_TILMONTH;
1585 		i_untilday = ZF_TILDAY;
1586 		i_untiltime = ZF_TILTIME;
1587 	}
1588 	z.z_filename = filename;
1589 	z.z_linenum = linenum;
1590 	z.z_stdoff = gethms(fields[i_stdoff], _("invalid UT offset"));
1591 	if ((cp = strchr(fields[i_format], '%')) != 0) {
1592 		if ((*++cp != 's' && *cp != 'z') || strchr(cp, '%')
1593 		    || strchr(fields[i_format], '/')) {
1594 			error(_("invalid abbreviation format"));
1595 			return false;
1596 		}
1597 	}
1598 	z.z_format_specifier = cp ? *cp : '\0';
1599 	format_len = strlen(fields[i_format]);
1600 	if (max_format_len < format_len)
1601 	  max_format_len = format_len;
1602 	hasuntil = nfields > i_untilyear;
1603 	if (hasuntil) {
1604 		z.z_untilrule.r_filename = filename;
1605 		z.z_untilrule.r_linenum = linenum;
1606 		if (!rulesub(
1607 			&z.z_untilrule,
1608 			fields[i_untilyear],
1609 			"only",
1610 			"",
1611 			(nfields > i_untilmonth) ?
1612 			fields[i_untilmonth] : "Jan",
1613 			(nfields > i_untilday) ? fields[i_untilday] : "1",
1614 			(nfields > i_untiltime) ? fields[i_untiltime] : "0"))
1615 		  return false;
1616 		z.z_untiltime = rpytime(&z.z_untilrule,
1617 			z.z_untilrule.r_loyear);
1618 		if (iscont && nzones > 0 &&
1619 			z.z_untiltime > min_time &&
1620 			z.z_untiltime < max_time &&
1621 			zones[nzones - 1].z_untiltime > min_time &&
1622 			zones[nzones - 1].z_untiltime < max_time &&
1623 			zones[nzones - 1].z_untiltime >= z.z_untiltime) {
1624 				error(_(
1625 "Zone continuation line end time is not after end time of previous line"
1626 					));
1627 				return false;
1628 		}
1629 	}
1630 	z.z_name = iscont ? NULL : ecpyalloc(fields[ZF_NAME]);
1631 	z.z_rule = ecpyalloc(fields[i_rule]);
1632 	z.z_format = cp1 = ecpyalloc(fields[i_format]);
1633 	if (z.z_format_specifier == 'z') {
1634 	  cp1[cp - fields[i_format]] = 's';
1635 	  if (noise)
1636 	    warning(_("format '%s' not handled by pre-2015 versions of zic"),
1637 		    fields[i_format]);
1638 	}
1639 	zones = growalloc(zones, sizeof *zones, nzones, &nzones_alloc);
1640 	zones[nzones++] = z;
1641 	/*
1642 	** If there was an UNTIL field on this line,
1643 	** there's more information about the zone on the next line.
1644 	*/
1645 	return hasuntil;
1646 }
1647 
1648 static zic_t
1649 getleapdatetime(char **fields, int nfields, bool expire_line)
1650 {
1651 	const char *		cp;
1652 	const struct lookup *	lp;
1653 	zic_t			i, j;
1654 	zic_t			year;
1655 	int			month, day;
1656 	zic_t			dayoff, tod;
1657 	zic_t			t;
1658 	char			xs;
1659 
1660 	dayoff = 0;
1661 	cp = fields[LP_YEAR];
1662 	if (sscanf(cp, "%"SCNdZIC"%c", &year, &xs) != 1) {
1663 		/*
1664 		** Leapin' Lizards!
1665 		*/
1666 		error(_("invalid leaping year"));
1667 		return -1;
1668 	}
1669 	if (!expire_line) {
1670 	    if (!leapseen || leapmaxyear < year)
1671 		leapmaxyear = year;
1672 	    if (!leapseen || leapminyear > year)
1673 		leapminyear = year;
1674 	    leapseen = true;
1675 	}
1676 	j = EPOCH_YEAR;
1677 	while (j != year) {
1678 		if (year > j) {
1679 			i = len_years[isleap(j)];
1680 			++j;
1681 		} else {
1682 			--j;
1683 			i = -len_years[isleap(j)];
1684 		}
1685 		dayoff = oadd(dayoff, i);
1686 	}
1687 	if ((lp = byword(fields[LP_MONTH], mon_names)) == NULL) {
1688 		error(_("invalid month name"));
1689 		return -1;
1690 	}
1691 	month = lp->l_value;
1692 	j = TM_JANUARY;
1693 	while (j != month) {
1694 		i = len_months[isleap(year)][j];
1695 		dayoff = oadd(dayoff, i);
1696 		++j;
1697 	}
1698 	cp = fields[LP_DAY];
1699 	if (sscanf(cp, "%d%c", &day, &xs) != 1 ||
1700 		day <= 0 || day > len_months[isleap(year)][month]) {
1701 			error(_("invalid day of month"));
1702 			return -1;
1703 	}
1704 	dayoff = oadd(dayoff, day - 1);
1705 	if (dayoff < min_time / SECSPERDAY) {
1706 		error(_("time too small"));
1707 		return -1;
1708 	}
1709 	if (dayoff > max_time / SECSPERDAY) {
1710 		error(_("time too large"));
1711 		return -1;
1712 	}
1713 	t = dayoff * SECSPERDAY;
1714 	tod = gethms(fields[LP_TIME], _("invalid time of day"));
1715 	t = tadd(t, tod);
1716 	if (t < 0)
1717 	  error(_("leap second precedes Epoch"));
1718 	return t;
1719 }
1720 
1721 static void
1722 inleap(char **fields, int nfields)
1723 {
1724   if (nfields != LEAP_FIELDS)
1725     error(_("wrong number of fields on Leap line"));
1726   else {
1727     zic_t t = getleapdatetime(fields, nfields, false);
1728     if (0 <= t) {
1729       struct lookup const *lp = byword(fields[LP_ROLL], leap_types);
1730       if (!lp)
1731 	error(_("invalid Rolling/Stationary field on Leap line"));
1732       else {
1733 	int correction = 0;
1734 	if (!fields[LP_CORR][0]) /* infile() turns "-" into "".  */
1735 	  correction = -1;
1736 	else if (strcmp(fields[LP_CORR], "+") == 0)
1737 	  correction = 1;
1738 	else
1739 	  error(_("invalid CORRECTION field on Leap line"));
1740 	if (correction)
1741 	  leapadd(t, correction, lp->l_value);
1742       }
1743     }
1744   }
1745 }
1746 
1747 static void
1748 inexpires(char **fields, int nfields)
1749 {
1750   if (nfields != EXPIRES_FIELDS)
1751     error(_("wrong number of fields on Expires line"));
1752   else if (0 <= leapexpires)
1753     error(_("multiple Expires lines"));
1754   else
1755     leapexpires = getleapdatetime(fields, nfields, true);
1756 }
1757 
1758 static void
1759 inlink(char **fields, int nfields)
1760 {
1761 	struct link	l;
1762 
1763 	if (nfields != LINK_FIELDS) {
1764 		error(_("wrong number of fields on Link line"));
1765 		return;
1766 	}
1767 	if (*fields[LF_TARGET] == '\0') {
1768 		error(_("blank TARGET field on Link line"));
1769 		return;
1770 	}
1771 	if (! namecheck(fields[LF_LINKNAME]))
1772 	  return;
1773 	l.l_filename = filename;
1774 	l.l_linenum = linenum;
1775 	l.l_target = ecpyalloc(fields[LF_TARGET]);
1776 	l.l_linkname = ecpyalloc(fields[LF_LINKNAME]);
1777 	links = growalloc(links, sizeof *links, nlinks, &nlinks_alloc);
1778 	links[nlinks++] = l;
1779 }
1780 
1781 static bool
1782 rulesub(struct rule *rp, const char *loyearp, const char *hiyearp,
1783     const char *typep, const char *monthp, const char *dayp,
1784     const char *timep)
1785 {
1786 	const struct lookup *	lp;
1787 	const char *		cp;
1788 	char *			dp;
1789 	char *			ep;
1790 	char			xs;
1791 
1792 	if ((lp = byword(monthp, mon_names)) == NULL) {
1793 		error(_("invalid month name"));
1794 		return false;
1795 	}
1796 	rp->r_month = lp->l_value;
1797 	rp->r_todisstd = false;
1798 	rp->r_todisut = false;
1799 	dp = ecpyalloc(timep);
1800 	if (*dp != '\0') {
1801 		ep = dp + strlen(dp) - 1;
1802 		switch (lowerit(*ep)) {
1803 			case 's':	/* Standard */
1804 				rp->r_todisstd = true;
1805 				rp->r_todisut = false;
1806 				*ep = '\0';
1807 				break;
1808 			case 'w':	/* Wall */
1809 				rp->r_todisstd = false;
1810 				rp->r_todisut = false;
1811 				*ep = '\0';
1812 				break;
1813 			case 'g':	/* Greenwich */
1814 			case 'u':	/* Universal */
1815 			case 'z':	/* Zulu */
1816 				rp->r_todisstd = true;
1817 				rp->r_todisut = true;
1818 				*ep = '\0';
1819 				break;
1820 		}
1821 	}
1822 	rp->r_tod = gethms(dp, _("invalid time of day"));
1823 	free(dp);
1824 	/*
1825 	** Year work.
1826 	*/
1827 	cp = loyearp;
1828 	lp = byword(cp, begin_years);
1829 	rp->r_lowasnum = lp == NULL;
1830 	if (!rp->r_lowasnum) switch (lp->l_value) {
1831 		case YR_MINIMUM:
1832 			rp->r_loyear = ZIC_MIN;
1833 			break;
1834 		case YR_MAXIMUM:
1835 			rp->r_loyear = ZIC_MAX;
1836 			break;
1837 		default: UNREACHABLE();
1838 	} else if (sscanf(cp, "%"SCNdZIC"%c", &rp->r_loyear, &xs) != 1) {
1839 		error(_("invalid starting year"));
1840 		return false;
1841 	}
1842 	cp = hiyearp;
1843 	lp = byword(cp, end_years);
1844 	rp->r_hiwasnum = lp == NULL;
1845 	if (!rp->r_hiwasnum) switch (lp->l_value) {
1846 		case YR_MINIMUM:
1847 			rp->r_hiyear = ZIC_MIN;
1848 			break;
1849 		case YR_MAXIMUM:
1850 			rp->r_hiyear = ZIC_MAX;
1851 			break;
1852 		case YR_ONLY:
1853 			rp->r_hiyear = rp->r_loyear;
1854 			break;
1855 		default: UNREACHABLE();
1856 	} else if (sscanf(cp, "%"SCNdZIC"%c", &rp->r_hiyear, &xs) != 1) {
1857 		error(_("invalid ending year"));
1858 		return false;
1859 	}
1860 	if (rp->r_loyear > rp->r_hiyear) {
1861 		error(_("starting year greater than ending year"));
1862 		return false;
1863 	}
1864 	if (*typep != '\0') {
1865 		error(_("year type \"%s\" is unsupported; use \"-\" instead"),
1866 			typep);
1867 		return false;
1868 	}
1869 	/*
1870 	** Day work.
1871 	** Accept things such as:
1872 	**	1
1873 	**	lastSunday
1874 	**	last-Sunday (undocumented; warn about this)
1875 	**	Sun<=20
1876 	**	Sun>=7
1877 	*/
1878 	dp = ecpyalloc(dayp);
1879 	if ((lp = byword(dp, lasts)) != NULL) {
1880 		rp->r_dycode = DC_DOWLEQ;
1881 		rp->r_wday = lp->l_value;
1882 		rp->r_dayofmonth = len_months[1][rp->r_month];
1883 	} else {
1884 		if ((ep = strchr(dp, '<')) != 0)
1885 			rp->r_dycode = DC_DOWLEQ;
1886 		else if ((ep = strchr(dp, '>')) != 0)
1887 			rp->r_dycode = DC_DOWGEQ;
1888 		else {
1889 			ep = dp;
1890 			rp->r_dycode = DC_DOM;
1891 		}
1892 		if (rp->r_dycode != DC_DOM) {
1893 			*ep++ = 0;
1894 			if (*ep++ != '=') {
1895 				error(_("invalid day of month"));
1896 				free(dp);
1897 				return false;
1898 			}
1899 			if ((lp = byword(dp, wday_names)) == NULL) {
1900 				error(_("invalid weekday name"));
1901 				free(dp);
1902 				return false;
1903 			}
1904 			rp->r_wday = lp->l_value;
1905 		}
1906 		if (sscanf(ep, "%d%c", &rp->r_dayofmonth, &xs) != 1 ||
1907 			rp->r_dayofmonth <= 0 ||
1908 			(rp->r_dayofmonth > len_months[1][rp->r_month])) {
1909 				error(_("invalid day of month"));
1910 				free(dp);
1911 				return false;
1912 		}
1913 	}
1914 	free(dp);
1915 	return true;
1916 }
1917 
1918 static void
1919 convert(uint_fast32_t val, char *buf)
1920 {
1921 	int	i;
1922 	int	shift;
1923 	unsigned char *const b = (unsigned char *) buf;
1924 
1925 	for (i = 0, shift = 24; i < 4; ++i, shift -= 8)
1926 		b[i] = (val >> shift) & 0xff;
1927 }
1928 
1929 static void
1930 convert64(uint_fast64_t val, char *buf)
1931 {
1932 	int	i;
1933 	int	shift;
1934 	unsigned char *const b = (unsigned char *) buf;
1935 
1936 	for (i = 0, shift = 56; i < 8; ++i, shift -= 8)
1937 		b[i] = (val >> shift) & 0xff;
1938 }
1939 
1940 static void
1941 puttzcode(const int_fast32_t val, FILE *const fp)
1942 {
1943 	char	buf[4];
1944 
1945 	convert(val, buf);
1946 	fwrite(buf, sizeof buf, (size_t) 1, fp);
1947 }
1948 
1949 static void
1950 puttzcodepass(zic_t val, FILE *fp, int pass)
1951 {
1952   if (pass == 1)
1953     puttzcode(val, fp);
1954   else {
1955 	char	buf[8];
1956 
1957 	convert64(val, buf);
1958 	fwrite(buf, sizeof buf, (size_t) 1, fp);
1959     }
1960 }
1961 
1962 static int
1963 atcomp(const void *avp, const void *bvp)
1964 {
1965   struct attype const *ap = avp, *bp = bvp;
1966   zic_t a = ap->at, b = bp->at;
1967   return a < b ? -1 : a > b;
1968 }
1969 
1970 struct timerange {
1971   int defaulttype;
1972   ptrdiff_t base, count;
1973   int leapbase, leapcount;
1974   bool pretrans, leapexpiry;
1975 };
1976 
1977 static struct timerange
1978 limitrange(struct timerange r, bool locut, zic_t lo, zic_t hi,
1979 	   zic_t const *ats, unsigned char const *types)
1980 {
1981   /* Omit ordinary transitions < LO.  */
1982   while (0 < r.count && ats[r.base] < lo) {
1983     r.defaulttype = types[r.base];
1984     r.count--;
1985     r.base++;
1986   }
1987 
1988   /* "-00" before any -r low cutoff.  */
1989   if (min_time < lo_time)
1990     r.defaulttype = unspecifiedtype;
1991 
1992   /* Omit as many initial leap seconds as possible, such that the
1993      first leap second in the truncated list is <= LO, and is a
1994      positive leap second if and only if it has a positive correction.
1995      This supports common TZif readers that assume that the first leap
1996      second is positive if and only if its correction is positive.  */
1997   while (1 < r.leapcount && trans[r.leapbase + 1] <= lo) {
1998     r.leapcount--;
1999     r.leapbase++;
2000   }
2001   while (0 < r.leapbase
2002 	 && ((corr[r.leapbase - 1] < corr[r.leapbase])
2003 	     != (0 < corr[r.leapbase]))) {
2004     r.leapcount++;
2005     r.leapbase--;
2006   }
2007 
2008 
2009   /* Omit ordinary and leap second transitions greater than HI + 1.  */
2010   if (hi < max_time) {
2011     while (0 < r.count && hi + 1 < ats[r.base + r.count - 1])
2012       r.count--;
2013     while (0 < r.leapcount && hi + 1 < trans[r.leapbase + r.leapcount - 1])
2014       r.leapcount--;
2015   }
2016 
2017   /* Determine whether to keep the last too-low transition if no
2018      transition is exactly at LO.  The kept transition will be output
2019      as a LO "transition"; see "Output a LO_TIME transition" below.
2020      This is needed when the output is truncated at the start, and is
2021      also useful when catering to buggy 32-bit clients that do not use
2022      time type 0 for timestamps before the first transition.  */
2023   r.pretrans = locut && r.base && ! (r.count && ats[r.base] == lo);
2024 
2025   /* Determine whether to append an expiration to the leap second table.  */
2026   r.leapexpiry = 0 <= leapexpires && leapexpires - 1 <= hi;
2027 
2028   return r;
2029 }
2030 
2031 static void
2032 writezone(const char *const name, const char *const string, char version,
2033 	int defaulttype)
2034 {
2035 	FILE *			fp;
2036 	ptrdiff_t		i, j;
2037 	int			pass;
2038 	zic_t one = 1;
2039 	zic_t y2038_boundary = one << 31;
2040 	ptrdiff_t nats = timecnt + WORK_AROUND_QTBUG_53071;
2041 	char *tempname = NULL;
2042 	char const *outname = name;
2043 
2044 	/* Allocate the ATS and TYPES arrays via a single malloc,
2045 	   as this is a bit faster.  */
2046 	zic_t *ats = zic_malloc(align_to(size_product(nats, sizeof *ats + 1),
2047 				_Alignof(zic_t)));
2048 	void *typesptr = ats + nats;
2049 	unsigned char *types = typesptr;
2050 	struct timerange rangeall, range32, range64;
2051 
2052 	/*
2053 	** Sort.
2054 	*/
2055 	if (timecnt > 1)
2056 		qsort(attypes, (size_t) timecnt, sizeof *attypes, atcomp);
2057 	/*
2058 	** Optimize.
2059 	*/
2060 	{
2061 		ptrdiff_t fromi, toi;
2062 
2063 		toi = 0;
2064 		fromi = 0;
2065 		for ( ; fromi < timecnt; ++fromi) {
2066 			if (toi != 0
2067 			    && ((attypes[fromi].at
2068 				 + utoffs[attypes[toi - 1].type])
2069 				<= (attypes[toi - 1].at
2070 				    + utoffs[toi == 1 ? 0
2071 					     : attypes[toi - 2].type]))) {
2072 					attypes[toi - 1].type =
2073 						attypes[fromi].type;
2074 					continue;
2075 			}
2076 			if (toi == 0
2077 			    || attypes[fromi].dontmerge
2078 			    || (utoffs[attypes[toi - 1].type]
2079 				!= utoffs[attypes[fromi].type])
2080 			    || (isdsts[attypes[toi - 1].type]
2081 				!= isdsts[attypes[fromi].type])
2082 			    || (desigidx[attypes[toi - 1].type]
2083 				!= desigidx[attypes[fromi].type]))
2084 					attypes[toi++] = attypes[fromi];
2085 		}
2086 		timecnt = toi;
2087 	}
2088 
2089 	if (noise && timecnt > 1200) {
2090 	  if (timecnt > TZ_MAX_TIMES)
2091 		warning(_("reference clients mishandle"
2092 			  " more than %d transition times"),
2093 			TZ_MAX_TIMES);
2094 	  else
2095 		warning(_("pre-2014 clients may mishandle"
2096 			  " more than 1200 transition times"));
2097 	}
2098 	/*
2099 	** Transfer.
2100 	*/
2101 	for (i = 0; i < timecnt; ++i) {
2102 		ats[i] = attypes[i].at;
2103 		types[i] = attypes[i].type;
2104 	}
2105 
2106 	/*
2107 	** Correct for leap seconds.
2108 	*/
2109 	for (i = 0; i < timecnt; ++i) {
2110 		j = leapcnt;
2111 		while (--j >= 0)
2112 			if (ats[i] > trans[j] - corr[j]) {
2113 				ats[i] = tadd(ats[i], corr[j]);
2114 				break;
2115 			}
2116 	}
2117 
2118 	/* Work around QTBUG-53071 for timestamps less than y2038_boundary - 1,
2119 	   by inserting a no-op transition at time y2038_boundary - 1.
2120 	   This works only for timestamps before the boundary, which
2121 	   should be good enough in practice as QTBUG-53071 should be
2122 	   long-dead by 2038.  Do this after correcting for leap
2123 	   seconds, as the idea is to insert a transition just before
2124 	   32-bit time_t rolls around, and this occurs at a slightly
2125 	   different moment if transitions are leap-second corrected.  */
2126 	if (WORK_AROUND_QTBUG_53071 && timecnt != 0 && want_bloat()
2127 	    && ats[timecnt - 1] < y2038_boundary - 1 && strchr(string, '<')) {
2128 	  ats[timecnt] = y2038_boundary - 1;
2129 	  types[timecnt] = types[timecnt - 1];
2130 	  timecnt++;
2131 	}
2132 
2133 	rangeall.defaulttype = defaulttype;
2134 	rangeall.base = rangeall.leapbase = 0;
2135 	rangeall.count = timecnt;
2136 	rangeall.leapcount = leapcnt;
2137 	rangeall.pretrans = rangeall.leapexpiry = false;
2138 	range64 = limitrange(rangeall, min_time < lo_time,
2139 			     lo_time, hi_time, ats, types);
2140 	range32 = limitrange(range64, true,
2141 			     INT32_MIN, INT32_MAX, ats, types);
2142 
2143 	/* TZif version 4 is needed if a no-op transition is appended to
2144 	   indicate the expiration of the leap second table, or if the first
2145 	   leap second transition is not to a +1 or -1 correction.  */
2146 	for (pass = 1; pass <= 2; pass++) {
2147 	  struct timerange const *r = pass == 1 ? &range32 : &range64;
2148 	  if (pass == 1 && !want_bloat())
2149 	    continue;
2150 	  if (r->leapexpiry) {
2151 	    if (noise)
2152 	      warning(_("%s: pre-2021b clients may mishandle"
2153 			" leap second expiry"),
2154 		      name);
2155 	    version = '4';
2156 	  }
2157 	  if (0 < r->leapcount
2158 	      && corr[r->leapbase] != 1 && corr[r->leapbase] != -1) {
2159 	    if (noise)
2160 	      warning(_("%s: pre-2021b clients may mishandle"
2161 			" leap second table truncation"),
2162 		      name);
2163 	    version = '4';
2164 	  }
2165 	  if (version == '4')
2166 	    break;
2167  	}
2168 
2169 	fp = open_outfile(&outname, &tempname);
2170 
2171 	for (pass = 1; pass <= 2; ++pass) {
2172 		ptrdiff_t	thistimei, thistimecnt, thistimelim;
2173 		int	thisleapi, thisleapcnt, thisleaplim;
2174 		struct tzhead tzh;
2175 		int thisdefaulttype;
2176 		bool hicut, pretrans, thisleapexpiry;
2177 		zic_t lo;
2178 		int old0;
2179 		char		omittype[TZ_MAX_TYPES];
2180 		int		typemap[TZ_MAX_TYPES];
2181 		int		thistypecnt, stdcnt, utcnt;
2182 		char		thischars[TZ_MAX_CHARS];
2183 		int		thischarcnt;
2184 		bool		toomanytimes;
2185 		int		indmap[TZ_MAX_CHARS];
2186 
2187 		if (pass == 1) {
2188 			/* Arguably the default time type in the 32-bit data
2189 			   should be range32.defaulttype, which is suited for
2190 			   timestamps just before INT32_MIN.  However, zic
2191 			   traditionally used the time type of the indefinite
2192 			   past instead.  Internet RFC 8532 says readers should
2193 			   ignore 32-bit data, so this discrepancy matters only
2194 			   to obsolete readers where the traditional type might
2195 			   be more appropriate even if it's "wrong".  So, use
2196 			   the historical zic value, unless -r specifies a low
2197 			   cutoff that excludes some 32-bit timestamps.  */
2198 			thisdefaulttype = (lo_time <= INT32_MIN
2199 					   ? range64.defaulttype
2200 					   : range32.defaulttype);
2201 
2202 			thistimei = range32.base;
2203 			thistimecnt = range32.count;
2204 			toomanytimes = thistimecnt >> 31 >> 1 != 0;
2205 			thisleapi = range32.leapbase;
2206 			thisleapcnt = range32.leapcount;
2207 			pretrans = range32.pretrans;
2208 			thisleapexpiry = range32.leapexpiry;
2209 			hicut = hi_time < INT32_MAX;
2210 		} else {
2211 			thisdefaulttype = range64.defaulttype;
2212 			thistimei = range64.base;
2213 			thistimecnt = range64.count;
2214 			toomanytimes = thistimecnt >> 31 >> 31 >> 2 != 0;
2215 			thisleapi = range64.leapbase;
2216 			thisleapcnt = range64.leapcount;
2217 			pretrans = range64.pretrans;
2218 			thisleapexpiry = range64.leapexpiry;
2219 			hicut = hi_time < max_time;
2220 		}
2221 		if (toomanytimes)
2222 		  error(_("too many transition times"));
2223 
2224 		thistimelim = thistimei + thistimecnt;
2225 		memset(omittype, true, typecnt);
2226 		omittype[thisdefaulttype] = false;
2227 		for (i = thistimei - pretrans; i < thistimelim; i++)
2228 		  omittype[types[i]] = false;
2229 		if (hicut)
2230 		  omittype[unspecifiedtype] = false;
2231 
2232 		/* Reorder types to make THISDEFAULTTYPE type 0.
2233 		   Use TYPEMAP to swap OLD0 and THISDEFAULTTYPE so that
2234 		   THISDEFAULTTYPE appears as type 0 in the output instead
2235 		   of OLD0.  TYPEMAP also omits unused types.  */
2236 		old0 = strlen(omittype);
2237 
2238 #ifndef LEAVE_SOME_PRE_2011_SYSTEMS_IN_THE_LURCH
2239 		/*
2240 		** For some pre-2011 systems: if the last-to-be-written
2241 		** standard (or daylight) type has an offset different from the
2242 		** most recently used offset,
2243 		** append an (unused) copy of the most recently used type
2244 		** (to help get global "altzone" and "timezone" variables
2245 		** set correctly).
2246 		*/
2247 		if (want_bloat()) {
2248 			int	mrudst, mrustd, hidst, histd, type;
2249 
2250 			hidst = histd = mrudst = mrustd = -1;
2251 			for (i = thistimei - pretrans; i < thistimelim; ++i)
2252 				if (isdsts[types[i]])
2253 					mrudst = types[i];
2254 				else	mrustd = types[i];
2255 			for (i = old0; i < typecnt; i++) {
2256 			  int h = (i == old0 ? thisdefaulttype
2257 				   : i == thisdefaulttype ? old0 : i);
2258 			  if (!omittype[h]) {
2259 			    if (isdsts[h])
2260 			      hidst = i;
2261 			    else
2262 			      histd = i;
2263 			  }
2264 			}
2265 			if (hidst >= 0 && mrudst >= 0 && hidst != mrudst &&
2266 				utoffs[hidst] != utoffs[mrudst]) {
2267 					isdsts[mrudst] = -1;
2268 					type = addtype(utoffs[mrudst],
2269 						&chars[desigidx[mrudst]],
2270 						true,
2271 						ttisstds[mrudst],
2272 						ttisuts[mrudst]);
2273 					isdsts[mrudst] = 1;
2274 					omittype[type] = false;
2275 			}
2276 			if (histd >= 0 && mrustd >= 0 && histd != mrustd &&
2277 				utoffs[histd] != utoffs[mrustd]) {
2278 					isdsts[mrustd] = -1;
2279 					type = addtype(utoffs[mrustd],
2280 						&chars[desigidx[mrustd]],
2281 						false,
2282 						ttisstds[mrustd],
2283 						ttisuts[mrustd]);
2284 					isdsts[mrustd] = 0;
2285 					omittype[type] = false;
2286 			}
2287 		}
2288 #endif /* !defined LEAVE_SOME_PRE_2011_SYSTEMS_IN_THE_LURCH */
2289  		thistypecnt = 0;
2290 		for (i = old0; i < typecnt; i++)
2291 		  if (!omittype[i])
2292 		    typemap[i == old0 ? thisdefaulttype
2293 			    : i == thisdefaulttype ? old0 : i]
2294 		      = thistypecnt++;
2295 
2296 		for (i = 0; i < (int)(sizeof indmap / sizeof indmap[0]); ++i)
2297 			indmap[i] = -1;
2298 		thischarcnt = stdcnt = utcnt = 0;
2299 		for (i = old0; i < typecnt; i++) {
2300 			char *	thisabbr;
2301 
2302 			if (omittype[i])
2303 				continue;
2304 			if (ttisstds[i])
2305 			  stdcnt = thistypecnt;
2306 			if (ttisuts[i])
2307 			  utcnt = thistypecnt;
2308 			if (indmap[desigidx[i]] >= 0)
2309 				continue;
2310 			thisabbr = &chars[desigidx[i]];
2311 			for (j = 0; j < thischarcnt; ++j)
2312 				if (strcmp(&thischars[j], thisabbr) == 0)
2313 					break;
2314 			if (j == thischarcnt) {
2315 				strcpy(&thischars[thischarcnt], thisabbr);
2316 				thischarcnt += strlen(thisabbr) + 1;
2317 			}
2318 			indmap[desigidx[i]] = j;
2319 		}
2320 		if (pass == 1 && !want_bloat()) {
2321 		  pretrans = hicut = thisleapexpiry = false;
2322 		  thistimecnt = thisleapcnt = 0;
2323 		  thistypecnt = thischarcnt = 1;
2324 		}
2325 #define DO(field)	fwrite(tzh.field, sizeof tzh.field, (size_t) 1, fp)
2326 		memset(&tzh, 0, sizeof(tzh));
2327 		memcpy(tzh.tzh_magic, TZ_MAGIC, sizeof tzh.tzh_magic);
2328 		tzh.tzh_version[0] = version;
2329 		convert(utcnt, tzh.tzh_ttisutcnt);
2330 		convert(stdcnt, tzh.tzh_ttisstdcnt);
2331 		convert(thisleapcnt + thisleapexpiry, tzh.tzh_leapcnt);
2332 		convert(pretrans + thistimecnt + hicut, tzh.tzh_timecnt);
2333 		convert(thistypecnt, tzh.tzh_typecnt);
2334 		convert(thischarcnt, tzh.tzh_charcnt);
2335 		DO(tzh_magic);
2336 		DO(tzh_version);
2337 		DO(tzh_reserved);
2338 		DO(tzh_ttisutcnt);
2339 		DO(tzh_ttisstdcnt);
2340 		DO(tzh_leapcnt);
2341 		DO(tzh_timecnt);
2342 		DO(tzh_typecnt);
2343 		DO(tzh_charcnt);
2344 #undef DO
2345 		if (pass == 1 && !want_bloat()) {
2346 		  /* Output a minimal data block with just one time type.  */
2347 		  puttzcode(0, fp);	/* utoff */
2348 		  putc(0, fp);		/* dst */
2349 		  putc(0, fp);		/* index of abbreviation */
2350 		  putc(0, fp);		/* empty-string abbreviation */
2351 		  continue;
2352 		}
2353 
2354 		/* Output a LO_TIME transition if needed; see limitrange.
2355 		   But do not go below the minimum representable value
2356 		   for this pass.  */
2357 		lo = pass == 1 && lo_time < INT32_MIN ? INT32_MIN : lo_time;
2358 
2359 		if (pretrans)
2360 		  puttzcodepass(lo, fp, pass);
2361 		for (i = thistimei; i < thistimelim; ++i) {
2362 		  puttzcodepass(ats[i], fp, pass);
2363 		}
2364 		if (hicut)
2365 		  puttzcodepass(hi_time + 1, fp, pass);
2366 		for (i = thistimei - pretrans; i < thistimelim; ++i)
2367 		  putc(typemap[types[i]], fp);
2368 		if (hicut)
2369 		  putc(typemap[unspecifiedtype], fp);
2370 
2371 		for (i = old0; i < typecnt; i++) {
2372 		  int h = (i == old0 ? thisdefaulttype
2373 			   : i == thisdefaulttype ? old0 : i);
2374 		  if (!omittype[h]) {
2375 		    puttzcode(utoffs[h], fp);
2376 		    putc(isdsts[h], fp);
2377 		    putc(indmap[desigidx[h]], fp);
2378 		  }
2379 		}
2380 		if (thischarcnt != 0)
2381 			fwrite(thischars, sizeof thischars[0],
2382 				(size_t) thischarcnt, fp);
2383 		thisleaplim = thisleapi + thisleapcnt;
2384 		for (i = thisleapi; i < thisleaplim; ++i) {
2385 			zic_t	todo;
2386 
2387 			if (roll[i]) {
2388 				if (timecnt == 0 || trans[i] < ats[0]) {
2389 					j = 0;
2390 					while (isdsts[j])
2391 						if (++j >= typecnt) {
2392 							j = 0;
2393 							break;
2394 						}
2395 				} else {
2396 					j = 1;
2397 					while (j < timecnt &&
2398 						trans[i] >= ats[j])
2399 							++j;
2400 					j = types[j - 1];
2401 				}
2402 				todo = tadd(trans[i], -utoffs[j]);
2403 			} else	todo = trans[i];
2404 			puttzcodepass(todo, fp, pass);
2405 			puttzcode(corr[i], fp);
2406 		}
2407 		if (thisleapexpiry) {
2408 		  /* Append a no-op leap correction indicating when the leap
2409 		     second table expires.  Although this does not conform to
2410 		     Internet RFC 8536, most clients seem to accept this and
2411 		     the plan is to amend the RFC to allow this in version 4
2412 		     TZif files.  */
2413 		  puttzcodepass(leapexpires, fp, pass);
2414 		  puttzcode(thisleaplim ? corr[thisleaplim - 1] : 0, fp);
2415 		}
2416 		if (stdcnt != 0)
2417 		  for (i = old0; i < typecnt; i++)
2418 			if (!omittype[i])
2419 				putc(ttisstds[i], fp);
2420 		if (utcnt != 0)
2421 		  for (i = old0; i < typecnt; i++)
2422 			if (!omittype[i])
2423 				putc(ttisuts[i], fp);
2424 	}
2425 	fprintf(fp, "\n%s\n", string);
2426 	close_file(fp, directory, name, tempname);
2427 	rename_dest(tempname, name);
2428 	free(ats);
2429 }
2430 
2431 static char const *
2432 abbroffset(char *buf, zic_t offset)
2433 {
2434 	char sign = '+';
2435 	int seconds, minutes;
2436 
2437 	if (offset < 0) {
2438 		offset = -offset;
2439 		sign = '-';
2440 	}
2441 
2442 	seconds = offset % SECSPERMIN;
2443 	offset /= SECSPERMIN;
2444 	minutes = offset % MINSPERHOUR;
2445 	offset /= MINSPERHOUR;
2446 	if (100 <= offset) {
2447 		error(_("%%z UT offset magnitude exceeds 99:59:59"));
2448 		return "%z";
2449 	} else {
2450 		char *p = buf;
2451 		*p++ = sign;
2452 		*p++ = '0' + offset / 10;
2453 		*p++ = '0' + offset % 10;
2454 		if (minutes | seconds) {
2455 			*p++ = '0' + minutes / 10;
2456 			*p++ = '0' + minutes % 10;
2457 			if (seconds) {
2458 				*p++ = '0' + seconds / 10;
2459 				*p++ = '0' + seconds % 10;
2460 			}
2461 		}
2462 		*p = '\0';
2463 		return buf;
2464 	}
2465 }
2466 
2467 static size_t
2468 doabbr(char *abbr, size_t abbrlen, struct zone const *zp, const char *letters,
2469     bool isdst, zic_t save, bool doquotes)
2470 {
2471 	char *	cp;
2472 	char *	slashp;
2473 	size_t	len;
2474 	char const *format = zp->z_format;
2475 
2476 	slashp = strchr(format, '/');
2477 	if (slashp == NULL) {
2478 		char letterbuf[PERCENT_Z_LEN_BOUND + 1];
2479 		if (zp->z_format_specifier == 'z')
2480 			letters = abbroffset(letterbuf, zp->z_stdoff + save);
2481 		else if (!letters)
2482 			letters = "%s";
2483 		snprintf(abbr, abbrlen, format, letters);
2484 	} else if (isdst) {
2485 		strlcpy(abbr, slashp + 1, abbrlen);
2486 	} else {
2487 		memcpy(abbr, format, slashp - format);
2488 		abbr[slashp - format] = '\0';
2489 	}
2490 	len = strlen(abbr);
2491 	if (!doquotes)
2492 		return len;
2493 	for (cp = abbr; is_alpha(*cp); cp++)
2494 		continue;
2495 	if (len > 0 && *cp == '\0')
2496 		return len;
2497 	abbr[len + 2] = '\0';
2498 	abbr[len + 1] = '>';
2499 	memmove(abbr + 1, abbr, len);
2500 	abbr[0] = '<';
2501 	return len + 2;
2502 }
2503 
2504 static void
2505 updateminmax(const zic_t x)
2506 {
2507 	if (min_year > x)
2508 		min_year = x;
2509 	if (max_year < x)
2510 		max_year = x;
2511 }
2512 
2513 static int
2514 stringoffset(char *result, int resultlen, zic_t offset)
2515 {
2516 	int	hours;
2517 	int	minutes;
2518 	int	seconds;
2519 	bool negative = offset < 0;
2520 	int len = negative;
2521 
2522 	if (negative) {
2523 		offset = -offset;
2524 		result[0] = '-';
2525 	}
2526 	seconds = offset % SECSPERMIN;
2527 	offset /= SECSPERMIN;
2528 	minutes = offset % MINSPERHOUR;
2529 	offset /= MINSPERHOUR;
2530 	hours = offset;
2531 	if (hours >= HOURSPERDAY * DAYSPERWEEK) {
2532 		result[0] = '\0';
2533 		return 0;
2534 	}
2535 	len += snprintf(result + len, resultlen - len, "%d", hours);
2536 	if (minutes != 0 || seconds != 0) {
2537 		len += snprintf(result + len, resultlen - len,
2538 		    ":%02d", minutes);
2539 		if (seconds != 0)
2540 			len += snprintf(result + len, resultlen - len,
2541 			    ":%02d", seconds);
2542 	}
2543 	return len;
2544 }
2545 
2546 static int
2547 stringrule(char *result, int resultlen, struct rule *const rp, zic_t save, const zic_t stdoff)
2548 {
2549 	zic_t	tod = rp->r_tod;
2550 	int	compat = 0, len = 0;
2551 
2552 	if (rp->r_dycode == DC_DOM) {
2553 		int	month, total;
2554 
2555 		if (rp->r_dayofmonth == 29 && rp->r_month == TM_FEBRUARY)
2556 			return -1;
2557 		total = 0;
2558 		for (month = 0; month < rp->r_month; ++month)
2559 			total += len_months[0][month];
2560 		/* Omit the "J" in Jan and Feb, as that's shorter.  */
2561 		if (rp->r_month <= 1)
2562 		  len += snprintf(result + len, resultlen - len, "%d", total + rp->r_dayofmonth - 1);
2563 		else
2564 		  len += snprintf(result + len, resultlen - len, "J%d", total + rp->r_dayofmonth);
2565 	} else {
2566 		int	week;
2567 		int	wday = rp->r_wday;
2568 		int	wdayoff;
2569 
2570 		if (rp->r_dycode == DC_DOWGEQ) {
2571 			wdayoff = (rp->r_dayofmonth - 1) % DAYSPERWEEK;
2572 			if (wdayoff)
2573 				compat = 2013;
2574 			wday -= wdayoff;
2575 			tod += wdayoff * SECSPERDAY;
2576 			week = 1 + (rp->r_dayofmonth - 1) / DAYSPERWEEK;
2577 		} else if (rp->r_dycode == DC_DOWLEQ) {
2578 			if (rp->r_dayofmonth == len_months[1][rp->r_month])
2579 				week = 5;
2580 			else {
2581 				wdayoff = rp->r_dayofmonth % DAYSPERWEEK;
2582 				if (wdayoff)
2583 					compat = 2013;
2584 				wday -= wdayoff;
2585 				tod += wdayoff * SECSPERDAY;
2586 				week = rp->r_dayofmonth / DAYSPERWEEK;
2587 			}
2588 		} else	return -1;	/* "cannot happen" */
2589 		if (wday < 0)
2590 			wday += DAYSPERWEEK;
2591 		len += snprintf(result + len, resultlen - len, "M%d.%d.%d",
2592 				  rp->r_month + 1, week, wday);
2593 	}
2594 	if (rp->r_todisut)
2595 	  tod += stdoff;
2596 	if (rp->r_todisstd && !rp->r_isdst)
2597 	  tod += save;
2598 	if (tod != 2 * SECSPERMIN * MINSPERHOUR) {
2599 		if (len + 1 < resultlen)
2600 		    result[len++] = '/';
2601 		if (! stringoffset(result + len, resultlen - len, tod))
2602 			return -1;
2603 		if (tod < 0) {
2604 			if (compat < 2013)
2605 				compat = 2013;
2606 		} else if (SECSPERDAY <= tod) {
2607 			if (compat < 1994)
2608 				compat = 1994;
2609 		}
2610 	}
2611 	return compat;
2612 }
2613 
2614 static int
2615 rule_cmp(struct rule const *a, struct rule const *b)
2616 {
2617 	if (!a)
2618 		return -!!b;
2619 	if (!b)
2620 		return 1;
2621 	if (a->r_hiyear != b->r_hiyear)
2622 		return a->r_hiyear < b->r_hiyear ? -1 : 1;
2623 	if (a->r_hiyear == ZIC_MAX)
2624 		return 0;
2625 	if (a->r_month - b->r_month != 0)
2626 		return a->r_month - b->r_month;
2627 	return a->r_dayofmonth - b->r_dayofmonth;
2628 }
2629 
2630 static int
2631 stringzone(char *result, int resultlen, const struct zone *const zpfirst,
2632     const int zonecount)
2633 {
2634 	const struct zone *	zp;
2635 	struct rule *		rp;
2636 	struct rule *		stdrp;
2637 	struct rule *		dstrp;
2638 	ptrdiff_t	i;
2639 	int			compat = 0;
2640 	int			c;
2641 	size_t			len;
2642 	int			offsetlen;
2643 	struct rule		stdr, dstr;
2644 	int dstcmp;
2645 	struct rule *lastrp[2] = { NULL, NULL };
2646 	struct zone zstr[2];
2647 	struct zone const *stdzp;
2648 	struct zone const *dstzp;
2649 
2650 	result[0] = '\0';
2651 
2652 	/* Internet RFC 8536 section 5.1 says to use an empty TZ string if
2653 	   future timestamps are truncated.  */
2654 	if (hi_time < max_time)
2655 	  return -1;
2656 
2657 	zp = zpfirst + zonecount - 1;
2658 	for (i = 0; i < zp->z_nrules; ++i) {
2659 		struct rule **last;
2660 		int cmp;
2661 		rp = &zp->z_rules[i];
2662 		last = &lastrp[rp->r_isdst];
2663 		cmp = rule_cmp(*last, rp);
2664 		if (cmp < 0)
2665 		  *last = rp;
2666 		else if (cmp == 0)
2667 		  return -1;
2668 	}
2669 	stdrp = lastrp[false];
2670 	dstrp = lastrp[true];
2671 	dstcmp = zp->z_nrules ? rule_cmp(dstrp, stdrp) : zp->z_isdst ? 1 : -1;
2672 	stdzp = dstzp = zp;
2673 
2674 	if (dstcmp < 0) {
2675 	  /* Standard time all year.  */
2676 	  dstrp = NULL;
2677 	} else if (0 < dstcmp) {
2678 	  /* DST all year.  Use an abbreviation like
2679 	     "XXX3EDT4,0/0,J365/23" for EDT (-04) all year.  */
2680 	  zic_t save = dstrp ? dstrp->r_save : zp->z_save;
2681 	  if (0 <= save)
2682 	    {
2683 	      /* Positive DST, the typical case for all-year DST.
2684 		 Fake a timezone with negative DST.  */
2685 	      stdzp = &zstr[0];
2686 	      dstzp = &zstr[1];
2687 	      zstr[0].z_stdoff = zp->z_stdoff + 2 * save;
2688 	      zstr[0].z_format = "XXX";  /* Any 3 letters will do.  */
2689 	      zstr[0].z_format_specifier = 0;
2690 	      zstr[1].z_stdoff = zstr[0].z_stdoff;
2691 	      zstr[1].z_format = zp->z_format;
2692 	      zstr[1].z_format_specifier = zp->z_format_specifier;
2693 	    }
2694 	  dstr.r_month = TM_JANUARY;
2695 	  dstr.r_dycode = DC_DOM;
2696 	  dstr.r_dayofmonth = 1;
2697 	  dstr.r_tod = 0;
2698 	  dstr.r_todisstd = dstr.r_todisut = false;
2699 	  dstr.r_isdst = true;
2700 	  dstr.r_save = save < 0 ? save : -save;
2701 	  dstr.r_abbrvar = dstrp ? dstrp->r_abbrvar : NULL;
2702 	  stdr.r_month = TM_DECEMBER;
2703 	  stdr.r_dycode = DC_DOM;
2704 	  stdr.r_dayofmonth = 31;
2705 	  stdr.r_tod = SECSPERDAY + dstr.r_save;
2706 	  stdr.r_todisstd = stdr.r_todisut = false;
2707 	  stdr.r_isdst = false;
2708 	  stdr.r_save = 0;
2709 	  stdr.r_abbrvar = save < 0 && stdrp ? stdrp->r_abbrvar : NULL;
2710 	  dstrp = &dstr;
2711 	  stdrp = &stdr;
2712 	}
2713 	len = doabbr(result, resultlen, stdzp, stdrp ? stdrp->r_abbrvar : NULL,
2714 		     false, 0, true);
2715 	offsetlen = stringoffset(result + len, resultlen - len,
2716 	    -stdzp->z_stdoff);
2717 	if (! offsetlen) {
2718 		result[0] = '\0';
2719 		return -1;
2720 	}
2721 	len += offsetlen;
2722 	if (dstrp == NULL)
2723 		return compat;
2724 	len += doabbr(result + len, resultlen - len, dstzp, dstrp->r_abbrvar,
2725 		      dstrp->r_isdst, dstrp->r_save, true);
2726 	if (dstrp->r_save != SECSPERMIN * MINSPERHOUR) {
2727 		offsetlen = stringoffset(result + len, resultlen - len,
2728 				   - (dstzp->z_stdoff + dstrp->r_save));
2729 		if (! offsetlen) {
2730 			result[0] = '\0';
2731 			return -1;
2732 		}
2733 		len += offsetlen;
2734 	}
2735 	result[len++] = ',';
2736 	c = stringrule(result + len, resultlen - len, dstrp, dstrp->r_save, stdzp->z_stdoff);
2737 	if (c < 0) {
2738 		result[0] = '\0';
2739 		return -1;
2740 	}
2741 	if (compat < c)
2742 		compat = c;
2743 	len += strlen(result + len);
2744 	result[len++] = ',';
2745 	c = stringrule(result + len, resultlen - len, stdrp, dstrp->r_save, stdzp->z_stdoff);
2746 	if (c < 0) {
2747 		result[0] = '\0';
2748 		return -1;
2749 	}
2750 	if (compat < c)
2751 		compat = c;
2752 	return compat;
2753 }
2754 
2755 static void
2756 outzone(const struct zone *zpfirst, ptrdiff_t zonecount)
2757 {
2758 	const struct zone *	zp;
2759 	struct rule *		rp;
2760 	ptrdiff_t		i, j;
2761 	bool			usestart, useuntil;
2762 	zic_t			starttime, untiltime;
2763 	zic_t			stdoff;
2764 	zic_t			save;
2765 	zic_t			year;
2766 	zic_t			startoff;
2767 	bool			startttisstd;
2768 	bool			startttisut;
2769 	int			type;
2770 	char *			startbuf;
2771 	char *			ab;
2772 	char *			envvar;
2773 	size_t			max_abbr_len;
2774 	size_t			max_envvar_len;
2775 	bool			prodstic; /* all rules are min to max */
2776 	int			compat;
2777 	bool			do_extend;
2778 	char			version;
2779 	ptrdiff_t lastatmax = -1;
2780 	zic_t one = 1;
2781 	zic_t y2038_boundary = one << 31;
2782 	zic_t max_year0;
2783 	int defaulttype = -1;
2784 
2785 	check_for_signal();
2786 
2787 	max_abbr_len = 2 + max_format_len + max_abbrvar_len;
2788 	max_envvar_len = 2 * max_abbr_len + 5 * 9;
2789 	startbuf = zic_malloc(max_abbr_len + 1);
2790 	ab = zic_malloc(max_abbr_len + 1);
2791 	envvar = zic_malloc(max_envvar_len + 1);
2792 	INITIALIZE(untiltime);
2793 	INITIALIZE(starttime);
2794 	/*
2795 	** Now. . .finally. . .generate some useful data!
2796 	*/
2797 	timecnt = 0;
2798 	typecnt = 0;
2799 	charcnt = 0;
2800 	prodstic = zonecount == 1;
2801 	/*
2802 	** Thanks to Earl Chew
2803 	** for noting the need to unconditionally initialize startttisstd.
2804 	*/
2805 	startttisstd = false;
2806 	startttisut = false;
2807 	min_year = max_year = EPOCH_YEAR;
2808 	if (leapseen) {
2809 		updateminmax(leapminyear);
2810 		updateminmax(leapmaxyear + (leapmaxyear < ZIC_MAX));
2811 	}
2812 	for (i = 0; i < zonecount; ++i) {
2813 		zp = &zpfirst[i];
2814 		if (i < zonecount - 1)
2815 			updateminmax(zp->z_untilrule.r_loyear);
2816 		for (j = 0; j < zp->z_nrules; ++j) {
2817 			rp = &zp->z_rules[j];
2818 			if (rp->r_lowasnum)
2819 				updateminmax(rp->r_loyear);
2820 			if (rp->r_hiwasnum)
2821 				updateminmax(rp->r_hiyear);
2822 			if (rp->r_lowasnum || rp->r_hiwasnum)
2823 				prodstic = false;
2824 		}
2825 	}
2826 	/*
2827 	** Generate lots of data if a rule can't cover all future times.
2828 	*/
2829 	compat = stringzone(envvar, max_envvar_len + 1, zpfirst, zonecount);
2830 	version = compat < 2013 ? '2' : '3';
2831 	do_extend = compat < 0;
2832 	if (noise) {
2833 		if (!*envvar)
2834 			warning("%s %s",
2835 				_("no POSIX environment variable for zone"),
2836 				zpfirst->z_name);
2837 		else if (compat != 0) {
2838 			/* Circa-COMPAT clients, and earlier clients, might
2839 			   not work for this zone when given dates before
2840 			   1970 or after 2038.  */
2841 			warning(_("%s: pre-%d clients may mishandle"
2842 				  " distant timestamps"),
2843 				zpfirst->z_name, compat);
2844 		}
2845 	}
2846 	if (do_extend) {
2847 		/*
2848 		** Search through a couple of extra years past the obvious
2849 		** 400, to avoid edge cases.  For example, suppose a non-POSIX
2850 		** rule applies from 2012 onwards and has transitions in March
2851 		** and September, plus some one-off transitions in November
2852 		** 2013.  If zic looked only at the last 400 years, it would
2853 		** set max_year=2413, with the intent that the 400 years 2014
2854 		** through 2413 will be repeated.  The last transition listed
2855 		** in the tzfile would be in 2413-09, less than 400 years
2856 		** after the last one-off transition in 2013-11.  Two years
2857 		** might be overkill, but with the kind of edge cases
2858 		** available we're not sure that one year would suffice.
2859 		*/
2860 		enum { years_of_observations = YEARSPERREPEAT + 2 };
2861 
2862 		if (min_year >= ZIC_MIN + years_of_observations)
2863 			min_year -= years_of_observations;
2864 		else	min_year = ZIC_MIN;
2865 		if (max_year <= ZIC_MAX - years_of_observations)
2866 			max_year += years_of_observations;
2867 		else	max_year = ZIC_MAX;
2868 		/*
2869 		** Regardless of any of the above,
2870 		** for a "proDSTic" zone which specifies that its rules
2871 		** always have and always will be in effect,
2872 		** we only need one cycle to define the zone.
2873 		*/
2874 		if (prodstic) {
2875 			min_year = 1900;
2876 			max_year = min_year + years_of_observations;
2877 		}
2878 	}
2879 	max_year0 = max_year;
2880 	if (want_bloat()) {
2881 	  /* For the benefit of older systems,
2882 	     generate data from 1900 through 2038.  */
2883 	  if (min_year > 1900)
2884 		min_year = 1900;
2885 	  if (max_year < 2038)
2886 		max_year = 2038;
2887 	}
2888 
2889 	if (min_time < lo_time || hi_time < max_time)
2890 	  unspecifiedtype = addtype(0, "-00", false, false, false);
2891 
2892 	for (i = 0; i < zonecount; ++i) {
2893 		struct rule *prevrp = NULL;
2894 		zic_t prevktime;
2895 		INITIALIZE(prevktime);
2896 		/*
2897 		** A guess that may well be corrected later.
2898 		*/
2899 		save = 0;
2900 		zp = &zpfirst[i];
2901 		usestart = i > 0 && (zp - 1)->z_untiltime > min_time;
2902 		useuntil = i < (zonecount - 1);
2903 		if (useuntil && zp->z_untiltime <= min_time)
2904 			continue;
2905 		stdoff = zp->z_stdoff;
2906 		eat(zp->z_filename, zp->z_linenum);
2907 		*startbuf = '\0';
2908 		startoff = zp->z_stdoff;
2909 		if (zp->z_nrules == 0) {
2910 			save = zp->z_save;
2911 			doabbr(startbuf, max_abbr_len + 1,
2912 			    zp, NULL, zp->z_isdst, save, false);
2913 			type = addtype(oadd(zp->z_stdoff, save),
2914 				startbuf, zp->z_isdst, startttisstd,
2915 				startttisut);
2916 			if (usestart) {
2917 				addtt(starttime, type);
2918 				usestart = false;
2919 			} else
2920 				defaulttype = type;
2921 		} else for (year = min_year; year <= max_year; ++year) {
2922 			if (useuntil && year > zp->z_untilrule.r_hiyear)
2923 				break;
2924 			/*
2925 			** Mark which rules to do in the current year.
2926 			** For those to do, calculate rpytime(rp, year);
2927 			** The former TYPE field was also considered here.
2928 			*/
2929 			for (j = 0; j < zp->z_nrules; ++j) {
2930 				rp = &zp->z_rules[j];
2931 				eats(zp->z_filename, zp->z_linenum,
2932 					rp->r_filename, rp->r_linenum);
2933 				rp->r_todo = year >= rp->r_loyear &&
2934 						year <= rp->r_hiyear;
2935 				if (rp->r_todo) {
2936 					rp->r_temp = rpytime(rp, year);
2937 					rp->r_todo
2938 					  = (rp->r_temp < y2038_boundary
2939 					     || year <= max_year0);
2940 				}
2941 			}
2942 			for ( ; ; ) {
2943 				ptrdiff_t	k;
2944 				zic_t	jtime, ktime;
2945 				zic_t	offset;
2946 
2947 				INITIALIZE(ktime);
2948 				if (useuntil) {
2949 					/*
2950 					** Turn untiltime into UT
2951 					** assuming the current stdoff and
2952 					** save values.
2953 					*/
2954 					untiltime = zp->z_untiltime;
2955 					if (!zp->z_untilrule.r_todisut)
2956 						untiltime = tadd(untiltime,
2957 								 -stdoff);
2958 					if (!zp->z_untilrule.r_todisstd)
2959 						untiltime = tadd(untiltime,
2960 								 -save);
2961 				}
2962 				/*
2963 				** Find the rule (of those to do, if any)
2964 				** that takes effect earliest in the year.
2965 				*/
2966 				k = -1;
2967 				for (j = 0; j < zp->z_nrules; ++j) {
2968 					rp = &zp->z_rules[j];
2969 					if (!rp->r_todo)
2970 						continue;
2971 					eats(zp->z_filename, zp->z_linenum,
2972 						rp->r_filename, rp->r_linenum);
2973 					offset = rp->r_todisut ? 0 : stdoff;
2974 					if (!rp->r_todisstd)
2975 						offset = oadd(offset, save);
2976 					jtime = rp->r_temp;
2977 					if (jtime == min_time ||
2978 						jtime == max_time)
2979 							continue;
2980 					jtime = tadd(jtime, -offset);
2981 					if (k < 0 || jtime < ktime) {
2982 						k = j;
2983 						ktime = jtime;
2984 					} else if (jtime == ktime) {
2985 					  char const *dup_rules_msg =
2986 					    _("two rules for same instant");
2987 					  eats(zp->z_filename, zp->z_linenum,
2988 					       rp->r_filename, rp->r_linenum);
2989 					  warning("%s", dup_rules_msg);
2990 					  rp = &zp->z_rules[k];
2991 					  eats(zp->z_filename, zp->z_linenum,
2992 					       rp->r_filename, rp->r_linenum);
2993 					  error("%s", dup_rules_msg);
2994 					}
2995 				}
2996 				if (k < 0)
2997 					break;	/* go on to next year */
2998 				rp = &zp->z_rules[k];
2999 				rp->r_todo = false;
3000 				if (useuntil && ktime >= untiltime)
3001 					break;
3002 				save = rp->r_save;
3003 				if (usestart && ktime == starttime)
3004 					usestart = false;
3005 				if (usestart) {
3006 					if (ktime < starttime) {
3007 						startoff = oadd(zp->z_stdoff,
3008 								save);
3009 						doabbr(startbuf,
3010 							max_abbr_len + 1,
3011 							zp,
3012 							rp->r_abbrvar,
3013 							rp->r_isdst,
3014 							rp->r_save,
3015 							false);
3016 						continue;
3017 					}
3018 					if (*startbuf == '\0'
3019 					    && startoff == oadd(zp->z_stdoff,
3020 								save)) {
3021 							doabbr(startbuf,
3022 								max_abbr_len + 1,
3023 								zp,
3024 								rp->r_abbrvar,
3025 								rp->r_isdst,
3026 								rp->r_save,
3027 								false);
3028 					}
3029 				}
3030 				eats(zp->z_filename, zp->z_linenum,
3031 					rp->r_filename, rp->r_linenum);
3032 				doabbr(ab, max_abbr_len + 1, zp, rp->r_abbrvar,
3033 				       rp->r_isdst, rp->r_save, false);
3034 				offset = oadd(zp->z_stdoff, rp->r_save);
3035 				if (!want_bloat() && !useuntil && !do_extend
3036 				    && prevrp && lo_time <= prevktime
3037 				    && rp->r_hiyear == ZIC_MAX
3038 				    && prevrp->r_hiyear == ZIC_MAX)
3039 				  break;
3040 				type = addtype(offset, ab, rp->r_isdst,
3041 					rp->r_todisstd, rp->r_todisut);
3042 				if (defaulttype < 0 && !rp->r_isdst)
3043 				  defaulttype = type;
3044 				if (rp->r_hiyear == ZIC_MAX
3045 				    && ! (0 <= lastatmax
3046 					  && ktime < attypes[lastatmax].at))
3047 				  lastatmax = timecnt;
3048 				addtt(ktime, type);
3049 				prevrp = rp;
3050 				prevktime = ktime;
3051 			}
3052 		}
3053 		if (usestart) {
3054 			if (*startbuf == '\0' &&
3055 				zp->z_format != NULL &&
3056 				strchr(zp->z_format, '%') == NULL &&
3057 				strchr(zp->z_format, '/') == NULL)
3058 					strncpy(startbuf, zp->z_format,
3059 					    max_abbr_len + 1 - 1);
3060 			eat(zp->z_filename, zp->z_linenum);
3061 			if (*startbuf == '\0')
3062 error(_("can't determine time zone abbreviation to use just after until time"));
3063 			else {
3064 			  bool isdst = startoff != zp->z_stdoff;
3065 			  type = addtype(startoff, startbuf, isdst,
3066 					 startttisstd, startttisut);
3067 			  if (defaulttype < 0 && !isdst)
3068 			    defaulttype = type;
3069 			  addtt(starttime, type);
3070 			}
3071 		}
3072 		/*
3073 		** Now we may get to set starttime for the next zone line.
3074 		*/
3075 		if (useuntil) {
3076 			startttisstd = zp->z_untilrule.r_todisstd;
3077 			startttisut = zp->z_untilrule.r_todisut;
3078 			starttime = zp->z_untiltime;
3079 			if (!startttisstd)
3080 			  starttime = tadd(starttime, -save);
3081 			if (!startttisut)
3082 			  starttime = tadd(starttime, -stdoff);
3083 		}
3084 	}
3085 	if (defaulttype < 0)
3086 	  defaulttype = 0;
3087 	if (0 <= lastatmax)
3088 	  attypes[lastatmax].dontmerge = true;
3089 	if (do_extend) {
3090 		/*
3091 		** If we're extending the explicitly listed observations
3092 		** for 400 years because we can't fill the POSIX-TZ field,
3093 		** check whether we actually ended up explicitly listing
3094 		** observations through that period.  If there aren't any
3095 		** near the end of the 400-year period, add a redundant
3096 		** one at the end of the final year, to make it clear
3097 		** that we are claiming to have definite knowledge of
3098 		** the lack of transitions up to that point.
3099 		*/
3100 		struct rule xr;
3101 		struct attype *lastat;
3102 		memset(&xr, 0, sizeof(xr));
3103 		xr.r_month = TM_JANUARY;
3104 		xr.r_dycode = DC_DOM;
3105 		xr.r_dayofmonth = 1;
3106 		xr.r_tod = 0;
3107 		for (lastat = attypes, i = 1; i < timecnt; i++)
3108 			if (attypes[i].at > lastat->at)
3109 				lastat = &attypes[i];
3110 		if (!lastat || lastat->at < rpytime(&xr, max_year - 1)) {
3111 			addtt(rpytime(&xr, max_year + 1),
3112 			      lastat ? lastat->type : defaulttype);
3113 			attypes[timecnt - 1].dontmerge = true;
3114 		}
3115 	}
3116 	writezone(zpfirst->z_name, envvar, version, defaulttype);
3117 	free(startbuf);
3118 	free(ab);
3119 	free(envvar);
3120 }
3121 
3122 static void
3123 addtt(zic_t starttime, int type)
3124 {
3125 	attypes = growalloc(attypes, sizeof *attypes, timecnt, &timecnt_alloc);
3126 	attypes[timecnt].at = starttime;
3127 	attypes[timecnt].dontmerge = false;
3128 	attypes[timecnt].type = type;
3129 	++timecnt;
3130 }
3131 
3132 static int
3133 addtype(zic_t utoff, char const *abbr, bool isdst, bool ttisstd, bool ttisut)
3134 {
3135 	int	i, j;
3136 
3137 	if (! (-1L - 2147483647L <= utoff && utoff <= 2147483647L)) {
3138 		error(_("UT offset out of range"));
3139 		exit(EXIT_FAILURE);
3140 	}
3141 	if (!want_bloat())
3142 	  ttisstd = ttisut = false;
3143 
3144 	for (j = 0; j < charcnt; ++j)
3145 		if (strcmp(&chars[j], abbr) == 0)
3146 			break;
3147 	if (j == charcnt)
3148 		newabbr(abbr);
3149 	else {
3150 	  /* If there's already an entry, return its index.  */
3151 	  for (i = 0; i < typecnt; i++)
3152 	    if (utoff == utoffs[i] && isdst == isdsts[i] && j == desigidx[i]
3153 		&& ttisstd == ttisstds[i] && ttisut == ttisuts[i])
3154 	      return i;
3155 	}
3156 	/*
3157 	** There isn't one; add a new one, unless there are already too
3158 	** many.
3159 	*/
3160 	if (typecnt >= TZ_MAX_TYPES) {
3161 		error(_("too many local time types"));
3162 		exit(EXIT_FAILURE);
3163 	}
3164 	i = typecnt++;
3165 	utoffs[i] = utoff;
3166 	isdsts[i] = isdst;
3167 	ttisstds[i] = ttisstd;
3168 	ttisuts[i] = ttisut;
3169 	desigidx[i] = j;
3170 	return i;
3171 }
3172 
3173 static void
3174 leapadd(zic_t t, int correction, int rolling)
3175 {
3176 	int	i;
3177 
3178 	if (TZ_MAX_LEAPS <= leapcnt) {
3179 		error(_("too many leap seconds"));
3180 		exit(EXIT_FAILURE);
3181 	}
3182 	if (rolling && (lo_time != min_time || hi_time != max_time)) {
3183 	  error(_("Rolling leap seconds not supported with -r"));
3184 	  exit(EXIT_FAILURE);
3185 	}
3186 	for (i = 0; i < leapcnt; ++i)
3187 		if (t <= trans[i])
3188 			break;
3189 	memmove(&trans[i + 1], &trans[i], (leapcnt - i) * sizeof *trans);
3190 	memmove(&corr[i + 1], &corr[i], (leapcnt - i) * sizeof *corr);
3191 	memmove(&roll[i + 1], &roll[i], (leapcnt - i) * sizeof *roll);
3192 	trans[i] = t;
3193 	corr[i] = correction;
3194 	roll[i] = rolling;
3195 	++leapcnt;
3196 }
3197 
3198 static void
3199 adjleap(void)
3200 {
3201 	int	i;
3202 	zic_t	last = 0;
3203 	zic_t	prevtrans = 0;
3204 
3205 	/*
3206 	** propagate leap seconds forward
3207 	*/
3208 	for (i = 0; i < leapcnt; ++i) {
3209 		if (trans[i] - prevtrans < 28 * SECSPERDAY) {
3210 			error(_("Leap seconds too close together"));
3211 			exit(EXIT_FAILURE);
3212 		}
3213 		prevtrans = trans[i];
3214 		trans[i] = tadd(trans[i], last);
3215 		last = corr[i] += last;
3216 	}
3217 
3218 	if (0 <= leapexpires) {
3219 	  leapexpires = oadd(leapexpires, last);
3220 	  if (! (leapcnt == 0 || (trans[leapcnt - 1] < leapexpires))) {
3221 	    error(_("last Leap time does not precede Expires time"));
3222 	    exit(EXIT_FAILURE);
3223 	  }
3224 	}
3225 }
3226 
3227 /* Is A a space character in the C locale?  */
3228 static bool
3229 is_space(char a)
3230 {
3231 	switch (a) {
3232 	  default:
3233 		return false;
3234 	  case ' ': case '\f': case '\n': case '\r': case '\t': case '\v':
3235 	  	return true;
3236 	}
3237 }
3238 
3239 /* Is A an alphabetic character in the C locale?  */
3240 static bool
3241 is_alpha(char a)
3242 {
3243 	switch (a) {
3244 	  default:
3245 		return false;
3246 	  case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G':
3247 	  case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N':
3248 	  case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U':
3249 	  case 'V': case 'W': case 'X': case 'Y': case 'Z':
3250 	  case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g':
3251 	  case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n':
3252 	  case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u':
3253 	  case 'v': case 'w': case 'x': case 'y': case 'z':
3254 		return true;
3255 	}
3256 }
3257 
3258 /* If A is an uppercase character in the C locale, return its lowercase
3259    counterpart.  Otherwise, return A.  */
3260 static char
3261 lowerit(char a)
3262 {
3263 	switch (a) {
3264 	  default: return a;
3265 	  case 'A': return 'a'; case 'B': return 'b'; case 'C': return 'c';
3266 	  case 'D': return 'd'; case 'E': return 'e'; case 'F': return 'f';
3267 	  case 'G': return 'g'; case 'H': return 'h'; case 'I': return 'i';
3268 	  case 'J': return 'j'; case 'K': return 'k'; case 'L': return 'l';
3269 	  case 'M': return 'm'; case 'N': return 'n'; case 'O': return 'o';
3270 	  case 'P': return 'p'; case 'Q': return 'q'; case 'R': return 'r';
3271 	  case 'S': return 's'; case 'T': return 't'; case 'U': return 'u';
3272 	  case 'V': return 'v'; case 'W': return 'w'; case 'X': return 'x';
3273 	  case 'Y': return 'y'; case 'Z': return 'z';
3274 	}
3275 }
3276 
3277 /* case-insensitive equality */
3278 static ATTRIBUTE_PURE bool
3279 ciequal(const char *ap, const char *bp)
3280 {
3281 	while (lowerit(*ap) == lowerit(*bp++))
3282 		if (*ap++ == '\0')
3283 			return true;
3284 	return false;
3285 }
3286 
3287 static ATTRIBUTE_PURE bool
3288 itsabbr(const char *abbr, const char *word)
3289 {
3290 	if (lowerit(*abbr) != lowerit(*word))
3291 		return false;
3292 	++word;
3293 	while (*++abbr != '\0')
3294 		do {
3295 			if (*word == '\0')
3296 				return false;
3297 		} while (lowerit(*word++) != lowerit(*abbr));
3298 	return true;
3299 }
3300 
3301 /* Return true if ABBR is an initial prefix of WORD, ignoring ASCII case.  */
3302 
3303 static ATTRIBUTE_PURE bool
3304 ciprefix(char const *abbr, char const *word)
3305 {
3306   do
3307     if (!*abbr)
3308       return true;
3309   while (lowerit(*abbr++) == lowerit(*word++));
3310 
3311   return false;
3312 }
3313 
3314 static const struct lookup *
3315 byword(const char *word, const struct lookup *table)
3316 {
3317 	const struct lookup *	foundlp;
3318 	const struct lookup *	lp;
3319 
3320 	if (word == NULL || table == NULL)
3321 		return NULL;
3322 
3323 	/* If TABLE is LASTS and the word starts with "last" followed
3324 	   by a non-'-', skip the "last" and look in WDAY_NAMES instead.
3325 	   Warn about any usage of the undocumented prefix "last-".  */
3326 	if (table == lasts && ciprefix("last", word) && word[4]) {
3327 	  if (word[4] == '-')
3328 	    warning(_("\"%s\" is undocumented; use \"last%s\" instead"),
3329 		    word, word + 5);
3330 	  else {
3331 	    word += 4;
3332 	    table = wday_names;
3333 	  }
3334 	}
3335 
3336 	/*
3337 	** Look for exact match.
3338 	*/
3339 	for (lp = table; lp->l_word != NULL; ++lp)
3340 		if (ciequal(word, lp->l_word))
3341 			return lp;
3342 	/*
3343 	** Look for inexact match.
3344 	*/
3345 	foundlp = NULL;
3346 	for (lp = table; lp->l_word != NULL; ++lp)
3347 		if (ciprefix(word, lp->l_word)) {
3348 			if (foundlp == NULL)
3349 				foundlp = lp;
3350 			else	return NULL;	/* multiple inexact matches */
3351 		}
3352 
3353 	if (foundlp && noise) {
3354 	  /* Warn about any backward-compatibility issue with pre-2017c zic.  */
3355 	  bool pre_2017c_match = false;
3356 	  for (lp = table; lp->l_word; lp++)
3357 	    if (itsabbr(word, lp->l_word)) {
3358 	      if (pre_2017c_match) {
3359 		warning(_("\"%s\" is ambiguous in pre-2017c zic"), word);
3360 		break;
3361 	      }
3362 	      pre_2017c_match = true;
3363 	    }
3364 	}
3365 
3366 	return foundlp;
3367 }
3368 
3369 static char **
3370 getfields(char *cp)
3371 {
3372 	char *	dp;
3373 	char **	array;
3374 	int	nsubs;
3375 
3376 	if (cp == NULL)
3377 		return NULL;
3378 	array = zic_malloc(size_product(strlen(cp) + 1, sizeof *array));
3379 	nsubs = 0;
3380 	for ( ; ; ) {
3381 		while (is_space(*cp))
3382 				++cp;
3383 		if (*cp == '\0' || *cp == '#')
3384 			break;
3385 		array[nsubs++] = dp = cp;
3386 		do {
3387 			if ((*dp = *cp++) != '"')
3388 				++dp;
3389 			else while ((*dp = *cp++) != '"')
3390 				if (*dp != '\0')
3391 					++dp;
3392 				else {
3393 				  error(_("Odd number of quotation marks"));
3394 				  exit(EXIT_FAILURE);
3395 				}
3396 		} while (*cp && *cp != '#' && !is_space(*cp));
3397 		if (is_space(*cp))
3398 			++cp;
3399 		*dp = '\0';
3400 	}
3401 	array[nsubs] = NULL;
3402 	return array;
3403 }
3404 
3405 static _Noreturn void
3406 time_overflow(void)
3407 {
3408 	error(_("time overflow"));
3409 	exit(EXIT_FAILURE);
3410 }
3411 
3412 static ATTRIBUTE_PURE zic_t
3413 oadd(zic_t t1, zic_t t2)
3414 {
3415 	if (t1 < 0 ? t2 < ZIC_MIN - t1 : ZIC_MAX - t1 < t2)
3416 		time_overflow();
3417 	return t1 + t2;
3418 }
3419 
3420 static ATTRIBUTE_PURE zic_t
3421 tadd(zic_t t1, zic_t t2)
3422 {
3423 	if (t1 < 0) {
3424 		if (t2 < min_time - t1) {
3425 			if (t1 != min_time)
3426 				time_overflow();
3427 			return min_time;
3428 		}
3429 	} else {
3430 		if (max_time - t1 < t2) {
3431 			if (t1 != max_time)
3432 				time_overflow();
3433 			return max_time;
3434 		}
3435 	}
3436 	return t1 + t2;
3437 }
3438 
3439 /*
3440 ** Given a rule, and a year, compute the date (in seconds since January 1,
3441 ** 1970, 00:00 LOCAL time) in that year that the rule refers to.
3442 */
3443 
3444 static zic_t
3445 rpytime(const struct rule *rp, zic_t wantedy)
3446 {
3447 	int	m, i;
3448 	zic_t	dayoff;			/* with a nod to Margaret O. */
3449 	zic_t	t, y;
3450 	int yrem;
3451 
3452 	if (wantedy == ZIC_MIN)
3453 		return min_time;
3454 	if (wantedy == ZIC_MAX)
3455 		return max_time;
3456 	m = TM_JANUARY;
3457 	y = EPOCH_YEAR;
3458 
3459 	/* dayoff = floor((wantedy - y) / YEARSPERREPEAT) * DAYSPERREPEAT,
3460 	   sans overflow.  */
3461 	yrem = wantedy % YEARSPERREPEAT - y % YEARSPERREPEAT;
3462 	dayoff = ((wantedy / YEARSPERREPEAT - y / YEARSPERREPEAT
3463 		   + yrem / YEARSPERREPEAT - (yrem % YEARSPERREPEAT < 0))
3464 		  * DAYSPERREPEAT);
3465 	/* wantedy = y + ((wantedy - y) mod YEARSPERREPEAT), sans overflow.  */
3466 	wantedy = y + (yrem + 2 * YEARSPERREPEAT) % YEARSPERREPEAT;
3467 
3468 	while (wantedy != y) {
3469 		i = len_years[isleap(y)];
3470 		dayoff = oadd(dayoff, i);
3471 		y++;
3472 	}
3473 	while (m != rp->r_month) {
3474 		i = len_months[isleap(y)][m];
3475 		dayoff = oadd(dayoff, i);
3476 		++m;
3477 	}
3478 	i = rp->r_dayofmonth;
3479 	if (m == TM_FEBRUARY && i == 29 && !isleap(y)) {
3480 		if (rp->r_dycode == DC_DOWLEQ)
3481 			--i;
3482 		else {
3483 			error(_("use of 2/29 in non leap-year"));
3484 			exit(EXIT_FAILURE);
3485 		}
3486 	}
3487 	--i;
3488 	dayoff = oadd(dayoff, i);
3489 	if (rp->r_dycode == DC_DOWGEQ || rp->r_dycode == DC_DOWLEQ) {
3490 		/*
3491 		** Don't trust mod of negative numbers.
3492 		*/
3493 		zic_t wday = ((EPOCH_WDAY + dayoff % DAYSPERWEEK + DAYSPERWEEK)
3494 			      % DAYSPERWEEK);
3495 		while (wday != rp->r_wday)
3496 			if (rp->r_dycode == DC_DOWGEQ) {
3497 				dayoff = oadd(dayoff, (zic_t) 1);
3498 				if (++wday >= DAYSPERWEEK)
3499 					wday = 0;
3500 				++i;
3501 			} else {
3502 				dayoff = oadd(dayoff, (zic_t) -1);
3503 				if (--wday < 0)
3504 					wday = DAYSPERWEEK - 1;
3505 				--i;
3506 			}
3507 		if (i < 0 || i >= len_months[isleap(y)][m]) {
3508 			if (noise)
3509 				warning(_("rule goes past start/end of month; \
3510 will not work with pre-2004 versions of zic"));
3511 		}
3512 	}
3513 	if (dayoff < min_time / SECSPERDAY)
3514 		return min_time;
3515 	if (dayoff > max_time / SECSPERDAY)
3516 		return max_time;
3517 	t = (zic_t) dayoff * SECSPERDAY;
3518 	return tadd(t, rp->r_tod);
3519 }
3520 
3521 static void
3522 newabbr(const char *string)
3523 {
3524 	int	i;
3525 
3526 	if (strcmp(string, GRANDPARENTED) != 0) {
3527 		const char *	cp;
3528 		const char *	mp;
3529 
3530 		cp = string;
3531 		mp = NULL;
3532 		while (is_alpha(*cp) || ('0' <= *cp && *cp <= '9')
3533 		       || *cp == '-' || *cp == '+')
3534 				++cp;
3535 		if (noise && cp - string < 3)
3536 		  mp = _("time zone abbreviation has fewer than 3 characters");
3537 		if (cp - string > ZIC_MAX_ABBR_LEN_WO_WARN)
3538 		  mp = _("time zone abbreviation has too many characters");
3539 		if (*cp != '\0')
3540 mp = _("time zone abbreviation differs from POSIX standard");
3541 		if (mp != NULL)
3542 			warning("%s (%s)", mp, string);
3543 	}
3544 	i = strlen(string) + 1;
3545 	if (charcnt + i > TZ_MAX_CHARS) {
3546 		error(_("too many, or too long, time zone abbreviations"));
3547 		exit(EXIT_FAILURE);
3548 	}
3549 	strncpy(&chars[charcnt], string, sizeof(chars) - charcnt - 1);
3550 	charcnt += i;
3551 }
3552 
3553 /* Ensure that the directories of ARGNAME exist, by making any missing
3554    ones.  If ANCESTORS, do this only for ARGNAME's ancestors; otherwise,
3555    do it for ARGNAME too.  Exit with failure if there is trouble.
3556    Do not consider an existing file to be trouble.  */
3557 static void
3558 mkdirs(char const *argname, bool ancestors)
3559 {
3560 	char *	name;
3561 	char *	cp;
3562 
3563 	cp = name = ecpyalloc(argname);
3564 
3565 	/* On MS-Windows systems, do not worry about drive letters or
3566 	   backslashes, as this should suffice in practice.  Time zone
3567 	   names do not use drive letters and backslashes.  If the -d
3568 	   option of zic does not name an already-existing directory,
3569 	   it can use slashes to separate the already-existing
3570 	   ancestor prefix from the to-be-created subdirectories.  */
3571 
3572 	/* Do not mkdir a root directory, as it must exist.  */
3573 	while (*cp == '/')
3574 	  cp++;
3575 
3576 	while (cp && ((cp = strchr(cp, '/')) || !ancestors)) {
3577 		if (cp)
3578 		  *cp = '\0';
3579 		/*
3580 		** Try to create it.  It's OK if creation fails because
3581 		** the directory already exists, perhaps because some
3582 		** other process just created it.  For simplicity do
3583 		** not check first whether it already exists, as that
3584 		** is checked anyway if the mkdir fails.
3585 		*/
3586 		if (mkdir(name, MKDIR_UMASK) != 0) {
3587 			/* Do not report an error if err == EEXIST, because
3588 			   some other process might have made the directory
3589 			   in the meantime.  Likewise for ENOSYS, because
3590 			   Solaris 10 mkdir fails with ENOSYS if the
3591 			   directory is an automounted mount point.  */
3592 			int err = errno;
3593 			if (err != EEXIST && err != ENOSYS) {
3594 				error(_("%s: Can't create directory %s: %s"),
3595 				      progname, name, strerror(err));
3596 				exit(EXIT_FAILURE);
3597 			}
3598 		}
3599 		if (cp)
3600 		  *cp++ = '/';
3601 	}
3602 	free(name);
3603 }
3604