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