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