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