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