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