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