possible 64-bit changes

Arthur David Olson olsona at lecserver.nci.nih.gov
Thu Mar 24 14:30:47 UTC 2005


With a sense that folks are leaning toward evolution rather than revolution,
here are possible changes to the time zone stuff to cater to systems with
64-bit time_t values. There are minor changes to header files, changes to
zic.c (the producer of binary files) and localtime.c (the consumer),
and changes to a couple of man pages. I've also made a minor change to
the Makefile and to zdump.c to improve testing.

No changes are made to any of the data files. The compiler produces output
that starts with data in the old 32-bit format (for the benefit of old systems)
followed by data with 64-bit time_t values. The compiler pumps out 400 years
worth of repeating data so that localtime can handle transitions into the far
future using range reduction logic.

				--ado

*** ../../src/tz/tzfile.h	Mon Mar 21 16:33:42 2005
--- tzfile.h	Mon Mar 21 16:33: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.18";
  #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 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 */
***************
*** 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
*** ../../src/tz/private.h	Mon Mar 21 16:33:42 2005
--- private.h	Mon Mar 21 16:33:17 2005
***************
*** 25,30 ****
--- 25,36 ----
  #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 DAYSPERREPEAT */
+ 
  /*
  ** UNIX was a registered trademark of The Open Group in 2003.
  */
*** ../../src/tz/zic.c	Mon Mar 21 16:33:43 2005
--- zic.c	Thu Mar 24 09:18:56 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.126";
  
  #include "private.h"
  #include "locale.h"
  #include "tzfile.h"
  
+ #define	ZIC_VERSION	'2'
+ 
+ #define zic_t		signed64_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 ----
*** ../../src/tz/localtime.c	Mon Mar 21 16:33:42 2005
--- localtime.c	Thu Mar 24 09:15:28 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)
*** ../../src/tz/tzfile.5	Mon Mar 21 16:33:42 2005
--- tzfile.5	Mon Mar 21 16:33:17 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 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.12
  .\" This file is in the public domain, so clarified as of
  .\" 1996-06-05 by Arthur David Olson (arthur_david_olson at nih.gov).
*** ../../src/tz/zic.8	Mon Mar 21 16:33:43 2005
--- zic.8	Mon Mar 21 16:33:17 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
*** ../../src/tz/Makefile	Mon Mar 21 16:33:41 2005
--- Makefile	Mon Mar 21 16:33:16 2005
***************
*** 1,4 ****
! # @(#)Makefile	7.107
  
  # 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.108
  
  # 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).
***************
*** 403,409 ****
  		for i in "long long" unsigned double; \
  		do \
  			make CFLAGS="-DTYPECHECK -D_TIME_T \"-Dtime_t=$$i\"" ; \
! 			./zdump -v US/Eastern ; \
  			make clean ; \
  		done
  
--- 403,409 ----
  		for i in "long long" unsigned double; \
  		do \
  			make CFLAGS="-DTYPECHECK -D_TIME_T \"-Dtime_t=$$i\"" ; \
! 			./zdump -v Europe/Rome ; \
  			make clean ; \
  		done
  
*** ../../src/tz/zdump.c	Mon Mar 21 16:33:42 2005
--- zdump.c	Tue Mar 22 08:57:18 2005
***************
*** 1,4 ****
! static char	elsieid[] = "@(#)zdump.c	7.63";
  
  /*
  ** This code has been made independent of the rest of the time
--- 1,4 ----
! static char	elsieid[] = "@(#)zdump.c	7.64";
  
  /*
  ** This code has been made independent of the rest of the time
***************
*** 175,186 ****
  			(void) fprintf(stderr, "\n%s: ", progname);
  			(void) fprintf(stderr, tformat(), *tp);
  			(void) fprintf(stderr, " ->");
! 			(void) fprintf(stderr, " sec %d", tmp->tm_sec);
! 			(void) fprintf(stderr, " min %d", tmp->tm_min);
! 			(void) fprintf(stderr, " hour %d", tmp->tm_hour);
! 			(void) fprintf(stderr, " mday %d", tmp->tm_mday);
! 			(void) fprintf(stderr, " mon %d", tmp->tm_mon);
! 			(void) fprintf(stderr, " year %d", tmp->tm_year);
  			(void) fprintf(stderr, " -> ");
  			(void) fprintf(stderr, tformat(), t);
  			(void) fprintf(stderr, "\n");
--- 175,187 ----
  			(void) fprintf(stderr, "\n%s: ", progname);
  			(void) fprintf(stderr, tformat(), *tp);
  			(void) fprintf(stderr, " ->");
! 			(void) fprintf(stderr, " year=%d", tmp->tm_year);
! 			(void) fprintf(stderr, " mon=%d", tmp->tm_mon);
! 			(void) fprintf(stderr, " mday=%d", tmp->tm_mday);
! 			(void) fprintf(stderr, " hour=%d", tmp->tm_hour);
! 			(void) fprintf(stderr, " min=%d", tmp->tm_min);
! 			(void) fprintf(stderr, " sec=%d", tmp->tm_sec);
! 			(void) fprintf(stderr, " isdst=%d", tmp->tm_isdst);
  			(void) fprintf(stderr, " -> ");
  			(void) fprintf(stderr, tformat(), t);
  			(void) fprintf(stderr, "\n");



More information about the tz mailing list