1193323Sed/*	$NetBSD: zic.c,v 1.28 2011/01/15 12:31:57 martin Exp $	*/
2193323Sed/*
3193323Sed** This file is in the public domain, so clarified as of
4193323Sed** 2006-07-17 by Arthur David Olson.
5193323Sed*/
6193323Sed
7193323Sed#if HAVE_NBTOOL_CONFIG_H
8193323Sed#include "nbtool_config.h"
9193323Sed#endif
10193323Sed
11249423Sdim#include <sys/cdefs.h>
12198090Srdivacky#ifndef lint
13234353Sdim__RCSID("$NetBSD: zic.c,v 1.28 2011/01/15 12:31:57 martin Exp $");
14234353Sdim#endif /* !defined lint */
15193323Sed
16193323Sedstatic char	elsieid[] = "@(#)zic.c	8.25";
17193323Sed
18193323Sed#include "private.h"
19193323Sed#include "locale.h"
20193323Sed#include "tzfile.h"
21218893Sdim
22249423Sdim#define	ZIC_VERSION	'2'
23198090Srdivacky
24234353Sdimtypedef int_fast64_t	zic_t;
25198090Srdivacky
26198090Srdivacky#ifndef ZIC_MAX_ABBR_LEN_WO_WARN
27226633Sdim#define ZIC_MAX_ABBR_LEN_WO_WARN	6
28226633Sdim#endif /* !defined ZIC_MAX_ABBR_LEN_WO_WARN */
29198090Srdivacky
30198090Srdivacky#if HAVE_SYS_STAT_H
31263508Sdim#include "sys/stat.h"
32198090Srdivacky#endif
33234353Sdim#ifdef S_IRUSR
34198090Srdivacky#define MKDIR_UMASK (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)
35203954Srdivacky#else
36251662Sdim#define MKDIR_UMASK 0755
37198090Srdivacky#endif
38198090Srdivacky
39198090Srdivacky#include "unistd.h"
40198090Srdivacky
41198090Srdivacky/*
42239462Sdim** On some ancient hosts, predicates like `isspace(C)' are defined
43239462Sdim** only if isascii(C) || C == EOF. Modern hosts obey the C Standard,
44226633Sdim** which says they are defined only if C == ((unsigned char) C) || C == EOF.
45226633Sdim** Neither the C Standard nor Posix require that `isascii' exist.
46243830Sdim** For portability, we check both ancient and modern requirements.
47243830Sdim** If isascii is not defined, the isascii check succeeds trivially.
48193323Sed*/
49193323Sed#include "ctype.h"
50234353Sdim#ifndef isascii
51193323Sed#define isascii(x) 1
52193323Sed#endif
53198090Srdivacky
54198090Srdivacky#define OFFSET_STRLEN_MAXIMUM	(7 + INT_STRLEN_MAXIMUM(long))
55198090Srdivacky#define RULE_STRLEN_MAXIMUM	8	/* "Mdd.dd.d" */
56198090Srdivacky
57198090Srdivacky#define end(cp)	(strchr((cp), '\0'))
58249423Sdim
59249423Sdimstruct rule {
60198090Srdivacky	const char *	r_filename;
61198090Srdivacky	int		r_linenum;
62198090Srdivacky	const char *	r_name;
63198090Srdivacky
64263508Sdim	int		r_loyear;	/* for example, 1986 */
65198090Srdivacky	int		r_hiyear;	/* for example, 1986 */
66198090Srdivacky	const char *	r_yrtype;
67239462Sdim	int		r_lowasnum;
68239462Sdim	int		r_hiwasnum;
69239462Sdim
70239462Sdim	int		r_month;	/* 0..11 */
71234353Sdim
72239462Sdim	int		r_dycode;	/* see below */
73239462Sdim	int		r_dayofmonth;
74234353Sdim	int		r_wday;
75234353Sdim
76203954Srdivacky	long		r_tod;		/* time from midnight */
77198090Srdivacky	int		r_todisstd;	/* above is standard time if TRUE */
78198090Srdivacky					/* or wall clock time if FALSE */
79251662Sdim	int		r_todisgmt;	/* above is GMT if TRUE */
80251662Sdim					/* or local time if FALSE */
81198090Srdivacky	long		r_stdoff;	/* offset from standard time */
82198090Srdivacky	const char *	r_abbrvar;	/* variable part of abbreviation */
83218893Sdim
84198090Srdivacky	int		r_todo;		/* a rule to do (used in outzone) */
85218893Sdim	zic_t		r_temp;		/* used in outzone */
86239462Sdim};
87239462Sdim
88226633Sdim/*
89226633Sdim**	r_dycode		r_dayofmonth	r_wday
90243830Sdim*/
91243830Sdim
92198090Srdivacky#define DC_DOM		0	/* 1..31 */	/* unused */
93198090Srdivacky#define DC_DOWGEQ	1	/* 1..31 */	/* 0..6 (Sun..Sat) */
94198090Srdivacky#define DC_DOWLEQ	2	/* 1..31 */	/* 0..6 (Sun..Sat) */
95193323Sed
96193323Sedstruct zone {
97193323Sed	const char *	z_filename;
98193323Sed	int		z_linenum;
99193323Sed
100198090Srdivacky	const char *	z_name;
101221345Sdim	long		z_gmtoff;
102234353Sdim	const char *	z_rule;
103234353Sdim	const char *	z_format;
104243830Sdim
105243830Sdim	long		z_stdoff;
106263508Sdim
107193323Sed	struct rule *	z_rules;
108193323Sed	int		z_nrules;
109234353Sdim
110193323Sed	struct rule	z_untilrule;
111193323Sed	zic_t		z_untiltime;
112193323Sed};
113193323Sed
114193323Sedextern int	getopt(int argc, char * const argv[],
115193323Sed			const char * options);
116194612Sedextern int	link(const char * fromname, const char * toname);
117198090Srdivackyextern char *	optarg;
118193323Sedextern int	optind;
119193323Sed
120193323Sedstatic void	addtt(zic_t starttime, int type);
121221345Sdimstatic int	addtype(long gmtoff, const char * abbr, int isdst,
122226633Sdim				int ttisstd, int ttisgmt);
123193323Sedstatic void	leapadd(zic_t t, int positive, int rolling, int count);
124199989Srdivackystatic void	adjleap(void);
125221345Sdimstatic void	associate(void);
126198090Srdivackystatic int	ciequal(const char * ap, const char * bp);
127198090Srdivackystatic void	convert(long val, char * buf);
128195340Sedstatic void	convert64(zic_t val, char * buf);
129198090Srdivackystatic void	dolink(const char * fromfield, const char * tofield);
130198090Srdivackystatic void	doabbr(char * abbr, const int, const char * format,
131198396Srdivacky			const char * letters, int isdst, int doquotes);
132210299Sedstatic void	eat(const char * name, int num);
133224145Sdimstatic void	eats(const char * name, int num,
134249423Sdim			const char * rname, int rnum);
135234353Sdimstatic long	eitol(int i);
136239462Sdimstatic void	error(const char * message);
137243830Sdimstatic char **	getfields(char * buf);
138263508Sdimstatic long	gethms(const char * string, const char * errstrng,
139263508Sdim			int signable);
140193323Sedstatic void	infile(const char * filename);
141193323Sedstatic void	inleap(char ** fields, int nfields);
142234353Sdimstatic void	inlink(char ** fields, int nfields);
143193323Sedstatic void	inrule(char ** fields, int nfields);
144193323Sedstatic int	inzcont(char ** fields, int nfields);
145218893Sdimstatic int	inzone(char ** fields, int nfields);
146218893Sdimstatic int	inzsub(char ** fields, int nfields, int iscont);
147218893Sdimstatic int	is32(zic_t x);
148218893Sdimstatic int	itsabbr(const char * abbr, const char * word);
149234353Sdimstatic int	itsdir(const char * name);
150218893Sdimstatic int	lowerit(int c);
151249423Sdimint		main(int, char **);
152218893Sdimstatic char *	memcheck(char * tocheck);
153218893Sdimstatic int	mkdirs(char * filename);
154243830Sdimstatic void	newabbr(const char * abbr);
155243830Sdimstatic long	oadd(long t1, long t2);
156218893Sdimstatic void	outzone(const struct zone * zp, int ntzones);
157218893Sdimstatic void	puttzcode(long code, FILE * fp);
158234353Sdimstatic void	puttzcode64(zic_t code, FILE * fp);
159218893Sdimstatic int	rcomp(const void * leftp, const void * rightp);
160218893Sdimstatic zic_t	rpytime(const struct rule * rp, int wantedy);
161199481Srdivackystatic void	rulesub(struct rule * rp,
162234353Sdim			const char * loyearp, const char * hiyearp,
163249423Sdim			const char * typep, const char * monthp,
164234353Sdim			const char * dayp, const char * timep);
165234353Sdimstatic int 	stringoffset(char * result, long offset);
166234353Sdimstatic int	stringrule(char * result, const struct rule * rp,
167234353Sdim			long dstoff, long gmtoff);
168234353Sdimstatic void 	stringzone(char * result, const int,
169234353Sdim			const struct zone * zp, int ntzones);
170234353Sdimstatic void	setboundaries(void);
171234353Sdimstatic zic_t	tadd(zic_t t1, long t2);
172234353Sdimstatic void	usage(FILE *stream, int status);
173263508Sdimstatic void	warning(const char * const);
174234353Sdimstatic void	writezone(const char * name, const char * string);
175234353Sdimstatic int	yearistype(int year, const char * type);
176234353Sdimstatic int	atcomp(const void *avp, const void *bvp);
177234353Sdimstatic void	updateminmax(int x);
178251662Sdim
179234353Sdimstatic int		charcnt;
180234353Sdimstatic int		errors;
181234353Sdimstatic const char *	filename;
182234353Sdimstatic int		leapcnt;
183234353Sdimstatic int		leapseen;
184239462Sdimstatic int		leapminyear;
185239462Sdimstatic int		leapmaxyear;
186234353Sdimstatic int		linenum;
187234353Sdimstatic int		max_abbrvar_len;
188243830Sdimstatic int		max_format_len;
189243830Sdimstatic zic_t		max_time;
190234353Sdimstatic int		max_year;
191198090Srdivackystatic zic_t		min_time;
192198090Srdivackystatic int		min_year;
193206083Srdivackystatic int		noise;
194199481Srdivackystatic const char *	rfilename;
195221345Sdimstatic int		rlinenum;
196199481Srdivackystatic const char *	progname;
197199481Srdivackystatic int		timecnt;
198234353Sdimstatic int		typecnt;
199234353Sdim
200234353Sdim/*
201234353Sdim** Line codes.
202234353Sdim*/
203263508Sdim
204234353Sdim#define LC_RULE		0
205234353Sdim#define LC_ZONE		1
206234353Sdim#define LC_LINK		2
207234353Sdim#define LC_LEAP		3
208234353Sdim
209234353Sdim/*
210239462Sdim** Which fields are which on a Zone line.
211239462Sdim*/
212234353Sdim
213234353Sdim#define ZF_NAME		1
214243830Sdim#define ZF_GMTOFF	2
215243830Sdim#define ZF_RULE		3
216234353Sdim#define ZF_FORMAT	4
217199481Srdivacky#define ZF_TILYEAR	5
218199481Srdivacky#define ZF_TILMONTH	6
219234353Sdim#define ZF_TILDAY	7
220234353Sdim#define ZF_TILTIME	8
221234353Sdim#define ZONE_MINFIELDS	5
222234353Sdim#define ZONE_MAXFIELDS	9
223234353Sdim
224263508Sdim/*
225234353Sdim** Which fields are which on a Zone continuation line.
226234353Sdim*/
227263508Sdim
228249423Sdim#define ZFC_GMTOFF	0
229234353Sdim#define ZFC_RULE	1
230234353Sdim#define ZFC_FORMAT	2
231234353Sdim#define ZFC_TILYEAR	3
232234353Sdim#define ZFC_TILMONTH	4
233234353Sdim#define ZFC_TILDAY	5
234234353Sdim#define ZFC_TILTIME	6
235234353Sdim#define ZONEC_MINFIELDS	3
236234353Sdim#define ZONEC_MAXFIELDS	7
237234353Sdim
238234353Sdim/*
239234353Sdim** Which files are which on a Rule line.
240234353Sdim*/
241234353Sdim
242251662Sdim#define RF_NAME		1
243234353Sdim#define RF_LOYEAR	2
244263508Sdim#define RF_HIYEAR	3
245234353Sdim#define RF_COMMAND	4
246234353Sdim#define RF_MONTH	5
247239462Sdim#define RF_DAY		6
248239462Sdim#define RF_TOD		7
249234353Sdim#define RF_STDOFF	8
250234353Sdim#define RF_ABBRVAR	9
251243830Sdim#define RULE_FIELDS	10
252243830Sdim
253234353Sdim/*
254234353Sdim** Which fields are which on a Link line.
255193323Sed*/
256234353Sdim
257234353Sdim#define LF_FROM		1
258234353Sdim#define LF_TO		2
259234353Sdim#define LINK_FIELDS	3
260234353Sdim
261234353Sdim/*
262234353Sdim** Which fields are which on a Leap line.
263243830Sdim*/
264243830Sdim
265263508Sdim#define LP_YEAR		1
266234353Sdim#define LP_MONTH	2
267212904Sdim#define LP_DAY		3
268193323Sed#define LP_TIME		4
269234353Sdim#define LP_CORR		5
270234353Sdim#define LP_ROLL		6
271234353Sdim#define LEAP_FIELDS	7
272234353Sdim
273234353Sdim/*
274234353Sdim** Year synonyms.
275234353Sdim*/
276234353Sdim
277234353Sdim#define YR_MINIMUM	0
278234353Sdim#define YR_MAXIMUM	1
279234353Sdim#define YR_ONLY		2
280234353Sdim
281234353Sdimstatic struct rule *	rules;
282234353Sdimstatic int		nrules;	/* number of rules */
283234353Sdim
284234353Sdimstatic struct zone *	zones;
285234353Sdimstatic int		nzones;	/* number of zones */
286234353Sdim
287234353Sdimstruct link {
288234353Sdim	const char *	l_filename;
289249423Sdim	int		l_linenum;
290234353Sdim	const char *	l_from;
291239462Sdim	const char *	l_to;
292243830Sdim};
293263508Sdim
294263508Sdimstatic struct link *	links;
295234353Sdimstatic int		nlinks;
296212904Sdim
297193323Sedstruct lookup {
298234353Sdim	const char *	l_word;
299234353Sdim	const int	l_value;
300234353Sdim};
301234353Sdim
302234353Sdimstatic struct lookup const *	byword(const char * string,
303249423Sdim					const struct lookup * lp);
304234353Sdim
305234353Sdimstatic struct lookup const	line_codes[] = {
306243830Sdim	{ "Rule",	LC_RULE },
307243830Sdim	{ "Zone",	LC_ZONE },
308234353Sdim	{ "Link",	LC_LINK },
309212904Sdim	{ "Leap",	LC_LEAP },
310193323Sed	{ NULL,		0}
311234353Sdim};
312234353Sdim
313234353Sdimstatic struct lookup const	mon_names[] = {
314234353Sdim	{ "January",	TM_JANUARY },
315234353Sdim	{ "February",	TM_FEBRUARY },
316234353Sdim	{ "March",	TM_MARCH },
317234353Sdim	{ "April",	TM_APRIL },
318234353Sdim	{ "May",	TM_MAY },
319234353Sdim	{ "June",	TM_JUNE },
320234353Sdim	{ "July",	TM_JULY },
321218893Sdim	{ "August",	TM_AUGUST },
322218893Sdim	{ "September",	TM_SEPTEMBER },
323234353Sdim	{ "October",	TM_OCTOBER },
324234353Sdim	{ "November",	TM_NOVEMBER },
325234353Sdim	{ "December",	TM_DECEMBER },
326234353Sdim	{ NULL,		0 }
327234353Sdim};
328234353Sdim
329234353Sdimstatic struct lookup const	wday_names[] = {
330234353Sdim	{ "Sunday",	TM_SUNDAY },
331234353Sdim	{ "Monday",	TM_MONDAY },
332234353Sdim	{ "Tuesday",	TM_TUESDAY },
333234353Sdim	{ "Wednesday",	TM_WEDNESDAY },
334234353Sdim	{ "Thursday",	TM_THURSDAY },
335234353Sdim	{ "Friday",	TM_FRIDAY },
336212904Sdim	{ "Saturday",	TM_SATURDAY },
337234353Sdim	{ NULL,		0 }
338234353Sdim};
339234353Sdim
340234353Sdimstatic struct lookup const	lasts[] = {
341234353Sdim	{ "last-Sunday",	TM_SUNDAY },
342234353Sdim	{ "last-Monday",	TM_MONDAY },
343234353Sdim	{ "last-Tuesday",	TM_TUESDAY },
344234353Sdim	{ "last-Wednesday",	TM_WEDNESDAY },
345234353Sdim	{ "last-Thursday",	TM_THURSDAY },
346234353Sdim	{ "last-Friday",	TM_FRIDAY },
347234353Sdim	{ "last-Saturday",	TM_SATURDAY },
348234353Sdim	{ NULL,			0 }
349234353Sdim};
350193323Sed
351193323Sedstatic struct lookup const	begin_years[] = {
352212904Sdim	{ "minimum",	YR_MINIMUM },
353212904Sdim	{ "maximum",	YR_MAXIMUM },
354212904Sdim	{ NULL,		0 }
355234353Sdim};
356212904Sdim
357212904Sdimstatic struct lookup const	end_years[] = {
358212904Sdim	{ "minimum",	YR_MINIMUM },
359212904Sdim	{ "maximum",	YR_MAXIMUM },
360212904Sdim	{ "only",	YR_ONLY },
361212904Sdim	{ NULL,		0 }
362212904Sdim};
363212904Sdim
364234353Sdimstatic struct lookup const	leap_types[] = {
365212904Sdim	{ "Rolling",	TRUE },
366212904Sdim	{ "Stationary",	FALSE },
367234353Sdim	{ NULL,		0 }
368212904Sdim};
369212904Sdim
370234353Sdimstatic const int	len_months[2][MONSPERYEAR] = {
371218893Sdim	{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
372218893Sdim	{ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
373234353Sdim};
374212904Sdim
375212904Sdimstatic const int	len_years[2] = {
376212904Sdim	DAYSPERNYEAR, DAYSPERLYEAR
377218893Sdim};
378212904Sdim
379212904Sdimstatic struct attype {
380212904Sdim	zic_t		at;
381218893Sdim	unsigned char	type;
382212904Sdim}			attypes[TZ_MAX_TIMES];
383212904Sdimstatic long		gmtoffs[TZ_MAX_TYPES];
384212904Sdimstatic char		isdsts[TZ_MAX_TYPES];
385212904Sdimstatic unsigned char	abbrinds[TZ_MAX_TYPES];
386218893Sdimstatic char		ttisstds[TZ_MAX_TYPES];
387212904Sdimstatic char		ttisgmts[TZ_MAX_TYPES];
388212904Sdimstatic char		chars[TZ_MAX_CHARS];
389212904Sdimstatic zic_t		trans[TZ_MAX_LEAPS];
390212904Sdimstatic long		corr[TZ_MAX_LEAPS];
391212904Sdimstatic char		roll[TZ_MAX_LEAPS];
392218893Sdim
393212904Sdim/*
394212904Sdim** Memory allocation.
395212904Sdim*/
396212904Sdim
397212904Sdimstatic char *
398212904Sdimmemcheck(ptr)
399234353Sdimchar * const	ptr;
400212904Sdim{
401234353Sdim	if (ptr == NULL) {
402212904Sdim		const char *e = strerror(errno);
403212904Sdim
404212904Sdim		(void) fprintf(stderr, _("%s: Memory exhausted: %s\n"),
405234353Sdim			progname, e);
406212904Sdim		exit(EXIT_FAILURE);
407212904Sdim	}
408212904Sdim	return ptr;
409234353Sdim}
410212904Sdim
411212904Sdim#define emalloc(size)		memcheck(imalloc(size))
412218893Sdim#define erealloc(ptr, size)	memcheck(irealloc((ptr), (size)))
413234353Sdim#define ecpyalloc(ptr)		memcheck(icpyalloc(ptr))
414218893Sdim#define ecatalloc(oldp, newp)	memcheck(icatalloc((oldp), (newp)))
415218893Sdim
416212904Sdim/*
417212904Sdim** Error handling.
418212904Sdim*/
419212904Sdim
420212904Sdimstatic void
421212904Sdimeats(name, num, rname, rnum)
422212904Sdimconst char * const	name;
423212904Sdimconst int		num;
424212904Sdimconst char * const	rname;
425212904Sdimconst int		rnum;
426212904Sdim{
427212904Sdim	filename = name;
428212904Sdim	linenum = num;
429212904Sdim	rfilename = rname;
430212904Sdim	rlinenum = rnum;
431212904Sdim}
432212904Sdim
433212904Sdimstatic void
434234353Sdimeat(name, num)
435234353Sdimconst char * const	name;
436212904Sdimconst int		num;
437212904Sdim{
438212904Sdim	eats(name, num, (char *) NULL, -1);
439212904Sdim}
440212904Sdim
441212904Sdimstatic void
442212904Sdimerror(string)
443212904Sdimconst char * const	string;
444212904Sdim{
445212904Sdim	/*
446212904Sdim	** Match the format of "cc" to allow sh users to
447218893Sdim	**	zic ... 2>&1 | error -t "*" -v
448212904Sdim	** on BSD systems.
449212904Sdim	*/
450212904Sdim	(void) fprintf(stderr, _("\"%s\", line %d: %s"),
451212904Sdim		filename, linenum, string);
452212904Sdim	if (rfilename != NULL)
453212904Sdim		(void) fprintf(stderr, _(" (rule from \"%s\", line %d)"),
454218893Sdim			rfilename, rlinenum);
455218893Sdim	(void) fprintf(stderr, "\n");
456218893Sdim	++errors;
457212904Sdim}
458212904Sdim
459212904Sdimstatic void
460212904Sdimwarning(string)
461212904Sdimconst char * const	string;
462212904Sdim{
463234353Sdim	char *	cp;
464234353Sdim
465212904Sdim	cp = ecpyalloc(_("warning: "));
466212904Sdim	cp = ecatalloc(cp, string);
467212904Sdim	error(cp);
468212904Sdim	ifree(cp);
469212904Sdim	--errors;
470212904Sdim}
471212904Sdim
472212904Sdimstatic void
473212904Sdimusage(FILE *stream, int status)
474212904Sdim{
475212904Sdim	(void) fprintf(stream, _("%s: usage is %s \
476212904Sdim[ --version ] [ --help ] [ -v ] [ -l localtime ] [ -p posixrules ] \\\n\
477212904Sdim\t[ -d directory ] [ -L leapseconds ] [ -y yearistype ] [ filename ... ]\n\
478212904Sdim\n\
479212904SdimReport bugs to tz@elsie.nci.nih.gov.\n"),
480212904Sdim		       progname, progname);
481212904Sdim	exit(status);
482212904Sdim}
483212904Sdim
484212904Sdimstatic const char *	psxrules;
485212904Sdimstatic const char *	lcltime;
486198090Srdivackystatic const char *	directory;
487198090Srdivackystatic const char *	leapsec;
488193323Sedstatic const char *	yitcommand;
489193323Sed
490198090Srdivackyint
491198090Srdivackymain(argc, argv)
492198090Srdivackyint	argc;
493193323Sedchar *	argv[];
494193323Sed{
495198090Srdivacky	register int	i;
496198090Srdivacky	register int	j;
497198090Srdivacky	register int	c;
498198090Srdivacky
499193323Sed#ifdef _POSIX_VERSION
500193323Sed	(void) umask(umask(S_IWGRP | S_IWOTH) | (S_IWGRP | S_IWOTH));
501198090Srdivacky#endif /* defined _POSIX_VERSION */
502198090Srdivacky#if HAVE_GETTEXT - 0
503198090Srdivacky	(void) setlocale(LC_MESSAGES, "");
504198090Srdivacky#ifdef TZ_DOMAINDIR
505193323Sed	(void) bindtextdomain(TZ_DOMAIN, TZ_DOMAINDIR);
506193323Sed#endif /* defined TEXTDOMAINDIR */
507198090Srdivacky	(void) textdomain(TZ_DOMAIN);
508198090Srdivacky#endif /* HAVE_GETTEXT */
509198090Srdivacky	progname = argv[0];
510193323Sed	if (TYPE_BIT(zic_t) < 64) {
511193323Sed		(void) fprintf(stderr, "%s: %s\n", progname,
512198090Srdivacky			_("wild compilation-time specification of zic_t"));
513198090Srdivacky		exit(EXIT_FAILURE);
514221345Sdim	}
515218893Sdim	for (i = 1; i < argc; ++i)
516221345Sdim		if (strcmp(argv[i], "--version") == 0) {
517221345Sdim			(void) printf("%s\n", elsieid);
518221345Sdim			exit(EXIT_SUCCESS);
519218893Sdim		} else if (strcmp(argv[i], "--help") == 0) {
520198090Srdivacky			usage(stdout, EXIT_SUCCESS);
521198090Srdivacky		}
522221345Sdim	while ((c = getopt(argc, argv, "d:l:p:L:vsy:")) != EOF && c != -1)
523218893Sdim		switch (c) {
524198090Srdivacky			default:
525193323Sed				usage(stderr, EXIT_FAILURE);
526193323Sed			case 'd':
527221345Sdim				if (directory == NULL)
528221345Sdim					directory = optarg;
529198090Srdivacky				else {
530218893Sdim					(void) fprintf(stderr,
531221345Sdim_("%s: More than one -d option specified\n"),
532221345Sdim						progname);
533221345Sdim					exit(EXIT_FAILURE);
534221345Sdim				}
535218893Sdim				break;
536221345Sdim			case 'l':
537221345Sdim				if (lcltime == NULL)
538198090Srdivacky					lcltime = optarg;
539221345Sdim				else {
540221345Sdim					(void) fprintf(stderr,
541221345Sdim_("%s: More than one -l option specified\n"),
542221345Sdim						progname);
543221345Sdim					exit(EXIT_FAILURE);
544198090Srdivacky				}
545221345Sdim				break;
546221345Sdim			case 'p':
547218893Sdim				if (psxrules == NULL)
548221345Sdim					psxrules = optarg;
549221345Sdim				else {
550221345Sdim					(void) fprintf(stderr,
551221345Sdim_("%s: More than one -p option specified\n"),
552193323Sed						progname);
553193323Sed					exit(EXIT_FAILURE);
554234353Sdim				}
555234353Sdim				break;
556234353Sdim			case 'y':
557234353Sdim				if (yitcommand == NULL)
558234353Sdim					yitcommand = optarg;
559234353Sdim				else {
560234353Sdim					(void) fprintf(stderr,
561234353Sdim_("%s: More than one -y option specified\n"),
562234353Sdim						progname);
563234353Sdim					exit(EXIT_FAILURE);
564234353Sdim				}
565234353Sdim				break;
566234353Sdim			case 'L':
567234353Sdim				if (leapsec == NULL)
568234353Sdim					leapsec = optarg;
569234353Sdim				else {
570234353Sdim					(void) fprintf(stderr,
571234353Sdim_("%s: More than one -L option specified\n"),
572234353Sdim						progname);
573234353Sdim					exit(EXIT_FAILURE);
574234353Sdim				}
575234353Sdim				break;
576234353Sdim			case 'v':
577234353Sdim				noise = TRUE;
578234353Sdim				break;
579234353Sdim			case 's':
580234353Sdim				(void) printf("%s: -s ignored\n", progname);
581234353Sdim				break;
582234353Sdim		}
583234353Sdim	if (optind == argc - 1 && strcmp(argv[optind], "=") == 0)
584234353Sdim		usage(stderr, EXIT_FAILURE);	/* usage message by request */
585234353Sdim	if (directory == NULL)
586234353Sdim		directory = TZDIR;
587234353Sdim	if (yitcommand == NULL)
588234353Sdim		yitcommand = "yearistype";
589234353Sdim
590234353Sdim	setboundaries();
591234353Sdim
592234353Sdim	if (optind < argc && leapsec != NULL) {
593239462Sdim		infile(leapsec);
594239462Sdim		adjleap();
595239462Sdim	}
596239462Sdim
597239462Sdim	for (i = optind; i < argc; ++i)
598239462Sdim		infile(argv[i]);
599239462Sdim	if (errors)
600239462Sdim		exit(EXIT_FAILURE);
601239462Sdim	associate();
602239462Sdim	for (i = 0; i < nzones; i = j) {
603239462Sdim		/*
604239462Sdim		** Find the next non-continuation zone entry.
605239462Sdim		*/
606239462Sdim		for (j = i + 1; j < nzones && zones[j].z_name == NULL; ++j)
607239462Sdim			continue;
608239462Sdim		outzone(&zones[i], j - i);
609239462Sdim	}
610239462Sdim	/*
611239462Sdim	** Make links.
612239462Sdim	*/
613239462Sdim	for (i = 0; i < nlinks; ++i) {
614239462Sdim		eat(links[i].l_filename, links[i].l_linenum);
615239462Sdim		dolink(links[i].l_from, links[i].l_to);
616198090Srdivacky		if (noise)
617234353Sdim			for (j = 0; j < nlinks; ++j)
618193323Sed				if (strcmp(links[i].l_to,
619193323Sed					links[j].l_from) == 0)
620193323Sed						warning(_("link to link"));
621193323Sed	}
622193323Sed	if (lcltime != NULL) {
623193323Sed		eat("command line", 1);
624193323Sed		dolink(lcltime, TZDEFAULT);
625193323Sed	}
626193323Sed	if (psxrules != NULL) {
627193323Sed		eat("command line", 1);
628193323Sed		dolink(psxrules, TZDEFRULES);
629193323Sed	}
630193323Sed	return (errors == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
631193323Sed}
632218893Sdim
633218893Sdimstatic void
634218893Sdimdolink(fromfield, tofield)
635218893Sdimconst char * const	fromfield;
636199481Srdivackyconst char * const	tofield;
637198090Srdivacky{
638198090Srdivacky	register char *	fromname;
639198090Srdivacky	register char *	toname;
640198090Srdivacky
641198090Srdivacky	if (fromfield[0] == '/')
642198090Srdivacky		fromname = ecpyalloc(fromfield);
643198090Srdivacky	else {
644198090Srdivacky		fromname = ecpyalloc(directory);
645193323Sed		fromname = ecatalloc(fromname, "/");
646193323Sed		fromname = ecatalloc(fromname, fromfield);
647199481Srdivacky	}
648193323Sed	if (tofield[0] == '/')
649193323Sed		toname = ecpyalloc(tofield);
650193323Sed	else {
651199481Srdivacky		toname = ecpyalloc(directory);
652193323Sed		toname = ecatalloc(toname, "/");
653193323Sed		toname = ecatalloc(toname, tofield);
654193323Sed	}
655193323Sed	/*
656193323Sed	** We get to be careful here since
657193323Sed	** there's a fair chance of root running us.
658193323Sed	*/
659199481Srdivacky	if (!itsdir(toname))
660199481Srdivacky		(void) remove(toname);
661193323Sed	if (link(fromname, toname) != 0) {
662193323Sed		int	result;
663193323Sed
664199481Srdivacky		if (mkdirs(toname) != 0)
665193323Sed			exit(EXIT_FAILURE);
666193323Sed
667234353Sdim		result = link(fromname, toname);
668234353Sdim#if HAVE_SYMLINK
669234353Sdim		if (result != 0 &&
670234353Sdim			access(fromname, F_OK) == 0 &&
671234353Sdim			!itsdir(fromname)) {
672234353Sdim				const char *s = tofield;
673234353Sdim				register char * symlinkcontents = NULL;
674234353Sdim
675234353Sdim				while ((s = strchr(s+1, '/')) != NULL)
676234353Sdim					symlinkcontents =
677234353Sdim						ecatalloc(symlinkcontents,
678234353Sdim						"../");
679234353Sdim				symlinkcontents =
680234353Sdim					ecatalloc(symlinkcontents,
681234353Sdim					fromname);
682239462Sdim				result = symlink(symlinkcontents,
683234353Sdim					toname);
684234353Sdim				if (result == 0)
685234353Sdimwarning(_("hard link failed, symbolic link used"));
686234353Sdim				ifree(symlinkcontents);
687234353Sdim		}
688234353Sdim#endif /* HAVE_SYMLINK */
689234353Sdim		if (result != 0) {
690243830Sdim			const char *e = strerror(errno);
691234353Sdim
692234353Sdim			(void) fprintf(stderr,
693249423Sdim				_("%s: Can't link from %s to %s: %s\n"),
694234353Sdim				progname, fromname, toname, e);
695234353Sdim			exit(EXIT_FAILURE);
696239462Sdim		}
697234353Sdim	}
698263508Sdim	ifree(fromname);
699234353Sdim	ifree(toname);
700251662Sdim}
701234353Sdim
702243830Sdim#define TIME_T_BITS_IN_FILE	64
703234353Sdim
704234353Sdimstatic void
705234353Sdimsetboundaries(void)
706234353Sdim{
707234353Sdim	register int	i;
708234353Sdim
709234353Sdim	min_time = -1;
710234353Sdim	for (i = 0; i < TIME_T_BITS_IN_FILE - 1; ++i)
711234353Sdim		min_time *= 2;
712234353Sdim	max_time = -(min_time + 1);
713234353Sdim}
714234353Sdim
715234353Sdimstatic int
716234353Sdimitsdir(name)
717234353Sdimconst char * const	name;
718234353Sdim{
719234353Sdim	register char *	myname;
720234353Sdim	register int	accres;
721234353Sdim
722234353Sdim	myname = ecpyalloc(name);
723234353Sdim	myname = ecatalloc(myname, "/.");
724249423Sdim	accres = access(myname, F_OK);
725234353Sdim	ifree(myname);
726251662Sdim	return accres == 0;
727263508Sdim}
728234353Sdim
729234353Sdim/*
730234353Sdim** Associate sets of rules with zones.
731234353Sdim*/
732243830Sdim
733234353Sdim/*
734234353Sdim** Sort by rule name.
735234353Sdim*/
736234353Sdim
737234353Sdimstatic int
738239462Sdimrcomp(cp1, cp2)
739234353Sdimconst void *	cp1;
740234353Sdimconst void *	cp2;
741234353Sdim{
742234353Sdim	return strcmp(((const struct rule *) cp1)->r_name,
743234353Sdim		((const struct rule *) cp2)->r_name);
744234353Sdim}
745234353Sdim
746234353Sdimstatic void
747234353Sdimassociate(void)
748234353Sdim{
749234353Sdim	register struct zone *	zp;
750234353Sdim	register struct rule *	rp;
751239462Sdim	register int		base, out;
752234353Sdim	register int		i, j;
753234353Sdim
754234353Sdim	if (nrules != 0) {
755243830Sdim		(void) qsort((void *) rules, (size_t) nrules,
756234353Sdim			(size_t) sizeof *rules, rcomp);
757234353Sdim		for (i = 0; i < nrules - 1; ++i) {
758234353Sdim			if (strcmp(rules[i].r_name,
759234353Sdim				rules[i + 1].r_name) != 0)
760234353Sdim					continue;
761234353Sdim			if (strcmp(rules[i].r_filename,
762234353Sdim				rules[i + 1].r_filename) == 0)
763234353Sdim					continue;
764234353Sdim			eat(rules[i].r_filename, rules[i].r_linenum);
765234353Sdim			warning(_("same rule name in multiple files"));
766234353Sdim			eat(rules[i + 1].r_filename, rules[i + 1].r_linenum);
767234353Sdim			warning(_("same rule name in multiple files"));
768234353Sdim			for (j = i + 2; j < nrules; ++j) {
769234353Sdim				if (strcmp(rules[i].r_name,
770234353Sdim					rules[j].r_name) != 0)
771234353Sdim						break;
772234353Sdim				if (strcmp(rules[i].r_filename,
773234353Sdim					rules[j].r_filename) == 0)
774234353Sdim						continue;
775234353Sdim				if (strcmp(rules[i + 1].r_filename,
776249423Sdim					rules[j].r_filename) == 0)
777243830Sdim						continue;
778234353Sdim				break;
779234353Sdim			}
780239462Sdim			i = j - 1;
781234353Sdim		}
782263508Sdim	}
783234353Sdim	for (i = 0; i < nzones; ++i) {
784251662Sdim		zp = &zones[i];
785234353Sdim		zp->z_rules = NULL;
786234353Sdim		zp->z_nrules = 0;
787234353Sdim	}
788234353Sdim	for (base = 0; base < nrules; base = out) {
789234353Sdim		rp = &rules[base];
790234353Sdim		for (out = base + 1; out < nrules; ++out)
791239462Sdim			if (strcmp(rp->r_name, rules[out].r_name) != 0)
792234353Sdim				break;
793234353Sdim		for (i = 0; i < nzones; ++i) {
794234353Sdim			zp = &zones[i];
795243830Sdim			if (strcmp(zp->z_rule, rp->r_name) != 0)
796234353Sdim				continue;
797234353Sdim			zp->z_rules = rp;
798234353Sdim			zp->z_nrules = out - base;
799		}
800	}
801	for (i = 0; i < nzones; ++i) {
802		zp = &zones[i];
803		if (zp->z_nrules == 0) {
804			/*
805			** Maybe we have a local standard time offset.
806			*/
807			eat(zp->z_filename, zp->z_linenum);
808			zp->z_stdoff = gethms(zp->z_rule, _("unruly zone"),
809				TRUE);
810			/*
811			** Note, though, that if there's no rule,
812			** a '%s' in the format is a bad thing.
813			*/
814			if (strchr(zp->z_format, '%') != 0)
815				error(_("%s in ruleless zone"));
816		}
817	}
818	if (errors)
819		exit(EXIT_FAILURE);
820}
821
822static void
823infile(name)
824const char *	name;
825{
826	register FILE *			fp;
827	register char **		fields;
828	register char *			cp;
829	register const struct lookup *	lp;
830	register int			nfields;
831	register int			wantcont;
832	register int			num;
833	char				buf[BUFSIZ];
834
835	if (strcmp(name, "-") == 0) {
836		name = _("standard input");
837		fp = stdin;
838	} else if ((fp = fopen(name, "r")) == NULL) {
839		const char *e = strerror(errno);
840
841		(void) fprintf(stderr, _("%s: Can't open %s: %s\n"),
842			progname, name, e);
843		exit(EXIT_FAILURE);
844	}
845	wantcont = FALSE;
846	for (num = 1; ; ++num) {
847		eat(name, num);
848		if (fgets(buf, (int) sizeof buf, fp) != buf)
849			break;
850		cp = strchr(buf, '\n');
851		if (cp == NULL) {
852			error(_("line too long"));
853			exit(EXIT_FAILURE);
854		}
855		*cp = '\0';
856		fields = getfields(buf);
857		nfields = 0;
858		while (fields[nfields] != NULL) {
859			static char	nada;
860
861			if (strcmp(fields[nfields], "-") == 0)
862				fields[nfields] = &nada;
863			++nfields;
864		}
865		if (nfields == 0) {
866			/* nothing to do */
867		} else if (wantcont) {
868			wantcont = inzcont(fields, nfields);
869		} else {
870			lp = byword(fields[0], line_codes);
871			if (lp == NULL)
872				error(_("input line of unknown type"));
873			else switch ((int) (lp->l_value)) {
874				case LC_RULE:
875					inrule(fields, nfields);
876					wantcont = FALSE;
877					break;
878				case LC_ZONE:
879					wantcont = inzone(fields, nfields);
880					break;
881				case LC_LINK:
882					inlink(fields, nfields);
883					wantcont = FALSE;
884					break;
885				case LC_LEAP:
886					if (name != leapsec)
887						(void) fprintf(stderr,
888_("%s: Leap line in non leap seconds file %s\n"),
889							progname, name);
890					else	inleap(fields, nfields);
891					wantcont = FALSE;
892					break;
893				default:	/* "cannot happen" */
894					(void) fprintf(stderr,
895_("%s: panic: Invalid l_value %d\n"),
896						progname, lp->l_value);
897					exit(EXIT_FAILURE);
898			}
899		}
900		ifree((char *) fields);
901	}
902	if (ferror(fp)) {
903		(void) fprintf(stderr, _("%s: Error reading %s\n"),
904			progname, filename);
905		exit(EXIT_FAILURE);
906	}
907	if (fp != stdin && fclose(fp)) {
908		const char *e = strerror(errno);
909
910		(void) fprintf(stderr, _("%s: Error closing %s: %s\n"),
911			progname, filename, e);
912		exit(EXIT_FAILURE);
913	}
914	if (wantcont)
915		error(_("expected continuation line not found"));
916}
917
918/*
919** Convert a string of one of the forms
920**	h	-h	hh:mm	-hh:mm	hh:mm:ss	-hh:mm:ss
921** into a number of seconds.
922** A null string maps to zero.
923** Call error with errstring and return zero on errors.
924*/
925
926static long
927gethms(string, errstring, signable)
928const char *		string;
929const char * const	errstring;
930const int		signable;
931{
932	long	hh;
933	int	mm, ss, sign;
934
935	if (string == NULL || *string == '\0')
936		return 0;
937	if (!signable)
938		sign = 1;
939	else if (*string == '-') {
940		sign = -1;
941		++string;
942	} else	sign = 1;
943	if (sscanf(string, scheck(string, "%ld"), &hh) == 1)
944		mm = ss = 0;
945	else if (sscanf(string, scheck(string, "%ld:%d"), &hh, &mm) == 2)
946		ss = 0;
947	else if (sscanf(string, scheck(string, "%ld:%d:%d"),
948		&hh, &mm, &ss) != 3) {
949			error(errstring);
950			return 0;
951	}
952	if (hh < 0 ||
953		mm < 0 || mm >= MINSPERHOUR ||
954		ss < 0 || ss > SECSPERMIN) {
955			error(errstring);
956			return 0;
957	}
958	if (LONG_MAX / SECSPERHOUR < hh) {
959		error(_("time overflow"));
960		return 0;
961	}
962	if (noise && hh == HOURSPERDAY && mm == 0 && ss == 0)
963		warning(_("24:00 not handled by pre-1998 versions of zic"));
964	if (noise && (hh > HOURSPERDAY ||
965		(hh == HOURSPERDAY && (mm != 0 || ss != 0))))
966warning(_("values over 24 hours not handled by pre-2007 versions of zic"));
967	return oadd(eitol(sign) * hh * eitol(SECSPERHOUR),
968		    eitol(sign) * (eitol(mm) * eitol(SECSPERMIN) + eitol(ss)));
969}
970
971static void
972inrule(fields, nfields)
973register char ** const	fields;
974const int		nfields;
975{
976	static struct rule	r;
977
978	if (nfields != RULE_FIELDS) {
979		error(_("wrong number of fields on Rule line"));
980		return;
981	}
982	if (*fields[RF_NAME] == '\0') {
983		error(_("nameless rule"));
984		return;
985	}
986	r.r_filename = filename;
987	r.r_linenum = linenum;
988	r.r_stdoff = gethms(fields[RF_STDOFF], _("invalid saved time"), TRUE);
989	rulesub(&r, fields[RF_LOYEAR], fields[RF_HIYEAR], fields[RF_COMMAND],
990		fields[RF_MONTH], fields[RF_DAY], fields[RF_TOD]);
991	r.r_name = ecpyalloc(fields[RF_NAME]);
992	r.r_abbrvar = ecpyalloc(fields[RF_ABBRVAR]);
993	if (max_abbrvar_len < strlen(r.r_abbrvar))
994		max_abbrvar_len = strlen(r.r_abbrvar);
995	rules = (struct rule *) (void *) erealloc((char *) rules,
996		(int) ((nrules + 1) * sizeof *rules));
997	rules[nrules++] = r;
998}
999
1000static int
1001inzone(fields, nfields)
1002register char ** const	fields;
1003const int		nfields;
1004{
1005	register int	i;
1006	static char *	buf;
1007
1008	if (nfields < ZONE_MINFIELDS || nfields > ZONE_MAXFIELDS) {
1009		error(_("wrong number of fields on Zone line"));
1010		return FALSE;
1011	}
1012	if (strcmp(fields[ZF_NAME], TZDEFAULT) == 0 && lcltime != NULL) {
1013		buf = erealloc(buf, (int) (132 + strlen(TZDEFAULT)));
1014		(void)sprintf(buf,	/* XXX: sprintf is safe */
1015_("\"Zone %s\" line and -l option are mutually exclusive"),
1016			TZDEFAULT);
1017		error(buf);
1018		return FALSE;
1019	}
1020	if (strcmp(fields[ZF_NAME], TZDEFRULES) == 0 && psxrules != NULL) {
1021		buf = erealloc(buf, (int) (132 + strlen(TZDEFRULES)));
1022		(void)sprintf(buf,	/* XXX: sprintf is safe */
1023_("\"Zone %s\" line and -p option are mutually exclusive"),
1024			TZDEFRULES);
1025		error(buf);
1026		return FALSE;
1027	}
1028	for (i = 0; i < nzones; ++i)
1029		if (zones[i].z_name != NULL &&
1030			strcmp(zones[i].z_name, fields[ZF_NAME]) == 0) {
1031				buf = erealloc(buf, (int) (132 +
1032					strlen(fields[ZF_NAME]) +
1033					strlen(zones[i].z_filename)));
1034				(void)sprintf(buf,	/* XXX: sprintf is safe */
1035_("duplicate zone name %s (file \"%s\", line %d)"),
1036					fields[ZF_NAME],
1037					zones[i].z_filename,
1038					zones[i].z_linenum);
1039				error(buf);
1040				return FALSE;
1041		}
1042	return inzsub(fields, nfields, FALSE);
1043}
1044
1045static int
1046inzcont(fields, nfields)
1047register char ** const	fields;
1048const int		nfields;
1049{
1050	if (nfields < ZONEC_MINFIELDS || nfields > ZONEC_MAXFIELDS) {
1051		error(_("wrong number of fields on Zone continuation line"));
1052		return FALSE;
1053	}
1054	return inzsub(fields, nfields, TRUE);
1055}
1056
1057static int
1058inzsub(fields, nfields, iscont)
1059register char ** const	fields;
1060const int		nfields;
1061const int		iscont;
1062{
1063	register char *		cp;
1064	static struct zone	z;
1065	register int		i_gmtoff, i_rule, i_format;
1066	register int		i_untilyear, i_untilmonth;
1067	register int		i_untilday, i_untiltime;
1068	register int		hasuntil;
1069
1070	if (iscont) {
1071		i_gmtoff = ZFC_GMTOFF;
1072		i_rule = ZFC_RULE;
1073		i_format = ZFC_FORMAT;
1074		i_untilyear = ZFC_TILYEAR;
1075		i_untilmonth = ZFC_TILMONTH;
1076		i_untilday = ZFC_TILDAY;
1077		i_untiltime = ZFC_TILTIME;
1078		z.z_name = NULL;
1079	} else {
1080		i_gmtoff = ZF_GMTOFF;
1081		i_rule = ZF_RULE;
1082		i_format = ZF_FORMAT;
1083		i_untilyear = ZF_TILYEAR;
1084		i_untilmonth = ZF_TILMONTH;
1085		i_untilday = ZF_TILDAY;
1086		i_untiltime = ZF_TILTIME;
1087		z.z_name = ecpyalloc(fields[ZF_NAME]);
1088	}
1089	z.z_filename = filename;
1090	z.z_linenum = linenum;
1091	z.z_gmtoff = gethms(fields[i_gmtoff], _("invalid UTC offset"), TRUE);
1092	if ((cp = strchr(fields[i_format], '%')) != 0) {
1093		if (*++cp != 's' || strchr(cp, '%') != 0) {
1094			error(_("invalid abbreviation format"));
1095			return FALSE;
1096		}
1097	}
1098	z.z_rule = ecpyalloc(fields[i_rule]);
1099	z.z_format = ecpyalloc(fields[i_format]);
1100	if (max_format_len < strlen(z.z_format))
1101		max_format_len = strlen(z.z_format);
1102	hasuntil = nfields > i_untilyear;
1103	if (hasuntil) {
1104		z.z_untilrule.r_filename = filename;
1105		z.z_untilrule.r_linenum = linenum;
1106		rulesub(&z.z_untilrule,
1107			fields[i_untilyear],
1108			"only",
1109			"",
1110			(nfields > i_untilmonth) ?
1111			fields[i_untilmonth] : "Jan",
1112			(nfields > i_untilday) ? fields[i_untilday] : "1",
1113			(nfields > i_untiltime) ? fields[i_untiltime] : "0");
1114		z.z_untiltime = rpytime(&z.z_untilrule,
1115			z.z_untilrule.r_loyear);
1116		if (iscont && nzones > 0 &&
1117			z.z_untiltime > min_time &&
1118			z.z_untiltime < max_time &&
1119			zones[nzones - 1].z_untiltime > min_time &&
1120			zones[nzones - 1].z_untiltime < max_time &&
1121			zones[nzones - 1].z_untiltime >= z.z_untiltime) {
1122				error(_(
1123"Zone continuation line end time is not after end time of previous line"
1124					));
1125				return FALSE;
1126		}
1127	}
1128	zones = (struct zone *) (void *) erealloc((char *) zones,
1129		(int) ((nzones + 1) * sizeof *zones));
1130	zones[nzones++] = z;
1131	/*
1132	** If there was an UNTIL field on this line,
1133	** there's more information about the zone on the next line.
1134	*/
1135	return hasuntil;
1136}
1137
1138static void
1139inleap(fields, nfields)
1140register char ** const	fields;
1141const int		nfields;
1142{
1143	register const char *		cp;
1144	register const struct lookup *	lp;
1145	register int			i, j;
1146	int				year, month, day;
1147	long				dayoff, tod;
1148	zic_t				t;
1149
1150	if (nfields != LEAP_FIELDS) {
1151		error(_("wrong number of fields on Leap line"));
1152		return;
1153	}
1154	dayoff = 0;
1155	cp = fields[LP_YEAR];
1156	if (sscanf(cp, scheck(cp, "%d"), &year) != 1) {
1157		/*
1158		** Leapin' Lizards!
1159		*/
1160		error(_("invalid leaping year"));
1161		return;
1162	}
1163	if (!leapseen || leapmaxyear < year)
1164		leapmaxyear = year;
1165	if (!leapseen || leapminyear > year)
1166		leapminyear = year;
1167	leapseen = TRUE;
1168	j = EPOCH_YEAR;
1169	while (j != year) {
1170		if (year > j) {
1171			i = len_years[isleap(j)];
1172			++j;
1173		} else {
1174			--j;
1175			i = -len_years[isleap(j)];
1176		}
1177		dayoff = oadd(dayoff, eitol(i));
1178	}
1179	if ((lp = byword(fields[LP_MONTH], mon_names)) == NULL) {
1180		error(_("invalid month name"));
1181		return;
1182	}
1183	month = lp->l_value;
1184	j = TM_JANUARY;
1185	while (j != month) {
1186		i = len_months[isleap(year)][j];
1187		dayoff = oadd(dayoff, eitol(i));
1188		++j;
1189	}
1190	cp = fields[LP_DAY];
1191	if (sscanf(cp, scheck(cp, "%d"), &day) != 1 ||
1192		day <= 0 || day > len_months[isleap(year)][month]) {
1193			error(_("invalid day of month"));
1194			return;
1195	}
1196	dayoff = oadd(dayoff, eitol(day - 1));
1197	if (dayoff < 0 && !TYPE_SIGNED(zic_t)) {
1198		error(_("time before zero"));
1199		return;
1200	}
1201	if (dayoff < min_time / SECSPERDAY) {
1202		error(_("time too small"));
1203		return;
1204	}
1205	if (dayoff > max_time / SECSPERDAY) {
1206		error(_("time too large"));
1207		return;
1208	}
1209	t = (zic_t) dayoff * SECSPERDAY;
1210	tod = gethms(fields[LP_TIME], _("invalid time of day"), FALSE);
1211	cp = fields[LP_CORR];
1212	{
1213		register int	positive;
1214		int		count;
1215
1216		if (strcmp(cp, "") == 0) { /* infile() turns "-" into "" */
1217			positive = FALSE;
1218			count = 1;
1219		} else if (strcmp(cp, "--") == 0) {
1220			positive = FALSE;
1221			count = 2;
1222		} else if (strcmp(cp, "+") == 0) {
1223			positive = TRUE;
1224			count = 1;
1225		} else if (strcmp(cp, "++") == 0) {
1226			positive = TRUE;
1227			count = 2;
1228		} else {
1229			error(_("illegal CORRECTION field on Leap line"));
1230			return;
1231		}
1232		if ((lp = byword(fields[LP_ROLL], leap_types)) == NULL) {
1233			error(_(
1234				"illegal Rolling/Stationary field on Leap line"
1235				));
1236			return;
1237		}
1238		leapadd(tadd(t, tod), positive, lp->l_value, count);
1239	}
1240}
1241
1242static void
1243inlink(fields, nfields)
1244register char ** const	fields;
1245const int		nfields;
1246{
1247	struct link	l;
1248
1249	if (nfields != LINK_FIELDS) {
1250		error(_("wrong number of fields on Link line"));
1251		return;
1252	}
1253	if (*fields[LF_FROM] == '\0') {
1254		error(_("blank FROM field on Link line"));
1255		return;
1256	}
1257	if (*fields[LF_TO] == '\0') {
1258		error(_("blank TO field on Link line"));
1259		return;
1260	}
1261	l.l_filename = filename;
1262	l.l_linenum = linenum;
1263	l.l_from = ecpyalloc(fields[LF_FROM]);
1264	l.l_to = ecpyalloc(fields[LF_TO]);
1265	links = (struct link *) (void *) erealloc((char *) links,
1266		(int) ((nlinks + 1) * sizeof *links));
1267	links[nlinks++] = l;
1268}
1269
1270static void
1271rulesub(rp, loyearp, hiyearp, typep, monthp, dayp, timep)
1272register struct rule * const	rp;
1273const char * const		loyearp;
1274const char * const		hiyearp;
1275const char * const		typep;
1276const char * const		monthp;
1277const char * const		dayp;
1278const char * const		timep;
1279{
1280	register const struct lookup *	lp;
1281	register const char *		cp;
1282	register char *			dp;
1283	register char *			ep;
1284
1285	if ((lp = byword(monthp, mon_names)) == NULL) {
1286		error(_("invalid month name"));
1287		return;
1288	}
1289	rp->r_month = lp->l_value;
1290	rp->r_todisstd = FALSE;
1291	rp->r_todisgmt = FALSE;
1292	dp = ecpyalloc(timep);
1293	if (*dp != '\0') {
1294		ep = dp + strlen(dp) - 1;
1295		switch (lowerit(*ep)) {
1296			case 's':	/* Standard */
1297				rp->r_todisstd = TRUE;
1298				rp->r_todisgmt = FALSE;
1299				*ep = '\0';
1300				break;
1301			case 'w':	/* Wall */
1302				rp->r_todisstd = FALSE;
1303				rp->r_todisgmt = FALSE;
1304				*ep = '\0';
1305				break;
1306			case 'g':	/* Greenwich */
1307			case 'u':	/* Universal */
1308			case 'z':	/* Zulu */
1309				rp->r_todisstd = TRUE;
1310				rp->r_todisgmt = TRUE;
1311				*ep = '\0';
1312				break;
1313		}
1314	}
1315	rp->r_tod = gethms(dp, _("invalid time of day"), FALSE);
1316	ifree(dp);
1317	/*
1318	** Year work.
1319	*/
1320	cp = loyearp;
1321	lp = byword(cp, begin_years);
1322	rp->r_lowasnum = lp == NULL;
1323	if (!rp->r_lowasnum) switch ((int) lp->l_value) {
1324		case YR_MINIMUM:
1325			rp->r_loyear = INT_MIN;
1326			break;
1327		case YR_MAXIMUM:
1328			rp->r_loyear = INT_MAX;
1329			break;
1330		default:	/* "cannot happen" */
1331			(void) fprintf(stderr,
1332				_("%s: panic: Invalid l_value %d\n"),
1333				progname, lp->l_value);
1334			exit(EXIT_FAILURE);
1335	} else if (sscanf(cp, scheck(cp, "%d"), &rp->r_loyear) != 1) {
1336		error(_("invalid starting year"));
1337		return;
1338	}
1339	cp = hiyearp;
1340	lp = byword(cp, end_years);
1341	rp->r_hiwasnum = lp == NULL;
1342	if (!rp->r_hiwasnum) switch ((int) lp->l_value) {
1343		case YR_MINIMUM:
1344			rp->r_hiyear = INT_MIN;
1345			break;
1346		case YR_MAXIMUM:
1347			rp->r_hiyear = INT_MAX;
1348			break;
1349		case YR_ONLY:
1350			rp->r_hiyear = rp->r_loyear;
1351			break;
1352		default:	/* "cannot happen" */
1353			(void) fprintf(stderr,
1354				_("%s: panic: Invalid l_value %d\n"),
1355				progname, lp->l_value);
1356			exit(EXIT_FAILURE);
1357	} else if (sscanf(cp, scheck(cp, "%d"), &rp->r_hiyear) != 1) {
1358		error(_("invalid ending year"));
1359		return;
1360	}
1361	if (rp->r_loyear > rp->r_hiyear) {
1362		error(_("starting year greater than ending year"));
1363		return;
1364	}
1365	if (*typep == '\0')
1366		rp->r_yrtype = NULL;
1367	else {
1368		if (rp->r_loyear == rp->r_hiyear) {
1369			error(_("typed single year"));
1370			return;
1371		}
1372		rp->r_yrtype = ecpyalloc(typep);
1373	}
1374	/*
1375	** Day work.
1376	** Accept things such as:
1377	**	1
1378	**	last-Sunday
1379	**	Sun<=20
1380	**	Sun>=7
1381	*/
1382	dp = ecpyalloc(dayp);
1383	if ((lp = byword(dp, lasts)) != NULL) {
1384		rp->r_dycode = DC_DOWLEQ;
1385		rp->r_wday = lp->l_value;
1386		rp->r_dayofmonth = len_months[1][rp->r_month];
1387	} else {
1388		if ((ep = strchr(dp, '<')) != 0)
1389			rp->r_dycode = DC_DOWLEQ;
1390		else if ((ep = strchr(dp, '>')) != 0)
1391			rp->r_dycode = DC_DOWGEQ;
1392		else {
1393			ep = dp;
1394			rp->r_dycode = DC_DOM;
1395		}
1396		if (rp->r_dycode != DC_DOM) {
1397			*ep++ = 0;
1398			if (*ep++ != '=') {
1399				error(_("invalid day of month"));
1400				ifree(dp);
1401				return;
1402			}
1403			if ((lp = byword(dp, wday_names)) == NULL) {
1404				error(_("invalid weekday name"));
1405				ifree(dp);
1406				return;
1407			}
1408			rp->r_wday = lp->l_value;
1409		}
1410		if (sscanf(ep, scheck(ep, "%d"), &rp->r_dayofmonth) != 1 ||
1411			rp->r_dayofmonth <= 0 ||
1412			(rp->r_dayofmonth > len_months[1][rp->r_month])) {
1413				error(_("invalid day of month"));
1414				ifree(dp);
1415				return;
1416		}
1417	}
1418	ifree(dp);
1419}
1420
1421static void
1422convert(val, buf)
1423const long	val;
1424char * const	buf;
1425{
1426	register int	i;
1427	register int	shift;
1428
1429	for (i = 0, shift = 24; i < 4; ++i, shift -= 8)
1430		buf[i] = val >> shift;
1431}
1432
1433static void
1434convert64(val, buf)
1435const zic_t	val;
1436char * const	buf;
1437{
1438	register int	i;
1439	register int	shift;
1440
1441	for (i = 0, shift = 56; i < 8; ++i, shift -= 8)
1442		buf[i] = val >> shift;
1443}
1444
1445static void
1446puttzcode(val, fp)
1447const long	val;
1448FILE * const	fp;
1449{
1450	char	buf[4];
1451
1452	convert(val, buf);
1453	(void) fwrite((void *) buf, (size_t) sizeof buf, (size_t) 1, fp);
1454}
1455
1456static void
1457puttzcode64(val, fp)
1458const zic_t	val;
1459FILE * const	fp;
1460{
1461	char	buf[8];
1462
1463	convert64(val, buf);
1464	(void) fwrite((void *) buf, (size_t) sizeof buf, (size_t) 1, fp);
1465}
1466
1467static int
1468atcomp(avp, bvp)
1469const void *	avp;
1470const void *	bvp;
1471{
1472	const zic_t	a = ((const struct attype *) avp)->at;
1473	const zic_t	b = ((const struct attype *) bvp)->at;
1474
1475	return (a < b) ? -1 : (a > b);
1476}
1477
1478static int
1479is32(x)
1480const zic_t	x;
1481{
1482	return INT32_MIN <= x && x <= INT32_MAX;
1483}
1484
1485static void
1486writezone(name, string)
1487const char * const	name;
1488const char * const	string;
1489{
1490	register FILE *			fp;
1491	register int			i, j;
1492	register int			leapcnt32, leapi32;
1493	register int			timecnt32, timei32;
1494	register int			pass;
1495	static char *			fullname;
1496	static const struct tzhead	tzh0;
1497	static struct tzhead		tzh;
1498	zic_t				ats[TZ_MAX_TIMES];
1499	unsigned char			types[TZ_MAX_TIMES];
1500
1501	/*
1502	** Sort.
1503	*/
1504	if (timecnt > 1)
1505		(void) qsort((void *) attypes, (size_t) timecnt,
1506			(size_t) sizeof *attypes, atcomp);
1507	/*
1508	** Optimize.
1509	*/
1510	{
1511		int	fromi;
1512		int	toi;
1513
1514		toi = 0;
1515		fromi = 0;
1516		while (fromi < timecnt && attypes[fromi].at < min_time)
1517			++fromi;
1518		if (isdsts[0] == 0)
1519			while (fromi < timecnt && attypes[fromi].type == 0)
1520				++fromi;	/* handled by default rule */
1521		for ( ; fromi < timecnt; ++fromi) {
1522			if (toi != 0 && ((attypes[fromi].at +
1523				gmtoffs[attypes[toi - 1].type]) <=
1524				(attypes[toi - 1].at + gmtoffs[toi == 1 ? 0
1525				: attypes[toi - 2].type]))) {
1526					attypes[toi - 1].type =
1527						attypes[fromi].type;
1528					continue;
1529			}
1530			if (toi == 0 ||
1531				attypes[toi - 1].type != attypes[fromi].type)
1532					attypes[toi++] = attypes[fromi];
1533		}
1534		timecnt = toi;
1535	}
1536	/*
1537	** Transfer.
1538	*/
1539	for (i = 0; i < timecnt; ++i) {
1540		ats[i] = attypes[i].at;
1541		types[i] = attypes[i].type;
1542	}
1543	/*
1544	** Correct for leap seconds.
1545	*/
1546	for (i = 0; i < timecnt; ++i) {
1547		j = leapcnt;
1548		while (--j >= 0)
1549			if (ats[i] > trans[j] - corr[j]) {
1550				ats[i] = tadd(ats[i], corr[j]);
1551				break;
1552			}
1553	}
1554	/*
1555	** Figure out 32-bit-limited starts and counts.
1556	*/
1557	timecnt32 = timecnt;
1558	timei32 = 0;
1559	leapcnt32 = leapcnt;
1560	leapi32 = 0;
1561	while (timecnt32 > 0 && !is32(ats[timecnt32 - 1]))
1562		--timecnt32;
1563	while (timecnt32 > 0 && !is32(ats[timei32])) {
1564		--timecnt32;
1565		++timei32;
1566	}
1567	while (leapcnt32 > 0 && !is32(trans[leapcnt32 - 1]))
1568		--leapcnt32;
1569	while (leapcnt32 > 0 && !is32(trans[leapi32])) {
1570		--leapcnt32;
1571		++leapi32;
1572	}
1573	fullname = erealloc(fullname,
1574		(int) (strlen(directory) + 1 + strlen(name) + 1));
1575	(void) sprintf(fullname, "%s/%s", directory, name);	/* XXX: sprintf is safe */
1576	/*
1577	** Remove old file, if any, to snap links.
1578	*/
1579	if (!itsdir(fullname) && remove(fullname) != 0 && errno != ENOENT) {
1580		const char *e = strerror(errno);
1581
1582		(void) fprintf(stderr, _("%s: Can't remove %s: %s\n"),
1583			progname, fullname, e);
1584		exit(EXIT_FAILURE);
1585	}
1586	if ((fp = fopen(fullname, "wb")) == NULL) {
1587		if (mkdirs(fullname) != 0)
1588			exit(EXIT_FAILURE);
1589		if ((fp = fopen(fullname, "wb")) == NULL) {
1590			const char *e = strerror(errno);
1591
1592			(void) fprintf(stderr, _("%s: Can't create %s: %s\n"),
1593				progname, fullname, e);
1594			exit(EXIT_FAILURE);
1595		}
1596	}
1597	for (pass = 1; pass <= 2; ++pass) {
1598		register int	thistimei, thistimecnt;
1599		register int	thisleapi, thisleapcnt;
1600		register int	thistimelim, thisleaplim;
1601		int		writetype[TZ_MAX_TIMES];
1602		int		typemap[TZ_MAX_TYPES];
1603		register int	thistypecnt;
1604		char		thischars[TZ_MAX_CHARS];
1605		char		thischarcnt;
1606		int 		indmap[TZ_MAX_CHARS];
1607
1608		if (pass == 1) {
1609			thistimei = timei32;
1610			thistimecnt = timecnt32;
1611			thisleapi = leapi32;
1612			thisleapcnt = leapcnt32;
1613		} else {
1614			thistimei = 0;
1615			thistimecnt = timecnt;
1616			thisleapi = 0;
1617			thisleapcnt = leapcnt;
1618		}
1619		thistimelim = thistimei + thistimecnt;
1620		thisleaplim = thisleapi + thisleapcnt;
1621		for (i = 0; i < typecnt; ++i)
1622			writetype[i] = thistimecnt == timecnt;
1623		if (thistimecnt == 0) {
1624			/*
1625			** No transition times fall in the current
1626			** (32- or 64-bit) window.
1627			*/
1628			if (typecnt != 0)
1629				writetype[typecnt - 1] = TRUE;
1630		} else {
1631			for (i = thistimei - 1; i < thistimelim; ++i)
1632				if (i >= 0)
1633					writetype[types[i]] = TRUE;
1634			/*
1635			** For America/Godthab and Antarctica/Palmer
1636			*/
1637			if (thistimei == 0)
1638				writetype[0] = TRUE;
1639		}
1640#ifndef LEAVE_SOME_PRE_2011_SYSTEMS_IN_THE_LURCH
1641		/*
1642		** For some pre-2011 systems: if the last-to-be-written
1643		** standard (or daylight) type has an offset different from the
1644		** most recently used offset,
1645		** append an (unused) copy of the most recently used type
1646		** (to help get global "altzone" and "timezone" variables
1647		** set correctly).
1648		*/
1649		{
1650			register int	mrudst, mrustd, hidst, histd, type;
1651
1652			hidst = histd = mrudst = mrustd = -1;
1653			for (i = thistimei; i < thistimelim; ++i)
1654				if (isdsts[types[i]])
1655					mrudst = types[i];
1656				else	mrustd = types[i];
1657			for (i = 0; i < typecnt; ++i)
1658				if (writetype[i]) {
1659					if (isdsts[i])
1660						hidst = i;
1661					else	histd = i;
1662				}
1663			if (hidst >= 0 && mrudst >= 0 && hidst != mrudst &&
1664				gmtoffs[hidst] != gmtoffs[mrudst]) {
1665					isdsts[mrudst] = -1;
1666					type = addtype(gmtoffs[mrudst],
1667						&chars[abbrinds[mrudst]],
1668						TRUE,
1669						ttisstds[mrudst],
1670						ttisgmts[mrudst]);
1671					isdsts[mrudst] = TRUE;
1672					writetype[type] = TRUE;
1673			}
1674			if (histd >= 0 && mrustd >= 0 && histd != mrustd &&
1675				gmtoffs[histd] != gmtoffs[mrustd]) {
1676					isdsts[mrustd] = -1;
1677					type = addtype(gmtoffs[mrustd],
1678						&chars[abbrinds[mrustd]],
1679						FALSE,
1680						ttisstds[mrustd],
1681						ttisgmts[mrustd]);
1682					isdsts[mrustd] = FALSE;
1683					writetype[type] = TRUE;
1684			}
1685		}
1686#endif /* !defined LEAVE_SOME_PRE_2011_SYSTEMS_IN_THE_LURCH */
1687		thistypecnt = 0;
1688		for (i = 0; i < typecnt; ++i)
1689			typemap[i] = writetype[i] ?  thistypecnt++ : -1;
1690		for (i = 0; i < sizeof indmap / sizeof indmap[0]; ++i)
1691			indmap[i] = -1;
1692		thischarcnt = 0;
1693		for (i = 0; i < typecnt; ++i) {
1694			register char *	thisabbr;
1695
1696			if (!writetype[i])
1697				continue;
1698			if (indmap[abbrinds[i]] >= 0)
1699				continue;
1700			thisabbr = &chars[abbrinds[i]];
1701			for (j = 0; j < thischarcnt; ++j)
1702				if (strcmp(&thischars[j], thisabbr) == 0)
1703					break;
1704			if (j == thischarcnt) {
1705				(void) strcpy(&thischars[(int) thischarcnt],
1706					thisabbr);
1707				thischarcnt += strlen(thisabbr) + 1;
1708			}
1709			indmap[abbrinds[i]] = j;
1710		}
1711#define DO(field)	(void) fwrite((void *) tzh.field, \
1712				(size_t) sizeof tzh.field, (size_t) 1, fp)
1713		tzh = tzh0;
1714		(void) strncpy(tzh.tzh_magic, TZ_MAGIC, sizeof tzh.tzh_magic);
1715		tzh.tzh_version[0] = ZIC_VERSION;
1716		convert(eitol(thistypecnt), tzh.tzh_ttisgmtcnt);
1717		convert(eitol(thistypecnt), tzh.tzh_ttisstdcnt);
1718		convert(eitol(thisleapcnt), tzh.tzh_leapcnt);
1719		convert(eitol(thistimecnt), tzh.tzh_timecnt);
1720		convert(eitol(thistypecnt), tzh.tzh_typecnt);
1721		convert(eitol(thischarcnt), tzh.tzh_charcnt);
1722		DO(tzh_magic);
1723		DO(tzh_version);
1724		DO(tzh_reserved);
1725		DO(tzh_ttisgmtcnt);
1726		DO(tzh_ttisstdcnt);
1727		DO(tzh_leapcnt);
1728		DO(tzh_timecnt);
1729		DO(tzh_typecnt);
1730		DO(tzh_charcnt);
1731#undef DO
1732		for (i = thistimei; i < thistimelim; ++i)
1733			if (pass == 1)
1734				puttzcode((long) ats[i], fp);
1735			else	puttzcode64(ats[i], fp);
1736		for (i = thistimei; i < thistimelim; ++i) {
1737			unsigned char	uc;
1738
1739			uc = typemap[types[i]];
1740			(void) fwrite((void *) &uc,
1741				(size_t) sizeof uc,
1742				(size_t) 1,
1743				fp);
1744		}
1745		for (i = 0; i < typecnt; ++i)
1746			if (writetype[i]) {
1747				puttzcode(gmtoffs[i], fp);
1748				(void) putc(isdsts[i], fp);
1749				(void) putc((unsigned char) indmap[abbrinds[i]], fp);
1750			}
1751		if (thischarcnt != 0)
1752			(void) fwrite((void *) thischars,
1753				(size_t) sizeof thischars[0],
1754				(size_t) thischarcnt, fp);
1755		for (i = thisleapi; i < thisleaplim; ++i) {
1756			register zic_t	todo;
1757
1758			if (roll[i]) {
1759				if (timecnt == 0 || trans[i] < ats[0]) {
1760					j = 0;
1761					while (isdsts[j])
1762						if (++j >= typecnt) {
1763							j = 0;
1764							break;
1765						}
1766				} else {
1767					j = 1;
1768					while (j < timecnt &&
1769						trans[i] >= ats[j])
1770							++j;
1771					j = types[j - 1];
1772				}
1773				todo = tadd(trans[i], -gmtoffs[j]);
1774			} else	todo = trans[i];
1775			if (pass == 1)
1776				puttzcode((long) todo, fp);
1777			else	puttzcode64(todo, fp);
1778			puttzcode(corr[i], fp);
1779		}
1780		for (i = 0; i < typecnt; ++i)
1781			if (writetype[i])
1782				(void) putc(ttisstds[i], fp);
1783		for (i = 0; i < typecnt; ++i)
1784			if (writetype[i])
1785				(void) putc(ttisgmts[i], fp);
1786	}
1787	(void) fprintf(fp, "\n%s\n", string);
1788	if (ferror(fp) || fclose(fp)) {
1789		(void) fprintf(stderr, _("%s: Error writing %s\n"),
1790			progname, fullname);
1791		exit(EXIT_FAILURE);
1792	}
1793}
1794
1795static void
1796doabbr(abbr, abbrlen, format, letters, isdst, doquotes)
1797char * const		abbr;
1798const int		abbrlen;
1799const char * const	format;
1800const char * const	letters;
1801const int		isdst;
1802const int		doquotes;
1803{
1804	register char *	cp;
1805	register char *	slashp;
1806	register int	len;
1807
1808	slashp = strchr(format, '/');
1809	if (slashp == NULL) {
1810		if (letters == NULL)
1811			(void) strlcpy(abbr, format, abbrlen);
1812		else	(void) snprintf(abbr, abbrlen, format, letters);
1813	} else if (isdst) {
1814		(void) strlcpy(abbr, slashp + 1, abbrlen);
1815	} else {
1816		if (slashp > format)
1817			(void) strncpy(abbr, format,
1818				(unsigned) (slashp - format));
1819		abbr[slashp - format] = '\0';
1820	}
1821	if (!doquotes)
1822		return;
1823	for (cp = abbr; *cp != '\0'; ++cp)
1824		if (strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZ", *cp) == NULL &&
1825			strchr("abcdefghijklmnopqrstuvwxyz", *cp) == NULL)
1826				break;
1827	len = strlen(abbr);
1828	if (len > 0 && *cp == '\0')
1829		return;
1830	abbr[len + 2] = '\0';
1831	abbr[len + 1] = '>';
1832	for ( ; len > 0; --len)
1833		abbr[len] = abbr[len - 1];
1834	abbr[0] = '<';
1835}
1836
1837static void
1838updateminmax(x)
1839const int	x;
1840{
1841	if (min_year > x)
1842		min_year = x;
1843	if (max_year < x)
1844		max_year = x;
1845}
1846
1847static int
1848stringoffset(result, offset)
1849char *	result;
1850long	offset;
1851{
1852	register int	hours;
1853	register int	minutes;
1854	register int	seconds;
1855
1856	result[0] = '\0';
1857	if (offset < 0) {
1858		(void) strcpy(result, "-");
1859		offset = -offset;
1860	}
1861	seconds = offset % SECSPERMIN;
1862	offset /= SECSPERMIN;
1863	minutes = offset % MINSPERHOUR;
1864	offset /= MINSPERHOUR;
1865	hours = offset;
1866	if (hours >= HOURSPERDAY) {
1867		result[0] = '\0';
1868		return -1;
1869	}
1870	(void) sprintf(end(result), "%d", hours);
1871	if (minutes != 0 || seconds != 0) {
1872		(void) sprintf(end(result), ":%02d", minutes);
1873		if (seconds != 0)
1874			(void) sprintf(end(result), ":%02d", seconds);
1875	}
1876	return 0;
1877}
1878
1879static int
1880stringrule(result, rp, dstoff, gmtoff)
1881char *				result;
1882const struct rule * const	rp;
1883const long			dstoff;
1884const long			gmtoff;
1885{
1886	register long	tod;
1887
1888	result = end(result);
1889	if (rp->r_dycode == DC_DOM) {
1890		register int	month, total;
1891
1892		if (rp->r_dayofmonth == 29 && rp->r_month == TM_FEBRUARY)
1893			return -1;
1894		total = 0;
1895		for (month = 0; month < rp->r_month; ++month)
1896			total += len_months[0][month];
1897		(void) sprintf(result, "J%d", total + rp->r_dayofmonth);
1898	} else {
1899		register int	week;
1900
1901		if (rp->r_dycode == DC_DOWGEQ) {
1902			if ((rp->r_dayofmonth % DAYSPERWEEK) != 1)
1903				return -1;
1904			week = 1 + rp->r_dayofmonth / DAYSPERWEEK;
1905		} else if (rp->r_dycode == DC_DOWLEQ) {
1906			if (rp->r_dayofmonth == len_months[1][rp->r_month])
1907				week = 5;
1908			else {
1909				if ((rp->r_dayofmonth % DAYSPERWEEK) != 0)
1910					return -1;
1911				week = rp->r_dayofmonth / DAYSPERWEEK;
1912			}
1913		} else	return -1;	/* "cannot happen" */
1914		(void) sprintf(result, "M%d.%d.%d",
1915			rp->r_month + 1, week, rp->r_wday);
1916	}
1917	tod = rp->r_tod;
1918	if (rp->r_todisgmt)
1919		tod += gmtoff;
1920	if (rp->r_todisstd && rp->r_stdoff == 0)
1921		tod += dstoff;
1922	if (tod < 0) {
1923		result[0] = '\0';
1924		return -1;
1925	}
1926	if (tod != 2 * SECSPERMIN * MINSPERHOUR) {
1927		(void) strcat(result, "/");
1928		if (stringoffset(end(result), tod) != 0)
1929			return -1;
1930	}
1931	return 0;
1932}
1933
1934static void
1935stringzone(result, resultlen, zpfirst, zonecount)
1936char *				result;
1937const int			resultlen;
1938const struct zone * const	zpfirst;
1939const int			zonecount;
1940{
1941	register const struct zone *	zp;
1942	register struct rule *		rp;
1943	register struct rule *		stdrp;
1944	register struct rule *		dstrp;
1945	register int			i;
1946	register const char *		abbrvar;
1947
1948	result[0] = '\0';
1949	zp = zpfirst + zonecount - 1;
1950	stdrp = dstrp = NULL;
1951	for (i = 0; i < zp->z_nrules; ++i) {
1952		rp = &zp->z_rules[i];
1953		if (rp->r_hiwasnum || rp->r_hiyear != INT_MAX)
1954			continue;
1955		if (rp->r_yrtype != NULL)
1956			continue;
1957		if (rp->r_stdoff == 0) {
1958			if (stdrp == NULL)
1959				stdrp = rp;
1960			else	return;
1961		} else {
1962			if (dstrp == NULL)
1963				dstrp = rp;
1964			else	return;
1965		}
1966	}
1967	if (stdrp == NULL && dstrp == NULL) {
1968		/*
1969		** There are no rules running through "max".
1970		** Let's find the latest rule.
1971		*/
1972		for (i = 0; i < zp->z_nrules; ++i) {
1973			rp = &zp->z_rules[i];
1974			if (stdrp == NULL || rp->r_hiyear > stdrp->r_hiyear ||
1975				(rp->r_hiyear == stdrp->r_hiyear &&
1976				rp->r_month > stdrp->r_month))
1977					stdrp = rp;
1978		}
1979		if (stdrp != NULL && stdrp->r_stdoff != 0)
1980			return;	/* We end up in DST (a POSIX no-no). */
1981		/*
1982		** Horrid special case: if year is 2037,
1983		** presume this is a zone handled on a year-by-year basis;
1984		** do not try to apply a rule to the zone.
1985		*/
1986		if (stdrp != NULL && stdrp->r_hiyear == 2037)
1987			return;
1988	}
1989	if (stdrp == NULL && (zp->z_nrules != 0 || zp->z_stdoff != 0))
1990		return;
1991	abbrvar = (stdrp == NULL) ? "" : stdrp->r_abbrvar;
1992	doabbr(result, resultlen, zp->z_format, abbrvar, FALSE, TRUE);
1993	if (stringoffset(end(result), -zp->z_gmtoff) != 0) {
1994		result[0] = '\0';
1995		return;
1996	}
1997	if (dstrp == NULL)
1998		return;
1999	doabbr(end(result), resultlen - strlen(result),
2000		zp->z_format, dstrp->r_abbrvar, TRUE, TRUE);
2001	if (dstrp->r_stdoff != SECSPERMIN * MINSPERHOUR)
2002		if (stringoffset(end(result),
2003			-(zp->z_gmtoff + dstrp->r_stdoff)) != 0) {
2004				result[0] = '\0';
2005				return;
2006		}
2007	(void) strcat(result, ",");
2008	if (stringrule(result, dstrp, dstrp->r_stdoff, zp->z_gmtoff) != 0) {
2009		result[0] = '\0';
2010		return;
2011	}
2012	(void) strcat(result, ",");
2013	if (stringrule(result, stdrp, dstrp->r_stdoff, zp->z_gmtoff) != 0) {
2014		result[0] = '\0';
2015		return;
2016	}
2017}
2018
2019static void
2020outzone(zpfirst, zonecount)
2021const struct zone * const	zpfirst;
2022const int			zonecount;
2023{
2024	register const struct zone *	zp;
2025	register struct rule *		rp;
2026	register int			i, j;
2027	register int			usestart, useuntil;
2028	register zic_t			starttime, untiltime;
2029	register long			gmtoff;
2030	register long			stdoff;
2031	register int			year;
2032	register long			startoff;
2033	register int			startttisstd;
2034	register int			startttisgmt;
2035	register int			type;
2036	register char *			startbuf;
2037	register char *			ab;
2038	register char *			envvar;
2039	register int			max_abbr_len;
2040	register int			max_envvar_len;
2041	register int			prodstic; /* all rules are min to max */
2042
2043	max_abbr_len = 2 + max_format_len + max_abbrvar_len;
2044	max_envvar_len = 2 * max_abbr_len + 5 * 9;
2045	startbuf = emalloc(max_abbr_len + 1);
2046	ab = emalloc(max_abbr_len + 1);
2047	envvar = emalloc(max_envvar_len + 1);
2048	INITIALIZE(untiltime);
2049	INITIALIZE(starttime);
2050	/*
2051	** Now. . .finally. . .generate some useful data!
2052	*/
2053	timecnt = 0;
2054	typecnt = 0;
2055	charcnt = 0;
2056	prodstic = zonecount == 1;
2057	/*
2058	** Thanks to Earl Chew
2059	** for noting the need to unconditionally initialize startttisstd.
2060	*/
2061	startttisstd = FALSE;
2062	startttisgmt = FALSE;
2063	min_year = max_year = EPOCH_YEAR;
2064	if (leapseen) {
2065		updateminmax(leapminyear);
2066		updateminmax(leapmaxyear + (leapmaxyear < INT_MAX));
2067	}
2068	for (i = 0; i < zonecount; ++i) {
2069		zp = &zpfirst[i];
2070		if (i < zonecount - 1)
2071			updateminmax(zp->z_untilrule.r_loyear);
2072		for (j = 0; j < zp->z_nrules; ++j) {
2073			rp = &zp->z_rules[j];
2074			if (rp->r_lowasnum)
2075				updateminmax(rp->r_loyear);
2076			if (rp->r_hiwasnum)
2077				updateminmax(rp->r_hiyear);
2078		}
2079	}
2080	/*
2081	** Generate lots of data if a rule can't cover all future times.
2082	*/
2083	stringzone(envvar, max_envvar_len+1, zpfirst, zonecount);
2084	if (noise && envvar[0] == '\0') {
2085		register char *	wp;
2086
2087wp = ecpyalloc(_("no POSIX environment variable for zone"));
2088		wp = ecatalloc(wp, " ");
2089		wp = ecatalloc(wp, zpfirst->z_name);
2090		warning(wp);
2091		ifree(wp);
2092	}
2093	if (envvar[0] == '\0') {
2094		if (min_year >= INT_MIN + YEARSPERREPEAT)
2095			min_year -= YEARSPERREPEAT;
2096		else	min_year = INT_MIN;
2097		if (max_year <= INT_MAX - YEARSPERREPEAT)
2098			max_year += YEARSPERREPEAT;
2099		else	max_year = INT_MAX;
2100		/*
2101		** Regardless of any of the above,
2102		** for a "proDSTic" zone which specifies that its rules
2103		** always have and always will be in effect,
2104		** we only need one cycle to define the zone.
2105		*/
2106		if (prodstic) {
2107			min_year = 1900;
2108			max_year = min_year + YEARSPERREPEAT;
2109		}
2110	}
2111	/*
2112	** For the benefit of older systems,
2113	** generate data from 1900 through 2037.
2114	*/
2115	if (min_year > 1900)
2116		min_year = 1900;
2117	if (max_year < 2037)
2118		max_year = 2037;
2119	for (i = 0; i < zonecount; ++i) {
2120		/*
2121		** A guess that may well be corrected later.
2122		*/
2123		stdoff = 0;
2124		zp = &zpfirst[i];
2125		usestart = i > 0 && (zp - 1)->z_untiltime > min_time;
2126		useuntil = i < (zonecount - 1);
2127		if (useuntil && zp->z_untiltime <= min_time)
2128			continue;
2129		gmtoff = zp->z_gmtoff;
2130		eat(zp->z_filename, zp->z_linenum);
2131		*startbuf = '\0';
2132		startoff = zp->z_gmtoff;
2133		if (zp->z_nrules == 0) {
2134			stdoff = zp->z_stdoff;
2135			doabbr(startbuf, max_abbr_len + 1, zp->z_format,
2136				(char *) NULL, stdoff != 0, FALSE);
2137			type = addtype(oadd(zp->z_gmtoff, stdoff),
2138				startbuf, stdoff != 0, startttisstd,
2139				startttisgmt);
2140			if (usestart) {
2141				addtt(starttime, type);
2142				usestart = FALSE;
2143			} else if (stdoff != 0)
2144				addtt(min_time, type);
2145		} else for (year = min_year; year <= max_year; ++year) {
2146			if (useuntil && year > zp->z_untilrule.r_hiyear)
2147				break;
2148			/*
2149			** Mark which rules to do in the current year.
2150			** For those to do, calculate rpytime(rp, year);
2151			*/
2152			for (j = 0; j < zp->z_nrules; ++j) {
2153				rp = &zp->z_rules[j];
2154				eats(zp->z_filename, zp->z_linenum,
2155					rp->r_filename, rp->r_linenum);
2156				rp->r_todo = year >= rp->r_loyear &&
2157						year <= rp->r_hiyear &&
2158						yearistype(year, rp->r_yrtype);
2159				if (rp->r_todo)
2160					rp->r_temp = rpytime(rp, year);
2161			}
2162			for ( ; ; ) {
2163				register int	k;
2164				register zic_t	jtime, ktime;
2165				register long	offset;
2166
2167				INITIALIZE(ktime);
2168				if (useuntil) {
2169					/*
2170					** Turn untiltime into UTC
2171					** assuming the current gmtoff and
2172					** stdoff values.
2173					*/
2174					untiltime = zp->z_untiltime;
2175					if (!zp->z_untilrule.r_todisgmt)
2176						untiltime = tadd(untiltime,
2177							-gmtoff);
2178					if (!zp->z_untilrule.r_todisstd)
2179						untiltime = tadd(untiltime,
2180							-stdoff);
2181				}
2182				/*
2183				** Find the rule (of those to do, if any)
2184				** that takes effect earliest in the year.
2185				*/
2186				k = -1;
2187				for (j = 0; j < zp->z_nrules; ++j) {
2188					rp = &zp->z_rules[j];
2189					if (!rp->r_todo)
2190						continue;
2191					eats(zp->z_filename, zp->z_linenum,
2192						rp->r_filename, rp->r_linenum);
2193					offset = rp->r_todisgmt ? 0 : gmtoff;
2194					if (!rp->r_todisstd)
2195						offset = oadd(offset, stdoff);
2196					jtime = rp->r_temp;
2197					if (jtime == min_time ||
2198						jtime == max_time)
2199							continue;
2200					jtime = tadd(jtime, -offset);
2201					if (k < 0 || jtime < ktime) {
2202						k = j;
2203						ktime = jtime;
2204					}
2205				}
2206				if (k < 0)
2207					break;	/* go on to next year */
2208				rp = &zp->z_rules[k];
2209				rp->r_todo = FALSE;
2210				if (useuntil && ktime >= untiltime)
2211					break;
2212				stdoff = rp->r_stdoff;
2213				if (usestart && ktime == starttime)
2214					usestart = FALSE;
2215				if (usestart) {
2216					if (ktime < starttime) {
2217						startoff = oadd(zp->z_gmtoff,
2218							stdoff);
2219						doabbr(startbuf,
2220							max_abbr_len + 1,
2221							zp->z_format,
2222							rp->r_abbrvar,
2223							rp->r_stdoff != 0,
2224							FALSE);
2225						continue;
2226					}
2227					if (*startbuf == '\0' &&
2228						startoff == oadd(zp->z_gmtoff,
2229						stdoff)) {
2230							doabbr(startbuf,
2231								max_abbr_len + 1,
2232								zp->z_format,
2233								rp->r_abbrvar,
2234								rp->r_stdoff !=
2235								0,
2236								FALSE);
2237					}
2238				}
2239				eats(zp->z_filename, zp->z_linenum,
2240					rp->r_filename, rp->r_linenum);
2241				doabbr(ab, max_abbr_len+1, zp->z_format, rp->r_abbrvar,
2242					rp->r_stdoff != 0, FALSE);
2243				offset = oadd(zp->z_gmtoff, rp->r_stdoff);
2244				type = addtype(offset, ab, rp->r_stdoff != 0,
2245					rp->r_todisstd, rp->r_todisgmt);
2246				addtt(ktime, type);
2247			}
2248		}
2249		if (usestart) {
2250			if (*startbuf == '\0' &&
2251				zp->z_format != NULL &&
2252				strchr(zp->z_format, '%') == NULL &&
2253				strchr(zp->z_format, '/') == NULL)
2254					(void)strncpy(startbuf, zp->z_format,
2255					    max_abbr_len + 1 - 1);
2256			eat(zp->z_filename, zp->z_linenum);
2257			if (*startbuf == '\0')
2258error(_("can't determine time zone abbreviation to use just after until time"));
2259			else	addtt(starttime,
2260					addtype(startoff, startbuf,
2261						startoff != zp->z_gmtoff,
2262						startttisstd,
2263						startttisgmt));
2264		}
2265		/*
2266		** Now we may get to set starttime for the next zone line.
2267		*/
2268		if (useuntil) {
2269			startttisstd = zp->z_untilrule.r_todisstd;
2270			startttisgmt = zp->z_untilrule.r_todisgmt;
2271			starttime = zp->z_untiltime;
2272			if (!startttisstd)
2273				starttime = tadd(starttime, -stdoff);
2274			if (!startttisgmt)
2275				starttime = tadd(starttime, -gmtoff);
2276		}
2277	}
2278	writezone(zpfirst->z_name, envvar);
2279	ifree(startbuf);
2280	ifree(ab);
2281	ifree(envvar);
2282}
2283
2284static void
2285addtt(starttime, type)
2286const zic_t	starttime;
2287int		type;
2288{
2289	if (starttime <= min_time ||
2290		(timecnt == 1 && attypes[0].at < min_time)) {
2291		gmtoffs[0] = gmtoffs[type];
2292		isdsts[0] = isdsts[type];
2293		ttisstds[0] = ttisstds[type];
2294		ttisgmts[0] = ttisgmts[type];
2295		if (abbrinds[type] != 0)
2296			(void) strcpy(chars, &chars[abbrinds[type]]);
2297		abbrinds[0] = 0;
2298		charcnt = strlen(chars) + 1;
2299		typecnt = 1;
2300		timecnt = 0;
2301		type = 0;
2302	}
2303	if (timecnt >= TZ_MAX_TIMES) {
2304		error(_("too many transitions?!"));
2305		exit(EXIT_FAILURE);
2306	}
2307	attypes[timecnt].at = starttime;
2308	attypes[timecnt].type = type;
2309	++timecnt;
2310}
2311
2312static int
2313addtype(gmtoff, abbr, isdst, ttisstd, ttisgmt)
2314const long		gmtoff;
2315const char * const	abbr;
2316const int		isdst;
2317const int		ttisstd;
2318const int		ttisgmt;
2319{
2320	register int	i, j;
2321
2322	if (isdst != TRUE && isdst != FALSE) {
2323		error(_("internal error - addtype called with bad isdst"));
2324		exit(EXIT_FAILURE);
2325	}
2326	if (ttisstd != TRUE && ttisstd != FALSE) {
2327		error(_("internal error - addtype called with bad ttisstd"));
2328		exit(EXIT_FAILURE);
2329	}
2330	if (ttisgmt != TRUE && ttisgmt != FALSE) {
2331		error(_("internal error - addtype called with bad ttisgmt"));
2332		exit(EXIT_FAILURE);
2333	}
2334	/*
2335	** See if there's already an entry for this zone type.
2336	** If so, just return its index.
2337	*/
2338	for (i = 0; i < typecnt; ++i) {
2339		if (gmtoff == gmtoffs[i] && isdst == isdsts[i] &&
2340			strcmp(abbr, &chars[abbrinds[i]]) == 0 &&
2341			ttisstd == ttisstds[i] &&
2342			ttisgmt == ttisgmts[i])
2343				return i;
2344	}
2345	/*
2346	** There isn't one; add a new one, unless there are already too
2347	** many.
2348	*/
2349	if (typecnt >= TZ_MAX_TYPES) {
2350		error(_("too many local time types"));
2351		exit(EXIT_FAILURE);
2352	}
2353	if (! (-1L - 2147483647L <= gmtoff && gmtoff <= 2147483647L)) {
2354		error(_("UTC offset out of range"));
2355		exit(EXIT_FAILURE);
2356	}
2357	gmtoffs[i] = gmtoff;
2358	isdsts[i] = isdst;
2359	ttisstds[i] = ttisstd;
2360	ttisgmts[i] = ttisgmt;
2361
2362	for (j = 0; j < charcnt; ++j)
2363		if (strcmp(&chars[j], abbr) == 0)
2364			break;
2365	if (j == charcnt)
2366		newabbr(abbr);
2367	abbrinds[i] = j;
2368	++typecnt;
2369	return i;
2370}
2371
2372static void
2373leapadd(t, positive, rolling, count)
2374const zic_t	t;
2375const int	positive;
2376const int	rolling;
2377int		count;
2378{
2379	register int	i, j;
2380
2381	if (leapcnt + (positive ? count : 1) > TZ_MAX_LEAPS) {
2382		error(_("too many leap seconds"));
2383		exit(EXIT_FAILURE);
2384	}
2385	for (i = 0; i < leapcnt; ++i)
2386		if (t <= trans[i]) {
2387			if (t == trans[i]) {
2388				error(_("repeated leap second moment"));
2389				exit(EXIT_FAILURE);
2390			}
2391			break;
2392		}
2393	do {
2394		for (j = leapcnt; j > i; --j) {
2395			trans[j] = trans[j - 1];
2396			corr[j] = corr[j - 1];
2397			roll[j] = roll[j - 1];
2398		}
2399		trans[i] = t;
2400		corr[i] = positive ? 1L : eitol(-count);
2401		roll[i] = rolling;
2402		++leapcnt;
2403	} while (positive && --count != 0);
2404}
2405
2406static void
2407adjleap(void)
2408{
2409	register int	i;
2410	register long	last = 0;
2411
2412	/*
2413	** propagate leap seconds forward
2414	*/
2415	for (i = 0; i < leapcnt; ++i) {
2416		trans[i] = tadd(trans[i], last);
2417		last = corr[i] += last;
2418	}
2419}
2420
2421static int
2422yearistype(year, type)
2423const int		year;
2424const char * const	type;
2425{
2426	static char *	buf;
2427	int		result;
2428
2429	if (type == NULL || *type == '\0')
2430		return TRUE;
2431	buf = erealloc(buf, (int) (132 + strlen(yitcommand) + strlen(type)));
2432	(void)sprintf(buf, "%s %d %s", yitcommand, year, type); /* XXX: sprintf is safe */
2433	result = system(buf);
2434	if (WIFEXITED(result)) switch (WEXITSTATUS(result)) {
2435		case 0:
2436			return TRUE;
2437		case 1:
2438			return FALSE;
2439	}
2440	error(_("Wild result from command execution"));
2441	(void) fprintf(stderr, _("%s: command was '%s', result was %d\n"),
2442		progname, buf, result);
2443	for ( ; ; )
2444		exit(EXIT_FAILURE);
2445}
2446
2447static int
2448lowerit(a)
2449int	a;
2450{
2451	a = (unsigned char) a;
2452	return (isascii(a) && isupper(a)) ? tolower(a) : a;
2453}
2454
2455static int
2456ciequal(ap, bp)		/* case-insensitive equality */
2457register const char *	ap;
2458register const char *	bp;
2459{
2460	while (lowerit(*ap) == lowerit(*bp++))
2461		if (*ap++ == '\0')
2462			return TRUE;
2463	return FALSE;
2464}
2465
2466static int
2467itsabbr(abbr, word)
2468register const char *	abbr;
2469register const char *	word;
2470{
2471	if (lowerit(*abbr) != lowerit(*word))
2472		return FALSE;
2473	++word;
2474	while (*++abbr != '\0')
2475		do {
2476			if (*word == '\0')
2477				return FALSE;
2478		} while (lowerit(*word++) != lowerit(*abbr));
2479	return TRUE;
2480}
2481
2482static const struct lookup *
2483byword(word, table)
2484register const char * const		word;
2485register const struct lookup * const	table;
2486{
2487	register const struct lookup *	foundlp;
2488	register const struct lookup *	lp;
2489
2490	if (word == NULL || table == NULL)
2491		return NULL;
2492	/*
2493	** Look for exact match.
2494	*/
2495	for (lp = table; lp->l_word != NULL; ++lp)
2496		if (ciequal(word, lp->l_word))
2497			return lp;
2498	/*
2499	** Look for inexact match.
2500	*/
2501	foundlp = NULL;
2502	for (lp = table; lp->l_word != NULL; ++lp)
2503		if (itsabbr(word, lp->l_word)) {
2504			if (foundlp == NULL)
2505				foundlp = lp;
2506			else	return NULL;	/* multiple inexact matches */
2507		}
2508	return foundlp;
2509}
2510
2511static char **
2512getfields(cp)
2513register char *	cp;
2514{
2515	register char *		dp;
2516	register char **	array;
2517	register int		nsubs;
2518
2519	if (cp == NULL)
2520		return NULL;
2521	array = (char **) (void *)
2522		emalloc((int) ((strlen(cp) + 1) * sizeof *array));
2523	nsubs = 0;
2524	for ( ; ; ) {
2525		while (isascii((unsigned char) *cp) &&
2526			isspace((unsigned char) *cp))
2527				++cp;
2528		if (*cp == '\0' || *cp == '#')
2529			break;
2530		array[nsubs++] = dp = cp;
2531		do {
2532			if ((*dp = *cp++) != '"')
2533				++dp;
2534			else while ((*dp = *cp++) != '"')
2535				if (*dp != '\0')
2536					++dp;
2537				else {
2538					error(_(
2539						"Odd number of quotation marks"
2540						));
2541					exit(1);
2542				}
2543		} while (*cp != '\0' && *cp != '#' &&
2544			(!isascii(*cp) || !isspace((unsigned char) *cp)));
2545		if (isascii(*cp) && isspace((unsigned char) *cp))
2546			++cp;
2547		*dp = '\0';
2548	}
2549	array[nsubs] = NULL;
2550	return array;
2551}
2552
2553static long
2554oadd(t1, t2)
2555const long	t1;
2556const long	t2;
2557{
2558	register long	t;
2559
2560	t = t1 + t2;
2561	if ((t2 > 0 && t <= t1) || (t2 < 0 && t >= t1)) {
2562		error(_("time overflow"));
2563		exit(EXIT_FAILURE);
2564	}
2565	return t;
2566}
2567
2568static zic_t
2569tadd(t1, t2)
2570const zic_t	t1;
2571const long	t2;
2572{
2573	register zic_t	t;
2574
2575	if (t1 == max_time && t2 > 0)
2576		return max_time;
2577	if (t1 == min_time && t2 < 0)
2578		return min_time;
2579	t = t1 + t2;
2580	if ((t2 > 0 && t <= t1) || (t2 < 0 && t >= t1)) {
2581		error(_("time overflow"));
2582		exit(EXIT_FAILURE);
2583	}
2584	return t;
2585}
2586
2587/*
2588** Given a rule, and a year, compute the date - in seconds since January 1,
2589** 1970, 00:00 LOCAL time - in that year that the rule refers to.
2590*/
2591
2592static zic_t
2593rpytime(rp, wantedy)
2594register const struct rule * const	rp;
2595register const int			wantedy;
2596{
2597	register int	y, m, i;
2598	register long	dayoff;			/* with a nod to Margaret O. */
2599	register zic_t	t;
2600
2601	if (wantedy == INT_MIN)
2602		return min_time;
2603	if (wantedy == INT_MAX)
2604		return max_time;
2605	dayoff = 0;
2606	m = TM_JANUARY;
2607	y = EPOCH_YEAR;
2608	while (wantedy != y) {
2609		if (wantedy > y) {
2610			i = len_years[isleap(y)];
2611			++y;
2612		} else {
2613			--y;
2614			i = -len_years[isleap(y)];
2615		}
2616		dayoff = oadd(dayoff, eitol(i));
2617	}
2618	while (m != rp->r_month) {
2619		i = len_months[isleap(y)][m];
2620		dayoff = oadd(dayoff, eitol(i));
2621		++m;
2622	}
2623	i = rp->r_dayofmonth;
2624	if (m == TM_FEBRUARY && i == 29 && !isleap(y)) {
2625		if (rp->r_dycode == DC_DOWLEQ)
2626			--i;
2627		else {
2628			error(_("use of 2/29 in non leap-year"));
2629			exit(EXIT_FAILURE);
2630		}
2631	}
2632	--i;
2633	dayoff = oadd(dayoff, eitol(i));
2634	if (rp->r_dycode == DC_DOWGEQ || rp->r_dycode == DC_DOWLEQ) {
2635		register long	wday;
2636
2637#define LDAYSPERWEEK	((long) DAYSPERWEEK)
2638		wday = eitol(EPOCH_WDAY);
2639		/*
2640		** Don't trust mod of negative numbers.
2641		*/
2642		if (dayoff >= 0)
2643			wday = (wday + dayoff) % LDAYSPERWEEK;
2644		else {
2645			wday -= ((-dayoff) % LDAYSPERWEEK);
2646			if (wday < 0)
2647				wday += LDAYSPERWEEK;
2648		}
2649		while (wday != eitol(rp->r_wday))
2650			if (rp->r_dycode == DC_DOWGEQ) {
2651				dayoff = oadd(dayoff, (long) 1);
2652				if (++wday >= LDAYSPERWEEK)
2653					wday = 0;
2654				++i;
2655			} else {
2656				dayoff = oadd(dayoff, (long) -1);
2657				if (--wday < 0)
2658					wday = LDAYSPERWEEK - 1;
2659				--i;
2660			}
2661		if (i < 0 || i >= len_months[isleap(y)][m]) {
2662			if (noise)
2663				warning(_("rule goes past start/end of month--\
2664will not work with pre-2004 versions of zic"));
2665		}
2666	}
2667	if (dayoff < min_time / SECSPERDAY)
2668		return min_time;
2669	if (dayoff > max_time / SECSPERDAY)
2670		return max_time;
2671	t = (zic_t) dayoff * SECSPERDAY;
2672	return tadd(t, rp->r_tod);
2673}
2674
2675static void
2676newabbr(string)
2677const char * const	string;
2678{
2679	register int	i;
2680
2681	if (strcmp(string, GRANDPARENTED) != 0) {
2682		register const char *	cp;
2683		register char *		wp;
2684
2685		/*
2686		** Want one to ZIC_MAX_ABBR_LEN_WO_WARN alphabetics
2687		** optionally followed by a + or - and a number from 1 to 14.
2688		*/
2689		cp = string;
2690		wp = NULL;
2691		while (isascii((unsigned char) *cp) &&
2692			isalpha((unsigned char) *cp))
2693				++cp;
2694		if (cp - string == 0)
2695wp = _("time zone abbreviation lacks alphabetic at start");
2696		if (noise && cp - string > 3)
2697wp = _("time zone abbreviation has more than 3 alphabetics");
2698		if (cp - string > ZIC_MAX_ABBR_LEN_WO_WARN)
2699wp = _("time zone abbreviation has too many alphabetics");
2700		if (wp == NULL && (*cp == '+' || *cp == '-')) {
2701			++cp;
2702			if (isascii((unsigned char) *cp) &&
2703				isdigit((unsigned char) *cp))
2704					if (*cp++ == '1' &&
2705						*cp >= '0' && *cp <= '4')
2706							++cp;
2707		}
2708		if (*cp != '\0')
2709wp = _("time zone abbreviation differs from POSIX standard");
2710		if (wp != NULL) {
2711			wp = ecpyalloc(wp);
2712			wp = ecatalloc(wp, " (");
2713			wp = ecatalloc(wp, string);
2714			wp = ecatalloc(wp, ")");
2715			warning(wp);
2716			ifree(wp);
2717		}
2718	}
2719	i = strlen(string) + 1;
2720	if (charcnt + i > TZ_MAX_CHARS) {
2721		error(_("too many, or too long, time zone abbreviations"));
2722		exit(EXIT_FAILURE);
2723	}
2724	(void)strncpy(&chars[charcnt], string, sizeof(chars) - charcnt - 1);
2725	charcnt += eitol(i);
2726}
2727
2728static int
2729mkdirs(argname)
2730char *		argname;
2731{
2732	register char *	name;
2733	register char *	cp;
2734
2735	if (argname == NULL || *argname == '\0')
2736		return 0;
2737	cp = name = ecpyalloc(argname);
2738	while ((cp = strchr(cp + 1, '/')) != 0) {
2739		*cp = '\0';
2740#ifndef __NetBSD__
2741		/*
2742		** DOS drive specifier?
2743		*/
2744		if (isalpha((unsigned char) name[0]) &&
2745			name[1] == ':' && name[2] == '\0') {
2746				*cp = '/';
2747				continue;
2748		}
2749#endif /* !defined __NetBSD__ */
2750		if (!itsdir(name)) {
2751			/*
2752			** It doesn't seem to exist, so we try to create it.
2753			** Creation may fail because of the directory being
2754			** created by some other multiprocessor, so we get
2755			** to do extra checking.
2756			*/
2757			if (mkdir(name, MKDIR_UMASK) != 0) {
2758				const char *e = strerror(errno);
2759
2760				if (errno != EEXIST || !itsdir(name)) {
2761					(void) fprintf(stderr,
2762_("%s: Can't create directory %s: %s\n"),
2763						progname, name, e);
2764					ifree(name);
2765					return -1;
2766				}
2767			}
2768		}
2769		*cp = '/';
2770	}
2771	ifree(name);
2772	return 0;
2773}
2774
2775static long
2776eitol(i)
2777const int	i;
2778{
2779	long	l;
2780
2781	l = i;
2782	if ((i < 0 && l >= 0) || (i == 0 && l != 0) || (i > 0 && l <= 0)) {
2783		(void) fprintf(stderr,
2784			_("%s: %d did not sign extend correctly\n"),
2785			progname, i);
2786		exit(EXIT_FAILURE);
2787	}
2788	return l;
2789}
2790
2791/*
2792** UNIX was a registered trademark of The Open Group in 2003.
2793*/
2794