latest proposed 64-bit changes

Arthur David Olson olsona at lecserver.nci.nih.gov
Thu Jan 19 17:59:10 UTC 2006


Here's the latest version of proposed changes to the time zone package to
cope with 64-bit time values. As usual, these are differences from the
stuff that's available at ftp://elsie.nci.nih.gov/pub/tz{code,data}2005r.tar.gz.

I ran the package before and after these changes through the zgress
wringer that I sent out on Tuesday; here on elsie (a 32-bit system)
I get the same results from a zdump of all the binary data files
whether I use the before or after zdump and whether I use the
before or after data files.

For those who missed earlier rounds: the "new" version of zic generates a
three-part binary file; the file starts off with "Tzif2" (rather than the
old "Tzif\0"). The first part (other than the change in the magic "Tzif" string)
is identical in format to the existing time zone binary files. The second part
has the same format except that 64 bits are stored for each time value (rather
than the old 32 bits). The third part is a newline-enclosed POSIX-format
time zone string (such as "EST5EDT,M3.2.0,M11.1.0") if the future of the zone 
can be represented with such a string, or a newline-enclosed null string
otherwise.

If a zone's future can't be represented by a POSIX string, the new zic
generates 400 years worth of 64-bit time transition information; the stuff
in "localtime.c" sees if there's 400 years worth of regularity at the end of
the data and, if so, does its work modulo 400 to extend the data into the
very far future.

Given the magnitude of these changes I'll wait a while for feedback;
since these changes have already been around the block a couple of times
and since they pass the regression test, I won't wait too long.
Absent negative feedback, expect the changes to show up in the ftp version
on Presidents' Day (2006-02-20).

The changes below also reflect Roland McGrath's scheck suggestions.

				--ado

*** tzftp/tzfile.5	Thu Dec 22 09:31:16 2005
--- tzexp3/tzfile.5	Tue Jan 17 14:42:56 2006
***************
*** 9,15 ****
  .IR 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
  .BR long ,
  written in a ``standard'' byte order
--- 9,17 ----
  .IR tzset (3)
  begin with the magic characters "TZif" to identify then as
  time zone information files,
! followed by a character identifying the version of the file's format
! (as of 2005, either an ASCII NUL or a '2')
! followed by fifteen bytes containing zeroes reserved for future use,
  followed by six four-byte values of type
  .BR long ,
  written in a ``standard'' byte order
***************
*** 131,138 ****
  .I tzh_timecnt
  is zero or the time argument is less than the first transition time recorded
  in the file.
  .SH SEE ALSO
  newctime(3)
! .\" @(#)tzfile.5	7.12
  .\" This file is in the public domain, so clarified as of
  .\" 1996-06-05 by Arthur David Olson.
--- 133,150 ----
  .I tzh_timecnt
  is zero or the time argument is less than the first transition time recorded
  in the file.
+ .PP
+ For version-2-format time zone files,
+ the above header and data is followed by a second header and data,
+ identical in format except that
+ eight bytes are used for each transition time or leap second time.
+ After the second header and data comes a newline-encloded,
+ POSIX-TZ-environment-variable-style string for use in handling instants
+ after the last transition time stored in the file
+ (with nothing between the newlines if there is no POSIX representation for
+ such instants).
  .SH SEE ALSO
  newctime(3)
! .\" @(#)tzfile.5	7.13
  .\" This file is in the public domain, so clarified as of
  .\" 1996-06-05 by Arthur David Olson.
*** tzftp/Makefile	Thu Dec 22 09:31:13 2005
--- tzexp3/Makefile	Tue Jan 17 14:42:54 2006
***************
*** 1,4 ****
! # @(#)Makefile	7.109
  
  # Change the line below for your time zone (after finding the zone you want in
  # the time zone files, or adding it to a time zone file).
--- 1,4 ----
! # @(#)Makefile	7.110
  
  # Change the line below for your time zone (after finding the zone you want in
  # the time zone files, or adding it to a time zone file).
***************
*** 95,100 ****
--- 95,101 ----
  #  -DHAVE_SETTIMEOFDAY=1 if settimeofday has just 1 arg (SVR4)
  #  -DHAVE_SETTIMEOFDAY=2 if settimeofday uses 2nd arg (4.3BSD)
  #  -DHAVE_SETTIMEOFDAY=3 if settimeofday ignores 2nd arg (4.4BSD)
+ #  -DHAVE_STDINT_H=1 if you have a pre-C99 compiler with "stdint.h"
  #  -DHAVE_STRERROR=0 if your system lacks the strerror function
  #  -DHAVE_SYMLINK=0 if your system lacks the symlink function
  #  -DHAVE_SYS_STAT_H=0 if your compiler lacks a "sys/stat.h"
*** tzftp/tzfile.h	Thu Dec 22 09:31:16 2005
--- tzexp3/tzfile.h	Tue Jan 17 15:05:09 2006
***************
*** 21,27 ****
  
  #ifndef lint
  #ifndef NOID
! static char	tzfilehid[] = "@(#)tzfile.h	7.18";
  #endif /* !defined NOID */
  #endif /* !defined lint */
  
--- 21,27 ----
  
  #ifndef lint
  #ifndef NOID
! static char	tzfilehid[] = "@(#)tzfile.h	7.19";
  #endif /* !defined NOID */
  #endif /* !defined lint */
  
***************
*** 49,55 ****
  
  struct tzhead {
  	char	tzh_magic[4];		/* TZ_MAGIC */
! 	char	tzh_reserved[16];	/* reserved for future use */
  	char	tzh_ttisgmtcnt[4];	/* coded number of trans. time flags */
  	char	tzh_ttisstdcnt[4];	/* coded number of trans. time flags */
  	char	tzh_leapcnt[4];		/* coded number of leap seconds */
--- 49,56 ----
  
  struct tzhead {
  	char	tzh_magic[4];		/* TZ_MAGIC */
! 	char	tzh_version[1];		/* '\0' or '2' as of 2005 */
! 	char	tzh_reserved[15];	/* reserved--must be zero */
  	char	tzh_ttisgmtcnt[4];	/* coded number of trans. time flags */
  	char	tzh_ttisstdcnt[4];	/* coded number of trans. time flags */
  	char	tzh_leapcnt[4];		/* coded number of leap seconds */
***************
*** 84,101 ****
  */
  
  /*
  ** In the current implementation, "tzset()" refuses to deal with files that
  ** exceed any of the limits below.
  */
  
  #ifndef TZ_MAX_TIMES
! /*
! ** The TZ_MAX_TIMES value below is enough to handle a bit more than a
! ** year's worth of solar time (corrected daily to the nearest second) or
! ** 138 years of Pacific Presidential Election time
! ** (where there are three time zone transitions every fourth year).
! */
! #define TZ_MAX_TIMES	370
  #endif /* !defined TZ_MAX_TIMES */
  
  #ifndef TZ_MAX_TYPES
--- 85,106 ----
  */
  
  /*
+ ** If tzh_version is '2' or greater, the above is followed by a second instance
+ ** of tzhead and a second instance of the data in which each coded transition
+ ** time uses 8 rather than 4 chars,
+ ** then a POSIX-TZ-environment-variable-style string for use in handling
+ ** instants after the last transition time stored in the file
+ ** (with nothing between the newlines if there is no POSIX representation for
+ ** such instants).
+ */
+ 
+ /*
  ** In the current implementation, "tzset()" refuses to deal with files that
  ** exceed any of the limits below.
  */
  
  #ifndef TZ_MAX_TIMES
! #define TZ_MAX_TIMES	1200
  #endif /* !defined TZ_MAX_TIMES */
  
  #ifndef TZ_MAX_TYPES
*** tzftp/private.h	Thu Dec 22 09:31:15 2005
--- tzexp3/private.h	Tue Jan 17 15:36:50 2006
***************
*** 21,27 ****
  
  #ifndef lint
  #ifndef NOID
! static char	privatehid[] = "@(#)private.h	7.55";
  #endif /* !defined NOID */
  #endif /* !defined lint */
  
--- 21,27 ----
  
  #ifndef lint
  #ifndef NOID
! static char	privatehid[] = "@(#)private.h	7.62";
  #endif /* !defined NOID */
  #endif /* !defined lint */
  
***************
*** 48,53 ****
--- 48,57 ----
  #define HAVE_SETTIMEOFDAY	3
  #endif /* !defined HAVE_SETTIMEOFDAY */
  
+ #ifndef HAVE_STDINT_H
+ #define HAVE_STDINT_H		(199901 <= __STDC_VERSION__)
+ #endif /* !defined HAVE_STDINT_H */
+ 
  #ifndef HAVE_STRERROR
  #define HAVE_STRERROR		1
  #endif /* !defined HAVE_STRERROR */
***************
*** 89,95 ****
  #include "stdio.h"
  #include "errno.h"
  #include "string.h"
! #include "limits.h"	/* for CHAR_BIT */
  #include "time.h"
  #include "stdlib.h"
  
--- 93,99 ----
  #include "stdio.h"
  #include "errno.h"
  #include "string.h"
! #include "limits.h"	/* for CHAR_BIT et al. */
  #include "time.h"
  #include "stdlib.h"
  
***************
*** 124,129 ****
--- 128,152 ----
  /* Unlike <ctype.h>'s isdigit, this also works if c < 0 | c > UCHAR_MAX. */
  #define is_digit(c) ((unsigned)(c) - '0' <= 9)
  
+ #if HAVE_STDINT_H
+ #include <stdint.h>
+ #endif /* !HAVE_STDINT_H */
+ 
+ #ifndef INT_FAST64_MAX
+ #ifdef LLONG_MAX
+ typedef long long	int_fast64_t;
+ #else /* !defined LLONG_MAX */
+ typedef long		int_fast64_t;
+ #endif /* !defined LLONG_MAX */
+ #endif /* !defined INT_FAST64_MAX */
+ 
+ #ifndef INT32_MAX
+ #define INT32_MAX 0x7fffffff
+ #endif /* !defined INT32_MAX */
+ #ifndef INT32_MIN
+ #define INT32_MIN (-1 - INT32_MAX)
+ #endif /* !defined INT32_MIN */
+ 
  /*
  ** Workarounds for compilers/systems.
  */
***************
*** 211,224 ****
  ** Private function declarations.
  */
  
! char *	icalloc P((int nelem, int elsize));
! char *	icatalloc P((char * old, const char * new));
! char *	icpyalloc P((const char * string));
! char *	imalloc P((int n));
! void *	irealloc P((void * pointer, int size));
! void	icfree P((char * pointer));
! void	ifree P((char * pointer));
! char *	scheck P((const char *string, char *format));
  
  /*
  ** Finally, some convenience items.
--- 234,247 ----
  ** Private function declarations.
  */
  
! char *		icalloc P((int nelem, int elsize));
! char *		icatalloc P((char * old, const char * new));
! char *		icpyalloc P((const char * string));
! char *		imalloc P((int n));
! void *		irealloc P((void * pointer, int size));
! void		icfree P((char * pointer));
! void		ifree P((char * pointer));
! const char *	scheck P((const char * string, const char * format));
  
  /*
  ** Finally, some convenience items.
***************
*** 310,316 ****
--- 333,359 ----
  char *ctime_r P((time_t const *, char *));
  #endif /* HAVE_INCOMPATIBLE_CTIME_R */
  
+ #ifndef YEARSPERREPEAT
+ #define YEARSPERREPEAT		400	/* years before a Gregorian repeat */
+ #endif /* !defined YEARSPERREPEAT */
+ 
  /*
+ ** The Gregorian year averages 365.2425 days, which is 31556952 seconds.
+ */
+ 
+ #ifndef AVGSECSPERYEAR
+ #define AVGSECSPERYEAR		31556952
+ #endif /* !defined AVGSECSPERYEAR */
+ 
+ #ifndef SECSPERREPEAT
+ #define SECSPERREPEAT		((int_fast64_t) YEARSPERREPEAT * (int_fast64_t) AVGSECSPERYEAR)
+ #endif /* !defined SECSPERREPEAT */
+  
+ #ifndef SECSPERREPEAT_BITS
+ #define SECSPERREPEAT_BITS	34	/* ceil(log2(SECSPERREPEAT)) */
+ #endif /* !defined SECSPERREPEAT_BITS */
+ 
+ /*
  ** UNIX was a registered trademark of The Open Group in 2003.
  */
  
*** tzftp/localtime.c	Thu Dec 22 09:31:14 2005
--- tzexp3/localtime.c	Tue Jan 17 14:42:54 2006
***************
*** 5,11 ****
  
  #ifndef lint
  #ifndef NOID
! static char	elsieid[] = "@(#)localtime.c	7.97";
  #endif /* !defined NOID */
  #endif /* !defined lint */
  
--- 5,11 ----
  
  #ifndef lint
  #ifndef NOID
! static char	elsieid[] = "@(#)localtime.c	7.98";
  #endif /* !defined NOID */
  #endif /* !defined lint */
  
***************
*** 110,115 ****
--- 110,117 ----
  	int		timecnt;
  	int		typecnt;
  	int		charcnt;
+ 	int		goback;
+ 	int		goahead;
  	time_t		ats[TZ_MAX_TIMES];
  	unsigned char	types[TZ_MAX_TIMES];
  	struct ttinfo	ttis[TZ_MAX_TYPES];
***************
*** 135,142 ****
  */
  
  static long		detzcode P((const char * codep));
  static const char *	getzname P((const char * strp));
! static const char *	getqzname P((const char * strp, const char delim));
  static const char *	getnum P((const char * strp, int * nump, int min,
  				int max));
  static const char *	getsecs P((const char * strp, long * secsp));
--- 137,146 ----
  */
  
  static long		detzcode P((const char * codep));
+ static time_t		detzcode64 P((const char * codep));
+ static int		differ_by_repeat P((time_t t1, time_t t0));
  static const char *	getzname P((const char * strp));
! static const char *	getqzname P((const char * strp, const int delim));
  static const char *	getnum P((const char * strp, int * nump, int min,
  				int max));
  static const char *	getsecs P((const char * strp, long * secsp));
***************
*** 173,179 ****
  				const struct tm * btmp));
  static time_t		transtime P((time_t janfirst, int year,
  				const struct rule * rulep, long offset));
! static int		tzload P((const char * name, struct state * sp));
  static int		tzparse P((const char * name, struct state * sp,
  				int lastditch));
  
--- 177,184 ----
  				const struct tm * btmp));
  static time_t		transtime P((time_t janfirst, int year,
  				const struct rule * rulep, long offset));
! static int		tzload P((const char * name, struct state * sp,
! 				int doextend));
  static int		tzparse P((const char * name, struct state * sp,
  				int lastditch));
  
***************
*** 234,239 ****
--- 239,257 ----
  	return result;
  }
  
+ static time_t
+ detzcode64(codep)
+ const char * const	codep;
+ {
+ 	register time_t	result;
+ 	register int	i;
+ 
+ 	result = (codep[0] & 0x80) ? ~0L : 0L;
+ 	for (i = 0; i < 8; ++i)
+ 		result = result * 256 + (codep[i] & 0xff);
+ 	return result;
+ }
+ 
  static void
  settzname P((void))
  {
***************
*** 303,315 ****
  }
  
  static int
! tzload(name, sp)
  register const char *		name;
  register struct state * const	sp;
  {
! 	register const char *	p;
! 	register int		i;
! 	register int		fid;
  
  	if (name == NULL && (name = TZDEFAULT) == NULL)
  		return -1;
--- 321,353 ----
  }
  
  static int
! differ_by_repeat(t1, t0)
! const time_t	t1;
! const time_t	t0;
! {
! 	if (TYPE_INTEGRAL(time_t) &&
! 		TYPE_BIT(time_t) - TYPE_SIGNED(time_t) < SECSPERREPEAT_BITS)
! 			return 0;
! 	return t1 - t0 == SECSPERREPEAT;
! }
! 
! static int
! tzload(name, sp, doextend)
  register const char *		name;
  register struct state * const	sp;
+ register const int		doextend;
  {
! 	register const char *		p;
! 	register int			i;
! 	register int			fid;
! 	register int			stored;
! 	register int			nread;
! 	union {
! 		struct tzhead	tzhead;
! 		char		buf[2 * sizeof(struct tzhead) +
! 					2 * sizeof *sp +
! 					4 * TZ_MAX_TIMES];
! 	} u;
  
  	if (name == NULL && (name = TZDEFAULT) == NULL)
  		return -1;
***************
*** 347,364 ****
  		if ((fid = open(name, OPEN_MODE)) == -1)
  			return -1;
  	}
! 	{
! 		struct tzhead *	tzhp;
! 		union {
! 			struct tzhead	tzhead;
! 			char		buf[sizeof *sp + sizeof *tzhp];
! 		} u;
  		int		ttisstdcnt;
  		int		ttisgmtcnt;
  
- 		i = read(fid, u.buf, sizeof u.buf);
- 		if (close(fid) != 0)
- 			return -1;
  		ttisstdcnt = (int) detzcode(u.tzhead.tzh_ttisstdcnt);
  		ttisgmtcnt = (int) detzcode(u.tzhead.tzh_ttisgmtcnt);
  		sp->leapcnt = (int) detzcode(u.tzhead.tzh_leapcnt);
--- 385,397 ----
  		if ((fid = open(name, OPEN_MODE)) == -1)
  			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);
***************
*** 373,389 ****
  			(ttisstdcnt != sp->typecnt && ttisstdcnt != 0) ||
  			(ttisgmtcnt != sp->typecnt && ttisgmtcnt != 0))
  				return -1;
! 		if (i - (p - u.buf) < sp->timecnt * 4 +	/* ats */
  			sp->timecnt +			/* types */
! 			sp->typecnt * (4 + 2) +		/* ttinfos */
  			sp->charcnt +			/* chars */
! 			sp->leapcnt * (4 + 4) +		/* lsinfos */
  			ttisstdcnt +			/* ttisstds */
  			ttisgmtcnt)			/* ttisgmts */
  				return -1;
  		for (i = 0; i < sp->timecnt; ++i) {
! 			sp->ats[i] = detzcode(p);
! 			p += 4;
  		}
  		for (i = 0; i < sp->timecnt; ++i) {
  			sp->types[i] = (unsigned char) *p++;
--- 406,424 ----
  			(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++;
***************
*** 411,418 ****
  			register struct lsinfo *	lsisp;
  
  			lsisp = &sp->lsis[i];
! 			lsisp->ls_trans = detzcode(p);
! 			p += 4;
  			lsisp->ls_corr = detzcode(p);
  			p += 4;
  		}
--- 446,454 ----
  			register 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;
  		}
***************
*** 469,475 ****
--- 505,567 ----
  				}
  				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(time_t) && TYPE_INTEGRAL(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;
+ 			register 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];
+ 			}
+ 	}
+ 	i = 2 * YEARSPERREPEAT;
+ 	sp->goback = sp->goahead = sp->timecnt > i;
+ 	sp->goback &= sp->types[i] == sp->types[0] &&
+ 		differ_by_repeat(sp->ats[i], sp->ats[0]);
+ 	sp->goahead &=
+ 		sp->types[sp->timecnt - 1] == sp->types[sp->timecnt - 1 - i] &&
+ 		differ_by_repeat(sp->ats[sp->timecnt - 1],
+ 			 sp->ats[sp->timecnt - 1 - i]);
  	return 0;
  }
  
***************
*** 502,520 ****
  
  /*
  ** Given a pointer into an extended time zone string, scan until the ending
! ** delimiter of the zone name is located.   Return a pointer to the delimiter.
  **
  ** As with getzname above, the legal character set is actually quite
  ** restricted, with other characters producing undefined results.
! ** We choose not to care - allowing almost anything to be in the zone abbrev.
  */
  
  static const char *
  getqzname(strp, delim)
  register const char *	strp;
! const char		delim;
  {
! 	register char	c;
  
  	while ((c = *strp) != '\0' && c != delim)
  		++strp;
--- 594,612 ----
  
  /*
  ** Given a pointer into an extended time zone string, scan until the ending
! ** delimiter of the zone name is located. Return a pointer to the delimiter.
  **
  ** As with getzname above, the legal character set is actually quite
  ** restricted, with other characters producing undefined results.
! ** We don't do any checking here; checking is done later in common-case code.
  */
  
  static const char *
  getqzname(strp, delim)
  register const char *	strp;
! const int		delim;
  {
! 	register int	c;
  
  	while ((c = *strp) != '\0' && c != delim)
  		++strp;
***************
*** 823,831 ****
  		if (name == NULL)
  			return -1;
  	}
! 	load_result = tzload(TZDEFRULES, sp);
  	if (load_result != 0)
  		sp->leapcnt = 0;		/* so, we're off a little */
  	if (*name != '\0') {
  		if (*name == '<') {
  			dstname = ++name;
--- 915,924 ----
  		if (name == NULL)
  			return -1;
  	}
! 	load_result = tzload(TZDEFRULES, sp, FALSE);
  	if (load_result != 0)
  		sp->leapcnt = 0;		/* so, we're off a little */
+ 	sp->timecnt = 0;
  	if (*name != '\0') {
  		if (*name == '<') {
  			dstname = ++name;
***************
*** 865,875 ****
  				return -1;
  			sp->typecnt = 2;	/* standard time and DST */
  			/*
! 			** Two transitions per year, from EPOCH_YEAR to 2037.
  			*/
- 			sp->timecnt = 2 * (2037 - EPOCH_YEAR + 1);
- 			if (sp->timecnt > TZ_MAX_TIMES)
- 				return -1;
  			sp->ttis[0].tt_gmtoff = -dstoffset;
  			sp->ttis[0].tt_isdst = 1;
  			sp->ttis[0].tt_abbrind = stdlen + 1;
--- 958,965 ----
  				return -1;
  			sp->typecnt = 2;	/* standard time and DST */
  			/*
! 			** Two transitions per year, from EPOCH_YEAR forward.
  			*/
  			sp->ttis[0].tt_gmtoff = -dstoffset;
  			sp->ttis[0].tt_isdst = 1;
  			sp->ttis[0].tt_abbrind = stdlen + 1;
***************
*** 879,885 ****
  			atp = sp->ats;
  			typep = sp->types;
  			janfirst = 0;
! 			for (year = EPOCH_YEAR; year <= 2037; ++year) {
  				starttime = transtime(janfirst, year, &start,
  					stdoffset);
  				endtime = transtime(janfirst, year, &end,
--- 969,979 ----
  			atp = sp->ats;
  			typep = sp->types;
  			janfirst = 0;
! 			for (year = EPOCH_YEAR;
! 			    sp->timecnt + 2 <= TZ_MAX_TIMES;
! 			    ++year) {
! 			    	time_t	newfirst;
! 
  				starttime = transtime(janfirst, year, &start,
  					stdoffset);
  				endtime = transtime(janfirst, year, &end,
***************
*** 895,902 ****
  					*atp++ = endtime;
  					*typep++ = 1;	/* DST ends */
  				}
! 				janfirst += year_lengths[isleap(year)] *
  					SECSPERDAY;
  			}
  		} else {
  			register long	theirstdoffset;
--- 989,1001 ----
  					*atp++ = endtime;
  					*typep++ = 1;	/* DST ends */
  				}
! 				sp->timecnt += 2;
! 				newfirst = janfirst;
! 				newfirst += year_lengths[isleap(year)] *
  					SECSPERDAY;
+ 				if (newfirst <= janfirst)
+ 					break;
+ 				janfirst = newfirst;
  			}
  		} else {
  			register long	theirstdoffset;
***************
*** 1011,1017 ****
  gmtload(sp)
  struct state * const	sp;
  {
! 	if (tzload(gmt, sp) != 0)
  		(void) tzparse(gmt, sp, TRUE);
  }
  
--- 1110,1116 ----
  gmtload(sp)
  struct state * const	sp;
  {
! 	if (tzload(gmt, sp, TRUE) != 0)
  		(void) tzparse(gmt, sp, TRUE);
  }
  
***************
*** 1038,1044 ****
  		}
  	}
  #endif /* defined ALL_STATE */
! 	if (tzload((char *) NULL, lclptr) != 0)
  		gmtload(lclptr);
  	settzname();
  }
--- 1137,1143 ----
  		}
  	}
  #endif /* defined ALL_STATE */
! 	if (tzload((char *) NULL, lclptr, TRUE) != 0)
  		gmtload(lclptr);
  	settzname();
  }
***************
*** 1080,1086 ****
  		lclptr->ttis[0].tt_gmtoff = 0;
  		lclptr->ttis[0].tt_abbrind = 0;
  		(void) strcpy(lclptr->chars, gmt);
! 	} else if (tzload(name, lclptr) != 0)
  		if (name[0] == ':' || tzparse(name, lclptr, FALSE) != 0)
  			(void) gmtload(lclptr);
  	settzname();
--- 1179,1185 ----
  		lclptr->ttis[0].tt_gmtoff = 0;
  		lclptr->ttis[0].tt_abbrind = 0;
  		(void) strcpy(lclptr->chars, gmt);
! 	} else if (tzload(name, lclptr, TRUE) != 0)
  		if (name[0] == ':' || tzparse(name, lclptr, FALSE) != 0)
  			(void) gmtload(lclptr);
  	settzname();
***************
*** 1113,1118 ****
--- 1212,1256 ----
  	if (sp == NULL)
  		return gmtsub(timep, offset, tmp);
  #endif /* defined ALL_STATE */
+ 	if ((sp->goback && t < sp->ats[0]) ||
+ 		(sp->goahead && t > sp->ats[sp->timecnt - 1])) {
+ 			time_t			newt = t;
+ 			register time_t		seconds;
+ 			register time_t		tcycles;
+ 			register int_fast64_t	icycles;
+ 
+ 			if (t < sp->ats[0])
+ 				seconds = sp->ats[0] - t;
+ 			else	seconds = t - sp->ats[sp->timecnt - 1];
+ 			--seconds;
+ 			tcycles = seconds / YEARSPERREPEAT / AVGSECSPERYEAR;
+ 			++tcycles;
+ 			icycles = tcycles;
+ 			if (tcycles - icycles >= 1 || icycles - tcycles >= 1)
+ 				return NULL;
+ 			seconds = icycles;
+ 			seconds *= YEARSPERREPEAT;
+ 			seconds *= AVGSECSPERYEAR;
+ 			if (t < sp->ats[0])
+ 				newt += seconds;
+ 			else	newt -= seconds;
+ 			if (newt < sp->ats[0] ||
+ 				newt > sp->ats[sp->timecnt - 1])
+ 					return NULL;	/* "cannot happen" */
+ 			result = localsub(&newt, offset, tmp);
+ 			if (result == tmp) {
+ 				register time_t	newy;
+ 
+ 				newy = tmp->tm_year;
+ 				if (t < sp->ats[0])
+ 					newy -= icycles * YEARSPERREPEAT;
+ 				else	newy += icycles * YEARSPERREPEAT;
+ 				tmp->tm_year = newy;
+ 				if (tmp->tm_year != newy)
+ 					return NULL;
+ 			}
+ 			return result;
+ 	}
  	if (sp->timecnt == 0 || t < sp->ats[0]) {
  		i = 0;
  		while (sp->ttis[i].tt_isdst)
*** tzftp/zic.c	Thu Dec 22 09:31:15 2005
--- tzexp3/zic.c	Tue Jan 17 15:17:09 2006
***************
*** 1,15 ****
! static char	elsieid[] = "@(#)zic.c	7.128";
  
- /*
- ** Regardless of the type of time_t, we do our work using this type.
- */
- 
- typedef int	zic_t;
- 
  #include "private.h"
  #include "locale.h"
  #include "tzfile.h"
  
  #ifndef ZIC_MAX_ABBR_LEN_WO_WARN
  #define ZIC_MAX_ABBR_LEN_WO_WARN	6
  #endif /* !defined ZIC_MAX_ABBR_LEN_WO_WARN */
--- 1,13 ----
! static char	elsieid[] = "@(#)zic.c	7.129";
  
  #include "private.h"
  #include "locale.h"
  #include "tzfile.h"
  
+ #define	ZIC_VERSION	'2'
+ 
+ typedef int_fast64_t	zic_t;
+ 
  #ifndef ZIC_MAX_ABBR_LEN_WO_WARN
  #define ZIC_MAX_ABBR_LEN_WO_WARN	6
  #endif /* !defined ZIC_MAX_ABBR_LEN_WO_WARN */
***************
*** 36,41 ****
--- 34,44 ----
  #define isascii(x) 1
  #endif
  
+ #define OFFSET_STRLEN_MAXIMUM	(7 + INT_STRLEN_MAXIMUM(long))
+ #define RULE_STRLEN_MAXIMUM	8	/* "Mdd.dd.d" */
+ 
+ #define end(cp)	(strchr((cp), '\0'))
+ 
  struct rule {
  	const char *	r_filename;
  	int		r_linenum;
***************
*** 44,49 ****
--- 47,54 ----
  	int		r_loyear;	/* for example, 1986 */
  	int		r_hiyear;	/* for example, 1986 */
  	const char *	r_yrtype;
+ 	int		r_lowasnum;
+ 	int		r_hiwasnum;
  
  	int		r_month;	/* 0..11 */
  
***************
*** 103,111 ****
  static void	associate P((void));
  static int	ciequal P((const char * ap, const char * bp));
  static void	convert P((long val, char * buf));
  static void	dolink P((const char * fromfile, const char * tofile));
  static void	doabbr P((char * abbr, const char * format,
! 			const char * letters, int isdst));
  static void	eat P((const char * name, int num));
  static void	eats P((const char * name, int num,
  			const char * rname, int rnum));
--- 108,117 ----
  static void	associate P((void));
  static int	ciequal P((const char * ap, const char * bp));
  static void	convert P((long val, char * buf));
+ static void	convert64 P((zic_t val, char * buf));
  static void	dolink P((const char * fromfile, const char * tofile));
  static void	doabbr P((char * abbr, const char * format,
! 			const char * letters, int isdst, int doquotes));
  static void	eat P((const char * name, int num));
  static void	eats P((const char * name, int num,
  			const char * rname, int rnum));
***************
*** 121,126 ****
--- 127,133 ----
  static int	inzcont P((char ** fields, int nfields));
  static int	inzone P((char ** fields, int nfields));
  static int	inzsub P((char ** fields, int nfields, int iscont));
+ static int	is32 P((zic_t x));
  static int	itsabbr P((const char * abbr, const char * word));
  static int	itsdir P((const char * name));
  static int	lowerit P((int c));
***************
*** 130,135 ****
--- 137,143 ----
  static long	oadd P((long t1, long t2));
  static void	outzone P((const struct zone * zp, int ntzones));
  static void	puttzcode P((long code, FILE * fp));
+ static void	puttzcode64 P((zic_t code, FILE * fp));
  static int	rcomp P((const void * leftp, const void * rightp));
  static zic_t	rpytime P((const struct rule * rp, int wantedy));
  static void	rulesub P((struct rule * rp,
***************
*** 136,145 ****
  			const char * loyearp, const char * hiyearp,
  			const char * typep, const char * monthp,
  			const char * dayp, const char * timep));
  static void	setboundaries P((void));
  static zic_t	tadd P((zic_t t1, long t2));
  static void	usage P((void));
! static void	writezone P((const char * name));
  static int	yearistype P((int year, const char * type));
  
  #if !HAVE_STRERROR
--- 144,158 ----
  			const char * loyearp, const char * hiyearp,
  			const char * typep, const char * monthp,
  			const char * dayp, const char * timep));
+ static int 	stringoffset P((char * result, long offset));
+ static int	stringrule P((char * result, const struct rule * rp,
+ 			long dstoff, long gmtoff));
+ static void 	stringzone P((char * result,
+ 			const struct zone * zp, int ntzones));
  static void	setboundaries P((void));
  static zic_t	tadd P((zic_t t1, long t2));
  static void	usage P((void));
! static void	writezone P((const char * name, const char * string));
  static int	yearistype P((int year, const char * type));
  
  #if !HAVE_STRERROR
***************
*** 150,162 ****
  static int		errors;
  static const char *	filename;
  static int		leapcnt;
  static int		linenum;
  static zic_t		max_time;
  static int		max_year;
- static int		max_year_representable;
  static zic_t		min_time;
  static int		min_year;
- static int		min_year_representable;
  static int		noise;
  static const char *	rfilename;
  static int		rlinenum;
--- 163,178 ----
  static int		errors;
  static const char *	filename;
  static int		leapcnt;
+ static int		leapseen;
+ static int		leapminyear;
+ static int		leapmaxyear;
  static int		linenum;
+ static int		max_abbrvar_len;
+ static int		max_format_len;
  static zic_t		max_time;
  static int		max_year;
  static zic_t		min_time;
  static int		min_year;
  static int		noise;
  static const char *	rfilename;
  static int		rlinenum;
***************
*** 453,459 ****
  usage P((void))
  {
  	(void) fprintf(stderr, _("%s: usage is %s \
! [ --version ] [ -s ] [ -v ] [ -l localtime ] [ -p posixrules ] \\\n\
  \t[ -d directory ] [ -L leapseconds ] [ -y yearistype ] [ filename ... ]\n"),
  		progname, progname);
  	exit(EXIT_FAILURE);
--- 469,475 ----
  usage P((void))
  {
  	(void) fprintf(stderr, _("%s: usage is %s \
! [ --version ] [ -v ] [ -l localtime ] [ -p posixrules ] \\\n\
  \t[ -d directory ] [ -L leapseconds ] [ -y yearistype ] [ filename ... ]\n"),
  		progname, progname);
  	exit(EXIT_FAILURE);
***************
*** 464,470 ****
  static const char *	directory;
  static const char *	leapsec;
  static const char *	yitcommand;
- static int		sflag = FALSE;
  
  int
  main(argc, argv)
--- 480,485 ----
***************
*** 486,491 ****
--- 501,511 ----
  	(void) textdomain(TZ_DOMAIN);
  #endif /* HAVE_GETTEXT */
  	progname = argv[0];
+ 	if (TYPE_BIT(zic_t) < 64) {
+ 		(void) fprintf(stderr, "%s: %s\n", progname,
+ 			_("wild compilation-time specification of zic_t"));
+ 		exit(EXIT_FAILURE);
+ 	}
  	for (i = 1; i < argc; ++i)
  		if (strcmp(argv[i], "--version") == 0) {
  			(void) printf("%s\n", elsieid);
***************
*** 549,555 ****
  				noise = TRUE;
  				break;
  			case 's':
! 				sflag = TRUE;
  				break;
  		}
  	if (optind == argc - 1 && strcmp(argv[optind], "=") == 0)
--- 569,575 ----
  				noise = TRUE;
  				break;
  			case 's':
! 				(void) printf("%s: -s ignored\n", progname);
  				break;
  		}
  	if (optind == argc - 1 && strcmp(argv[optind], "=") == 0)
***************
*** 671,724 ****
  	ifree(toname);
  }
  
! #ifndef INT_MAX
! #define INT_MAX	((int) (((unsigned)~0)>>1))
! #endif /* !defined INT_MAX */
  
- #ifndef INT_MIN
- #define INT_MIN	((int) ~(((unsigned)~0)>>1))
- #endif /* !defined INT_MIN */
- 
- /*
- ** The tz file format currently allows at most 32-bit quantities.
- ** This restriction should be removed before signed 32-bit values
- ** wrap around in 2038, but unfortunately this will require a
- ** change to the tz file format.
- */
- 
- #define MAX_BITS_IN_FILE	32
- #define TIME_T_BITS_IN_FILE	((TYPE_BIT(zic_t) < MAX_BITS_IN_FILE) ? \
- 					TYPE_BIT(zic_t) : MAX_BITS_IN_FILE)
- 
  static void
  setboundaries P((void))
  {
  	register int	i;
  
! 	if (TYPE_SIGNED(zic_t)) {
! 		min_time = -1;
! 		for (i = 0; i < TIME_T_BITS_IN_FILE - 1; ++i)
! 			min_time *= 2;
! 		max_time = -(min_time + 1);
! 		if (sflag)
! 			min_time = 0;
! 	} else {
! 		min_time = 0;
! 		max_time = 2 - sflag;
! 		for (i = 0; i < TIME_T_BITS_IN_FILE - 1; ++i)
! 			max_time *= 2;
! 		--max_time;
! 	}
! 	{
! 		time_t	t;
! 
! 		t = (time_t) min_time;
! 		min_year = TM_YEAR_BASE + gmtime(&t)->tm_year;
! 		t = (time_t) max_time;
! 		max_year = TM_YEAR_BASE + gmtime(&t)->tm_year;
! 	}
! 	min_year_representable = min_year;
! 	max_year_representable = max_year;
  }
  
  static int
--- 691,707 ----
  	ifree(toname);
  }
  
! #define TIME_T_BITS_IN_FILE	64
  
  static void
  setboundaries P((void))
  {
  	register int	i;
  
! 	min_time = -1;
! 	for (i = 0; i < TIME_T_BITS_IN_FILE - 1; ++i)
! 		min_time *= 2;
! 	max_time = -(min_time + 1);
  }
  
  static int
***************
*** 993,998 ****
--- 976,983 ----
  		fields[RF_MONTH], fields[RF_DAY], fields[RF_TOD]);
  	r.r_name = ecpyalloc(fields[RF_NAME]);
  	r.r_abbrvar = ecpyalloc(fields[RF_ABBRVAR]);
+ 	if (max_abbrvar_len < strlen(r.r_abbrvar))
+ 		max_abbrvar_len = strlen(r.r_abbrvar);
  	rules = (struct rule *) (void *) erealloc((char *) rules,
  		(int) ((nrules + 1) * sizeof *rules));
  	rules[nrules++] = r;
***************
*** 1098,1103 ****
--- 1083,1090 ----
  	}
  	z.z_rule = ecpyalloc(fields[i_rule]);
  	z.z_format = ecpyalloc(fields[i_format]);
+ 	if (max_format_len < strlen(z.z_format))
+ 		max_format_len = strlen(z.z_format);
  	hasuntil = nfields > i_untilyear;
  	if (hasuntil) {
  		z.z_untilrule.r_filename = filename;
***************
*** 1159,1164 ****
--- 1146,1156 ----
  		error(_("invalid leaping year"));
  		return;
  	}
+ 	if (!leapseen || leapmaxyear < year)
+ 		leapmaxyear = year;
+ 	if (!leapseen || leapminyear < year)
+ 		leapminyear = year;
+ 	leapseen = TRUE;
  	j = EPOCH_YEAR;
  	while (j != year) {
  		if (year > j) {
***************
*** 1313,1319 ****
  	*/
  	cp = loyearp;
  	lp = byword(cp, begin_years);
! 	if (lp != NULL) switch ((int) lp->l_value) {
  		case YR_MINIMUM:
  			rp->r_loyear = INT_MIN;
  			break;
--- 1305,1312 ----
  	*/
  	cp = loyearp;
  	lp = byword(cp, begin_years);
! 	rp->r_lowasnum = lp == NULL;
! 	if (!rp->r_lowasnum) switch ((int) lp->l_value) {
  		case YR_MINIMUM:
  			rp->r_loyear = INT_MIN;
  			break;
***************
*** 1328,1341 ****
  	} else if (sscanf(cp, scheck(cp, "%d"), &rp->r_loyear) != 1) {
  		error(_("invalid starting year"));
  		return;
- 	} else if (noise) {
- 		if (rp->r_loyear < min_year_representable)
- 			warning(_("starting year too low to be represented"));
- 		else if (rp->r_loyear > max_year_representable)
- 			warning(_("starting year too high to be represented"));
  	}
  	cp = hiyearp;
! 	if ((lp = byword(cp, end_years)) != NULL) switch ((int) lp->l_value) {
  		case YR_MINIMUM:
  			rp->r_hiyear = INT_MIN;
  			break;
--- 1321,1331 ----
  	} else if (sscanf(cp, scheck(cp, "%d"), &rp->r_loyear) != 1) {
  		error(_("invalid starting year"));
  		return;
  	}
  	cp = hiyearp;
! 	lp = byword(cp, end_years);
! 	rp->r_hiwasnum = lp == NULL;
! 	if (!rp->r_hiwasnum) switch ((int) lp->l_value) {
  		case YR_MINIMUM:
  			rp->r_hiyear = INT_MIN;
  			break;
***************
*** 1353,1363 ****
  	} else if (sscanf(cp, scheck(cp, "%d"), &rp->r_hiyear) != 1) {
  		error(_("invalid ending year"));
  		return;
- 	} else if (noise) {
- 		if (rp->r_loyear < min_year_representable)
- 			warning(_("ending year too low to be represented"));
- 		else if (rp->r_loyear > max_year_representable)
- 			warning(_("ending year too high to be represented"));
  	}
  	if (rp->r_loyear > rp->r_hiyear) {
  		error(_("starting year greater than ending year"));
--- 1343,1348 ----
***************
*** 1372,1379 ****
  		}
  		rp->r_yrtype = ecpyalloc(typep);
  	}
- 	if (rp->r_loyear < min_year && rp->r_loyear > 0)
- 		min_year = rp->r_loyear;
  	/*
  	** Day work.
  	** Accept things such as:
--- 1357,1362 ----
***************
*** 1427,1433 ****
  char * const	buf;
  {
  	register int	i;
! 	register long	shift;
  
  	for (i = 0, shift = 24; i < 4; ++i, shift -= 8)
  		buf[i] = val >> shift;
--- 1410,1416 ----
  char * const	buf;
  {
  	register int	i;
! 	register int	shift;
  
  	for (i = 0, shift = 24; i < 4; ++i, shift -= 8)
  		buf[i] = val >> shift;
***************
*** 1434,1439 ****
--- 1417,1434 ----
  }
  
  static void
+ convert64(val, buf)
+ const zic_t	val;
+ char * const	buf;
+ {
+ 	register int	i;
+ 	register int	shift;
+ 
+ 	for (i = 0, shift = 56; i < 8; ++i, shift -= 8)
+ 		buf[i] = val >> shift;
+ }
+ 
+ static void
  puttzcode(val, fp)
  const long	val;
  FILE * const	fp;
***************
*** 1444,1471 ****
  	(void) fwrite((void *) buf, (size_t) sizeof buf, (size_t) 1, fp);
  }
  
  static int
  atcomp(avp, bvp)
! void *	avp;
! void *	bvp;
  {
! 	if (((struct attype *) avp)->at < ((struct attype *) bvp)->at)
! 		return -1;
! 	else if (((struct attype *) avp)->at > ((struct attype *) bvp)->at)
! 		return 1;
! 	else	return 0;
  }
  
  static void
! writezone(name)
  const char * const	name;
  {
! 	register FILE *		fp;
! 	register int		i, j;
! 	static char *		fullname;
! 	static struct tzhead	tzh;
! 	zic_t			ats[TZ_MAX_TIMES];
! 	unsigned char		types[TZ_MAX_TIMES];
  
  	/*
  	** Sort.
--- 1439,1488 ----
  	(void) fwrite((void *) buf, (size_t) sizeof buf, (size_t) 1, fp);
  }
  
+ static void
+ puttzcode64(val, fp)
+ const zic_t	val;
+ FILE * const	fp;
+ {
+ 	char	buf[8];
+ 
+ 	convert64(val, buf);
+ 	(void) fwrite((void *) buf, (size_t) sizeof buf, (size_t) 1, fp);
+ }
+ 
  static int
  atcomp(avp, bvp)
! const void *	avp;
! const void *	bvp;
  {
! 	const zic_t	a = ((const struct attype *) avp)->at;
! 	const zic_t	b = ((const struct attype *) bvp)->at;
! 
! 	return (a < b) ? -1 : (a > b);
  }
  
+ static int
+ is32(x)
+ const zic_t	x;
+ {
+ 	return INT32_MIN <= x && x <= INT32_MAX;
+ }
+ 
  static void
! writezone(name, string)
  const char * const	name;
+ const char * const	string;
  {
! 	register FILE *			fp;
! 	register int			i, j;
! 	register int			leapcnt32, leapi32;
! 	register int			timecnt32, timei32;
! 	register int			pass;
! 	static char *			fullname;
! 	static const struct tzhead	tzh0;
! 	static struct tzhead		tzh;
! 	zic_t				ats[TZ_MAX_TIMES];
! 	unsigned char			types[TZ_MAX_TIMES];
  
  	/*
  	** Sort.
***************
*** 1509,1514 ****
--- 1526,1561 ----
  		ats[i] = attypes[i].at;
  		types[i] = attypes[i].type;
  	}
+ 	/*
+ 	** Correct for leap seconds.
+ 	*/
+ 	for (i = 0; i < timecnt; ++i) {
+ 		j = leapcnt;
+ 		while (--j >= 0)
+ 			if (ats[i] >= trans[j]) {
+ 				ats[i] = tadd(ats[i], corr[j]);
+ 				break;
+ 			}
+ 	}
+ 	/*
+ 	** Figure out 32-bit-limited starts and counts.
+ 	*/
+ 	timecnt32 = timecnt;
+ 	timei32 = 0;
+ 	leapcnt32 = leapcnt;
+ 	leapi32 = 0;
+ 	while (timecnt32 > 0 && !is32(ats[timecnt32 - 1]))
+ 		--timecnt32;
+ 	while (timecnt32 > 0 && !is32(ats[timei32])) {
+ 		--timecnt32;
+ 		++timei32;
+ 	}
+ 	while (leapcnt32 > 0 && !is32(trans[leapcnt32 - 1]))
+ 		--leapcnt32;
+ 	while (leapcnt32 > 0 && !is32(trans[leapi32])) {
+ 		--leapcnt32;
+ 		++leapi32;
+ 	}
  	fullname = erealloc(fullname,
  		(int) (strlen(directory) + 1 + strlen(name) + 1));
  	(void) sprintf(fullname, "%s/%s", directory, name);
***************
*** 1533,1599 ****
  			exit(EXIT_FAILURE);
  		}
  	}
! 	convert(eitol(typecnt), tzh.tzh_ttisgmtcnt);
! 	convert(eitol(typecnt), tzh.tzh_ttisstdcnt);
! 	convert(eitol(leapcnt), tzh.tzh_leapcnt);
! 	convert(eitol(timecnt), tzh.tzh_timecnt);
! 	convert(eitol(typecnt), tzh.tzh_typecnt);
! 	convert(eitol(charcnt), tzh.tzh_charcnt);
! 	(void) strncpy(tzh.tzh_magic, TZ_MAGIC, sizeof tzh.tzh_magic);
  #define DO(field)	(void) fwrite((void *) tzh.field, \
  				(size_t) sizeof tzh.field, (size_t) 1, fp)
! 	DO(tzh_magic);
! 	DO(tzh_reserved);
! 	DO(tzh_ttisgmtcnt);
! 	DO(tzh_ttisstdcnt);
! 	DO(tzh_leapcnt);
! 	DO(tzh_timecnt);
! 	DO(tzh_typecnt);
! 	DO(tzh_charcnt);
  #undef DO
! 	for (i = 0; i < timecnt; ++i) {
! 		j = leapcnt;
! 		while (--j >= 0)
! 			if (ats[i] >= trans[j]) {
! 				ats[i] = tadd(ats[i], corr[j]);
! 				break;
  			}
! 		puttzcode((long) ats[i], fp);
  	}
! 	if (timecnt > 0)
! 		(void) fwrite((void *) types, (size_t) sizeof types[0],
! 			(size_t) timecnt, fp);
! 	for (i = 0; i < typecnt; ++i) {
! 		puttzcode((long) gmtoffs[i], fp);
! 		(void) putc(isdsts[i], fp);
! 		(void) putc(abbrinds[i], fp);
! 	}
! 	if (charcnt != 0)
! 		(void) fwrite((void *) chars, (size_t) sizeof chars[0],
! 			(size_t) charcnt, fp);
! 	for (i = 0; i < leapcnt; ++i) {
! 		if (roll[i]) {
! 			if (timecnt == 0 || trans[i] < ats[0]) {
! 				j = 0;
! 				while (isdsts[j])
! 					if (++j >= typecnt) {
! 						j = 0;
! 						break;
! 					}
! 			} else {
! 				j = 1;
! 				while (j < timecnt && trans[i] >= ats[j])
! 					++j;
! 				j = types[j - 1];
! 			}
! 			puttzcode((long) tadd(trans[i], -gmtoffs[j]), fp);
! 		} else	puttzcode((long) trans[i], fp);
! 		puttzcode((long) corr[i], fp);
! 	}
! 	for (i = 0; i < typecnt; ++i)
! 		(void) putc(ttisstds[i], fp);
! 	for (i = 0; i < typecnt; ++i)
! 		(void) putc(ttisgmts[i], fp);
  	if (ferror(fp) || fclose(fp)) {
  		(void) fprintf(stderr, _("%s: Error writing %s\n"),
  			progname, fullname);
--- 1580,1699 ----
  			exit(EXIT_FAILURE);
  		}
  	}
! 	for (pass = 1; pass <= 2; ++pass) {
! 		register int	thistimei, thistimecnt;
! 		register int	thisleapi, thisleapcnt;
! 		register int	thistimelim, thisleaplim;
! 		int		writetype[TZ_MAX_TIMES];
! 		int		typemap[TZ_MAX_TYPES];
! 		register int	thistypecnt;
! 
! 		if (pass == 1) {
! 			thistimei = timei32;
! 			thistimecnt = timecnt32;
! 			thisleapi = leapi32;
! 			thisleapcnt = leapcnt32;
! 		} else {
! 			thistimei = 0;
! 			thistimecnt = timecnt;
! 			thisleapi = 0;
! 			thisleapcnt = leapcnt;
! 		}
! 		thistimelim = thistimei + thistimecnt;
! 		thisleaplim = thisleapi + thisleapcnt;
! 		for (i = 0; i < typecnt; ++i)
! 			writetype[i] = thistimecnt == timecnt;
! 		if (thistimecnt == 0)
! 			writetype[types[thistimelim - 1]] = TRUE;
! 		else {
! 			for (i = thistimei - 1; i < thistimelim; ++i)
! 				if (i >= 0)
! 					writetype[types[i]] = TRUE;
! 			/*
! 			** For America/Godthab and Antarctica/Palmer
! 			*/
! 			if (thistimei == 0)
! 				writetype[0] = TRUE;
! 		}
! 		thistypecnt = 0;
! 		for (i = 0; i < typecnt; ++i)
! 			typemap[i] = writetype[i] ?  thistypecnt++ : -1;
  #define DO(field)	(void) fwrite((void *) tzh.field, \
  				(size_t) sizeof tzh.field, (size_t) 1, fp)
! 		tzh = tzh0;
! 		(void) strncpy(tzh.tzh_magic, TZ_MAGIC, sizeof tzh.tzh_magic);
! 		tzh.tzh_version[0] = ZIC_VERSION;
! 		convert(eitol(thistypecnt), tzh.tzh_ttisgmtcnt);
! 		convert(eitol(thistypecnt), tzh.tzh_ttisstdcnt);
! 		convert(eitol(thisleapcnt), tzh.tzh_leapcnt);
! 		convert(eitol(thistimecnt), tzh.tzh_timecnt);
! 		convert(eitol(thistypecnt), tzh.tzh_typecnt);
! 		convert(eitol(charcnt), tzh.tzh_charcnt);
! 		DO(tzh_magic);
! 		DO(tzh_version);
! 		DO(tzh_reserved);
! 		DO(tzh_ttisgmtcnt);
! 		DO(tzh_ttisstdcnt);
! 		DO(tzh_leapcnt);
! 		DO(tzh_timecnt);
! 		DO(tzh_typecnt);
! 		DO(tzh_charcnt);
  #undef DO
! 		for (i = thistimei; i < thistimelim; ++i)
! 			if (pass == 1)
! 				puttzcode((long) ats[i], fp);
! 			else	puttzcode64(ats[i], fp);
! 		for (i = thistimei; i < thistimelim; ++i) {
! 			unsigned char	uc;
! 
! 			uc = typemap[types[i]];
! 			(void) fwrite((void *) &uc,
! 				(size_t) sizeof uc,
! 				(size_t) 1,
! 				fp);
! 		}
! 		for (i = 0; i < typecnt; ++i)
! 			if (writetype[i]) {
! 				puttzcode(gmtoffs[i], fp);
! 				(void) putc(isdsts[i], fp);
! 				(void) putc(abbrinds[i], fp);
  			}
! 		if (charcnt != 0)
! 			(void) fwrite((void *) chars, (size_t) sizeof chars[0],
! 				(size_t) charcnt, fp);
! 		for (i = thisleapi; i < thisleaplim; ++i) {
! 			register zic_t	todo;
! 
! 			if (roll[i]) {
! 				if (timecnt == 0 || trans[i] < ats[0]) {
! 					j = 0;
! 					while (isdsts[j])
! 						if (++j >= typecnt) {
! 							j = 0;
! 							break;
! 						}
! 				} else {
! 					j = 1;
! 					while (j < timecnt &&
! 						trans[i] >= ats[j])
! 							++j;
! 					j = types[j - 1];
! 				}
! 				todo = tadd(trans[i], -gmtoffs[j]);
! 			} else	todo = trans[i];
! 			if (pass == 1)
! 				puttzcode((long) todo, fp);
! 			else	puttzcode64(todo, fp);
! 			puttzcode(corr[i], fp);
! 		}
! 		for (i = 0; i < typecnt; ++i)
! 			if (writetype[i])
! 				(void) putc(ttisstds[i], fp);
! 		for (i = 0; i < typecnt; ++i)
! 			if (writetype[i])
! 				(void) putc(ttisgmts[i], fp);
  	}
! 	(void) fprintf(fp, "\n%s\n", string);
  	if (ferror(fp) || fclose(fp)) {
  		(void) fprintf(stderr, _("%s: Error writing %s\n"),
  			progname, fullname);
***************
*** 1602,1626 ****
  }
  
  static void
! doabbr(abbr, format, letters, isdst)
  char * const		abbr;
  const char * const	format;
  const char * const	letters;
  const int		isdst;
  {
! 	if (strchr(format, '/') == NULL) {
  		if (letters == NULL)
  			(void) strcpy(abbr, format);
  		else	(void) sprintf(abbr, format, letters);
! 	} else if (isdst)
! 		(void) strcpy(abbr, strchr(format, '/') + 1);
! 	else {
! 		(void) strcpy(abbr, format);
! 		*strchr(abbr, '/') = '\0';
  	}
  }
  
  static void
  outzone(zpfirst, zonecount)
  const struct zone * const	zpfirst;
  const int			zonecount;
--- 1702,1928 ----
  }
  
  static void
! doabbr(abbr, format, letters, isdst, doquotes)
  char * const		abbr;
  const char * const	format;
  const char * const	letters;
  const int		isdst;
+ const int		doquotes;
  {
! 	register char *	cp;
! 	register char *	slashp;
! 	register int	len;
! 
! 	slashp = strchr(format, '/');
! 	if (slashp == NULL) {
  		if (letters == NULL)
  			(void) strcpy(abbr, format);
  		else	(void) sprintf(abbr, format, letters);
! 	} else if (isdst) {
! 		(void) strcpy(abbr, slashp + 1);
! 	} else {
! 		if (slashp > format)
! 			(void) strncpy(abbr, format,
! 				(unsigned) (slashp - format));
! 		abbr[slashp - format] = '\0';
  	}
+ 	if (!doquotes)
+ 		return;
+ 	for (cp = abbr; *cp != '\0'; ++cp)
+ 		if (strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZ", *cp) == NULL &&
+ 			strchr("abcdefghijklmnopqrstuvwxyz", *cp) == NULL)
+ 				break;
+ 	len = strlen(abbr);
+ 	if (len > 0 && *cp == '\0')
+ 		return;
+ 	abbr[len + 2] = '\0';
+ 	abbr[len + 1] = '>';
+ 	for ( ; len > 0; --len)
+ 		abbr[len] = abbr[len - 1];
+ 	abbr[0] = '<';
  }
  
  static void
+ updateminmax(x)
+ const int	x;
+ {
+ 	if (min_year > x)
+ 		min_year = x;
+ 	if (max_year < x)
+ 		max_year = x;
+ }
+ 
+ static int
+ stringoffset(result, offset)
+ char *	result;
+ long	offset;
+ {
+ 	register int	hours;
+ 	register int	minutes;
+ 	register int	seconds;
+ 
+ 	result[0] = '\0';
+ 	if (offset < 0) {
+ 		(void) strcpy(result, "-");
+ 		offset = -offset;
+ 	}
+ 	seconds = offset % SECSPERMIN;
+ 	offset /= SECSPERMIN;
+ 	minutes = offset % MINSPERHOUR;
+ 	offset /= MINSPERHOUR;
+ 	hours = offset;
+ 	if (hours >= HOURSPERDAY) {
+ 		result[0] = '\0';
+ 		return -1;
+ 	}
+ 	(void) sprintf(end(result), "%d", hours);
+ 	if (minutes != 0 || seconds != 0) {
+ 		(void) sprintf(end(result), ":%02d", minutes);
+ 		if (seconds != 0)
+ 			(void) sprintf(end(result), ":%02d", seconds);
+ 	}
+ 	return 0;
+ }
+ 
+ static int
+ stringrule(result, rp, dstoff, gmtoff)
+ char *				result;
+ const struct rule * const	rp;
+ const long			dstoff;
+ const long			gmtoff;
+ {
+ 	register long	tod;
+ 
+ 	result = end(result);
+ 	if (rp->r_dycode == DC_DOM) {
+ 		register int	month, total;
+ 
+ 		if (rp->r_dayofmonth == 29 && rp->r_month == TM_FEBRUARY)
+ 			return -1;
+ 		total = 0;
+ 		for (month = 0; month < rp->r_month; ++month)
+ 			total += len_months[0][month];
+ 		(void) sprintf(result, "J%d", total + rp->r_dayofmonth);
+ 	} else {
+ 		register int	week;
+ 
+ 		if (rp->r_dycode == DC_DOWGEQ) {
+ 			week = 1 + rp->r_dayofmonth / DAYSPERWEEK;
+ 			if ((week - 1) * DAYSPERWEEK + 1 != rp->r_dayofmonth)
+ 				return -1;
+ 		} else if (rp->r_dycode == DC_DOWLEQ) {
+ 			if (rp->r_dayofmonth == len_months[1][rp->r_month])
+ 				week = 5;
+ 			else {
+ 				week = 1 + rp->r_dayofmonth / DAYSPERWEEK;
+ 				if (week * DAYSPERWEEK - 1 != rp->r_dayofmonth)
+ 					return -1;
+ 			}
+ 		} else	return -1;	/* "cannot happen" */
+ 		(void) sprintf(result, "M%d.%d.%d",
+ 			rp->r_month + 1, week, rp->r_wday);
+ 	}
+ 	tod = rp->r_tod;
+ 	if (rp->r_todisgmt)
+ 		tod += gmtoff;
+ 	if (rp->r_todisstd && rp->r_stdoff == 0)
+ 		tod += dstoff;
+ 	if (tod < 0) {
+ 		result[0] = '\0';
+ 		return -1;
+ 	}
+ 	if (tod != 2 * SECSPERMIN * MINSPERHOUR) {
+ 		(void) strcat(result, "/");
+ 		if (stringoffset(end(result), tod) != 0)
+ 			return -1;
+ 	}
+ 	return 0;
+ }
+ 
+ static void
+ stringzone(result, zpfirst, zonecount)
+ char *				result;
+ const struct zone * const	zpfirst;
+ const int			zonecount;
+ {
+ 	register const struct zone *	zp;
+ 	register struct rule *		rp;
+ 	register struct rule *		stdrp;
+ 	register struct rule *		dstrp;
+ 	register int			i;
+ 	register const char *		abbrvar;
+ 
+ 	result[0] = '\0';
+ 	zp = zpfirst + zonecount - 1;
+ 	stdrp = dstrp = NULL;
+ 	for (i = 0; i < zp->z_nrules; ++i) {
+ 		rp = &zp->z_rules[i];
+ 		if (rp->r_hiwasnum || rp->r_hiyear != INT_MAX)
+ 			continue;
+ 		if (rp->r_yrtype != NULL)
+ 			continue;
+ 		if (rp->r_stdoff == 0) {
+ 			if (stdrp == NULL)
+ 				stdrp = rp;
+ 			else	return;
+ 		} else {
+ 			if (dstrp == NULL)
+ 				dstrp = rp;
+ 			else	return;
+ 		}
+ 	}
+ 	if (stdrp == NULL && dstrp == NULL) {
+ 		/*
+ 		** There are no rules running through "max".
+ 		** Let's find the latest rule.
+ 		*/
+ 		for (i = 0; i < zp->z_nrules; ++i) {
+ 			rp = &zp->z_rules[i];
+ 			if (stdrp == NULL || rp->r_hiyear > stdrp->r_hiyear ||
+ 				(rp->r_hiyear == stdrp->r_hiyear &&
+ 				rp->r_month > stdrp->r_month))
+ 					stdrp = rp;
+ 		}
+ 		if (stdrp != NULL && stdrp->r_stdoff != 0)
+ 			return;	/* We end up in DST (a POSIX no-no). */
+ 		/*
+ 		** Horrid special case: if year is 2037,
+ 		** presume this is a zone handled on a year-by-year basis;
+ 		** do not try to apply a rule to the zone.
+ 		*/
+ 		if (stdrp != NULL && stdrp->r_hiyear == 2037)
+ 			return;
+ 	}
+ 	if (stdrp == NULL && zp->z_nrules != 0)
+ 		return;
+ 	abbrvar = (stdrp == NULL) ? "" : stdrp->r_abbrvar;
+ 	doabbr(result, zp->z_format, abbrvar, FALSE, TRUE);
+ 	if (stringoffset(end(result), -zp->z_gmtoff) != 0) {
+ 		result[0] = '\0';
+ 		return;
+ 	}
+ 	if (dstrp == NULL)
+ 		return;
+ 	doabbr(end(result), zp->z_format, dstrp->r_abbrvar, TRUE, TRUE);
+ 	if (dstrp->r_stdoff != SECSPERMIN * MINSPERHOUR)
+ 		if (stringoffset(end(result),
+ 			-(zp->z_gmtoff + dstrp->r_stdoff)) != 0) {
+ 				result[0] = '\0';
+ 				return;
+ 		}
+ 	(void) strcat(result, ",");
+ 	if (stringrule(result, dstrp, dstrp->r_stdoff, zp->z_gmtoff) != 0) {
+ 		result[0] = '\0';
+ 		return;
+ 	}
+ 	(void) strcat(result, ",");
+ 	if (stringrule(result, stdrp, dstrp->r_stdoff, zp->z_gmtoff) != 0) {
+ 		result[0] = '\0';
+ 		return;
+ 	}
+ }
+ 
+ static void
  outzone(zpfirst, zonecount)
  const struct zone * const	zpfirst;
  const int			zonecount;
***************
*** 1637,1644 ****
  	register int			startttisstd;
  	register int			startttisgmt;
  	register int			type;
! 	char				startbuf[BUFSIZ];
  
  	INITIALIZE(untiltime);
  	INITIALIZE(starttime);
  	/*
--- 1939,1955 ----
  	register int			startttisstd;
  	register int			startttisgmt;
  	register int			type;
! 	register char *			startbuf;
! 	register char *			ab;
! 	register char *			envvar;
! 	register int			max_abbr_len;
! 	register int			max_envvar_len;
  
+ 	max_abbr_len = 2 + max_format_len + max_abbrvar_len;
+ 	max_envvar_len = 2 * max_abbr_len + 5 * 9;
+ 	startbuf = emalloc(max_abbr_len + 1);
+ 	ab = emalloc(max_abbr_len + 1);
+ 	envvar = emalloc(max_envvar_len + 1);
  	INITIALIZE(untiltime);
  	INITIALIZE(starttime);
  	/*
***************
*** 1653,1659 ****
--- 1964,2012 ----
  	*/
  	startttisstd = FALSE;
  	startttisgmt = FALSE;
+ 	min_year = max_year = EPOCH_YEAR;
+ 	if (leapseen) {
+ 		updateminmax(leapminyear);
+ 		updateminmax(leapmaxyear);
+ 	}
  	for (i = 0; i < zonecount; ++i) {
+ 		zp = &zpfirst[i];
+ 		updateminmax(zp->z_untilrule.r_loyear);
+ 		for (j = 0; j < zp->z_nrules; ++j) {
+ 			rp = &zp->z_rules[j];
+ 			if (rp->r_lowasnum)
+ 				updateminmax(rp->r_loyear);
+ 			if (rp->r_hiwasnum)
+ 				updateminmax(rp->r_hiyear);
+ 		}
+ 	}
+ 	/*
+ 	** Generate lots of data if a rule can't cover all future times.
+ 	*/
+ 	stringzone(envvar, zpfirst, zonecount);
+ 	if (noise && envvar[0] == '\0') {
+ 		register char *	wp;
+ 
+ wp = ecpyalloc(_("no POSIX environment variable for zone"));
+ 		wp = ecatalloc(wp, " ");
+ 		wp = ecatalloc(wp, zpfirst->z_name); 
+ 		warning(wp);
+ 		ifree(wp);
+ 	}
+ 	if (envvar[0] == '\0') {
+ 		if (min_year >= INT_MIN + YEARSPERREPEAT)
+ 			min_year -= YEARSPERREPEAT;
+ 		else	min_year = INT_MIN;
+ 		if (max_year <= INT_MAX - YEARSPERREPEAT)
+ 			max_year += YEARSPERREPEAT;
+ 		else	max_year = INT_MAX;
+ 	}
+ 	/*
+ 	** For the benefit of older systems, generate data through 2037.
+ 	*/
+ 	if (max_year < 2037)
+ 		max_year = 2037;
+ 	for (i = 0; i < zonecount; ++i) {
  		/*
  		** A guess that may well be corrected later.
  		*/
***************
*** 1670,1676 ****
  		if (zp->z_nrules == 0) {
  			stdoff = zp->z_stdoff;
  			doabbr(startbuf, zp->z_format,
! 				(char *) NULL, stdoff != 0);
  			type = addtype(oadd(zp->z_gmtoff, stdoff),
  				startbuf, stdoff != 0, startttisstd,
  				startttisgmt);
--- 2023,2029 ----
  		if (zp->z_nrules == 0) {
  			stdoff = zp->z_stdoff;
  			doabbr(startbuf, zp->z_format,
! 				(char *) NULL, stdoff != 0, FALSE);
  			type = addtype(oadd(zp->z_gmtoff, stdoff),
  				startbuf, stdoff != 0, startttisstd,
  				startttisgmt);
***************
*** 1700,1706 ****
  				register int	k;
  				register zic_t	jtime, ktime;
  				register long	offset;
- 				char		buf[BUFSIZ];
  
  				INITIALIZE(ktime);
  				if (useuntil) {
--- 2053,2058 ----
***************
*** 1756,1779 ****
  							stdoff);
  						doabbr(startbuf, zp->z_format,
  							rp->r_abbrvar,
! 							rp->r_stdoff != 0);
  						continue;
  					}
  					if (*startbuf == '\0' &&
  						startoff == oadd(zp->z_gmtoff,
! 						stdoff))
  							doabbr(startbuf,
  								zp->z_format,
  								rp->r_abbrvar,
  								rp->r_stdoff !=
! 								0);
  				}
  				eats(zp->z_filename, zp->z_linenum,
  					rp->r_filename, rp->r_linenum);
! 				doabbr(buf, zp->z_format, rp->r_abbrvar,
! 					rp->r_stdoff != 0);
  				offset = oadd(zp->z_gmtoff, rp->r_stdoff);
! 				type = addtype(offset, buf, rp->r_stdoff != 0,
  					rp->r_todisstd, rp->r_todisgmt);
  				addtt(ktime, type);
  			}
--- 2108,2134 ----
  							stdoff);
  						doabbr(startbuf, zp->z_format,
  							rp->r_abbrvar,
! 							rp->r_stdoff != 0,
! 							FALSE);
  						continue;
  					}
  					if (*startbuf == '\0' &&
  						startoff == oadd(zp->z_gmtoff,
! 						stdoff)) {
  							doabbr(startbuf,
  								zp->z_format,
  								rp->r_abbrvar,
  								rp->r_stdoff !=
! 								0,
! 								FALSE);
! 					}
  				}
  				eats(zp->z_filename, zp->z_linenum,
  					rp->r_filename, rp->r_linenum);
! 				doabbr(ab, zp->z_format, rp->r_abbrvar,
! 					rp->r_stdoff != 0, FALSE);
  				offset = oadd(zp->z_gmtoff, rp->r_stdoff);
! 				type = addtype(offset, ab, rp->r_stdoff != 0,
  					rp->r_todisstd, rp->r_todisgmt);
  				addtt(ktime, type);
  			}
***************
*** 1806,1812 ****
  				starttime = tadd(starttime, -gmtoff);
  		}
  	}
! 	writezone(zpfirst->z_name);
  }
  
  static void
--- 2161,2170 ----
  				starttime = tadd(starttime, -gmtoff);
  		}
  	}
! 	writezone(zpfirst->z_name, envvar);
! 	ifree(startbuf);
! 	ifree(ab);
! 	ifree(envvar);
  }
  
  static void
***************
*** 2185,2192 ****
  will not work with pre-2004 versions of zic"));
  		}
  	}
- 	if (dayoff < 0 && !TYPE_SIGNED(zic_t))
- 		return min_time;
  	if (dayoff < min_time / SECSPERDAY)
  		return min_time;
  	if (dayoff > max_time / SECSPERDAY)
--- 2543,2548 ----
***************
*** 2212,2218 ****
  		cp = string;
  		wp = NULL;
  		while (isascii((unsigned char) *cp) &&
! 			isalpha((unsigned char) *cp))
  				++cp;
  		if (cp - string == 0)
  wp = _("time zone abbreviation lacks alphabetic at start");
--- 2568,2574 ----
  		cp = string;
  		wp = NULL;
  		while (isascii((unsigned char) *cp) &&
! 			isspace((unsigned char) *cp))
  				++cp;
  		if (cp - string == 0)
  wp = _("time zone abbreviation lacks alphabetic at start");
*** tzftp/scheck.c	Thu Dec 22 09:31:15 2005
--- tzexp3/scheck.c	Tue Jan 17 14:42:55 2006
***************
*** 1,6 ****
  #ifndef lint
  #ifndef NOID
! static char	elsieid[] = "@(#)scheck.c	8.16";
  #endif /* !defined lint */
  #endif /* !defined NOID */
  
--- 1,6 ----
  #ifndef lint
  #ifndef NOID
! static char	elsieid[] = "@(#)scheck.c	8.17";
  #endif /* !defined lint */
  #endif /* !defined NOID */
  
***************
*** 8,27 ****
  
  #include "private.h"
  
! char *
  scheck(string, format)
  const char * const	string;
! char * const		format;
  {
  	register char *		fbuf;
  	register const char *	fp;
  	register char *		tp;
  	register int		c;
! 	register char *		result;
  	char			dummy;
- 	static char		nada;
  
! 	result = &nada;
  	if (string == NULL || format == NULL)
  		return result;
  	fbuf = imalloc((int) (2 * strlen(format) + 4));
--- 8,26 ----
  
  #include "private.h"
  
! const char *
  scheck(string, format)
  const char * const	string;
! const char * const	format;
  {
  	register char *		fbuf;
  	register const char *	fp;
  	register char *		tp;
  	register int		c;
! 	register const char *	result;
  	char			dummy;
  
! 	result = "";
  	if (string == NULL || format == NULL)
  		return result;
  	fbuf = imalloc((int) (2 * strlen(format) + 4));



More information about the tz mailing list