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