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