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