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