zic.c

来自「一个C源代码分析器」· C语言 代码 · 共 1,940 行 · 第 1/3 页

C
1,940
字号
			(fwrite_size_t) timecnt, fp);	for (i = 0; i < typecnt; ++i) {		puttzcode((long) gmtoffs[i], fp);		(void) putc(isdsts[i], fp);		(void) putc(abbrinds[i], fp);	}	if (charcnt != 0)		(void) fwrite((genericptr_t) chars,			(fwrite_size_t) sizeof chars[0],			(fwrite_size_t) charcnt, fp);	for (i = 0; i < leapcnt; ++i) {		if (roll[i]) {			if (timecnt == 0 || trans[i] < ats[0]) {				j = 0;				while (isdsts[j])					if (++j >= typecnt) {						j = 0;						break;					}			} else {				j = 1;				while (j < timecnt && trans[i] >= ats[j])					++j;				j = types[j - 1];			}			puttzcode((long) tadd(trans[i], -gmtoffs[j]), fp);		} else	puttzcode((long) trans[i], fp);		puttzcode((long) corr[i], fp);	}	for (i = 0; i < typecnt; ++i)		(void) putc(ttisstds[i], fp);	if (ferror(fp) || fclose(fp)) {		(void) fprintf(stderr, "%s: Write error on ", progname);		(void) perror(fullname);		(void) exit(EXIT_FAILURE);	}}static voidoutzone(zpfirst, zonecount)const struct zone * const	zpfirst;const int			zonecount;{	register const struct zone *	zp;	register struct rule *		rp;	register int			i, j;	register int			usestart, useuntil;	register time_t			starttime, untiltime;	register long			gmtoff;	register long			stdoff;	register int			year;	register long			startoff;	register int			startisdst;	register int			startttisstd;	register int			type;	char				startbuf[BUFSIZ];	/*	** Now. . .finally. . .generate some useful data!	*/	timecnt = 0;	typecnt = 0;	charcnt = 0;	/*	** A guess that may well be corrected later.	*/	stdoff = 0;	/*	** Thanks to Earl Chew (earl@dnd.icp.nec.com.au)	** for noting the need to unconditionally initialize startttisstd.	*/	startttisstd = FALSE;#ifdef lint	starttime = 0;#endif /* defined lint */	for (i = 0; i < zonecount; ++i) {		zp = &zpfirst[i];		usestart = i > 0 && (zp - 1)->z_untiltime > min_time;		useuntil = i < (zonecount - 1);		if (useuntil && zp->z_untiltime <= min_time)			continue;		gmtoff = zp->z_gmtoff;		eat(zp->z_filename, zp->z_linenum);		startisdst = -1;		if (zp->z_nrules == 0) {			stdoff = zp->z_stdoff;			(void) strcpy(startbuf, zp->z_format);			type = addtype(oadd(zp->z_gmtoff, stdoff),				startbuf, stdoff != 0, startttisstd);			if (usestart)				addtt(starttime, type);			else if (stdoff != 0)				addtt(min_time, type);		} else for (year = min_year; year <= max_year; ++year) {			if (useuntil && year > zp->z_untilrule.r_hiyear)				break;			/*			** Mark which rules to do in the current year.			** For those to do, calculate rpytime(rp, year);			*/			for (j = 0; j < zp->z_nrules; ++j) {				rp = &zp->z_rules[j];				eats(zp->z_filename, zp->z_linenum,					rp->r_filename, rp->r_linenum);				rp->r_todo = year >= rp->r_loyear &&						year <= rp->r_hiyear &&						yearistype(year, rp->r_yrtype);				if (rp->r_todo)					rp->r_temp = rpytime(rp, year);			}			for ( ; ; ) {				register int	k;				register time_t	jtime, ktime;				register long	offset;				char		buf[BUFSIZ];				if (useuntil) {					/*					** Turn untiltime into GMT					** assuming the current gmtoff and					** stdoff values.					*/					untiltime = tadd(zp->z_untiltime,						-gmtoff);					if (!zp->z_untilrule.r_todisstd)						untiltime = tadd(untiltime,							-stdoff);				}				/*				** Find the rule (of those to do, if any)				** that takes effect earliest in the year.				*/				k = -1;#ifdef lint				ktime = 0;#endif /* defined lint */				for (j = 0; j < zp->z_nrules; ++j) {					rp = &zp->z_rules[j];					if (!rp->r_todo)						continue;					eats(zp->z_filename, zp->z_linenum,						rp->r_filename, rp->r_linenum);					offset = gmtoff;					if (!rp->r_todisstd)						offset = oadd(offset, stdoff);					jtime = rp->r_temp;					if (jtime == min_time ||						jtime == max_time)							continue;					jtime = tadd(jtime, -offset);					if (k < 0 || jtime < ktime) {						k = j;						ktime = jtime;					}				}				if (k < 0)					break;	/* go on to next year */				rp = &zp->z_rules[k];				rp->r_todo = FALSE;				if (useuntil && ktime >= untiltime)					break;				if (usestart) {				    if (ktime < starttime) {					stdoff = rp->r_stdoff;					startoff = oadd(zp->z_gmtoff,						rp->r_stdoff);					(void) sprintf(startbuf, zp->z_format,						rp->r_abbrvar);					startisdst = rp->r_stdoff != 0;					continue;				    }				    usestart = FALSE;				    if (ktime != starttime) {					if (startisdst < 0 &&					    zp->z_gmtoff !=					    (zp - 1)->z_gmtoff) {						type = (timecnt == 0) ? 0 :							types[timecnt - 1];						startoff = oadd(gmtoffs[type],							-(zp - 1)->z_gmtoff);						startisdst = startoff != 0;						startoff = oadd(startoff,							zp->z_gmtoff);						(void) strcpy(startbuf,							&chars[abbrinds[type]]);					}					if (startisdst >= 0)addtt(starttime, addtype(startoff, startbuf, startisdst, startttisstd));				    }				}				eats(zp->z_filename, zp->z_linenum,					rp->r_filename, rp->r_linenum);				(void) sprintf(buf, zp->z_format,					rp->r_abbrvar);				offset = oadd(zp->z_gmtoff, rp->r_stdoff);				type = addtype(offset, buf, rp->r_stdoff != 0,					rp->r_todisstd);				addtt(ktime, type);				stdoff = rp->r_stdoff;			}		}		/*		** Now we may get to set starttime for the next zone line.		*/		if (useuntil) {			starttime = tadd(zp->z_untiltime, -gmtoff);			startttisstd = zp->z_untilrule.r_todisstd;			if (!startttisstd)				starttime = tadd(starttime, -stdoff);		}	}	writezone(zpfirst->z_name);}static voidaddtt(starttime, type)const time_t	starttime;const int	type;{	if (timecnt != 0 && type == types[timecnt - 1])		return;	/* easy enough! */	if (timecnt == 0 && type == 0 && isdsts[0] == 0)		return; /* handled by default rule */	if (timecnt >= TZ_MAX_TIMES) {		error("too many transitions?!");		(void) exit(EXIT_FAILURE);	}	ats[timecnt] = starttime;	types[timecnt] = type;	++timecnt;}static intaddtype(gmtoff, abbr, isdst, ttisstd)const long		gmtoff;const char * const	abbr;const int		isdst;const int		ttisstd;{	register int	i, j;	/*	** See if there's already an entry for this zone type.	** If so, just return its index.	*/	for (i = 0; i < typecnt; ++i) {		if (gmtoff == gmtoffs[i] && isdst == isdsts[i] &&			strcmp(abbr, &chars[abbrinds[i]]) == 0 &&			ttisstd == ttisstds[i])				return i;	}	/*	** There isn't one; add a new one, unless there are already too	** many.	*/	if (typecnt >= TZ_MAX_TYPES) {		error("too many local time types");		(void) exit(EXIT_FAILURE);	}	gmtoffs[i] = gmtoff;	isdsts[i] = isdst;	ttisstds[i] = ttisstd;	for (j = 0; j < charcnt; ++j)		if (strcmp(&chars[j], abbr) == 0)			break;	if (j == charcnt)		newabbr(abbr);	abbrinds[i] = j;	++typecnt;	return i;}static voidleapadd(t, positive, rolling, count)const time_t	t;const int	positive;const int	rolling;int		count;{	register int	i, j;	if (leapcnt + (positive ? count : 1) > TZ_MAX_LEAPS) {		error("too many leap seconds");		(void) exit(EXIT_FAILURE);	}	for (i = 0; i < leapcnt; ++i)		if (t <= trans[i]) {			if (t == trans[i]) {				error("repeated leap second moment");				(void) exit(EXIT_FAILURE);			}			break;		}	do {		for (j = leapcnt; j > i; --j) {			trans[j] = trans[j - 1];			corr[j] = corr[j - 1];			roll[j] = roll[j - 1];		}		trans[i] = t;		corr[i] = positive ? 1L : eitol(-count);		roll[i] = rolling;		++leapcnt;	} while (positive && --count != 0);}static voidadjleap(){	register int	i;	register long	last = 0;	/*	** propagate leap seconds forward	*/	for (i = 0; i < leapcnt; ++i) {		trans[i] = tadd(trans[i], last);		last = corr[i] += last;	}}static intyearistype(year, type)const int		year;const char * const	type;{	static char *	buf;	int		result;	if (type == NULL || *type == '\0')		return TRUE;	if (strcmp(type, "uspres") == 0)		return (year % 4) == 0;	if (strcmp(type, "nonpres") == 0)		return (year % 4) != 0;	buf = erealloc(buf, 132 + strlen(yitcommand) + strlen(type));	(void) sprintf(buf, "%s %d %s", yitcommand, year, type);	result = system(buf);	if (result == 0)		return TRUE;	if (result == (1 << 8))		return FALSE;	error("Wild result from command execution");	(void) fprintf(stderr, "%s: command was '%s', result was %d\n",		progname, buf, result);	for ( ; ; )		(void) exit(EXIT_FAILURE);}static intlowerit(a)const int	a;{	return (isascii(a) && isupper(a)) ? tolower(a) : a;}static intciequal(ap, bp)		/* case-insensitive equality */register const char *	ap;register const char *	bp;{	while (lowerit(*ap) == lowerit(*bp++))		if (*ap++ == '\0')			return TRUE;	return FALSE;}static intitsabbr(abbr, word)register const char *	abbr;register const char *	word;{	if (lowerit(*abbr) != lowerit(*word))		return FALSE;	++word;	while (*++abbr != '\0')		do if (*word == '\0')			return FALSE;				while (lowerit(*word++) != lowerit(*abbr));	return TRUE;}static const struct lookup *byword(word, table)register const char * const		word;register const struct lookup * const	table;{	register const struct lookup *	foundlp;	register const struct lookup *	lp;	if (word == NULL || table == NULL)		return NULL;	/*	** Look for exact match.	*/	for (lp = table; lp->l_word != NULL; ++lp)		if (ciequal(word, lp->l_word))			return lp;	/*	** Look for inexact match.	*/	foundlp = NULL;	for (lp = table; lp->l_word != NULL; ++lp)		if (itsabbr(word, lp->l_word))			if (foundlp == NULL)				foundlp = lp;			else	return NULL;	/* multiple inexact matches */	return foundlp;}static char **getfields(cp)register char *	cp;{	register char *		dp;	register char **	array;	register int		nsubs;	if (cp == NULL)		return NULL;	array = (char **) emalloc((int) ((strlen(cp) + 1) * sizeof *array));	nsubs = 0;	for ( ; ; ) {		while (isascii(*cp) && isspace(*cp))			++cp;		if (*cp == '\0' || *cp == '#')			break;		array[nsubs++] = dp = cp;		do {			if ((*dp = *cp++) != '"')				++dp;			else while ((*dp = *cp++) != '"')				if (*dp != '\0')					++dp;				else	error("Odd number of quotation marks");		} while (*cp != '\0' && *cp != '#' &&			(!isascii(*cp) || !isspace(*cp)));		if (isascii(*cp) && isspace(*cp))			++cp;		*dp = '\0';	}	array[nsubs] = NULL;	return array;}static longoadd(t1, t2)const long	t1;const long	t2;{	register long	t;	t = t1 + t2;	if ((t2 > 0 && t <= t1) || (t2 < 0 && t >= t1)) {		error("time overflow");		(void) exit(EXIT_FAILURE);	}	return t;}static time_ttadd(t1, t2)const time_t	t1;const long	t2;{	register time_t	t;	if (t1 == max_time && t2 > 0)		return max_time;	if (t1 == min_time && t2 < 0)		return min_time;	t = t1 + t2;	if ((t2 > 0 && t <= t1) || (t2 < 0 && t >= t1)) {		error("time overflow");		(void) exit(EXIT_FAILURE);	}	return t;}/*** Given a rule, and a year, compute the date - in seconds since January 1,** 1970, 00:00 LOCAL time - in that year that the rule refers to.*/static time_trpytime(rp, wantedy)register const struct rule * const	rp;register const int			wantedy;{	register int	y, m, i;	register long	dayoff;			/* with a nod to Margaret O. */	register time_t	t;	if (wantedy == min_int)		return min_time;	if (wantedy == max_int)		return max_time;	dayoff = 0;	m = TM_JANUARY;	y = EPOCH_YEAR;	while (wantedy != y) {		if (wantedy > y) {			i = len_years[isleap(y)];			++y;		} else {			--y;			i = -len_years[isleap(y)];		}		dayoff = oadd(dayoff, eitol(i));	}	while (m != rp->r_month) {		i = len_months[isleap(y)][m];		dayoff = oadd(dayoff, eitol(i));		++m;	}	i = rp->r_dayofmonth;	if (m == TM_FEBRUARY && i == 29 && !isleap(y)) {		if (rp->r_dycode == DC_DOWLEQ)			--i;		else {			error("use of 2/29 in non leap-year");			(void) exit(EXIT_FAILURE);		}	}	--i;	dayoff = oadd(dayoff, eitol(i));	if (rp->r_dycode == DC_DOWGEQ || rp->r_dycode == DC_DOWLEQ) {		register long	wday;#define LDAYSPERWEEK	((long) DAYSPERWEEK)		wday = eitol(EPOCH_WDAY);		/*		** Don't trust mod of negative numbers.		*/		if (dayoff >= 0)			wday = (wday + dayoff) % LDAYSPERWEEK;		else {			wday -= ((-dayoff) % LDAYSPERWEEK);			if (wday < 0)				wday += LDAYSPERWEEK;		}		while (wday != eitol(rp->r_wday))			if (rp->r_dycode == DC_DOWGEQ) {				dayoff = oadd(dayoff, (long) 1);				if (++wday >= LDAYSPERWEEK)					wday = 0;				++i;			} else {				dayoff = oadd(dayoff, (long) -1);				if (--wday < 0)					wday = LDAYSPERWEEK - 1;				--i;			}		if (i < 0 || i >= len_months[isleap(y)][m]) {			error("no day in month matches rule");			(void) exit(EXIT_FAILURE);		}	}	if (dayoff < 0 && !tt_signed)		return min_time;	t = (time_t) dayoff * SECSPERDAY;	/*	** Cheap overflow check.	*/	if (t / SECSPERDAY != dayoff)		return (dayoff > 0) ? max_time : min_time;	return tadd(t, rp->r_tod);}static voidnewabbr(string)const char * const	string;{	register int	i;	i = strlen(string) + 1;	if (charcnt + i > TZ_MAX_CHARS) {		error("too many, or too long, time zone abbreviations");		(void) exit(EXIT_FAILURE);	}	(void) strcpy(&chars[charcnt], string);	charcnt += eitol(i);}static intmkdirs(argname)char * const	argname;{	register char *	name;	register char *	cp;	if (argname == NULL || *argname == '\0')		return 0;	cp = name = ecpyalloc(argname);	while ((cp = strchr(cp + 1, '/')) != 0) {		*cp = '\0';#ifndef unix		/*		** MS-DOS drive specifier?		*/		if (strlen(name) == 2 && isascii(name[0]) &&			isalpha(name[0]) && name[1] == ':') {				*cp = '/';				continue;		}#endif /* !defined unix */		if (!itsdir(name)) {			/*			** It doesn't seem to exist, so we try to create it.			*/			if (emkdir(name, 0755) != 0) {				(void) fprintf(stderr,					"%s: Can't create directory ",					progname);				(void) perror(name);				ifree(name);				return -1;			}		}		*cp = '/';	}	ifree(name);	return 0;}static longeitol(i)const int	i;{	long	l;	l = i;	if ((i < 0 && l >= 0) || (i == 0 && l != 0) || (i > 0 && l <= 0)) {		(void) fprintf(stderr,			"%s: %d did not sign extend correctly\n",			progname, i);		(void) exit(EXIT_FAILURE);	}	return l;}/*** UNIX is a registered trademark of AT&T.*/

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?