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