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