xref: /netbsd-src/lib/libc/time/zic.c (revision f3cfa6f6ce31685c6c4a758bc430e69eb99f50a4)
1 /*	$NetBSD: zic.c,v 1.74 2019/04/04 18:18:31 christos Exp $	*/
2 /*
3 ** This file is in the public domain, so clarified as of
4 ** 2006-07-17 by Arthur David Olson.
5 */
6 
7 #if HAVE_NBTOOL_CONFIG_H
8 #include "nbtool_config.h"
9 #endif
10 
11 #include <sys/cdefs.h>
12 #ifndef lint
13 __RCSID("$NetBSD: zic.c,v 1.74 2019/04/04 18:18:31 christos Exp $");
14 #endif /* !defined lint */
15 
16 #include "private.h"
17 #include "tzfile.h"
18 
19 #include <fcntl.h>
20 #include <locale.h>
21 #include <stdarg.h>
22 #include <stddef.h>
23 #include <stdio.h>
24 #include <unistd.h>
25 #include <util.h>
26 
27 #define	ZIC_VERSION_PRE_2013 '2'
28 #define	ZIC_VERSION	'3'
29 
30 typedef int_fast64_t	zic_t;
31 #define ZIC_MIN INT_FAST64_MIN
32 #define ZIC_MAX INT_FAST64_MAX
33 #define PRIdZIC PRIdFAST64
34 #define SCNdZIC SCNdFAST64
35 
36 #ifndef ZIC_MAX_ABBR_LEN_WO_WARN
37 #define ZIC_MAX_ABBR_LEN_WO_WARN	6
38 #endif /* !defined ZIC_MAX_ABBR_LEN_WO_WARN */
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 #if HAVE_SYS_STAT_H
48 #include <sys/stat.h>
49 #endif
50 #ifdef S_IRUSR
51 #define MKDIR_UMASK (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)
52 #else
53 #define MKDIR_UMASK 0755
54 #endif
55 /* Port to native MS-Windows and to ancient UNIX.  */
56 #if !defined S_ISDIR && defined S_IFDIR && defined S_IFMT
57 # define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
58 #endif
59 
60 #if HAVE_SYS_WAIT_H
61 #include <sys/wait.h>	/* for WIFEXITED and WEXITSTATUS */
62 #endif /* HAVE_SYS_WAIT_H */
63 
64 #ifndef WIFEXITED
65 #define WIFEXITED(status)	(((status) & 0xff) == 0)
66 #endif /* !defined WIFEXITED */
67 #ifndef WEXITSTATUS
68 #define WEXITSTATUS(status)	(((status) >> 8) & 0xff)
69 #endif /* !defined WEXITSTATUS */
70 
71 /* The maximum ptrdiff_t value, for pre-C99 platforms.  */
72 #ifndef PTRDIFF_MAX
73 static ptrdiff_t const PTRDIFF_MAX = MAXVAL(ptrdiff_t, TYPE_BIT(ptrdiff_t));
74 #endif
75 
76 /* The minimum alignment of a type, for pre-C11 platforms.  */
77 #if __STDC_VERSION__ < 201112
78 # define _Alignof(type) offsetof(struct { char a; type b; }, b)
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 	const char *	r_filename;
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 	const char *	r_yrtype;
94 	bool		r_lowasnum;
95 	bool		r_hiwasnum;
96 
97 	int		r_month;	/* 0..11 */
98 
99 	int		r_dycode;	/* see below */
100 	int		r_dayofmonth;
101 	int		r_wday;
102 
103 	zic_t		r_tod;		/* time from midnight */
104 	bool		r_todisstd;	/* above is standard time if 1 */
105 					/* or wall clock time if 0 */
106 	bool		r_todisgmt;	/* above is GMT if 1 */
107 					/* or local time if 0 */
108 	bool		r_isdst;	/* is this daylight saving time? */
109 	zic_t		r_stdoff;	/* offset from default time (which is
110 					   usually standard time) */
111 	const char *	r_abbrvar;	/* variable part of abbreviation */
112 
113 	bool		r_todo;		/* a rule to do (used in outzone) */
114 	zic_t		r_temp;		/* used in outzone */
115 };
116 
117 /*
118 **	r_dycode		r_dayofmonth	r_wday
119 */
120 
121 #define DC_DOM		0	/* 1..31 */	/* unused */
122 #define DC_DOWGEQ	1	/* 1..31 */	/* 0..6 (Sun..Sat) */
123 #define DC_DOWLEQ	2	/* 1..31 */	/* 0..6 (Sun..Sat) */
124 
125 struct zone {
126 	const char *	z_filename;
127 	lineno		z_linenum;
128 
129 	const char *	z_name;
130 	zic_t		z_gmtoff;
131 	char *		z_rule;
132 	const char *	z_format;
133 	char		z_format_specifier;
134 
135 	bool		z_isdst;
136 	zic_t		z_stdoff;
137 
138 	struct rule *	z_rules;
139 	ptrdiff_t	z_nrules;
140 
141 	struct rule	z_untilrule;
142 	zic_t		z_untiltime;
143 };
144 
145 #if !HAVE_POSIX_DECLS
146 extern int	getopt(int argc, char * const argv[],
147 			const char * options);
148 extern int	link(const char * fromname, const char * toname);
149 extern char *	optarg;
150 extern int	optind;
151 #endif
152 
153 #if ! HAVE_LINK
154 # define link(from, to) (errno = ENOTSUP, -1)
155 #endif
156 #if ! HAVE_SYMLINK
157 # define readlink(file, buf, size) (errno = ENOTSUP, -1)
158 # define symlink(from, to) (errno = ENOTSUP, -1)
159 # define S_ISLNK(m) 0
160 #endif
161 #ifndef AT_SYMLINK_FOLLOW
162 # define linkat(fromdir, from, todir, to, flag) \
163     (itssymlink(from) ? (errno = ENOTSUP, -1) : link(from, to))
164 #endif
165 
166 static void	addtt(zic_t starttime, int type);
167 static int	addtype(zic_t, char const *, bool, bool, bool);
168 static void	leapadd(zic_t, bool, int, int);
169 static void	adjleap(void);
170 static void	associate(void);
171 static void	dolink(const char *, const char *, bool);
172 static char **	getfields(char * buf);
173 static zic_t	gethms(const char * string, const char * errstring);
174 static zic_t	getstdoff(char *, bool *);
175 static void	infile(const char * filename);
176 static void	inleap(char ** fields, int nfields);
177 static void	inlink(char ** fields, int nfields);
178 static void	inrule(char ** fields, int nfields);
179 static bool	inzcont(char ** fields, int nfields);
180 static bool	inzone(char ** fields, int nfields);
181 static bool	inzsub(char **, int, bool);
182 static bool	itsdir(char const *);
183 static bool	itssymlink(char const *);
184 static bool	is_alpha(char a);
185 static char	lowerit(char);
186 static void	mkdirs(char const *, bool);
187 static void	newabbr(const char * abbr);
188 static zic_t	oadd(zic_t t1, zic_t t2);
189 static void	outzone(const struct zone * zp, ptrdiff_t ntzones);
190 static zic_t	rpytime(const struct rule * rp, zic_t wantedy);
191 static void	rulesub(struct rule * rp,
192 			const char * loyearp, const char * hiyearp,
193 			const char * typep, const char * monthp,
194 			const char * dayp, const char * timep);
195 static zic_t	tadd(zic_t t1, zic_t t2);
196 static bool	yearistype(zic_t year, const char * type);
197 
198 /* Bound on length of what %z can expand to.  */
199 enum { PERCENT_Z_LEN_BOUND = sizeof "+995959" - 1 };
200 
201 /* If true, work around a bug in Qt 5.6.1 and earlier, which mishandles
202    TZif files whose POSIX-TZ-style strings contain '<'; see
203    QTBUG-53071 <https://bugreports.qt.io/browse/QTBUG-53071>.  This
204    workaround will no longer be needed when Qt 5.6.1 and earlier are
205    obsolete, say in the year 2021.  */
206 #ifndef WORK_AROUND_QTBUG_53071
207 enum { WORK_AROUND_QTBUG_53071 = true };
208 #endif
209 
210 static int		charcnt;
211 static bool		errors;
212 static bool		warnings;
213 static const char *	filename;
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 size_t		max_format_len;
221 static zic_t		max_year;
222 static zic_t		min_year;
223 static bool		noise;
224 static const char *	rfilename;
225 static lineno		rlinenum;
226 static const char *	progname;
227 static ptrdiff_t	timecnt;
228 static ptrdiff_t	timecnt_alloc;
229 static int		typecnt;
230 
231 /*
232 ** Line codes.
233 */
234 
235 #define LC_RULE		0
236 #define LC_ZONE		1
237 #define LC_LINK		2
238 #define LC_LEAP		3
239 
240 /*
241 ** Which fields are which on a Zone line.
242 */
243 
244 #define ZF_NAME		1
245 #define ZF_GMTOFF	2
246 #define ZF_RULE		3
247 #define ZF_FORMAT	4
248 #define ZF_TILYEAR	5
249 #define ZF_TILMONTH	6
250 #define ZF_TILDAY	7
251 #define ZF_TILTIME	8
252 #define ZONE_MINFIELDS	5
253 #define ZONE_MAXFIELDS	9
254 
255 /*
256 ** Which fields are which on a Zone continuation line.
257 */
258 
259 #define ZFC_GMTOFF	0
260 #define ZFC_RULE	1
261 #define ZFC_FORMAT	2
262 #define ZFC_TILYEAR	3
263 #define ZFC_TILMONTH	4
264 #define ZFC_TILDAY	5
265 #define ZFC_TILTIME	6
266 #define ZONEC_MINFIELDS	3
267 #define ZONEC_MAXFIELDS	7
268 
269 /*
270 ** Which files are which on a Rule line.
271 */
272 
273 #define RF_NAME		1
274 #define RF_LOYEAR	2
275 #define RF_HIYEAR	3
276 #define RF_COMMAND	4
277 #define RF_MONTH	5
278 #define RF_DAY		6
279 #define RF_TOD		7
280 #define RF_STDOFF	8
281 #define RF_ABBRVAR	9
282 #define RULE_FIELDS	10
283 
284 /*
285 ** Which fields are which on a Link line.
286 */
287 
288 #define LF_FROM		1
289 #define LF_TO		2
290 #define LINK_FIELDS	3
291 
292 /*
293 ** Which fields are which on a Leap line.
294 */
295 
296 #define LP_YEAR		1
297 #define LP_MONTH	2
298 #define LP_DAY		3
299 #define LP_TIME		4
300 #define LP_CORR		5
301 #define LP_ROLL		6
302 #define LEAP_FIELDS	7
303 
304 /*
305 ** Year synonyms.
306 */
307 
308 #define YR_MINIMUM	0
309 #define YR_MAXIMUM	1
310 #define YR_ONLY		2
311 
312 static struct rule *	rules;
313 static ptrdiff_t	nrules;	/* number of rules */
314 static ptrdiff_t	nrules_alloc;
315 
316 static struct zone *	zones;
317 static ptrdiff_t	nzones;	/* number of zones */
318 static ptrdiff_t	nzones_alloc;
319 
320 struct link {
321 	const char *	l_filename;
322 	lineno		l_linenum;
323 	const char *	l_from;
324 	const char *	l_to;
325 };
326 
327 static struct link *	links;
328 static ptrdiff_t	nlinks;
329 static ptrdiff_t	nlinks_alloc;
330 
331 struct lookup {
332 	const char *	l_word;
333 	const int	l_value;
334 };
335 
336 static struct lookup const *	byword(const char * string,
337 					const struct lookup * lp);
338 
339 static struct lookup const zi_line_codes[] = {
340 	{ "Rule",	LC_RULE },
341 	{ "Zone",	LC_ZONE },
342 	{ "Link",	LC_LINK },
343 	{ NULL,		0 }
344 };
345 static struct lookup const leap_line_codes[] = {
346 	{ "Leap",	LC_LEAP },
347 	{ NULL,		0}
348 };
349 
350 static struct lookup const	mon_names[] = {
351 	{ "January",	TM_JANUARY },
352 	{ "February",	TM_FEBRUARY },
353 	{ "March",	TM_MARCH },
354 	{ "April",	TM_APRIL },
355 	{ "May",	TM_MAY },
356 	{ "June",	TM_JUNE },
357 	{ "July",	TM_JULY },
358 	{ "August",	TM_AUGUST },
359 	{ "September",	TM_SEPTEMBER },
360 	{ "October",	TM_OCTOBER },
361 	{ "November",	TM_NOVEMBER },
362 	{ "December",	TM_DECEMBER },
363 	{ NULL,		0 }
364 };
365 
366 static struct lookup const	wday_names[] = {
367 	{ "Sunday",	TM_SUNDAY },
368 	{ "Monday",	TM_MONDAY },
369 	{ "Tuesday",	TM_TUESDAY },
370 	{ "Wednesday",	TM_WEDNESDAY },
371 	{ "Thursday",	TM_THURSDAY },
372 	{ "Friday",	TM_FRIDAY },
373 	{ "Saturday",	TM_SATURDAY },
374 	{ NULL,		0 }
375 };
376 
377 static struct lookup const	lasts[] = {
378 	{ "last-Sunday",	TM_SUNDAY },
379 	{ "last-Monday",	TM_MONDAY },
380 	{ "last-Tuesday",	TM_TUESDAY },
381 	{ "last-Wednesday",	TM_WEDNESDAY },
382 	{ "last-Thursday",	TM_THURSDAY },
383 	{ "last-Friday",	TM_FRIDAY },
384 	{ "last-Saturday",	TM_SATURDAY },
385 	{ NULL,			0 }
386 };
387 
388 static struct lookup const	begin_years[] = {
389 	{ "minimum",	YR_MINIMUM },
390 	{ "maximum",	YR_MAXIMUM },
391 	{ NULL,		0 }
392 };
393 
394 static struct lookup const	end_years[] = {
395 	{ "minimum",	YR_MINIMUM },
396 	{ "maximum",	YR_MAXIMUM },
397 	{ "only",	YR_ONLY },
398 	{ NULL,		0 }
399 };
400 
401 static struct lookup const	leap_types[] = {
402 	{ "Rolling",	true },
403 	{ "Stationary",	false },
404 	{ NULL,		0 }
405 };
406 
407 static const int	len_months[2][MONSPERYEAR] = {
408 	{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
409 	{ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
410 };
411 
412 static const int	len_years[2] = {
413 	DAYSPERNYEAR, DAYSPERLYEAR
414 };
415 
416 static struct attype {
417 	zic_t		at;
418 	bool		dontmerge;
419 	unsigned char	type;
420 } *			attypes;
421 static zic_t		gmtoffs[TZ_MAX_TYPES];
422 static char		isdsts[TZ_MAX_TYPES];
423 static unsigned char	abbrinds[TZ_MAX_TYPES];
424 static bool		ttisstds[TZ_MAX_TYPES];
425 static bool		ttisgmts[TZ_MAX_TYPES];
426 static char		chars[TZ_MAX_CHARS];
427 static zic_t		trans[TZ_MAX_LEAPS];
428 static zic_t		corr[TZ_MAX_LEAPS];
429 static char		roll[TZ_MAX_LEAPS];
430 
431 /*
432 ** Memory allocation.
433 */
434 
435 static _Noreturn void
436 memory_exhausted(const char *msg)
437 {
438 	fprintf(stderr, _("%s: Memory exhausted: %s\n"), progname, msg);
439 	exit(EXIT_FAILURE);
440 }
441 
442 static ATTRIBUTE_PURE size_t
443 size_product(size_t nitems, size_t itemsize)
444 {
445 	if (SIZE_MAX / itemsize < nitems)
446 		memory_exhausted(_("size overflow"));
447 	return nitems * itemsize;
448 }
449 
450 static ATTRIBUTE_PURE size_t
451 align_to(size_t size, size_t alignment)
452 {
453   size_t aligned_size = size + alignment - 1;
454   aligned_size -= aligned_size % alignment;
455   if (aligned_size < size)
456     memory_exhausted(_("alignment overflow"));
457   return aligned_size;
458 }
459 
460 #if !HAVE_STRDUP
461 static char *
462 strdup(char const *str)
463 {
464 	char *result = malloc(strlen(str) + 1);
465 	return result ? strcpy(result, str) : result;
466 }
467 #endif
468 
469 static void *
470 memcheck(void *ptr)
471 {
472 	if (ptr == NULL)
473 		memory_exhausted(strerror(errno));
474 	return ptr;
475 }
476 
477 static void * ATTRIBUTE_MALLOC
478 zic_malloc(size_t size)
479 {
480 	return memcheck(malloc(size));
481 }
482 
483 static void *
484 zic_realloc(void *ptr, size_t size)
485 {
486 	return memcheck(realloc(ptr, size));
487 }
488 
489 static char * ATTRIBUTE_MALLOC
490 ecpyalloc(char const *str)
491 {
492 	return memcheck(strdup(str));
493 }
494 
495 static void *
496 growalloc(void *ptr, size_t itemsize, ptrdiff_t nitems, ptrdiff_t *nitems_alloc)
497 {
498 	if (nitems < *nitems_alloc)
499 		return ptr;
500 	else {
501 		ptrdiff_t nitems_max = PTRDIFF_MAX - WORK_AROUND_QTBUG_53071;
502 		ptrdiff_t amax = (ptrdiff_t)((size_t)nitems_max < SIZE_MAX ?
503 		    (size_t)nitems_max : SIZE_MAX);
504 		if ((amax - 1) / 3 * 2 < *nitems_alloc)
505 			memory_exhausted(_("integer overflow"));
506 		*nitems_alloc += (*nitems_alloc >> 1) + 1;
507 		return zic_realloc(ptr, size_product(*nitems_alloc, itemsize));
508 	}
509 }
510 
511 /*
512 ** Error handling.
513 */
514 
515 static void
516 eats(char const *name, lineno num, char const *rname, lineno rnum)
517 {
518 	filename = name;
519 	linenum = num;
520 	rfilename = rname;
521 	rlinenum = rnum;
522 }
523 
524 static void
525 eat(char const *name, lineno num)
526 {
527 	eats(name, num, NULL, -1);
528 }
529 
530 static void ATTRIBUTE_FORMAT((printf, 1, 0))
531 verror(const char *const string, va_list args)
532 {
533 	/*
534 	** Match the format of "cc" to allow sh users to
535 	**	zic ... 2>&1 | error -t "*" -v
536 	** on BSD systems.
537 	*/
538 	if (filename)
539 	  fprintf(stderr, _("\"%s\", line %"PRIdMAX": "), filename, linenum);
540 	vfprintf(stderr, string, args);
541 	if (rfilename != NULL)
542 		fprintf(stderr, _(" (rule from \"%s\", line %"PRIdMAX")"),
543 			rfilename, rlinenum);
544 	fprintf(stderr, "\n");
545 }
546 
547 static void ATTRIBUTE_FORMAT((printf, 1, 2))
548 error(const char *const string, ...)
549 {
550 	va_list args;
551 	va_start(args, string);
552 	verror(string, args);
553 	va_end(args);
554 	errors = true;
555 }
556 
557 static void ATTRIBUTE_FORMAT((printf, 1, 2))
558 warning(const char *const string, ...)
559 {
560 	va_list args;
561 	fprintf(stderr, _("warning: "));
562 	va_start(args, string);
563 	verror(string, args);
564 	va_end(args);
565 	warnings = true;
566 }
567 
568 static void
569 close_file(FILE *stream, char const *dir, char const *name)
570 {
571   char const *e = (ferror(stream) ? _("I/O error")
572 		   : fclose(stream) != 0 ? strerror(errno) : NULL);
573   if (e) {
574     fprintf(stderr, "%s: %s%s%s%s%s\n", progname,
575 	    dir ? dir : "", dir ? "/" : "",
576 	    name ? name : "", name ? ": " : "",
577 	    e);
578     exit(EXIT_FAILURE);
579   }
580 }
581 
582 static _Noreturn void
583 usage(FILE *stream, int status)
584 {
585   fprintf(stream,
586 	  _("%s: usage is %s [ --version ] [ --help ] [ -v ] \\\n"
587 	    "\t[ -l localtime ] [ -p posixrules ] [ -d directory ] \\\n"
588 	    "\t[ -t localtime-link ] [ -L leapseconds ] [ -r '[@lo][/@hi]' ] \\\n"
589 	    "\t[ filename ... ]\n\n"
590 	    "Report bugs to %s.\n"),
591 	  progname, progname, REPORT_BUGS_TO);
592   if (status == EXIT_SUCCESS)
593     close_file(stream, NULL, NULL);
594   exit(status);
595 }
596 
597 /* Change the working directory to DIR, possibly creating DIR and its
598    ancestors.  After this is done, all files are accessed with names
599    relative to DIR.  */
600 static void
601 change_directory (char const *dir)
602 {
603   if (chdir(dir) != 0) {
604     int chdir_errno = errno;
605     if (chdir_errno == ENOENT) {
606       mkdirs(dir, false);
607       chdir_errno = chdir(dir) == 0 ? 0 : errno;
608     }
609     if (chdir_errno != 0) {
610       fprintf(stderr, _("%s: Can't chdir to %s: %s\n"),
611 	      progname, dir, strerror(chdir_errno));
612       exit(EXIT_FAILURE);
613     }
614   }
615 }
616 
617 #define TIME_T_BITS_IN_FILE 64
618 
619 /* The minimum and maximum values representable in a TZif file.  */
620 static zic_t const min_time = MINVAL(zic_t, TIME_T_BITS_IN_FILE);
621 static zic_t const max_time = MAXVAL(zic_t, TIME_T_BITS_IN_FILE);
622 
623 /* The minimum, and one less than the maximum, values specified by
624    the -r option.  These default to MIN_TIME and MAX_TIME.  */
625 static zic_t lo_time = MINVAL(zic_t, TIME_T_BITS_IN_FILE);
626 static zic_t hi_time = MAXVAL(zic_t, TIME_T_BITS_IN_FILE);
627 
628 /* Set the time range of the output to TIMERANGE.
629    Return true if successful.  */
630 static bool
631 timerange_option(char *timerange)
632 {
633   intmax_t lo = min_time, hi = max_time;
634   char *lo_end = timerange, *hi_end;
635   if (*timerange == '@') {
636     errno = 0;
637     lo = strtoimax (timerange + 1, &lo_end, 10);
638     if (lo_end == timerange + 1 || (lo == INTMAX_MAX && errno == ERANGE))
639       return false;
640   }
641   hi_end = lo_end;
642   if (lo_end[0] == '/' && lo_end[1] == '@') {
643     errno = 0;
644     hi = strtoimax (lo_end + 2, &hi_end, 10);
645     if (hi_end == lo_end + 2 || hi == INTMAX_MIN)
646       return false;
647     hi -= ! (hi == INTMAX_MAX && errno == ERANGE);
648   }
649   if (*hi_end || hi < lo || max_time < lo || hi < min_time)
650     return false;
651   lo_time = lo < min_time ? min_time : lo;
652   hi_time = max_time < hi ? max_time : hi;
653   return true;
654 }
655 
656 static const char *	psxrules;
657 static const char *	lcltime;
658 static const char *	directory;
659 static const char *	leapsec;
660 static const char *	tzdefault;
661 static const char *	yitcommand;
662 
663 int
664 main(int argc, char **argv)
665 {
666 	int	c, k;
667 	ptrdiff_t	i, j;
668 	bool timerange_given = false;
669 
670 #ifdef S_IWGRP
671 	umask(umask(S_IWGRP | S_IWOTH) | (S_IWGRP | S_IWOTH));
672 #endif
673 #if HAVE_GETTEXT
674 	setlocale(LC_MESSAGES, "");
675 #ifdef TZ_DOMAINDIR
676 	bindtextdomain(TZ_DOMAIN, TZ_DOMAINDIR);
677 #endif /* defined TEXTDOMAINDIR */
678 	textdomain(TZ_DOMAIN);
679 #endif /* HAVE_GETTEXT */
680 	progname = argv[0];
681 	if (TYPE_BIT(zic_t) < 64) {
682 		fprintf(stderr, "%s: %s\n", progname,
683 			_("wild compilation-time specification of zic_t"));
684 		return EXIT_FAILURE;
685 	}
686 	for (k = 1; k < argc; k++)
687 		if (strcmp(argv[k], "--version") == 0) {
688 			printf("zic %s%s\n", PKGVERSION, TZVERSION);
689 			close_file(stdout, NULL, NULL);
690 			return EXIT_SUCCESS;
691 		} else if (strcmp(argv[k], "--help") == 0) {
692 			usage(stdout, EXIT_SUCCESS);
693 		}
694 	while ((c = getopt(argc, argv, "d:l:L:p:r:st:vy:")) != EOF && c != -1)
695 		switch (c) {
696 			default:
697 				usage(stderr, EXIT_FAILURE);
698 			case 'd':
699 				if (directory == NULL)
700 					directory = optarg;
701 				else {
702 					fprintf(stderr,
703 _("%s: More than one -d option specified\n"),
704 						progname);
705 					return EXIT_FAILURE;
706 				}
707 				break;
708 			case 'l':
709 				if (lcltime == NULL)
710 					lcltime = optarg;
711 				else {
712 					fprintf(stderr,
713 _("%s: More than one -l option specified\n"),
714 						progname);
715 					return EXIT_FAILURE;
716 				}
717 				break;
718 			case 'p':
719 				if (psxrules == NULL)
720 					psxrules = optarg;
721 				else {
722 					fprintf(stderr,
723 _("%s: More than one -p option specified\n"),
724 						progname);
725 					return EXIT_FAILURE;
726 				}
727 				break;
728 			case 't':
729 				if (tzdefault != NULL) {
730 				  fprintf(stderr,
731 					  _("%s: More than one -t option"
732 					    " specified\n"),
733 					  progname);
734 				  return EXIT_FAILURE;
735 				}
736 				tzdefault = optarg;
737 				break;
738 			case 'y':
739 				if (yitcommand == NULL) {
740 					warning(_("-y is obsolescent"));
741 					yitcommand = optarg;
742 				} else {
743 					fprintf(stderr,
744 _("%s: More than one -y option specified\n"),
745 						progname);
746 					return EXIT_FAILURE;
747 				}
748 				break;
749 			case 'L':
750 				if (leapsec == NULL)
751 					leapsec = optarg;
752 				else {
753 					fprintf(stderr,
754 _("%s: More than one -L option specified\n"),
755 						progname);
756 					return EXIT_FAILURE;
757 				}
758 				break;
759 			case 'v':
760 				noise = true;
761 				break;
762 			case 'r':
763 				if (timerange_given) {
764 				  fprintf(stderr,
765 _("%s: More than one -r option specified\n"),
766 					  progname);
767 				  return EXIT_FAILURE;
768 				}
769 				if (! timerange_option(optarg)) {
770 				  fprintf(stderr,
771 _("%s: invalid time range: %s\n"),
772 					  progname, optarg);
773 				  return EXIT_FAILURE;
774 				}
775 				timerange_given = true;
776 				break;
777 			case 's':
778 				warning(_("-s ignored"));
779 				break;
780 		}
781 	if (optind == argc - 1 && strcmp(argv[optind], "=") == 0)
782 		usage(stderr, EXIT_FAILURE);	/* usage message by request */
783 	if (directory == NULL)
784 		directory = TZDIR;
785 	if (tzdefault == NULL)
786 		tzdefault = TZDEFAULT;
787 	if (yitcommand == NULL)
788 		yitcommand = "yearistype";
789 
790 	if (optind < argc && leapsec != NULL) {
791 		infile(leapsec);
792 		adjleap();
793 	}
794 
795 	for (k = optind; k < argc; k++)
796 		infile(argv[k]);
797 	if (errors)
798 		return EXIT_FAILURE;
799 	associate();
800 	change_directory(directory);
801 	for (i = 0; i < nzones; i = j) {
802 		/*
803 		** Find the next non-continuation zone entry.
804 		*/
805 		for (j = i + 1; j < nzones && zones[j].z_name == NULL; ++j)
806 			continue;
807 		outzone(&zones[i], j - i);
808 	}
809 	/*
810 	** Make links.
811 	*/
812 	for (i = 0; i < nlinks; ++i) {
813 		eat(links[i].l_filename, links[i].l_linenum);
814 		dolink(links[i].l_from, links[i].l_to, false);
815 		if (noise)
816 			for (j = 0; j < nlinks; ++j)
817 				if (strcmp(links[i].l_to,
818 					links[j].l_from) == 0)
819 						warning(_("link to link"));
820 	}
821 	if (lcltime != NULL) {
822 		eat(_("command line"), 1);
823 		dolink(lcltime, tzdefault, true);
824 	}
825 	if (psxrules != NULL) {
826 		eat(_("command line"), 1);
827 		dolink(psxrules, TZDEFRULES, true);
828 	}
829 	if (warnings && (ferror(stderr) || fclose(stderr) != 0))
830 	  return EXIT_FAILURE;
831 	return errors ? EXIT_FAILURE : EXIT_SUCCESS;
832 }
833 
834 static bool
835 componentcheck(char const *name, char const *component,
836 	       char const *component_end)
837 {
838 	enum { component_len_max = 14 };
839 	ptrdiff_t component_len = component_end - component;
840 	if (component_len == 0) {
841 	  if (!*name)
842 	    error (_("empty file name"));
843 	  else
844 	    error (_(component == name
845 		     ? "file name '%s' begins with '/'"
846 		     : *component_end
847 		     ? "file name '%s' contains '//'"
848 		     : "file name '%s' ends with '/'"),
849 		   name);
850 	  return false;
851 	}
852 	if (0 < component_len && component_len <= 2
853 	    && component[0] == '.' && component_end[-1] == '.') {
854 	  int len = component_len;
855 	  error(_("file name '%s' contains '%.*s' component"),
856 		name, len, component);
857 	  return false;
858 	}
859 	if (noise) {
860 	  if (0 < component_len && component[0] == '-')
861 	    warning(_("file name '%s' component contains leading '-'"),
862 		    name);
863 	  if (component_len_max < component_len)
864 	    warning(_("file name '%s' contains overlength component"
865 		      " '%.*s...'"),
866 		    name, component_len_max, component);
867 	}
868 	return true;
869 }
870 
871 static bool
872 namecheck(const char *name)
873 {
874 	char const *cp;
875 
876 	/* Benign characters in a portable file name.  */
877 	static char const benign[] =
878 	  "-/_"
879 	  "abcdefghijklmnopqrstuvwxyz"
880 	  "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
881 
882 	/* Non-control chars in the POSIX portable character set,
883 	   excluding the benign characters.  */
884 	static char const printable_and_not_benign[] =
885 	  " !\"#$%&'()*+,.0123456789:;<=>?@[\\]^`{|}~";
886 
887 	char const *component = name;
888 	for (cp = name; *cp; cp++) {
889 		unsigned char c = *cp;
890 		if (noise && !strchr(benign, c)) {
891 			warning((strchr(printable_and_not_benign, c)
892 				 ? _("file name '%s' contains byte '%c'")
893 				 : _("file name '%s' contains byte '\\%o'")),
894 				name, c);
895 		}
896 		if (c == '/') {
897 			if (!componentcheck(name, component, cp))
898 			  return false;
899 			component = cp + 1;
900 		}
901 	}
902 	return componentcheck(name, component, cp);
903 }
904 
905 /* Create symlink contents suitable for symlinking FROM to TO, as a
906    freshly allocated string.  FROM should be a relative file name, and
907    is relative to the global variable DIRECTORY.  TO can be either
908    relative or absolute.  */
909 static char *
910 relname(char const *from, char const *to)
911 {
912   size_t i, taillen, dotdotetcsize;
913   size_t dir_len = 0, dotdots = 0, linksize = SIZE_MAX;
914   char const *f = from;
915   char *result = NULL;
916   if (*to == '/') {
917     /* Make F absolute too.  */
918     size_t len = strlen(directory);
919     bool needslash = len && directory[len - 1] != '/';
920     linksize = len + needslash + strlen(from) + 1;
921     f = result = emalloc(linksize);
922     strcpy(result, directory);
923     result[len] = '/';
924     strcpy(result + len + needslash, from);
925   }
926   for (i = 0; f[i] && f[i] == to[i]; i++)
927     if (f[i] == '/')
928       dir_len = i + 1;
929   for (; to[i]; i++)
930     dotdots += to[i] == '/' && to[i - 1] != '/';
931   taillen = strlen(f + dir_len);
932   dotdotetcsize = 3 * dotdots + taillen + 1;
933   if (dotdotetcsize <= linksize) {
934     if (!result)
935       result = emalloc(dotdotetcsize);
936     for (i = 0; i < dotdots; i++)
937       memcpy(result + 3 * i, "../", 3);
938     memmove(result + 3 * dotdots, f + dir_len, taillen + 1);
939   }
940   return result;
941 }
942 
943 /* Hard link FROM to TO, following any symbolic links.
944    Return 0 if successful, an error number otherwise.  */
945 static int
946 hardlinkerr(char const *from, char const *to)
947 {
948   int r = linkat(AT_FDCWD, from, AT_FDCWD, to, AT_SYMLINK_FOLLOW);
949   return r == 0 ? 0 : errno;
950 }
951 
952 static void
953 dolink(char const *fromfield, char const *tofield, bool staysymlink)
954 {
955 	bool todirs_made = false;
956 	int link_errno;
957 
958 	/*
959 	** We get to be careful here since
960 	** there's a fair chance of root running us.
961 	*/
962 	if (itsdir(fromfield)) {
963 		fprintf(stderr, _("%s: link from %s/%s failed: %s\n"),
964 			progname, directory, fromfield, strerror(EPERM));
965 		exit(EXIT_FAILURE);
966 	}
967 	if (staysymlink)
968 	  staysymlink = itssymlink(tofield);
969 	if (remove(tofield) == 0)
970 	  todirs_made = true;
971 	else if (errno != ENOENT) {
972 	  char const *e = strerror(errno);
973 	  fprintf(stderr, _("%s: Can't remove %s/%s: %s\n"),
974 	    progname, directory, tofield, e);
975 	  exit(EXIT_FAILURE);
976 	}
977 	link_errno = staysymlink ? ENOTSUP : hardlinkerr(fromfield, tofield);
978 	if (link_errno == ENOENT && !todirs_made) {
979 	  mkdirs(tofield, true);
980 	  todirs_made = true;
981 	  link_errno = hardlinkerr(fromfield, tofield);
982 	}
983 	if (link_errno != 0) {
984 	  bool absolute = *fromfield == '/';
985 	  char *linkalloc = absolute ? NULL : relname(fromfield, tofield);
986 	  char const *contents = absolute ? fromfield : linkalloc;
987 	  int symlink_errno = symlink(contents, tofield) == 0 ? 0 : errno;
988 	  if (!todirs_made
989 	      && (symlink_errno == ENOENT || symlink_errno == ENOTSUP)) {
990 	    mkdirs(tofield, true);
991 	    if (symlink_errno == ENOENT)
992 	      symlink_errno = symlink(contents, tofield) == 0 ? 0 : errno;
993 	  }
994 	  free(linkalloc);
995 	  if (symlink_errno == 0) {
996 	    if (link_errno != ENOTSUP)
997 	      warning(_("symbolic link used because hard link failed: %s"),
998 		      strerror(link_errno));
999 	  } else {
1000 	    FILE *fp, *tp;
1001 	    int c;
1002 	    fp = fopen(fromfield, "rb");
1003 	    if (!fp) {
1004 	      char const *e = strerror(errno);
1005 	      fprintf(stderr, _("%s: Can't read %s/%s: %s\n"),
1006 		      progname, directory, fromfield, e);
1007 	      exit(EXIT_FAILURE);
1008 	    }
1009 	    tp = fopen(tofield, "wb");
1010 	    if (!tp) {
1011 	      char const *e = strerror(errno);
1012 	      fprintf(stderr, _("%s: Can't create %s/%s: %s\n"),
1013 		      progname, directory, tofield, e);
1014 	      exit(EXIT_FAILURE);
1015 	    }
1016 	    while ((c = getc(fp)) != EOF)
1017 	      putc(c, tp);
1018 	    close_file(fp, directory, fromfield);
1019 	    close_file(tp, directory, tofield);
1020 	    if (link_errno != ENOTSUP)
1021 	      warning(_("copy used because hard link failed: %s"),
1022 		      strerror(link_errno));
1023 	    else if (symlink_errno != ENOTSUP)
1024 	      warning(_("copy used because symbolic link failed: %s"),
1025 		      strerror(symlink_errno));
1026 	  }
1027 	}
1028 }
1029 
1030 /* Return true if NAME is a directory.  */
1031 static bool
1032 itsdir(char const *name)
1033 {
1034 	struct stat st;
1035 	int res = stat(name, &st);
1036 #ifdef S_ISDIR
1037 	if (res == 0)
1038 		return S_ISDIR(st.st_mode) != 0;
1039 #endif
1040 	if (res == 0 || errno == EOVERFLOW) {
1041 		size_t n = strlen(name);
1042 		char *nameslashdot = emalloc(n + 3);
1043 		bool dir;
1044 		memcpy(nameslashdot, name, n);
1045 		strcpy(&nameslashdot[n], &"/."[! (n && name[n - 1] != '/')]);
1046 		dir = stat(nameslashdot, &st) == 0 || errno == EOVERFLOW;
1047 		free(nameslashdot);
1048 		return dir;
1049 	}
1050 	return false;
1051 }
1052 
1053 /* Return true if NAME is a symbolic link.  */
1054 static bool
1055 itssymlink(char const *name)
1056 {
1057   char c;
1058   return 0 <= readlink(name, &c, 1);
1059 }
1060 
1061 /*
1062 ** Associate sets of rules with zones.
1063 */
1064 
1065 /*
1066 ** Sort by rule name.
1067 */
1068 
1069 static int
1070 rcomp(const void *cp1, const void *cp2)
1071 {
1072 	return strcmp(((const struct rule *) cp1)->r_name,
1073 		((const struct rule *) cp2)->r_name);
1074 }
1075 
1076 static void
1077 associate(void)
1078 {
1079 	struct zone *	zp;
1080 	struct rule *	rp;
1081 	ptrdiff_t	base, out;
1082 	int		i, j;
1083 
1084 	if (nrules != 0) {
1085 		qsort(rules, (size_t)nrules, sizeof *rules, rcomp);
1086 		for (i = 0; i < nrules - 1; ++i) {
1087 			if (strcmp(rules[i].r_name,
1088 				rules[i + 1].r_name) != 0)
1089 					continue;
1090 			if (strcmp(rules[i].r_filename,
1091 				rules[i + 1].r_filename) == 0)
1092 					continue;
1093 			eat(rules[i].r_filename, rules[i].r_linenum);
1094 			warning(_("same rule name in multiple files"));
1095 			eat(rules[i + 1].r_filename, rules[i + 1].r_linenum);
1096 			warning(_("same rule name in multiple files"));
1097 			for (j = i + 2; j < nrules; ++j) {
1098 				if (strcmp(rules[i].r_name,
1099 					rules[j].r_name) != 0)
1100 						break;
1101 				if (strcmp(rules[i].r_filename,
1102 					rules[j].r_filename) == 0)
1103 						continue;
1104 				if (strcmp(rules[i + 1].r_filename,
1105 					rules[j].r_filename) == 0)
1106 						continue;
1107 				break;
1108 			}
1109 			i = j - 1;
1110 		}
1111 	}
1112 	for (i = 0; i < nzones; ++i) {
1113 		zp = &zones[i];
1114 		zp->z_rules = NULL;
1115 		zp->z_nrules = 0;
1116 	}
1117 	for (base = 0; base < nrules; base = out) {
1118 		rp = &rules[base];
1119 		for (out = base + 1; out < nrules; ++out)
1120 			if (strcmp(rp->r_name, rules[out].r_name) != 0)
1121 				break;
1122 		for (i = 0; i < nzones; ++i) {
1123 			zp = &zones[i];
1124 			if (strcmp(zp->z_rule, rp->r_name) != 0)
1125 				continue;
1126 			zp->z_rules = rp;
1127 			zp->z_nrules = out - base;
1128 		}
1129 	}
1130 	for (i = 0; i < nzones; ++i) {
1131 		zp = &zones[i];
1132 		if (zp->z_nrules == 0) {
1133 			/*
1134 			** Maybe we have a local standard time offset.
1135 			*/
1136 			eat(zp->z_filename, zp->z_linenum);
1137 			zp->z_stdoff = getstdoff(zp->z_rule, &zp->z_isdst);
1138 			/*
1139 			** Note, though, that if there's no rule,
1140 			** a '%s' in the format is a bad thing.
1141 			*/
1142 			if (zp->z_format_specifier == 's')
1143 				error("%s", _("%s in ruleless zone"));
1144 		}
1145 	}
1146 	if (errors)
1147 		exit(EXIT_FAILURE);
1148 }
1149 
1150 static void
1151 infile(const char *name)
1152 {
1153 	FILE *			fp;
1154 	char **		fields;
1155 	char *			cp;
1156 	const struct lookup *	lp;
1157 	int			nfields;
1158 	bool			wantcont;
1159 	lineno			num;
1160 	char				buf[BUFSIZ];
1161 
1162 	if (strcmp(name, "-") == 0) {
1163 		name = _("standard input");
1164 		fp = stdin;
1165 	} else if ((fp = fopen(name, "r")) == NULL) {
1166 		const char *e = strerror(errno);
1167 
1168 		fprintf(stderr, _("%s: Can't open %s: %s\n"),
1169 			progname, name, e);
1170 		exit(EXIT_FAILURE);
1171 	}
1172 	wantcont = false;
1173 	for (num = 1; ; ++num) {
1174 		eat(name, num);
1175 		if (fgets(buf, (int) sizeof buf, fp) != buf)
1176 			break;
1177 		cp = strchr(buf, '\n');
1178 		if (cp == NULL) {
1179 			error(_("line too long"));
1180 			exit(EXIT_FAILURE);
1181 		}
1182 		*cp = '\0';
1183 		fields = getfields(buf);
1184 		nfields = 0;
1185 		while (fields[nfields] != NULL) {
1186 			static char	nada;
1187 
1188 			if (strcmp(fields[nfields], "-") == 0)
1189 				fields[nfields] = &nada;
1190 			++nfields;
1191 		}
1192 		if (nfields == 0) {
1193 			/* nothing to do */
1194 		} else if (wantcont) {
1195 			wantcont = inzcont(fields, nfields);
1196 		} else {
1197 			struct lookup const *line_codes
1198 			  = name == leapsec ? leap_line_codes : zi_line_codes;
1199 			lp = byword(fields[0], line_codes);
1200 			if (lp == NULL)
1201 				error(_("input line of unknown type"));
1202 			else switch (lp->l_value) {
1203 				case LC_RULE:
1204 					inrule(fields, nfields);
1205 					wantcont = false;
1206 					break;
1207 				case LC_ZONE:
1208 					wantcont = inzone(fields, nfields);
1209 					break;
1210 				case LC_LINK:
1211 					inlink(fields, nfields);
1212 					wantcont = false;
1213 					break;
1214 				case LC_LEAP:
1215 					inleap(fields, nfields);
1216 					wantcont = false;
1217 					break;
1218 				default:	/* "cannot happen" */
1219 					fprintf(stderr,
1220 _("%s: panic: Invalid l_value %d\n"),
1221 						progname, lp->l_value);
1222 					exit(EXIT_FAILURE);
1223 			}
1224 		}
1225 		free(fields);
1226 	}
1227 	close_file(fp, NULL, filename);
1228 	if (wantcont)
1229 		error(_("expected continuation line not found"));
1230 }
1231 
1232 /*
1233 ** Convert a string of one of the forms
1234 **	h	-h	hh:mm	-hh:mm	hh:mm:ss	-hh:mm:ss
1235 ** into a number of seconds.
1236 ** A null string maps to zero.
1237 ** Call error with errstring and return zero on errors.
1238 */
1239 
1240 static zic_t
1241 gethms(char const *string, char const *errstring)
1242 {
1243 	zic_t	hh;
1244 	int sign, mm = 0, ss = 0;
1245 	char hhx, mmx, ssx, xr = '0', xs;
1246 	int tenths = 0;
1247 	bool ok = true;
1248 
1249 	if (string == NULL || *string == '\0')
1250 		return 0;
1251 	if (*string == '-') {
1252 		sign = -1;
1253 		++string;
1254 	} else	sign = 1;
1255 	switch (sscanf(string,
1256 		       "%"SCNdZIC"%c%d%c%d%c%1d%*[0]%c%*[0123456789]%c",
1257 		       &hh, &hhx, &mm, &mmx, &ss, &ssx, &tenths, &xr, &xs)) {
1258 	  default: ok = false; break;
1259 	  case 8:
1260 	    ok = '0' <= xr && xr <= '9';
1261 	    /* fallthrough */
1262 	  case 7:
1263 	    ok &= ssx == '.';
1264 	    if (ok && noise)
1265 	      warning(_("fractional seconds rejected by"
1266 			" pre-2018 versions of zic"));
1267 	    /* fallthrough */
1268 	  case 5: ok &= mmx == ':'; /* fallthrough */
1269 	  case 3: ok &= hhx == ':'; /* fallthrough */
1270 	  case 1: break;
1271 	}
1272 	if (!ok) {
1273 			error("%s", errstring);
1274 			return 0;
1275 	}
1276 	if (hh < 0 ||
1277 		mm < 0 || mm >= MINSPERHOUR ||
1278 		ss < 0 || ss > SECSPERMIN) {
1279 			error("%s", errstring);
1280 			return 0;
1281 	}
1282 	if (ZIC_MAX / SECSPERHOUR < hh) {
1283 		error(_("time overflow"));
1284 		return 0;
1285 	}
1286 	ss += 5 + ((ss ^ 1) & (xr == '0')) <= tenths; /* Round to even.  */
1287 	if (noise && (hh > HOURSPERDAY ||
1288 		(hh == HOURSPERDAY && (mm != 0 || ss != 0))))
1289 warning(_("values over 24 hours not handled by pre-2007 versions of zic"));
1290 	return oadd(sign * hh * SECSPERHOUR,
1291 		    sign * (mm * SECSPERMIN + ss));
1292 }
1293 
1294 static zic_t
1295 getstdoff(char *field, bool *isdst)
1296 {
1297   int dst = -1;
1298   zic_t stdoff;
1299   size_t fieldlen = strlen(field);
1300   if (fieldlen != 0) {
1301     char *ep = field + fieldlen - 1;
1302     switch (*ep) {
1303       case 'd': dst = 1; *ep = '\0'; break;
1304       case 's': dst = 0; *ep = '\0'; break;
1305     }
1306   }
1307   stdoff = gethms(field, _("invalid saved time"));
1308   *isdst = dst < 0 ? stdoff != 0 : dst;
1309   return stdoff;
1310 }
1311 
1312 static void
1313 inrule(char **fields, int nfields)
1314 {
1315 	static struct rule	r;
1316 
1317 	if (nfields != RULE_FIELDS) {
1318 		error(_("wrong number of fields on Rule line"));
1319 		return;
1320 	}
1321 	switch (*fields[RF_NAME]) {
1322 	  case '\0':
1323 	  case ' ': case '\f': case '\n': case '\r': case '\t': case '\v':
1324 	  case '+': case '-':
1325 	  case '0': case '1': case '2': case '3': case '4':
1326 	  case '5': case '6': case '7': case '8': case '9':
1327 		error(_("Invalid rule name \"%s\""), fields[RF_NAME]);
1328 		return;
1329 	}
1330 	r.r_filename = filename;
1331 	r.r_linenum = linenum;
1332 	r.r_stdoff = getstdoff(fields[RF_STDOFF], &r.r_isdst);
1333 	rulesub(&r, fields[RF_LOYEAR], fields[RF_HIYEAR], fields[RF_COMMAND],
1334 		fields[RF_MONTH], fields[RF_DAY], fields[RF_TOD]);
1335 	r.r_name = ecpyalloc(fields[RF_NAME]);
1336 	r.r_abbrvar = ecpyalloc(fields[RF_ABBRVAR]);
1337 	if (max_abbrvar_len < strlen(r.r_abbrvar))
1338 		max_abbrvar_len = strlen(r.r_abbrvar);
1339 	rules = growalloc(rules, sizeof *rules, nrules, &nrules_alloc);
1340 	rules[nrules++] = r;
1341 }
1342 
1343 static bool
1344 inzone(char **fields, int nfields)
1345 {
1346 	ptrdiff_t	i;
1347 
1348 	if (nfields < ZONE_MINFIELDS || nfields > ZONE_MAXFIELDS) {
1349 		error(_("wrong number of fields on Zone line"));
1350 		return false;
1351 	}
1352 	if (lcltime != NULL && strcmp(fields[ZF_NAME], tzdefault) == 0) {
1353 		error(
1354 _("\"Zone %s\" line and -l option are mutually exclusive"),
1355 			tzdefault);
1356 		return false;
1357 	}
1358 	if (strcmp(fields[ZF_NAME], TZDEFRULES) == 0 && psxrules != NULL) {
1359 		error(
1360 _("\"Zone %s\" line and -p option are mutually exclusive"),
1361 			TZDEFRULES);
1362 		return false;
1363 	}
1364 	for (i = 0; i < nzones; ++i)
1365 		if (zones[i].z_name != NULL &&
1366 		    strcmp(zones[i].z_name, fields[ZF_NAME]) == 0) {
1367 			error(_("duplicate zone name %s"
1368 				" (file \"%s\", line %"PRIdMAX")"),
1369 				fields[ZF_NAME],
1370 				zones[i].z_filename,
1371 				zones[i].z_linenum);
1372 			return false;
1373 		}
1374 	return inzsub(fields, nfields, false);
1375 }
1376 
1377 static bool
1378 inzcont(char **fields, int nfields)
1379 {
1380 	if (nfields < ZONEC_MINFIELDS || nfields > ZONEC_MAXFIELDS) {
1381 		error(_("wrong number of fields on Zone continuation line"));
1382 		return false;
1383 	}
1384 	return inzsub(fields, nfields, true);
1385 }
1386 
1387 static bool
1388 inzsub(char **fields, int nfields, bool iscont)
1389 {
1390 	char *		cp;
1391 	char *		cp1;
1392 	static struct zone	z;
1393 	int		i_gmtoff, i_rule, i_format;
1394 	int		i_untilyear, i_untilmonth;
1395 	int		i_untilday, i_untiltime;
1396 	bool		hasuntil;
1397 
1398 	if (iscont) {
1399 		i_gmtoff = ZFC_GMTOFF;
1400 		i_rule = ZFC_RULE;
1401 		i_format = ZFC_FORMAT;
1402 		i_untilyear = ZFC_TILYEAR;
1403 		i_untilmonth = ZFC_TILMONTH;
1404 		i_untilday = ZFC_TILDAY;
1405 		i_untiltime = ZFC_TILTIME;
1406 		z.z_name = NULL;
1407 	} else if (!namecheck(fields[ZF_NAME]))
1408 		return false;
1409 	else {
1410 		i_gmtoff = ZF_GMTOFF;
1411 		i_rule = ZF_RULE;
1412 		i_format = ZF_FORMAT;
1413 		i_untilyear = ZF_TILYEAR;
1414 		i_untilmonth = ZF_TILMONTH;
1415 		i_untilday = ZF_TILDAY;
1416 		i_untiltime = ZF_TILTIME;
1417 		z.z_name = ecpyalloc(fields[ZF_NAME]);
1418 	}
1419 	z.z_filename = filename;
1420 	z.z_linenum = linenum;
1421 	z.z_gmtoff = gethms(fields[i_gmtoff], _("invalid UT offset"));
1422 	if ((cp = strchr(fields[i_format], '%')) != 0) {
1423 		if ((*++cp != 's' && *cp != 'z') || strchr(cp, '%')
1424 		    || strchr(fields[i_format], '/')) {
1425 			error(_("invalid abbreviation format"));
1426 			return false;
1427 		}
1428 	}
1429 	z.z_rule = ecpyalloc(fields[i_rule]);
1430 	z.z_format = cp1 = ecpyalloc(fields[i_format]);
1431 	z.z_format_specifier = cp ? *cp : '\0';
1432 	if (z.z_format_specifier == 'z') {
1433 	  if (noise)
1434 	    warning(_("format '%s' not handled by pre-2015 versions of zic"),
1435 		    z.z_format);
1436 	  cp1[cp - fields[i_format]] = 's';
1437 	}
1438 	if (max_format_len < strlen(z.z_format))
1439 		max_format_len = strlen(z.z_format);
1440 	hasuntil = nfields > i_untilyear;
1441 	if (hasuntil) {
1442 		z.z_untilrule.r_filename = filename;
1443 		z.z_untilrule.r_linenum = linenum;
1444 		rulesub(&z.z_untilrule,
1445 			fields[i_untilyear],
1446 			"only",
1447 			"",
1448 			(nfields > i_untilmonth) ?
1449 			fields[i_untilmonth] : "Jan",
1450 			(nfields > i_untilday) ? fields[i_untilday] : "1",
1451 			(nfields > i_untiltime) ? fields[i_untiltime] : "0");
1452 		z.z_untiltime = rpytime(&z.z_untilrule,
1453 			z.z_untilrule.r_loyear);
1454 		if (iscont && nzones > 0 &&
1455 			z.z_untiltime > min_time &&
1456 			z.z_untiltime < max_time &&
1457 			zones[nzones - 1].z_untiltime > min_time &&
1458 			zones[nzones - 1].z_untiltime < max_time &&
1459 			zones[nzones - 1].z_untiltime >= z.z_untiltime) {
1460 				error(_(
1461 "Zone continuation line end time is not after end time of previous line"
1462 					));
1463 				return false;
1464 		}
1465 	}
1466 	zones = growalloc(zones, sizeof *zones, nzones, &nzones_alloc);
1467 	zones[nzones++] = z;
1468 	/*
1469 	** If there was an UNTIL field on this line,
1470 	** there's more information about the zone on the next line.
1471 	*/
1472 	return hasuntil;
1473 }
1474 
1475 static void
1476 inleap(char **fields, int nfields)
1477 {
1478 	const char *		cp;
1479 	const struct lookup *	lp;
1480 	zic_t			i, j;
1481 	zic_t			year;
1482 	int			month, day;
1483 	zic_t			dayoff, tod;
1484 	zic_t			t;
1485 	char			xs;
1486 
1487 	if (nfields != LEAP_FIELDS) {
1488 		error(_("wrong number of fields on Leap line"));
1489 		return;
1490 	}
1491 	dayoff = 0;
1492 	cp = fields[LP_YEAR];
1493 	if (sscanf(cp, "%"SCNdZIC"%c", &year, &xs) != 1) {
1494 		/*
1495 		** Leapin' Lizards!
1496 		*/
1497 		error(_("invalid leaping year"));
1498 		return;
1499 	}
1500 	if (!leapseen || leapmaxyear < year)
1501 		leapmaxyear = year;
1502 	if (!leapseen || leapminyear > year)
1503 		leapminyear = year;
1504 	leapseen = true;
1505 	j = EPOCH_YEAR;
1506 	while (j != year) {
1507 		if (year > j) {
1508 			i = len_years[isleap(j)];
1509 			++j;
1510 		} else {
1511 			--j;
1512 			i = -len_years[isleap(j)];
1513 		}
1514 		dayoff = oadd(dayoff, i);
1515 	}
1516 	if ((lp = byword(fields[LP_MONTH], mon_names)) == NULL) {
1517 		error(_("invalid month name"));
1518 		return;
1519 	}
1520 	month = lp->l_value;
1521 	j = TM_JANUARY;
1522 	while (j != month) {
1523 		i = len_months[isleap(year)][j];
1524 		dayoff = oadd(dayoff, i);
1525 		++j;
1526 	}
1527 	cp = fields[LP_DAY];
1528 	if (sscanf(cp, "%d%c", &day, &xs) != 1 ||
1529 		day <= 0 || day > len_months[isleap(year)][month]) {
1530 			error(_("invalid day of month"));
1531 			return;
1532 	}
1533 	dayoff = oadd(dayoff, day - 1);
1534 	if (dayoff < min_time / SECSPERDAY) {
1535 		error(_("time too small"));
1536 		return;
1537 	}
1538 	if (dayoff > max_time / SECSPERDAY) {
1539 		error(_("time too large"));
1540 		return;
1541 	}
1542 	t = dayoff * SECSPERDAY;
1543 	tod = gethms(fields[LP_TIME], _("invalid time of day"));
1544 	cp = fields[LP_CORR];
1545 	{
1546 		bool	positive;
1547 		int	count;
1548 
1549 		if (strcmp(cp, "") == 0) { /* infile() turns "-" into "" */
1550 			positive = false;
1551 			count = 1;
1552 		} else if (strcmp(cp, "+") == 0) {
1553 			positive = true;
1554 			count = 1;
1555 		} else {
1556 			error(_("illegal CORRECTION field on Leap line"));
1557 			return;
1558 		}
1559 		if ((lp = byword(fields[LP_ROLL], leap_types)) == NULL) {
1560 			error(_(
1561 				"illegal Rolling/Stationary field on Leap line"
1562 				));
1563 			return;
1564 		}
1565 		t = tadd(t, tod);
1566 		if (t < 0) {
1567 			error(_("leap second precedes Epoch"));
1568 			return;
1569 		}
1570 		leapadd(t, positive, lp->l_value, count);
1571 	}
1572 }
1573 
1574 static void
1575 inlink(char **fields, int nfields)
1576 {
1577 	struct link	l;
1578 
1579 	if (nfields != LINK_FIELDS) {
1580 		error(_("wrong number of fields on Link line"));
1581 		return;
1582 	}
1583 	if (*fields[LF_FROM] == '\0') {
1584 		error(_("blank FROM field on Link line"));
1585 		return;
1586 	}
1587 	if (! namecheck(fields[LF_TO]))
1588 	  return;
1589 	l.l_filename = filename;
1590 	l.l_linenum = linenum;
1591 	l.l_from = ecpyalloc(fields[LF_FROM]);
1592 	l.l_to = ecpyalloc(fields[LF_TO]);
1593 	links = growalloc(links, sizeof *links, nlinks, &nlinks_alloc);
1594 	links[nlinks++] = l;
1595 }
1596 
1597 static void
1598 rulesub(struct rule *rp, const char *loyearp, const char *hiyearp,
1599     const char *typep, const char *monthp, const char *dayp,
1600     const char *timep)
1601 {
1602 	const struct lookup *	lp;
1603 	const char *		cp;
1604 	char *			dp;
1605 	char *			ep;
1606 	char			xs;
1607 
1608 	if ((lp = byword(monthp, mon_names)) == NULL) {
1609 		error(_("invalid month name"));
1610 		return;
1611 	}
1612 	rp->r_month = lp->l_value;
1613 	rp->r_todisstd = false;
1614 	rp->r_todisgmt = false;
1615 	dp = ecpyalloc(timep);
1616 	if (*dp != '\0') {
1617 		ep = dp + strlen(dp) - 1;
1618 		switch (lowerit(*ep)) {
1619 			case 's':	/* Standard */
1620 				rp->r_todisstd = true;
1621 				rp->r_todisgmt = false;
1622 				*ep = '\0';
1623 				break;
1624 			case 'w':	/* Wall */
1625 				rp->r_todisstd = false;
1626 				rp->r_todisgmt = false;
1627 				*ep = '\0';
1628 				break;
1629 			case 'g':	/* Greenwich */
1630 			case 'u':	/* Universal */
1631 			case 'z':	/* Zulu */
1632 				rp->r_todisstd = true;
1633 				rp->r_todisgmt = true;
1634 				*ep = '\0';
1635 				break;
1636 		}
1637 	}
1638 	rp->r_tod = gethms(dp, _("invalid time of day"));
1639 	free(dp);
1640 	/*
1641 	** Year work.
1642 	*/
1643 	cp = loyearp;
1644 	lp = byword(cp, begin_years);
1645 	rp->r_lowasnum = lp == NULL;
1646 	if (!rp->r_lowasnum) switch (lp->l_value) {
1647 		case YR_MINIMUM:
1648 			rp->r_loyear = ZIC_MIN;
1649 			break;
1650 		case YR_MAXIMUM:
1651 			rp->r_loyear = ZIC_MAX;
1652 			break;
1653 		default:	/* "cannot happen" */
1654 			fprintf(stderr,
1655 				_("%s: panic: Invalid l_value %d\n"),
1656 				progname, lp->l_value);
1657 			exit(EXIT_FAILURE);
1658 	} else if (sscanf(cp, "%"SCNdZIC"%c", &rp->r_loyear, &xs) != 1) {
1659 		error(_("invalid starting year"));
1660 		return;
1661 	}
1662 	cp = hiyearp;
1663 	lp = byword(cp, end_years);
1664 	rp->r_hiwasnum = lp == NULL;
1665 	if (!rp->r_hiwasnum) switch (lp->l_value) {
1666 		case YR_MINIMUM:
1667 			rp->r_hiyear = ZIC_MIN;
1668 			break;
1669 		case YR_MAXIMUM:
1670 			rp->r_hiyear = ZIC_MAX;
1671 			break;
1672 		case YR_ONLY:
1673 			rp->r_hiyear = rp->r_loyear;
1674 			break;
1675 		default:	/* "cannot happen" */
1676 			fprintf(stderr,
1677 				_("%s: panic: Invalid l_value %d\n"),
1678 				progname, lp->l_value);
1679 			exit(EXIT_FAILURE);
1680 	} else if (sscanf(cp, "%"SCNdZIC"%c", &rp->r_hiyear, &xs) != 1) {
1681 		error(_("invalid ending year"));
1682 		return;
1683 	}
1684 	if (rp->r_loyear > rp->r_hiyear) {
1685 		error(_("starting year greater than ending year"));
1686 		return;
1687 	}
1688 	if (*typep == '\0')
1689 		rp->r_yrtype = NULL;
1690 	else {
1691 		if (rp->r_loyear == rp->r_hiyear) {
1692 			error(_("typed single year"));
1693 			return;
1694 		}
1695 		warning(_("year type \"%s\" is obsolete; use \"-\" instead"),
1696 			typep);
1697 		rp->r_yrtype = ecpyalloc(typep);
1698 	}
1699 	/*
1700 	** Day work.
1701 	** Accept things such as:
1702 	**	1
1703 	**	lastSunday
1704 	**	last-Sunday (undocumented; warn about this)
1705 	**	Sun<=20
1706 	**	Sun>=7
1707 	*/
1708 	dp = ecpyalloc(dayp);
1709 	if ((lp = byword(dp, lasts)) != NULL) {
1710 		rp->r_dycode = DC_DOWLEQ;
1711 		rp->r_wday = lp->l_value;
1712 		rp->r_dayofmonth = len_months[1][rp->r_month];
1713 	} else {
1714 		if ((ep = strchr(dp, '<')) != 0)
1715 			rp->r_dycode = DC_DOWLEQ;
1716 		else if ((ep = strchr(dp, '>')) != 0)
1717 			rp->r_dycode = DC_DOWGEQ;
1718 		else {
1719 			ep = dp;
1720 			rp->r_dycode = DC_DOM;
1721 		}
1722 		if (rp->r_dycode != DC_DOM) {
1723 			*ep++ = 0;
1724 			if (*ep++ != '=') {
1725 				error(_("invalid day of month"));
1726 				free(dp);
1727 				return;
1728 			}
1729 			if ((lp = byword(dp, wday_names)) == NULL) {
1730 				error(_("invalid weekday name"));
1731 				free(dp);
1732 				return;
1733 			}
1734 			rp->r_wday = lp->l_value;
1735 		}
1736 		if (sscanf(ep, "%d%c", &rp->r_dayofmonth, &xs) != 1 ||
1737 			rp->r_dayofmonth <= 0 ||
1738 			(rp->r_dayofmonth > len_months[1][rp->r_month])) {
1739 				error(_("invalid day of month"));
1740 				free(dp);
1741 				return;
1742 		}
1743 	}
1744 	free(dp);
1745 }
1746 
1747 static void
1748 convert(const int_fast32_t val, char *const buf)
1749 {
1750 	int	i;
1751 	int	shift;
1752 	unsigned char *const b = (unsigned char *) buf;
1753 
1754 	for (i = 0, shift = 24; i < 4; ++i, shift -= 8)
1755 		b[i] = val >> shift;
1756 }
1757 
1758 static void
1759 convert64(const zic_t val, char *const buf)
1760 {
1761 	int	i;
1762 	int	shift;
1763 	unsigned char *const b = (unsigned char *) buf;
1764 
1765 	for (i = 0, shift = 56; i < 8; ++i, shift -= 8)
1766 		b[i] = val >> shift;
1767 }
1768 
1769 static void
1770 puttzcode(const int_fast32_t val, FILE *const fp)
1771 {
1772 	char	buf[4];
1773 
1774 	convert(val, buf);
1775 	fwrite(buf, sizeof buf, (size_t) 1, fp);
1776 }
1777 
1778 static void
1779 puttzcodepass(zic_t val, FILE *fp, int pass)
1780 {
1781   if (pass == 1)
1782     puttzcode(val, fp);
1783   else {
1784 	char	buf[8];
1785 
1786 	convert64(val, buf);
1787 	fwrite(buf, sizeof buf, (size_t) 1, fp);
1788     }
1789 }
1790 
1791 static int
1792 atcomp(const void *avp, const void *bvp)
1793 {
1794 	const zic_t	a = ((const struct attype *) avp)->at;
1795 	const zic_t	b = ((const struct attype *) bvp)->at;
1796 
1797 	return (a < b) ? -1 : (a > b);
1798 }
1799 
1800 static void
1801 swaptypes(int i, int j)
1802 {
1803   { zic_t t = gmtoffs[i]; gmtoffs[i] = gmtoffs[j]; gmtoffs[j] = t; }
1804   { char t = isdsts[i]; isdsts[i] = isdsts[j]; isdsts[j] = t; }
1805   { unsigned char t = abbrinds[i]; abbrinds[i] = abbrinds[j];
1806     abbrinds[j] = t; }
1807   { bool t = ttisstds[i]; ttisstds[i] = ttisstds[j]; ttisstds[j] = t; }
1808   { bool t = ttisgmts[i]; ttisgmts[i] = ttisgmts[j]; ttisgmts[j] = t; }
1809 }
1810 
1811 struct timerange {
1812   int defaulttype;
1813   ptrdiff_t base, count;
1814   int leapbase, leapcount;
1815 };
1816 
1817 static struct timerange
1818 limitrange(struct timerange r, zic_t lo, zic_t hi,
1819 	   zic_t const *ats, unsigned char const *types)
1820 {
1821   while (0 < r.count && ats[r.base] < lo) {
1822     r.defaulttype = types[r.base];
1823     r.count--;
1824     r.base++;
1825   }
1826   while (0 < r.leapcount && trans[r.leapbase] < lo) {
1827     r.leapcount--;
1828     r.leapbase++;
1829   }
1830 
1831   if (hi < ZIC_MAX) {
1832     while (0 < r.count && hi + 1 < ats[r.base + r.count - 1])
1833       r.count--;
1834     while (0 < r.leapcount && hi + 1 < trans[r.leapbase + r.leapcount - 1])
1835       r.leapcount--;
1836   }
1837 
1838   return r;
1839 }
1840 
1841 static void
1842 writezone(const char *const name, const char *const string, char version,
1843 	int defaulttype)
1844 {
1845 	FILE *			fp;
1846 	ptrdiff_t		i, j;
1847 	int			pass;
1848 	static const struct tzhead	tzh0;
1849 	static struct tzhead		tzh;
1850 	bool dir_checked = false;
1851 	zic_t one = 1;
1852 	zic_t y2038_boundary = one << 31;
1853 	ptrdiff_t nats = timecnt + WORK_AROUND_QTBUG_53071;
1854 
1855 	/* Allocate the ATS and TYPES arrays via a single malloc,
1856 	   as this is a bit faster.  */
1857 	zic_t *ats = zic_malloc(align_to(size_product(nats, sizeof *ats + 1),
1858 				_Alignof(zic_t)));
1859 	void *typesptr = ats + nats;
1860 	unsigned char *types = typesptr;
1861 	struct timerange rangeall, range32, range64;
1862 
1863 	/*
1864 	** Sort.
1865 	*/
1866 	if (timecnt > 1)
1867 		qsort(attypes, (size_t) timecnt, sizeof *attypes, atcomp);
1868 	/*
1869 	** Optimize.
1870 	*/
1871 	{
1872 		ptrdiff_t fromi, toi;
1873 
1874 		toi = 0;
1875 		fromi = 0;
1876 		for ( ; fromi < timecnt; ++fromi) {
1877 			if (toi != 0 && ((attypes[fromi].at +
1878 				gmtoffs[attypes[toi - 1].type]) <=
1879 				(attypes[toi - 1].at + gmtoffs[toi == 1 ? 0
1880 				: attypes[toi - 2].type]))) {
1881 					attypes[toi - 1].type =
1882 						attypes[fromi].type;
1883 					continue;
1884 			}
1885 			if (toi == 0
1886 			    || attypes[fromi].dontmerge
1887 			    || attypes[toi - 1].type != attypes[fromi].type)
1888 					attypes[toi++] = attypes[fromi];
1889 		}
1890 		timecnt = toi;
1891 	}
1892 
1893 	if (noise && timecnt > 1200) {
1894 	  if (timecnt > TZ_MAX_TIMES)
1895 		warning(_("reference clients mishandle"
1896 			  " more than %d transition times"),
1897 			TZ_MAX_TIMES);
1898 	  else
1899 		warning(_("pre-2014 clients may mishandle"
1900 			  " more than 1200 transition times"));
1901 	}
1902 	/*
1903 	** Transfer.
1904 	*/
1905 	for (i = 0; i < timecnt; ++i) {
1906 		ats[i] = attypes[i].at;
1907 		types[i] = attypes[i].type;
1908 	}
1909 
1910 	/*
1911 	** Correct for leap seconds.
1912 	*/
1913 	for (i = 0; i < timecnt; ++i) {
1914 		j = leapcnt;
1915 		while (--j >= 0)
1916 			if (ats[i] > trans[j] - corr[j]) {
1917 				ats[i] = tadd(ats[i], corr[j]);
1918 				break;
1919 			}
1920 	}
1921 
1922 	/* Work around QTBUG-53071 for timestamps less than y2038_boundary - 1,
1923 	   by inserting a no-op transition at time y2038_boundary - 1.
1924 	   This works only for timestamps before the boundary, which
1925 	   should be good enough in practice as QTBUG-53071 should be
1926 	   long-dead by 2038.  Do this after correcting for leap
1927 	   seconds, as the idea is to insert a transition just before
1928 	   32-bit time_t rolls around, and this occurs at a slightly
1929 	   different moment if transitions are leap-second corrected.  */
1930 	if (WORK_AROUND_QTBUG_53071 && timecnt != 0
1931 	    && ats[timecnt - 1] < y2038_boundary - 1 && strchr(string, '<')) {
1932 	  ats[timecnt] = y2038_boundary - 1;
1933 	  types[timecnt] = types[timecnt - 1];
1934 	  timecnt++;
1935 	}
1936 
1937 	rangeall.defaulttype = defaulttype;
1938 	rangeall.base = rangeall.leapbase = 0;
1939 	rangeall.count = timecnt;
1940 	rangeall.leapcount = leapcnt;
1941 	range64 = limitrange(rangeall, lo_time, hi_time, ats, types);
1942 	range32 = limitrange(range64, INT32_MIN, INT32_MAX, ats, types);
1943 
1944 	/*
1945 	** Remove old file, if any, to snap links.
1946 	*/
1947 	if (remove(name) == 0)
1948 		dir_checked = true;
1949 	else if (errno != ENOENT) {
1950 		const char *e = strerror(errno);
1951 
1952 		fprintf(stderr, _("%s: Can't remove %s/%s: %s\n"),
1953 			progname, directory, name, e);
1954 		exit(EXIT_FAILURE);
1955 	}
1956 	fp = fopen(name, "wb");
1957 	if (!fp) {
1958 	  int fopen_errno = errno;
1959 	  if (fopen_errno == ENOENT && !dir_checked) {
1960 	    mkdirs(name, true);
1961 	    fp = fopen(name, "wb");
1962 	    fopen_errno = errno;
1963 	  }
1964 	  if (!fp) {
1965 	    fprintf(stderr, _("%s: Can't create %s/%s: %s\n"),
1966 		    progname, directory, name, strerror(fopen_errno));
1967 	    exit(EXIT_FAILURE);
1968 	  }
1969 	}
1970 	for (pass = 1; pass <= 2; ++pass) {
1971 		ptrdiff_t	thistimei, thistimecnt, thistimelim;
1972 		int	thisleapi, thisleapcnt, thisleaplim;
1973 		int currenttype, thisdefaulttype;
1974 		bool locut, hicut;
1975 		zic_t lo;
1976 		int old0;
1977 		char		omittype[TZ_MAX_TYPES];
1978 		int		typemap[TZ_MAX_TYPES];
1979 		int	thistypecnt;
1980 		char		thischars[TZ_MAX_CHARS];
1981 		int		thischarcnt;
1982 		bool		toomanytimes;
1983 		int		indmap[TZ_MAX_CHARS];
1984 
1985 		if (pass == 1) {
1986 			/* Arguably the default time type in the 32-bit data
1987 			   should be range32.defaulttype, which is suited for
1988 			   timestamps just before INT32_MIN.  However, zic
1989 			   traditionally used the time type of the indefinite
1990 			   past instead.  Internet RFC 8532 says readers should
1991 			   ignore 32-bit data, so this discrepancy matters only
1992 			   to obsolete readers where the traditional type might
1993 			   be more appropriate even if it's "wrong".  So, use
1994 			   the historical zic value, unless -r specifies a low
1995 			   cutoff that excludes some 32-bit timestamps.  */
1996 			thisdefaulttype = (lo_time <= INT32_MIN
1997 					   ? range64.defaulttype
1998 					   : range32.defaulttype);
1999 
2000 			thistimei = range32.base;
2001 			thistimecnt = range32.count;
2002 			toomanytimes = thistimecnt >> 31 >> 1 != 0;
2003 			thisleapi = range32.leapbase;
2004 			thisleapcnt = range32.leapcount;
2005 			locut = INT32_MIN < lo_time;
2006 			hicut = hi_time < INT32_MAX;
2007 		} else {
2008 			thisdefaulttype = range64.defaulttype;
2009 			thistimei = range64.base;
2010 			thistimecnt = range64.count;
2011 			toomanytimes = thistimecnt >> 31 >> 31 >> 2 != 0;
2012 			thisleapi = range64.leapbase;
2013 			thisleapcnt = range64.leapcount;
2014 			locut = min_time < lo_time;
2015 			hicut = hi_time < max_time;
2016 		}
2017 		if (toomanytimes)
2018 		  error(_("too many transition times"));
2019 
2020 		/* Keep the last too-low transition if no transition is
2021 		   exactly at LO.  The kept transition will be output as
2022 		   a LO "transition"; see "Output a LO_TIME transition"
2023 		   below.  This is needed when the output is truncated at
2024 		   the start, and is also useful when catering to buggy
2025 		   32-bit clients that do not use time type 0 for
2026 		   timestamps before the first transition.  */
2027 		if (0 < thistimei && ats[thistimei] != lo_time) {
2028 		  thistimei--;
2029 		  thistimecnt++;
2030 		  locut = false;
2031 		}
2032 
2033 		thistimelim = thistimei + thistimecnt;
2034 		thisleaplim = thisleapi + thisleapcnt;
2035 		if (thistimecnt != 0) {
2036 		  if (ats[thistimei] == lo_time)
2037 		    locut = false;
2038 		  if (hi_time < ZIC_MAX && ats[thistimelim - 1] == hi_time + 1)
2039 		    hicut = false;
2040 		}
2041 		memset(omittype, true, typecnt);
2042 		omittype[thisdefaulttype] = false;
2043 		for (i = thistimei; i < thistimelim; i++)
2044 		  omittype[types[i]] = false;
2045 
2046 		/* Reorder types to make THISDEFAULTTYPE type 0.
2047 		   Use TYPEMAP to swap OLD0 and THISDEFAULTTYPE so that
2048 		   THISDEFAULTTYPE appears as type 0 in the output instead
2049 		   of OLD0.  TYPEMAP also omits unused types.  */
2050 		old0 = strlen(omittype);
2051 		swaptypes(old0, thisdefaulttype);
2052 
2053 #ifndef LEAVE_SOME_PRE_2011_SYSTEMS_IN_THE_LURCH
2054 		/*
2055 		** For some pre-2011 systems: if the last-to-be-written
2056 		** standard (or daylight) type has an offset different from the
2057 		** most recently used offset,
2058 		** append an (unused) copy of the most recently used type
2059 		** (to help get global "altzone" and "timezone" variables
2060 		** set correctly).
2061 		*/
2062 		{
2063 			int	mrudst, mrustd, hidst, histd, type;
2064 
2065 			hidst = histd = mrudst = mrustd = -1;
2066 			for (i = thistimei; i < thistimelim; ++i)
2067 				if (isdsts[types[i]])
2068 					mrudst = types[i];
2069 				else	mrustd = types[i];
2070 			for (i = old0; i < typecnt; i++)
2071 				if (!omittype[i]) {
2072 					if (isdsts[i])
2073 						hidst = i;
2074 					else	histd = i;
2075 				}
2076 			if (hidst >= 0 && mrudst >= 0 && hidst != mrudst &&
2077 				gmtoffs[hidst] != gmtoffs[mrudst]) {
2078 					isdsts[mrudst] = -1;
2079 					type = addtype(gmtoffs[mrudst],
2080 						&chars[abbrinds[mrudst]],
2081 						true,
2082 						ttisstds[mrudst],
2083 						ttisgmts[mrudst]);
2084 					isdsts[mrudst] = 1;
2085 					omittype[type] = false;
2086 			}
2087 			if (histd >= 0 && mrustd >= 0 && histd != mrustd &&
2088 				gmtoffs[histd] != gmtoffs[mrustd]) {
2089 					isdsts[mrustd] = -1;
2090 					type = addtype(gmtoffs[mrustd],
2091 						&chars[abbrinds[mrustd]],
2092 						false,
2093 						ttisstds[mrustd],
2094 						ttisgmts[mrustd]);
2095 					isdsts[mrustd] = 0;
2096 					omittype[type] = true;
2097 			}
2098 		}
2099 #endif /* !defined LEAVE_SOME_PRE_2011_SYSTEMS_IN_THE_LURCH */
2100  		thistypecnt = 0;
2101 		for (i = old0; i < typecnt; i++)
2102 		  if (!omittype[i])
2103 		    typemap[i == old0 ? thisdefaulttype
2104 			    : i == thisdefaulttype ? old0 : i]
2105 		      = thistypecnt++;
2106 
2107 		for (i = 0; i < (int)(sizeof indmap / sizeof indmap[0]); ++i)
2108 			indmap[i] = -1;
2109 		thischarcnt = 0;
2110 		for (i = old0; i < typecnt; i++) {
2111 			char *	thisabbr;
2112 
2113 			if (omittype[i])
2114 				continue;
2115 			if (indmap[abbrinds[i]] >= 0)
2116 				continue;
2117 			thisabbr = &chars[abbrinds[i]];
2118 			for (j = 0; j < thischarcnt; ++j)
2119 				if (strcmp(&thischars[j], thisabbr) == 0)
2120 					break;
2121 			if (j == thischarcnt) {
2122 				strcpy(&thischars[thischarcnt], thisabbr);
2123 				thischarcnt += strlen(thisabbr) + 1;
2124 			}
2125 			indmap[abbrinds[i]] = j;
2126 		}
2127 #define DO(field)	fwrite(tzh.field, sizeof tzh.field, (size_t) 1, fp)
2128 		tzh = tzh0;
2129 		memcpy(tzh.tzh_magic, TZ_MAGIC, sizeof tzh.tzh_magic);
2130 		tzh.tzh_version[0] = version;
2131 		convert(thistypecnt, tzh.tzh_ttisgmtcnt);
2132 		convert(thistypecnt, tzh.tzh_ttisstdcnt);
2133 		convert(thisleapcnt, tzh.tzh_leapcnt);
2134 		convert(locut + thistimecnt + hicut, tzh.tzh_timecnt);
2135 		convert(thistypecnt, tzh.tzh_typecnt);
2136 		convert(thischarcnt, tzh.tzh_charcnt);
2137 		DO(tzh_magic);
2138 		DO(tzh_version);
2139 		DO(tzh_reserved);
2140 		DO(tzh_ttisgmtcnt);
2141 		DO(tzh_ttisstdcnt);
2142 		DO(tzh_leapcnt);
2143 		DO(tzh_timecnt);
2144 		DO(tzh_typecnt);
2145 		DO(tzh_charcnt);
2146 #undef DO
2147 		/* Output a LO_TIME transition if needed; see limitrange.
2148 		   But do not go below the minimum representable value
2149 		   for this pass.  */
2150 		lo = pass == 1 && lo_time < INT32_MIN ? INT32_MIN : lo_time;
2151 
2152 		if (locut)
2153 		  puttzcodepass(lo, fp, pass);
2154 		for (i = thistimei; i < thistimelim; ++i) {
2155 		  zic_t at = ats[i] < lo ? lo : ats[i];
2156 		  puttzcodepass(at, fp, pass);
2157 		}
2158 		if (hicut)
2159 		  puttzcodepass(hi_time + 1, fp, pass);
2160 		currenttype = 0;
2161 		if (locut)
2162 		  putc(currenttype, fp);
2163 		for (i = thistimei; i < thistimelim; ++i) {
2164 		  currenttype = typemap[types[i]];
2165 		  putc(currenttype, fp);
2166  		}
2167 		if (hicut)
2168 		  putc(currenttype, fp);
2169 
2170 		for (i = old0; i < typecnt; i++)
2171 			if (!omittype[i]) {
2172 				puttzcode(gmtoffs[i], fp);
2173 				putc(isdsts[i], fp);
2174 				putc((unsigned char) indmap[abbrinds[i]], fp);
2175 			}
2176 		if (thischarcnt != 0)
2177 			fwrite(thischars, sizeof thischars[0],
2178 				(size_t) thischarcnt, fp);
2179 		for (i = thisleapi; i < thisleaplim; ++i) {
2180 			zic_t	todo;
2181 
2182 			if (roll[i]) {
2183 				if (timecnt == 0 || trans[i] < ats[0]) {
2184 					j = 0;
2185 					while (isdsts[j])
2186 						if (++j >= typecnt) {
2187 							j = 0;
2188 							break;
2189 						}
2190 				} else {
2191 					j = 1;
2192 					while (j < timecnt &&
2193 						trans[i] >= ats[j])
2194 							++j;
2195 					j = types[j - 1];
2196 				}
2197 				todo = tadd(trans[i], -gmtoffs[j]);
2198 			} else	todo = trans[i];
2199 			puttzcodepass(todo, fp, pass);
2200 			puttzcode(corr[i], fp);
2201 		}
2202 		for (i = old0; i < typecnt; i++)
2203 			if (!omittype[i])
2204 				putc(ttisstds[i], fp);
2205 		for (i = old0; i < typecnt; i++)
2206 			if (!omittype[i])
2207 				putc(ttisgmts[i], fp);
2208 		swaptypes(old0, thisdefaulttype);
2209 	}
2210 	fprintf(fp, "\n%s\n", string);
2211 	close_file(fp, directory, name);
2212 	free(ats);
2213 }
2214 
2215 static char const *
2216 abbroffset(char *buf, zic_t offset)
2217 {
2218 	char sign = '+';
2219 	int seconds, minutes;
2220 
2221 	if (offset < 0) {
2222 		offset = -offset;
2223 		sign = '-';
2224 	}
2225 
2226 	seconds = offset % SECSPERMIN;
2227 	offset /= SECSPERMIN;
2228 	minutes = offset % MINSPERHOUR;
2229 	offset /= MINSPERHOUR;
2230 	if (100 <= offset) {
2231 		error(_("%%z UT offset magnitude exceeds 99:59:59"));
2232 		return "%z";
2233 	} else {
2234 		char *p = buf;
2235 		*p++ = sign;
2236 		*p++ = '0' + offset / 10;
2237 		*p++ = '0' + offset % 10;
2238 		if (minutes | seconds) {
2239 			*p++ = '0' + minutes / 10;
2240 			*p++ = '0' + minutes % 10;
2241 			if (seconds) {
2242 				*p++ = '0' + seconds / 10;
2243 				*p++ = '0' + seconds % 10;
2244 			}
2245 		}
2246 		*p = '\0';
2247 		return buf;
2248 	}
2249 }
2250 
2251 static size_t
2252 doabbr(char *abbr, int abbrlen, struct zone const *zp, const char *letters,
2253     bool isdst, zic_t stdoff, bool doquotes)
2254 {
2255 	char *	cp;
2256 	char *	slashp;
2257 	size_t	len;
2258 	char const *format = zp->z_format;
2259 
2260 	slashp = strchr(format, '/');
2261 	if (slashp == NULL) {
2262 		char letterbuf[PERCENT_Z_LEN_BOUND + 1];
2263 		if (zp->z_format_specifier == 'z')
2264 			letters = abbroffset(letterbuf, zp->z_gmtoff + stdoff);
2265 		else if (!letters)
2266 			letters = "%s";
2267 		snprintf(abbr, abbrlen, format, letters);
2268 	} else if (isdst) {
2269 		strlcpy(abbr, slashp + 1, abbrlen);
2270 	} else {
2271 		memcpy(abbr, format, slashp - format);
2272 		abbr[slashp - format] = '\0';
2273 	}
2274 	len = strlen(abbr);
2275 	if (!doquotes)
2276 		return len;
2277 	for (cp = abbr; is_alpha(*cp); cp++)
2278 		continue;
2279 	if (len > 0 && *cp == '\0')
2280 		return len;
2281 	abbr[len + 2] = '\0';
2282 	abbr[len + 1] = '>';
2283 	memmove(abbr + 1, abbr, len);
2284 	abbr[0] = '<';
2285 	return len + 2;
2286 }
2287 
2288 static void
2289 updateminmax(const zic_t x)
2290 {
2291 	if (min_year > x)
2292 		min_year = x;
2293 	if (max_year < x)
2294 		max_year = x;
2295 }
2296 
2297 static int
2298 stringoffset(char *result, zic_t offset)
2299 {
2300 	int	hours;
2301 	int	minutes;
2302 	int	seconds;
2303 	bool negative = offset < 0;
2304 	int len = negative;
2305 
2306 	if (negative) {
2307 		offset = -offset;
2308 		result[0] = '-';
2309 	}
2310 	seconds = offset % SECSPERMIN;
2311 	offset /= SECSPERMIN;
2312 	minutes = offset % MINSPERHOUR;
2313 	offset /= MINSPERHOUR;
2314 	hours = offset;
2315 	if (hours >= HOURSPERDAY * DAYSPERWEEK) {
2316 		result[0] = '\0';
2317 		return 0;
2318 	}
2319 	len += sprintf(result + len, "%d", hours);
2320 	if (minutes != 0 || seconds != 0) {
2321 		len += sprintf(result + len, ":%02d", minutes);
2322 		if (seconds != 0)
2323 			len += sprintf(result + len, ":%02d", seconds);
2324 	}
2325 	return len;
2326 }
2327 
2328 static int
2329 stringrule(char *result, const struct rule *const rp, const zic_t dstoff,
2330     const zic_t gmtoff)
2331 {
2332 	zic_t	tod = rp->r_tod;
2333 	int	compat = 0;
2334 
2335 	if (rp->r_dycode == DC_DOM) {
2336 		int	month, total;
2337 
2338 		if (rp->r_dayofmonth == 29 && rp->r_month == TM_FEBRUARY)
2339 			return -1;
2340 		total = 0;
2341 		for (month = 0; month < rp->r_month; ++month)
2342 			total += len_months[0][month];
2343 		/* Omit the "J" in Jan and Feb, as that's shorter.  */
2344 		if (rp->r_month <= 1)
2345 		  result += sprintf(result, "%d", total + rp->r_dayofmonth - 1);
2346 		else
2347 		  result += sprintf(result, "J%d", total + rp->r_dayofmonth);
2348 	} else {
2349 		int	week;
2350 		int	wday = rp->r_wday;
2351 		int	wdayoff;
2352 
2353 		if (rp->r_dycode == DC_DOWGEQ) {
2354 			wdayoff = (rp->r_dayofmonth - 1) % DAYSPERWEEK;
2355 			if (wdayoff)
2356 				compat = 2013;
2357 			wday -= wdayoff;
2358 			tod += wdayoff * SECSPERDAY;
2359 			week = 1 + (rp->r_dayofmonth - 1) / DAYSPERWEEK;
2360 		} else if (rp->r_dycode == DC_DOWLEQ) {
2361 			if (rp->r_dayofmonth == len_months[1][rp->r_month])
2362 				week = 5;
2363 			else {
2364 				wdayoff = rp->r_dayofmonth % DAYSPERWEEK;
2365 				if (wdayoff)
2366 					compat = 2013;
2367 				wday -= wdayoff;
2368 				tod += wdayoff * SECSPERDAY;
2369 				week = rp->r_dayofmonth / DAYSPERWEEK;
2370 			}
2371 		} else	return -1;	/* "cannot happen" */
2372 		if (wday < 0)
2373 			wday += DAYSPERWEEK;
2374 		result += sprintf(result, "M%d.%d.%d",
2375 				  rp->r_month + 1, week, wday);
2376 	}
2377 	if (rp->r_todisgmt)
2378 		tod += gmtoff;
2379 	if (rp->r_todisstd && !rp->r_isdst)
2380 		tod += dstoff;
2381 	if (tod != 2 * SECSPERMIN * MINSPERHOUR) {
2382 		*result++ = '/';
2383 		if (! stringoffset(result, tod))
2384 			return -1;
2385 		if (tod < 0) {
2386 			if (compat < 2013)
2387 				compat = 2013;
2388 		} else if (SECSPERDAY <= tod) {
2389 			if (compat < 1994)
2390 				compat = 1994;
2391 		}
2392 	}
2393 	return compat;
2394 }
2395 
2396 static int
2397 rule_cmp(struct rule const *a, struct rule const *b)
2398 {
2399 	if (!a)
2400 		return -!!b;
2401 	if (!b)
2402 		return 1;
2403 	if (a->r_hiyear != b->r_hiyear)
2404 		return a->r_hiyear < b->r_hiyear ? -1 : 1;
2405 	if (a->r_month - b->r_month != 0)
2406 		return a->r_month - b->r_month;
2407 	return a->r_dayofmonth - b->r_dayofmonth;
2408 }
2409 
2410 enum { YEAR_BY_YEAR_ZONE = 1 };
2411 
2412 static int
2413 stringzone(char *result, const int resultlen, const struct zone *const zpfirst,
2414     const int zonecount)
2415 {
2416 	const struct zone *	zp;
2417 	struct rule *		rp;
2418 	struct rule *		stdrp;
2419 	struct rule *		dstrp;
2420 	ptrdiff_t	i;
2421 	const char *		abbrvar;
2422 	int			compat = 0;
2423 	int			c;
2424 	size_t			len;
2425 	int			offsetlen;
2426 	struct rule		stdr, dstr;
2427 
2428 	result[0] = '\0';
2429 
2430 	/* Internet RFC 8536 section 5.1 says to use an empty TZ string if
2431 	   future timestamps are truncated.  */
2432 	if (hi_time < max_time)
2433 	  return -1;
2434 
2435 	zp = zpfirst + zonecount - 1;
2436 	stdrp = dstrp = NULL;
2437 	for (i = 0; i < zp->z_nrules; ++i) {
2438 		rp = &zp->z_rules[i];
2439 		if (rp->r_hiwasnum || rp->r_hiyear != ZIC_MAX)
2440 			continue;
2441 		if (rp->r_yrtype != NULL)
2442 			continue;
2443 		if (!rp->r_isdst) {
2444 			if (stdrp == NULL)
2445 				stdrp = rp;
2446 			else	return -1;
2447 		} else {
2448 			if (dstrp == NULL)
2449 				dstrp = rp;
2450 			else	return -1;
2451 		}
2452 	}
2453 	if (stdrp == NULL && dstrp == NULL) {
2454 		/*
2455 		** There are no rules running through "max".
2456 		** Find the latest std rule in stdabbrrp
2457 		** and latest rule of any type in stdrp.
2458 		*/
2459 		struct rule *stdabbrrp = NULL;
2460 		for (i = 0; i < zp->z_nrules; ++i) {
2461 			rp = &zp->z_rules[i];
2462 			if (!rp->r_isdst && rule_cmp(stdabbrrp, rp) < 0)
2463 				stdabbrrp = rp;
2464 			if (rule_cmp(stdrp, rp) < 0)
2465 				stdrp = rp;
2466 		}
2467 		/*
2468 		** Horrid special case: if year is 2037,
2469 		** presume this is a zone handled on a year-by-year basis;
2470 		** do not try to apply a rule to the zone.
2471 		*/
2472 		if (stdrp != NULL && stdrp->r_hiyear == 2037)
2473 			return YEAR_BY_YEAR_ZONE;
2474 
2475 		if (stdrp != NULL && stdrp->r_isdst) {
2476 			/* Perpetual DST.  */
2477 			dstr.r_month = TM_JANUARY;
2478 			dstr.r_dycode = DC_DOM;
2479 			dstr.r_dayofmonth = 1;
2480 			dstr.r_tod = 0;
2481 			dstr.r_todisstd = dstr.r_todisgmt = false;
2482 			dstr.r_isdst = stdrp->r_isdst;
2483 			dstr.r_stdoff = stdrp->r_stdoff;
2484 			dstr.r_abbrvar = stdrp->r_abbrvar;
2485 			stdr.r_month = TM_DECEMBER;
2486 			stdr.r_dycode = DC_DOM;
2487 			stdr.r_dayofmonth = 31;
2488 			stdr.r_tod = SECSPERDAY + stdrp->r_stdoff;
2489 			stdr.r_todisstd = stdr.r_todisgmt = false;
2490 			stdr.r_isdst = false;
2491 			stdr.r_stdoff = 0;
2492 			stdr.r_abbrvar
2493 			  = (stdabbrrp ? stdabbrrp->r_abbrvar : "");
2494 			dstrp = &dstr;
2495 			stdrp = &stdr;
2496 		}
2497 	}
2498 	if (stdrp == NULL && (zp->z_nrules != 0 || zp->z_isdst))
2499 		return -1;
2500 	abbrvar = (stdrp == NULL) ? "" : stdrp->r_abbrvar;
2501 	len = doabbr(result, resultlen, zp, abbrvar, false, 0, true);
2502 	offsetlen = stringoffset(result + len, -zp->z_gmtoff);
2503 	if (! offsetlen) {
2504 		result[0] = '\0';
2505 		return -1;
2506 	}
2507 	len += offsetlen;
2508 	if (dstrp == NULL)
2509 		return compat;
2510 	len += doabbr(result + len, resultlen - len, zp, dstrp->r_abbrvar,
2511 		      dstrp->r_isdst, dstrp->r_stdoff, true);
2512 	if (dstrp->r_stdoff != SECSPERMIN * MINSPERHOUR) {
2513 		offsetlen = stringoffset(result + len,
2514 		    -(zp->z_gmtoff + dstrp->r_stdoff));
2515 		if (! offsetlen) {
2516 			result[0] = '\0';
2517 			return -1;
2518 		}
2519 		len += offsetlen;
2520 	}
2521 	result[len++] = ',';
2522 	c = stringrule(result + len, dstrp, dstrp->r_stdoff, zp->z_gmtoff);
2523 	if (c < 0) {
2524 		result[0] = '\0';
2525 		return -1;
2526 	}
2527 	if (compat < c)
2528 		compat = c;
2529 	len += strlen(result + len);
2530 	result[len++] = ',';
2531 	c = stringrule(result + len, stdrp, dstrp->r_stdoff, zp->z_gmtoff);
2532 	if (c < 0) {
2533 		result[0] = '\0';
2534 		return -1;
2535 	}
2536 	if (compat < c)
2537 		compat = c;
2538 	return compat;
2539 }
2540 
2541 static void
2542 outzone(const struct zone *zpfirst, ptrdiff_t zonecount)
2543 {
2544 	const struct zone *	zp;
2545 	struct rule *		rp;
2546 	ptrdiff_t		i, j;
2547 	bool			usestart, useuntil;
2548 	zic_t			starttime, untiltime;
2549 	zic_t			gmtoff;
2550 	zic_t			stdoff;
2551 	zic_t			year;
2552 	zic_t			startoff;
2553 	bool			startttisstd;
2554 	bool			startttisgmt;
2555 	int			type;
2556 	char *			startbuf;
2557 	char *			ab;
2558 	char *			envvar;
2559 	size_t			max_abbr_len;
2560 	size_t			max_envvar_len;
2561 	bool			prodstic; /* all rules are min to max */
2562 	int			compat;
2563 	bool			do_extend;
2564 	int			version;
2565 	ptrdiff_t lastatmax = -1;
2566 	zic_t one = 1;
2567 	zic_t y2038_boundary = one << 31;
2568 	zic_t max_year0;
2569 	int defaulttype = -1;
2570 
2571 	max_abbr_len = 2 + max_format_len + max_abbrvar_len;
2572 	max_envvar_len = 2 * max_abbr_len + 5 * 9;
2573 	startbuf = zic_malloc(max_abbr_len + 1);
2574 	ab = zic_malloc(max_abbr_len + 1);
2575 	envvar = zic_malloc(max_envvar_len + 1);
2576 	INITIALIZE(untiltime);
2577 	INITIALIZE(starttime);
2578 	/*
2579 	** Now. . .finally. . .generate some useful data!
2580 	*/
2581 	timecnt = 0;
2582 	typecnt = 0;
2583 	charcnt = 0;
2584 	prodstic = zonecount == 1;
2585 	/*
2586 	** Thanks to Earl Chew
2587 	** for noting the need to unconditionally initialize startttisstd.
2588 	*/
2589 	startttisstd = false;
2590 	startttisgmt = false;
2591 	min_year = max_year = EPOCH_YEAR;
2592 	if (leapseen) {
2593 		updateminmax(leapminyear);
2594 		updateminmax(leapmaxyear + (leapmaxyear < ZIC_MAX));
2595 	}
2596 	for (i = 0; i < zonecount; ++i) {
2597 		zp = &zpfirst[i];
2598 		if (i < zonecount - 1)
2599 			updateminmax(zp->z_untilrule.r_loyear);
2600 		for (j = 0; j < zp->z_nrules; ++j) {
2601 			rp = &zp->z_rules[j];
2602 			if (rp->r_lowasnum)
2603 				updateminmax(rp->r_loyear);
2604 			if (rp->r_hiwasnum)
2605 				updateminmax(rp->r_hiyear);
2606 			if (rp->r_lowasnum || rp->r_hiwasnum)
2607 				prodstic = false;
2608 		}
2609 	}
2610 	/*
2611 	** Generate lots of data if a rule can't cover all future times.
2612 	*/
2613 	compat = stringzone(envvar, max_envvar_len + 1, zpfirst, zonecount);
2614 	version = compat < 2013 ? ZIC_VERSION_PRE_2013 : ZIC_VERSION;
2615 	do_extend = compat < 0 || compat == YEAR_BY_YEAR_ZONE;
2616 	if (noise) {
2617 		if (!*envvar)
2618 			warning("%s %s",
2619 				_("no POSIX environment variable for zone"),
2620 				zpfirst->z_name);
2621 		else if (compat != 0 && compat != YEAR_BY_YEAR_ZONE) {
2622 			/* Circa-COMPAT clients, and earlier clients, might
2623 			   not work for this zone when given dates before
2624 			   1970 or after 2038.  */
2625 			warning(_("%s: pre-%d clients may mishandle"
2626 				  " distant timestamps"),
2627 				zpfirst->z_name, compat);
2628 		}
2629 	}
2630 	if (do_extend) {
2631 		/*
2632 		** Search through a couple of extra years past the obvious
2633 		** 400, to avoid edge cases.  For example, suppose a non-POSIX
2634 		** rule applies from 2012 onwards and has transitions in March
2635 		** and September, plus some one-off transitions in November
2636 		** 2013.  If zic looked only at the last 400 years, it would
2637 		** set max_year=2413, with the intent that the 400 years 2014
2638 		** through 2413 will be repeated.  The last transition listed
2639 		** in the tzfile would be in 2413-09, less than 400 years
2640 		** after the last one-off transition in 2013-11.  Two years
2641 		** might be overkill, but with the kind of edge cases
2642 		** available we're not sure that one year would suffice.
2643 		*/
2644 		enum { years_of_observations = YEARSPERREPEAT + 2 };
2645 
2646 		if (min_year >= ZIC_MIN + years_of_observations)
2647 			min_year -= years_of_observations;
2648 		else	min_year = ZIC_MIN;
2649 		if (max_year <= ZIC_MAX - years_of_observations)
2650 			max_year += years_of_observations;
2651 		else	max_year = ZIC_MAX;
2652 		/*
2653 		** Regardless of any of the above,
2654 		** for a "proDSTic" zone which specifies that its rules
2655 		** always have and always will be in effect,
2656 		** we only need one cycle to define the zone.
2657 		*/
2658 		if (prodstic) {
2659 			min_year = 1900;
2660 			max_year = min_year + years_of_observations;
2661 		}
2662 	}
2663 	/*
2664 	** For the benefit of older systems,
2665 	** generate data from 1900 through 2038.
2666 	*/
2667 	if (min_year > 1900)
2668 		min_year = 1900;
2669 	max_year0 = max_year;
2670 	if (max_year < 2038)
2671 		max_year = 2038;
2672 	for (i = 0; i < zonecount; ++i) {
2673 		/*
2674 		** A guess that may well be corrected later.
2675 		*/
2676 		stdoff = 0;
2677 		zp = &zpfirst[i];
2678 		usestart = i > 0 && (zp - 1)->z_untiltime > min_time;
2679 		useuntil = i < (zonecount - 1);
2680 		if (useuntil && zp->z_untiltime <= min_time)
2681 			continue;
2682 		gmtoff = zp->z_gmtoff;
2683 		eat(zp->z_filename, zp->z_linenum);
2684 		*startbuf = '\0';
2685 		startoff = zp->z_gmtoff;
2686 		if (zp->z_nrules == 0) {
2687 			stdoff = zp->z_stdoff;
2688 			doabbr(startbuf, max_abbr_len + 1, zp,
2689 			    NULL, zp->z_isdst, stdoff, false);
2690 			type = addtype(oadd(zp->z_gmtoff, stdoff),
2691 				startbuf, zp->z_isdst, startttisstd,
2692 				startttisgmt);
2693 			if (usestart) {
2694 				addtt(starttime, type);
2695 				usestart = false;
2696 			} else
2697 				defaulttype = type;
2698 		} else for (year = min_year; year <= max_year; ++year) {
2699 			if (useuntil && year > zp->z_untilrule.r_hiyear)
2700 				break;
2701 			/*
2702 			** Mark which rules to do in the current year.
2703 			** For those to do, calculate rpytime(rp, year);
2704 			*/
2705 			for (j = 0; j < zp->z_nrules; ++j) {
2706 				rp = &zp->z_rules[j];
2707 				eats(zp->z_filename, zp->z_linenum,
2708 					rp->r_filename, rp->r_linenum);
2709 				rp->r_todo = year >= rp->r_loyear &&
2710 						year <= rp->r_hiyear &&
2711 						yearistype(year, rp->r_yrtype);
2712 				if (rp->r_todo) {
2713 					rp->r_temp = rpytime(rp, year);
2714 					rp->r_todo
2715 					  = (rp->r_temp < y2038_boundary
2716 					     || year <= max_year0);
2717 				}
2718 			}
2719 			for ( ; ; ) {
2720 				ptrdiff_t	k;
2721 				zic_t	jtime, ktime;
2722 				zic_t	offset;
2723 
2724 				INITIALIZE(ktime);
2725 				if (useuntil) {
2726 					/*
2727 					** Turn untiltime into UT
2728 					** assuming the current gmtoff and
2729 					** stdoff values.
2730 					*/
2731 					untiltime = zp->z_untiltime;
2732 					if (!zp->z_untilrule.r_todisgmt)
2733 						untiltime = tadd(untiltime,
2734 							-gmtoff);
2735 					if (!zp->z_untilrule.r_todisstd)
2736 						untiltime = tadd(untiltime,
2737 							-stdoff);
2738 				}
2739 				/*
2740 				** Find the rule (of those to do, if any)
2741 				** that takes effect earliest in the year.
2742 				*/
2743 				k = -1;
2744 				for (j = 0; j < zp->z_nrules; ++j) {
2745 					rp = &zp->z_rules[j];
2746 					if (!rp->r_todo)
2747 						continue;
2748 					eats(zp->z_filename, zp->z_linenum,
2749 						rp->r_filename, rp->r_linenum);
2750 					offset = rp->r_todisgmt ? 0 : gmtoff;
2751 					if (!rp->r_todisstd)
2752 						offset = oadd(offset, stdoff);
2753 					jtime = rp->r_temp;
2754 					if (jtime == min_time ||
2755 						jtime == max_time)
2756 							continue;
2757 					jtime = tadd(jtime, -offset);
2758 					if (k < 0 || jtime < ktime) {
2759 						k = j;
2760 						ktime = jtime;
2761 					} else if (jtime == ktime) {
2762 					  char const *dup_rules_msg =
2763 					    _("two rules for same instant");
2764 					  eats(zp->z_filename, zp->z_linenum,
2765 					       rp->r_filename, rp->r_linenum);
2766 					  warning("%s", dup_rules_msg);
2767 					  rp = &zp->z_rules[k];
2768 					  eats(zp->z_filename, zp->z_linenum,
2769 					       rp->r_filename, rp->r_linenum);
2770 					  error("%s", dup_rules_msg);
2771 					}
2772 				}
2773 				if (k < 0)
2774 					break;	/* go on to next year */
2775 				rp = &zp->z_rules[k];
2776 				rp->r_todo = false;
2777 				if (useuntil && ktime >= untiltime)
2778 					break;
2779 				stdoff = rp->r_stdoff;
2780 				if (usestart && ktime == starttime)
2781 					usestart = false;
2782 				if (usestart) {
2783 					if (ktime < starttime) {
2784 						startoff = oadd(zp->z_gmtoff,
2785 							stdoff);
2786 						doabbr(startbuf,
2787 							max_abbr_len + 1,
2788 							zp,
2789 							rp->r_abbrvar,
2790 							rp->r_isdst,
2791 							rp->r_stdoff,
2792 							false);
2793 						continue;
2794 					}
2795 					if (*startbuf == '\0' &&
2796 						startoff == oadd(zp->z_gmtoff,
2797 						stdoff)) {
2798 							doabbr(startbuf,
2799 								max_abbr_len + 1,
2800 								zp,
2801 								rp->r_abbrvar,
2802 								rp->r_isdst,
2803 								rp->r_stdoff,
2804 								false);
2805 					}
2806 				}
2807 				eats(zp->z_filename, zp->z_linenum,
2808 					rp->r_filename, rp->r_linenum);
2809 				doabbr(ab, max_abbr_len + 1, zp, rp->r_abbrvar,
2810 				       rp->r_isdst, rp->r_stdoff, false);
2811 				offset = oadd(zp->z_gmtoff, rp->r_stdoff);
2812 				type = addtype(offset, ab, rp->r_isdst,
2813 					rp->r_todisstd, rp->r_todisgmt);
2814 				if (defaulttype < 0 && !rp->r_isdst)
2815 				  defaulttype = type;
2816 				if (rp->r_hiyear == ZIC_MAX
2817 				    && ! (0 <= lastatmax
2818 					  && ktime < attypes[lastatmax].at))
2819 				  lastatmax = timecnt;
2820 				addtt(ktime, type);
2821 			}
2822 		}
2823 		if (usestart) {
2824 			if (*startbuf == '\0' &&
2825 				zp->z_format != NULL &&
2826 				strchr(zp->z_format, '%') == NULL &&
2827 				strchr(zp->z_format, '/') == NULL)
2828 					strncpy(startbuf, zp->z_format,
2829 					    max_abbr_len + 1 - 1);
2830 			eat(zp->z_filename, zp->z_linenum);
2831 			if (*startbuf == '\0')
2832 error(_("can't determine time zone abbreviation to use just after until time"));
2833 			else {
2834 			  bool isdst = startoff != zp->z_gmtoff;
2835 			  type = addtype(startoff, startbuf, isdst,
2836 					 startttisstd, startttisgmt);
2837 			  if (defaulttype < 0 && !isdst)
2838 			    defaulttype = type;
2839 			  addtt(starttime, type);
2840 			}
2841 		}
2842 		/*
2843 		** Now we may get to set starttime for the next zone line.
2844 		*/
2845 		if (useuntil) {
2846 			startttisstd = zp->z_untilrule.r_todisstd;
2847 			startttisgmt = zp->z_untilrule.r_todisgmt;
2848 			starttime = zp->z_untiltime;
2849 			if (!startttisstd)
2850 				starttime = tadd(starttime, -stdoff);
2851 			if (!startttisgmt)
2852 				starttime = tadd(starttime, -gmtoff);
2853 		}
2854 	}
2855 	if (defaulttype < 0)
2856 	  defaulttype = 0;
2857 	if (0 <= lastatmax)
2858 	  attypes[lastatmax].dontmerge = true;
2859 	if (do_extend) {
2860 		/*
2861 		** If we're extending the explicitly listed observations
2862 		** for 400 years because we can't fill the POSIX-TZ field,
2863 		** check whether we actually ended up explicitly listing
2864 		** observations through that period.  If there aren't any
2865 		** near the end of the 400-year period, add a redundant
2866 		** one at the end of the final year, to make it clear
2867 		** that we are claiming to have definite knowledge of
2868 		** the lack of transitions up to that point.
2869 		*/
2870 		struct rule xr;
2871 		struct attype *lastat;
2872 		memset(&xr, 0, sizeof(xr));
2873 		xr.r_month = TM_JANUARY;
2874 		xr.r_dycode = DC_DOM;
2875 		xr.r_dayofmonth = 1;
2876 		xr.r_tod = 0;
2877 		for (lastat = attypes, i = 1; i < timecnt; i++)
2878 			if (attypes[i].at > lastat->at)
2879 				lastat = &attypes[i];
2880 		if (!lastat || lastat->at < rpytime(&xr, max_year - 1)) {
2881 			addtt(rpytime(&xr, max_year + 1),
2882 			      lastat ? lastat->type : defaulttype);
2883 			attypes[timecnt - 1].dontmerge = true;
2884 		}
2885 	}
2886 	writezone(zpfirst->z_name, envvar, version, defaulttype);
2887 	free(startbuf);
2888 	free(ab);
2889 	free(envvar);
2890 }
2891 
2892 static void
2893 addtt(zic_t starttime, int type)
2894 {
2895 	attypes = growalloc(attypes, sizeof *attypes, timecnt, &timecnt_alloc);
2896 	attypes[timecnt].at = starttime;
2897 	attypes[timecnt].dontmerge = false;
2898 	attypes[timecnt].type = type;
2899 	++timecnt;
2900 }
2901 
2902 static int
2903 addtype(zic_t gmtoff, char const *abbr, bool isdst, bool ttisstd, bool ttisgmt)
2904 {
2905 	int	i, j;
2906 
2907 	/*
2908 	** See if there's already an entry for this zone type.
2909 	** If so, just return its index.
2910 	*/
2911 	for (i = 0; i < typecnt; ++i) {
2912 		if (gmtoff == gmtoffs[i] && isdst == isdsts[i] &&
2913 			strcmp(abbr, &chars[abbrinds[i]]) == 0 &&
2914 			ttisstd == ttisstds[i] &&
2915 			ttisgmt == ttisgmts[i])
2916 				return i;
2917 	}
2918 	/*
2919 	** There isn't one; add a new one, unless there are already too
2920 	** many.
2921 	*/
2922 	if (typecnt >= TZ_MAX_TYPES) {
2923 		error(_("too many local time types"));
2924 		exit(EXIT_FAILURE);
2925 	}
2926 	if (! (-1L - 2147483647L <= gmtoff && gmtoff <= 2147483647L)) {
2927 		error(_("UT offset out of range"));
2928 		exit(EXIT_FAILURE);
2929 	}
2930 	gmtoffs[i] = gmtoff;
2931 	isdsts[i] = isdst;
2932 	ttisstds[i] = ttisstd;
2933 	ttisgmts[i] = ttisgmt;
2934 
2935 	for (j = 0; j < charcnt; ++j)
2936 		if (strcmp(&chars[j], abbr) == 0)
2937 			break;
2938 	if (j == charcnt)
2939 		newabbr(abbr);
2940 	abbrinds[i] = j;
2941 	++typecnt;
2942 	return i;
2943 }
2944 
2945 static void
2946 leapadd(zic_t t, bool positive, int rolling, int count)
2947 {
2948 	int	i, j;
2949 
2950 	if (leapcnt + (positive ? count : 1) > TZ_MAX_LEAPS) {
2951 		error(_("too many leap seconds"));
2952 		exit(EXIT_FAILURE);
2953 	}
2954 	for (i = 0; i < leapcnt; ++i)
2955 		if (t <= trans[i])
2956 			break;
2957 	do {
2958 		for (j = leapcnt; j > i; --j) {
2959 			trans[j] = trans[j - 1];
2960 			corr[j] = corr[j - 1];
2961 			roll[j] = roll[j - 1];
2962 		}
2963 		trans[i] = t;
2964 		corr[i] = positive ? 1 : -count;
2965 		roll[i] = rolling;
2966 		++leapcnt;
2967 	} while (positive && --count != 0);
2968 }
2969 
2970 static void
2971 adjleap(void)
2972 {
2973 	int	i;
2974 	zic_t	last = 0;
2975 	zic_t	prevtrans = 0;
2976 
2977 	/*
2978 	** propagate leap seconds forward
2979 	*/
2980 	for (i = 0; i < leapcnt; ++i) {
2981 		if (trans[i] - prevtrans < 28 * SECSPERDAY) {
2982 			error(_("Leap seconds too close together"));
2983 			exit(EXIT_FAILURE);
2984 		}
2985 		prevtrans = trans[i];
2986 		trans[i] = tadd(trans[i], last);
2987 		last = corr[i] += last;
2988 	}
2989 }
2990 
2991 static char *
2992 shellquote(char *b, char const *s)
2993 {
2994   *b++ = '\'';
2995   while (*s) {
2996     if (*s == '\'')
2997       *b++ = '\'', *b++ = '\\', *b++ = '\'';
2998     *b++ = *s++;
2999   }
3000   *b++ = '\'';
3001   return b;
3002 }
3003 
3004 static bool
3005 yearistype(zic_t year, const char *type)
3006 {
3007 	char *buf;
3008 	char *b;
3009 	int result;
3010 	size_t len;
3011 
3012 	if (type == NULL || *type == '\0')
3013 		return true;
3014 	buf = zic_malloc(len = 1 + 4 * strlen(yitcommand) + 2
3015 		      + INT_STRLEN_MAXIMUM(zic_t) + 2 + 4 * strlen(type) + 2);
3016 	b = shellquote(buf, yitcommand);
3017 	*b++ = ' ';
3018 	b += snprintf(b, len - (b - buf), "%"PRIdZIC, year);
3019 	*b++ = ' ';
3020 	b = shellquote(b, type);
3021 	*b = '\0';
3022 	result = system(buf);
3023 	if (WIFEXITED(result)) {
3024 		int status = WEXITSTATUS(result);
3025 		if (status <= 1) {
3026 			free(buf);
3027 			return status == 0;
3028 		}
3029 	}
3030 	error(_("Wild result from command execution"));
3031 	fprintf(stderr, _("%s: command was '%s', result was %d\n"),
3032 		progname, buf, result);
3033 	exit(EXIT_FAILURE);
3034 }
3035 
3036 /* Is A a space character in the C locale?  */
3037 static bool
3038 is_space(char a)
3039 {
3040 	switch (a) {
3041 	  default:
3042 		return false;
3043 	  case ' ': case '\f': case '\n': case '\r': case '\t': case '\v':
3044 	  	return true;
3045 	}
3046 }
3047 
3048 /* Is A an alphabetic character in the C locale?  */
3049 static bool
3050 is_alpha(char a)
3051 {
3052 	switch (a) {
3053 	  default:
3054 		return false;
3055 	  case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G':
3056 	  case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N':
3057 	  case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U':
3058 	  case 'V': case 'W': case 'X': case 'Y': case 'Z':
3059 	  case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g':
3060 	  case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n':
3061 	  case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u':
3062 	  case 'v': case 'w': case 'x': case 'y': case 'z':
3063 		return true;
3064 	}
3065 }
3066 
3067 /* If A is an uppercase character in the C locale, return its lowercase
3068    counterpart.  Otherwise, return A.  */
3069 static char
3070 lowerit(char a)
3071 {
3072 	switch (a) {
3073 	  default: return a;
3074 	  case 'A': return 'a'; case 'B': return 'b'; case 'C': return 'c';
3075 	  case 'D': return 'd'; case 'E': return 'e'; case 'F': return 'f';
3076 	  case 'G': return 'g'; case 'H': return 'h'; case 'I': return 'i';
3077 	  case 'J': return 'j'; case 'K': return 'k'; case 'L': return 'l';
3078 	  case 'M': return 'm'; case 'N': return 'n'; case 'O': return 'o';
3079 	  case 'P': return 'p'; case 'Q': return 'q'; case 'R': return 'r';
3080 	  case 'S': return 's'; case 'T': return 't'; case 'U': return 'u';
3081 	  case 'V': return 'v'; case 'W': return 'w'; case 'X': return 'x';
3082 	  case 'Y': return 'y'; case 'Z': return 'z';
3083 	}
3084 }
3085 
3086 /* case-insensitive equality */
3087 static ATTRIBUTE_PURE bool
3088 ciequal(const char *ap, const char *bp)
3089 {
3090 	while (lowerit(*ap) == lowerit(*bp++))
3091 		if (*ap++ == '\0')
3092 			return true;
3093 	return false;
3094 }
3095 
3096 static ATTRIBUTE_PURE bool
3097 itsabbr(const char *abbr, const char *word)
3098 {
3099 	if (lowerit(*abbr) != lowerit(*word))
3100 		return false;
3101 	++word;
3102 	while (*++abbr != '\0')
3103 		do {
3104 			if (*word == '\0')
3105 				return false;
3106 		} while (lowerit(*word++) != lowerit(*abbr));
3107 	return true;
3108 }
3109 
3110 /* Return true if ABBR is an initial prefix of WORD, ignoring ASCII case.  */
3111 
3112 static ATTRIBUTE_PURE bool
3113 ciprefix(char const *abbr, char const *word)
3114 {
3115   do
3116     if (!*abbr)
3117       return true;
3118   while (lowerit(*abbr++) == lowerit(*word++));
3119 
3120   return false;
3121 }
3122 
3123 static const struct lookup *
3124 byword(const char *word, const struct lookup *table)
3125 {
3126 	const struct lookup *	foundlp;
3127 	const struct lookup *	lp;
3128 
3129 	if (word == NULL || table == NULL)
3130 		return NULL;
3131 
3132 	/* If TABLE is LASTS and the word starts with "last" followed
3133 	   by a non-'-', skip the "last" and look in WDAY_NAMES instead.
3134 	   Warn about any usage of the undocumented prefix "last-".  */
3135 	if (table == lasts && ciprefix("last", word) && word[4]) {
3136 	  if (word[4] == '-')
3137 	    warning(_("\"%s\" is undocumented; use \"last%s\" instead"),
3138 		    word, word + 5);
3139 	  else {
3140 	    word += 4;
3141 	    table = wday_names;
3142 	  }
3143 	}
3144 
3145 	/*
3146 	** Look for exact match.
3147 	*/
3148 	for (lp = table; lp->l_word != NULL; ++lp)
3149 		if (ciequal(word, lp->l_word))
3150 			return lp;
3151 	/*
3152 	** Look for inexact match.
3153 	*/
3154 	foundlp = NULL;
3155 	for (lp = table; lp->l_word != NULL; ++lp)
3156 		if (ciprefix(word, lp->l_word)) {
3157 			if (foundlp == NULL)
3158 				foundlp = lp;
3159 			else	return NULL;	/* multiple inexact matches */
3160 		}
3161 
3162 	/* Warn about any backward-compatibility issue with pre-2017c zic.  */
3163 	if (foundlp) {
3164 	  bool pre_2017c_match = false;
3165 	  for (lp = table; lp->l_word; lp++)
3166 	    if (itsabbr(word, lp->l_word)) {
3167 	      if (pre_2017c_match) {
3168 		warning(_("\"%s\" is ambiguous in pre-2017c zic"), word);
3169 		break;
3170 	      }
3171 	      pre_2017c_match = true;
3172 	    }
3173 	}
3174 
3175 	return foundlp;
3176 }
3177 
3178 static char **
3179 getfields(char *cp)
3180 {
3181 	char *	dp;
3182 	char **	array;
3183 	int	nsubs;
3184 
3185 	if (cp == NULL)
3186 		return NULL;
3187 	array = zic_malloc(size_product(strlen(cp) + 1, sizeof *array));
3188 	nsubs = 0;
3189 	for ( ; ; ) {
3190 		while (is_space(*cp))
3191 				++cp;
3192 		if (*cp == '\0' || *cp == '#')
3193 			break;
3194 		array[nsubs++] = dp = cp;
3195 		do {
3196 			if ((*dp = *cp++) != '"')
3197 				++dp;
3198 			else while ((*dp = *cp++) != '"')
3199 				if (*dp != '\0')
3200 					++dp;
3201 				else {
3202 				  error(_("Odd number of quotation marks"));
3203 				  exit(EXIT_FAILURE);
3204 				}
3205 		} while (*cp && *cp != '#' && !is_space(*cp));
3206 		if (is_space(*cp))
3207 			++cp;
3208 		*dp = '\0';
3209 	}
3210 	array[nsubs] = NULL;
3211 	return array;
3212 }
3213 
3214 static _Noreturn void
3215 time_overflow(void)
3216 {
3217 	error(_("time overflow"));
3218 	exit(EXIT_FAILURE);
3219 }
3220 
3221 static ATTRIBUTE_PURE zic_t
3222 oadd(zic_t t1, zic_t t2)
3223 {
3224 	if (t1 < 0 ? t2 < ZIC_MIN - t1 : ZIC_MAX - t1 < t2)
3225 		time_overflow();
3226 	return t1 + t2;
3227 }
3228 
3229 static ATTRIBUTE_PURE zic_t
3230 tadd(zic_t t1, zic_t t2)
3231 {
3232 	if (t1 < 0) {
3233 		if (t2 < min_time - t1) {
3234 			if (t1 != min_time)
3235 				time_overflow();
3236 			return min_time;
3237 		}
3238 	} else {
3239 		if (max_time - t1 < t2) {
3240 			if (t1 != max_time)
3241 				time_overflow();
3242 			return max_time;
3243 		}
3244 	}
3245 	return t1 + t2;
3246 }
3247 
3248 /*
3249 ** Given a rule, and a year, compute the date (in seconds since January 1,
3250 ** 1970, 00:00 LOCAL time) in that year that the rule refers to.
3251 */
3252 
3253 static zic_t
3254 rpytime(const struct rule *rp, zic_t wantedy)
3255 {
3256 	int	m, i;
3257 	zic_t	dayoff;			/* with a nod to Margaret O. */
3258 	zic_t	t, y;
3259 
3260 	if (wantedy == ZIC_MIN)
3261 		return min_time;
3262 	if (wantedy == ZIC_MAX)
3263 		return max_time;
3264 	dayoff = 0;
3265 	m = TM_JANUARY;
3266 	y = EPOCH_YEAR;
3267 	if (y < wantedy) {
3268 	  wantedy -= y;
3269 	  dayoff = (wantedy / YEARSPERREPEAT) * (SECSPERREPEAT / SECSPERDAY);
3270 	  wantedy %= YEARSPERREPEAT;
3271 	  wantedy += y;
3272 	} else if (wantedy < 0) {
3273 	  dayoff = (wantedy / YEARSPERREPEAT) * (SECSPERREPEAT / SECSPERDAY);
3274 	  wantedy %= YEARSPERREPEAT;
3275 	}
3276 	while (wantedy != y) {
3277 		if (wantedy > y) {
3278 			i = len_years[isleap(y)];
3279 			++y;
3280 		} else {
3281 			--y;
3282 			i = -len_years[isleap(y)];
3283 		}
3284 		dayoff = oadd(dayoff, i);
3285 	}
3286 	while (m != rp->r_month) {
3287 		i = len_months[isleap(y)][m];
3288 		dayoff = oadd(dayoff, i);
3289 		++m;
3290 	}
3291 	i = rp->r_dayofmonth;
3292 	if (m == TM_FEBRUARY && i == 29 && !isleap(y)) {
3293 		if (rp->r_dycode == DC_DOWLEQ)
3294 			--i;
3295 		else {
3296 			error(_("use of 2/29 in non leap-year"));
3297 			exit(EXIT_FAILURE);
3298 		}
3299 	}
3300 	--i;
3301 	dayoff = oadd(dayoff, i);
3302 	if (rp->r_dycode == DC_DOWGEQ || rp->r_dycode == DC_DOWLEQ) {
3303 		zic_t	wday;
3304 
3305 #define LDAYSPERWEEK	((zic_t) DAYSPERWEEK)
3306 		wday = EPOCH_WDAY;
3307 		/*
3308 		** Don't trust mod of negative numbers.
3309 		*/
3310 		if (dayoff >= 0)
3311 			wday = (wday + dayoff) % LDAYSPERWEEK;
3312 		else {
3313 			wday -= ((-dayoff) % LDAYSPERWEEK);
3314 			if (wday < 0)
3315 				wday += LDAYSPERWEEK;
3316 		}
3317 		while (wday != rp->r_wday)
3318 			if (rp->r_dycode == DC_DOWGEQ) {
3319 				dayoff = oadd(dayoff, (zic_t) 1);
3320 				if (++wday >= LDAYSPERWEEK)
3321 					wday = 0;
3322 				++i;
3323 			} else {
3324 				dayoff = oadd(dayoff, (zic_t) -1);
3325 				if (--wday < 0)
3326 					wday = LDAYSPERWEEK - 1;
3327 				--i;
3328 			}
3329 		if (i < 0 || i >= len_months[isleap(y)][m]) {
3330 			if (noise)
3331 				warning(_("rule goes past start/end of month; \
3332 will not work with pre-2004 versions of zic"));
3333 		}
3334 	}
3335 	if (dayoff < min_time / SECSPERDAY)
3336 		return min_time;
3337 	if (dayoff > max_time / SECSPERDAY)
3338 		return max_time;
3339 	t = (zic_t) dayoff * SECSPERDAY;
3340 	return tadd(t, rp->r_tod);
3341 }
3342 
3343 static void
3344 newabbr(const char *string)
3345 {
3346 	int	i;
3347 
3348 	if (strcmp(string, GRANDPARENTED) != 0) {
3349 		const char *	cp;
3350 		const char *	mp;
3351 
3352 		cp = string;
3353 		mp = NULL;
3354 		while (is_alpha(*cp) || ('0' <= *cp && *cp <= '9')
3355 		       || *cp == '-' || *cp == '+')
3356 				++cp;
3357 		if (noise && cp - string < 3)
3358 		  mp = _("time zone abbreviation has fewer than 3 characters");
3359 		if (cp - string > ZIC_MAX_ABBR_LEN_WO_WARN)
3360 		  mp = _("time zone abbreviation has too many characters");
3361 		if (*cp != '\0')
3362 mp = _("time zone abbreviation differs from POSIX standard");
3363 		if (mp != NULL)
3364 			warning("%s (%s)", mp, string);
3365 	}
3366 	i = strlen(string) + 1;
3367 	if (charcnt + i > TZ_MAX_CHARS) {
3368 		error(_("too many, or too long, time zone abbreviations"));
3369 		exit(EXIT_FAILURE);
3370 	}
3371 	strncpy(&chars[charcnt], string, sizeof(chars) - charcnt - 1);
3372 	charcnt += i;
3373 }
3374 
3375 /* Ensure that the directories of ARGNAME exist, by making any missing
3376    ones.  If ANCESTORS, do this only for ARGNAME's ancestors; otherwise,
3377    do it for ARGNAME too.  Exit with failure if there is trouble.
3378    Do not consider an existing non-directory to be trouble.  */
3379 static void
3380 mkdirs(char const *argname, bool ancestors)
3381 {
3382 	char *	name;
3383 	char *	cp;
3384 
3385 	cp = name = ecpyalloc(argname);
3386 
3387 	/* On MS-Windows systems, do not worry about drive letters or
3388 	   backslashes, as this should suffice in practice.  Time zone
3389 	   names do not use drive letters and backslashes.  If the -d
3390 	   option of zic does not name an already-existing directory,
3391 	   it can use slashes to separate the already-existing
3392 	   ancestor prefix from the to-be-created subdirectories.  */
3393 
3394 	/* Do not mkdir a root directory, as it must exist.  */
3395 	while (*cp == '/')
3396 	  cp++;
3397 
3398 	while (cp && ((cp = strchr(cp, '/')) || !ancestors)) {
3399 		if (cp)
3400 		  *cp = '\0';
3401 		/*
3402 		** Try to create it.  It's OK if creation fails because
3403 		** the directory already exists, perhaps because some
3404 		** other process just created it.  For simplicity do
3405 		** not check first whether it already exists, as that
3406 		** is checked anyway if the mkdir fails.
3407 		*/
3408 		if (mkdir(name, MKDIR_UMASK) != 0) {
3409 			/* For speed, skip itsdir if errno == EEXIST.  Since
3410 			   mkdirs is called only after open fails with ENOENT
3411 			   on a subfile, EEXIST implies itsdir here.  */
3412 			int err = errno;
3413 			if (err != EEXIST && !itsdir(name)) {
3414 				error(_("%s: Can't create directory %s: %s"),
3415 				      progname, name, strerror(err));
3416 				exit(EXIT_FAILURE);
3417 			}
3418 		}
3419 		if (cp)
3420 		  *cp++ = '/';
3421 	}
3422 	free(name);
3423 }
3424