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