xref: /original-bsd/share/zoneinfo/zic.c (revision 8b296c7a)
17b35baebSbostic /*-
2*8b296c7aSbostic  * Copyright (c) 1991, 1993
3*8b296c7aSbostic  *	The Regents of the University of California.  All rights reserved.
47b35baebSbostic  *
57b35baebSbostic  * This code is derived from software contributed to Berkeley by
67b35baebSbostic  * Arthur David Olson of the National Cancer Institute.
77b35baebSbostic  *
87b35baebSbostic  * %sccs.include.redist.c%
97b35baebSbostic  */
107b35baebSbostic 
1151034c06Sbostic #ifndef lint
12*8b296c7aSbostic static char sccsid[] = "@(#)zic.c	8.1 (Berkeley) 07/19/93";
137b35baebSbostic #endif /* not lint */
147b35baebSbostic 
157b35baebSbostic #ifdef notdef
1651034c06Sbostic static char	elsieid[] = "@(#)zic.c	4.12";
177b35baebSbostic #endif
1851034c06Sbostic 
196068c877Sbostic #include <sys/types.h>
206068c877Sbostic #include <sys/cdefs.h>
216068c877Sbostic #include <sys/stat.h>
226068c877Sbostic #include <time.h>
236068c877Sbostic #include <tzfile.h>
246068c877Sbostic #include <stdio.h>
256068c877Sbostic #include <ctype.h>
266068c877Sbostic #include <string.h>
276068c877Sbostic #include <stdlib.h>
2851034c06Sbostic 
2951034c06Sbostic #ifndef TRUE
3051034c06Sbostic #define TRUE	1
3151034c06Sbostic #define FALSE	0
3251034c06Sbostic #endif /* !defined TRUE */
3351034c06Sbostic 
3451034c06Sbostic struct rule {
3551034c06Sbostic 	const char *	r_filename;
3651034c06Sbostic 	int		r_linenum;
3751034c06Sbostic 	const char *	r_name;
3851034c06Sbostic 
3951034c06Sbostic 	int		r_loyear;	/* for example, 1986 */
4051034c06Sbostic 	int		r_hiyear;	/* for example, 1986 */
4151034c06Sbostic 	const char *	r_yrtype;
4251034c06Sbostic 
4351034c06Sbostic 	int		r_month;	/* 0..11 */
4451034c06Sbostic 
4551034c06Sbostic 	int		r_dycode;	/* see below */
4651034c06Sbostic 	int		r_dayofmonth;
4751034c06Sbostic 	int		r_wday;
4851034c06Sbostic 
4951034c06Sbostic 	long		r_tod;		/* time from midnight */
5051034c06Sbostic 	int		r_todisstd;	/* above is standard time if TRUE */
5151034c06Sbostic 					/* or wall clock time if FALSE */
5251034c06Sbostic 	long		r_stdoff;	/* offset from standard time */
5351034c06Sbostic 	const char *	r_abbrvar;	/* variable part of abbreviation */
5451034c06Sbostic 
5551034c06Sbostic 	int		r_todo;		/* a rule to do (used in outzone) */
5651034c06Sbostic 	time_t		r_temp;		/* used in outzone */
5751034c06Sbostic };
5851034c06Sbostic 
5951034c06Sbostic /*
6051034c06Sbostic **	r_dycode		r_dayofmonth	r_wday
6151034c06Sbostic */
6251034c06Sbostic 
6351034c06Sbostic #define DC_DOM		0	/* 1..31 */	/* unused */
6451034c06Sbostic #define DC_DOWGEQ	1	/* 1..31 */	/* 0..6 (Sun..Sat) */
6551034c06Sbostic #define DC_DOWLEQ	2	/* 1..31 */	/* 0..6 (Sun..Sat) */
6651034c06Sbostic 
6751034c06Sbostic struct zone {
6851034c06Sbostic 	const char *	z_filename;
6951034c06Sbostic 	int		z_linenum;
7051034c06Sbostic 
7151034c06Sbostic 	const char *	z_name;
7251034c06Sbostic 	long		z_gmtoff;
7351034c06Sbostic 	const char *	z_rule;
7451034c06Sbostic 	const char *	z_format;
7551034c06Sbostic 
7651034c06Sbostic 	long		z_stdoff;
7751034c06Sbostic 
7851034c06Sbostic 	struct rule *	z_rules;
7951034c06Sbostic 	int		z_nrules;
8051034c06Sbostic 
8151034c06Sbostic 	struct rule	z_untilrule;
8251034c06Sbostic 	time_t		z_untiltime;
8351034c06Sbostic };
8451034c06Sbostic 
856068c877Sbostic extern char *	icatalloc __P((char * old, const char * new));
866068c877Sbostic extern char *	icpyalloc __P((const char * string));
876068c877Sbostic extern void	ifree __P((char * p));
886068c877Sbostic extern char *	imalloc __P((int n));
896068c877Sbostic extern char *	irealloc __P((char * old, int n));
906068c877Sbostic extern int	link __P((const char * fromname, const char * toname));
9151034c06Sbostic extern char *	optarg;
9251034c06Sbostic extern int	optind;
936068c877Sbostic extern void	perror __P((const char * string));
946068c877Sbostic extern char *	scheck __P((const char * string, const char * format));
956068c877Sbostic static void	addtt __P((time_t starttime, int type));
966068c877Sbostic static int	addtype
976068c877Sbostic 		    __P((long gmtoff, const char * abbr, int isdst,
9851034c06Sbostic 		    int ttisstd));
996068c877Sbostic static void	addleap __P((time_t t, int positive, int rolling));
1006068c877Sbostic static void	adjleap __P((void));
1016068c877Sbostic static void	associate __P((void));
1026068c877Sbostic static int	ciequal __P((const char * ap, const char * bp));
1036068c877Sbostic static void	convert __P((long val, char * buf));
1046068c877Sbostic static void	dolink __P((const char * fromfile, const char * tofile));
1056068c877Sbostic static void	eat __P((const char * name, int num));
1066068c877Sbostic static void	eats __P((const char * name, int num,
10751034c06Sbostic 		    const char * rname, int rnum));
1086068c877Sbostic static long	eitol __P((int i));
1096068c877Sbostic static void	error __P((const char * message));
1106068c877Sbostic static char **	getfields __P((char * buf));
1116068c877Sbostic static long	gethms __P((char * string, const char * errstrng,
11251034c06Sbostic 		    int signable));
1136068c877Sbostic static void	infile __P((const char * filename));
1146068c877Sbostic static void	inleap __P((char ** fields, int nfields));
1156068c877Sbostic static void	inlink __P((char ** fields, int nfields));
1166068c877Sbostic static void	inrule __P((char ** fields, int nfields));
1176068c877Sbostic static int	inzcont __P((char ** fields, int nfields));
1186068c877Sbostic static int	inzone __P((char ** fields, int nfields));
1196068c877Sbostic static int	inzsub __P((char ** fields, int nfields, int iscont));
1206068c877Sbostic static int	itsabbr __P((const char * abbr, const char * word));
1216068c877Sbostic static int	itsdir __P((const char * name));
1226068c877Sbostic static int	lowerit __P((int c));
1236068c877Sbostic static char *	memcheck __P((char * tocheck));
1246068c877Sbostic static int	mkdirs __P((char * filename));
1256068c877Sbostic static void	newabbr __P((const char * abbr));
1266068c877Sbostic static long	oadd __P((long t1, long t2));
1276068c877Sbostic static void	outzone __P((const struct zone * zp, int ntzones));
1286068c877Sbostic static void	puttzcode __P((long code, FILE * fp));
1296068c877Sbostic static int	rcomp __P((const void *leftp, const void *rightp));
1306068c877Sbostic static time_t	rpytime __P((const struct rule * rp, int wantedy));
1316068c877Sbostic static void	rulesub __P((struct rule * rp, char * loyearp, char * hiyearp,
1326068c877Sbostic 		char * typep, char * monthp, char * dayp, char * timep));
1336068c877Sbostic static void	setboundaries __P((void));
1346068c877Sbostic static time_t	tadd __P((time_t t1, long t2));
1356068c877Sbostic static void	usage __P((void));
1366068c877Sbostic static void	writezone __P((const char * name));
1376068c877Sbostic static int	yearistype __P((int year, const char * type));
13851034c06Sbostic 
13951034c06Sbostic static int		charcnt;
14051034c06Sbostic static int		errors;
14151034c06Sbostic static const char *	filename;
14251034c06Sbostic static int		leapcnt;
14351034c06Sbostic static int		linenum;
14451034c06Sbostic static time_t		max_time;
14551034c06Sbostic static int		max_year;
14651034c06Sbostic static time_t		min_time;
14751034c06Sbostic static int		min_year;
14851034c06Sbostic static int		noise;
14951034c06Sbostic static const char *	rfilename;
15051034c06Sbostic static int		rlinenum;
15151034c06Sbostic static const char *	progname;
15251034c06Sbostic static int		timecnt;
15351034c06Sbostic static int		typecnt;
15451034c06Sbostic static int		tt_signed;
15551034c06Sbostic 
15651034c06Sbostic /*
15751034c06Sbostic ** Line codes.
15851034c06Sbostic */
15951034c06Sbostic 
16051034c06Sbostic #define LC_RULE		0
16151034c06Sbostic #define LC_ZONE		1
16251034c06Sbostic #define LC_LINK		2
16351034c06Sbostic #define LC_LEAP		3
16451034c06Sbostic 
16551034c06Sbostic /*
16651034c06Sbostic ** Which fields are which on a Zone line.
16751034c06Sbostic */
16851034c06Sbostic 
16951034c06Sbostic #define ZF_NAME		1
17051034c06Sbostic #define ZF_GMTOFF	2
17151034c06Sbostic #define ZF_RULE		3
17251034c06Sbostic #define ZF_FORMAT	4
17351034c06Sbostic #define ZF_TILYEAR	5
17451034c06Sbostic #define ZF_TILMONTH	6
17551034c06Sbostic #define ZF_TILDAY	7
17651034c06Sbostic #define ZF_TILTIME	8
17751034c06Sbostic #define ZONE_MINFIELDS	5
17851034c06Sbostic #define ZONE_MAXFIELDS	9
17951034c06Sbostic 
18051034c06Sbostic /*
18151034c06Sbostic ** Which fields are which on a Zone continuation line.
18251034c06Sbostic */
18351034c06Sbostic 
18451034c06Sbostic #define ZFC_GMTOFF	0
18551034c06Sbostic #define ZFC_RULE	1
18651034c06Sbostic #define ZFC_FORMAT	2
18751034c06Sbostic #define ZFC_TILYEAR	3
18851034c06Sbostic #define ZFC_TILMONTH	4
18951034c06Sbostic #define ZFC_TILDAY	5
19051034c06Sbostic #define ZFC_TILTIME	6
19151034c06Sbostic #define ZONEC_MINFIELDS	3
19251034c06Sbostic #define ZONEC_MAXFIELDS	7
19351034c06Sbostic 
19451034c06Sbostic /*
19551034c06Sbostic ** Which files are which on a Rule line.
19651034c06Sbostic */
19751034c06Sbostic 
19851034c06Sbostic #define RF_NAME		1
19951034c06Sbostic #define RF_LOYEAR	2
20051034c06Sbostic #define RF_HIYEAR	3
20151034c06Sbostic #define RF_COMMAND	4
20251034c06Sbostic #define RF_MONTH	5
20351034c06Sbostic #define RF_DAY		6
20451034c06Sbostic #define RF_TOD		7
20551034c06Sbostic #define RF_STDOFF	8
20651034c06Sbostic #define RF_ABBRVAR	9
20751034c06Sbostic #define RULE_FIELDS	10
20851034c06Sbostic 
20951034c06Sbostic /*
21051034c06Sbostic ** Which fields are which on a Link line.
21151034c06Sbostic */
21251034c06Sbostic 
21351034c06Sbostic #define LF_FROM		1
21451034c06Sbostic #define LF_TO		2
21551034c06Sbostic #define LINK_FIELDS	3
21651034c06Sbostic 
21751034c06Sbostic /*
21851034c06Sbostic ** Which fields are which on a Leap line.
21951034c06Sbostic */
22051034c06Sbostic 
22151034c06Sbostic #define LP_YEAR		1
22251034c06Sbostic #define LP_MONTH	2
22351034c06Sbostic #define LP_DAY		3
22451034c06Sbostic #define LP_TIME		4
22551034c06Sbostic #define LP_CORR		5
22651034c06Sbostic #define LP_ROLL		6
22751034c06Sbostic #define LEAP_FIELDS	7
22851034c06Sbostic 
22951034c06Sbostic /*
23051034c06Sbostic ** Year synonyms.
23151034c06Sbostic */
23251034c06Sbostic 
23351034c06Sbostic #define YR_MINIMUM	0
23451034c06Sbostic #define YR_MAXIMUM	1
23551034c06Sbostic #define YR_ONLY		2
23651034c06Sbostic 
23751034c06Sbostic static struct rule *	rules;
23851034c06Sbostic static int		nrules;	/* number of rules */
23951034c06Sbostic 
24051034c06Sbostic static struct zone *	zones;
24151034c06Sbostic static int		nzones;	/* number of zones */
24251034c06Sbostic 
24351034c06Sbostic struct link {
24451034c06Sbostic 	const char *	l_filename;
24551034c06Sbostic 	int		l_linenum;
24651034c06Sbostic 	const char *	l_from;
24751034c06Sbostic 	const char *	l_to;
24851034c06Sbostic };
24951034c06Sbostic 
25051034c06Sbostic static struct link *	links;
25151034c06Sbostic static int		nlinks;
25251034c06Sbostic 
25351034c06Sbostic struct lookup {
25451034c06Sbostic 	const char *	l_word;
25551034c06Sbostic 	const int	l_value;
25651034c06Sbostic };
25751034c06Sbostic 
2586068c877Sbostic static struct lookup const *	byword __P((const char * string,
25951034c06Sbostic 					const struct lookup * lp));
26051034c06Sbostic 
26151034c06Sbostic static struct lookup const	line_codes[] = {
26251034c06Sbostic 	"Rule",		LC_RULE,
26351034c06Sbostic 	"Zone",		LC_ZONE,
26451034c06Sbostic 	"Link",		LC_LINK,
26551034c06Sbostic 	"Leap",		LC_LEAP,
26651034c06Sbostic 	NULL,		0
26751034c06Sbostic };
26851034c06Sbostic 
26951034c06Sbostic static struct lookup const	mon_names[] = {
27051034c06Sbostic 	"January",	TM_JANUARY,
27151034c06Sbostic 	"February",	TM_FEBRUARY,
27251034c06Sbostic 	"March",	TM_MARCH,
27351034c06Sbostic 	"April",	TM_APRIL,
27451034c06Sbostic 	"May",		TM_MAY,
27551034c06Sbostic 	"June",		TM_JUNE,
27651034c06Sbostic 	"July",		TM_JULY,
27751034c06Sbostic 	"August",	TM_AUGUST,
27851034c06Sbostic 	"September",	TM_SEPTEMBER,
27951034c06Sbostic 	"October",	TM_OCTOBER,
28051034c06Sbostic 	"November",	TM_NOVEMBER,
28151034c06Sbostic 	"December",	TM_DECEMBER,
28251034c06Sbostic 	NULL,		0
28351034c06Sbostic };
28451034c06Sbostic 
28551034c06Sbostic static struct lookup const	wday_names[] = {
28651034c06Sbostic 	"Sunday",	TM_SUNDAY,
28751034c06Sbostic 	"Monday",	TM_MONDAY,
28851034c06Sbostic 	"Tuesday",	TM_TUESDAY,
28951034c06Sbostic 	"Wednesday",	TM_WEDNESDAY,
29051034c06Sbostic 	"Thursday",	TM_THURSDAY,
29151034c06Sbostic 	"Friday",	TM_FRIDAY,
29251034c06Sbostic 	"Saturday",	TM_SATURDAY,
29351034c06Sbostic 	NULL,		0
29451034c06Sbostic };
29551034c06Sbostic 
29651034c06Sbostic static struct lookup const	lasts[] = {
29751034c06Sbostic 	"last-Sunday",		TM_SUNDAY,
29851034c06Sbostic 	"last-Monday",		TM_MONDAY,
29951034c06Sbostic 	"last-Tuesday",		TM_TUESDAY,
30051034c06Sbostic 	"last-Wednesday",	TM_WEDNESDAY,
30151034c06Sbostic 	"last-Thursday",	TM_THURSDAY,
30251034c06Sbostic 	"last-Friday",		TM_FRIDAY,
30351034c06Sbostic 	"last-Saturday",	TM_SATURDAY,
30451034c06Sbostic 	NULL,			0
30551034c06Sbostic };
30651034c06Sbostic 
30751034c06Sbostic static struct lookup const	begin_years[] = {
30851034c06Sbostic 	"minimum",		YR_MINIMUM,
30951034c06Sbostic 	"maximum",		YR_MAXIMUM,
31051034c06Sbostic 	NULL,			0
31151034c06Sbostic };
31251034c06Sbostic 
31351034c06Sbostic static struct lookup const	end_years[] = {
31451034c06Sbostic 	"minimum",		YR_MINIMUM,
31551034c06Sbostic 	"maximum",		YR_MAXIMUM,
31651034c06Sbostic 	"only",			YR_ONLY,
31751034c06Sbostic 	NULL,			0
31851034c06Sbostic };
31951034c06Sbostic 
32051034c06Sbostic static struct lookup const	leap_types[] = {
32151034c06Sbostic 	"Rolling",		TRUE,
32251034c06Sbostic 	"Stationary",		FALSE,
32351034c06Sbostic 	NULL,			0
32451034c06Sbostic };
32551034c06Sbostic 
32651034c06Sbostic static const int	len_months[2][MONSPERYEAR] = {
32751034c06Sbostic 	31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31,
32851034c06Sbostic 	31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
32951034c06Sbostic };
33051034c06Sbostic 
33151034c06Sbostic static const int	len_years[2] = {
33251034c06Sbostic 	DAYSPERNYEAR, DAYSPERLYEAR
33351034c06Sbostic };
33451034c06Sbostic 
33551034c06Sbostic static time_t		ats[TZ_MAX_TIMES];
33651034c06Sbostic static unsigned char	types[TZ_MAX_TIMES];
33751034c06Sbostic static long		gmtoffs[TZ_MAX_TYPES];
33851034c06Sbostic static char		isdsts[TZ_MAX_TYPES];
33951034c06Sbostic static char		abbrinds[TZ_MAX_TYPES];
34051034c06Sbostic static char		ttisstds[TZ_MAX_TYPES];
34151034c06Sbostic static char		chars[TZ_MAX_CHARS];
34251034c06Sbostic static time_t		trans[TZ_MAX_LEAPS];
34351034c06Sbostic static long		corr[TZ_MAX_LEAPS];
34451034c06Sbostic static char		roll[TZ_MAX_LEAPS];
34551034c06Sbostic 
34651034c06Sbostic /*
34751034c06Sbostic ** Memory allocation.
34851034c06Sbostic */
34951034c06Sbostic 
35051034c06Sbostic static char *
memcheck(ptr)35151034c06Sbostic memcheck(ptr)
35251034c06Sbostic char * const	ptr;
35351034c06Sbostic {
35451034c06Sbostic 	if (ptr == NULL) {
35551034c06Sbostic 		(void) perror(progname);
35651034c06Sbostic 		(void) exit(EXIT_FAILURE);
35751034c06Sbostic 	}
35851034c06Sbostic 	return ptr;
35951034c06Sbostic }
36051034c06Sbostic 
36151034c06Sbostic #define emalloc(size)		memcheck(imalloc(size))
36251034c06Sbostic #define erealloc(ptr, size)	memcheck(irealloc(ptr, size))
36351034c06Sbostic #define ecpyalloc(ptr)		memcheck(icpyalloc(ptr))
36451034c06Sbostic #define ecatalloc(oldp, newp)	memcheck(icatalloc(oldp, newp))
36551034c06Sbostic 
36651034c06Sbostic /*
36751034c06Sbostic ** Error handling.
36851034c06Sbostic */
36951034c06Sbostic 
37051034c06Sbostic static void
eats(name,num,rname,rnum)37151034c06Sbostic eats(name, num, rname, rnum)
37251034c06Sbostic const char * const	name;
37351034c06Sbostic const int		num;
37451034c06Sbostic const char * const	rname;
37551034c06Sbostic const int		rnum;
37651034c06Sbostic {
37751034c06Sbostic 	filename = name;
37851034c06Sbostic 	linenum = num;
37951034c06Sbostic 	rfilename = rname;
38051034c06Sbostic 	rlinenum = rnum;
38151034c06Sbostic }
38251034c06Sbostic 
38351034c06Sbostic static void
eat(name,num)38451034c06Sbostic eat(name, num)
38551034c06Sbostic const char * const	name;
38651034c06Sbostic const int		num;
38751034c06Sbostic {
38851034c06Sbostic 	eats(name, num, (char *) NULL, -1);
38951034c06Sbostic }
39051034c06Sbostic 
39151034c06Sbostic static void
error(string)39251034c06Sbostic error(string)
39351034c06Sbostic const char * const	string;
39451034c06Sbostic {
39551034c06Sbostic 	/*
39651034c06Sbostic 	** Match the format of "cc" to allow sh users to
39751034c06Sbostic 	** 	zic ... 2>&1 | error -t "*" -v
39851034c06Sbostic 	** on BSD systems.
39951034c06Sbostic 	*/
40051034c06Sbostic 	(void) fprintf(stderr, "\"%s\", line %d: %s",
40151034c06Sbostic 		filename, linenum, string);
40251034c06Sbostic 	if (rfilename != NULL)
40351034c06Sbostic 		(void) fprintf(stderr, " (rule from \"%s\", line %d)",
40451034c06Sbostic 			rfilename, rlinenum);
40551034c06Sbostic 	(void) fprintf(stderr, "\n");
40651034c06Sbostic 	++errors;
40751034c06Sbostic }
40851034c06Sbostic 
40951034c06Sbostic static void
usage()41051034c06Sbostic usage()
41151034c06Sbostic {
41251034c06Sbostic 	(void) fprintf(stderr,
41351034c06Sbostic "%s: usage is %s [ -s ] [ -v ] [ -l localtime ] [ -p posixrules ] [ -d directory ]\n\
41451034c06Sbostic \t[ -L leapseconds ] [ filename ... ]\n",
41551034c06Sbostic 		progname, progname);
41651034c06Sbostic 	(void) exit(EXIT_FAILURE);
41751034c06Sbostic }
41851034c06Sbostic 
41951034c06Sbostic static const char *	psxrules = NULL;
42051034c06Sbostic static const char *	lcltime = NULL;
42151034c06Sbostic static const char *	directory = NULL;
42251034c06Sbostic static const char *	leapsec = NULL;
42351034c06Sbostic static int		sflag = FALSE;
42451034c06Sbostic 
42551034c06Sbostic int
main(argc,argv)42651034c06Sbostic main(argc, argv)
42751034c06Sbostic int	argc;
42851034c06Sbostic char *	argv[];
42951034c06Sbostic {
43051034c06Sbostic 	register int	i, j;
43151034c06Sbostic 	register int	c;
43251034c06Sbostic 
43351034c06Sbostic 	(void) umask(umask(022) | 022);
43451034c06Sbostic 	progname = argv[0];
43551034c06Sbostic 	while ((c = getopt(argc, argv, "d:l:p:L:vs")) != EOF)
43651034c06Sbostic 		switch (c) {
43751034c06Sbostic 			default:
43851034c06Sbostic 				usage();
43951034c06Sbostic 			case 'd':
44051034c06Sbostic 				if (directory == NULL)
44151034c06Sbostic 					directory = optarg;
44251034c06Sbostic 				else {
44351034c06Sbostic 					(void) fprintf(stderr,
44451034c06Sbostic "%s: More than one -d option specified\n",
44551034c06Sbostic 						progname);
44651034c06Sbostic 					(void) exit(EXIT_FAILURE);
44751034c06Sbostic 				}
44851034c06Sbostic 				break;
44951034c06Sbostic 			case 'l':
45051034c06Sbostic 				if (lcltime == NULL)
45151034c06Sbostic 					lcltime = optarg;
45251034c06Sbostic 				else {
45351034c06Sbostic 					(void) fprintf(stderr,
45451034c06Sbostic "%s: More than one -l option specified\n",
45551034c06Sbostic 						progname);
45651034c06Sbostic 					(void) exit(EXIT_FAILURE);
45751034c06Sbostic 				}
45851034c06Sbostic 				break;
45951034c06Sbostic 			case 'p':
46051034c06Sbostic 				if (psxrules == NULL)
46151034c06Sbostic 					psxrules = optarg;
46251034c06Sbostic 				else {
46351034c06Sbostic 					(void) fprintf(stderr,
46451034c06Sbostic "%s: More than one -p option specified\n",
46551034c06Sbostic 						progname);
46651034c06Sbostic 					(void) exit(EXIT_FAILURE);
46751034c06Sbostic 				}
46851034c06Sbostic 				break;
46951034c06Sbostic 			case 'L':
47051034c06Sbostic 				if (leapsec == NULL)
47151034c06Sbostic 					leapsec = optarg;
47251034c06Sbostic 				else {
47351034c06Sbostic 					(void) fprintf(stderr,
47451034c06Sbostic "%s: More than one -L option specified\n",
47551034c06Sbostic 						progname);
47651034c06Sbostic 					(void) exit(EXIT_FAILURE);
47751034c06Sbostic 				}
47851034c06Sbostic 				break;
47951034c06Sbostic 			case 'v':
48051034c06Sbostic 				noise = TRUE;
48151034c06Sbostic 				break;
48251034c06Sbostic 			case 's':
48351034c06Sbostic 				sflag = TRUE;
48451034c06Sbostic 				break;
48551034c06Sbostic 		}
48651034c06Sbostic 	if (optind == argc - 1 && strcmp(argv[optind], "=") == 0)
48751034c06Sbostic 		usage();	/* usage message by request */
48851034c06Sbostic 	if (directory == NULL)
48951034c06Sbostic 		directory = TZDIR;
49051034c06Sbostic 
49151034c06Sbostic 	setboundaries();
49251034c06Sbostic 
49351034c06Sbostic 	if (optind < argc && leapsec != NULL) {
49451034c06Sbostic 		infile(leapsec);
49551034c06Sbostic 		adjleap();
49651034c06Sbostic 	}
49751034c06Sbostic 
49851034c06Sbostic 	zones = (struct zone *) emalloc(0);
49951034c06Sbostic 	rules = (struct rule *) emalloc(0);
50051034c06Sbostic 	links = (struct link *) emalloc(0);
50151034c06Sbostic 	for (i = optind; i < argc; ++i)
50251034c06Sbostic 		infile(argv[i]);
50351034c06Sbostic 	if (errors)
50451034c06Sbostic 		(void) exit(EXIT_FAILURE);
50551034c06Sbostic 	associate();
50651034c06Sbostic 	for (i = 0; i < nzones; i = j) {
50751034c06Sbostic 		/*
50851034c06Sbostic 		** Find the next non-continuation zone entry.
50951034c06Sbostic 		*/
51051034c06Sbostic 		for (j = i + 1; j < nzones && zones[j].z_name == NULL; ++j)
51151034c06Sbostic 			;
51251034c06Sbostic 		outzone(&zones[i], j - i);
51351034c06Sbostic 	}
51451034c06Sbostic 	/*
51551034c06Sbostic 	** Make links.
51651034c06Sbostic 	*/
51751034c06Sbostic 	for (i = 0; i < nlinks; ++i)
51851034c06Sbostic 		dolink(links[i].l_from, links[i].l_to);
51951034c06Sbostic 	if (lcltime != NULL)
52051034c06Sbostic 		dolink(lcltime, TZDEFAULT);
52151034c06Sbostic 	if (psxrules != NULL)
52251034c06Sbostic 		dolink(psxrules, TZDEFRULES);
52351034c06Sbostic 	return (errors == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
52451034c06Sbostic }
52551034c06Sbostic 
52651034c06Sbostic static void
dolink(fromfile,tofile)52751034c06Sbostic dolink(fromfile, tofile)
52851034c06Sbostic const char * const	fromfile;
52951034c06Sbostic const char * const	tofile;
53051034c06Sbostic {
53151034c06Sbostic 	register char *	fromname;
53251034c06Sbostic 	register char *	toname;
53351034c06Sbostic 
53451034c06Sbostic 	fromname = ecpyalloc(directory);
53551034c06Sbostic 	fromname = ecatalloc(fromname, "/");
53651034c06Sbostic 	fromname = ecatalloc(fromname, fromfile);
53751034c06Sbostic 	toname = ecpyalloc(directory);
53851034c06Sbostic 	toname = ecatalloc(toname, "/");
53951034c06Sbostic 	toname = ecatalloc(toname, tofile);
54051034c06Sbostic 	/*
54151034c06Sbostic 	** We get to be careful here since
54251034c06Sbostic 	** there's a fair chance of root running us.
54351034c06Sbostic 	*/
54451034c06Sbostic 	if (!itsdir(toname))
54551034c06Sbostic 		(void) remove(toname);
54651034c06Sbostic 	if (link(fromname, toname) != 0) {
54751034c06Sbostic 		(void) fprintf(stderr, "%s: Can't link from %s to ",
54851034c06Sbostic 			progname, fromname);
54951034c06Sbostic 		(void) perror(toname);
55051034c06Sbostic 		(void) exit(EXIT_FAILURE);
55151034c06Sbostic 	}
55251034c06Sbostic 	ifree(fromname);
55351034c06Sbostic 	ifree(toname);
55451034c06Sbostic }
55551034c06Sbostic 
55651034c06Sbostic static void
setboundaries()55751034c06Sbostic setboundaries()
55851034c06Sbostic {
55951034c06Sbostic 	register time_t	bit;
56051034c06Sbostic 
56151034c06Sbostic 	for (bit = 1; bit > 0; bit <<= 1)
56251034c06Sbostic 		;
56351034c06Sbostic 	if (bit == 0) {		/* time_t is an unsigned type */
56451034c06Sbostic 		tt_signed = FALSE;
56551034c06Sbostic 		min_time = 0;
56651034c06Sbostic 		max_time = ~(time_t) 0;
56751034c06Sbostic 		if (sflag)
56851034c06Sbostic 			max_time >>= 1;
56951034c06Sbostic 	} else {
57051034c06Sbostic 		tt_signed = TRUE;
57151034c06Sbostic 		min_time = bit;
57251034c06Sbostic 		max_time = bit;
57351034c06Sbostic 		++max_time;
57451034c06Sbostic 		max_time = -max_time;
57551034c06Sbostic 		if (sflag)
57651034c06Sbostic 			min_time = 0;
57751034c06Sbostic 	}
57851034c06Sbostic 	min_year = TM_YEAR_BASE + gmtime(&min_time)->tm_year;
57951034c06Sbostic 	max_year = TM_YEAR_BASE + gmtime(&max_time)->tm_year;
58051034c06Sbostic }
58151034c06Sbostic 
58251034c06Sbostic static int
itsdir(name)58351034c06Sbostic itsdir(name)
58451034c06Sbostic const char * const	name;
58551034c06Sbostic {
58651034c06Sbostic 	struct stat	s;
58751034c06Sbostic 
5886068c877Sbostic 	return (stat(name, &s) == 0 && S_ISDIR(s.st_mode));
58951034c06Sbostic }
59051034c06Sbostic 
59151034c06Sbostic /*
59251034c06Sbostic ** Associate sets of rules with zones.
59351034c06Sbostic */
59451034c06Sbostic 
59551034c06Sbostic /*
59651034c06Sbostic ** Sort by rule name.
59751034c06Sbostic */
59851034c06Sbostic 
59951034c06Sbostic static int
rcomp(cp1,cp2)60051034c06Sbostic rcomp(cp1, cp2)
6016068c877Sbostic const void *	cp1;
6026068c877Sbostic const void *	cp2;
60351034c06Sbostic {
60451034c06Sbostic 	return strcmp(((struct rule *) cp1)->r_name,
60551034c06Sbostic 		((struct rule *) cp2)->r_name);
60651034c06Sbostic }
60751034c06Sbostic 
60851034c06Sbostic static void
associate()60951034c06Sbostic associate()
61051034c06Sbostic {
61151034c06Sbostic 	register struct zone *	zp;
61251034c06Sbostic 	register struct rule *	rp;
61351034c06Sbostic 	register int		base, out;
61451034c06Sbostic 	register int		i;
61551034c06Sbostic 
61651034c06Sbostic 	if (nrules != 0)
6176068c877Sbostic 		(void) qsort((void *) rules, (size_t) nrules,
6186068c877Sbostic 		     (size_t) sizeof *rules, rcomp);
61951034c06Sbostic 	for (i = 0; i < nzones; ++i) {
62051034c06Sbostic 		zp = &zones[i];
62151034c06Sbostic 		zp->z_rules = NULL;
62251034c06Sbostic 		zp->z_nrules = 0;
62351034c06Sbostic 	}
62451034c06Sbostic 	for (base = 0; base < nrules; base = out) {
62551034c06Sbostic 		rp = &rules[base];
62651034c06Sbostic 		for (out = base + 1; out < nrules; ++out)
62751034c06Sbostic 			if (strcmp(rp->r_name, rules[out].r_name) != 0)
62851034c06Sbostic 				break;
62951034c06Sbostic 		for (i = 0; i < nzones; ++i) {
63051034c06Sbostic 			zp = &zones[i];
63151034c06Sbostic 			if (strcmp(zp->z_rule, rp->r_name) != 0)
63251034c06Sbostic 				continue;
63351034c06Sbostic 			zp->z_rules = rp;
63451034c06Sbostic 			zp->z_nrules = out - base;
63551034c06Sbostic 		}
63651034c06Sbostic 	}
63751034c06Sbostic 	for (i = 0; i < nzones; ++i) {
63851034c06Sbostic 		zp = &zones[i];
63951034c06Sbostic 		if (zp->z_nrules == 0) {
64051034c06Sbostic 			/*
64151034c06Sbostic 			** Maybe we have a local standard time offset.
64251034c06Sbostic 			*/
64351034c06Sbostic 			eat(zp->z_filename, zp->z_linenum);
6446068c877Sbostic 			zp->z_stdoff =
6456068c877Sbostic 			    gethms((char *)zp->z_rule, "unruly zone", TRUE);
64651034c06Sbostic 			/*
64751034c06Sbostic 			** Note, though, that if there's no rule,
64851034c06Sbostic 			** a '%s' in the format is a bad thing.
64951034c06Sbostic 			*/
65051034c06Sbostic 			if (strchr(zp->z_format, '%') != 0)
65151034c06Sbostic 				error("%s in ruleless zone");
65251034c06Sbostic 		}
65351034c06Sbostic 	}
65451034c06Sbostic 	if (errors)
65551034c06Sbostic 		(void) exit(EXIT_FAILURE);
65651034c06Sbostic }
65751034c06Sbostic 
65851034c06Sbostic static void
infile(name)65951034c06Sbostic infile(name)
66051034c06Sbostic const char *	name;
66151034c06Sbostic {
66251034c06Sbostic 	register FILE *			fp;
66351034c06Sbostic 	register char **		fields;
66451034c06Sbostic 	register char *			cp;
66551034c06Sbostic 	register const struct lookup *	lp;
66651034c06Sbostic 	register int			nfields;
66751034c06Sbostic 	register int			wantcont;
66851034c06Sbostic 	register int			num;
66951034c06Sbostic 	char				buf[BUFSIZ];
67051034c06Sbostic 
67151034c06Sbostic 	if (strcmp(name, "-") == 0) {
67251034c06Sbostic 		name = "standard input";
67351034c06Sbostic 		fp = stdin;
67451034c06Sbostic 	} else if ((fp = fopen(name, "r")) == NULL) {
67551034c06Sbostic 		(void) fprintf(stderr, "%s: Can't open ", progname);
67651034c06Sbostic 		(void) perror(name);
67751034c06Sbostic 		(void) exit(EXIT_FAILURE);
67851034c06Sbostic 	}
67951034c06Sbostic 	wantcont = FALSE;
68051034c06Sbostic 	for (num = 1; ; ++num) {
68151034c06Sbostic 		eat(name, num);
68251034c06Sbostic 		if (fgets(buf, (int) sizeof buf, fp) != buf)
68351034c06Sbostic 			break;
68451034c06Sbostic 		cp = strchr(buf, '\n');
68551034c06Sbostic 		if (cp == NULL) {
68651034c06Sbostic 			error("line too long");
68751034c06Sbostic 			(void) exit(EXIT_FAILURE);
68851034c06Sbostic 		}
68951034c06Sbostic 		*cp = '\0';
69051034c06Sbostic 		fields = getfields(buf);
69151034c06Sbostic 		nfields = 0;
69251034c06Sbostic 		while (fields[nfields] != NULL) {
69351034c06Sbostic 			if (ciequal(fields[nfields], "-"))
69451034c06Sbostic 				fields[nfields] = "";
69551034c06Sbostic 			++nfields;
69651034c06Sbostic 		}
69751034c06Sbostic 		if (nfields == 0) {
69851034c06Sbostic 			/* nothing to do */
69951034c06Sbostic 		} else if (wantcont) {
70051034c06Sbostic 			wantcont = inzcont(fields, nfields);
70151034c06Sbostic 		} else {
70251034c06Sbostic 			lp = byword(fields[0], line_codes);
70351034c06Sbostic 			if (lp == NULL)
70451034c06Sbostic 				error("input line of unknown type");
70551034c06Sbostic 			else switch ((int) (lp->l_value)) {
70651034c06Sbostic 				case LC_RULE:
70751034c06Sbostic 					inrule(fields, nfields);
70851034c06Sbostic 					wantcont = FALSE;
70951034c06Sbostic 					break;
71051034c06Sbostic 				case LC_ZONE:
71151034c06Sbostic 					wantcont = inzone(fields, nfields);
71251034c06Sbostic 					break;
71351034c06Sbostic 				case LC_LINK:
71451034c06Sbostic 					inlink(fields, nfields);
71551034c06Sbostic 					wantcont = FALSE;
71651034c06Sbostic 					break;
71751034c06Sbostic 				case LC_LEAP:
71851034c06Sbostic 					if (name != leapsec)
71951034c06Sbostic 						(void) fprintf(stderr,
72051034c06Sbostic "%s: Leap line in non leap seconds file %s\n",
72151034c06Sbostic 							progname, name);
72251034c06Sbostic 					else	inleap(fields, nfields);
72351034c06Sbostic 					wantcont = FALSE;
72451034c06Sbostic 					break;
72551034c06Sbostic 				default:	/* "cannot happen" */
72651034c06Sbostic 					(void) fprintf(stderr,
72751034c06Sbostic "%s: panic: Invalid l_value %d\n",
72851034c06Sbostic 						progname, lp->l_value);
72951034c06Sbostic 					(void) exit(EXIT_FAILURE);
73051034c06Sbostic 			}
73151034c06Sbostic 		}
73251034c06Sbostic 		ifree((char *) fields);
73351034c06Sbostic 	}
73451034c06Sbostic 	if (ferror(fp)) {
73551034c06Sbostic 		(void) fprintf(stderr, "%s: Error reading ", progname);
73651034c06Sbostic 		(void) perror(filename);
73751034c06Sbostic 		(void) exit(EXIT_FAILURE);
73851034c06Sbostic 	}
73951034c06Sbostic 	if (fp != stdin && fclose(fp)) {
74051034c06Sbostic 		(void) fprintf(stderr, "%s: Error closing ", progname);
74151034c06Sbostic 		(void) perror(filename);
74251034c06Sbostic 		(void) exit(EXIT_FAILURE);
74351034c06Sbostic 	}
74451034c06Sbostic 	if (wantcont)
74551034c06Sbostic 		error("expected continuation line not found");
74651034c06Sbostic }
74751034c06Sbostic 
74851034c06Sbostic /*
74951034c06Sbostic ** Convert a string of one of the forms
75051034c06Sbostic **	h	-h 	hh:mm	-hh:mm	hh:mm:ss	-hh:mm:ss
75151034c06Sbostic ** into a number of seconds.
75251034c06Sbostic ** A null string maps to zero.
75351034c06Sbostic ** Call error with errstring and return zero on errors.
75451034c06Sbostic */
75551034c06Sbostic 
75651034c06Sbostic static long
gethms(string,errstring,signable)75751034c06Sbostic gethms(string, errstring, signable)
7586068c877Sbostic char *		string;
75951034c06Sbostic const char * const	errstring;
76051034c06Sbostic const int		signable;
76151034c06Sbostic {
76251034c06Sbostic 	int	hh, mm, ss, sign;
76351034c06Sbostic 
76451034c06Sbostic 	if (string == NULL || *string == '\0')
76551034c06Sbostic 		return 0;
76651034c06Sbostic 	if (!signable)
76751034c06Sbostic 		sign = 1;
76851034c06Sbostic 	else if (*string == '-') {
76951034c06Sbostic 		sign = -1;
77051034c06Sbostic 		++string;
77151034c06Sbostic 	} else	sign = 1;
77251034c06Sbostic 	if (sscanf(string, scheck(string, "%d"), &hh) == 1)
77351034c06Sbostic 		mm = ss = 0;
77451034c06Sbostic 	else if (sscanf(string, scheck(string, "%d:%d"), &hh, &mm) == 2)
77551034c06Sbostic 		ss = 0;
77651034c06Sbostic 	else if (sscanf(string, scheck(string, "%d:%d:%d"),
77751034c06Sbostic 		&hh, &mm, &ss) != 3) {
77851034c06Sbostic 			error(errstring);
77951034c06Sbostic 			return 0;
78051034c06Sbostic 	}
78151034c06Sbostic 	if (hh < 0 || hh >= HOURSPERDAY ||
78251034c06Sbostic 		mm < 0 || mm >= MINSPERHOUR ||
78351034c06Sbostic 		ss < 0 || ss > SECSPERMIN) {
78451034c06Sbostic 			error(errstring);
78551034c06Sbostic 			return 0;
78651034c06Sbostic 	}
78751034c06Sbostic 	return eitol(sign) *
78851034c06Sbostic 		(eitol(hh * MINSPERHOUR + mm) *
78951034c06Sbostic 		eitol(SECSPERMIN) + eitol(ss));
79051034c06Sbostic }
79151034c06Sbostic 
79251034c06Sbostic static void
inrule(fields,nfields)79351034c06Sbostic inrule(fields, nfields)
79451034c06Sbostic register char ** const	fields;
79551034c06Sbostic const int		nfields;
79651034c06Sbostic {
79751034c06Sbostic 	static struct rule	r;
79851034c06Sbostic 
79951034c06Sbostic 	if (nfields != RULE_FIELDS) {
80051034c06Sbostic 		error("wrong number of fields on Rule line");
80151034c06Sbostic 		return;
80251034c06Sbostic 	}
80351034c06Sbostic 	if (*fields[RF_NAME] == '\0') {
80451034c06Sbostic 		error("nameless rule");
80551034c06Sbostic 		return;
80651034c06Sbostic 	}
80751034c06Sbostic 	r.r_filename = filename;
80851034c06Sbostic 	r.r_linenum = linenum;
80951034c06Sbostic 	r.r_stdoff = gethms(fields[RF_STDOFF], "invalid saved time", TRUE);
81051034c06Sbostic 	rulesub(&r, fields[RF_LOYEAR], fields[RF_HIYEAR], fields[RF_COMMAND],
81151034c06Sbostic 		fields[RF_MONTH], fields[RF_DAY], fields[RF_TOD]);
81251034c06Sbostic 	r.r_name = ecpyalloc(fields[RF_NAME]);
81351034c06Sbostic 	r.r_abbrvar = ecpyalloc(fields[RF_ABBRVAR]);
81451034c06Sbostic 	rules = (struct rule *) erealloc((char *) rules,
81551034c06Sbostic 		(int) ((nrules + 1) * sizeof *rules));
81651034c06Sbostic 	rules[nrules++] = r;
81751034c06Sbostic }
81851034c06Sbostic 
81951034c06Sbostic static int
inzone(fields,nfields)82051034c06Sbostic inzone(fields, nfields)
82151034c06Sbostic register char ** const	fields;
82251034c06Sbostic const int		nfields;
82351034c06Sbostic {
82451034c06Sbostic 	register int	i;
82551034c06Sbostic 	char		buf[132];
82651034c06Sbostic 
82751034c06Sbostic 	if (nfields < ZONE_MINFIELDS || nfields > ZONE_MAXFIELDS) {
82851034c06Sbostic 		error("wrong number of fields on Zone line");
82951034c06Sbostic 		return FALSE;
83051034c06Sbostic 	}
83151034c06Sbostic 	if (strcmp(fields[ZF_NAME], TZDEFAULT) == 0 && lcltime != NULL) {
83251034c06Sbostic 		(void) sprintf(buf,
83351034c06Sbostic 			"\"Zone %s\" line and -l option are mutually exclusive",
83451034c06Sbostic 			TZDEFAULT);
83551034c06Sbostic 		error(buf);
83651034c06Sbostic 		return FALSE;
83751034c06Sbostic 	}
83851034c06Sbostic 	if (strcmp(fields[ZF_NAME], TZDEFRULES) == 0 && psxrules != NULL) {
83951034c06Sbostic 		(void) sprintf(buf,
84051034c06Sbostic 			"\"Zone %s\" line and -p option are mutually exclusive",
84151034c06Sbostic 			TZDEFRULES);
84251034c06Sbostic 		error(buf);
84351034c06Sbostic 		return FALSE;
84451034c06Sbostic 	}
84551034c06Sbostic 	for (i = 0; i < nzones; ++i)
84651034c06Sbostic 		if (zones[i].z_name != NULL &&
84751034c06Sbostic 			strcmp(zones[i].z_name, fields[ZF_NAME]) == 0) {
84851034c06Sbostic 				(void) sprintf(buf,
84951034c06Sbostic "duplicate zone name %s (file \"%s\", line %d)",
85051034c06Sbostic 					fields[ZF_NAME],
85151034c06Sbostic 					zones[i].z_filename,
85251034c06Sbostic 					zones[i].z_linenum);
85351034c06Sbostic 				error(buf);
85451034c06Sbostic 				return FALSE;
85551034c06Sbostic 		}
85651034c06Sbostic 	return inzsub(fields, nfields, FALSE);
85751034c06Sbostic }
85851034c06Sbostic 
85951034c06Sbostic static int
inzcont(fields,nfields)86051034c06Sbostic inzcont(fields, nfields)
86151034c06Sbostic register char ** const	fields;
86251034c06Sbostic const int		nfields;
86351034c06Sbostic {
86451034c06Sbostic 	if (nfields < ZONEC_MINFIELDS || nfields > ZONEC_MAXFIELDS) {
86551034c06Sbostic 		error("wrong number of fields on Zone continuation line");
86651034c06Sbostic 		return FALSE;
86751034c06Sbostic 	}
86851034c06Sbostic 	return inzsub(fields, nfields, TRUE);
86951034c06Sbostic }
87051034c06Sbostic 
87151034c06Sbostic static int
inzsub(fields,nfields,iscont)87251034c06Sbostic inzsub(fields, nfields, iscont)
87351034c06Sbostic register char ** const	fields;
87451034c06Sbostic const int		nfields;
87551034c06Sbostic const int		iscont;
87651034c06Sbostic {
87751034c06Sbostic 	register char *		cp;
87851034c06Sbostic 	static struct zone	z;
87951034c06Sbostic 	register int		i_gmtoff, i_rule, i_format;
88051034c06Sbostic 	register int		i_untilyear, i_untilmonth;
88151034c06Sbostic 	register int		i_untilday, i_untiltime;
88251034c06Sbostic 	register int		hasuntil;
88351034c06Sbostic 
88451034c06Sbostic 	if (iscont) {
88551034c06Sbostic 		i_gmtoff = ZFC_GMTOFF;
88651034c06Sbostic 		i_rule = ZFC_RULE;
88751034c06Sbostic 		i_format = ZFC_FORMAT;
88851034c06Sbostic 		i_untilyear = ZFC_TILYEAR;
88951034c06Sbostic 		i_untilmonth = ZFC_TILMONTH;
89051034c06Sbostic 		i_untilday = ZFC_TILDAY;
89151034c06Sbostic 		i_untiltime = ZFC_TILTIME;
89251034c06Sbostic 		z.z_name = NULL;
89351034c06Sbostic 	} else {
89451034c06Sbostic 		i_gmtoff = ZF_GMTOFF;
89551034c06Sbostic 		i_rule = ZF_RULE;
89651034c06Sbostic 		i_format = ZF_FORMAT;
89751034c06Sbostic 		i_untilyear = ZF_TILYEAR;
89851034c06Sbostic 		i_untilmonth = ZF_TILMONTH;
89951034c06Sbostic 		i_untilday = ZF_TILDAY;
90051034c06Sbostic 		i_untiltime = ZF_TILTIME;
90151034c06Sbostic 		z.z_name = ecpyalloc(fields[ZF_NAME]);
90251034c06Sbostic 	}
90351034c06Sbostic 	z.z_filename = filename;
90451034c06Sbostic 	z.z_linenum = linenum;
90551034c06Sbostic 	z.z_gmtoff = gethms(fields[i_gmtoff], "invalid GMT offset", TRUE);
90651034c06Sbostic 	if ((cp = strchr(fields[i_format], '%')) != 0) {
90751034c06Sbostic 		if (*++cp != 's' || strchr(cp, '%') != 0) {
90851034c06Sbostic 			error("invalid abbreviation format");
90951034c06Sbostic 			return FALSE;
91051034c06Sbostic 		}
91151034c06Sbostic 	}
91251034c06Sbostic 	z.z_rule = ecpyalloc(fields[i_rule]);
91351034c06Sbostic 	z.z_format = ecpyalloc(fields[i_format]);
91451034c06Sbostic 	hasuntil = nfields > i_untilyear;
91551034c06Sbostic 	if (hasuntil) {
91651034c06Sbostic 		z.z_untilrule.r_filename = filename;
91751034c06Sbostic 		z.z_untilrule.r_linenum = linenum;
91851034c06Sbostic 		rulesub(&z.z_untilrule,
91951034c06Sbostic 			fields[i_untilyear],
92051034c06Sbostic 			"only",
92151034c06Sbostic 			"",
92251034c06Sbostic 			(nfields > i_untilmonth) ? fields[i_untilmonth] : "Jan",
92351034c06Sbostic 			(nfields > i_untilday) ? fields[i_untilday] : "1",
92451034c06Sbostic 			(nfields > i_untiltime) ? fields[i_untiltime] : "0");
92551034c06Sbostic 		z.z_untiltime = rpytime(&z.z_untilrule, z.z_untilrule.r_loyear);
92651034c06Sbostic 		if (iscont && nzones > 0 && z.z_untiltime < max_time &&
92751034c06Sbostic 			z.z_untiltime > min_time &&
92851034c06Sbostic 			zones[nzones - 1].z_untiltime >= z.z_untiltime) {
92951034c06Sbostic error("Zone continuation line end time is not after end time of previous line");
93051034c06Sbostic 			return FALSE;
93151034c06Sbostic 		}
93251034c06Sbostic 	}
93351034c06Sbostic 	zones = (struct zone *) erealloc((char *) zones,
93451034c06Sbostic 		(int) ((nzones + 1) * sizeof *zones));
93551034c06Sbostic 	zones[nzones++] = z;
93651034c06Sbostic 	/*
93751034c06Sbostic 	** If there was an UNTIL field on this line,
93851034c06Sbostic 	** there's more information about the zone on the next line.
93951034c06Sbostic 	*/
94051034c06Sbostic 	return hasuntil;
94151034c06Sbostic }
94251034c06Sbostic 
94351034c06Sbostic static void
inleap(fields,nfields)94451034c06Sbostic inleap(fields, nfields)
94551034c06Sbostic register char ** const	fields;
94651034c06Sbostic const int		nfields;
94751034c06Sbostic {
94851034c06Sbostic 	register const char *		cp;
94951034c06Sbostic 	register const struct lookup *	lp;
95051034c06Sbostic 	register int			i, j;
95151034c06Sbostic 	int				year, month, day;
95251034c06Sbostic 	long				dayoff, tod;
95351034c06Sbostic 	time_t				t;
95451034c06Sbostic 
95551034c06Sbostic 	if (nfields != LEAP_FIELDS) {
95651034c06Sbostic 		error("wrong number of fields on Leap line");
95751034c06Sbostic 		return;
95851034c06Sbostic 	}
95951034c06Sbostic 	dayoff = 0;
96051034c06Sbostic 	cp = fields[LP_YEAR];
9616068c877Sbostic 	if (sscanf((char *)cp, scheck(cp, "%d"), &year) != 1 ||
96251034c06Sbostic 		year < min_year || year > max_year) {
96351034c06Sbostic 			/*
96451034c06Sbostic 			 * Leapin' Lizards!
96551034c06Sbostic 			 */
96651034c06Sbostic 			error("invalid leaping year");
96751034c06Sbostic 			return;
96851034c06Sbostic 	}
96951034c06Sbostic 	j = EPOCH_YEAR;
97051034c06Sbostic 	while (j != year) {
97151034c06Sbostic 		if (year > j) {
97251034c06Sbostic 			i = len_years[isleap(j)];
97351034c06Sbostic 			++j;
97451034c06Sbostic 		} else {
97551034c06Sbostic 			--j;
97651034c06Sbostic 			i = -len_years[isleap(j)];
97751034c06Sbostic 		}
97851034c06Sbostic 		dayoff = oadd(dayoff, eitol(i));
97951034c06Sbostic 	}
98051034c06Sbostic 	if ((lp = byword(fields[LP_MONTH], mon_names)) == NULL) {
98151034c06Sbostic 		error("invalid month name");
98251034c06Sbostic 		return;
98351034c06Sbostic 	}
98451034c06Sbostic 	month = lp->l_value;
98551034c06Sbostic 	j = TM_JANUARY;
98651034c06Sbostic 	while (j != month) {
98751034c06Sbostic 		i = len_months[isleap(year)][j];
98851034c06Sbostic 		dayoff = oadd(dayoff, eitol(i));
98951034c06Sbostic 		++j;
99051034c06Sbostic 	}
99151034c06Sbostic 	cp = fields[LP_DAY];
9926068c877Sbostic 	if (sscanf((char *)cp, scheck(cp, "%d"), &day) != 1 ||
99351034c06Sbostic 		day <= 0 || day > len_months[isleap(year)][month]) {
99451034c06Sbostic 			error("invalid day of month");
99551034c06Sbostic 			return;
99651034c06Sbostic 	}
99751034c06Sbostic 	dayoff = oadd(dayoff, eitol(day - 1));
99851034c06Sbostic 	if (dayoff < 0 && !tt_signed) {
99951034c06Sbostic 		error("time before zero");
100051034c06Sbostic 		return;
100151034c06Sbostic 	}
100251034c06Sbostic 	t = (time_t) dayoff * SECSPERDAY;
100351034c06Sbostic 	/*
100451034c06Sbostic 	** Cheap overflow check.
100551034c06Sbostic 	*/
100651034c06Sbostic 	if (t / SECSPERDAY != dayoff) {
100751034c06Sbostic 		error("time overflow");
100851034c06Sbostic 		return;
100951034c06Sbostic 	}
101051034c06Sbostic 	tod = gethms(fields[LP_TIME], "invalid time of day", FALSE);
101151034c06Sbostic 	cp = fields[LP_CORR];
101251034c06Sbostic 	if (strcmp(cp, "+") != 0 && strcmp(cp, "") != 0) {
101351034c06Sbostic 		/* infile() turned "-" into "" */
101451034c06Sbostic 		error("illegal CORRECTION field on Leap line");
101551034c06Sbostic 		return;
101651034c06Sbostic 	}
101751034c06Sbostic 	if ((lp = byword(fields[LP_ROLL], leap_types)) == NULL) {
101851034c06Sbostic 		error("illegal Rolling/Stationary field on Leap line");
101951034c06Sbostic 		return;
102051034c06Sbostic 	}
102151034c06Sbostic 	addleap(tadd(t, tod), *cp == '+', lp->l_value);
102251034c06Sbostic }
102351034c06Sbostic 
102451034c06Sbostic static void
inlink(fields,nfields)102551034c06Sbostic inlink(fields, nfields)
102651034c06Sbostic register char ** const	fields;
102751034c06Sbostic const int		nfields;
102851034c06Sbostic {
102951034c06Sbostic 	struct link	l;
103051034c06Sbostic 
103151034c06Sbostic 	if (nfields != LINK_FIELDS) {
103251034c06Sbostic 		error("wrong number of fields on Link line");
103351034c06Sbostic 		return;
103451034c06Sbostic 	}
103551034c06Sbostic 	if (*fields[LF_FROM] == '\0') {
103651034c06Sbostic 		error("blank FROM field on Link line");
103751034c06Sbostic 		return;
103851034c06Sbostic 	}
103951034c06Sbostic 	if (*fields[LF_TO] == '\0') {
104051034c06Sbostic 		error("blank TO field on Link line");
104151034c06Sbostic 		return;
104251034c06Sbostic 	}
104351034c06Sbostic 	l.l_filename = filename;
104451034c06Sbostic 	l.l_linenum = linenum;
104551034c06Sbostic 	l.l_from = ecpyalloc(fields[LF_FROM]);
104651034c06Sbostic 	l.l_to = ecpyalloc(fields[LF_TO]);
104751034c06Sbostic 	links = (struct link *) erealloc((char *) links,
104851034c06Sbostic 		(int) ((nlinks + 1) * sizeof *links));
104951034c06Sbostic 	links[nlinks++] = l;
105051034c06Sbostic }
105151034c06Sbostic 
105251034c06Sbostic static void
rulesub(rp,loyearp,hiyearp,typep,monthp,dayp,timep)105351034c06Sbostic rulesub(rp, loyearp, hiyearp, typep, monthp, dayp, timep)
105451034c06Sbostic register struct rule * const	rp;
105551034c06Sbostic char * const			loyearp;
105651034c06Sbostic char * const			hiyearp;
105751034c06Sbostic char * const			typep;
105851034c06Sbostic char * const			monthp;
105951034c06Sbostic char * const			dayp;
106051034c06Sbostic char * const			timep;
106151034c06Sbostic {
106251034c06Sbostic 	register struct lookup const *	lp;
106351034c06Sbostic 	register char *			cp;
106451034c06Sbostic 
106551034c06Sbostic 	if ((lp = byword(monthp, mon_names)) == NULL) {
106651034c06Sbostic 		error("invalid month name");
106751034c06Sbostic 		return;
106851034c06Sbostic 	}
106951034c06Sbostic 	rp->r_month = lp->l_value;
107051034c06Sbostic 	rp->r_todisstd = FALSE;
107151034c06Sbostic 	cp = timep;
107251034c06Sbostic 	if (*cp != '\0') {
107351034c06Sbostic 		cp += strlen(cp) - 1;
107451034c06Sbostic 		switch (lowerit(*cp)) {
107551034c06Sbostic 			case 's':
107651034c06Sbostic 				rp->r_todisstd = TRUE;
107751034c06Sbostic 				*cp = '\0';
107851034c06Sbostic 				break;
107951034c06Sbostic 			case 'w':
108051034c06Sbostic 				rp->r_todisstd = FALSE;
108151034c06Sbostic 				*cp = '\0';
108251034c06Sbostic 				break;
108351034c06Sbostic 		}
108451034c06Sbostic 	}
108551034c06Sbostic 	rp->r_tod = gethms(timep, "invalid time of day", FALSE);
108651034c06Sbostic 	/*
108751034c06Sbostic 	** Year work.
108851034c06Sbostic 	*/
108951034c06Sbostic 	cp = loyearp;
109051034c06Sbostic 	if ((lp = byword(cp, begin_years)) != NULL) switch ((int) lp->l_value) {
109151034c06Sbostic 		case YR_MINIMUM:
109251034c06Sbostic 			rp->r_loyear = min_year;
109351034c06Sbostic 			break;
109451034c06Sbostic 		case YR_MAXIMUM:
109551034c06Sbostic 			rp->r_loyear = max_year;
109651034c06Sbostic 			break;
109751034c06Sbostic 		default:	/* "cannot happen" */
109851034c06Sbostic 			(void) fprintf(stderr,
109951034c06Sbostic 				"%s: panic: Invalid l_value %d\n",
110051034c06Sbostic 				progname, lp->l_value);
110151034c06Sbostic 			(void) exit(EXIT_FAILURE);
110251034c06Sbostic 	} else if (sscanf(cp, scheck(cp, "%d"), &rp->r_loyear) != 1 ||
110351034c06Sbostic 		rp->r_loyear < min_year || rp->r_loyear > max_year) {
110451034c06Sbostic 			if (noise)
110551034c06Sbostic 				error("invalid starting year");
110651034c06Sbostic 			if (rp->r_loyear > max_year)
110751034c06Sbostic 				return;
110851034c06Sbostic 	}
110951034c06Sbostic 	cp = hiyearp;
111051034c06Sbostic 	if ((lp = byword(cp, end_years)) != NULL) switch ((int) lp->l_value) {
111151034c06Sbostic 		case YR_MINIMUM:
111251034c06Sbostic 			rp->r_hiyear = min_year;
111351034c06Sbostic 			break;
111451034c06Sbostic 		case YR_MAXIMUM:
111551034c06Sbostic 			rp->r_hiyear = max_year;
111651034c06Sbostic 			break;
111751034c06Sbostic 		case YR_ONLY:
111851034c06Sbostic 			rp->r_hiyear = rp->r_loyear;
111951034c06Sbostic 			break;
112051034c06Sbostic 		default:	/* "cannot happen" */
112151034c06Sbostic 			(void) fprintf(stderr,
112251034c06Sbostic 				"%s: panic: Invalid l_value %d\n",
112351034c06Sbostic 				progname, lp->l_value);
112451034c06Sbostic 			(void) exit(EXIT_FAILURE);
112551034c06Sbostic 	} else if (sscanf(cp, scheck(cp, "%d"), &rp->r_hiyear) != 1 ||
112651034c06Sbostic 		rp->r_hiyear < min_year || rp->r_hiyear > max_year) {
112751034c06Sbostic 			if (noise)
112851034c06Sbostic 				error("invalid ending year");
112951034c06Sbostic 			if (rp->r_hiyear < min_year)
113051034c06Sbostic 				return;
113151034c06Sbostic 	}
113251034c06Sbostic 	if (rp->r_hiyear < min_year)
113351034c06Sbostic  		return;
113451034c06Sbostic  	if (rp->r_loyear < min_year)
113551034c06Sbostic  		rp->r_loyear = min_year;
113651034c06Sbostic  	if (rp->r_hiyear > max_year)
113751034c06Sbostic  		rp->r_hiyear = max_year;
113851034c06Sbostic 	if (rp->r_loyear > rp->r_hiyear) {
113951034c06Sbostic 		error("starting year greater than ending year");
114051034c06Sbostic 		return;
114151034c06Sbostic 	}
114251034c06Sbostic 	if (*typep == '\0')
114351034c06Sbostic 		rp->r_yrtype = NULL;
114451034c06Sbostic 	else {
114551034c06Sbostic 		if (rp->r_loyear == rp->r_hiyear) {
114651034c06Sbostic 			error("typed single year");
114751034c06Sbostic 			return;
114851034c06Sbostic 		}
114951034c06Sbostic 		rp->r_yrtype = ecpyalloc(typep);
115051034c06Sbostic 	}
115151034c06Sbostic 	/*
115251034c06Sbostic 	** Day work.
115351034c06Sbostic 	** Accept things such as:
115451034c06Sbostic 	**	1
115551034c06Sbostic 	**	last-Sunday
115651034c06Sbostic 	**	Sun<=20
115751034c06Sbostic 	**	Sun>=7
115851034c06Sbostic 	*/
115951034c06Sbostic 	if ((lp = byword(dayp, lasts)) != NULL) {
116051034c06Sbostic 		rp->r_dycode = DC_DOWLEQ;
116151034c06Sbostic 		rp->r_wday = lp->l_value;
116251034c06Sbostic 		rp->r_dayofmonth = len_months[1][rp->r_month];
116351034c06Sbostic 	} else {
116451034c06Sbostic 		if ((cp = strchr(dayp, '<')) != 0)
116551034c06Sbostic 			rp->r_dycode = DC_DOWLEQ;
116651034c06Sbostic 		else if ((cp = strchr(dayp, '>')) != 0)
116751034c06Sbostic 			rp->r_dycode = DC_DOWGEQ;
116851034c06Sbostic 		else {
116951034c06Sbostic 			cp = dayp;
117051034c06Sbostic 			rp->r_dycode = DC_DOM;
117151034c06Sbostic 		}
117251034c06Sbostic 		if (rp->r_dycode != DC_DOM) {
117351034c06Sbostic 			*cp++ = 0;
117451034c06Sbostic 			if (*cp++ != '=') {
117551034c06Sbostic 				error("invalid day of month");
117651034c06Sbostic 				return;
117751034c06Sbostic 			}
117851034c06Sbostic 			if ((lp = byword(dayp, wday_names)) == NULL) {
117951034c06Sbostic 				error("invalid weekday name");
118051034c06Sbostic 				return;
118151034c06Sbostic 			}
118251034c06Sbostic 			rp->r_wday = lp->l_value;
118351034c06Sbostic 		}
118451034c06Sbostic 		if (sscanf(cp, scheck(cp, "%d"), &rp->r_dayofmonth) != 1 ||
118551034c06Sbostic 			rp->r_dayofmonth <= 0 ||
118651034c06Sbostic 			(rp->r_dayofmonth > len_months[1][rp->r_month])) {
118751034c06Sbostic 				error("invalid day of month");
118851034c06Sbostic 				return;
118951034c06Sbostic 		}
119051034c06Sbostic 	}
119151034c06Sbostic }
119251034c06Sbostic 
119351034c06Sbostic static void
convert(val,buf)119451034c06Sbostic convert(val, buf)
119551034c06Sbostic const long	val;
119651034c06Sbostic char * const	buf;
119751034c06Sbostic {
119851034c06Sbostic 	register int	i;
119951034c06Sbostic 	register long	shift;
120051034c06Sbostic 
120151034c06Sbostic 	for (i = 0, shift = 24; i < 4; ++i, shift -= 8)
120251034c06Sbostic 		buf[i] = val >> shift;
120351034c06Sbostic }
120451034c06Sbostic 
120551034c06Sbostic static void
puttzcode(val,fp)120651034c06Sbostic puttzcode(val, fp)
120751034c06Sbostic const long	val;
120851034c06Sbostic FILE * const	fp;
120951034c06Sbostic {
121051034c06Sbostic 	char	buf[4];
121151034c06Sbostic 
121251034c06Sbostic 	convert(val, buf);
12136068c877Sbostic 	(void) fwrite((void *) buf, (size_t) sizeof buf, (size_t) 1, fp);
121451034c06Sbostic }
121551034c06Sbostic 
121651034c06Sbostic static void
writezone(name)121751034c06Sbostic writezone(name)
121851034c06Sbostic const char * const	name;
121951034c06Sbostic {
122051034c06Sbostic 	register FILE *		fp;
122151034c06Sbostic 	register int		i, j;
122251034c06Sbostic 	char			fullname[BUFSIZ];
122351034c06Sbostic 	static struct tzhead	tzh;
122451034c06Sbostic 
122551034c06Sbostic 	if (strlen(directory) + 1 + strlen(name) >= sizeof fullname) {
122651034c06Sbostic 		(void) fprintf(stderr,
122751034c06Sbostic 			"%s: File name %s/%s too long\n", progname,
122851034c06Sbostic 			directory, name);
122951034c06Sbostic 		(void) exit(EXIT_FAILURE);
123051034c06Sbostic 	}
123151034c06Sbostic 	(void) sprintf(fullname, "%s/%s", directory, name);
123251034c06Sbostic 	if ((fp = fopen(fullname, "wb")) == NULL) {
123351034c06Sbostic 		if (mkdirs(fullname) != 0)
123451034c06Sbostic 			(void) exit(EXIT_FAILURE);
123551034c06Sbostic 		if ((fp = fopen(fullname, "wb")) == NULL) {
123651034c06Sbostic 			(void) fprintf(stderr, "%s: Can't create ", progname);
123751034c06Sbostic 			(void) perror(fullname);
123851034c06Sbostic 			(void) exit(EXIT_FAILURE);
123951034c06Sbostic 		}
124051034c06Sbostic 	}
124151034c06Sbostic 	convert(eitol(typecnt), tzh.tzh_ttisstdcnt);
124251034c06Sbostic 	convert(eitol(leapcnt), tzh.tzh_leapcnt);
124351034c06Sbostic 	convert(eitol(timecnt), tzh.tzh_timecnt);
124451034c06Sbostic 	convert(eitol(typecnt), tzh.tzh_typecnt);
124551034c06Sbostic 	convert(eitol(charcnt), tzh.tzh_charcnt);
12466068c877Sbostic 	(void) fwrite((void *) &tzh, (size_t) sizeof tzh, (size_t) 1, fp);
124751034c06Sbostic 	for (i = 0; i < timecnt; ++i) {
124851034c06Sbostic 		j = leapcnt;
124951034c06Sbostic 		while (--j >= 0)
125051034c06Sbostic 			if (ats[i] >= trans[j]) {
125151034c06Sbostic 				ats[i] = tadd(ats[i], corr[j]);
125251034c06Sbostic 				break;
125351034c06Sbostic 			}
125451034c06Sbostic 		puttzcode((long) ats[i], fp);
125551034c06Sbostic 	}
125651034c06Sbostic 	if (timecnt > 0)
12576068c877Sbostic 		(void) fwrite((void *) types, (size_t) sizeof types[0],
12586068c877Sbostic 		    (size_t) timecnt, fp);
125951034c06Sbostic 	for (i = 0; i < typecnt; ++i) {
126051034c06Sbostic 		puttzcode((long) gmtoffs[i], fp);
126151034c06Sbostic 		(void) putc(isdsts[i], fp);
126251034c06Sbostic 		(void) putc(abbrinds[i], fp);
126351034c06Sbostic 	}
126451034c06Sbostic 	if (charcnt != 0)
12656068c877Sbostic 		(void) fwrite((void *) chars, (size_t) sizeof chars[0],
12666068c877Sbostic 			(size_t) charcnt, fp);
126751034c06Sbostic 	for (i = 0; i < leapcnt; ++i) {
126851034c06Sbostic 		if (roll[i]) {
126951034c06Sbostic 			if (timecnt == 0 || trans[i] < ats[0]) {
127051034c06Sbostic 				j = 0;
127151034c06Sbostic 				while (isdsts[j])
127251034c06Sbostic 					if (++j >= typecnt) {
127351034c06Sbostic 						j = 0;
127451034c06Sbostic 						break;
127551034c06Sbostic 					}
127651034c06Sbostic 			} else {
127751034c06Sbostic 				j = 1;
127851034c06Sbostic 				while (j < timecnt && trans[i] >= ats[j])
127951034c06Sbostic 					++j;
128051034c06Sbostic 				j = types[j - 1];
128151034c06Sbostic 			}
128251034c06Sbostic 			puttzcode((long) tadd(trans[i], -gmtoffs[j]), fp);
128351034c06Sbostic 		} else	puttzcode((long) trans[i], fp);
128451034c06Sbostic 		puttzcode((long) corr[i], fp);
128551034c06Sbostic 	}
128651034c06Sbostic 	for (i = 0; i < typecnt; ++i)
128751034c06Sbostic 		(void) putc(ttisstds[i], fp);
128851034c06Sbostic 	if (ferror(fp) || fclose(fp)) {
128951034c06Sbostic 		(void) fprintf(stderr, "%s: Write error on ", progname);
129051034c06Sbostic 		(void) perror(fullname);
129151034c06Sbostic 		(void) exit(EXIT_FAILURE);
129251034c06Sbostic 	}
129351034c06Sbostic }
129451034c06Sbostic 
129551034c06Sbostic static void
outzone(zpfirst,zonecount)129651034c06Sbostic outzone(zpfirst, zonecount)
129751034c06Sbostic const struct zone * const	zpfirst;
129851034c06Sbostic const int			zonecount;
129951034c06Sbostic {
130051034c06Sbostic 	register const struct zone *	zp;
130151034c06Sbostic 	register struct rule *		rp;
130251034c06Sbostic 	register int			i, j;
130351034c06Sbostic 	register int			usestart, useuntil;
130451034c06Sbostic 	register time_t			starttime, untiltime;
130551034c06Sbostic 	register long			gmtoff;
130651034c06Sbostic 	register long			stdoff;
130751034c06Sbostic 	register int			year;
130851034c06Sbostic 	register long			startoff;
130951034c06Sbostic 	register int			startisdst;
131051034c06Sbostic 	register int			startttisstd;
131151034c06Sbostic 	register int			type;
131251034c06Sbostic 	char				startbuf[BUFSIZ];
131351034c06Sbostic 
131451034c06Sbostic 	/*
131551034c06Sbostic 	** Now. . .finally. . .generate some useful data!
131651034c06Sbostic 	*/
131751034c06Sbostic 	timecnt = 0;
131851034c06Sbostic 	typecnt = 0;
131951034c06Sbostic 	charcnt = 0;
132051034c06Sbostic 	/*
132151034c06Sbostic 	** Two guesses. . .the second may well be corrected later.
132251034c06Sbostic 	*/
132351034c06Sbostic 	gmtoff = zpfirst->z_gmtoff;
132451034c06Sbostic 	stdoff = 0;
132551034c06Sbostic 	starttime = 0;
132651034c06Sbostic 	startttisstd = FALSE;
132751034c06Sbostic 	for (i = 0; i < zonecount; ++i) {
132851034c06Sbostic 		usestart = i > 0;
132951034c06Sbostic 		useuntil = i < (zonecount - 1);
133051034c06Sbostic 		zp = &zpfirst[i];
133151034c06Sbostic 		eat(zp->z_filename, zp->z_linenum);
133251034c06Sbostic 		startisdst = -1;
133351034c06Sbostic 		if (zp->z_nrules == 0) {
133451034c06Sbostic 			type = addtype(oadd(zp->z_gmtoff, zp->z_stdoff),
133551034c06Sbostic 				zp->z_format, zp->z_stdoff != 0,
133651034c06Sbostic 				startttisstd);
133751034c06Sbostic 			if (usestart)
133851034c06Sbostic 				addtt(starttime, type);
133951034c06Sbostic 			gmtoff = zp->z_gmtoff;
134051034c06Sbostic 			stdoff = zp->z_stdoff;
134151034c06Sbostic 		} else for (year = min_year; year <= max_year; ++year) {
134251034c06Sbostic 			if (useuntil && year > zp->z_untilrule.r_hiyear)
134351034c06Sbostic 				break;
134451034c06Sbostic 			/*
134551034c06Sbostic 			** Mark which rules to do in the current year.
134651034c06Sbostic 			** For those to do, calculate rpytime(rp, year);
134751034c06Sbostic 			*/
134851034c06Sbostic 			for (j = 0; j < zp->z_nrules; ++j) {
134951034c06Sbostic 				rp = &zp->z_rules[j];
135051034c06Sbostic 				eats(zp->z_filename, zp->z_linenum,
135151034c06Sbostic 					rp->r_filename, rp->r_linenum);
135251034c06Sbostic 				rp->r_todo = year >= rp->r_loyear &&
135351034c06Sbostic 						year <= rp->r_hiyear &&
135451034c06Sbostic 						yearistype(year, rp->r_yrtype);
135551034c06Sbostic 				if (rp->r_todo)
135651034c06Sbostic 					rp->r_temp = rpytime(rp, year);
135751034c06Sbostic 			}
135851034c06Sbostic 			for ( ; ; ) {
135951034c06Sbostic 				register int	k;
136051034c06Sbostic 				register time_t	jtime, ktime;
136151034c06Sbostic 				register long	offset;
136251034c06Sbostic 				char		buf[BUFSIZ];
136351034c06Sbostic 
136451034c06Sbostic 				if (useuntil) {
136551034c06Sbostic 					/*
136651034c06Sbostic 					** Turn untiltime into GMT
136751034c06Sbostic 					** assuming the current gmtoff and
136851034c06Sbostic 					** stdoff values.
136951034c06Sbostic 					*/
137051034c06Sbostic 					offset = gmtoff;
137151034c06Sbostic 					if (!zp->z_untilrule.r_todisstd)
137251034c06Sbostic 						offset = oadd(offset, stdoff);
137351034c06Sbostic 					untiltime = tadd(zp->z_untiltime,
137451034c06Sbostic 						-offset);
137551034c06Sbostic 				}
137651034c06Sbostic 				/*
137751034c06Sbostic 				** Find the rule (of those to do, if any)
137851034c06Sbostic 				** that takes effect earliest in the year.
137951034c06Sbostic 				*/
138051034c06Sbostic 				k = -1;
138151034c06Sbostic #ifdef lint
138251034c06Sbostic 				ktime = 0;
138351034c06Sbostic #endif /* defined lint */
138451034c06Sbostic 				for (j = 0; j < zp->z_nrules; ++j) {
138551034c06Sbostic 					rp = &zp->z_rules[j];
138651034c06Sbostic 					if (!rp->r_todo)
138751034c06Sbostic 						continue;
138851034c06Sbostic 					eats(zp->z_filename, zp->z_linenum,
138951034c06Sbostic 						rp->r_filename, rp->r_linenum);
139051034c06Sbostic 					offset = gmtoff;
139151034c06Sbostic 					if (!rp->r_todisstd)
139251034c06Sbostic 						offset = oadd(offset, stdoff);
139351034c06Sbostic 					jtime = rp->r_temp;
139451034c06Sbostic 					if (jtime == min_time ||
139551034c06Sbostic 						jtime == max_time)
139651034c06Sbostic 							continue;
139751034c06Sbostic 					jtime = tadd(jtime, -offset);
139851034c06Sbostic 					if (k < 0 || jtime < ktime) {
139951034c06Sbostic 						k = j;
140051034c06Sbostic 						ktime = jtime;
140151034c06Sbostic 					}
140251034c06Sbostic 				}
140351034c06Sbostic 				if (k < 0)
140451034c06Sbostic 					break;	/* go on to next year */
140551034c06Sbostic 				rp = &zp->z_rules[k];
140651034c06Sbostic 				rp->r_todo = FALSE;
140751034c06Sbostic 				if (useuntil && ktime >= untiltime)
140851034c06Sbostic 					break;
140951034c06Sbostic 				if (usestart) {
141051034c06Sbostic 					if (ktime < starttime) {
141151034c06Sbostic 						stdoff = rp->r_stdoff;
141251034c06Sbostic 						startoff = oadd(zp->z_gmtoff,
141351034c06Sbostic 							rp->r_stdoff);
141451034c06Sbostic 						(void) sprintf(startbuf,
141551034c06Sbostic 							zp->z_format,
141651034c06Sbostic 							rp->r_abbrvar);
141751034c06Sbostic 						startisdst =
141851034c06Sbostic 							rp->r_stdoff != 0;
141951034c06Sbostic 						continue;
142051034c06Sbostic 					}
142151034c06Sbostic 					if (ktime != starttime &&
142251034c06Sbostic 						startisdst >= 0)
142351034c06Sbostic addtt(starttime, addtype(startoff, startbuf, startisdst, startttisstd));
142451034c06Sbostic 					usestart = FALSE;
142551034c06Sbostic 				}
142651034c06Sbostic 				eats(zp->z_filename, zp->z_linenum,
142751034c06Sbostic 					rp->r_filename, rp->r_linenum);
142851034c06Sbostic 				(void) sprintf(buf, zp->z_format,
142951034c06Sbostic 					rp->r_abbrvar);
143051034c06Sbostic 				offset = oadd(zp->z_gmtoff, rp->r_stdoff);
143151034c06Sbostic 				type = addtype(offset, buf, rp->r_stdoff != 0,
143251034c06Sbostic 					rp->r_todisstd);
143351034c06Sbostic 				if (timecnt != 0 || rp->r_stdoff != 0)
143451034c06Sbostic 					addtt(ktime, type);
143551034c06Sbostic 				gmtoff = zp->z_gmtoff;
143651034c06Sbostic 				stdoff = rp->r_stdoff;
143751034c06Sbostic 			}
143851034c06Sbostic 		}
143951034c06Sbostic 		/*
144051034c06Sbostic 		** Now we may get to set starttime for the next zone line.
144151034c06Sbostic 		*/
144251034c06Sbostic 		if (useuntil) {
144351034c06Sbostic 			starttime = tadd(zp->z_untiltime,
144451034c06Sbostic 				-gmtoffs[types[timecnt - 1]]);
144551034c06Sbostic 			startttisstd = zp->z_untilrule.r_todisstd;
144651034c06Sbostic 		}
144751034c06Sbostic 	}
144851034c06Sbostic 	writezone(zpfirst->z_name);
144951034c06Sbostic }
145051034c06Sbostic 
145151034c06Sbostic static void
addtt(starttime,type)145251034c06Sbostic addtt(starttime, type)
145351034c06Sbostic const time_t	starttime;
145451034c06Sbostic const int	type;
145551034c06Sbostic {
145651034c06Sbostic 	if (timecnt != 0 && type == types[timecnt - 1])
145751034c06Sbostic 		return;	/* easy enough! */
145851034c06Sbostic 	if (timecnt >= TZ_MAX_TIMES) {
145951034c06Sbostic 		error("too many transitions?!");
146051034c06Sbostic 		(void) exit(EXIT_FAILURE);
146151034c06Sbostic 	}
146251034c06Sbostic 	ats[timecnt] = starttime;
146351034c06Sbostic 	types[timecnt] = type;
146451034c06Sbostic 	++timecnt;
146551034c06Sbostic }
146651034c06Sbostic 
146751034c06Sbostic static int
addtype(gmtoff,abbr,isdst,ttisstd)146851034c06Sbostic addtype(gmtoff, abbr, isdst, ttisstd)
146951034c06Sbostic const long		gmtoff;
147051034c06Sbostic const char * const	abbr;
147151034c06Sbostic const int		isdst;
147251034c06Sbostic const int		ttisstd;
147351034c06Sbostic {
147451034c06Sbostic 	register int	i, j;
147551034c06Sbostic 
147651034c06Sbostic 	/*
147751034c06Sbostic 	** See if there's already an entry for this zone type.
147851034c06Sbostic 	** If so, just return its index.
147951034c06Sbostic 	*/
148051034c06Sbostic 	for (i = 0; i < typecnt; ++i) {
148151034c06Sbostic 		if (gmtoff == gmtoffs[i] && isdst == isdsts[i] &&
148251034c06Sbostic 			strcmp(abbr, &chars[abbrinds[i]]) == 0 &&
148351034c06Sbostic 			ttisstd == ttisstds[i])
148451034c06Sbostic 				return i;
148551034c06Sbostic 	}
148651034c06Sbostic 	/*
148751034c06Sbostic 	** There isn't one; add a new one, unless there are already too
148851034c06Sbostic 	** many.
148951034c06Sbostic 	*/
149051034c06Sbostic 	if (typecnt >= TZ_MAX_TYPES) {
149151034c06Sbostic 		error("too many local time types");
149251034c06Sbostic 		(void) exit(EXIT_FAILURE);
149351034c06Sbostic 	}
149451034c06Sbostic 	gmtoffs[i] = gmtoff;
149551034c06Sbostic 	isdsts[i] = isdst;
149651034c06Sbostic 	ttisstds[i] = ttisstd;
149751034c06Sbostic 
149851034c06Sbostic 	for (j = 0; j < charcnt; ++j)
149951034c06Sbostic 		if (strcmp(&chars[j], abbr) == 0)
150051034c06Sbostic 			break;
150151034c06Sbostic 	if (j == charcnt)
150251034c06Sbostic 		newabbr(abbr);
150351034c06Sbostic 	abbrinds[i] = j;
150451034c06Sbostic 	++typecnt;
150551034c06Sbostic 	return i;
150651034c06Sbostic }
150751034c06Sbostic 
150851034c06Sbostic static void
addleap(t,positive,rolling)150951034c06Sbostic addleap(t, positive, rolling)
151051034c06Sbostic const time_t	t;
151151034c06Sbostic const int	positive;
151251034c06Sbostic const int	rolling;
151351034c06Sbostic {
151451034c06Sbostic 	register int	i, j;
151551034c06Sbostic 
151651034c06Sbostic 	if (leapcnt >= TZ_MAX_LEAPS) {
151751034c06Sbostic 		error("too many leap seconds");
151851034c06Sbostic 		(void) exit(EXIT_FAILURE);
151951034c06Sbostic 	}
152051034c06Sbostic 	for (i = 0; i < leapcnt; ++i)
152151034c06Sbostic 		if (t <= trans[i]) {
152251034c06Sbostic 			if (t == trans[i]) {
152351034c06Sbostic 				error("repeated leap second moment");
152451034c06Sbostic 				(void) exit(EXIT_FAILURE);
152551034c06Sbostic 			}
152651034c06Sbostic 			break;
152751034c06Sbostic 		}
152851034c06Sbostic 	for (j = leapcnt; j > i; --j) {
152951034c06Sbostic 		trans[j] = trans[j-1];
153051034c06Sbostic 		corr[j] = corr[j-1];
153151034c06Sbostic 		roll[j] = roll[j-1];
153251034c06Sbostic 	}
153351034c06Sbostic 	trans[i] = t;
153451034c06Sbostic 	corr[i] = (positive ? 1L : -1L);
153551034c06Sbostic 	roll[i] = rolling;
153651034c06Sbostic 	++leapcnt;
153751034c06Sbostic }
153851034c06Sbostic 
153951034c06Sbostic static void
adjleap()154051034c06Sbostic adjleap()
154151034c06Sbostic {
154251034c06Sbostic 	register int	i;
154351034c06Sbostic 	register long	last = 0;
154451034c06Sbostic 
154551034c06Sbostic 	/*
154651034c06Sbostic 	** propagate leap seconds forward
154751034c06Sbostic 	*/
154851034c06Sbostic 	for (i = 0; i < leapcnt; ++i) {
154951034c06Sbostic 		trans[i] = tadd(trans[i], last);
155051034c06Sbostic 		last = corr[i] += last;
155151034c06Sbostic 	}
155251034c06Sbostic }
155351034c06Sbostic 
155451034c06Sbostic static int
yearistype(year,type)155551034c06Sbostic yearistype(year, type)
155651034c06Sbostic const int		year;
155751034c06Sbostic const char * const	type;
155851034c06Sbostic {
155951034c06Sbostic 	char	buf[BUFSIZ];
156051034c06Sbostic 	int	result;
156151034c06Sbostic 
156251034c06Sbostic 	if (type == NULL || *type == '\0')
156351034c06Sbostic 		return TRUE;
156451034c06Sbostic 	if (strcmp(type, "uspres") == 0)
156551034c06Sbostic 		return (year % 4) == 0;
156651034c06Sbostic 	if (strcmp(type, "nonpres") == 0)
156751034c06Sbostic 		return (year % 4) != 0;
156851034c06Sbostic 	(void) sprintf(buf, "yearistype %d %s", year, type);
156951034c06Sbostic 	result = system(buf);
157051034c06Sbostic 	if (result == 0)
157151034c06Sbostic 		return TRUE;
157251034c06Sbostic 	if (result == (1 << 8))
157351034c06Sbostic 		return FALSE;
157451034c06Sbostic 	error("Wild result from command execution");
157551034c06Sbostic 	(void) fprintf(stderr, "%s: command was '%s', result was %d\n",
157651034c06Sbostic 		progname, buf, result);
157751034c06Sbostic 	for ( ; ; )
157851034c06Sbostic 		(void) exit(EXIT_FAILURE);
157951034c06Sbostic }
158051034c06Sbostic 
158151034c06Sbostic static int
lowerit(a)158251034c06Sbostic lowerit(a)
158351034c06Sbostic const int	a;
158451034c06Sbostic {
158551034c06Sbostic 	return (isascii(a) && isupper(a)) ? tolower(a) : a;
158651034c06Sbostic }
158751034c06Sbostic 
158851034c06Sbostic static int
ciequal(ap,bp)158951034c06Sbostic ciequal(ap, bp)		/* case-insensitive equality */
159051034c06Sbostic register const char *	ap;
159151034c06Sbostic register const char *	bp;
159251034c06Sbostic {
159351034c06Sbostic 	while (lowerit(*ap) == lowerit(*bp++))
159451034c06Sbostic 		if (*ap++ == '\0')
159551034c06Sbostic 			return TRUE;
159651034c06Sbostic 	return FALSE;
159751034c06Sbostic }
159851034c06Sbostic 
159951034c06Sbostic static int
itsabbr(abbr,word)160051034c06Sbostic itsabbr(abbr, word)
160151034c06Sbostic register const char *	abbr;
160251034c06Sbostic register const char *	word;
160351034c06Sbostic {
160451034c06Sbostic 	if (lowerit(*abbr) != lowerit(*word))
160551034c06Sbostic 		return FALSE;
160651034c06Sbostic 	++word;
160751034c06Sbostic 	while (*++abbr != '\0')
160851034c06Sbostic 		do if (*word == '\0')
160951034c06Sbostic 			return FALSE;
161051034c06Sbostic 				while (lowerit(*word++) != lowerit(*abbr));
161151034c06Sbostic 	return TRUE;
161251034c06Sbostic }
161351034c06Sbostic 
161451034c06Sbostic static const struct lookup *
byword(word,table)161551034c06Sbostic byword(word, table)
161651034c06Sbostic register const char * const		word;
161751034c06Sbostic register const struct lookup * const	table;
161851034c06Sbostic {
161951034c06Sbostic 	register const struct lookup *	foundlp;
162051034c06Sbostic 	register const struct lookup *	lp;
162151034c06Sbostic 
162251034c06Sbostic 	if (word == NULL || table == NULL)
162351034c06Sbostic 		return NULL;
162451034c06Sbostic 	/*
162551034c06Sbostic 	** Look for exact match.
162651034c06Sbostic 	*/
162751034c06Sbostic 	for (lp = table; lp->l_word != NULL; ++lp)
162851034c06Sbostic 		if (ciequal(word, lp->l_word))
162951034c06Sbostic 			return lp;
163051034c06Sbostic 	/*
163151034c06Sbostic 	** Look for inexact match.
163251034c06Sbostic 	*/
163351034c06Sbostic 	foundlp = NULL;
163451034c06Sbostic 	for (lp = table; lp->l_word != NULL; ++lp)
163551034c06Sbostic 		if (itsabbr(word, lp->l_word))
163651034c06Sbostic 			if (foundlp == NULL)
163751034c06Sbostic 				foundlp = lp;
163851034c06Sbostic 			else	return NULL;	/* multiple inexact matches */
163951034c06Sbostic 	return foundlp;
164051034c06Sbostic }
164151034c06Sbostic 
164251034c06Sbostic static char **
getfields(cp)164351034c06Sbostic getfields(cp)
164451034c06Sbostic register char *	cp;
164551034c06Sbostic {
164651034c06Sbostic 	register char *		dp;
164751034c06Sbostic 	register char **	array;
164851034c06Sbostic 	register int		nsubs;
164951034c06Sbostic 
165051034c06Sbostic 	if (cp == NULL)
165151034c06Sbostic 		return NULL;
165251034c06Sbostic 	array = (char **) emalloc((int) ((strlen(cp) + 1) * sizeof *array));
165351034c06Sbostic 	nsubs = 0;
165451034c06Sbostic 	for ( ; ; ) {
165551034c06Sbostic 		while (isascii(*cp) && isspace(*cp))
165651034c06Sbostic 			++cp;
165751034c06Sbostic 		if (*cp == '\0' || *cp == '#')
165851034c06Sbostic 			break;
165951034c06Sbostic 		array[nsubs++] = dp = cp;
166051034c06Sbostic 		do {
166151034c06Sbostic 			if ((*dp = *cp++) != '"')
166251034c06Sbostic 				++dp;
166351034c06Sbostic 			else while ((*dp = *cp++) != '"')
166451034c06Sbostic 				if (*dp != '\0')
166551034c06Sbostic 					++dp;
166651034c06Sbostic 				else	error("Odd number of quotation marks");
166751034c06Sbostic 		} while (*cp != '\0' && *cp != '#' &&
166851034c06Sbostic 			(!isascii(*cp) || !isspace(*cp)));
166951034c06Sbostic 		if (isascii(*cp) && isspace(*cp))
167051034c06Sbostic 			++cp;
167151034c06Sbostic 		*dp = '\0';
167251034c06Sbostic 	}
167351034c06Sbostic 	array[nsubs] = NULL;
167451034c06Sbostic 	return array;
167551034c06Sbostic }
167651034c06Sbostic 
167751034c06Sbostic static long
oadd(t1,t2)167851034c06Sbostic oadd(t1, t2)
167951034c06Sbostic const long	t1;
168051034c06Sbostic const long	t2;
168151034c06Sbostic {
168251034c06Sbostic 	register long	t;
168351034c06Sbostic 
168451034c06Sbostic 	t = t1 + t2;
168551034c06Sbostic 	if (t2 > 0 && t <= t1 || t2 < 0 && t >= t1) {
168651034c06Sbostic 		error("time overflow");
168751034c06Sbostic 		(void) exit(EXIT_FAILURE);
168851034c06Sbostic 	}
168951034c06Sbostic 	return t;
169051034c06Sbostic }
169151034c06Sbostic 
169251034c06Sbostic static time_t
tadd(t1,t2)169351034c06Sbostic tadd(t1, t2)
169451034c06Sbostic const time_t	t1;
169551034c06Sbostic const long	t2;
169651034c06Sbostic {
169751034c06Sbostic 	register time_t	t;
169851034c06Sbostic 
169951034c06Sbostic 	if (t1 == max_time && t2 > 0)
170051034c06Sbostic 		return max_time;
170151034c06Sbostic 	if (t1 == min_time && t2 < 0)
170251034c06Sbostic 		return min_time;
170351034c06Sbostic 	t = t1 + t2;
170451034c06Sbostic 	if (t2 > 0 && t <= t1 || t2 < 0 && t >= t1) {
170551034c06Sbostic 		error("time overflow");
170651034c06Sbostic 		(void) exit(EXIT_FAILURE);
170751034c06Sbostic 	}
170851034c06Sbostic 	return t;
170951034c06Sbostic }
171051034c06Sbostic 
171151034c06Sbostic /*
171251034c06Sbostic ** Given a rule, and a year, compute the date - in seconds since January 1,
171351034c06Sbostic ** 1970, 00:00 LOCAL time - in that year that the rule refers to.
171451034c06Sbostic */
171551034c06Sbostic 
171651034c06Sbostic static time_t
rpytime(rp,wantedy)171751034c06Sbostic rpytime(rp, wantedy)
171851034c06Sbostic register const struct rule * const	rp;
171951034c06Sbostic register const int			wantedy;
172051034c06Sbostic {
172151034c06Sbostic 	register int	y, m, i;
172251034c06Sbostic 	register long	dayoff;			/* with a nod to Margaret O. */
172351034c06Sbostic 	register time_t	t;
172451034c06Sbostic 
172551034c06Sbostic 	dayoff = 0;
172651034c06Sbostic 	m = TM_JANUARY;
172751034c06Sbostic 	y = EPOCH_YEAR;
172851034c06Sbostic 	while (wantedy != y) {
172951034c06Sbostic 		if (wantedy > y) {
173051034c06Sbostic 			i = len_years[isleap(y)];
173151034c06Sbostic 			++y;
173251034c06Sbostic 		} else {
173351034c06Sbostic 			--y;
173451034c06Sbostic 			i = -len_years[isleap(y)];
173551034c06Sbostic 		}
173651034c06Sbostic 		dayoff = oadd(dayoff, eitol(i));
173751034c06Sbostic 	}
173851034c06Sbostic 	while (m != rp->r_month) {
173951034c06Sbostic 		i = len_months[isleap(y)][m];
174051034c06Sbostic 		dayoff = oadd(dayoff, eitol(i));
174151034c06Sbostic 		++m;
174251034c06Sbostic 	}
174351034c06Sbostic 	i = rp->r_dayofmonth;
174451034c06Sbostic 	if (m == TM_FEBRUARY && i == 29 && !isleap(y)) {
174551034c06Sbostic 		if (rp->r_dycode == DC_DOWLEQ)
174651034c06Sbostic 			--i;
174751034c06Sbostic 		else {
174851034c06Sbostic 			error("use of 2/29 in non leap-year");
174951034c06Sbostic 			(void) exit(EXIT_FAILURE);
175051034c06Sbostic 		}
175151034c06Sbostic 	}
175251034c06Sbostic 	--i;
175351034c06Sbostic 	dayoff = oadd(dayoff, eitol(i));
175451034c06Sbostic 	if (rp->r_dycode == DC_DOWGEQ || rp->r_dycode == DC_DOWLEQ) {
175551034c06Sbostic 		register long	wday;
175651034c06Sbostic 
175751034c06Sbostic #define LDAYSPERWEEK	((long) DAYSPERWEEK)
175851034c06Sbostic 		wday = eitol(EPOCH_WDAY);
175951034c06Sbostic 		/*
176051034c06Sbostic 		** Don't trust mod of negative numbers.
176151034c06Sbostic 		*/
176251034c06Sbostic 		if (dayoff >= 0)
176351034c06Sbostic 			wday = (wday + dayoff) % LDAYSPERWEEK;
176451034c06Sbostic 		else {
176551034c06Sbostic 			wday -= ((-dayoff) % LDAYSPERWEEK);
176651034c06Sbostic 			if (wday < 0)
176751034c06Sbostic 				wday += LDAYSPERWEEK;
176851034c06Sbostic 		}
176951034c06Sbostic 		while (wday != eitol(rp->r_wday))
177051034c06Sbostic 			if (rp->r_dycode == DC_DOWGEQ) {
177151034c06Sbostic 				dayoff = oadd(dayoff, (long) 1);
177251034c06Sbostic 				if (++wday >= LDAYSPERWEEK)
177351034c06Sbostic 					wday = 0;
177451034c06Sbostic 				++i;
177551034c06Sbostic 			} else {
177651034c06Sbostic 				dayoff = oadd(dayoff, (long) -1);
177751034c06Sbostic 				if (--wday < 0)
17783044ec37Sbostic 					wday = LDAYSPERWEEK - 1;
177951034c06Sbostic 				--i;
178051034c06Sbostic 			}
178151034c06Sbostic 		if (i < 0 || i >= len_months[isleap(y)][m]) {
178251034c06Sbostic 			error("no day in month matches rule");
178351034c06Sbostic 			(void) exit(EXIT_FAILURE);
178451034c06Sbostic 		}
178551034c06Sbostic 	}
178651034c06Sbostic 	if (dayoff < 0 && !tt_signed) {
178751034c06Sbostic 		if (wantedy == rp->r_loyear)
178851034c06Sbostic 			return min_time;
178951034c06Sbostic 		error("time before zero");
179051034c06Sbostic 		(void) exit(EXIT_FAILURE);
179151034c06Sbostic 	}
179251034c06Sbostic 	t = (time_t) dayoff * SECSPERDAY;
179351034c06Sbostic 	/*
179451034c06Sbostic 	** Cheap overflow check.
179551034c06Sbostic 	*/
179651034c06Sbostic 	if (t / SECSPERDAY != dayoff) {
179751034c06Sbostic 		if (wantedy == rp->r_hiyear)
179851034c06Sbostic 			return max_time;
179951034c06Sbostic 		if (wantedy == rp->r_loyear)
180051034c06Sbostic 			return min_time;
180151034c06Sbostic 		error("time overflow");
180251034c06Sbostic 		(void) exit(EXIT_FAILURE);
180351034c06Sbostic 	}
180451034c06Sbostic 	return tadd(t, rp->r_tod);
180551034c06Sbostic }
180651034c06Sbostic 
180751034c06Sbostic static void
newabbr(string)180851034c06Sbostic newabbr(string)
180951034c06Sbostic const char * const	string;
181051034c06Sbostic {
181151034c06Sbostic 	register int	i;
181251034c06Sbostic 
181351034c06Sbostic 	i = strlen(string) + 1;
181451034c06Sbostic 	if (charcnt + i >= TZ_MAX_CHARS) {
181551034c06Sbostic 		error("too many, or too long, time zone abbreviations");
181651034c06Sbostic 		(void) exit(EXIT_FAILURE);
181751034c06Sbostic 	}
181851034c06Sbostic 	(void) strcpy(&chars[charcnt], string);
181951034c06Sbostic 	charcnt += eitol(i);
182051034c06Sbostic }
182151034c06Sbostic 
182251034c06Sbostic static int
mkdirs(name)182351034c06Sbostic mkdirs(name)
182451034c06Sbostic char * const	name;
182551034c06Sbostic {
182651034c06Sbostic 	register char *	cp;
182751034c06Sbostic 
182851034c06Sbostic 	if ((cp = name) == NULL || *cp == '\0')
182951034c06Sbostic 		return 0;
183051034c06Sbostic 	while ((cp = strchr(cp + 1, '/')) != 0) {
183151034c06Sbostic 		*cp = '\0';
183251034c06Sbostic 		if (!itsdir(name)) {
183351034c06Sbostic 			/*
183451034c06Sbostic 			** It doesn't seem to exist, so we try to create it.
183551034c06Sbostic 			*/
18366068c877Sbostic 			if (mkdir(name, 0755) != 0) {
183751034c06Sbostic 				(void) fprintf(stderr,
183851034c06Sbostic 					"%s: Can't create directory ",
183951034c06Sbostic 					progname);
184051034c06Sbostic 				(void) perror(name);
184151034c06Sbostic 				return -1;
184251034c06Sbostic 			}
184351034c06Sbostic 		}
184451034c06Sbostic 		*cp = '/';
184551034c06Sbostic 	}
184651034c06Sbostic 	return 0;
184751034c06Sbostic }
184851034c06Sbostic 
184951034c06Sbostic static long
eitol(i)185051034c06Sbostic eitol(i)
185151034c06Sbostic const int	i;
185251034c06Sbostic {
185351034c06Sbostic 	long	l;
185451034c06Sbostic 
185551034c06Sbostic 	l = i;
185651034c06Sbostic 	if (i < 0 && l >= 0 || i == 0 && l != 0 || i > 0 && l <= 0) {
185751034c06Sbostic 		(void) fprintf(stderr, "%s: %d did not sign extend correctly\n",
185851034c06Sbostic 			progname, i);
185951034c06Sbostic 		(void) exit(EXIT_FAILURE);
186051034c06Sbostic 	}
186151034c06Sbostic 	return l;
186251034c06Sbostic }
186351034c06Sbostic 
186451034c06Sbostic /*
186551034c06Sbostic ** UNIX is a registered trademark of AT&T.
186651034c06Sbostic */
1867