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