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