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