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