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