File:  [DragonFly] / src / usr.sbin / zic / zic.c
Revision 1.3: download - view: text, annotated - select for diffs
Sun Feb 29 16:55:28 2004 UTC (10 years, 1 month ago) by joerg
Branches: MAIN
CVS tags: HEAD
De-K&R-ify function prototyps and remove register keyword.

Submitted by Chris Pressey <cpressey@catseye.mine.nu>

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