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