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