intl/icu/source/tools/tzcode/localtime.c

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/intl/icu/source/tools/tzcode/localtime.c	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,2080 @@
     1.4 +/*
     1.5 +** This file is in the public domain, so clarified as of
     1.6 +** 1996-06-05 by Arthur David Olson.
     1.7 +*/
     1.8 +
     1.9 +#ifndef lint
    1.10 +#ifndef NOID
    1.11 +static char	elsieid[] = "@(#)localtime.c	8.9";
    1.12 +#endif /* !defined NOID */
    1.13 +#endif /* !defined lint */
    1.14 +
    1.15 +/*
    1.16 +** Leap second handling from Bradley White.
    1.17 +** POSIX-style TZ environment variable handling from Guy Harris.
    1.18 +*/
    1.19 +
    1.20 +/*LINTLIBRARY*/
    1.21 +
    1.22 +#include "private.h"
    1.23 +#include "tzfile.h"
    1.24 +#include "fcntl.h"
    1.25 +#include "float.h"	/* for FLT_MAX and DBL_MAX */
    1.26 +
    1.27 +#ifndef TZ_ABBR_MAX_LEN
    1.28 +#define TZ_ABBR_MAX_LEN	16
    1.29 +#endif /* !defined TZ_ABBR_MAX_LEN */
    1.30 +
    1.31 +#ifndef TZ_ABBR_CHAR_SET
    1.32 +#define TZ_ABBR_CHAR_SET \
    1.33 +	"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 :+-._"
    1.34 +#endif /* !defined TZ_ABBR_CHAR_SET */
    1.35 +
    1.36 +#ifndef TZ_ABBR_ERR_CHAR
    1.37 +#define TZ_ABBR_ERR_CHAR	'_'
    1.38 +#endif /* !defined TZ_ABBR_ERR_CHAR */
    1.39 +
    1.40 +/*
    1.41 +** SunOS 4.1.1 headers lack O_BINARY.
    1.42 +*/
    1.43 +
    1.44 +#ifdef O_BINARY
    1.45 +#define OPEN_MODE	(O_RDONLY | O_BINARY)
    1.46 +#endif /* defined O_BINARY */
    1.47 +#ifndef O_BINARY
    1.48 +#define OPEN_MODE	O_RDONLY
    1.49 +#endif /* !defined O_BINARY */
    1.50 +
    1.51 +#ifndef WILDABBR
    1.52 +/*
    1.53 +** Someone might make incorrect use of a time zone abbreviation:
    1.54 +**	1.	They might reference tzname[0] before calling tzset (explicitly
    1.55 +**		or implicitly).
    1.56 +**	2.	They might reference tzname[1] before calling tzset (explicitly
    1.57 +**		or implicitly).
    1.58 +**	3.	They might reference tzname[1] after setting to a time zone
    1.59 +**		in which Daylight Saving Time is never observed.
    1.60 +**	4.	They might reference tzname[0] after setting to a time zone
    1.61 +**		in which Standard Time is never observed.
    1.62 +**	5.	They might reference tm.TM_ZONE after calling offtime.
    1.63 +** What's best to do in the above cases is open to debate;
    1.64 +** for now, we just set things up so that in any of the five cases
    1.65 +** WILDABBR is used. Another possibility: initialize tzname[0] to the
    1.66 +** string "tzname[0] used before set", and similarly for the other cases.
    1.67 +** And another: initialize tzname[0] to "ERA", with an explanation in the
    1.68 +** manual page of what this "time zone abbreviation" means (doing this so
    1.69 +** that tzname[0] has the "normal" length of three characters).
    1.70 +*/
    1.71 +#define WILDABBR	"   "
    1.72 +#endif /* !defined WILDABBR */
    1.73 +
    1.74 +static char		wildabbr[] = WILDABBR;
    1.75 +
    1.76 +static const char	gmt[] = "GMT";
    1.77 +
    1.78 +/*
    1.79 +** The DST rules to use if TZ has no rules and we can't load TZDEFRULES.
    1.80 +** We default to US rules as of 1999-08-17.
    1.81 +** POSIX 1003.1 section 8.1.1 says that the default DST rules are
    1.82 +** implementation dependent; for historical reasons, US rules are a
    1.83 +** common default.
    1.84 +*/
    1.85 +#ifndef TZDEFRULESTRING
    1.86 +#define TZDEFRULESTRING ",M4.1.0,M10.5.0"
    1.87 +#endif /* !defined TZDEFDST */
    1.88 +
    1.89 +struct ttinfo {				/* time type information */
    1.90 +	long		tt_gmtoff;	/* UTC offset in seconds */
    1.91 +	int		tt_isdst;	/* used to set tm_isdst */
    1.92 +	int		tt_abbrind;	/* abbreviation list index */
    1.93 +	int		tt_ttisstd;	/* TRUE if transition is std time */
    1.94 +	int		tt_ttisgmt;	/* TRUE if transition is UTC */
    1.95 +};
    1.96 +
    1.97 +struct lsinfo {				/* leap second information */
    1.98 +	time_t		ls_trans;	/* transition time */
    1.99 +	long		ls_corr;	/* correction to apply */
   1.100 +};
   1.101 +
   1.102 +#define BIGGEST(a, b)	(((a) > (b)) ? (a) : (b))
   1.103 +
   1.104 +#ifdef TZNAME_MAX
   1.105 +#define MY_TZNAME_MAX	TZNAME_MAX
   1.106 +#endif /* defined TZNAME_MAX */
   1.107 +#ifndef TZNAME_MAX
   1.108 +#define MY_TZNAME_MAX	255
   1.109 +#endif /* !defined TZNAME_MAX */
   1.110 +
   1.111 +struct state {
   1.112 +	int		leapcnt;
   1.113 +	int		timecnt;
   1.114 +	int		typecnt;
   1.115 +	int		charcnt;
   1.116 +	int		goback;
   1.117 +	int		goahead;
   1.118 +	time_t		ats[TZ_MAX_TIMES];
   1.119 +	unsigned char	types[TZ_MAX_TIMES];
   1.120 +	struct ttinfo	ttis[TZ_MAX_TYPES];
   1.121 +	char		chars[BIGGEST(BIGGEST(TZ_MAX_CHARS + 1, sizeof gmt),
   1.122 +				(2 * (MY_TZNAME_MAX + 1)))];
   1.123 +	struct lsinfo	lsis[TZ_MAX_LEAPS];
   1.124 +};
   1.125 +
   1.126 +struct rule {
   1.127 +	int		r_type;		/* type of rule--see below */
   1.128 +	int		r_day;		/* day number of rule */
   1.129 +	int		r_week;		/* week number of rule */
   1.130 +	int		r_mon;		/* month number of rule */
   1.131 +	long		r_time;		/* transition time of rule */
   1.132 +};
   1.133 +
   1.134 +#define JULIAN_DAY		0	/* Jn - Julian day */
   1.135 +#define DAY_OF_YEAR		1	/* n - day of year */
   1.136 +#define MONTH_NTH_DAY_OF_WEEK	2	/* Mm.n.d - month, week, day of week */
   1.137 +
   1.138 +/*
   1.139 +** Prototypes for static functions.
   1.140 +*/
   1.141 +
   1.142 +static long		detzcode(const char * codep);
   1.143 +static time_t		detzcode64(const char * codep);
   1.144 +static int		differ_by_repeat(time_t t1, time_t t0);
   1.145 +static const char *	getzname(const char * strp);
   1.146 +static const char *	getqzname(const char * strp, const int delim);
   1.147 +static const char *	getnum(const char * strp, int * nump, int min,
   1.148 +				int max);
   1.149 +static const char *	getsecs(const char * strp, long * secsp);
   1.150 +static const char *	getoffset(const char * strp, long * offsetp);
   1.151 +static const char *	getrule(const char * strp, struct rule * rulep);
   1.152 +static void		gmtload(struct state * sp);
   1.153 +static struct tm *	gmtsub(const time_t * timep, long offset,
   1.154 +				struct tm * tmp);
   1.155 +static struct tm *	localsub(const time_t * timep, long offset,
   1.156 +				struct tm * tmp);
   1.157 +static int		increment_overflow(int * number, int delta);
   1.158 +static int		leaps_thru_end_of(int y);
   1.159 +static int		long_increment_overflow(long * number, int delta);
   1.160 +static int		long_normalize_overflow(long * tensptr,
   1.161 +				int * unitsptr, int base);
   1.162 +static int		normalize_overflow(int * tensptr, int * unitsptr,
   1.163 +				int base);
   1.164 +static void		settzname(void);
   1.165 +static time_t		time1(struct tm * tmp,
   1.166 +				struct tm * (*funcp)(const time_t *,
   1.167 +				long, struct tm *),
   1.168 +				long offset);
   1.169 +static time_t		time2(struct tm *tmp,
   1.170 +				struct tm * (*funcp)(const time_t *,
   1.171 +				long, struct tm*),
   1.172 +				long offset, int * okayp);
   1.173 +static time_t		time2sub(struct tm *tmp,
   1.174 +				struct tm * (*funcp)(const time_t *,
   1.175 +				long, struct tm*),
   1.176 +				long offset, int * okayp, int do_norm_secs);
   1.177 +static struct tm *	timesub(const time_t * timep, long offset,
   1.178 +				const struct state * sp, struct tm * tmp);
   1.179 +static int		tmcomp(const struct tm * atmp,
   1.180 +				const struct tm * btmp);
   1.181 +static time_t		transtime(time_t janfirst, int year,
   1.182 +				const struct rule * rulep, long offset);
   1.183 +static int		typesequiv(const struct state * sp, int a, int b);
   1.184 +static int		tzload(const char * name, struct state * sp,
   1.185 +				int doextend);
   1.186 +static int		tzparse(const char * name, struct state * sp,
   1.187 +				int lastditch);
   1.188 +
   1.189 +#ifdef ALL_STATE
   1.190 +static struct state *	lclptr;
   1.191 +static struct state *	gmtptr;
   1.192 +#endif /* defined ALL_STATE */
   1.193 +
   1.194 +#ifndef ALL_STATE
   1.195 +static struct state	lclmem;
   1.196 +static struct state	gmtmem;
   1.197 +#define lclptr		(&lclmem)
   1.198 +#define gmtptr		(&gmtmem)
   1.199 +#endif /* State Farm */
   1.200 +
   1.201 +#ifndef TZ_STRLEN_MAX
   1.202 +#define TZ_STRLEN_MAX 255
   1.203 +#endif /* !defined TZ_STRLEN_MAX */
   1.204 +
   1.205 +static char		lcl_TZname[TZ_STRLEN_MAX + 1];
   1.206 +static int		lcl_is_set;
   1.207 +static int		gmt_is_set;
   1.208 +
   1.209 +char *			tzname[2] = {
   1.210 +	wildabbr,
   1.211 +	wildabbr
   1.212 +};
   1.213 +
   1.214 +/*
   1.215 +** Section 4.12.3 of X3.159-1989 requires that
   1.216 +**	Except for the strftime function, these functions [asctime,
   1.217 +**	ctime, gmtime, localtime] return values in one of two static
   1.218 +**	objects: a broken-down time structure and an array of char.
   1.219 +** Thanks to Paul Eggert for noting this.
   1.220 +*/
   1.221 +
   1.222 +static struct tm	tm;
   1.223 +
   1.224 +#ifdef USG_COMPAT
   1.225 +time_t			timezone = 0;
   1.226 +int			daylight = 0;
   1.227 +#endif /* defined USG_COMPAT */
   1.228 +
   1.229 +#ifdef ALTZONE
   1.230 +time_t			altzone = 0;
   1.231 +#endif /* defined ALTZONE */
   1.232 +
   1.233 +static long
   1.234 +detzcode(codep)
   1.235 +const char * const	codep;
   1.236 +{
   1.237 +	register long	result;
   1.238 +	register int	i;
   1.239 +
   1.240 +	result = (codep[0] & 0x80) ? ~0L : 0;
   1.241 +	for (i = 0; i < 4; ++i)
   1.242 +		result = (result << 8) | (codep[i] & 0xff);
   1.243 +	return result;
   1.244 +}
   1.245 +
   1.246 +static time_t
   1.247 +detzcode64(codep)
   1.248 +const char * const	codep;
   1.249 +{
   1.250 +	register time_t	result;
   1.251 +	register int	i;
   1.252 +
   1.253 +	result = (codep[0] & 0x80) ?  (~(int_fast64_t) 0) : 0;
   1.254 +	for (i = 0; i < 8; ++i)
   1.255 +		result = result * 256 + (codep[i] & 0xff);
   1.256 +	return result;
   1.257 +}
   1.258 +
   1.259 +static void
   1.260 +settzname(void)
   1.261 +{
   1.262 +	register struct state * const	sp = lclptr;
   1.263 +	register int			i;
   1.264 +
   1.265 +	tzname[0] = wildabbr;
   1.266 +	tzname[1] = wildabbr;
   1.267 +#ifdef USG_COMPAT
   1.268 +	daylight = 0;
   1.269 +	timezone = 0;
   1.270 +#endif /* defined USG_COMPAT */
   1.271 +#ifdef ALTZONE
   1.272 +	altzone = 0;
   1.273 +#endif /* defined ALTZONE */
   1.274 +#ifdef ALL_STATE
   1.275 +	if (sp == NULL) {
   1.276 +		tzname[0] = tzname[1] = gmt;
   1.277 +		return;
   1.278 +	}
   1.279 +#endif /* defined ALL_STATE */
   1.280 +	for (i = 0; i < sp->typecnt; ++i) {
   1.281 +		register const struct ttinfo * const	ttisp = &sp->ttis[i];
   1.282 +
   1.283 +		tzname[ttisp->tt_isdst] =
   1.284 +			&sp->chars[ttisp->tt_abbrind];
   1.285 +#ifdef USG_COMPAT
   1.286 +		if (ttisp->tt_isdst)
   1.287 +			daylight = 1;
   1.288 +		if (i == 0 || !ttisp->tt_isdst)
   1.289 +			timezone = -(ttisp->tt_gmtoff);
   1.290 +#endif /* defined USG_COMPAT */
   1.291 +#ifdef ALTZONE
   1.292 +		if (i == 0 || ttisp->tt_isdst)
   1.293 +			altzone = -(ttisp->tt_gmtoff);
   1.294 +#endif /* defined ALTZONE */
   1.295 +	}
   1.296 +	/*
   1.297 +	** And to get the latest zone names into tzname. . .
   1.298 +	*/
   1.299 +	for (i = 0; i < sp->timecnt; ++i) {
   1.300 +		register const struct ttinfo * const	ttisp =
   1.301 +							&sp->ttis[
   1.302 +								sp->types[i]];
   1.303 +
   1.304 +		tzname[ttisp->tt_isdst] =
   1.305 +			&sp->chars[ttisp->tt_abbrind];
   1.306 +	}
   1.307 +	/*
   1.308 +	** Finally, scrub the abbreviations.
   1.309 +	** First, replace bogus characters.
   1.310 +	*/
   1.311 +	for (i = 0; i < sp->charcnt; ++i)
   1.312 +		if (strchr(TZ_ABBR_CHAR_SET, sp->chars[i]) == NULL)
   1.313 +			sp->chars[i] = TZ_ABBR_ERR_CHAR;
   1.314 +	/*
   1.315 +	** Second, truncate long abbreviations.
   1.316 +	*/
   1.317 +	for (i = 0; i < sp->typecnt; ++i) {
   1.318 +		register const struct ttinfo * const	ttisp = &sp->ttis[i];
   1.319 +		register char *				cp = &sp->chars[ttisp->tt_abbrind];
   1.320 +
   1.321 +		if (strlen(cp) > TZ_ABBR_MAX_LEN &&
   1.322 +			strcmp(cp, GRANDPARENTED) != 0)
   1.323 +				*(cp + TZ_ABBR_MAX_LEN) = '\0';
   1.324 +	}
   1.325 +}
   1.326 +
   1.327 +static int
   1.328 +differ_by_repeat(t1, t0)
   1.329 +const time_t	t1;
   1.330 +const time_t	t0;
   1.331 +{
   1.332 +	if (TYPE_INTEGRAL(time_t) &&
   1.333 +		TYPE_BIT(time_t) - TYPE_SIGNED(time_t) < SECSPERREPEAT_BITS)
   1.334 +			return 0;
   1.335 +	return t1 - t0 == SECSPERREPEAT;
   1.336 +}
   1.337 +
   1.338 +static int
   1.339 +tzload(name, sp, doextend)
   1.340 +register const char *		name;
   1.341 +register struct state * const	sp;
   1.342 +register const int		doextend;
   1.343 +{
   1.344 +	register const char *		p;
   1.345 +	register int			i;
   1.346 +	register int			fid;
   1.347 +	register int			stored;
   1.348 +	register int			nread;
   1.349 +	union {
   1.350 +		struct tzhead	tzhead;
   1.351 +		char		buf[2 * sizeof(struct tzhead) +
   1.352 +					2 * sizeof *sp +
   1.353 +					4 * TZ_MAX_TIMES];
   1.354 +	} u;
   1.355 +
   1.356 +	if (name == NULL && (name = TZDEFAULT) == NULL)
   1.357 +		return -1;
   1.358 +	{
   1.359 +		register int	doaccess;
   1.360 +		/*
   1.361 +		** Section 4.9.1 of the C standard says that
   1.362 +		** "FILENAME_MAX expands to an integral constant expression
   1.363 +		** that is the size needed for an array of char large enough
   1.364 +		** to hold the longest file name string that the implementation
   1.365 +		** guarantees can be opened."
   1.366 +		*/
   1.367 +		char		fullname[FILENAME_MAX + 1];
   1.368 +
   1.369 +		if (name[0] == ':')
   1.370 +			++name;
   1.371 +		doaccess = name[0] == '/';
   1.372 +		if (!doaccess) {
   1.373 +			if ((p = TZDIR) == NULL)
   1.374 +				return -1;
   1.375 +			if ((strlen(p) + strlen(name) + 1) >= sizeof fullname)
   1.376 +				return -1;
   1.377 +			(void) strcpy(fullname, p);
   1.378 +			(void) strcat(fullname, "/");
   1.379 +			(void) strcat(fullname, name);
   1.380 +			/*
   1.381 +			** Set doaccess if '.' (as in "../") shows up in name.
   1.382 +			*/
   1.383 +			if (strchr(name, '.') != NULL)
   1.384 +				doaccess = TRUE;
   1.385 +			name = fullname;
   1.386 +		}
   1.387 +		if (doaccess && access(name, R_OK) != 0)
   1.388 +			return -1;
   1.389 +		if ((fid = open(name, OPEN_MODE)) == -1)
   1.390 +			return -1;
   1.391 +	}
   1.392 +	nread = read(fid, u.buf, sizeof u.buf);
   1.393 +	if (close(fid) < 0 || nread <= 0)
   1.394 +		return -1;
   1.395 +	for (stored = 4; stored <= 8; stored *= 2) {
   1.396 +		int		ttisstdcnt;
   1.397 +		int		ttisgmtcnt;
   1.398 +
   1.399 +		ttisstdcnt = (int) detzcode(u.tzhead.tzh_ttisstdcnt);
   1.400 +		ttisgmtcnt = (int) detzcode(u.tzhead.tzh_ttisgmtcnt);
   1.401 +		sp->leapcnt = (int) detzcode(u.tzhead.tzh_leapcnt);
   1.402 +		sp->timecnt = (int) detzcode(u.tzhead.tzh_timecnt);
   1.403 +		sp->typecnt = (int) detzcode(u.tzhead.tzh_typecnt);
   1.404 +		sp->charcnt = (int) detzcode(u.tzhead.tzh_charcnt);
   1.405 +		p = u.tzhead.tzh_charcnt + sizeof u.tzhead.tzh_charcnt;
   1.406 +		if (sp->leapcnt < 0 || sp->leapcnt > TZ_MAX_LEAPS ||
   1.407 +			sp->typecnt <= 0 || sp->typecnt > TZ_MAX_TYPES ||
   1.408 +			sp->timecnt < 0 || sp->timecnt > TZ_MAX_TIMES ||
   1.409 +			sp->charcnt < 0 || sp->charcnt > TZ_MAX_CHARS ||
   1.410 +			(ttisstdcnt != sp->typecnt && ttisstdcnt != 0) ||
   1.411 +			(ttisgmtcnt != sp->typecnt && ttisgmtcnt != 0))
   1.412 +				return -1;
   1.413 +		if (nread - (p - u.buf) <
   1.414 +			sp->timecnt * stored +		/* ats */
   1.415 +			sp->timecnt +			/* types */
   1.416 +			sp->typecnt * 6 +		/* ttinfos */
   1.417 +			sp->charcnt +			/* chars */
   1.418 +			sp->leapcnt * (stored + 4) +	/* lsinfos */
   1.419 +			ttisstdcnt +			/* ttisstds */
   1.420 +			ttisgmtcnt)			/* ttisgmts */
   1.421 +				return -1;
   1.422 +		for (i = 0; i < sp->timecnt; ++i) {
   1.423 +			sp->ats[i] = (stored == 4) ?
   1.424 +				detzcode(p) : detzcode64(p);
   1.425 +			p += stored;
   1.426 +		}
   1.427 +		for (i = 0; i < sp->timecnt; ++i) {
   1.428 +			sp->types[i] = (unsigned char) *p++;
   1.429 +			if (sp->types[i] >= sp->typecnt)
   1.430 +				return -1;
   1.431 +		}
   1.432 +		for (i = 0; i < sp->typecnt; ++i) {
   1.433 +			register struct ttinfo *	ttisp;
   1.434 +
   1.435 +			ttisp = &sp->ttis[i];
   1.436 +			ttisp->tt_gmtoff = detzcode(p);
   1.437 +			p += 4;
   1.438 +			ttisp->tt_isdst = (unsigned char) *p++;
   1.439 +			if (ttisp->tt_isdst != 0 && ttisp->tt_isdst != 1)
   1.440 +				return -1;
   1.441 +			ttisp->tt_abbrind = (unsigned char) *p++;
   1.442 +			if (ttisp->tt_abbrind < 0 ||
   1.443 +				ttisp->tt_abbrind > sp->charcnt)
   1.444 +					return -1;
   1.445 +		}
   1.446 +		for (i = 0; i < sp->charcnt; ++i)
   1.447 +			sp->chars[i] = *p++;
   1.448 +		sp->chars[i] = '\0';	/* ensure '\0' at end */
   1.449 +		for (i = 0; i < sp->leapcnt; ++i) {
   1.450 +			register struct lsinfo *	lsisp;
   1.451 +
   1.452 +			lsisp = &sp->lsis[i];
   1.453 +			lsisp->ls_trans = (stored == 4) ?
   1.454 +				detzcode(p) : detzcode64(p);
   1.455 +			p += stored;
   1.456 +			lsisp->ls_corr = detzcode(p);
   1.457 +			p += 4;
   1.458 +		}
   1.459 +		for (i = 0; i < sp->typecnt; ++i) {
   1.460 +			register struct ttinfo *	ttisp;
   1.461 +
   1.462 +			ttisp = &sp->ttis[i];
   1.463 +			if (ttisstdcnt == 0)
   1.464 +				ttisp->tt_ttisstd = FALSE;
   1.465 +			else {
   1.466 +				ttisp->tt_ttisstd = *p++;
   1.467 +				if (ttisp->tt_ttisstd != TRUE &&
   1.468 +					ttisp->tt_ttisstd != FALSE)
   1.469 +						return -1;
   1.470 +			}
   1.471 +		}
   1.472 +		for (i = 0; i < sp->typecnt; ++i) {
   1.473 +			register struct ttinfo *	ttisp;
   1.474 +
   1.475 +			ttisp = &sp->ttis[i];
   1.476 +			if (ttisgmtcnt == 0)
   1.477 +				ttisp->tt_ttisgmt = FALSE;
   1.478 +			else {
   1.479 +				ttisp->tt_ttisgmt = *p++;
   1.480 +				if (ttisp->tt_ttisgmt != TRUE &&
   1.481 +					ttisp->tt_ttisgmt != FALSE)
   1.482 +						return -1;
   1.483 +			}
   1.484 +		}
   1.485 +		/*
   1.486 +		** Out-of-sort ats should mean we're running on a
   1.487 +		** signed time_t system but using a data file with
   1.488 +		** unsigned values (or vice versa).
   1.489 +		*/
   1.490 +		for (i = 0; i < sp->timecnt - 2; ++i)
   1.491 +			if (sp->ats[i] > sp->ats[i + 1]) {
   1.492 +				++i;
   1.493 +				if (TYPE_SIGNED(time_t)) {
   1.494 +					/*
   1.495 +					** Ignore the end (easy).
   1.496 +					*/
   1.497 +					sp->timecnt = i;
   1.498 +				} else {
   1.499 +					/*
   1.500 +					** Ignore the beginning (harder).
   1.501 +					*/
   1.502 +					register int	j;
   1.503 +
   1.504 +					for (j = 0; j + i < sp->timecnt; ++j) {
   1.505 +						sp->ats[j] = sp->ats[j + i];
   1.506 +						sp->types[j] = sp->types[j + i];
   1.507 +					}
   1.508 +					sp->timecnt = j;
   1.509 +				}
   1.510 +				break;
   1.511 +			}
   1.512 +		/*
   1.513 +		** If this is an old file, we're done.
   1.514 +		*/
   1.515 +		if (u.tzhead.tzh_version[0] == '\0')
   1.516 +			break;
   1.517 +		nread -= p - u.buf;
   1.518 +		for (i = 0; i < nread; ++i)
   1.519 +			u.buf[i] = p[i];
   1.520 +		/*
   1.521 +		** If this is a narrow integer time_t system, we're done.
   1.522 +		*/
   1.523 +		if (stored >= (int) sizeof(time_t) && TYPE_INTEGRAL(time_t))
   1.524 +			break;
   1.525 +	}
   1.526 +	if (doextend && nread > 2 &&
   1.527 +		u.buf[0] == '\n' && u.buf[nread - 1] == '\n' &&
   1.528 +		sp->typecnt + 2 <= TZ_MAX_TYPES) {
   1.529 +			struct state	ts;
   1.530 +			register int	result;
   1.531 +
   1.532 +			u.buf[nread - 1] = '\0';
   1.533 +			result = tzparse(&u.buf[1], &ts, FALSE);
   1.534 +			if (result == 0 && ts.typecnt == 2 &&
   1.535 +				sp->charcnt + ts.charcnt <= TZ_MAX_CHARS) {
   1.536 +					for (i = 0; i < 2; ++i)
   1.537 +						ts.ttis[i].tt_abbrind +=
   1.538 +							sp->charcnt;
   1.539 +					for (i = 0; i < ts.charcnt; ++i)
   1.540 +						sp->chars[sp->charcnt++] =
   1.541 +							ts.chars[i];
   1.542 +					i = 0;
   1.543 +					while (i < ts.timecnt &&
   1.544 +						ts.ats[i] <=
   1.545 +						sp->ats[sp->timecnt - 1])
   1.546 +							++i;
   1.547 +					while (i < ts.timecnt &&
   1.548 +					    sp->timecnt < TZ_MAX_TIMES) {
   1.549 +						sp->ats[sp->timecnt] =
   1.550 +							ts.ats[i];
   1.551 +						sp->types[sp->timecnt] =
   1.552 +							sp->typecnt +
   1.553 +							ts.types[i];
   1.554 +						++sp->timecnt;
   1.555 +						++i;
   1.556 +					}
   1.557 +					sp->ttis[sp->typecnt++] = ts.ttis[0];
   1.558 +					sp->ttis[sp->typecnt++] = ts.ttis[1];
   1.559 +			}
   1.560 +	}
   1.561 +	sp->goback = sp->goahead = FALSE;
   1.562 +	if (sp->timecnt > 1) {
   1.563 +		for (i = 1; i < sp->timecnt; ++i)
   1.564 +			if (typesequiv(sp, sp->types[i], sp->types[0]) &&
   1.565 +				differ_by_repeat(sp->ats[i], sp->ats[0])) {
   1.566 +					sp->goback = TRUE;
   1.567 +					break;
   1.568 +				}
   1.569 +		for (i = sp->timecnt - 2; i >= 0; --i)
   1.570 +			if (typesequiv(sp, sp->types[sp->timecnt - 1],
   1.571 +				sp->types[i]) &&
   1.572 +				differ_by_repeat(sp->ats[sp->timecnt - 1],
   1.573 +				sp->ats[i])) {
   1.574 +					sp->goahead = TRUE;
   1.575 +					break;
   1.576 +		}
   1.577 +	}
   1.578 +	return 0;
   1.579 +}
   1.580 +
   1.581 +static int
   1.582 +typesequiv(sp, a, b)
   1.583 +const struct state * const	sp;
   1.584 +const int			a;
   1.585 +const int			b;
   1.586 +{
   1.587 +	register int	result;
   1.588 +
   1.589 +	if (sp == NULL ||
   1.590 +		a < 0 || a >= sp->typecnt ||
   1.591 +		b < 0 || b >= sp->typecnt)
   1.592 +			result = FALSE;
   1.593 +	else {
   1.594 +		register const struct ttinfo *	ap = &sp->ttis[a];
   1.595 +		register const struct ttinfo *	bp = &sp->ttis[b];
   1.596 +		result = ap->tt_gmtoff == bp->tt_gmtoff &&
   1.597 +			ap->tt_isdst == bp->tt_isdst &&
   1.598 +			ap->tt_ttisstd == bp->tt_ttisstd &&
   1.599 +			ap->tt_ttisgmt == bp->tt_ttisgmt &&
   1.600 +			strcmp(&sp->chars[ap->tt_abbrind],
   1.601 +			&sp->chars[bp->tt_abbrind]) == 0;
   1.602 +	}
   1.603 +	return result;
   1.604 +}
   1.605 +
   1.606 +static const int	mon_lengths[2][MONSPERYEAR] = {
   1.607 +	{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
   1.608 +	{ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
   1.609 +};
   1.610 +
   1.611 +static const int	year_lengths[2] = {
   1.612 +	DAYSPERNYEAR, DAYSPERLYEAR
   1.613 +};
   1.614 +
   1.615 +/*
   1.616 +** Given a pointer into a time zone string, scan until a character that is not
   1.617 +** a valid character in a zone name is found. Return a pointer to that
   1.618 +** character.
   1.619 +*/
   1.620 +
   1.621 +static const char *
   1.622 +getzname(strp)
   1.623 +register const char *	strp;
   1.624 +{
   1.625 +	register char	c;
   1.626 +
   1.627 +	while ((c = *strp) != '\0' && !is_digit(c) && c != ',' && c != '-' &&
   1.628 +		c != '+')
   1.629 +			++strp;
   1.630 +	return strp;
   1.631 +}
   1.632 +
   1.633 +/*
   1.634 +** Given a pointer into an extended time zone string, scan until the ending
   1.635 +** delimiter of the zone name is located. Return a pointer to the delimiter.
   1.636 +**
   1.637 +** As with getzname above, the legal character set is actually quite
   1.638 +** restricted, with other characters producing undefined results.
   1.639 +** We don't do any checking here; checking is done later in common-case code.
   1.640 +*/
   1.641 +
   1.642 +static const char *
   1.643 +getqzname(register const char *strp, const int delim)
   1.644 +{
   1.645 +	register int	c;
   1.646 +
   1.647 +	while ((c = *strp) != '\0' && c != delim)
   1.648 +		++strp;
   1.649 +	return strp;
   1.650 +}
   1.651 +
   1.652 +/*
   1.653 +** Given a pointer into a time zone string, extract a number from that string.
   1.654 +** Check that the number is within a specified range; if it is not, return
   1.655 +** NULL.
   1.656 +** Otherwise, return a pointer to the first character not part of the number.
   1.657 +*/
   1.658 +
   1.659 +static const char *
   1.660 +getnum(strp, nump, min, max)
   1.661 +register const char *	strp;
   1.662 +int * const		nump;
   1.663 +const int		min;
   1.664 +const int		max;
   1.665 +{
   1.666 +	register char	c;
   1.667 +	register int	num;
   1.668 +
   1.669 +	if (strp == NULL || !is_digit(c = *strp))
   1.670 +		return NULL;
   1.671 +	num = 0;
   1.672 +	do {
   1.673 +		num = num * 10 + (c - '0');
   1.674 +		if (num > max)
   1.675 +			return NULL;	/* illegal value */
   1.676 +		c = *++strp;
   1.677 +	} while (is_digit(c));
   1.678 +	if (num < min)
   1.679 +		return NULL;		/* illegal value */
   1.680 +	*nump = num;
   1.681 +	return strp;
   1.682 +}
   1.683 +
   1.684 +/*
   1.685 +** Given a pointer into a time zone string, extract a number of seconds,
   1.686 +** in hh[:mm[:ss]] form, from the string.
   1.687 +** If any error occurs, return NULL.
   1.688 +** Otherwise, return a pointer to the first character not part of the number
   1.689 +** of seconds.
   1.690 +*/
   1.691 +
   1.692 +static const char *
   1.693 +getsecs(strp, secsp)
   1.694 +register const char *	strp;
   1.695 +long * const		secsp;
   1.696 +{
   1.697 +	int	num;
   1.698 +
   1.699 +	/*
   1.700 +	** `HOURSPERDAY * DAYSPERWEEK - 1' allows quasi-Posix rules like
   1.701 +	** "M10.4.6/26", which does not conform to Posix,
   1.702 +	** but which specifies the equivalent of
   1.703 +	** ``02:00 on the first Sunday on or after 23 Oct''.
   1.704 +	*/
   1.705 +	strp = getnum(strp, &num, 0, HOURSPERDAY * DAYSPERWEEK - 1);
   1.706 +	if (strp == NULL)
   1.707 +		return NULL;
   1.708 +	*secsp = num * (long) SECSPERHOUR;
   1.709 +	if (*strp == ':') {
   1.710 +		++strp;
   1.711 +		strp = getnum(strp, &num, 0, MINSPERHOUR - 1);
   1.712 +		if (strp == NULL)
   1.713 +			return NULL;
   1.714 +		*secsp += num * SECSPERMIN;
   1.715 +		if (*strp == ':') {
   1.716 +			++strp;
   1.717 +			/* `SECSPERMIN' allows for leap seconds. */
   1.718 +			strp = getnum(strp, &num, 0, SECSPERMIN);
   1.719 +			if (strp == NULL)
   1.720 +				return NULL;
   1.721 +			*secsp += num;
   1.722 +		}
   1.723 +	}
   1.724 +	return strp;
   1.725 +}
   1.726 +
   1.727 +/*
   1.728 +** Given a pointer into a time zone string, extract an offset, in
   1.729 +** [+-]hh[:mm[:ss]] form, from the string.
   1.730 +** If any error occurs, return NULL.
   1.731 +** Otherwise, return a pointer to the first character not part of the time.
   1.732 +*/
   1.733 +
   1.734 +static const char *
   1.735 +getoffset(strp, offsetp)
   1.736 +register const char *	strp;
   1.737 +long * const		offsetp;
   1.738 +{
   1.739 +	register int	neg = 0;
   1.740 +
   1.741 +	if (*strp == '-') {
   1.742 +		neg = 1;
   1.743 +		++strp;
   1.744 +	} else if (*strp == '+')
   1.745 +		++strp;
   1.746 +	strp = getsecs(strp, offsetp);
   1.747 +	if (strp == NULL)
   1.748 +		return NULL;		/* illegal time */
   1.749 +	if (neg)
   1.750 +		*offsetp = -*offsetp;
   1.751 +	return strp;
   1.752 +}
   1.753 +
   1.754 +/*
   1.755 +** Given a pointer into a time zone string, extract a rule in the form
   1.756 +** date[/time]. See POSIX section 8 for the format of "date" and "time".
   1.757 +** If a valid rule is not found, return NULL.
   1.758 +** Otherwise, return a pointer to the first character not part of the rule.
   1.759 +*/
   1.760 +
   1.761 +static const char *
   1.762 +getrule(strp, rulep)
   1.763 +const char *			strp;
   1.764 +register struct rule * const	rulep;
   1.765 +{
   1.766 +	if (*strp == 'J') {
   1.767 +		/*
   1.768 +		** Julian day.
   1.769 +		*/
   1.770 +		rulep->r_type = JULIAN_DAY;
   1.771 +		++strp;
   1.772 +		strp = getnum(strp, &rulep->r_day, 1, DAYSPERNYEAR);
   1.773 +	} else if (*strp == 'M') {
   1.774 +		/*
   1.775 +		** Month, week, day.
   1.776 +		*/
   1.777 +		rulep->r_type = MONTH_NTH_DAY_OF_WEEK;
   1.778 +		++strp;
   1.779 +		strp = getnum(strp, &rulep->r_mon, 1, MONSPERYEAR);
   1.780 +		if (strp == NULL)
   1.781 +			return NULL;
   1.782 +		if (*strp++ != '.')
   1.783 +			return NULL;
   1.784 +		strp = getnum(strp, &rulep->r_week, 1, 5);
   1.785 +		if (strp == NULL)
   1.786 +			return NULL;
   1.787 +		if (*strp++ != '.')
   1.788 +			return NULL;
   1.789 +		strp = getnum(strp, &rulep->r_day, 0, DAYSPERWEEK - 1);
   1.790 +	} else if (is_digit(*strp)) {
   1.791 +		/*
   1.792 +		** Day of year.
   1.793 +		*/
   1.794 +		rulep->r_type = DAY_OF_YEAR;
   1.795 +		strp = getnum(strp, &rulep->r_day, 0, DAYSPERLYEAR - 1);
   1.796 +	} else	return NULL;		/* invalid format */
   1.797 +	if (strp == NULL)
   1.798 +		return NULL;
   1.799 +	if (*strp == '/') {
   1.800 +		/*
   1.801 +		** Time specified.
   1.802 +		*/
   1.803 +		++strp;
   1.804 +		strp = getsecs(strp, &rulep->r_time);
   1.805 +	} else	rulep->r_time = 2 * SECSPERHOUR;	/* default = 2:00:00 */
   1.806 +	return strp;
   1.807 +}
   1.808 +
   1.809 +/*
   1.810 +** Given the Epoch-relative time of January 1, 00:00:00 UTC, in a year, the
   1.811 +** year, a rule, and the offset from UTC at the time that rule takes effect,
   1.812 +** calculate the Epoch-relative time that rule takes effect.
   1.813 +*/
   1.814 +
   1.815 +static time_t
   1.816 +transtime(janfirst, year, rulep, offset)
   1.817 +const time_t				janfirst;
   1.818 +const int				year;
   1.819 +register const struct rule * const	rulep;
   1.820 +const long				offset;
   1.821 +{
   1.822 +	register int	leapyear;
   1.823 +	register time_t	value;
   1.824 +	register int	i;
   1.825 +	int		d, m1, yy0, yy1, yy2, dow;
   1.826 +
   1.827 +	INITIALIZE(value);
   1.828 +	leapyear = isleap(year);
   1.829 +	switch (rulep->r_type) {
   1.830 +
   1.831 +	case JULIAN_DAY:
   1.832 +		/*
   1.833 +		** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap
   1.834 +		** years.
   1.835 +		** In non-leap years, or if the day number is 59 or less, just
   1.836 +		** add SECSPERDAY times the day number-1 to the time of
   1.837 +		** January 1, midnight, to get the day.
   1.838 +		*/
   1.839 +		value = janfirst + (rulep->r_day - 1) * SECSPERDAY;
   1.840 +		if (leapyear && rulep->r_day >= 60)
   1.841 +			value += SECSPERDAY;
   1.842 +		break;
   1.843 +
   1.844 +	case DAY_OF_YEAR:
   1.845 +		/*
   1.846 +		** n - day of year.
   1.847 +		** Just add SECSPERDAY times the day number to the time of
   1.848 +		** January 1, midnight, to get the day.
   1.849 +		*/
   1.850 +		value = janfirst + rulep->r_day * SECSPERDAY;
   1.851 +		break;
   1.852 +
   1.853 +	case MONTH_NTH_DAY_OF_WEEK:
   1.854 +		/*
   1.855 +		** Mm.n.d - nth "dth day" of month m.
   1.856 +		*/
   1.857 +		value = janfirst;
   1.858 +		for (i = 0; i < rulep->r_mon - 1; ++i)
   1.859 +			value += mon_lengths[leapyear][i] * SECSPERDAY;
   1.860 +
   1.861 +		/*
   1.862 +		** Use Zeller's Congruence to get day-of-week of first day of
   1.863 +		** month.
   1.864 +		*/
   1.865 +		m1 = (rulep->r_mon + 9) % 12 + 1;
   1.866 +		yy0 = (rulep->r_mon <= 2) ? (year - 1) : year;
   1.867 +		yy1 = yy0 / 100;
   1.868 +		yy2 = yy0 % 100;
   1.869 +		dow = ((26 * m1 - 2) / 10 +
   1.870 +			1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7;
   1.871 +		if (dow < 0)
   1.872 +			dow += DAYSPERWEEK;
   1.873 +
   1.874 +		/*
   1.875 +		** "dow" is the day-of-week of the first day of the month. Get
   1.876 +		** the day-of-month (zero-origin) of the first "dow" day of the
   1.877 +		** month.
   1.878 +		*/
   1.879 +		d = rulep->r_day - dow;
   1.880 +		if (d < 0)
   1.881 +			d += DAYSPERWEEK;
   1.882 +		for (i = 1; i < rulep->r_week; ++i) {
   1.883 +			if (d + DAYSPERWEEK >=
   1.884 +				mon_lengths[leapyear][rulep->r_mon - 1])
   1.885 +					break;
   1.886 +			d += DAYSPERWEEK;
   1.887 +		}
   1.888 +
   1.889 +		/*
   1.890 +		** "d" is the day-of-month (zero-origin) of the day we want.
   1.891 +		*/
   1.892 +		value += d * SECSPERDAY;
   1.893 +		break;
   1.894 +	}
   1.895 +
   1.896 +	/*
   1.897 +	** "value" is the Epoch-relative time of 00:00:00 UTC on the day in
   1.898 +	** question. To get the Epoch-relative time of the specified local
   1.899 +	** time on that day, add the transition time and the current offset
   1.900 +	** from UTC.
   1.901 +	*/
   1.902 +	return value + rulep->r_time + offset;
   1.903 +}
   1.904 +
   1.905 +/*
   1.906 +** Given a POSIX section 8-style TZ string, fill in the rule tables as
   1.907 +** appropriate.
   1.908 +*/
   1.909 +
   1.910 +static int
   1.911 +tzparse(name, sp, lastditch)
   1.912 +const char *			name;
   1.913 +register struct state * const	sp;
   1.914 +const int			lastditch;
   1.915 +{
   1.916 +	const char *			stdname;
   1.917 +	const char *			dstname;
   1.918 +	size_t				stdlen;
   1.919 +	size_t				dstlen;
   1.920 +	long				stdoffset;
   1.921 +	long				dstoffset;
   1.922 +	register time_t *		atp;
   1.923 +	register unsigned char *	typep;
   1.924 +	register char *			cp;
   1.925 +	register int			load_result;
   1.926 +
   1.927 +	INITIALIZE(dstname);
   1.928 +	stdname = name;
   1.929 +	if (lastditch) {
   1.930 +		stdlen = strlen(name);	/* length of standard zone name */
   1.931 +		name += stdlen;
   1.932 +		if (stdlen >= sizeof sp->chars)
   1.933 +			stdlen = (sizeof sp->chars) - 1;
   1.934 +		stdoffset = 0;
   1.935 +	} else {
   1.936 +		if (*name == '<') {
   1.937 +			name++;
   1.938 +			stdname = name;
   1.939 +			name = getqzname(name, '>');
   1.940 +			if (*name != '>')
   1.941 +				return (-1);
   1.942 +			stdlen = name - stdname;
   1.943 +			name++;
   1.944 +		} else {
   1.945 +			name = getzname(name);
   1.946 +			stdlen = name - stdname;
   1.947 +		}
   1.948 +		if (*name == '\0')
   1.949 +			return -1;
   1.950 +		name = getoffset(name, &stdoffset);
   1.951 +		if (name == NULL)
   1.952 +			return -1;
   1.953 +	}
   1.954 +	load_result = tzload(TZDEFRULES, sp, FALSE);
   1.955 +	if (load_result != 0)
   1.956 +		sp->leapcnt = 0;		/* so, we're off a little */
   1.957 +	if (*name != '\0') {
   1.958 +		if (*name == '<') {
   1.959 +			dstname = ++name;
   1.960 +			name = getqzname(name, '>');
   1.961 +			if (*name != '>')
   1.962 +				return -1;
   1.963 +			dstlen = name - dstname;
   1.964 +			name++;
   1.965 +		} else {
   1.966 +			dstname = name;
   1.967 +			name = getzname(name);
   1.968 +			dstlen = name - dstname; /* length of DST zone name */
   1.969 +		}
   1.970 +		if (*name != '\0' && *name != ',' && *name != ';') {
   1.971 +			name = getoffset(name, &dstoffset);
   1.972 +			if (name == NULL)
   1.973 +				return -1;
   1.974 +		} else	dstoffset = stdoffset - SECSPERHOUR;
   1.975 +		if (*name == '\0' && load_result != 0)
   1.976 +			name = TZDEFRULESTRING;
   1.977 +		if (*name == ',' || *name == ';') {
   1.978 +			struct rule	start;
   1.979 +			struct rule	end;
   1.980 +			register int	year;
   1.981 +			register time_t	janfirst;
   1.982 +			time_t		starttime;
   1.983 +			time_t		endtime;
   1.984 +
   1.985 +			++name;
   1.986 +			if ((name = getrule(name, &start)) == NULL)
   1.987 +				return -1;
   1.988 +			if (*name++ != ',')
   1.989 +				return -1;
   1.990 +			if ((name = getrule(name, &end)) == NULL)
   1.991 +				return -1;
   1.992 +			if (*name != '\0')
   1.993 +				return -1;
   1.994 +			sp->typecnt = 2;	/* standard time and DST */
   1.995 +			/*
   1.996 +			** Two transitions per year, from EPOCH_YEAR forward.
   1.997 +			*/
   1.998 +			sp->ttis[0].tt_gmtoff = -dstoffset;
   1.999 +			sp->ttis[0].tt_isdst = 1;
  1.1000 +			sp->ttis[0].tt_abbrind = stdlen + 1;
  1.1001 +			sp->ttis[1].tt_gmtoff = -stdoffset;
  1.1002 +			sp->ttis[1].tt_isdst = 0;
  1.1003 +			sp->ttis[1].tt_abbrind = 0;
  1.1004 +			atp = sp->ats;
  1.1005 +			typep = sp->types;
  1.1006 +			janfirst = 0;
  1.1007 +			sp->timecnt = 0;
  1.1008 +			for (year = EPOCH_YEAR;
  1.1009 +			    sp->timecnt + 2 <= TZ_MAX_TIMES;
  1.1010 +			    ++year) {
  1.1011 +			    	time_t	newfirst;
  1.1012 +
  1.1013 +				starttime = transtime(janfirst, year, &start,
  1.1014 +					stdoffset);
  1.1015 +				endtime = transtime(janfirst, year, &end,
  1.1016 +					dstoffset);
  1.1017 +				if (starttime > endtime) {
  1.1018 +					*atp++ = endtime;
  1.1019 +					*typep++ = 1;	/* DST ends */
  1.1020 +					*atp++ = starttime;
  1.1021 +					*typep++ = 0;	/* DST begins */
  1.1022 +				} else {
  1.1023 +					*atp++ = starttime;
  1.1024 +					*typep++ = 0;	/* DST begins */
  1.1025 +					*atp++ = endtime;
  1.1026 +					*typep++ = 1;	/* DST ends */
  1.1027 +				}
  1.1028 +				sp->timecnt += 2;
  1.1029 +				newfirst = janfirst;
  1.1030 +				newfirst += year_lengths[isleap(year)] *
  1.1031 +					SECSPERDAY;
  1.1032 +				if (newfirst <= janfirst)
  1.1033 +					break;
  1.1034 +				janfirst = newfirst;
  1.1035 +			}
  1.1036 +		} else {
  1.1037 +			register long	theirstdoffset;
  1.1038 +			register long	theirdstoffset;
  1.1039 +			register long	theiroffset;
  1.1040 +			register int	isdst;
  1.1041 +			register int	i;
  1.1042 +			register int	j;
  1.1043 +
  1.1044 +			if (*name != '\0')
  1.1045 +				return -1;
  1.1046 +			/*
  1.1047 +			** Initial values of theirstdoffset and theirdstoffset.
  1.1048 +			*/
  1.1049 +			theirstdoffset = 0;
  1.1050 +			for (i = 0; i < sp->timecnt; ++i) {
  1.1051 +				j = sp->types[i];
  1.1052 +				if (!sp->ttis[j].tt_isdst) {
  1.1053 +					theirstdoffset =
  1.1054 +						-sp->ttis[j].tt_gmtoff;
  1.1055 +					break;
  1.1056 +				}
  1.1057 +			}
  1.1058 +			theirdstoffset = 0;
  1.1059 +			for (i = 0; i < sp->timecnt; ++i) {
  1.1060 +				j = sp->types[i];
  1.1061 +				if (sp->ttis[j].tt_isdst) {
  1.1062 +					theirdstoffset =
  1.1063 +						-sp->ttis[j].tt_gmtoff;
  1.1064 +					break;
  1.1065 +				}
  1.1066 +			}
  1.1067 +			/*
  1.1068 +			** Initially we're assumed to be in standard time.
  1.1069 +			*/
  1.1070 +			isdst = FALSE;
  1.1071 +			theiroffset = theirstdoffset;
  1.1072 +			/*
  1.1073 +			** Now juggle transition times and types
  1.1074 +			** tracking offsets as you do.
  1.1075 +			*/
  1.1076 +			for (i = 0; i < sp->timecnt; ++i) {
  1.1077 +				j = sp->types[i];
  1.1078 +				sp->types[i] = sp->ttis[j].tt_isdst;
  1.1079 +				if (sp->ttis[j].tt_ttisgmt) {
  1.1080 +					/* No adjustment to transition time */
  1.1081 +				} else {
  1.1082 +					/*
  1.1083 +					** If summer time is in effect, and the
  1.1084 +					** transition time was not specified as
  1.1085 +					** standard time, add the summer time
  1.1086 +					** offset to the transition time;
  1.1087 +					** otherwise, add the standard time
  1.1088 +					** offset to the transition time.
  1.1089 +					*/
  1.1090 +					/*
  1.1091 +					** Transitions from DST to DDST
  1.1092 +					** will effectively disappear since
  1.1093 +					** POSIX provides for only one DST
  1.1094 +					** offset.
  1.1095 +					*/
  1.1096 +					if (isdst && !sp->ttis[j].tt_ttisstd) {
  1.1097 +						sp->ats[i] += dstoffset -
  1.1098 +							theirdstoffset;
  1.1099 +					} else {
  1.1100 +						sp->ats[i] += stdoffset -
  1.1101 +							theirstdoffset;
  1.1102 +					}
  1.1103 +				}
  1.1104 +				theiroffset = -sp->ttis[j].tt_gmtoff;
  1.1105 +				if (sp->ttis[j].tt_isdst)
  1.1106 +					theirdstoffset = theiroffset;
  1.1107 +				else	theirstdoffset = theiroffset;
  1.1108 +			}
  1.1109 +			/*
  1.1110 +			** Finally, fill in ttis.
  1.1111 +			** ttisstd and ttisgmt need not be handled.
  1.1112 +			*/
  1.1113 +			sp->ttis[0].tt_gmtoff = -stdoffset;
  1.1114 +			sp->ttis[0].tt_isdst = FALSE;
  1.1115 +			sp->ttis[0].tt_abbrind = 0;
  1.1116 +			sp->ttis[1].tt_gmtoff = -dstoffset;
  1.1117 +			sp->ttis[1].tt_isdst = TRUE;
  1.1118 +			sp->ttis[1].tt_abbrind = stdlen + 1;
  1.1119 +			sp->typecnt = 2;
  1.1120 +		}
  1.1121 +	} else {
  1.1122 +		dstlen = 0;
  1.1123 +		sp->typecnt = 1;		/* only standard time */
  1.1124 +		sp->timecnt = 0;
  1.1125 +		sp->ttis[0].tt_gmtoff = -stdoffset;
  1.1126 +		sp->ttis[0].tt_isdst = 0;
  1.1127 +		sp->ttis[0].tt_abbrind = 0;
  1.1128 +	}
  1.1129 +	sp->charcnt = stdlen + 1;
  1.1130 +	if (dstlen != 0)
  1.1131 +		sp->charcnt += dstlen + 1;
  1.1132 +	if ((size_t) sp->charcnt > sizeof sp->chars)
  1.1133 +		return -1;
  1.1134 +	cp = sp->chars;
  1.1135 +	(void) strncpy(cp, stdname, stdlen);
  1.1136 +	cp += stdlen;
  1.1137 +	*cp++ = '\0';
  1.1138 +	if (dstlen != 0) {
  1.1139 +		(void) strncpy(cp, dstname, dstlen);
  1.1140 +		*(cp + dstlen) = '\0';
  1.1141 +	}
  1.1142 +	return 0;
  1.1143 +}
  1.1144 +
  1.1145 +static void
  1.1146 +gmtload(sp)
  1.1147 +struct state * const	sp;
  1.1148 +{
  1.1149 +	if (tzload(gmt, sp, TRUE) != 0)
  1.1150 +		(void) tzparse(gmt, sp, TRUE);
  1.1151 +}
  1.1152 +
  1.1153 +#ifndef STD_INSPIRED
  1.1154 +/*
  1.1155 +** A non-static declaration of tzsetwall in a system header file
  1.1156 +** may cause a warning about this upcoming static declaration...
  1.1157 +*/
  1.1158 +static
  1.1159 +#endif /* !defined STD_INSPIRED */
  1.1160 +void
  1.1161 +tzsetwall(void)
  1.1162 +{
  1.1163 +	if (lcl_is_set < 0)
  1.1164 +		return;
  1.1165 +	lcl_is_set = -1;
  1.1166 +
  1.1167 +#ifdef ALL_STATE
  1.1168 +	if (lclptr == NULL) {
  1.1169 +		lclptr = (struct state *) malloc(sizeof *lclptr);
  1.1170 +		if (lclptr == NULL) {
  1.1171 +			settzname();	/* all we can do */
  1.1172 +			return;
  1.1173 +		}
  1.1174 +	}
  1.1175 +#endif /* defined ALL_STATE */
  1.1176 +	if (tzload((char *) NULL, lclptr, TRUE) != 0)
  1.1177 +		gmtload(lclptr);
  1.1178 +	settzname();
  1.1179 +}
  1.1180 +
  1.1181 +void
  1.1182 +tzset(void)
  1.1183 +{
  1.1184 +	register const char *	name;
  1.1185 +
  1.1186 +	name = getenv("TZ");
  1.1187 +	if (name == NULL) {
  1.1188 +		tzsetwall();
  1.1189 +		return;
  1.1190 +	}
  1.1191 +
  1.1192 +	if (lcl_is_set > 0 && strcmp(lcl_TZname, name) == 0)
  1.1193 +		return;
  1.1194 +	lcl_is_set = strlen(name) < sizeof lcl_TZname;
  1.1195 +	if (lcl_is_set)
  1.1196 +		(void) strcpy(lcl_TZname, name);
  1.1197 +
  1.1198 +#ifdef ALL_STATE
  1.1199 +	if (lclptr == NULL) {
  1.1200 +		lclptr = (struct state *) malloc(sizeof *lclptr);
  1.1201 +		if (lclptr == NULL) {
  1.1202 +			settzname();	/* all we can do */
  1.1203 +			return;
  1.1204 +		}
  1.1205 +	}
  1.1206 +#endif /* defined ALL_STATE */
  1.1207 +	if (*name == '\0') {
  1.1208 +		/*
  1.1209 +		** User wants it fast rather than right.
  1.1210 +		*/
  1.1211 +		lclptr->leapcnt = 0;		/* so, we're off a little */
  1.1212 +		lclptr->timecnt = 0;
  1.1213 +		lclptr->typecnt = 0;
  1.1214 +		lclptr->ttis[0].tt_isdst = 0;
  1.1215 +		lclptr->ttis[0].tt_gmtoff = 0;
  1.1216 +		lclptr->ttis[0].tt_abbrind = 0;
  1.1217 +		(void) strcpy(lclptr->chars, gmt);
  1.1218 +	} else if (tzload(name, lclptr, TRUE) != 0)
  1.1219 +		if (name[0] == ':' || tzparse(name, lclptr, FALSE) != 0)
  1.1220 +			(void) gmtload(lclptr);
  1.1221 +	settzname();
  1.1222 +}
  1.1223 +
  1.1224 +/*
  1.1225 +** The easy way to behave "as if no library function calls" localtime
  1.1226 +** is to not call it--so we drop its guts into "localsub", which can be
  1.1227 +** freely called. (And no, the PANS doesn't require the above behavior--
  1.1228 +** but it *is* desirable.)
  1.1229 +**
  1.1230 +** The unused offset argument is for the benefit of mktime variants.
  1.1231 +*/
  1.1232 +
  1.1233 +/*ARGSUSED*/
  1.1234 +static struct tm *
  1.1235 +localsub(timep, offset, tmp)
  1.1236 +const time_t * const	timep;
  1.1237 +const long		offset;
  1.1238 +struct tm * const	tmp;
  1.1239 +{
  1.1240 +	register struct state *		sp;
  1.1241 +	register const struct ttinfo *	ttisp;
  1.1242 +	register int			i;
  1.1243 +	register struct tm *		result;
  1.1244 +	const time_t			t = *timep;
  1.1245 +
  1.1246 +	sp = lclptr;
  1.1247 +#ifdef ALL_STATE
  1.1248 +	if (sp == NULL)
  1.1249 +		return gmtsub(timep, offset, tmp);
  1.1250 +#endif /* defined ALL_STATE */
  1.1251 +	if ((sp->goback && t < sp->ats[0]) ||
  1.1252 +		(sp->goahead && t > sp->ats[sp->timecnt - 1])) {
  1.1253 +			time_t			newt = t;
  1.1254 +			register time_t		seconds;
  1.1255 +			register time_t		tcycles;
  1.1256 +			register int_fast64_t	icycles;
  1.1257 +
  1.1258 +			if (t < sp->ats[0])
  1.1259 +				seconds = sp->ats[0] - t;
  1.1260 +			else	seconds = t - sp->ats[sp->timecnt - 1];
  1.1261 +			--seconds;
  1.1262 +			tcycles = seconds / YEARSPERREPEAT / AVGSECSPERYEAR;
  1.1263 +			++tcycles;
  1.1264 +			icycles = tcycles;
  1.1265 +			if (tcycles - icycles >= 1 || icycles - tcycles >= 1)
  1.1266 +				return NULL;
  1.1267 +			seconds = icycles;
  1.1268 +			seconds *= YEARSPERREPEAT;
  1.1269 +			seconds *= AVGSECSPERYEAR;
  1.1270 +			if (t < sp->ats[0])
  1.1271 +				newt += seconds;
  1.1272 +			else	newt -= seconds;
  1.1273 +			if (newt < sp->ats[0] ||
  1.1274 +				newt > sp->ats[sp->timecnt - 1])
  1.1275 +					return NULL;	/* "cannot happen" */
  1.1276 +			result = localsub(&newt, offset, tmp);
  1.1277 +			if (result == tmp) {
  1.1278 +				register time_t	newy;
  1.1279 +
  1.1280 +				newy = tmp->tm_year;
  1.1281 +				if (t < sp->ats[0])
  1.1282 +					newy -= icycles * YEARSPERREPEAT;
  1.1283 +				else	newy += icycles * YEARSPERREPEAT;
  1.1284 +				tmp->tm_year = newy;
  1.1285 +				if (tmp->tm_year != newy)
  1.1286 +					return NULL;
  1.1287 +			}
  1.1288 +			return result;
  1.1289 +	}
  1.1290 +	if (sp->timecnt == 0 || t < sp->ats[0]) {
  1.1291 +		i = 0;
  1.1292 +		while (sp->ttis[i].tt_isdst)
  1.1293 +			if (++i >= sp->typecnt) {
  1.1294 +				i = 0;
  1.1295 +				break;
  1.1296 +			}
  1.1297 +	} else {
  1.1298 +		register int	lo = 1;
  1.1299 +		register int	hi = sp->timecnt;
  1.1300 +
  1.1301 +		while (lo < hi) {
  1.1302 +			register int	mid = (lo + hi) >> 1;
  1.1303 +
  1.1304 +			if (t < sp->ats[mid])
  1.1305 +				hi = mid;
  1.1306 +			else	lo = mid + 1;
  1.1307 +		}
  1.1308 +		i = (int) sp->types[lo - 1];
  1.1309 +	}
  1.1310 +	ttisp = &sp->ttis[i];
  1.1311 +	/*
  1.1312 +	** To get (wrong) behavior that's compatible with System V Release 2.0
  1.1313 +	** you'd replace the statement below with
  1.1314 +	**	t += ttisp->tt_gmtoff;
  1.1315 +	**	timesub(&t, 0L, sp, tmp);
  1.1316 +	*/
  1.1317 +	result = timesub(&t, ttisp->tt_gmtoff, sp, tmp);
  1.1318 +	tmp->tm_isdst = ttisp->tt_isdst;
  1.1319 +	tzname[tmp->tm_isdst] = &sp->chars[ttisp->tt_abbrind];
  1.1320 +#ifdef TM_ZONE
  1.1321 +	tmp->TM_ZONE = &sp->chars[ttisp->tt_abbrind];
  1.1322 +#endif /* defined TM_ZONE */
  1.1323 +	return result;
  1.1324 +}
  1.1325 +
  1.1326 +struct tm *
  1.1327 +localtime(timep)
  1.1328 +const time_t * const	timep;
  1.1329 +{
  1.1330 +	tzset();
  1.1331 +	return localsub(timep, 0L, &tm);
  1.1332 +}
  1.1333 +
  1.1334 +/*
  1.1335 +** Re-entrant version of localtime.
  1.1336 +*/
  1.1337 +
  1.1338 +struct tm *
  1.1339 +localtime_r(timep, tmp)
  1.1340 +const time_t * const	timep;
  1.1341 +struct tm *		tmp;
  1.1342 +{
  1.1343 +	return localsub(timep, 0L, tmp);
  1.1344 +}
  1.1345 +
  1.1346 +/*
  1.1347 +** gmtsub is to gmtime as localsub is to localtime.
  1.1348 +*/
  1.1349 +
  1.1350 +static struct tm *
  1.1351 +gmtsub(timep, offset, tmp)
  1.1352 +const time_t * const	timep;
  1.1353 +const long		offset;
  1.1354 +struct tm * const	tmp;
  1.1355 +{
  1.1356 +	register struct tm *	result;
  1.1357 +
  1.1358 +	if (!gmt_is_set) {
  1.1359 +		gmt_is_set = TRUE;
  1.1360 +#ifdef ALL_STATE
  1.1361 +		gmtptr = (struct state *) malloc(sizeof *gmtptr);
  1.1362 +		if (gmtptr != NULL)
  1.1363 +#endif /* defined ALL_STATE */
  1.1364 +			gmtload(gmtptr);
  1.1365 +	}
  1.1366 +	result = timesub(timep, offset, gmtptr, tmp);
  1.1367 +#ifdef TM_ZONE
  1.1368 +	/*
  1.1369 +	** Could get fancy here and deliver something such as
  1.1370 +	** "UTC+xxxx" or "UTC-xxxx" if offset is non-zero,
  1.1371 +	** but this is no time for a treasure hunt.
  1.1372 +	*/
  1.1373 +	if (offset != 0)
  1.1374 +		tmp->TM_ZONE = wildabbr;
  1.1375 +	else {
  1.1376 +#ifdef ALL_STATE
  1.1377 +		if (gmtptr == NULL)
  1.1378 +			tmp->TM_ZONE = gmt;
  1.1379 +		else	tmp->TM_ZONE = gmtptr->chars;
  1.1380 +#endif /* defined ALL_STATE */
  1.1381 +#ifndef ALL_STATE
  1.1382 +		tmp->TM_ZONE = gmtptr->chars;
  1.1383 +#endif /* State Farm */
  1.1384 +	}
  1.1385 +#endif /* defined TM_ZONE */
  1.1386 +	return result;
  1.1387 +}
  1.1388 +
  1.1389 +struct tm *
  1.1390 +gmtime(timep)
  1.1391 +const time_t * const	timep;
  1.1392 +{
  1.1393 +	return gmtsub(timep, 0L, &tm);
  1.1394 +}
  1.1395 +
  1.1396 +/*
  1.1397 +* Re-entrant version of gmtime.
  1.1398 +*/
  1.1399 +
  1.1400 +struct tm *
  1.1401 +gmtime_r(timep, tmp)
  1.1402 +const time_t * const	timep;
  1.1403 +struct tm *		tmp;
  1.1404 +{
  1.1405 +	return gmtsub(timep, 0L, tmp);
  1.1406 +}
  1.1407 +
  1.1408 +#ifdef STD_INSPIRED
  1.1409 +
  1.1410 +struct tm *
  1.1411 +offtime(timep, offset)
  1.1412 +const time_t * const	timep;
  1.1413 +const long		offset;
  1.1414 +{
  1.1415 +	return gmtsub(timep, offset, &tm);
  1.1416 +}
  1.1417 +
  1.1418 +#endif /* defined STD_INSPIRED */
  1.1419 +
  1.1420 +/*
  1.1421 +** Return the number of leap years through the end of the given year
  1.1422 +** where, to make the math easy, the answer for year zero is defined as zero.
  1.1423 +*/
  1.1424 +
  1.1425 +static int
  1.1426 +leaps_thru_end_of(y)
  1.1427 +register const int	y;
  1.1428 +{
  1.1429 +	return (y >= 0) ? (y / 4 - y / 100 + y / 400) :
  1.1430 +		-(leaps_thru_end_of(-(y + 1)) + 1);
  1.1431 +}
  1.1432 +
  1.1433 +static struct tm *
  1.1434 +timesub(timep, offset, sp, tmp)
  1.1435 +const time_t * const			timep;
  1.1436 +const long				offset;
  1.1437 +register const struct state * const	sp;
  1.1438 +register struct tm * const		tmp;
  1.1439 +{
  1.1440 +	register const struct lsinfo *	lp;
  1.1441 +	register time_t			tdays;
  1.1442 +	register int			idays;	/* unsigned would be so 2003 */
  1.1443 +	register long			rem;
  1.1444 +	int				y;
  1.1445 +	register const int *		ip;
  1.1446 +	register long			corr;
  1.1447 +	register int			hit;
  1.1448 +	register int			i;
  1.1449 +
  1.1450 +	corr = 0;
  1.1451 +	hit = 0;
  1.1452 +#ifdef ALL_STATE
  1.1453 +	i = (sp == NULL) ? 0 : sp->leapcnt;
  1.1454 +#endif /* defined ALL_STATE */
  1.1455 +#ifndef ALL_STATE
  1.1456 +	i = sp->leapcnt;
  1.1457 +#endif /* State Farm */
  1.1458 +	while (--i >= 0) {
  1.1459 +		lp = &sp->lsis[i];
  1.1460 +		if (*timep >= lp->ls_trans) {
  1.1461 +			if (*timep == lp->ls_trans) {
  1.1462 +				hit = ((i == 0 && lp->ls_corr > 0) ||
  1.1463 +					lp->ls_corr > sp->lsis[i - 1].ls_corr);
  1.1464 +				if (hit)
  1.1465 +					while (i > 0 &&
  1.1466 +						sp->lsis[i].ls_trans ==
  1.1467 +						sp->lsis[i - 1].ls_trans + 1 &&
  1.1468 +						sp->lsis[i].ls_corr ==
  1.1469 +						sp->lsis[i - 1].ls_corr + 1) {
  1.1470 +							++hit;
  1.1471 +							--i;
  1.1472 +					}
  1.1473 +			}
  1.1474 +			corr = lp->ls_corr;
  1.1475 +			break;
  1.1476 +		}
  1.1477 +	}
  1.1478 +	y = EPOCH_YEAR;
  1.1479 +	tdays = *timep / SECSPERDAY;
  1.1480 +	rem = *timep - tdays * SECSPERDAY;
  1.1481 +	while (tdays < 0 || tdays >= year_lengths[isleap(y)]) {
  1.1482 +		int		newy;
  1.1483 +		register time_t	tdelta;
  1.1484 +		register int	idelta;
  1.1485 +		register int	leapdays;
  1.1486 +
  1.1487 +		tdelta = tdays / DAYSPERLYEAR;
  1.1488 +		idelta = tdelta;
  1.1489 +		if (tdelta - idelta >= 1 || idelta - tdelta >= 1)
  1.1490 +			return NULL;
  1.1491 +		if (idelta == 0)
  1.1492 +			idelta = (tdays < 0) ? -1 : 1;
  1.1493 +		newy = y;
  1.1494 +		if (increment_overflow(&newy, idelta))
  1.1495 +			return NULL;
  1.1496 +		leapdays = leaps_thru_end_of(newy - 1) -
  1.1497 +			leaps_thru_end_of(y - 1);
  1.1498 +		tdays -= ((time_t) newy - y) * DAYSPERNYEAR;
  1.1499 +		tdays -= leapdays;
  1.1500 +		y = newy;
  1.1501 +	}
  1.1502 +	{
  1.1503 +		register long	seconds;
  1.1504 +
  1.1505 +		seconds = tdays * SECSPERDAY + 0.5;
  1.1506 +		tdays = seconds / SECSPERDAY;
  1.1507 +		rem += seconds - tdays * SECSPERDAY;
  1.1508 +	}
  1.1509 +	/*
  1.1510 +	** Given the range, we can now fearlessly cast...
  1.1511 +	*/
  1.1512 +	idays = tdays;
  1.1513 +	rem += offset - corr;
  1.1514 +	while (rem < 0) {
  1.1515 +		rem += SECSPERDAY;
  1.1516 +		--idays;
  1.1517 +	}
  1.1518 +	while (rem >= SECSPERDAY) {
  1.1519 +		rem -= SECSPERDAY;
  1.1520 +		++idays;
  1.1521 +	}
  1.1522 +	while (idays < 0) {
  1.1523 +		if (increment_overflow(&y, -1))
  1.1524 +			return NULL;
  1.1525 +		idays += year_lengths[isleap(y)];
  1.1526 +	}
  1.1527 +	while (idays >= year_lengths[isleap(y)]) {
  1.1528 +		idays -= year_lengths[isleap(y)];
  1.1529 +		if (increment_overflow(&y, 1))
  1.1530 +			return NULL;
  1.1531 +	}
  1.1532 +	tmp->tm_year = y;
  1.1533 +	if (increment_overflow(&tmp->tm_year, -TM_YEAR_BASE))
  1.1534 +		return NULL;
  1.1535 +	tmp->tm_yday = idays;
  1.1536 +	/*
  1.1537 +	** The "extra" mods below avoid overflow problems.
  1.1538 +	*/
  1.1539 +	tmp->tm_wday = EPOCH_WDAY +
  1.1540 +		((y - EPOCH_YEAR) % DAYSPERWEEK) *
  1.1541 +		(DAYSPERNYEAR % DAYSPERWEEK) +
  1.1542 +		leaps_thru_end_of(y - 1) -
  1.1543 +		leaps_thru_end_of(EPOCH_YEAR - 1) +
  1.1544 +		idays;
  1.1545 +	tmp->tm_wday %= DAYSPERWEEK;
  1.1546 +	if (tmp->tm_wday < 0)
  1.1547 +		tmp->tm_wday += DAYSPERWEEK;
  1.1548 +	tmp->tm_hour = (int) (rem / SECSPERHOUR);
  1.1549 +	rem %= SECSPERHOUR;
  1.1550 +	tmp->tm_min = (int) (rem / SECSPERMIN);
  1.1551 +	/*
  1.1552 +	** A positive leap second requires a special
  1.1553 +	** representation. This uses "... ??:59:60" et seq.
  1.1554 +	*/
  1.1555 +	tmp->tm_sec = (int) (rem % SECSPERMIN) + hit;
  1.1556 +	ip = mon_lengths[isleap(y)];
  1.1557 +	for (tmp->tm_mon = 0; idays >= ip[tmp->tm_mon]; ++(tmp->tm_mon))
  1.1558 +		idays -= ip[tmp->tm_mon];
  1.1559 +	tmp->tm_mday = (int) (idays + 1);
  1.1560 +	tmp->tm_isdst = 0;
  1.1561 +#ifdef TM_GMTOFF
  1.1562 +	tmp->TM_GMTOFF = offset;
  1.1563 +#endif /* defined TM_GMTOFF */
  1.1564 +	return tmp;
  1.1565 +}
  1.1566 +
  1.1567 +char *
  1.1568 +ctime(timep)
  1.1569 +const time_t * const	timep;
  1.1570 +{
  1.1571 +/*
  1.1572 +** Section 4.12.3.2 of X3.159-1989 requires that
  1.1573 +**	The ctime function converts the calendar time pointed to by timer
  1.1574 +**	to local time in the form of a string. It is equivalent to
  1.1575 +**		asctime(localtime(timer))
  1.1576 +*/
  1.1577 +	return asctime(localtime(timep));
  1.1578 +}
  1.1579 +
  1.1580 +char *
  1.1581 +ctime_r(timep, buf)
  1.1582 +const time_t * const	timep;
  1.1583 +char *			buf;
  1.1584 +{
  1.1585 +	struct tm	mytm;
  1.1586 +
  1.1587 +	return asctime_r(localtime_r(timep, &mytm), buf);
  1.1588 +}
  1.1589 +
  1.1590 +/*
  1.1591 +** Adapted from code provided by Robert Elz, who writes:
  1.1592 +**	The "best" way to do mktime I think is based on an idea of Bob
  1.1593 +**	Kridle's (so its said...) from a long time ago.
  1.1594 +**	It does a binary search of the time_t space. Since time_t's are
  1.1595 +**	just 32 bits, its a max of 32 iterations (even at 64 bits it
  1.1596 +**	would still be very reasonable).
  1.1597 +*/
  1.1598 +
  1.1599 +#ifndef WRONG
  1.1600 +#define WRONG	(-1)
  1.1601 +#endif /* !defined WRONG */
  1.1602 +
  1.1603 +/*
  1.1604 +** Simplified normalize logic courtesy Paul Eggert.
  1.1605 +*/
  1.1606 +
  1.1607 +static int
  1.1608 +increment_overflow(number, delta)
  1.1609 +int *	number;
  1.1610 +int	delta;
  1.1611 +{
  1.1612 +	int	number0;
  1.1613 +
  1.1614 +	number0 = *number;
  1.1615 +	*number += delta;
  1.1616 +	return (*number < number0) != (delta < 0);
  1.1617 +}
  1.1618 +
  1.1619 +static int
  1.1620 +long_increment_overflow(number, delta)
  1.1621 +long *	number;
  1.1622 +int	delta;
  1.1623 +{
  1.1624 +	long	number0;
  1.1625 +
  1.1626 +	number0 = *number;
  1.1627 +	*number += delta;
  1.1628 +	return (*number < number0) != (delta < 0);
  1.1629 +}
  1.1630 +
  1.1631 +static int
  1.1632 +normalize_overflow(tensptr, unitsptr, base)
  1.1633 +int * const	tensptr;
  1.1634 +int * const	unitsptr;
  1.1635 +const int	base;
  1.1636 +{
  1.1637 +	register int	tensdelta;
  1.1638 +
  1.1639 +	tensdelta = (*unitsptr >= 0) ?
  1.1640 +		(*unitsptr / base) :
  1.1641 +		(-1 - (-1 - *unitsptr) / base);
  1.1642 +	*unitsptr -= tensdelta * base;
  1.1643 +	return increment_overflow(tensptr, tensdelta);
  1.1644 +}
  1.1645 +
  1.1646 +static int
  1.1647 +long_normalize_overflow(tensptr, unitsptr, base)
  1.1648 +long * const	tensptr;
  1.1649 +int * const	unitsptr;
  1.1650 +const int	base;
  1.1651 +{
  1.1652 +	register int	tensdelta;
  1.1653 +
  1.1654 +	tensdelta = (*unitsptr >= 0) ?
  1.1655 +		(*unitsptr / base) :
  1.1656 +		(-1 - (-1 - *unitsptr) / base);
  1.1657 +	*unitsptr -= tensdelta * base;
  1.1658 +	return long_increment_overflow(tensptr, tensdelta);
  1.1659 +}
  1.1660 +
  1.1661 +static int
  1.1662 +tmcomp(atmp, btmp)
  1.1663 +register const struct tm * const atmp;
  1.1664 +register const struct tm * const btmp;
  1.1665 +{
  1.1666 +	register int	result;
  1.1667 +
  1.1668 +	if ((result = (atmp->tm_year - btmp->tm_year)) == 0 &&
  1.1669 +		(result = (atmp->tm_mon - btmp->tm_mon)) == 0 &&
  1.1670 +		(result = (atmp->tm_mday - btmp->tm_mday)) == 0 &&
  1.1671 +		(result = (atmp->tm_hour - btmp->tm_hour)) == 0 &&
  1.1672 +		(result = (atmp->tm_min - btmp->tm_min)) == 0)
  1.1673 +			result = atmp->tm_sec - btmp->tm_sec;
  1.1674 +	return result;
  1.1675 +}
  1.1676 +
  1.1677 +static time_t
  1.1678 +time2sub(tmp, funcp, offset, okayp, do_norm_secs)
  1.1679 +struct tm * const	tmp;
  1.1680 +struct tm * (* const	funcp)(const time_t*, long, struct tm*);
  1.1681 +const long		offset;
  1.1682 +int * const		okayp;
  1.1683 +const int		do_norm_secs;
  1.1684 +{
  1.1685 +	register const struct state *	sp;
  1.1686 +	register int			dir;
  1.1687 +	register int			i, j;
  1.1688 +	register int			saved_seconds;
  1.1689 +	register long			li;
  1.1690 +	register time_t			lo;
  1.1691 +	register time_t			hi;
  1.1692 +	long				y;
  1.1693 +	time_t				newt;
  1.1694 +	time_t				t;
  1.1695 +	struct tm			yourtm, mytm;
  1.1696 +
  1.1697 +	*okayp = FALSE;
  1.1698 +	yourtm = *tmp;
  1.1699 +	if (do_norm_secs) {
  1.1700 +		if (normalize_overflow(&yourtm.tm_min, &yourtm.tm_sec,
  1.1701 +			SECSPERMIN))
  1.1702 +				return WRONG;
  1.1703 +	}
  1.1704 +	if (normalize_overflow(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR))
  1.1705 +		return WRONG;
  1.1706 +	if (normalize_overflow(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY))
  1.1707 +		return WRONG;
  1.1708 +	y = yourtm.tm_year;
  1.1709 +	if (long_normalize_overflow(&y, &yourtm.tm_mon, MONSPERYEAR))
  1.1710 +		return WRONG;
  1.1711 +	/*
  1.1712 +	** Turn y into an actual year number for now.
  1.1713 +	** It is converted back to an offset from TM_YEAR_BASE later.
  1.1714 +	*/
  1.1715 +	if (long_increment_overflow(&y, TM_YEAR_BASE))
  1.1716 +		return WRONG;
  1.1717 +	while (yourtm.tm_mday <= 0) {
  1.1718 +		if (long_increment_overflow(&y, -1))
  1.1719 +			return WRONG;
  1.1720 +		li = y + (1 < yourtm.tm_mon);
  1.1721 +		yourtm.tm_mday += year_lengths[isleap(li)];
  1.1722 +	}
  1.1723 +	while (yourtm.tm_mday > DAYSPERLYEAR) {
  1.1724 +		li = y + (1 < yourtm.tm_mon);
  1.1725 +		yourtm.tm_mday -= year_lengths[isleap(li)];
  1.1726 +		if (long_increment_overflow(&y, 1))
  1.1727 +			return WRONG;
  1.1728 +	}
  1.1729 +	for ( ; ; ) {
  1.1730 +		i = mon_lengths[isleap(y)][yourtm.tm_mon];
  1.1731 +		if (yourtm.tm_mday <= i)
  1.1732 +			break;
  1.1733 +		yourtm.tm_mday -= i;
  1.1734 +		if (++yourtm.tm_mon >= MONSPERYEAR) {
  1.1735 +			yourtm.tm_mon = 0;
  1.1736 +			if (long_increment_overflow(&y, 1))
  1.1737 +				return WRONG;
  1.1738 +		}
  1.1739 +	}
  1.1740 +	if (long_increment_overflow(&y, -TM_YEAR_BASE))
  1.1741 +		return WRONG;
  1.1742 +	yourtm.tm_year = y;
  1.1743 +	if (yourtm.tm_year != y)
  1.1744 +		return WRONG;
  1.1745 +	if (yourtm.tm_sec >= 0 && yourtm.tm_sec < SECSPERMIN)
  1.1746 +		saved_seconds = 0;
  1.1747 +	else if (y + TM_YEAR_BASE < EPOCH_YEAR) {
  1.1748 +		/*
  1.1749 +		** We can't set tm_sec to 0, because that might push the
  1.1750 +		** time below the minimum representable time.
  1.1751 +		** Set tm_sec to 59 instead.
  1.1752 +		** This assumes that the minimum representable time is
  1.1753 +		** not in the same minute that a leap second was deleted from,
  1.1754 +		** which is a safer assumption than using 58 would be.
  1.1755 +		*/
  1.1756 +		if (increment_overflow(&yourtm.tm_sec, 1 - SECSPERMIN))
  1.1757 +			return WRONG;
  1.1758 +		saved_seconds = yourtm.tm_sec;
  1.1759 +		yourtm.tm_sec = SECSPERMIN - 1;
  1.1760 +	} else {
  1.1761 +		saved_seconds = yourtm.tm_sec;
  1.1762 +		yourtm.tm_sec = 0;
  1.1763 +	}
  1.1764 +	/*
  1.1765 +	** Do a binary search (this works whatever time_t's type is).
  1.1766 +	*/
  1.1767 +	if (!TYPE_SIGNED(time_t)) {
  1.1768 +		lo = 0;
  1.1769 +		hi = lo - 1;
  1.1770 +	} else if (!TYPE_INTEGRAL(time_t)) {
  1.1771 +		if (sizeof(time_t) > sizeof(float))
  1.1772 +			hi = (time_t) DBL_MAX;
  1.1773 +		else	hi = (time_t) FLT_MAX;
  1.1774 +		lo = -hi;
  1.1775 +	} else {
  1.1776 +		lo = 1;
  1.1777 +		for (i = 0; i < (int) TYPE_BIT(time_t) - 1; ++i)
  1.1778 +			lo *= 2;
  1.1779 +		hi = -(lo + 1);
  1.1780 +	}
  1.1781 +	for ( ; ; ) {
  1.1782 +		t = lo / 2 + hi / 2;
  1.1783 +		if (t < lo)
  1.1784 +			t = lo;
  1.1785 +		else if (t > hi)
  1.1786 +			t = hi;
  1.1787 +		if ((*funcp)(&t, offset, &mytm) == NULL) {
  1.1788 +			/*
  1.1789 +			** Assume that t is too extreme to be represented in
  1.1790 +			** a struct tm; arrange things so that it is less
  1.1791 +			** extreme on the next pass.
  1.1792 +			*/
  1.1793 +			dir = (t > 0) ? 1 : -1;
  1.1794 +		} else	dir = tmcomp(&mytm, &yourtm);
  1.1795 +		if (dir != 0) {
  1.1796 +			if (t == lo) {
  1.1797 +				++t;
  1.1798 +				if (t <= lo)
  1.1799 +					return WRONG;
  1.1800 +				++lo;
  1.1801 +			} else if (t == hi) {
  1.1802 +				--t;
  1.1803 +				if (t >= hi)
  1.1804 +					return WRONG;
  1.1805 +				--hi;
  1.1806 +			}
  1.1807 +			if (lo > hi)
  1.1808 +				return WRONG;
  1.1809 +			if (dir > 0)
  1.1810 +				hi = t;
  1.1811 +			else	lo = t;
  1.1812 +			continue;
  1.1813 +		}
  1.1814 +		if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst)
  1.1815 +			break;
  1.1816 +		/*
  1.1817 +		** Right time, wrong type.
  1.1818 +		** Hunt for right time, right type.
  1.1819 +		** It's okay to guess wrong since the guess
  1.1820 +		** gets checked.
  1.1821 +		*/
  1.1822 +		sp = (const struct state *)
  1.1823 +			((funcp == localsub) ? lclptr : gmtptr);
  1.1824 +#ifdef ALL_STATE
  1.1825 +		if (sp == NULL)
  1.1826 +			return WRONG;
  1.1827 +#endif /* defined ALL_STATE */
  1.1828 +		for (i = sp->typecnt - 1; i >= 0; --i) {
  1.1829 +			if (sp->ttis[i].tt_isdst != yourtm.tm_isdst)
  1.1830 +				continue;
  1.1831 +			for (j = sp->typecnt - 1; j >= 0; --j) {
  1.1832 +				if (sp->ttis[j].tt_isdst == yourtm.tm_isdst)
  1.1833 +					continue;
  1.1834 +				newt = t + sp->ttis[j].tt_gmtoff -
  1.1835 +					sp->ttis[i].tt_gmtoff;
  1.1836 +				if ((*funcp)(&newt, offset, &mytm) == NULL)
  1.1837 +					continue;
  1.1838 +				if (tmcomp(&mytm, &yourtm) != 0)
  1.1839 +					continue;
  1.1840 +				if (mytm.tm_isdst != yourtm.tm_isdst)
  1.1841 +					continue;
  1.1842 +				/*
  1.1843 +				** We have a match.
  1.1844 +				*/
  1.1845 +				t = newt;
  1.1846 +				goto label;
  1.1847 +			}
  1.1848 +		}
  1.1849 +		return WRONG;
  1.1850 +	}
  1.1851 +label:
  1.1852 +	newt = t + saved_seconds;
  1.1853 +	if ((newt < t) != (saved_seconds < 0))
  1.1854 +		return WRONG;
  1.1855 +	t = newt;
  1.1856 +	if ((*funcp)(&t, offset, tmp))
  1.1857 +		*okayp = TRUE;
  1.1858 +	return t;
  1.1859 +}
  1.1860 +
  1.1861 +static time_t
  1.1862 +time2(tmp, funcp, offset, okayp)
  1.1863 +struct tm * const	tmp;
  1.1864 +struct tm * (* const	funcp)(const time_t*, long, struct tm*);
  1.1865 +const long		offset;
  1.1866 +int * const		okayp;
  1.1867 +{
  1.1868 +	time_t	t;
  1.1869 +
  1.1870 +	/*
  1.1871 +	** First try without normalization of seconds
  1.1872 +	** (in case tm_sec contains a value associated with a leap second).
  1.1873 +	** If that fails, try with normalization of seconds.
  1.1874 +	*/
  1.1875 +	t = time2sub(tmp, funcp, offset, okayp, FALSE);
  1.1876 +	return *okayp ? t : time2sub(tmp, funcp, offset, okayp, TRUE);
  1.1877 +}
  1.1878 +
  1.1879 +static time_t
  1.1880 +time1(tmp, funcp, offset)
  1.1881 +struct tm * const	tmp;
  1.1882 +struct tm * (* const	funcp)(const time_t *, long, struct tm *);
  1.1883 +const long		offset;
  1.1884 +{
  1.1885 +	register time_t			t;
  1.1886 +	register const struct state *	sp;
  1.1887 +	register int			samei, otheri;
  1.1888 +	register int			sameind, otherind;
  1.1889 +	register int			i;
  1.1890 +	register int			nseen;
  1.1891 +	int				seen[TZ_MAX_TYPES];
  1.1892 +	int				types[TZ_MAX_TYPES];
  1.1893 +	int				okay;
  1.1894 +
  1.1895 +	if (tmp->tm_isdst > 1)
  1.1896 +		tmp->tm_isdst = 1;
  1.1897 +	t = time2(tmp, funcp, offset, &okay);
  1.1898 +#ifdef PCTS
  1.1899 +	/*
  1.1900 +	** PCTS code courtesy Grant Sullivan.
  1.1901 +	*/
  1.1902 +	if (okay)
  1.1903 +		return t;
  1.1904 +	if (tmp->tm_isdst < 0)
  1.1905 +		tmp->tm_isdst = 0;	/* reset to std and try again */
  1.1906 +#endif /* defined PCTS */
  1.1907 +#ifndef PCTS
  1.1908 +	if (okay || tmp->tm_isdst < 0)
  1.1909 +		return t;
  1.1910 +#endif /* !defined PCTS */
  1.1911 +	/*
  1.1912 +	** We're supposed to assume that somebody took a time of one type
  1.1913 +	** and did some math on it that yielded a "struct tm" that's bad.
  1.1914 +	** We try to divine the type they started from and adjust to the
  1.1915 +	** type they need.
  1.1916 +	*/
  1.1917 +	sp = (const struct state *) ((funcp == localsub) ?  lclptr : gmtptr);
  1.1918 +#ifdef ALL_STATE
  1.1919 +	if (sp == NULL)
  1.1920 +		return WRONG;
  1.1921 +#endif /* defined ALL_STATE */
  1.1922 +	for (i = 0; i < sp->typecnt; ++i)
  1.1923 +		seen[i] = FALSE;
  1.1924 +	nseen = 0;
  1.1925 +	for (i = sp->timecnt - 1; i >= 0; --i)
  1.1926 +		if (!seen[sp->types[i]]) {
  1.1927 +			seen[sp->types[i]] = TRUE;
  1.1928 +			types[nseen++] = sp->types[i];
  1.1929 +		}
  1.1930 +	for (sameind = 0; sameind < nseen; ++sameind) {
  1.1931 +		samei = types[sameind];
  1.1932 +		if (sp->ttis[samei].tt_isdst != tmp->tm_isdst)
  1.1933 +			continue;
  1.1934 +		for (otherind = 0; otherind < nseen; ++otherind) {
  1.1935 +			otheri = types[otherind];
  1.1936 +			if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst)
  1.1937 +				continue;
  1.1938 +			tmp->tm_sec += sp->ttis[otheri].tt_gmtoff -
  1.1939 +					sp->ttis[samei].tt_gmtoff;
  1.1940 +			tmp->tm_isdst = !tmp->tm_isdst;
  1.1941 +			t = time2(tmp, funcp, offset, &okay);
  1.1942 +			if (okay)
  1.1943 +				return t;
  1.1944 +			tmp->tm_sec -= sp->ttis[otheri].tt_gmtoff -
  1.1945 +					sp->ttis[samei].tt_gmtoff;
  1.1946 +			tmp->tm_isdst = !tmp->tm_isdst;
  1.1947 +		}
  1.1948 +	}
  1.1949 +	return WRONG;
  1.1950 +}
  1.1951 +
  1.1952 +time_t
  1.1953 +mktime(tmp)
  1.1954 +struct tm * const	tmp;
  1.1955 +{
  1.1956 +	tzset();
  1.1957 +	return time1(tmp, localsub, 0L);
  1.1958 +}
  1.1959 +
  1.1960 +#ifdef STD_INSPIRED
  1.1961 +
  1.1962 +time_t
  1.1963 +timelocal(tmp)
  1.1964 +struct tm * const	tmp;
  1.1965 +{
  1.1966 +	tmp->tm_isdst = -1;	/* in case it wasn't initialized */
  1.1967 +	return mktime(tmp);
  1.1968 +}
  1.1969 +
  1.1970 +time_t
  1.1971 +timegm(tmp)
  1.1972 +struct tm * const	tmp;
  1.1973 +{
  1.1974 +	tmp->tm_isdst = 0;
  1.1975 +	return time1(tmp, gmtsub, 0L);
  1.1976 +}
  1.1977 +
  1.1978 +time_t
  1.1979 +timeoff(tmp, offset)
  1.1980 +struct tm * const	tmp;
  1.1981 +const long		offset;
  1.1982 +{
  1.1983 +	tmp->tm_isdst = 0;
  1.1984 +	return time1(tmp, gmtsub, offset);
  1.1985 +}
  1.1986 +
  1.1987 +#endif /* defined STD_INSPIRED */
  1.1988 +
  1.1989 +#ifdef CMUCS
  1.1990 +
  1.1991 +/*
  1.1992 +** The following is supplied for compatibility with
  1.1993 +** previous versions of the CMUCS runtime library.
  1.1994 +*/
  1.1995 +
  1.1996 +long
  1.1997 +gtime(tmp)
  1.1998 +struct tm * const	tmp;
  1.1999 +{
  1.2000 +	const time_t	t = mktime(tmp);
  1.2001 +
  1.2002 +	if (t == WRONG)
  1.2003 +		return -1;
  1.2004 +	return t;
  1.2005 +}
  1.2006 +
  1.2007 +#endif /* defined CMUCS */
  1.2008 +
  1.2009 +/*
  1.2010 +** XXX--is the below the right way to conditionalize??
  1.2011 +*/
  1.2012 +
  1.2013 +#ifdef STD_INSPIRED
  1.2014 +
  1.2015 +/*
  1.2016 +** IEEE Std 1003.1-1988 (POSIX) legislates that 536457599
  1.2017 +** shall correspond to "Wed Dec 31 23:59:59 UTC 1986", which
  1.2018 +** is not the case if we are accounting for leap seconds.
  1.2019 +** So, we provide the following conversion routines for use
  1.2020 +** when exchanging timestamps with POSIX conforming systems.
  1.2021 +*/
  1.2022 +
  1.2023 +static long
  1.2024 +leapcorr(timep)
  1.2025 +time_t *	timep;
  1.2026 +{
  1.2027 +	register struct state *		sp;
  1.2028 +	register struct lsinfo *	lp;
  1.2029 +	register int			i;
  1.2030 +
  1.2031 +	sp = lclptr;
  1.2032 +	i = sp->leapcnt;
  1.2033 +	while (--i >= 0) {
  1.2034 +		lp = &sp->lsis[i];
  1.2035 +		if (*timep >= lp->ls_trans)
  1.2036 +			return lp->ls_corr;
  1.2037 +	}
  1.2038 +	return 0;
  1.2039 +}
  1.2040 +
  1.2041 +time_t
  1.2042 +time2posix(t)
  1.2043 +time_t	t;
  1.2044 +{
  1.2045 +	tzset();
  1.2046 +	return t - leapcorr(&t);
  1.2047 +}
  1.2048 +
  1.2049 +time_t
  1.2050 +posix2time(t)
  1.2051 +time_t	t;
  1.2052 +{
  1.2053 +	time_t	x;
  1.2054 +	time_t	y;
  1.2055 +
  1.2056 +	tzset();
  1.2057 +	/*
  1.2058 +	** For a positive leap second hit, the result
  1.2059 +	** is not unique. For a negative leap second
  1.2060 +	** hit, the corresponding time doesn't exist,
  1.2061 +	** so we return an adjacent second.
  1.2062 +	*/
  1.2063 +	x = t + leapcorr(&t);
  1.2064 +	y = x - leapcorr(&x);
  1.2065 +	if (y < t) {
  1.2066 +		do {
  1.2067 +			x++;
  1.2068 +			y = x - leapcorr(&x);
  1.2069 +		} while (y < t);
  1.2070 +		if (t != y)
  1.2071 +			return x - 1;
  1.2072 +	} else if (y > t) {
  1.2073 +		do {
  1.2074 +			--x;
  1.2075 +			y = x - leapcorr(&x);
  1.2076 +		} while (y > t);
  1.2077 +		if (t != y)
  1.2078 +			return x + 1;
  1.2079 +	}
  1.2080 +	return x;
  1.2081 +}
  1.2082 +
  1.2083 +#endif /* defined STD_INSPIRED */

mercurial