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