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