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