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