zic.c revision 2702
1#ifndef lint
2#ifndef NOID
3static char	elsieid[] = "@(#)zic.c	7.22";
4#endif /* !defined NOID */
5#endif /* !defined lint */
6
7#include "private.h"
8#include "tzfile.h"
9
10struct rule {
11	const char *	r_filename;
12	int		r_linenum;
13	const char *	r_name;
14
15	int		r_loyear;	/* for example, 1986 */
16	int		r_hiyear;	/* for example, 1986 */
17	const char *	r_yrtype;
18
19	int		r_month;	/* 0..11 */
20
21	int		r_dycode;	/* see below */
22	int		r_dayofmonth;
23	int		r_wday;
24
25	long		r_tod;		/* time from midnight */
26	int		r_todisstd;	/* above is standard time if TRUE */
27					/* or wall clock time if FALSE */
28	long		r_stdoff;	/* offset from standard time */
29	const char *	r_abbrvar;	/* variable part of abbreviation */
30
31	int		r_todo;		/* a rule to do (used in outzone) */
32	time_t		r_temp;		/* used in outzone */
33};
34
35/*
36**	r_dycode		r_dayofmonth	r_wday
37*/
38
39#define DC_DOM		0	/* 1..31 */	/* unused */
40#define DC_DOWGEQ	1	/* 1..31 */	/* 0..6 (Sun..Sat) */
41#define DC_DOWLEQ	2	/* 1..31 */	/* 0..6 (Sun..Sat) */
42
43struct zone {
44	const char *	z_filename;
45	int		z_linenum;
46
47	const char *	z_name;
48	long		z_gmtoff;
49	const char *	z_rule;
50	const char *	z_format;
51
52	long		z_stdoff;
53
54	struct rule *	z_rules;
55	int		z_nrules;
56
57	struct rule	z_untilrule;
58	time_t		z_untiltime;
59};
60
61extern int	emkdir P((const char * name, int mode));
62extern int	getopt P((int argc, char * argv[], const char * options));
63extern char *	icatalloc P((char * old, const char * new));
64extern char *	icpyalloc P((const char * string));
65extern void	ifree P((char * p));
66extern char *	imalloc P((int n));
67extern char *	irealloc P((char * old, int n));
68extern int	link P((const char * fromname, const char * toname));
69extern char *	optarg;
70extern int	optind;
71extern char *	scheck P((const char * string, const char * format));
72
73static void	addtt P((time_t starttime, int type));
74static int	addtype P((long gmtoff, const char * abbr, int isdst,
75				int ttisstd));
76static void	leapadd P((time_t t, int positive, int rolling, int count));
77static void	adjleap P((void));
78static void	associate P((void));
79static int	ciequal P((const char * ap, const char * bp));
80static void	convert P((long val, char * buf));
81static void	dolink P((const char * fromfile, const char * tofile));
82static void	eat P((const char * name, int num));
83static void	eats P((const char * name, int num,
84			const char * rname, int rnum));
85static long	eitol P((int i));
86static void	error P((const char * message));
87static char **	getfields P((char * buf));
88static long	gethms P((const char * string, const char * errstrng,
89			int signable));
90static void	infile P((const char * filename));
91static void	inleap P((char ** fields, int nfields));
92static void	inlink P((char ** fields, int nfields));
93static void	inrule P((char ** fields, int nfields));
94static int	inzcont P((char ** fields, int nfields));
95static int	inzone P((char ** fields, int nfields));
96static int	inzsub P((char ** fields, int nfields, int iscont));
97static int	itsabbr P((const char * abbr, const char * word));
98static int	itsdir P((const char * name));
99static int	lowerit P((int c));
100static char *	memcheck P((char * tocheck));
101static int	mkdirs P((char * filename));
102static void	newabbr P((const char * abbr));
103static long	oadd P((long t1, long t2));
104static void	outzone P((const struct zone * zp, int ntzones));
105static void	puttzcode P((long code, FILE * fp));
106static int	rcomp P((const genericptr_t leftp, const genericptr_t rightp));
107static time_t	rpytime P((const struct rule * rp, int wantedy));
108static void	rulesub P((struct rule * rp,
109			char * loyearp, char * hiyearp,
110			char * typep, char * monthp,
111			char * dayp, char * timep));
112static void	setboundaries P((void));
113static time_t	tadd P((time_t t1, long t2));
114static void	usage P((void));
115static void	writezone P((const char * name));
116static int	yearistype P((int year, const char * type));
117
118static int		charcnt;
119static int		errors;
120static const char *	filename;
121static int		leapcnt;
122static int		linenum;
123static int		max_int;
124static time_t		max_time;
125static int		max_year;
126static int		min_int;
127static time_t		min_time;
128static int		min_year;
129static int		noise;
130static const char *	rfilename;
131static int		rlinenum;
132static const char *	progname;
133static int		timecnt;
134static int		typecnt;
135static int		tt_signed;
136
137/*
138** Line codes.
139*/
140
141#define LC_RULE		0
142#define LC_ZONE		1
143#define LC_LINK		2
144#define LC_LEAP		3
145
146/*
147** Which fields are which on a Zone line.
148*/
149
150#define ZF_NAME		1
151#define ZF_GMTOFF	2
152#define ZF_RULE		3
153#define ZF_FORMAT	4
154#define ZF_TILYEAR	5
155#define ZF_TILMONTH	6
156#define ZF_TILDAY	7
157#define ZF_TILTIME	8
158#define ZONE_MINFIELDS	5
159#define ZONE_MAXFIELDS	9
160
161/*
162** Which fields are which on a Zone continuation line.
163*/
164
165#define ZFC_GMTOFF	0
166#define ZFC_RULE	1
167#define ZFC_FORMAT	2
168#define ZFC_TILYEAR	3
169#define ZFC_TILMONTH	4
170#define ZFC_TILDAY	5
171#define ZFC_TILTIME	6
172#define ZONEC_MINFIELDS	3
173#define ZONEC_MAXFIELDS	7
174
175/*
176** Which files are which on a Rule line.
177*/
178
179#define RF_NAME		1
180#define RF_LOYEAR	2
181#define RF_HIYEAR	3
182#define RF_COMMAND	4
183#define RF_MONTH	5
184#define RF_DAY		6
185#define RF_TOD		7
186#define RF_STDOFF	8
187#define RF_ABBRVAR	9
188#define RULE_FIELDS	10
189
190/*
191** Which fields are which on a Link line.
192*/
193
194#define LF_FROM		1
195#define LF_TO		2
196#define LINK_FIELDS	3
197
198/*
199** Which fields are which on a Leap line.
200*/
201
202#define LP_YEAR		1
203#define LP_MONTH	2
204#define LP_DAY		3
205#define LP_TIME		4
206#define LP_CORR		5
207#define LP_ROLL		6
208#define LEAP_FIELDS	7
209
210/*
211** Year synonyms.
212*/
213
214#define YR_MINIMUM	0
215#define YR_MAXIMUM	1
216#define YR_ONLY		2
217
218static struct rule *	rules;
219static int		nrules;	/* number of rules */
220
221static struct zone *	zones;
222static int		nzones;	/* number of zones */
223
224struct link {
225	const char *	l_filename;
226	int		l_linenum;
227	const char *	l_from;
228	const char *	l_to;
229};
230
231static struct link *	links;
232static int		nlinks;
233
234struct lookup {
235	const char *	l_word;
236	const int	l_value;
237};
238
239static struct lookup const *	byword P((const char * string,
240					const struct lookup * lp));
241
242static struct lookup const	line_codes[] = {
243	{ "Rule",	LC_RULE },
244	{ "Zone",	LC_ZONE },
245	{ "Link",	LC_LINK },
246	{ "Leap",	LC_LEAP },
247	{ NULL,		0}
248};
249
250static struct lookup const	mon_names[] = {
251	{ "January",	TM_JANUARY },
252	{ "February",	TM_FEBRUARY },
253	{ "March",	TM_MARCH },
254	{ "April",	TM_APRIL },
255	{ "May",	TM_MAY },
256	{ "June",	TM_JUNE },
257	{ "July",	TM_JULY },
258	{ "August",	TM_AUGUST },
259	{ "September",	TM_SEPTEMBER },
260	{ "October",	TM_OCTOBER },
261	{ "November",	TM_NOVEMBER },
262	{ "December",	TM_DECEMBER },
263	{ NULL,		0 }
264};
265
266static struct lookup const	wday_names[] = {
267	{ "Sunday",	TM_SUNDAY },
268	{ "Monday",	TM_MONDAY },
269	{ "Tuesday",	TM_TUESDAY },
270	{ "Wednesday",	TM_WEDNESDAY },
271	{ "Thursday",	TM_THURSDAY },
272	{ "Friday",	TM_FRIDAY },
273	{ "Saturday",	TM_SATURDAY },
274	{ NULL,		0 }
275};
276
277static struct lookup const	lasts[] = {
278	{ "last-Sunday",	TM_SUNDAY },
279	{ "last-Monday",	TM_MONDAY },
280	{ "last-Tuesday",	TM_TUESDAY },
281	{ "last-Wednesday",	TM_WEDNESDAY },
282	{ "last-Thursday",	TM_THURSDAY },
283	{ "last-Friday",	TM_FRIDAY },
284	{ "last-Saturday",	TM_SATURDAY },
285	{ NULL,			0 }
286};
287
288static struct lookup const	begin_years[] = {
289	{ "minimum",	YR_MINIMUM },
290	{ "maximum",	YR_MAXIMUM },
291	{ NULL,		0 }
292};
293
294static struct lookup const	end_years[] = {
295	{ "minimum",	YR_MINIMUM },
296	{ "maximum",	YR_MAXIMUM },
297	{ "only",	YR_ONLY },
298	{ NULL,		0 }
299};
300
301static struct lookup const	leap_types[] = {
302	{ "Rolling",	TRUE },
303	{ "Stationary",	FALSE },
304	{ NULL,		0 }
305};
306
307static const int	len_months[2][MONSPERYEAR] = {
308	{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
309	{ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
310};
311
312static const int	len_years[2] = {
313	DAYSPERNYEAR, DAYSPERLYEAR
314};
315
316static time_t		ats[TZ_MAX_TIMES];
317static unsigned char	types[TZ_MAX_TIMES];
318static long		gmtoffs[TZ_MAX_TYPES];
319static char		isdsts[TZ_MAX_TYPES];
320static unsigned char	abbrinds[TZ_MAX_TYPES];
321static char		ttisstds[TZ_MAX_TYPES];
322static char		chars[TZ_MAX_CHARS];
323static time_t		trans[TZ_MAX_LEAPS];
324static long		corr[TZ_MAX_LEAPS];
325static char		roll[TZ_MAX_LEAPS];
326
327/*
328** Memory allocation.
329*/
330
331static char *
332memcheck(ptr)
333char * const	ptr;
334{
335	if (ptr == NULL) {
336		(void) perror(progname);
337		(void) exit(EXIT_FAILURE);
338	}
339	return ptr;
340}
341
342#define emalloc(size)		memcheck(imalloc(size))
343#define erealloc(ptr, size)	memcheck(irealloc(ptr, size))
344#define ecpyalloc(ptr)		memcheck(icpyalloc(ptr))
345#define ecatalloc(oldp, newp)	memcheck(icatalloc(oldp, newp))
346
347/*
348** Error handling.
349*/
350
351static void
352eats(name, num, rname, rnum)
353const char * const	name;
354const int		num;
355const char * const	rname;
356const int		rnum;
357{
358	filename = name;
359	linenum = num;
360	rfilename = rname;
361	rlinenum = rnum;
362}
363
364static void
365eat(name, num)
366const char * const	name;
367const int		num;
368{
369	eats(name, num, (char *) NULL, -1);
370}
371
372static void
373error(string)
374const char * const	string;
375{
376	/*
377	** Match the format of "cc" to allow sh users to
378	** 	zic ... 2>&1 | error -t "*" -v
379	** on BSD systems.
380	*/
381	(void) fprintf(stderr, "\"%s\", line %d: %s",
382		filename, linenum, string);
383	if (rfilename != NULL)
384		(void) fprintf(stderr, " (rule from \"%s\", line %d)",
385			rfilename, rlinenum);
386	(void) fprintf(stderr, "\n");
387	++errors;
388}
389
390static void
391usage()
392{
393	(void) fprintf(stderr,
394"%s: usage is %s [ -s ] [ -v ] [ -l localtime ] [ -p posixrules ] [ -d directory ] \n\
395\t[ -L leapseconds ] [ -y yearistype ] [ filename ... ]\n",
396		progname, progname);
397	(void) exit(EXIT_FAILURE);
398}
399
400static const char *	psxrules;
401static const char *	lcltime;
402static const char *	directory;
403static const char *	leapsec;
404static const char *	yitcommand;
405static int		sflag = FALSE;
406
407int
408main(argc, argv)
409int	argc;
410char *	argv[];
411{
412	register int	i, j;
413	register int	c;
414
415#ifdef unix
416	(void) umask(umask(022) | 022);
417#endif /* defined unix */
418	progname = argv[0];
419	while ((c = getopt(argc, argv, "d:l:p:L:vsy:")) != EOF)
420		switch (c) {
421			default:
422				usage();
423			case 'd':
424				if (directory == NULL)
425					directory = optarg;
426				else {
427					(void) fprintf(stderr,
428"%s: More than one -d option specified\n",
429						progname);
430					(void) exit(EXIT_FAILURE);
431				}
432				break;
433			case 'l':
434				if (lcltime == NULL)
435					lcltime = optarg;
436				else {
437					(void) fprintf(stderr,
438"%s: More than one -l option specified\n",
439						progname);
440					(void) exit(EXIT_FAILURE);
441				}
442				break;
443			case 'p':
444				if (psxrules == NULL)
445					psxrules = optarg;
446				else {
447					(void) fprintf(stderr,
448"%s: More than one -p option specified\n",
449						progname);
450					(void) exit(EXIT_FAILURE);
451				}
452				break;
453			case 'y':
454				if (yitcommand == NULL)
455					yitcommand = optarg;
456				else {
457					(void) fprintf(stderr,
458"%s: More than one -y option specified\n",
459						progname);
460					(void) exit(EXIT_FAILURE);
461				}
462				break;
463			case 'L':
464				if (leapsec == NULL)
465					leapsec = optarg;
466				else {
467					(void) fprintf(stderr,
468"%s: More than one -L option specified\n",
469						progname);
470					(void) exit(EXIT_FAILURE);
471				}
472				break;
473			case 'v':
474				noise = TRUE;
475				break;
476			case 's':
477				sflag = TRUE;
478				break;
479		}
480	if (optind == argc - 1 && strcmp(argv[optind], "=") == 0)
481		usage();	/* usage message by request */
482	if (directory == NULL)
483		directory = TZDIR;
484	if (yitcommand == NULL)
485		yitcommand = "yearistype";
486
487	setboundaries();
488
489	if (optind < argc && leapsec != NULL) {
490		infile(leapsec);
491		adjleap();
492	}
493
494	zones = (struct zone *) emalloc(0);
495	rules = (struct rule *) emalloc(0);
496	links = (struct link *) emalloc(0);
497	for (i = optind; i < argc; ++i)
498		infile(argv[i]);
499	if (errors)
500		(void) exit(EXIT_FAILURE);
501	associate();
502	for (i = 0; i < nzones; i = j) {
503		/*
504		** Find the next non-continuation zone entry.
505		*/
506		for (j = i + 1; j < nzones && zones[j].z_name == NULL; ++j)
507			continue;
508		outzone(&zones[i], j - i);
509	}
510	/*
511	** Make links.
512	*/
513	for (i = 0; i < nlinks; ++i)
514		dolink(links[i].l_from, links[i].l_to);
515	if (lcltime != NULL)
516		dolink(lcltime, TZDEFAULT);
517	if (psxrules != NULL)
518		dolink(psxrules, TZDEFRULES);
519	return (errors == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
520}
521
522static void
523dolink(fromfile, tofile)
524const char * const	fromfile;
525const char * const	tofile;
526{
527	register char *	fromname;
528	register char *	toname;
529
530	if (fromfile[0] == '/')
531		fromname = fromfile;
532	else {
533		fromname = ecpyalloc(directory);
534		fromname = ecatalloc(fromname, "/");
535		fromname = ecatalloc(fromname, fromfile);
536	}
537	if (tofile[0] == '/')
538		toname = tofile;
539	else {
540		toname = ecpyalloc(directory);
541		toname = ecatalloc(toname, "/");
542		toname = ecatalloc(toname, tofile);
543	}
544	/*
545	** We get to be careful here since
546	** there's a fair chance of root running us.
547	*/
548	if (!itsdir(toname))
549		(void) remove(toname);
550	if (link(fromname, toname) != 0) {
551		if (mkdirs(toname) != 0)
552			(void) exit(EXIT_FAILURE);
553		if (link(fromname, toname) != 0) {
554			(void) fprintf(stderr, "%s: Can't link from %s to ",
555				progname, fromname);
556			(void) perror(toname);
557			(void) exit(EXIT_FAILURE);
558		}
559	}
560	if (fromname != fromfile)
561		ifree(fromname);
562	if (toname != tofile)
563		ifree(toname);
564}
565
566static void
567setboundaries()
568{
569	register time_t	bit;
570	register int bii;
571
572	for (bit = 1; bit > 0; bit <<= 1)
573		continue;
574	if (bit == 0) {		/* time_t is an unsigned type */
575		tt_signed = FALSE;
576		min_time = 0;
577		max_time = ~(time_t) 0;
578		if (sflag)
579			max_time >>= 1;
580	} else {
581		tt_signed = TRUE;
582		min_time = bit;
583		max_time = bit;
584		++max_time;
585		max_time = -max_time;
586		if (sflag)
587			min_time = 0;
588	}
589	min_year = TM_YEAR_BASE + gmtime(&min_time)->tm_year;
590	max_year = TM_YEAR_BASE + gmtime(&max_time)->tm_year;
591
592	for (bii = 1; bii > 0; bii <<= 1)
593		continue;
594	min_int = bii;
595	max_int = -1 - bii;
596}
597
598static int
599itsdir(name)
600const char * const	name;
601{
602	register char *	myname;
603	register int	accres;
604
605	myname = ecpyalloc(name);
606	myname = ecatalloc(myname, "/.");
607	accres = access(myname, 0);
608	ifree(myname);
609	return accres == 0;
610}
611
612/*
613** Associate sets of rules with zones.
614*/
615
616/*
617** Sort by rule name.
618*/
619
620static int
621rcomp(cp1, cp2)
622const genericptr_t	cp1;
623const genericptr_t	cp2;
624{
625	return strcmp(((struct rule *) cp1)->r_name,
626		((struct rule *) cp2)->r_name);
627}
628
629static void
630associate()
631{
632	register struct zone *	zp;
633	register struct rule *	rp;
634	register int		base, out;
635	register int		i;
636
637	if (nrules != 0)
638		(void) qsort((genericptr_t) rules,
639			(qsort_size_t) nrules,
640			(qsort_size_t) sizeof *rules, rcomp);
641	for (i = 0; i < nzones; ++i) {
642		zp = &zones[i];
643		zp->z_rules = NULL;
644		zp->z_nrules = 0;
645	}
646	for (base = 0; base < nrules; base = out) {
647		rp = &rules[base];
648		for (out = base + 1; out < nrules; ++out)
649			if (strcmp(rp->r_name, rules[out].r_name) != 0)
650				break;
651		for (i = 0; i < nzones; ++i) {
652			zp = &zones[i];
653			if (strcmp(zp->z_rule, rp->r_name) != 0)
654				continue;
655			zp->z_rules = rp;
656			zp->z_nrules = out - base;
657		}
658	}
659	for (i = 0; i < nzones; ++i) {
660		zp = &zones[i];
661		if (zp->z_nrules == 0) {
662			/*
663			** Maybe we have a local standard time offset.
664			*/
665			eat(zp->z_filename, zp->z_linenum);
666			zp->z_stdoff = gethms(zp->z_rule, "unruly zone", TRUE);
667			/*
668			** Note, though, that if there's no rule,
669			** a '%s' in the format is a bad thing.
670			*/
671			if (strchr(zp->z_format, '%') != 0)
672				error("%s in ruleless zone");
673		}
674	}
675	if (errors)
676		(void) exit(EXIT_FAILURE);
677}
678
679static void
680infile(name)
681const char *	name;
682{
683	register FILE *			fp;
684	register char **		fields;
685	register char *			cp;
686	register const struct lookup *	lp;
687	register int			nfields;
688	register int			wantcont;
689	register int			num;
690	char				buf[BUFSIZ];
691
692	if (strcmp(name, "-") == 0) {
693		name = "standard input";
694		fp = stdin;
695	} else if ((fp = fopen(name, "r")) == NULL) {
696		(void) fprintf(stderr, "%s: Can't open ", progname);
697		(void) perror(name);
698		(void) exit(EXIT_FAILURE);
699	}
700	wantcont = FALSE;
701	for (num = 1; ; ++num) {
702		eat(name, num);
703		if (fgets(buf, (int) sizeof buf, fp) != buf)
704			break;
705		cp = strchr(buf, '\n');
706		if (cp == NULL) {
707			error("line too long");
708			(void) exit(EXIT_FAILURE);
709		}
710		*cp = '\0';
711		fields = getfields(buf);
712		nfields = 0;
713		while (fields[nfields] != NULL) {
714			static char	nada[1];
715
716			if (ciequal(fields[nfields], "-"))
717				fields[nfields] = nada;
718			++nfields;
719		}
720		if (nfields == 0) {
721			/* nothing to do */
722		} else if (wantcont) {
723			wantcont = inzcont(fields, nfields);
724		} else {
725			lp = byword(fields[0], line_codes);
726			if (lp == NULL)
727				error("input line of unknown type");
728			else switch ((int) (lp->l_value)) {
729				case LC_RULE:
730					inrule(fields, nfields);
731					wantcont = FALSE;
732					break;
733				case LC_ZONE:
734					wantcont = inzone(fields, nfields);
735					break;
736				case LC_LINK:
737					inlink(fields, nfields);
738					wantcont = FALSE;
739					break;
740				case LC_LEAP:
741					if (name != leapsec)
742						(void) fprintf(stderr,
743"%s: Leap line in non leap seconds file %s\n",
744							progname, name);
745					else	inleap(fields, nfields);
746					wantcont = FALSE;
747					break;
748				default:	/* "cannot happen" */
749					(void) fprintf(stderr,
750"%s: panic: Invalid l_value %d\n",
751						progname, lp->l_value);
752					(void) exit(EXIT_FAILURE);
753			}
754		}
755		ifree((char *) fields);
756	}
757	if (ferror(fp)) {
758		(void) fprintf(stderr, "%s: Error reading ", progname);
759		(void) perror(filename);
760		(void) exit(EXIT_FAILURE);
761	}
762	if (fp != stdin && fclose(fp)) {
763		(void) fprintf(stderr, "%s: Error closing ", progname);
764		(void) perror(filename);
765		(void) exit(EXIT_FAILURE);
766	}
767	if (wantcont)
768		error("expected continuation line not found");
769}
770
771/*
772** Convert a string of one of the forms
773**	h	-h 	hh:mm	-hh:mm	hh:mm:ss	-hh:mm:ss
774** into a number of seconds.
775** A null string maps to zero.
776** Call error with errstring and return zero on errors.
777*/
778
779static long
780gethms(string, errstring, signable)
781const char *		string;
782const char * const	errstring;
783const int		signable;
784{
785	int	hh, mm, ss, sign;
786
787	if (string == NULL || *string == '\0')
788		return 0;
789	if (!signable)
790		sign = 1;
791	else if (*string == '-') {
792		sign = -1;
793		++string;
794	} else	sign = 1;
795	if (sscanf(string, scheck(string, "%d"), &hh) == 1)
796		mm = ss = 0;
797	else if (sscanf(string, scheck(string, "%d:%d"), &hh, &mm) == 2)
798		ss = 0;
799	else if (sscanf(string, scheck(string, "%d:%d:%d"),
800		&hh, &mm, &ss) != 3) {
801			error(errstring);
802			return 0;
803	}
804	if (hh < 0 || hh >= HOURSPERDAY ||
805		mm < 0 || mm >= MINSPERHOUR ||
806		ss < 0 || ss > SECSPERMIN) {
807			error(errstring);
808			return 0;
809	}
810	return eitol(sign) *
811		(eitol(hh * MINSPERHOUR + mm) *
812		eitol(SECSPERMIN) + eitol(ss));
813}
814
815static void
816inrule(fields, nfields)
817register char ** const	fields;
818const int		nfields;
819{
820	static struct rule	r;
821
822	if (nfields != RULE_FIELDS) {
823		error("wrong number of fields on Rule line");
824		return;
825	}
826	if (*fields[RF_NAME] == '\0') {
827		error("nameless rule");
828		return;
829	}
830	r.r_filename = filename;
831	r.r_linenum = linenum;
832	r.r_stdoff = gethms(fields[RF_STDOFF], "invalid saved time", TRUE);
833	rulesub(&r, fields[RF_LOYEAR], fields[RF_HIYEAR], fields[RF_COMMAND],
834		fields[RF_MONTH], fields[RF_DAY], fields[RF_TOD]);
835	r.r_name = ecpyalloc(fields[RF_NAME]);
836	r.r_abbrvar = ecpyalloc(fields[RF_ABBRVAR]);
837	rules = (struct rule *) erealloc((char *) rules,
838		(int) ((nrules + 1) * sizeof *rules));
839	rules[nrules++] = r;
840}
841
842static int
843inzone(fields, nfields)
844register char ** const	fields;
845const int		nfields;
846{
847	register int	i;
848	static char *	buf;
849
850	if (nfields < ZONE_MINFIELDS || nfields > ZONE_MAXFIELDS) {
851		error("wrong number of fields on Zone line");
852		return FALSE;
853	}
854	if (strcmp(fields[ZF_NAME], TZDEFAULT) == 0 && lcltime != NULL) {
855		buf = erealloc(buf, 132 + strlen(TZDEFAULT));
856		(void) sprintf(buf,
857"\"Zone %s\" line and -l option are mutually exclusive",
858			TZDEFAULT);
859		error(buf);
860		return FALSE;
861	}
862	if (strcmp(fields[ZF_NAME], TZDEFRULES) == 0 && psxrules != NULL) {
863		buf = erealloc(buf, 132 + strlen(TZDEFRULES));
864		(void) sprintf(buf,
865"\"Zone %s\" line and -p option are mutually exclusive",
866			TZDEFRULES);
867		error(buf);
868		return FALSE;
869	}
870	for (i = 0; i < nzones; ++i)
871		if (zones[i].z_name != NULL &&
872			strcmp(zones[i].z_name, fields[ZF_NAME]) == 0) {
873				buf = erealloc(buf, 132 +
874					strlen(fields[ZF_NAME]) +
875					strlen(zones[i].z_filename));
876				(void) sprintf(buf,
877"duplicate zone name %s (file \"%s\", line %d)",
878					fields[ZF_NAME],
879					zones[i].z_filename,
880					zones[i].z_linenum);
881				error(buf);
882				return FALSE;
883		}
884	return inzsub(fields, nfields, FALSE);
885}
886
887static int
888inzcont(fields, nfields)
889register char ** const	fields;
890const int		nfields;
891{
892	if (nfields < ZONEC_MINFIELDS || nfields > ZONEC_MAXFIELDS) {
893		error("wrong number of fields on Zone continuation line");
894		return FALSE;
895	}
896	return inzsub(fields, nfields, TRUE);
897}
898
899static int
900inzsub(fields, nfields, iscont)
901register char ** const	fields;
902const int		nfields;
903const int		iscont;
904{
905	register char *		cp;
906	static struct zone	z;
907	register int		i_gmtoff, i_rule, i_format;
908	register int		i_untilyear, i_untilmonth;
909	register int		i_untilday, i_untiltime;
910	register int		hasuntil;
911
912	if (iscont) {
913		i_gmtoff = ZFC_GMTOFF;
914		i_rule = ZFC_RULE;
915		i_format = ZFC_FORMAT;
916		i_untilyear = ZFC_TILYEAR;
917		i_untilmonth = ZFC_TILMONTH;
918		i_untilday = ZFC_TILDAY;
919		i_untiltime = ZFC_TILTIME;
920		z.z_name = NULL;
921	} else {
922		i_gmtoff = ZF_GMTOFF;
923		i_rule = ZF_RULE;
924		i_format = ZF_FORMAT;
925		i_untilyear = ZF_TILYEAR;
926		i_untilmonth = ZF_TILMONTH;
927		i_untilday = ZF_TILDAY;
928		i_untiltime = ZF_TILTIME;
929		z.z_name = ecpyalloc(fields[ZF_NAME]);
930	}
931	z.z_filename = filename;
932	z.z_linenum = linenum;
933	z.z_gmtoff = gethms(fields[i_gmtoff], "invalid GMT offset", TRUE);
934	if ((cp = strchr(fields[i_format], '%')) != 0) {
935		if (*++cp != 's' || strchr(cp, '%') != 0) {
936			error("invalid abbreviation format");
937			return FALSE;
938		}
939	}
940	z.z_rule = ecpyalloc(fields[i_rule]);
941	z.z_format = ecpyalloc(fields[i_format]);
942	hasuntil = nfields > i_untilyear;
943	if (hasuntil) {
944		z.z_untilrule.r_filename = filename;
945		z.z_untilrule.r_linenum = linenum;
946		rulesub(&z.z_untilrule,
947			fields[i_untilyear],
948			"only",
949			"",
950			(nfields > i_untilmonth) ?
951			fields[i_untilmonth] : "Jan",
952			(nfields > i_untilday) ? fields[i_untilday] : "1",
953			(nfields > i_untiltime) ? fields[i_untiltime] : "0");
954		z.z_untiltime = rpytime(&z.z_untilrule,
955			z.z_untilrule.r_loyear);
956		if (iscont && nzones > 0 &&
957			z.z_untiltime > min_time &&
958			z.z_untiltime < max_time &&
959			zones[nzones - 1].z_untiltime > min_time &&
960			zones[nzones - 1].z_untiltime < max_time &&
961			zones[nzones - 1].z_untiltime >= z.z_untiltime) {
962error("Zone continuation line end time is not after end time of previous line");
963				return FALSE;
964		}
965	}
966	zones = (struct zone *) erealloc((char *) zones,
967		(int) ((nzones + 1) * sizeof *zones));
968	zones[nzones++] = z;
969	/*
970	** If there was an UNTIL field on this line,
971	** there's more information about the zone on the next line.
972	*/
973	return hasuntil;
974}
975
976static void
977inleap(fields, nfields)
978register char ** const	fields;
979const int		nfields;
980{
981	register const char *		cp;
982	register const struct lookup *	lp;
983	register int			i, j;
984	int				year, month, day;
985	long				dayoff, tod;
986	time_t				t;
987
988	if (nfields != LEAP_FIELDS) {
989		error("wrong number of fields on Leap line");
990		return;
991	}
992	dayoff = 0;
993	cp = fields[LP_YEAR];
994	if (sscanf(cp, scheck(cp, "%d"), &year) != 1) {
995			/*
996			 * Leapin' Lizards!
997			 */
998			error("invalid leaping year");
999			return;
1000	}
1001	j = EPOCH_YEAR;
1002	while (j != year) {
1003		if (year > j) {
1004			i = len_years[isleap(j)];
1005			++j;
1006		} else {
1007			--j;
1008			i = -len_years[isleap(j)];
1009		}
1010		dayoff = oadd(dayoff, eitol(i));
1011	}
1012	if ((lp = byword(fields[LP_MONTH], mon_names)) == NULL) {
1013		error("invalid month name");
1014		return;
1015	}
1016	month = lp->l_value;
1017	j = TM_JANUARY;
1018	while (j != month) {
1019		i = len_months[isleap(year)][j];
1020		dayoff = oadd(dayoff, eitol(i));
1021		++j;
1022	}
1023	cp = fields[LP_DAY];
1024	if (sscanf(cp, scheck(cp, "%d"), &day) != 1 ||
1025		day <= 0 || day > len_months[isleap(year)][month]) {
1026			error("invalid day of month");
1027			return;
1028	}
1029	dayoff = oadd(dayoff, eitol(day - 1));
1030	if (dayoff < 0 && !tt_signed) {
1031		error("time before zero");
1032		return;
1033	}
1034	t = (time_t) dayoff * SECSPERDAY;
1035	/*
1036	** Cheap overflow check.
1037	*/
1038	if (t / SECSPERDAY != dayoff) {
1039		error("time overflow");
1040		return;
1041	}
1042	tod = gethms(fields[LP_TIME], "invalid time of day", FALSE);
1043	cp = fields[LP_CORR];
1044	{
1045		register int	positive;
1046		int		count;
1047
1048		if (strcmp(cp, "") == 0) { /* infile() turns "-" into "" */
1049			positive = FALSE;
1050			count = 1;
1051		} else if (strcmp(cp, "--") == 0) {
1052			positive = FALSE;
1053			count = 2;
1054		} else if (strcmp(cp, "+") == 0) {
1055			positive = TRUE;
1056			count = 1;
1057		} else if (strcmp(cp, "++") == 0) {
1058			positive = TRUE;
1059			count = 2;
1060		} else {
1061			error("illegal CORRECTION field on Leap line");
1062			return;
1063		}
1064		if ((lp = byword(fields[LP_ROLL], leap_types)) == NULL) {
1065			error("illegal Rolling/Stationary field on Leap line");
1066			return;
1067		}
1068		leapadd(tadd(t, tod), positive, lp->l_value, count);
1069	}
1070}
1071
1072static void
1073inlink(fields, nfields)
1074register char ** const	fields;
1075const int		nfields;
1076{
1077	struct link	l;
1078
1079	if (nfields != LINK_FIELDS) {
1080		error("wrong number of fields on Link line");
1081		return;
1082	}
1083	if (*fields[LF_FROM] == '\0') {
1084		error("blank FROM field on Link line");
1085		return;
1086	}
1087	if (*fields[LF_TO] == '\0') {
1088		error("blank TO field on Link line");
1089		return;
1090	}
1091	l.l_filename = filename;
1092	l.l_linenum = linenum;
1093	l.l_from = ecpyalloc(fields[LF_FROM]);
1094	l.l_to = ecpyalloc(fields[LF_TO]);
1095	links = (struct link *) erealloc((char *) links,
1096		(int) ((nlinks + 1) * sizeof *links));
1097	links[nlinks++] = l;
1098}
1099
1100static void
1101rulesub(rp, loyearp, hiyearp, typep, monthp, dayp, timep)
1102register struct rule * const	rp;
1103char * const			loyearp;
1104char * const			hiyearp;
1105char * const			typep;
1106char * const			monthp;
1107char * const			dayp;
1108char * const			timep;
1109{
1110	register struct lookup const *	lp;
1111	register char *			cp;
1112
1113	if ((lp = byword(monthp, mon_names)) == NULL) {
1114		error("invalid month name");
1115		return;
1116	}
1117	rp->r_month = lp->l_value;
1118	rp->r_todisstd = FALSE;
1119	cp = timep;
1120	if (*cp != '\0') {
1121		cp += strlen(cp) - 1;
1122		switch (lowerit(*cp)) {
1123			case 's':
1124				rp->r_todisstd = TRUE;
1125				*cp = '\0';
1126				break;
1127			case 'w':
1128				rp->r_todisstd = FALSE;
1129				*cp = '\0';
1130				break;
1131		}
1132	}
1133	rp->r_tod = gethms(timep, "invalid time of day", FALSE);
1134	/*
1135	** Year work.
1136	*/
1137	cp = loyearp;
1138	if ((lp = byword(cp, begin_years)) != NULL) switch ((int) lp->l_value) {
1139		case YR_MINIMUM:
1140			rp->r_loyear = min_int;
1141			break;
1142		case YR_MAXIMUM:
1143			rp->r_loyear = max_int;
1144			break;
1145		default:	/* "cannot happen" */
1146			(void) fprintf(stderr,
1147				"%s: panic: Invalid l_value %d\n",
1148				progname, lp->l_value);
1149			(void) exit(EXIT_FAILURE);
1150	} else if (sscanf(cp, scheck(cp, "%d"), &rp->r_loyear) != 1) {
1151		error("invalid starting year");
1152		return;
1153	}
1154	cp = hiyearp;
1155	if ((lp = byword(cp, end_years)) != NULL) switch ((int) lp->l_value) {
1156		case YR_MINIMUM:
1157			rp->r_hiyear = min_int;
1158			break;
1159		case YR_MAXIMUM:
1160			rp->r_hiyear = max_int;
1161			break;
1162		case YR_ONLY:
1163			rp->r_hiyear = rp->r_loyear;
1164			break;
1165		default:	/* "cannot happen" */
1166			(void) fprintf(stderr,
1167				"%s: panic: Invalid l_value %d\n",
1168				progname, lp->l_value);
1169			(void) exit(EXIT_FAILURE);
1170	} else if (sscanf(cp, scheck(cp, "%d"), &rp->r_hiyear) != 1) {
1171		error("invalid ending year");
1172		return;
1173	}
1174	if (rp->r_loyear > rp->r_hiyear) {
1175		error("starting year greater than ending year");
1176		return;
1177	}
1178	if (*typep == '\0')
1179		rp->r_yrtype = NULL;
1180	else {
1181		if (rp->r_loyear == rp->r_hiyear) {
1182			error("typed single year");
1183			return;
1184		}
1185		rp->r_yrtype = ecpyalloc(typep);
1186	}
1187	/*
1188	** Day work.
1189	** Accept things such as:
1190	**	1
1191	**	last-Sunday
1192	**	Sun<=20
1193	**	Sun>=7
1194	*/
1195	if ((lp = byword(dayp, lasts)) != NULL) {
1196		rp->r_dycode = DC_DOWLEQ;
1197		rp->r_wday = lp->l_value;
1198		rp->r_dayofmonth = len_months[1][rp->r_month];
1199	} else {
1200		if ((cp = strchr(dayp, '<')) != 0)
1201			rp->r_dycode = DC_DOWLEQ;
1202		else if ((cp = strchr(dayp, '>')) != 0)
1203			rp->r_dycode = DC_DOWGEQ;
1204		else {
1205			cp = dayp;
1206			rp->r_dycode = DC_DOM;
1207		}
1208		if (rp->r_dycode != DC_DOM) {
1209			*cp++ = 0;
1210			if (*cp++ != '=') {
1211				error("invalid day of month");
1212				return;
1213			}
1214			if ((lp = byword(dayp, wday_names)) == NULL) {
1215				error("invalid weekday name");
1216				return;
1217			}
1218			rp->r_wday = lp->l_value;
1219		}
1220		if (sscanf(cp, scheck(cp, "%d"), &rp->r_dayofmonth) != 1 ||
1221			rp->r_dayofmonth <= 0 ||
1222			(rp->r_dayofmonth > len_months[1][rp->r_month])) {
1223				error("invalid day of month");
1224				return;
1225		}
1226	}
1227}
1228
1229static void
1230convert(val, buf)
1231const long	val;
1232char * const	buf;
1233{
1234	register int	i;
1235	register long	shift;
1236
1237	for (i = 0, shift = 24; i < 4; ++i, shift -= 8)
1238		buf[i] = val >> shift;
1239}
1240
1241static void
1242puttzcode(val, fp)
1243const long	val;
1244FILE * const	fp;
1245{
1246	char	buf[4];
1247
1248	convert(val, buf);
1249	(void) fwrite((genericptr_t) buf,
1250		(fwrite_size_t) sizeof buf,
1251		(fwrite_size_t) 1, fp);
1252}
1253
1254static void
1255writezone(name)
1256const char * const	name;
1257{
1258	register FILE *		fp;
1259	register int		i, j;
1260	static char *		fullname;
1261	static struct tzhead	tzh;
1262
1263	fullname = erealloc(fullname,
1264		strlen(directory) + 1 + strlen(name) + 1);
1265	(void) sprintf(fullname, "%s/%s", directory, name);
1266	if ((fp = fopen(fullname, "wb")) == NULL) {
1267		if (mkdirs(fullname) != 0)
1268			(void) exit(EXIT_FAILURE);
1269		if ((fp = fopen(fullname, "wb")) == NULL) {
1270			(void) fprintf(stderr, "%s: Can't create ", progname);
1271			(void) perror(fullname);
1272			(void) exit(EXIT_FAILURE);
1273		}
1274	}
1275	convert(eitol(typecnt), tzh.tzh_ttisstdcnt);
1276	convert(eitol(leapcnt), tzh.tzh_leapcnt);
1277	convert(eitol(timecnt), tzh.tzh_timecnt);
1278	convert(eitol(typecnt), tzh.tzh_typecnt);
1279	convert(eitol(charcnt), tzh.tzh_charcnt);
1280	(void) fwrite((genericptr_t) &tzh,
1281		(fwrite_size_t) sizeof tzh,
1282		(fwrite_size_t) 1, fp);
1283	for (i = 0; i < timecnt; ++i) {
1284		j = leapcnt;
1285		while (--j >= 0)
1286			if (ats[i] >= trans[j]) {
1287				ats[i] = tadd(ats[i], corr[j]);
1288				break;
1289			}
1290		puttzcode((long) ats[i], fp);
1291	}
1292	if (timecnt > 0)
1293		(void) fwrite((genericptr_t) types,
1294			(fwrite_size_t) sizeof types[0],
1295			(fwrite_size_t) timecnt, fp);
1296	for (i = 0; i < typecnt; ++i) {
1297		puttzcode((long) gmtoffs[i], fp);
1298		(void) putc(isdsts[i], fp);
1299		(void) putc(abbrinds[i], fp);
1300	}
1301	if (charcnt != 0)
1302		(void) fwrite((genericptr_t) chars,
1303			(fwrite_size_t) sizeof chars[0],
1304			(fwrite_size_t) charcnt, fp);
1305	for (i = 0; i < leapcnt; ++i) {
1306		if (roll[i]) {
1307			if (timecnt == 0 || trans[i] < ats[0]) {
1308				j = 0;
1309				while (isdsts[j])
1310					if (++j >= typecnt) {
1311						j = 0;
1312						break;
1313					}
1314			} else {
1315				j = 1;
1316				while (j < timecnt && trans[i] >= ats[j])
1317					++j;
1318				j = types[j - 1];
1319			}
1320			puttzcode((long) tadd(trans[i], -gmtoffs[j]), fp);
1321		} else	puttzcode((long) trans[i], fp);
1322		puttzcode((long) corr[i], fp);
1323	}
1324	for (i = 0; i < typecnt; ++i)
1325		(void) putc(ttisstds[i], fp);
1326	if (ferror(fp) || fclose(fp)) {
1327		(void) fprintf(stderr, "%s: Write error on ", progname);
1328		(void) perror(fullname);
1329		(void) exit(EXIT_FAILURE);
1330	}
1331}
1332
1333static void
1334outzone(zpfirst, zonecount)
1335const struct zone * const	zpfirst;
1336const int			zonecount;
1337{
1338	register const struct zone *	zp;
1339	register struct rule *		rp;
1340	register int			i, j;
1341	register int			usestart, useuntil;
1342	register time_t			starttime, untiltime;
1343	register long			gmtoff;
1344	register long			stdoff;
1345	register int			year;
1346	register long			startoff;
1347	register int			startisdst;
1348	register int			startttisstd;
1349	register int			type;
1350	char				startbuf[BUFSIZ];
1351
1352	/*
1353	** Now. . .finally. . .generate some useful data!
1354	*/
1355	timecnt = 0;
1356	typecnt = 0;
1357	charcnt = 0;
1358	/*
1359	** A guess that may well be corrected later.
1360	*/
1361	stdoff = 0;
1362	/*
1363	** Thanks to Earl Chew (earl@dnd.icp.nec.com.au)
1364	** for noting the need to unconditionally initialize startttisstd.
1365	*/
1366	startttisstd = FALSE;
1367#ifdef lint
1368	starttime = 0;
1369#endif /* defined lint */
1370	for (i = 0; i < zonecount; ++i) {
1371		zp = &zpfirst[i];
1372		usestart = i > 0 && (zp - 1)->z_untiltime > min_time;
1373		useuntil = i < (zonecount - 1);
1374		if (useuntil && zp->z_untiltime <= min_time)
1375			continue;
1376		gmtoff = zp->z_gmtoff;
1377		eat(zp->z_filename, zp->z_linenum);
1378		startisdst = -1;
1379		if (zp->z_nrules == 0) {
1380			stdoff = zp->z_stdoff;
1381			(void) strcpy(startbuf, zp->z_format);
1382			type = addtype(oadd(zp->z_gmtoff, stdoff),
1383				startbuf, stdoff != 0, startttisstd);
1384			if (usestart)
1385				addtt(starttime, type);
1386			else if (stdoff != 0)
1387				addtt(min_time, type);
1388		} else for (year = min_year; year <= max_year; ++year) {
1389			if (useuntil && year > zp->z_untilrule.r_hiyear)
1390				break;
1391			/*
1392			** Mark which rules to do in the current year.
1393			** For those to do, calculate rpytime(rp, year);
1394			*/
1395			for (j = 0; j < zp->z_nrules; ++j) {
1396				rp = &zp->z_rules[j];
1397				eats(zp->z_filename, zp->z_linenum,
1398					rp->r_filename, rp->r_linenum);
1399				rp->r_todo = year >= rp->r_loyear &&
1400						year <= rp->r_hiyear &&
1401						yearistype(year, rp->r_yrtype);
1402				if (rp->r_todo)
1403					rp->r_temp = rpytime(rp, year);
1404			}
1405			for ( ; ; ) {
1406				register int	k;
1407				register time_t	jtime, ktime;
1408				register long	offset;
1409				char		buf[BUFSIZ];
1410
1411				if (useuntil) {
1412					/*
1413					** Turn untiltime into GMT
1414					** assuming the current gmtoff and
1415					** stdoff values.
1416					*/
1417					untiltime = tadd(zp->z_untiltime,
1418						-gmtoff);
1419					if (!zp->z_untilrule.r_todisstd)
1420						untiltime = tadd(untiltime,
1421							-stdoff);
1422				}
1423				/*
1424				** Find the rule (of those to do, if any)
1425				** that takes effect earliest in the year.
1426				*/
1427				k = -1;
1428#ifdef lint
1429				ktime = 0;
1430#endif /* defined lint */
1431				for (j = 0; j < zp->z_nrules; ++j) {
1432					rp = &zp->z_rules[j];
1433					if (!rp->r_todo)
1434						continue;
1435					eats(zp->z_filename, zp->z_linenum,
1436						rp->r_filename, rp->r_linenum);
1437					offset = gmtoff;
1438					if (!rp->r_todisstd)
1439						offset = oadd(offset, stdoff);
1440					jtime = rp->r_temp;
1441					if (jtime == min_time ||
1442						jtime == max_time)
1443							continue;
1444					jtime = tadd(jtime, -offset);
1445					if (k < 0 || jtime < ktime) {
1446						k = j;
1447						ktime = jtime;
1448					}
1449				}
1450				if (k < 0)
1451					break;	/* go on to next year */
1452				rp = &zp->z_rules[k];
1453				rp->r_todo = FALSE;
1454				if (useuntil && ktime >= untiltime)
1455					break;
1456				if (usestart) {
1457				    if (ktime < starttime) {
1458					stdoff = rp->r_stdoff;
1459					startoff = oadd(zp->z_gmtoff,
1460						rp->r_stdoff);
1461					(void) sprintf(startbuf, zp->z_format,
1462						rp->r_abbrvar);
1463					startisdst = rp->r_stdoff != 0;
1464					continue;
1465				    }
1466				    usestart = FALSE;
1467				    if (ktime != starttime) {
1468					if (startisdst < 0 &&
1469					    zp->z_gmtoff !=
1470					    (zp - 1)->z_gmtoff) {
1471						type = (timecnt == 0) ? 0 :
1472							types[timecnt - 1];
1473						startoff = oadd(gmtoffs[type],
1474							-(zp - 1)->z_gmtoff);
1475						startisdst = startoff != 0;
1476						startoff = oadd(startoff,
1477							zp->z_gmtoff);
1478						(void) strcpy(startbuf,
1479							&chars[abbrinds[type]]);
1480					}
1481					if (startisdst >= 0)
1482addtt(starttime, addtype(startoff, startbuf, startisdst, startttisstd));
1483				    }
1484				}
1485				eats(zp->z_filename, zp->z_linenum,
1486					rp->r_filename, rp->r_linenum);
1487				(void) sprintf(buf, zp->z_format,
1488					rp->r_abbrvar);
1489				offset = oadd(zp->z_gmtoff, rp->r_stdoff);
1490				type = addtype(offset, buf, rp->r_stdoff != 0,
1491					rp->r_todisstd);
1492				addtt(ktime, type);
1493				stdoff = rp->r_stdoff;
1494			}
1495		}
1496		/*
1497		** Now we may get to set starttime for the next zone line.
1498		*/
1499		if (useuntil) {
1500			starttime = tadd(zp->z_untiltime, -gmtoff);
1501			startttisstd = zp->z_untilrule.r_todisstd;
1502			if (!startttisstd)
1503				starttime = tadd(starttime, -stdoff);
1504		}
1505	}
1506	writezone(zpfirst->z_name);
1507}
1508
1509static void
1510addtt(starttime, type)
1511const time_t	starttime;
1512const int	type;
1513{
1514	if (timecnt != 0 && type == types[timecnt - 1])
1515		return;	/* easy enough! */
1516	if (timecnt == 0 && type == 0 && isdsts[0] == 0)
1517		return; /* handled by default rule */
1518	if (timecnt >= TZ_MAX_TIMES) {
1519		error("too many transitions?!");
1520		(void) exit(EXIT_FAILURE);
1521	}
1522	ats[timecnt] = starttime;
1523	types[timecnt] = type;
1524	++timecnt;
1525}
1526
1527static int
1528addtype(gmtoff, abbr, isdst, ttisstd)
1529const long		gmtoff;
1530const char * const	abbr;
1531const int		isdst;
1532const int		ttisstd;
1533{
1534	register int	i, j;
1535
1536	/*
1537	** See if there's already an entry for this zone type.
1538	** If so, just return its index.
1539	*/
1540	for (i = 0; i < typecnt; ++i) {
1541		if (gmtoff == gmtoffs[i] && isdst == isdsts[i] &&
1542			strcmp(abbr, &chars[abbrinds[i]]) == 0 &&
1543			ttisstd == ttisstds[i])
1544				return i;
1545	}
1546	/*
1547	** There isn't one; add a new one, unless there are already too
1548	** many.
1549	*/
1550	if (typecnt >= TZ_MAX_TYPES) {
1551		error("too many local time types");
1552		(void) exit(EXIT_FAILURE);
1553	}
1554	gmtoffs[i] = gmtoff;
1555	isdsts[i] = isdst;
1556	ttisstds[i] = ttisstd;
1557
1558	for (j = 0; j < charcnt; ++j)
1559		if (strcmp(&chars[j], abbr) == 0)
1560			break;
1561	if (j == charcnt)
1562		newabbr(abbr);
1563	abbrinds[i] = j;
1564	++typecnt;
1565	return i;
1566}
1567
1568static void
1569leapadd(t, positive, rolling, count)
1570const time_t	t;
1571const int	positive;
1572const int	rolling;
1573int		count;
1574{
1575	register int	i, j;
1576
1577	if (leapcnt + (positive ? count : 1) > TZ_MAX_LEAPS) {
1578		error("too many leap seconds");
1579		(void) exit(EXIT_FAILURE);
1580	}
1581	for (i = 0; i < leapcnt; ++i)
1582		if (t <= trans[i]) {
1583			if (t == trans[i]) {
1584				error("repeated leap second moment");
1585				(void) exit(EXIT_FAILURE);
1586			}
1587			break;
1588		}
1589	do {
1590		for (j = leapcnt; j > i; --j) {
1591			trans[j] = trans[j - 1];
1592			corr[j] = corr[j - 1];
1593			roll[j] = roll[j - 1];
1594		}
1595		trans[i] = t;
1596		corr[i] = positive ? 1L : eitol(-count);
1597		roll[i] = rolling;
1598		++leapcnt;
1599	} while (positive && --count != 0);
1600}
1601
1602static void
1603adjleap()
1604{
1605	register int	i;
1606	register long	last = 0;
1607
1608	/*
1609	** propagate leap seconds forward
1610	*/
1611	for (i = 0; i < leapcnt; ++i) {
1612		trans[i] = tadd(trans[i], last);
1613		last = corr[i] += last;
1614	}
1615}
1616
1617static int
1618yearistype(year, type)
1619const int		year;
1620const char * const	type;
1621{
1622	static char *	buf;
1623	int		result;
1624
1625	if (type == NULL || *type == '\0')
1626		return TRUE;
1627	if (strcmp(type, "uspres") == 0)
1628		return (year % 4) == 0;
1629	if (strcmp(type, "nonpres") == 0)
1630		return (year % 4) != 0;
1631	buf = erealloc(buf, 132 + strlen(yitcommand) + strlen(type));
1632	(void) sprintf(buf, "%s %d %s", yitcommand, year, type);
1633	result = system(buf);
1634	if (result == 0)
1635		return TRUE;
1636	if (result == (1 << 8))
1637		return FALSE;
1638	error("Wild result from command execution");
1639	(void) fprintf(stderr, "%s: command was '%s', result was %d\n",
1640		progname, buf, result);
1641	for ( ; ; )
1642		(void) exit(EXIT_FAILURE);
1643}
1644
1645static int
1646lowerit(a)
1647const int	a;
1648{
1649	return (isascii(a) && isupper(a)) ? tolower(a) : a;
1650}
1651
1652static int
1653ciequal(ap, bp)		/* case-insensitive equality */
1654register const char *	ap;
1655register const char *	bp;
1656{
1657	while (lowerit(*ap) == lowerit(*bp++))
1658		if (*ap++ == '\0')
1659			return TRUE;
1660	return FALSE;
1661}
1662
1663static int
1664itsabbr(abbr, word)
1665register const char *	abbr;
1666register const char *	word;
1667{
1668	if (lowerit(*abbr) != lowerit(*word))
1669		return FALSE;
1670	++word;
1671	while (*++abbr != '\0')
1672		do if (*word == '\0')
1673			return FALSE;
1674				while (lowerit(*word++) != lowerit(*abbr));
1675	return TRUE;
1676}
1677
1678static const struct lookup *
1679byword(word, table)
1680register const char * const		word;
1681register const struct lookup * const	table;
1682{
1683	register const struct lookup *	foundlp;
1684	register const struct lookup *	lp;
1685
1686	if (word == NULL || table == NULL)
1687		return NULL;
1688	/*
1689	** Look for exact match.
1690	*/
1691	for (lp = table; lp->l_word != NULL; ++lp)
1692		if (ciequal(word, lp->l_word))
1693			return lp;
1694	/*
1695	** Look for inexact match.
1696	*/
1697	foundlp = NULL;
1698	for (lp = table; lp->l_word != NULL; ++lp)
1699		if (itsabbr(word, lp->l_word))
1700			if (foundlp == NULL)
1701				foundlp = lp;
1702			else	return NULL;	/* multiple inexact matches */
1703	return foundlp;
1704}
1705
1706static char **
1707getfields(cp)
1708register char *	cp;
1709{
1710	register char *		dp;
1711	register char **	array;
1712	register int		nsubs;
1713
1714	if (cp == NULL)
1715		return NULL;
1716	array = (char **) emalloc((int) ((strlen(cp) + 1) * sizeof *array));
1717	nsubs = 0;
1718	for ( ; ; ) {
1719		while (isascii(*cp) && isspace(*cp))
1720			++cp;
1721		if (*cp == '\0' || *cp == '#')
1722			break;
1723		array[nsubs++] = dp = cp;
1724		do {
1725			if ((*dp = *cp++) != '"')
1726				++dp;
1727			else while ((*dp = *cp++) != '"')
1728				if (*dp != '\0')
1729					++dp;
1730				else	error("Odd number of quotation marks");
1731		} while (*cp != '\0' && *cp != '#' &&
1732			(!isascii(*cp) || !isspace(*cp)));
1733		if (isascii(*cp) && isspace(*cp))
1734			++cp;
1735		*dp = '\0';
1736	}
1737	array[nsubs] = NULL;
1738	return array;
1739}
1740
1741static long
1742oadd(t1, t2)
1743const long	t1;
1744const long	t2;
1745{
1746	register long	t;
1747
1748	t = t1 + t2;
1749	if ((t2 > 0 && t <= t1) || (t2 < 0 && t >= t1)) {
1750		error("time overflow");
1751		(void) exit(EXIT_FAILURE);
1752	}
1753	return t;
1754}
1755
1756static time_t
1757tadd(t1, t2)
1758const time_t	t1;
1759const long	t2;
1760{
1761	register time_t	t;
1762
1763	if (t1 == max_time && t2 > 0)
1764		return max_time;
1765	if (t1 == min_time && t2 < 0)
1766		return min_time;
1767	t = t1 + t2;
1768	if ((t2 > 0 && t <= t1) || (t2 < 0 && t >= t1)) {
1769		error("time overflow");
1770		(void) exit(EXIT_FAILURE);
1771	}
1772	return t;
1773}
1774
1775/*
1776** Given a rule, and a year, compute the date - in seconds since January 1,
1777** 1970, 00:00 LOCAL time - in that year that the rule refers to.
1778*/
1779
1780static time_t
1781rpytime(rp, wantedy)
1782register const struct rule * const	rp;
1783register const int			wantedy;
1784{
1785	register int	y, m, i;
1786	register long	dayoff;			/* with a nod to Margaret O. */
1787	register time_t	t;
1788
1789	if (wantedy == min_int)
1790		return min_time;
1791	if (wantedy == max_int)
1792		return max_time;
1793	dayoff = 0;
1794	m = TM_JANUARY;
1795	y = EPOCH_YEAR;
1796	while (wantedy != y) {
1797		if (wantedy > y) {
1798			i = len_years[isleap(y)];
1799			++y;
1800		} else {
1801			--y;
1802			i = -len_years[isleap(y)];
1803		}
1804		dayoff = oadd(dayoff, eitol(i));
1805	}
1806	while (m != rp->r_month) {
1807		i = len_months[isleap(y)][m];
1808		dayoff = oadd(dayoff, eitol(i));
1809		++m;
1810	}
1811	i = rp->r_dayofmonth;
1812	if (m == TM_FEBRUARY && i == 29 && !isleap(y)) {
1813		if (rp->r_dycode == DC_DOWLEQ)
1814			--i;
1815		else {
1816			error("use of 2/29 in non leap-year");
1817			(void) exit(EXIT_FAILURE);
1818		}
1819	}
1820	--i;
1821	dayoff = oadd(dayoff, eitol(i));
1822	if (rp->r_dycode == DC_DOWGEQ || rp->r_dycode == DC_DOWLEQ) {
1823		register long	wday;
1824
1825#define LDAYSPERWEEK	((long) DAYSPERWEEK)
1826		wday = eitol(EPOCH_WDAY);
1827		/*
1828		** Don't trust mod of negative numbers.
1829		*/
1830		if (dayoff >= 0)
1831			wday = (wday + dayoff) % LDAYSPERWEEK;
1832		else {
1833			wday -= ((-dayoff) % LDAYSPERWEEK);
1834			if (wday < 0)
1835				wday += LDAYSPERWEEK;
1836		}
1837		while (wday != eitol(rp->r_wday))
1838			if (rp->r_dycode == DC_DOWGEQ) {
1839				dayoff = oadd(dayoff, (long) 1);
1840				if (++wday >= LDAYSPERWEEK)
1841					wday = 0;
1842				++i;
1843			} else {
1844				dayoff = oadd(dayoff, (long) -1);
1845				if (--wday < 0)
1846					wday = LDAYSPERWEEK - 1;
1847				--i;
1848			}
1849		if (i < 0 || i >= len_months[isleap(y)][m]) {
1850			error("no day in month matches rule");
1851			(void) exit(EXIT_FAILURE);
1852		}
1853	}
1854	if (dayoff < 0 && !tt_signed)
1855		return min_time;
1856	t = (time_t) dayoff * SECSPERDAY;
1857	/*
1858	** Cheap overflow check.
1859	*/
1860	if (t / SECSPERDAY != dayoff)
1861		return (dayoff > 0) ? max_time : min_time;
1862	return tadd(t, rp->r_tod);
1863}
1864
1865static void
1866newabbr(string)
1867const char * const	string;
1868{
1869	register int	i;
1870
1871	i = strlen(string) + 1;
1872	if (charcnt + i > TZ_MAX_CHARS) {
1873		error("too many, or too long, time zone abbreviations");
1874		(void) exit(EXIT_FAILURE);
1875	}
1876	(void) strcpy(&chars[charcnt], string);
1877	charcnt += eitol(i);
1878}
1879
1880static int
1881mkdirs(argname)
1882char * const	argname;
1883{
1884	register char *	name;
1885	register char *	cp;
1886
1887	if (argname == NULL || *argname == '\0')
1888		return 0;
1889	cp = name = ecpyalloc(argname);
1890	while ((cp = strchr(cp + 1, '/')) != 0) {
1891		*cp = '\0';
1892#ifndef unix
1893		/*
1894		** MS-DOS drive specifier?
1895		*/
1896		if (strlen(name) == 2 && isascii(name[0]) &&
1897			isalpha(name[0]) && name[1] == ':') {
1898				*cp = '/';
1899				continue;
1900		}
1901#endif /* !defined unix */
1902		if (!itsdir(name)) {
1903			/*
1904			** It doesn't seem to exist, so we try to create it.
1905			*/
1906			if (emkdir(name, 0755) != 0) {
1907				(void) fprintf(stderr,
1908					"%s: Can't create directory ",
1909					progname);
1910				(void) perror(name);
1911				ifree(name);
1912				return -1;
1913			}
1914		}
1915		*cp = '/';
1916	}
1917	ifree(name);
1918	return 0;
1919}
1920
1921static long
1922eitol(i)
1923const int	i;
1924{
1925	long	l;
1926
1927	l = i;
1928	if ((i < 0 && l >= 0) || (i == 0 && l != 0) || (i > 0 && l <= 0)) {
1929		(void) fprintf(stderr,
1930			"%s: %d did not sign extend correctly\n",
1931			progname, i);
1932		(void) exit(EXIT_FAILURE);
1933	}
1934	return l;
1935}
1936
1937/*
1938** UNIX is a registered trademark of AT&T.
1939*/
1940