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