Proposed 64-bit changes

Arthur David Olson olsona at lecserver.nci.nih.gov
Thu Apr 21 19:24:10 UTC 2005


Below are diffs to the time zone code to cope with 64-bit time_t systems;
these reflect suggestions I've received to date. Absent negative feedback,
I'll update the ftp versions on May 2, 2005.

				--ado

diff -c -r tz/localtime.c tzexp/localtime.c
*** tz/localtime.c	Thu Apr 21 15:04:15 2005
--- tzexp/localtime.c	Mon Apr  4 15:39:41 2005
***************
*** 5,11 ****
  
  #ifndef lint
  #ifndef NOID
! static char	elsieid[] = "@(#)localtime.c	7.91";
  #endif /* !defined NOID */
  #endif /* !defined lint */
  
--- 5,11 ----
  
  #ifndef lint
  #ifndef NOID
! static char	elsieid[] = "@(#)localtime.c	7.92";
  #endif /* !defined NOID */
  #endif /* !defined lint */
  
***************
*** 98,103 ****
--- 98,105 ----
  	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];
***************
*** 123,128 ****
--- 125,131 ----
  */
  
  static long		detzcode P((const char * codep));
+ static time_t		detzcode64 P((const char * codep));
  static const char *	getzname P((const char * strp));
  static const char *	getnum P((const char * strp, int * nump, int min,
  				int max));
***************
*** 221,226 ****
--- 224,242 ----
  	return result;
  }
  
+ static time_t
+ detzcode64(codep)
+ const char * const	codep;
+ {
+ 	register signed64_t	result;
+ 	register int		i;
+ 
+ 	result = (codep[0] & 0x80) ? ~0L : 0L;
+ 	for (i = 0; i < 8; ++i)
+ 		result = (result << 8) | (codep[i] & 0xff);
+ 	return (time_t) result;
+ }
+ 
  static void
  settzname P((void))
  {
***************
*** 276,284 ****
  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;
--- 292,308 ----
  register const char *		name;
  register struct state * const	sp;
  {
! 	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;
***************
*** 316,333 ****
  		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);
--- 340,352 ----
  		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);
***************
*** 342,358 ****
  			(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++;
--- 361,379 ----
  			(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++;
***************
*** 380,387 ****
  			register struct lsinfo *	lsisp;
  
  			lsisp = &sp->lsis[i];
! 			lsisp->ls_trans = detzcode(p);
! 			p += 4;
  			lsisp->ls_corr = detzcode(p);
  			p += 4;
  		}
--- 401,409 ----
  			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;
  		}
***************
*** 438,444 ****
--- 460,488 ----
  				}
  				break;
  			}
+ 		/*
+ 		** If this is an old file, we're done.
+ 		*/
+ 		if (u.tzhead.tzh_version[0] == '\0')
+ 			break;
+ 		/*
+ 		** If this is a narrow integer time_t system, we're done.
+ 		*/
+ 		if (stored >= sizeof(time_t) && TYPE_INTEGRAL(time_t))
+ 			break;
+ 		nread -= p - u.buf;
+ 		for (i = 0; i < nread; ++i)
+ 			u.buf[i] = p[i];
  	}
+ 	i = 2 * YEARSPERREPEAT;
+ 	sp->goback = sp->goahead = sp->timecnt > i;
+ 	sp->goback &= sp->types[i] == sp->types[0] &&
+ 		sp->ats[i] - sp->ats[0] == SECSPERREPEAT;
+ 	sp->goahead &=
+ 		sp->types[sp->timecnt - 1] ==
+ 		sp->types[sp->timecnt - 1 - i] &&
+ 		sp->ats[sp->timecnt - 1] - sp->ats[sp->timecnt - 1 - i] ==
+ 		SECSPERREPEAT;
  	return 0;
  }
  
***************
*** 1046,1051 ****
--- 1090,1133 ----
  	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 signed64_t	icycles;
+ 
+ 			if (t < sp->ats[0])
+ 				seconds = sp->ats[0] - t;
+ 			else	seconds = t - sp->ats[sp->timecnt - 1];
+ 			--seconds;
+ 			tcycles = seconds / SECSPERREPEAT;
+ 			++tcycles;
+ 			icycles = tcycles;
+ 			if (tcycles - icycles >= 1 || icycles - tcycles >= 1)
+ 				return NULL;
+ 			seconds = icycles;
+ 			seconds *= SECSPERREPEAT;
+ 			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)
*** tz/private.h	Thu Apr 21 15:20:23 2005
--- tzexp/private.h	Thu Apr 21 15:21:15 2005
***************
*** 21,30 ****
  
  #ifndef lint
  #ifndef NOID
! static char	privatehid[] = "@(#)private.h	7.55";
  #endif /* !defined NOID */
  #endif /* !defined lint */
  
  /*
  ** Defaults for preprocessor symbols.
  ** You can override these in your C compiler options, e.g. `-DHAVE_ADJTIME=0'.
--- 21,36 ----
  
  #ifndef lint
  #ifndef NOID
! static char	privatehid[] = "@(#)private.h	7.62";
  #endif /* !defined NOID */
  #endif /* !defined lint */
  
+ #ifndef SIGNED64_T
+ #define SIGNED64_T	long long
+ #endif /* !defined SIGNED64_T */
+ 
+ typedef SIGNED64_T	signed64_t;
+ 
  /*
  ** Defaults for preprocessor symbols.
  ** You can override these in your C compiler options, e.g. `-DHAVE_ADJTIME=0'.
***************
*** 308,313 ****
--- 314,327 ----
  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 */
+ 
+ #ifndef SECSPERREPEAT
+ #define SECSPERREPEAT		12622780800
+ #endif /* !defined SECSPERREPEAT */
+ 
  /*
  ** UNIX was a registered trademark of The Open Group in 2003.
  */
diff -c -r tz/tzfile.5 tzexp/tzfile.5
*** tz/tzfile.5	Thu Apr 21 15:04:14 2005
--- tzexp/tzfile.5	Thu Apr 21 15:09:16 2005
***************
*** 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.11
  .\" This file is in the public domain, so clarified as of
  .\" 1996-06-05 by Arthur David Olson (arthur_david_olson at nih.gov).
--- 133,145 ----
  .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.
  .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 (arthur_david_olson at nih.gov).
diff -c -r tz/tzfile.h tzexp/tzfile.h
*** tz/tzfile.h	Thu Apr 21 15:04:14 2005
--- tzexp/tzfile.h	Thu Apr 21 15:09:17 2005
***************
*** 21,27 ****
  
  #ifndef lint
  #ifndef NOID
! static char	tzfilehid[] = "@(#)tzfile.h	7.17";
  #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,102 ----
  */
  
  /*
+ ** 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.
+ */
+ 
+ /*
  ** 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	1000
  #endif /* !defined TZ_MAX_TIMES */
  
  #ifndef TZ_MAX_TYPES
diff -c -r tz/zic.8 tzexp/zic.8
*** tz/zic.8	Thu Apr 21 15:04:14 2005
--- tzexp/zic.8	Mon Apr  4 15:39:43 2005
***************
*** 21,28 ****
  .B \-L
  .I leapsecondfilename
  ] [
- .B \-s
- ] [
  .B \-y
  .I command
  ] [
--- 21,26 ----
***************
*** 86,96 ****
  .IR zic )
  appears in the input.
  .TP
- .B \-s
- Limit time values stored in output files to values that are the same
- whether they're taken to be signed or unsigned.
- You can use this option to generate SVVS-compatible files.
- .TP
  .BI "\-y " command
  Use the given
  .I command
--- 84,89 ----
***************
*** 421,424 ****
  /usr/local/etc/zoneinfo	standard directory used for created files
  .SH "SEE ALSO"
  newctime(3), tzfile(5), zdump(8)
! .\" @(#)zic.8	7.22
--- 414,417 ----
  /usr/local/etc/zoneinfo	standard directory used for created files
  .SH "SEE ALSO"
  newctime(3), tzfile(5), zdump(8)
! .\" @(#)zic.8	7.23
diff -c -r tz/zic.c tzexp/zic.c
*** tz/zic.c	Thu Apr 21 15:04:15 2005
--- tzexp/zic.c	Mon Apr  4 15:39:43 2005
***************
*** 1,15 ****
! static char	elsieid[] = "@(#)zic.c	7.122";
  
- /*
- ** 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"
  
  #if HAVE_SYS_STAT_H
  #include "sys/stat.h"
  #endif
--- 1,13 ----
! static char	elsieid[] = "@(#)zic.c	7.127";
  
  #include "private.h"
  #include "locale.h"
  #include "tzfile.h"
  
+ #define	ZIC_VERSION	'2'
+ 
+ typedef signed64_t	zic_t;
+ 
  #if HAVE_SYS_STAT_H
  #include "sys/stat.h"
  #endif
***************
*** 40,45 ****
--- 38,45 ----
  	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 */
  
***************
*** 99,104 ****
--- 99,105 ----
  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));
***************
*** 117,122 ****
--- 118,124 ----
  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));
***************
*** 126,131 ****
--- 128,134 ----
  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,
***************
*** 146,158 ****
  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;
--- 149,162 ----
  static int		errors;
  static const char *	filename;
  static int		leapcnt;
+ static int		leapseen;
+ static int		leapminyear;
+ static int		leapmaxyear;
  static int		linenum;
  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;
***************
*** 449,455 ****
  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);
  	(void) exit(EXIT_FAILURE);
--- 453,459 ----
  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);
  	(void) exit(EXIT_FAILURE);
***************
*** 460,466 ****
  static const char *	directory;
  static const char *	leapsec;
  static const char *	yitcommand;
- static int		sflag = FALSE;
  
  int
  main(argc, argv)
--- 464,469 ----
***************
*** 482,487 ****
--- 485,495 ----
  	(void) textdomain(TZ_DOMAIN);
  #endif /* HAVE_GETTEXT */
  	progname = argv[0];
+ 	if (8 > sizeof(signed64_t)) {
+ 		(void) fprintf(stderr,
+ "%s: wild compilation-time specification of SIGNED64_T\n", progname);
+ 		exit(EXIT_FAILURE);
+ 	}
  	for (i = 1; i < argc; ++i)
  		if (strcmp(argv[i], "--version") == 0) {
  			(void) printf("%s\n", elsieid);
***************
*** 545,551 ****
  				noise = TRUE;
  				break;
  			case 's':
! 				sflag = TRUE;
  				break;
  		}
  	if (optind == argc - 1 && strcmp(argv[optind], "=") == 0)
--- 553,559 ----
  				noise = TRUE;
  				break;
  			case 's':
! 				(void) printf("%s: -s ignored\n", progname);
  				break;
  		}
  	if (optind == argc - 1 && strcmp(argv[optind], "=") == 0)
***************
*** 667,720 ****
  	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
--- 675,691 ----
  	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
***************
*** 1155,1160 ****
--- 1126,1136 ----
  		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) {
***************
*** 1309,1315 ****
  	*/
  	cp = loyearp;
  	lp = byword(cp, begin_years);
! 	if (lp != NULL) switch ((int) lp->l_value) {
  		case YR_MINIMUM:
  			rp->r_loyear = INT_MIN;
  			break;
--- 1285,1292 ----
  	*/
  	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;
***************
*** 1324,1337 ****
  	} 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;
--- 1301,1311 ----
  	} 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;
***************
*** 1349,1359 ****
  	} 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"));
--- 1323,1328 ----
***************
*** 1368,1375 ****
  		}
  		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:
--- 1337,1342 ----
***************
*** 1423,1429 ****
  char * const	buf;
  {
  	register int	i;
! 	register long	shift;
  
  	for (i = 0, shift = 24; i < 4; ++i, shift -= 8)
  		buf[i] = val >> shift;
--- 1390,1396 ----
  char * const	buf;
  {
  	register int	i;
! 	register int	shift;
  
  	for (i = 0, shift = 24; i < 4; ++i, shift -= 8)
  		buf[i] = val >> shift;
***************
*** 1430,1435 ****
--- 1397,1414 ----
  }
  
  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;
***************
*** 1440,1445 ****
--- 1419,1435 ----
  	(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)
  void *	avp;
***************
*** 1452,1467 ****
  	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.
--- 1442,1469 ----
  	else	return 0;
  }
  
+ static int
+ is32(x)
+ zic_t	x;
+ {
+ 	x >>= 31;
+ 	return x == 0 || x == ~0;
+ }
+ 
  static void
  writezone(name)
  const char * const	name;
  {
! 	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.
***************
*** 1505,1510 ****
--- 1507,1542 ----
  		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);
***************
*** 1529,1595 ****
  			(void) 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);
--- 1561,1652 ----
  			(void) exit(EXIT_FAILURE);
  		}
  	}
! 	for (pass = 1; pass <= 2; ++pass) {
! 		register int	thistimei, thistimecnt;
! 		register int	thisleapi, thisleapcnt;
! 		register int	thistimelim, thisleaplim;
! 
! 		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;
  #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(typecnt), tzh.tzh_ttisgmtcnt);
! 		convert(eitol(typecnt), tzh.tzh_ttisstdcnt);
! 		convert(eitol(thisleapcnt), tzh.tzh_leapcnt);
! 		convert(eitol(thistimecnt), tzh.tzh_timecnt);
! 		convert(eitol(typecnt), 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);
! 		if (thistimecnt > 0)
! 			(void) fwrite((void *) &types[thistimei],
! 				(size_t) sizeof types[0],
! 				(size_t) thistimecnt,
! 				fp);
! 		for (i = 0; i < typecnt; ++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(todo, fp);
! 			else	puttzcode64(todo, fp);
! 			puttzcode(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);
***************
*** 1617,1622 ****
--- 1674,1689 ----
  }
  
  static void
+ updateminmax(x)
+ const int	x;
+ {
+ 	if (min_year > x)
+ 		min_year = x;
+ 	if (max_year < x)
+ 		max_year = x;
+ }
+ 
+ static void
  outzone(zpfirst, zonecount)
  const struct zone * const	zpfirst;
  const int			zonecount;
***************
*** 1649,1655 ****
--- 1716,1744 ----
  	*/
  	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);
+ 		}
+ 	}
+ 	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 (i = 0; i < zonecount; ++i) {
  		/*
  		** A guess that may well be corrected later.
  		*/
***************
*** 2180,2187 ****
  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)
--- 2269,2274 ----



More information about the tz mailing list