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