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