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