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