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