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