Ejemplo n.º 1
0
TzTransitionList parseTimeZone(const char* tzName)
{
	static const char* zoneInfoDir = "/usr/share/zoneinfo/";
	static const char* etcZoneInfoDir = "/usr/share/zoneinfo/Etc/";
	std::string filePath = zoneInfoDir;
	filePath += tzName;
	
	struct stat stBuf;
	FILE* fp = fopen(filePath.c_str(), "r");
	if (!fp && errno == ENOENT)
	{
		// if file not found - try alternative filePath
		printf("Failed to find file: %s\n", filePath.c_str());

		filePath = etcZoneInfoDir;
		filePath += tzName;

		fp = fopen(filePath.c_str(), "r");
		if (!fp && errno == ENOENT)
		{
			printf("Failed to find second try file: %s\n", filePath.c_str());
			return TzTransitionList();
		}
	}
	if (fp)
	{
		if (fstat(fileno(fp), &stBuf) != 0)
		{
			printf("Failed to stat opened file: %s\n", filePath.c_str());
			fclose(fp);
			return TzTransitionList();
		}

		if (stBuf.st_size <= (int) sizeof(tzhead)) {
			printf("file too short to be a tz file: %s\n", filePath.c_str());
			fclose(fp);
			return TzTransitionList();
		}
	}
	else
	{
		printf("Failed to open file: %s\n", filePath.c_str());
		return TzTransitionList();
	}	

	char* buf = (char*) malloc(stBuf.st_size);
	size_t size = fread(buf, 1, stBuf.st_size, fp);
	fclose(fp);

	if (size != (size_t) stBuf.st_size) {
		printf("Short read on file: %s\n", filePath.c_str());
		free(buf);
		return TzTransitionList();
	}

	ttentrylist       ttEntryList;
	ttinfolist        ttInfoList;
	std::vector<char> ttAbbrList;

	/*
	  The  time zone information files used by tzset(3) begin with the
	  magic characters "TZif" to identify then as time zone information
	  files, followed by sixteen bytes reserved for future use,
	  followed by six four-byte values of type long, written in  a  "standard"
	  byte order (the high-order byte of the value is written first).
	  These values are, in order:

       tzh_ttisgmtcnt
              The number of UTC/local indicators stored in the file.

       tzh_ttisstdcnt
              The number of standard/wall indicators stored in the file.

       tzh_leapcnt
              The number of leap seconds for which data is stored in the file.

       tzh_timecnt
              The number of "transition times" for which data is stored in the file.

       tzh_typecnt
              The number of "local time types" for which data is stored in the file (must not be zero).

       tzh_charcnt
              The number of characters of "time zone abbreviation strings" stored in the file.
	*/
	
	long isGmt = 0;
	long isStd = 0;  
	long leapCnt = 0;
	long timeCnt = 0;
	long typeCnt = 0;	
	long charCnt = 0;

	(void) isGmt;
	(void) isStd;
	(void) leapCnt;
	(void) timeCnt;
	(void) typeCnt;
	(void) charCnt;
	
	int index = 0;
	for (int stored = 4; stored <= 8; stored *= 2) {

		DBG("-----------------------------------------------------\n");

		if (memcmp(buf, TZ_MAGIC, 4) != 0) {
			printf("Not a tz file. Header signature mismatch: %s\n", filePath.c_str());
			free(buf);
			return TzTransitionList();
		}
		
		struct tzhead* head = (struct tzhead*) (buf + index);

		isGmt   = detzcode(head->tzh_ttisgmtcnt);
		isStd   = detzcode(head->tzh_ttisstdcnt);
		leapCnt = detzcode(head->tzh_leapcnt);
		timeCnt = detzcode(head->tzh_timecnt);
		typeCnt = detzcode(head->tzh_typecnt);
		charCnt = detzcode(head->tzh_charcnt);

		ttInfoList.clear();
		ttInfoList.reserve(timeCnt);

		ttEntryList.clear();
		ttEntryList.reserve(typeCnt);

		ttAbbrList.clear();
		ttAbbrList.reserve(charCnt + 1);

		index += sizeof(struct tzhead);
	
		DBG("tzh_ttisgmtcnt: %ld\n", isGmt);
		DBG("tzh_ttisstdcnt: %ld\n", isStd);
		DBG("tzh_leapcnt: %ld\n", leapCnt);
		DBG("tzh_timecnt: %ld\n", timeCnt);
		DBG("tzh_typecnt: %ld\n", typeCnt);
		DBG("tzh_charcnt: %ld\n", charCnt);

		/* The  above  header  is followed by tzh_timecnt four-byte values of type
		   long, sorted in ascending order.  These values are  written  in  "standard"
		   byte  order.   Each is used as a transition time (as returned by
		   time(2)) at which the rules for computing local time change. */
		for (long i = 0; i < timeCnt; i++) {
			time_t time;
			time = (stored == 4) ? detzcode(buf + index) : detzcode64(buf + index);
			index += stored;
			
			ttentry e;
			e.time = time;
			ttEntryList.push_back(e);

			DBG("tzh_timecnt: Time: %ld, %s", time, asctime(gmtime(&time)));			
		}

		/* Next come tzh_timecnt one-byte values of type unsigned char;
		   each one tells which of the different types of "local time"
		   types described in the file is associated with the same-indexed
		   transition time. */
		for (long i = 0; i < timeCnt; i++) {
			unsigned char indexToLocalTime = (unsigned char) buf[index];
			index++;

			ttEntryList[i].indexToLocalTime = indexToLocalTime;
			
			DBG("tzh_timecnt: Index: %d\n", indexToLocalTime);			
		}

		/* These values serve as indices into an  array  of
		   ttinfo structures that appears next in the file; these structures are
		   defined as follows:

           struct ttinfo {
		   long         tt_gmtoff;
		   int          tt_isdst;
		   unsigned int tt_abbrind;
           };

		   Each  structure is written as a four-byte value for tt_gmtoff of type
		   long, in a standard byte order, followed by a one-byte value
		   for tt_isdst and a one-byte value for tt_abbrind.  In each structure,
		   tt_gmtoff gives the number of seconds to be  added  to  UTC,
		   tt_isdst  tells  whether  tm_isdst  should  be  set by localtime(3),
		   and tt_abbrind serves as an index into the array of time zone
		   abbreviation characters that follow the ttinfo structure(s) in the file. */
		for (long i = 0; i < typeCnt; i++) {

			ttinfo ttInfo;
			ttInfo.gmtOffset = detzcode(buf + index);
			index += 4;
			ttInfo.isDst = (unsigned char) buf[index];
			index++;
			ttInfo.abbrIndex = (unsigned char) buf[index];
			index++;

			ttInfoList.push_back(ttInfo);

			DBG("gmtOff: %ld, isDst: %d, abbrind: %d\n",
				ttInfo.gmtOffset, ttInfo.isDst, ttInfo.abbrIndex);
		}

		DBG("abbrev: ");
		for (long i = 0; i < charCnt; i++) {
			DBG("%c", buf[index]);
			ttAbbrList.push_back(buf[index]);
			index++;
		}
		ttAbbrList.push_back(0);
		DBG("\n");

		/* Then there are tzh_leapcnt pairs of four-byte values,
		   written in standard byte order; the first value of each
		   pair gives the  time (as  returned by time(2)) at which a leap
		   second occurs; the second gives the total number of leap seconds
		   to be applied after the given time.  The pairs of values are
		   sorted in ascending order by time. */
		for (long i = 0; i < leapCnt; i++) {

			long leapTime = (stored == 4) ? detzcode(buf + index)
							: detzcode64(buf + index);
			index += stored;

			long leapSeconds = detzcode(buf + index);
			index += 4;

			(void) leapTime;
			(void) leapSeconds;

			DBG("leapTime: %ld, leapSeconds: %ld\n",
				leapTime, leapSeconds);
		}

		/*
		  Then there are tzh_ttisstdcnt standard/wall indicators, each
		  stored as a one-byte value; they tell whether the  transition
		  times associated with local time types were specified as standard
		  time or wall clock time, and are used when a time zone file is
		  used in handling POSIX-style time zone environment variables.
		*/
		for (long i = 0; i < typeCnt; i++) {

			int standardOrWallClock = (unsigned char) buf[index];
			index++;

			(void) standardOrWallClock;
			DBG("standardOrWallClock: %d\n", standardOrWallClock);
		}
	

		/*
		  Finally, there are tzh_ttisgmtcnt UTC/local indicators,
		  each stored as a one-byte value; they tell whether  the
		  transition  times associated  with  local  time  types  were
		  specified as UTC or local time, and are used when a time zone
		  file is used in handling POSIX-style time zone environment variables.
		*/
		for (long i = 0; i < typeCnt; i++) {

			int utcOrLocalTime = (unsigned char) buf[index];
			index++;

			(void) utcOrLocalTime;
			DBG("utcOrLocalTime: %d\n", utcOrLocalTime);
		}

		/*
		  Localtime uses the first standard-time ttinfo structure in the file
		  (or simply the first ttinfo structure  in  the  absence  of  a
		  standard-time structure) if either tzh_timecnt is zero or the time
		  argument is less than the first transition time recorded in the
		  file.
		*/

		/*
		 * Out-of-sort ats should mean we're running on a
		 * signed time_t system but using a data file with
		 * unsigned values (or vice versa).
		 */
		for (int i = 0; i < timeCnt - 2; ++i) {
			if (ttEntryList[i].time > ttEntryList[i+1].time) {
				++i;
				if (TYPE_SIGNED(time_t)) {
					// Ignore the end (easy).
					timeCnt = i;
				} else {
					// Ignore the beginning (harder).
					int j;
					for (j = 0; (j + i) < timeCnt; ++j) {
						ttEntryList[j] = ttEntryList[j+i];
					}
					timeCnt = j;
				}
				break;
			}
		}

		/*
		 * If this is an old file, we're done.
		 */
		if (head->tzh_version[0] == '\0') {
			DBG("Version 0 file. breaking\n");
			break;
		}

		/*
		 * If this is a narrow integer time_t system, we're done.
		 */
		if ((stored >= (int) sizeof(time_t)) && (TYPE_INTEGRAL(time_t))) {
			DBG("narrow integer time_t system. breaking\n");
			break;
		}
	}
	
	DBG("Total Buffer size parsed: %d\n", index);
	
	free(buf);

	// Dummy entry for standardized timezones which never had
	// a transition time
	if (ttEntryList.empty() && !ttInfoList.empty()) {
		ttentry e;
		timeCnt = 1;
		e.time = -2147483648UL;
		e.indexToLocalTime = 0;
		ttEntryList.push_back(e);		
	}

	TzTransitionList result;
	for (int i = 0; i < timeCnt; i++) {
		const ttentry& entry = ttEntryList[i];
		const ttinfo& info   = ttInfoList[entry.indexToLocalTime];
		struct tm* gmTime    = gmtime(&entry.time);
		
		TzTransition trans;
		trans.time        = entry.time;
		trans.utcOffset   = info.gmtOffset;
		trans.isDst       = info.isDst;
		trans.year        = gmTime->tm_year + 1900;
		trans.abbrName[0] = 0;

		int j = info.abbrIndex;
		int k = 0;
		for (; (j < (int) ttAbbrList.size()) && (k < TZ_ABBR_MAX_LEN);
			 j++, k++) {
			trans.abbrName[k] = ttAbbrList[j];
			if (ttAbbrList[j] == 0)
				break;
		}
		trans.abbrName[TZ_ABBR_MAX_LEN-1] = 0;

		result.push_back(trans);
	}

	return result;
}
Ejemplo n.º 2
0
int
tzload(const char *name, char *canonname, struct state * sp, int doextend)
{
	const char *p;
	int			i;
	int			fid;
	int			stored;
	int			nread;
	union
	{
		struct tzhead tzhead;
		char		buf[2 * sizeof(struct tzhead) +
									2 * sizeof *sp +
									4 * TZ_MAX_TIMES];
	}			u;

	sp->goback = sp->goahead = FALSE;
	if (name == NULL && (name = TZDEFAULT) == NULL)
		return -1;
	if (name[0] == ':')
		++name;
	fid = pg_open_tzfile(name, canonname);
	if (fid < 0)
		return -1;
	nread = read(fid, u.buf, sizeof u.buf);
	if (close(fid) != 0 || nread <= 0)
		return -1;
	for (stored = 4; stored <= 8; stored *= 2)
	{
		int			ttisstdcnt;
		int			ttisgmtcnt;

		ttisstdcnt = (int) detzcode(u.tzhead.tzh_ttisstdcnt);
		ttisgmtcnt = (int) detzcode(u.tzhead.tzh_ttisgmtcnt);
		sp->leapcnt = (int) detzcode(u.tzhead.tzh_leapcnt);
		sp->timecnt = (int) detzcode(u.tzhead.tzh_timecnt);
		sp->typecnt = (int) detzcode(u.tzhead.tzh_typecnt);
		sp->charcnt = (int) detzcode(u.tzhead.tzh_charcnt);
		p = u.tzhead.tzh_charcnt + sizeof u.tzhead.tzh_charcnt;
		if (sp->leapcnt < 0 || sp->leapcnt > TZ_MAX_LEAPS ||
			sp->typecnt <= 0 || sp->typecnt > TZ_MAX_TYPES ||
			sp->timecnt < 0 || sp->timecnt > TZ_MAX_TIMES ||
			sp->charcnt < 0 || sp->charcnt > TZ_MAX_CHARS ||
			(ttisstdcnt != sp->typecnt && ttisstdcnt != 0) ||
			(ttisgmtcnt != sp->typecnt && ttisgmtcnt != 0))
			return -1;
		if (nread - (p - u.buf) <
			sp->timecnt * stored +		/* ats */
			sp->timecnt +		/* types */
			sp->typecnt * 6 +	/* ttinfos */
			sp->charcnt +		/* chars */
			sp->leapcnt * (stored + 4) +		/* lsinfos */
			ttisstdcnt +		/* ttisstds */
			ttisgmtcnt)			/* ttisgmts */
			return -1;
		for (i = 0; i < sp->timecnt; ++i)
		{
			sp->ats[i] = (stored == 4) ? detzcode(p) : detzcode64(p);
			p += stored;
		}
		for (i = 0; i < sp->timecnt; ++i)
		{
			sp->types[i] = (unsigned char) *p++;
			if (sp->types[i] >= sp->typecnt)
				return -1;
		}
		for (i = 0; i < sp->typecnt; ++i)
		{
			struct ttinfo *ttisp;

			ttisp = &sp->ttis[i];
			ttisp->tt_gmtoff = detzcode(p);
			p += 4;
			ttisp->tt_isdst = (unsigned char) *p++;
			if (ttisp->tt_isdst != 0 && ttisp->tt_isdst != 1)
				return -1;
			ttisp->tt_abbrind = (unsigned char) *p++;
			if (ttisp->tt_abbrind < 0 ||
				ttisp->tt_abbrind > sp->charcnt)
				return -1;
		}
		for (i = 0; i < sp->charcnt; ++i)
			sp->chars[i] = *p++;
		sp->chars[i] = '\0';	/* ensure '\0' at end */
		for (i = 0; i < sp->leapcnt; ++i)
		{
			struct lsinfo *lsisp;

			lsisp = &sp->lsis[i];
			lsisp->ls_trans = (stored == 4) ? detzcode(p) : detzcode64(p);
			p += stored;
			lsisp->ls_corr = detzcode(p);
			p += 4;
		}
		for (i = 0; i < sp->typecnt; ++i)
		{
			struct ttinfo *ttisp;

			ttisp = &sp->ttis[i];
			if (ttisstdcnt == 0)
				ttisp->tt_ttisstd = FALSE;
			else
			{
				ttisp->tt_ttisstd = *p++;
				if (ttisp->tt_ttisstd != TRUE &&
					ttisp->tt_ttisstd != FALSE)
					return -1;
			}
		}
		for (i = 0; i < sp->typecnt; ++i)
		{
			struct ttinfo *ttisp;

			ttisp = &sp->ttis[i];
			if (ttisgmtcnt == 0)
				ttisp->tt_ttisgmt = FALSE;
			else
			{
				ttisp->tt_ttisgmt = *p++;
				if (ttisp->tt_ttisgmt != TRUE &&
					ttisp->tt_ttisgmt != FALSE)
					return -1;
			}
		}

		/*
		 * Out-of-sort ats should mean we're running on a signed time_t system
		 * but using a data file with unsigned values (or vice versa).
		 */
		for (i = 0; i < sp->timecnt - 2; ++i)
			if (sp->ats[i] > sp->ats[i + 1])
			{
				++i;
				if (TYPE_SIGNED(pg_time_t))
				{
					/*
					 * Ignore the end (easy).
					 */
					sp->timecnt = i;
				}
				else
				{
					/*
					 * Ignore the beginning (harder).
					 */
					int			j;

					for (j = 0; j + i < sp->timecnt; ++j)
					{
						sp->ats[j] = sp->ats[j + i];
						sp->types[j] = sp->types[j + i];
					}
					sp->timecnt = j;
				}
				break;
			}

		/*
		 * If this is an old file, we're done.
		 */
		if (u.tzhead.tzh_version[0] == '\0')
			break;
		nread -= p - u.buf;
		for (i = 0; i < nread; ++i)
			u.buf[i] = p[i];

		/*
		 * If this is a narrow integer time_t system, we're done.
		 */
		if (stored >= (int) sizeof(pg_time_t) && TYPE_INTEGRAL(pg_time_t))
			break;
	}
	if (doextend && nread > 2 &&
		u.buf[0] == '\n' && u.buf[nread - 1] == '\n' &&
		sp->typecnt + 2 <= TZ_MAX_TYPES)
	{
		struct state ts;
		int			result;

		u.buf[nread - 1] = '\0';
		result = tzparse(&u.buf[1], &ts, FALSE);
		if (result == 0 && ts.typecnt == 2 &&
			sp->charcnt + ts.charcnt <= TZ_MAX_CHARS)
		{
			for (i = 0; i < 2; ++i)
				ts.ttis[i].tt_abbrind +=
					sp->charcnt;
			for (i = 0; i < ts.charcnt; ++i)
				sp->chars[sp->charcnt++] =
					ts.chars[i];
			i = 0;
			while (i < ts.timecnt &&
				   ts.ats[i] <=
				   sp->ats[sp->timecnt - 1])
				++i;
			while (i < ts.timecnt &&
				   sp->timecnt < TZ_MAX_TIMES)
			{
				sp->ats[sp->timecnt] =
					ts.ats[i];
				sp->types[sp->timecnt] =
					sp->typecnt +
					ts.types[i];
				++sp->timecnt;
				++i;
			}
			sp->ttis[sp->typecnt++] = ts.ttis[0];
			sp->ttis[sp->typecnt++] = ts.ttis[1];
		}
	}
	if (sp->timecnt > 1)
	{
		for (i = 1; i < sp->timecnt; ++i)
			if (typesequiv(sp, sp->types[i], sp->types[0]) &&
				differ_by_repeat(sp->ats[i], sp->ats[0]))
			{
				sp->goback = TRUE;
				break;
			}
		for (i = sp->timecnt - 2; i >= 0; --i)
			if (typesequiv(sp, sp->types[sp->timecnt - 1],
						   sp->types[i]) &&
				differ_by_repeat(sp->ats[sp->timecnt - 1],
								 sp->ats[i]))
			{
				sp->goahead = TRUE;
				break;
			}
	}
	return 0;
}
Ejemplo n.º 3
0
static int
tzload(const char *name, struct state * const sp, const int doextend)
{
	const char *		p;
	int			i;
	int			fid;
	int			stored;
	int			nread;
	typedef union {
		struct tzhead	tzhead;
		char		buf[2 * sizeof(struct tzhead) +
					2 * sizeof *sp +
					4 * TZ_MAX_TIMES];
	} u_t;
	u_t				u;
	u_t * const			up = &u;

	sp->goback = sp->goahead = FALSE;

	/* XXX The following is from OpenBSD, and I'm not sure it is correct */
	if (name != NULL && issetugid() != 0)
		if ((name[0] == ':' && name[1] == '/') || 
		    name[0] == '/' || strchr(name, '.'))
			name = NULL;
	if (name == NULL && (name = TZDEFAULT) == NULL)
		goto oops;
	{
		int	doaccess;
		struct stat	stab;
		/*
		** Section 4.9.1 of the C standard says that
		** "FILENAME_MAX expands to an integral constant expression
		** that is the size needed for an array of char large enough
		** to hold the longest file name string that the implementation
		** guarantees can be opened."
		*/
		char		fullname[FILENAME_MAX + 1];

		if (name[0] == ':')
			++name;
		doaccess = name[0] == '/';
		if (!doaccess) {
			if ((p = TZDIR) == NULL)
				goto oops;
			if ((strlen(p) + 1 + strlen(name) + 1) >= sizeof fullname)
				goto oops;
			strcpy(fullname, p);
			strcat(fullname, "/");
			strcat(fullname, name);
			/*
			** Set doaccess if '.' (as in "../") shows up in name.
			*/
			if (strchr(name, '.') != NULL)
				doaccess = TRUE;
			name = fullname;
		}
		if (doaccess && access(name, R_OK) != 0)
			goto oops;
		if ((fid = _open(name, O_RDONLY)) == -1)
			goto oops;
		if ((_fstat(fid, &stab) < 0) || !S_ISREG(stab.st_mode)) {
			_close(fid);
			return -1;
		}
	}
	nread = _read(fid, up->buf, sizeof up->buf);
	if (_close(fid) < 0 || nread <= 0)
		goto oops;
	for (stored = 4; stored <= 8; stored *= 2) {
		int		ttisstdcnt;
		int		ttisgmtcnt;

		ttisstdcnt = (int) detzcode(up->tzhead.tzh_ttisstdcnt);
		ttisgmtcnt = (int) detzcode(up->tzhead.tzh_ttisgmtcnt);
		sp->leapcnt = (int) detzcode(up->tzhead.tzh_leapcnt);
		sp->timecnt = (int) detzcode(up->tzhead.tzh_timecnt);
		sp->typecnt = (int) detzcode(up->tzhead.tzh_typecnt);
		sp->charcnt = (int) detzcode(up->tzhead.tzh_charcnt);
		p = up->tzhead.tzh_charcnt + sizeof up->tzhead.tzh_charcnt;
		if (sp->leapcnt < 0 || sp->leapcnt > TZ_MAX_LEAPS ||
			sp->typecnt <= 0 || sp->typecnt > TZ_MAX_TYPES ||
			sp->timecnt < 0 || sp->timecnt > TZ_MAX_TIMES ||
			sp->charcnt < 0 || sp->charcnt > TZ_MAX_CHARS ||
			(ttisstdcnt != sp->typecnt && ttisstdcnt != 0) ||
			(ttisgmtcnt != sp->typecnt && ttisgmtcnt != 0))
				goto oops;
		if (nread - (p - up->buf) <
			sp->timecnt * stored +		/* ats */
			sp->timecnt +			/* types */
			sp->typecnt * 6 +		/* ttinfos */
			sp->charcnt +			/* chars */
			sp->leapcnt * (stored + 4) +	/* lsinfos */
			ttisstdcnt +			/* ttisstds */
			ttisgmtcnt)			/* ttisgmts */
				goto oops;
		for (i = 0; i < sp->timecnt; ++i) {
			sp->ats[i] = (stored == 4) ?
				detzcode(p) : detzcode64(p);
			p += stored;
		}
		for (i = 0; i < sp->timecnt; ++i) {
			sp->types[i] = (unsigned char) *p++;
			if (sp->types[i] >= sp->typecnt)
				goto oops;
		}
		for (i = 0; i < sp->typecnt; ++i) {
			struct ttinfo *	ttisp;

			ttisp = &sp->ttis[i];
			ttisp->tt_gmtoff = detzcode(p);
			p += 4;
			ttisp->tt_isdst = (unsigned char) *p++;
			if (ttisp->tt_isdst != 0 && ttisp->tt_isdst != 1)
				goto oops;
			ttisp->tt_abbrind = (unsigned char) *p++;
			if (ttisp->tt_abbrind < 0 ||
				ttisp->tt_abbrind > sp->charcnt)
					goto oops;
		}
		for (i = 0; i < sp->charcnt; ++i)
			sp->chars[i] = *p++;
		sp->chars[i] = '\0';	/* ensure '\0' at end */
		for (i = 0; i < sp->leapcnt; ++i) {
			struct lsinfo *	lsisp;

			lsisp = &sp->lsis[i];
			lsisp->ls_trans = (stored == 4) ?
				detzcode(p) : detzcode64(p);
			p += stored;
			lsisp->ls_corr = detzcode(p);
			p += 4;
		}
		for (i = 0; i < sp->typecnt; ++i) {
			struct ttinfo *	ttisp;

			ttisp = &sp->ttis[i];
			if (ttisstdcnt == 0)
				ttisp->tt_ttisstd = FALSE;
			else {
				ttisp->tt_ttisstd = *p++;
				if (ttisp->tt_ttisstd != TRUE &&
					ttisp->tt_ttisstd != FALSE)
						goto oops;
			}
		}
		for (i = 0; i < sp->typecnt; ++i) {
			struct ttinfo *	ttisp;

			ttisp = &sp->ttis[i];
			if (ttisgmtcnt == 0)
				ttisp->tt_ttisgmt = FALSE;
			else {
				ttisp->tt_ttisgmt = *p++;
				if (ttisp->tt_ttisgmt != TRUE &&
					ttisp->tt_ttisgmt != FALSE)
						goto oops;
			}
		}
		/*
		** Out-of-sort ats should mean we're running on a
		** signed time_t system but using a data file with
		** unsigned values (or vice versa).
		*/
		for (i = 0; i < sp->timecnt - 2; ++i)
			if (sp->ats[i] > sp->ats[i + 1]) {
				++i;
				if (TYPE_SIGNED(time_t)) {
					/*
					** Ignore the end (easy).
					*/
					sp->timecnt = i;
				} else {
					/*
					** Ignore the beginning (harder).
					*/
					int	j;

					for (j = 0; j + i < sp->timecnt; ++j) {
						sp->ats[j] = sp->ats[j + i];
						sp->types[j] = sp->types[j + i];
					}
					sp->timecnt = j;
				}
				break;
			}
		/*
		** If this is an old file, we're done.
		*/
		if (up->tzhead.tzh_version[0] == '\0')
			break;
		nread -= p - up->buf;
		for (i = 0; i < nread; ++i)
			up->buf[i] = p[i];
		/*
		** If this is a narrow integer time_t system, we're done.
		*/
		if (stored >= (int) sizeof(time_t) && TYPE_INTEGRAL(time_t))
			break;
	}
	if (doextend && nread > 2 &&
		up->buf[0] == '\n' && up->buf[nread - 1] == '\n' &&
		sp->typecnt + 2 <= TZ_MAX_TYPES) {
			struct state	ts;
			int		result;

			up->buf[nread - 1] = '\0';
			result = tzparse(&up->buf[1], &ts, FALSE);
			if (result == 0 && ts.typecnt == 2 &&
				sp->charcnt + ts.charcnt <= TZ_MAX_CHARS) {
					for (i = 0; i < 2; ++i)
						ts.ttis[i].tt_abbrind +=
							sp->charcnt;
					for (i = 0; i < ts.charcnt; ++i)
						sp->chars[sp->charcnt++] =
							ts.chars[i];
					i = 0;
					while (i < ts.timecnt &&
						ts.ats[i] <=
						sp->ats[sp->timecnt - 1])
							++i;
					while (i < ts.timecnt &&
					    sp->timecnt < TZ_MAX_TIMES) {
						sp->ats[sp->timecnt] =
							ts.ats[i];
						sp->types[sp->timecnt] =
							sp->typecnt +
							ts.types[i];
						++sp->timecnt;
						++i;
					}
					sp->ttis[sp->typecnt++] = ts.ttis[0];
					sp->ttis[sp->typecnt++] = ts.ttis[1];
			}
	}
	if (sp->timecnt > 1) {
		for (i = 1; i < sp->timecnt; ++i)
			if (typesequiv(sp, sp->types[i], sp->types[0]) &&
				differ_by_repeat(sp->ats[i], sp->ats[0])) {
					sp->goback = TRUE;
					break;
				}
		for (i = sp->timecnt - 2; i >= 0; --i)
			if (typesequiv(sp, sp->types[sp->timecnt - 1],
				sp->types[i]) &&
				differ_by_repeat(sp->ats[sp->timecnt - 1],
				sp->ats[i])) {
					sp->goahead = TRUE;
					break;
		}
	}
	return 0;
oops:
	return -1;
}