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