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