tzcode.diff.diff.txt

text/plain

Filename: tzcode.diff.diff.txt
Type: text/plain
Part: 0
Message: Re: Cannot find a working 64-bit integer type on Illumos
--- zic.c-master-vs-upstream.diff	2024-07-04 14:38:42.919508000 +1200
+++ zic.c-patched-vs-upstream.diff	2024-07-04 14:37:23.663247000 +1200
@@ -1,6 +1,6 @@
 --- zic.filtered.c	2024-07-04 12:24:07.383657000 +1200
-+++ zic.c	2024-07-04 14:38:19.086696000 +1200
-@@ -3,104 +3,66 @@
++++ zic.c	2024-07-04 14:17:36.438520000 +1200
+@@ -3,104 +3,72 @@
  /*
   * This file is in the public domain, so clarified as of
   * 2006-07-17 by Arthur David Olson.
@@ -19,6 +19,8 @@
  
 -#include "version.h"
 +#include <fcntl.h>
++#include <inttypes.h>
++#include <stdint.h>
 +#include <sys/stat.h>
 +#include <time.h>
 +
@@ -36,20 +38,18 @@
 +#define	ZIC_VERSION_PRE_2013 '2'
 +#define	ZIC_VERSION	'3'
  
--typedef int_fast64_t zic_t;
--static zic_t const
--			ZIC_MIN = INT_FAST64_MIN,
--			ZIC_MAX = INT_FAST64_MAX,
+ typedef int_fast64_t zic_t;
+ static zic_t const
+ 			ZIC_MIN = INT_FAST64_MIN,
+ 			ZIC_MAX = INT_FAST64_MAX,
 -			ZIC32_MIN = -1 - (zic_t) 0x7fffffff,
 -			ZIC32_MAX = 0x7fffffff;
--#define SCNdZIC SCNdFAST64
-+typedef int64 zic_t;
-+#define ZIC_MIN PG_INT64_MIN
-+#define ZIC_MAX PG_INT64_MAX
++			ZIC32_MIN = INT32_MIN,
++			ZIC32_MAX = INT32_MAX;
+ #define SCNdZIC SCNdFAST64
  
  #ifndef ZIC_MAX_ABBR_LEN_WO_WARN
--#define ZIC_MAX_ABBR_LEN_WO_WARN 6
-+#define ZIC_MAX_ABBR_LEN_WO_WARN	6
+ #define ZIC_MAX_ABBR_LEN_WO_WARN 6
  #endif							/* !defined ZIC_MAX_ABBR_LEN_WO_WARN */
  
 -/* Minimum and maximum years, assuming signed 32-bit pg_time_t.  */
@@ -137,7 +137,7 @@
  	bool		r_hiwasnum;
  
  	int			r_month;		/* 0..11 */
-@@ -121,18 +83,16 @@
+@@ -121,18 +89,16 @@
  };
  
  /*
@@ -162,7 +162,7 @@
  	lineno_t	z_linenum;
  
  	const char *z_name;
-@@ -151,59 +111,46 @@
+@@ -151,59 +117,46 @@
  	zic_t		z_untiltime;
  };
  
@@ -245,7 +245,7 @@
  					const char *loyearp, const char *hiyearp,
  					const char *typep, const char *monthp,
  					const char *dayp, const char *timep);
-@@ -214,10 +161,21 @@
+@@ -214,10 +167,21 @@
  {
  PERCENT_Z_LEN_BOUND = sizeof "+995959" - 1};
  
@@ -268,7 +268,7 @@
  static int	leapcnt;
  static bool leapseen;
  static zic_t leapminyear;
-@@ -228,132 +186,99 @@
+@@ -228,132 +192,99 @@
  static zic_t max_year;
  static zic_t min_year;
  static bool noise;
@@ -453,7 +453,7 @@
  
  static struct rule *rules;
  static ptrdiff_t nrules;		/* number of rules */
-@@ -365,7 +290,7 @@
+@@ -365,7 +296,7 @@
  
  struct link
  {
@@ -462,7 +462,7 @@
  	lineno_t	l_linenum;
  	const char *l_target;
  	const char *l_linkname;
-@@ -381,8 +306,8 @@
+@@ -381,8 +312,8 @@
  	const int	l_value;
  };
  
@@ -473,7 +473,7 @@
  
  static struct lookup const zi_line_codes[] = {
  	{"Rule", LC_RULE},
-@@ -436,10 +361,12 @@
+@@ -436,10 +367,12 @@
  
  static struct lookup const begin_years[] = {
  	{"minimum", YR_MINIMUM},
@@ -486,7 +486,7 @@
  	{"maximum", YR_MAXIMUM},
  	{"only", YR_ONLY},
  	{NULL, 0}
-@@ -480,79 +407,30 @@
+@@ -480,79 +413,30 @@
   * Memory allocation.
   */
  
@@ -574,7 +574,7 @@
  emalloc(size_t size)
  {
  	return memcheck(malloc(size));
-@@ -564,100 +442,66 @@
+@@ -564,100 +448,66 @@
  	return memcheck(realloc(ptr, size));
  }
  
@@ -703,7 +703,7 @@
  {
  	va_list		args;
  
-@@ -667,8 +511,8 @@
+@@ -667,8 +517,8 @@
  	errors = true;
  }
  
@@ -714,7 +714,7 @@
  {
  	va_list		args;
  
-@@ -679,11 +523,8 @@
+@@ -679,11 +529,8 @@
  	warnings = true;
  }
  
@@ -727,7 +727,7 @@
  {
  	char const *e = (ferror(stream) ? _("I/O error")
  					 : fclose(stream) != 0 ? strerror(errno) : NULL);
-@@ -694,26 +535,23 @@
+@@ -694,26 +541,23 @@
  				dir ? dir : "", dir ? "/" : "",
  				name ? name : "", name ? ": " : "",
  				e);
@@ -759,7 +759,7 @@
  	exit(status);
  }
  
-@@ -741,221 +579,8 @@
+@@ -741,221 +585,8 @@
  	}
  }
  
@@ -982,7 +982,7 @@
  /* The minimum and maximum values representable in a TZif file.  */
  static zic_t const min_time = MINVAL(zic_t, TIME_T_BITS_IN_FILE);
  static zic_t const max_time = MAXVAL(zic_t, TIME_T_BITS_IN_FILE);
-@@ -965,19 +590,18 @@
+@@ -965,13 +596,12 @@
  static zic_t lo_time = MINVAL(zic_t, TIME_T_BITS_IN_FILE);
  static zic_t hi_time = MAXVAL(zic_t, TIME_T_BITS_IN_FILE);
  
@@ -999,32 +999,8 @@
  /* Set the time range of the output to TIMERANGE.
     Return true if successful.  */
  static bool
- timerange_option(char *timerange)
- {
--	intmax_t	lo = min_time,
-+	int64		lo = min_time,
- 				hi = max_time;
- 	char	   *lo_end = timerange,
- 			   *hi_end;
-@@ -986,7 +610,7 @@
- 	{
- 		errno = 0;
- 		lo = strtoimax(timerange + 1, &lo_end, 10);
--		if (lo_end == timerange + 1 || (lo == INTMAX_MAX && errno == ERANGE))
-+		if (lo_end == timerange + 1 || (lo == PG_INT64_MAX && errno == ERANGE))
- 			return false;
+@@ -1000,33 +630,15 @@
  	}
- 	hi_end = lo_end;
-@@ -994,39 +618,21 @@
- 	{
- 		errno = 0;
- 		hi = strtoimax(lo_end + 2, &hi_end, 10);
--		if (hi_end == lo_end + 2 || hi == INTMAX_MIN)
-+		if (hi_end == lo_end + 2 || hi == PG_INT64_MIN)
- 			return false;
--		hi -= !(hi == INTMAX_MAX && errno == ERANGE);
-+		hi -= !(hi == PG_INT64_MAX && errno == ERANGE);
- 	}
  	if (*hi_end || hi < lo || max_time < lo || hi < min_time)
  		return false;
 -	lo_time = max(lo, min_time);
@@ -1060,7 +1036,7 @@
  static const char *tzdefault;
  
  /* -1 if the TZif output file should be slim, 0 if default, 1 if the
-@@ -1053,18 +659,10 @@
+@@ -1053,18 +665,10 @@
  				j;
  	bool		timerange_given = false;
  
@@ -1081,7 +1057,7 @@
  	if (TYPE_BIT(zic_t) < 64)
  	{
  		fprintf(stderr, "%s: %s\n", progname,
-@@ -1074,16 +672,15 @@
+@@ -1074,16 +678,15 @@
  	for (k = 1; k < argc; k++)
  		if (strcmp(argv[k], "--version") == 0)
  		{
@@ -1101,7 +1077,7 @@
  		switch (c)
  		{
  			default:
-@@ -1106,36 +703,33 @@
+@@ -1106,36 +709,33 @@
  				break;
  			case 'd':
  				if (directory == NULL)
@@ -1144,7 +1120,7 @@
  							progname);
  					return EXIT_FAILURE;
  				}
-@@ -1156,12 +750,11 @@
+@@ -1156,12 +756,11 @@
  				break;
  			case 'L':
  				if (leapsec == NULL)
@@ -1159,7 +1135,7 @@
  							progname);
  					return EXIT_FAILURE;
  				}
-@@ -1169,12 +762,15 @@
+@@ -1169,12 +768,15 @@
  			case 'v':
  				noise = true;
  				break;
@@ -1177,7 +1153,7 @@
  							progname);
  					return EXIT_FAILURE;
  				}
-@@ -1187,27 +783,12 @@
+@@ -1187,27 +789,12 @@
  				}
  				timerange_given = true;
  				break;
@@ -1205,7 +1181,7 @@
  	if (bloat == 0)
  	{
  		static char const bloat_default[] = ZIC_BLOAT_DEFAULT;
-@@ -1220,23 +801,22 @@
+@@ -1220,23 +807,22 @@
  			abort();			/* Configuration error.  */
  	}
  	if (directory == NULL)
@@ -1232,7 +1208,7 @@
  	for (i = 0; i < nzones; i = j)
  	{
  		/*
-@@ -1246,15 +826,28 @@
+@@ -1246,15 +832,28 @@
  			continue;
  		outzone(&zones[i], j - i);
  	}
@@ -1264,7 +1240,7 @@
  		dolink(psxrules, TZDEFRULES, true);
  	}
  	if (warnings && (ferror(stderr) || fclose(stderr) != 0))
-@@ -1347,211 +940,22 @@
+@@ -1347,211 +946,22 @@
  	return componentcheck(name, component, cp);
  }
  
@@ -1487,7 +1463,7 @@
  	char const *f = target;
  	char	   *result = NULL;
  
-@@ -1559,14 +963,13 @@
+@@ -1559,14 +969,13 @@
  	{
  		/* Make F absolute too.  */
  		size_t		len = strlen(directory);
@@ -1506,7 +1482,7 @@
  	}
  	for (i = 0; f[i] && f[i] == linkname[i]; i++)
  		if (f[i] == '/')
-@@ -1574,7 +977,7 @@
+@@ -1574,7 +983,7 @@
  	for (; linkname[i]; i++)
  		dotdots += linkname[i] == '/' && linkname[i - 1] != '/';
  	taillen = strlen(f + dir_len);
@@ -1515,7 +1491,7 @@
  	if (dotdotetcsize <= linksize)
  	{
  		if (!result)
-@@ -1585,133 +988,80 @@
+@@ -1585,133 +994,80 @@
  	}
  	return result;
  }
@@ -1693,7 +1669,7 @@
  		{
  			FILE	   *fp,
  					   *tp;
-@@ -1726,37 +1076,69 @@
+@@ -1726,37 +1082,69 @@
  						progname, directory, target, e);
  				exit(EXIT_FAILURE);
  			}
@@ -1776,7 +1752,7 @@
  /*
   * Associate sets of rules with zones.
   */
-@@ -1768,10 +1150,8 @@
+@@ -1768,10 +1156,8 @@
  static int
  rcomp(const void *cp1, const void *cp2)
  {
@@ -1789,7 +1765,7 @@
  }
  
  static void
-@@ -1784,7 +1164,7 @@
+@@ -1784,7 +1170,7 @@
  				base,
  				out;
  
@@ -1798,7 +1774,7 @@
  	{
  		qsort(rules, nrules, sizeof *rules, rcomp);
  		for (i = 0; i < nrules - 1; ++i)
-@@ -1792,21 +1172,23 @@
+@@ -1792,21 +1178,23 @@
  			if (strcmp(rules[i].r_name,
  					   rules[i + 1].r_name) != 0)
  				continue;
@@ -1828,7 +1804,7 @@
  					continue;
  				break;
  			}
-@@ -1842,7 +1224,7 @@
+@@ -1842,7 +1230,7 @@
  			/*
  			 * Maybe we have a local standard time offset.
  			 */
@@ -1837,7 +1813,7 @@
  			zp->z_save = getsave(zp->z_rule, &zp->z_isdst);
  
  			/*
-@@ -1857,85 +1239,71 @@
+@@ -1857,85 +1245,60 @@
  		exit(EXIT_FAILURE);
  }
  
@@ -1947,23 +1923,12 @@
 -			/* nothing to do */
 +			if (name == leapsec && *buf == '#')
 +			{
-+				/*
-+				 * PG: INT64_FORMAT isn't portable for sscanf, so be content
-+				 * with scanning a "long".  Once we are requiring C99 in all
-+				 * live branches, it'd be sensible to adopt upstream's
-+				 * practice of using the <inttypes.h> macros.  But for now, we
-+				 * don't actually use this code, and it won't overflow before
-+				 * 2038 anyway.
-+				 */
-+				long		cl_tmp;
-+
-+				sscanf(buf, "#expires %ld", &cl_tmp);
-+				comment_leapexpires = cl_tmp;
++				sscanf(buf, "#expires %" SCNdZIC, &comment_leapexpires);
 +			}
  		}
  		else if (wantcont)
  		{
-@@ -1944,7 +1312,7 @@
+@@ -1944,7 +1307,7 @@
  		else
  		{
  			struct lookup const *line_codes
@@ -1972,7 +1937,7 @@
  
  			lp = byword(fields[0], line_codes);
  			if (lp == NULL)
-@@ -1971,12 +1339,16 @@
+@@ -1971,12 +1334,16 @@
  						inexpires(fields, nfields);
  						wantcont = false;
  						break;
@@ -1992,26 +1957,7 @@
  	if (wantcont)
  		error(_("expected continuation line not found"));
  }
-@@ -1992,7 +1364,8 @@
- static zic_t
- gethms(char const *string, char const *errstring)
- {
--	zic_t		hh;
-+	/* PG: make hh be int not zic_t to avoid sscanf portability issues */
-+	int			hh;
- 	int			sign,
- 				mm = 0,
- 				ss = 0;
-@@ -2014,7 +1387,7 @@
- 	else
- 		sign = 1;
- 	switch (sscanf(string,
--				   "%" SCNdZIC "%c%d%c%d%c%1d%*[0]%c%*[0123456789]%c",
-+				   "%d%c%d%c%d%c%1d%*[0]%c%*[0123456789]%c",
- 				   &hh, &hhx, &mm, &mmx, &ss, &ssx, &tenths, &xr, &xs))
- 	{
- 		default:
-@@ -2022,19 +1395,19 @@
+@@ -2022,19 +1389,19 @@
  			break;
  		case 8:
  			ok = '0' <= xr && xr <= '9';
@@ -2035,12 +1981,12 @@
  		case 1:
  			break;
  	}
-@@ -2050,16 +1423,19 @@
+@@ -2050,16 +1417,19 @@
  		error("%s", errstring);
  		return 0;
  	}
 +	/* Some compilers warn that this test is unsatisfiable for 32-bit ints */
-+#if INT_MAX > PG_INT32_MAX
++#if INT_MAX > INT32_MAX
  	if (ZIC_MAX / SECSPERHOUR < hh)
  	{
  		error(_("time overflow"));
@@ -2056,7 +2002,7 @@
  				sign * (mm * SECSPERMIN + ss));
  }
  
-@@ -2068,7 +1444,7 @@
+@@ -2068,7 +1438,7 @@
  {
  	int			dst = -1;
  	zic_t		save;
@@ -2065,7 +2011,7 @@
  
  	if (fieldlen != 0)
  	{
-@@ -2094,7 +1470,7 @@
+@@ -2094,7 +1464,7 @@
  static void
  inrule(char **fields, int nfields)
  {
@@ -2074,7 +2020,7 @@
  
  	if (nfields != RULE_FIELDS)
  	{
-@@ -2125,15 +1501,13 @@
+@@ -2125,15 +1495,13 @@
  			error(_("Invalid rule name \"%s\""), fields[RF_NAME]);
  			return;
  	}
@@ -2095,7 +2041,7 @@
  	if (max_abbrvar_len < strlen(r.r_abbrvar))
  		max_abbrvar_len = strlen(r.r_abbrvar);
  	rules = growalloc(rules, sizeof *rules, nrules, &nrules_alloc);
-@@ -2152,13 +1526,15 @@
+@@ -2152,13 +1520,15 @@
  	}
  	if (lcltime != NULL && strcmp(fields[ZF_NAME], tzdefault) == 0)
  	{
@@ -2113,7 +2059,7 @@
  			  TZDEFRULES);
  		return false;
  	}
-@@ -2167,9 +1543,9 @@
+@@ -2167,9 +1537,9 @@
  			strcmp(zones[i].z_name, fields[ZF_NAME]) == 0)
  		{
  			error(_("duplicate zone name %s"
@@ -2125,7 +2071,7 @@
  				  zones[i].z_linenum);
  			return false;
  		}
-@@ -2192,8 +1568,7 @@
+@@ -2192,8 +1562,7 @@
  {
  	char	   *cp;
  	char	   *cp1;
@@ -2135,7 +2081,7 @@
  	int			i_stdoff,
  				i_rule,
  				i_format;
-@@ -2212,6 +1587,7 @@
+@@ -2212,6 +1581,7 @@
  		i_untilmonth = ZFC_TILMONTH;
  		i_untilday = ZFC_TILDAY;
  		i_untiltime = ZFC_TILTIME;
@@ -2143,7 +2089,7 @@
  	}
  	else if (!namecheck(fields[ZF_NAME]))
  		return false;
-@@ -2224,11 +1600,12 @@
+@@ -2224,11 +1594,12 @@
  		i_untilmonth = ZF_TILMONTH;
  		i_untilday = ZF_TILDAY;
  		i_untiltime = ZF_TILTIME;
@@ -2158,7 +2104,7 @@
  	{
  		if ((*++cp != 's' && *cp != 'z') || strchr(cp, '%')
  			|| strchr(fields[i_format], '/'))
-@@ -2237,25 +1614,31 @@
+@@ -2237,25 +1608,31 @@
  			return false;
  		}
  	}
@@ -2204,7 +2150,7 @@
  		z.z_untiltime = rpytime(&z.z_untilrule,
  								z.z_untilrule.r_loyear);
  		if (iscont && nzones > 0 &&
-@@ -2265,21 +1648,10 @@
+@@ -2265,21 +1642,10 @@
  			zones[nzones - 1].z_untiltime < max_time &&
  			zones[nzones - 1].z_untiltime >= z.z_untiltime)
  		{
@@ -2227,7 +2173,7 @@
  	zones = growalloc(zones, sizeof *zones, nzones, &nzones_alloc);
  	zones[nzones++] = z;
  
-@@ -2291,13 +1663,15 @@
+@@ -2291,12 +1657,13 @@
  }
  
  static zic_t
@@ -2238,23 +2184,11 @@
  	const struct lookup *lp;
  	zic_t		i,
  				j;
--	zic_t		year;
 +
-+	/* PG: make year be int not zic_t to avoid sscanf portability issues */
-+	int			year;
+ 	zic_t		year;
  	int			month,
  				day;
- 	zic_t		dayoff,
-@@ -2307,7 +1681,7 @@
- 
- 	dayoff = 0;
- 	cp = fields[LP_YEAR];
--	if (sscanf(cp, "%" SCNdZIC "%c", &year, &xs) != 1)
-+	if (sscanf(cp, "%d%c", &year, &xs) != 1)
- 	{
- 		/*
- 		 * Leapin' Lizards!
-@@ -2384,7 +1758,7 @@
+@@ -2384,7 +1751,7 @@
  		error(_("wrong number of fields on Leap line"));
  	else
  	{
@@ -2263,7 +2197,7 @@
  
  		if (0 <= t)
  		{
-@@ -2417,7 +1791,7 @@
+@@ -2417,7 +1784,7 @@
  	else if (0 <= leapexpires)
  		error(_("multiple Expires lines"));
  	else
@@ -2272,7 +2206,7 @@
  }
  
  static void
-@@ -2437,15 +1811,15 @@
+@@ -2437,15 +1804,15 @@
  	}
  	if (!namecheck(fields[LF_LINKNAME]))
  		return;
@@ -2292,13 +2226,7 @@
  rulesub(struct rule *rp, const char *loyearp, const char *hiyearp,
  		const char *typep, const char *monthp, const char *dayp,
  		const char *timep)
-@@ -2456,15 +1830,18 @@
- 	char	   *ep;
- 	char		xs;
- 
-+	/* PG: year_tmp is to avoid sscanf portability issues */
-+	int			year_tmp;
-+
+@@ -2459,12 +1826,12 @@
  	if ((lp = byword(monthp, mon_names)) == NULL)
  	{
  		error(_("invalid month name"));
@@ -2313,7 +2241,7 @@
  	if (*dp != '\0')
  	{
  		ep = dp + strlen(dp) - 1;
-@@ -2497,22 +1874,28 @@
+@@ -2497,22 +1864,26 @@
  	 */
  	cp = loyearp;
  	lp = byword(cp, begin_years);
@@ -2340,10 +2268,7 @@
 +						progname, lp->l_value);
 +				exit(EXIT_FAILURE);
  		}
--	else if (sscanf(cp, "%" SCNdZIC "%c", &rp->r_loyear, &xs) != 1)
-+	else if (sscanf(cp, "%d%c", &year_tmp, &xs) == 1)
-+		rp->r_loyear = year_tmp;
-+	else
+ 	else if (sscanf(cp, "%" SCNdZIC "%c", &rp->r_loyear, &xs) != 1)
  	{
  		error(_("invalid starting year"));
 -		return false;
@@ -2351,7 +2276,7 @@
  	}
  	cp = hiyearp;
  	lp = byword(cp, end_years);
-@@ -2520,37 +1903,45 @@
+@@ -2520,37 +1891,43 @@
  	if (!rp->r_hiwasnum)
  		switch (lp->l_value)
  		{
@@ -2372,10 +2297,7 @@
 +						progname, lp->l_value);
 +				exit(EXIT_FAILURE);
  		}
--	else if (sscanf(cp, "%" SCNdZIC "%c", &rp->r_hiyear, &xs) != 1)
-+	else if (sscanf(cp, "%d%c", &year_tmp, &xs) == 1)
-+		rp->r_hiyear = year_tmp;
-+	else
+ 	else if (sscanf(cp, "%" SCNdZIC "%c", &rp->r_hiyear, &xs) != 1)
  	{
  		error(_("invalid ending year"));
 -		return false;
@@ -2404,7 +2326,7 @@
  	if ((lp = byword(dp, lasts)) != NULL)
  	{
  		rp->r_dycode = DC_DOWLEQ;
-@@ -2559,9 +1950,9 @@
+@@ -2559,9 +1936,9 @@
  	}
  	else
  	{
@@ -2416,7 +2338,7 @@
  			rp->r_dycode = DC_DOWGEQ;
  		else
  		{
-@@ -2575,13 +1966,13 @@
+@@ -2575,13 +1952,13 @@
  			{
  				error(_("invalid day of month"));
  				free(dp);
@@ -2432,7 +2354,7 @@
  			}
  			rp->r_wday = lp->l_value;
  		}
-@@ -2591,37 +1982,36 @@
+@@ -2591,37 +1968,36 @@
  		{
  			error(_("invalid day of month"));
  			free(dp);
@@ -2446,7 +2368,7 @@
  
  static void
 -convert(uint_fast32_t val, char *buf)
-+convert(const int32 val, char *const buf)
++convert(const int_fast32_t val, char *const buf)
  {
  	int			i;
  	int			shift;
@@ -2459,7 +2381,7 @@
  
  static void
 -convert64(uint_fast64_t val, char *buf)
-+convert64(const zic_t val, char *const buf)
++convert64(uint_fast64_t val, char *const buf)
  {
  	int			i;
  	int			shift;
@@ -2472,11 +2394,11 @@
  
  static void
 -puttzcode(zic_t val, FILE *fp)
-+puttzcode(const int32 val, FILE *const fp)
++puttzcode(zic_t val, FILE *const fp)
  {
  	char		buf[4];
  
-@@ -2646,12 +2036,10 @@
+@@ -2646,12 +2022,10 @@
  static int
  atcomp(const void *avp, const void *bvp)
  {
@@ -2492,7 +2414,7 @@
  }
  
  struct timerange
-@@ -2661,44 +2049,25 @@
+@@ -2661,44 +2035,25 @@
  				count;
  	int			leapbase,
  				leapcount;
@@ -2539,7 +2461,7 @@
  	{
  		while (0 < r.count && hi + 1 < ats[r.base + r.count - 1])
  			r.count--;
-@@ -2706,9 +2075,6 @@
+@@ -2706,9 +2061,6 @@
  			r.leapcount--;
  	}
  
@@ -2549,7 +2471,7 @@
  	return r;
  }
  
-@@ -2720,20 +2086,23 @@
+@@ -2720,20 +2072,23 @@
  	ptrdiff_t	i,
  				j;
  	int			pass;
@@ -2582,7 +2504,7 @@
  
  	/*
  	 * Sort.
-@@ -2810,49 +2179,61 @@
+@@ -2810,49 +2165,61 @@
  			}
  	}
  
@@ -2611,9 +2533,8 @@
 -						 max(hi_time,
 -							 redundant_time - (ZIC_MIN < redundant_time)),
 -						 ats, types);
--	range32 = limitrange(range64, ZIC32_MIN, ZIC32_MAX, ats, types);
 +	range64 = limitrange(rangeall, lo_time, hi_time, ats, types);
-+	range32 = limitrange(range64, PG_INT32_MIN, PG_INT32_MAX, ats, types);
+ 	range32 = limitrange(range64, ZIC32_MIN, ZIC32_MAX, ats, types);
  
  	/*
 -	 * TZif version 4 is needed if a no-op transition is appended to indicate
@@ -2674,7 +2595,7 @@
  	for (pass = 1; pass <= 2; ++pass)
  	{
  		ptrdiff_t	thistimei,
-@@ -2861,15 +2242,11 @@
+@@ -2861,15 +2228,11 @@
  		int			thisleapi,
  					thisleapcnt,
  					thisleaplim;
@@ -2693,7 +2614,7 @@
  		int			old0;
  		char		omittype[TZ_MAX_TYPES];
  		int			typemap[TZ_MAX_TYPES];
-@@ -2883,15 +2260,28 @@
+@@ -2883,15 +2246,28 @@
  
  		if (pass == 1)
  		{
@@ -2701,7 +2622,7 @@
 +			/*
 +			 * Arguably the default time type in the 32-bit data should be
 +			 * range32.defaulttype, which is suited for timestamps just before
-+			 * PG_INT32_MIN.  However, zic traditionally used the time type of
++			 * INT32_MIN.  However, zic traditionally used the time type of
 +			 * the indefinite past instead.  Internet RFC 8532 says readers
 +			 * should ignore 32-bit data, so this discrepancy matters only to
 +			 * obsolete readers where the traditional type might be more
@@ -2709,7 +2630,7 @@
 +			 * value, unless -r specifies a low cutoff that excludes some
 +			 * 32-bit timestamps.
 +			 */
-+			thisdefaulttype = (lo_time <= PG_INT32_MIN
++			thisdefaulttype = (lo_time <= INT32_MIN
 +							   ? range64.defaulttype
 +							   : range32.defaulttype);
 +
@@ -2721,12 +2642,12 @@
 -			thisleapexpiry = range32.leapexpiry;
 -			thismin = ZIC32_MIN;
 -			thismax = ZIC32_MAX;
-+			locut = PG_INT32_MIN < lo_time;
-+			hicut = hi_time < PG_INT32_MAX;
++			locut = INT32_MIN < lo_time;
++			hicut = hi_time < INT32_MAX;
  		}
  		else
  		{
-@@ -2901,52 +2291,40 @@
+@@ -2901,52 +2277,40 @@
  			toomanytimes = thistimecnt >> 31 >> 31 >> 2 != 0;
  			thisleapi = range64.leapbase;
  			thisleapcnt = range64.leapcount;
@@ -2801,7 +2722,7 @@
  
  		/*
  		 * Reorder types to make THISDEFAULTTYPE type 0. Use TYPEMAP to swap
-@@ -2972,14 +2350,7 @@
+@@ -2972,14 +2336,7 @@
  						type;
  
  			hidst = histd = mrudst = mrustd = -1;
@@ -2817,7 +2738,7 @@
  				if (isdsts[types[i]])
  					mrudst = types[i];
  				else
-@@ -3059,20 +2430,19 @@
+@@ -3059,20 +2416,19 @@
  		}
  		if (pass == 1 && !want_bloat())
  		{
@@ -2844,11 +2765,16 @@
  		convert(thistypecnt, tzh.tzh_typecnt);
  		convert(thischarcnt, tzh.tzh_charcnt);
  		DO(tzh_magic);
-@@ -3095,26 +2465,62 @@
- 			continue;
+@@ -3096,25 +2452,67 @@
  		}
  
-+		/* PG: print current timezone abbreviations if requested */
+ 		/*
++		 * PG: print current timezone abbreviations if requested.  Note that
++		 * we cast to int64_t, because int_fast64_t is not required to be
++		 * compatible with INT64_FORMAT.  We can't use PRIdFAST64 here because
++		 * we override fprintf with our own implementation that might not
++		 * understand it.
++		 */
 +		if (print_abbrevs && pass == 2)
 +		{
 +			/* Print "type" data for periods ending after print_cutoff */
@@ -2861,7 +2787,7 @@
 +
 +					fprintf(stdout, "%s\t" INT64_FORMAT "%s\n",
 +							thisabbrev,
-+							utoffs[tm],
++							(int64_t) utoffs[tm],
 +							isdsts[tm] ? "\tD" : "");
 +				}
 +			}
@@ -2873,17 +2799,16 @@
 +
 +				fprintf(stdout, "%s\t" INT64_FORMAT "%s\n",
 +						thisabbrev,
-+						utoffs[tm],
++						(int64_t) utoffs[tm],
 +						isdsts[tm] ? "\tD" : "");
 +			}
 +		}
 +
- 		/*
++		/*
  		 * Output a LO_TIME transition if needed; see limitrange. But do not
  		 * go below the minimum representable value for this pass.
  		 */
--		lo = pass == 1 && lo_time < ZIC32_MIN ? ZIC32_MIN : lo_time;
-+		lo = pass == 1 && lo_time < PG_INT32_MIN ? PG_INT32_MIN : lo_time;
+ 		lo = pass == 1 && lo_time < ZIC32_MIN ? ZIC32_MIN : lo_time;
  
 -		if (0 <= pretranstype)
 +		if (locut)
@@ -2915,7 +2840,7 @@
  
  		for (i = old0; i < typecnt; i++)
  		{
-@@ -3131,7 +2537,6 @@
+@@ -3131,7 +2529,6 @@
  		if (thischarcnt != 0)
  			fwrite(thischars, sizeof thischars[0],
  				   thischarcnt, fp);
@@ -2923,7 +2848,7 @@
  		for (i = thisleapi; i < thisleaplim; ++i)
  		{
  			zic_t		todo;
-@@ -3163,17 +2568,6 @@
+@@ -3163,17 +2560,6 @@
  			puttzcodepass(todo, fp, pass);
  			puttzcode(corr[i], fp);
  		}
@@ -2941,7 +2866,7 @@
  		if (stdcnt != 0)
  			for (i = old0; i < typecnt; i++)
  				if (!omittype[i])
-@@ -3184,8 +2578,7 @@
+@@ -3184,8 +2570,7 @@
  					putc(ttisuts[i], fp);
  	}
  	fprintf(fp, "\n%s\n", string);
@@ -2951,7 +2876,7 @@
  	free(ats);
  }
  
-@@ -3233,15 +2626,13 @@
+@@ -3233,15 +2618,13 @@
  	}
  }
  
@@ -2969,7 +2894,7 @@
  	char const *format = zp->z_format;
  
  	slashp = strchr(format, '/');
-@@ -3253,8 +2644,6 @@
+@@ -3253,8 +2636,6 @@
  			letters = abbroffset(letterbuf, zp->z_stdoff + save);
  		else if (!letters)
  			letters = "%s";
@@ -2978,7 +2903,7 @@
  		sprintf(abbr, format, letters);
  	}
  	else if (isdst)
-@@ -3413,17 +2802,11 @@
+@@ -3413,17 +2794,11 @@
  		return 1;
  	if (a->r_hiyear != b->r_hiyear)
  		return a->r_hiyear < b->r_hiyear ? -1 : 1;
@@ -2996,7 +2921,7 @@
  static int
  stringzone(char *result, struct zone const *zpfirst, ptrdiff_t zonecount)
  {
-@@ -3432,17 +2815,13 @@
+@@ -3432,17 +2807,13 @@
  	struct rule *stdrp;
  	struct rule *dstrp;
  	ptrdiff_t	i;
@@ -3016,7 +2941,7 @@
  
  	result[0] = '\0';
  
-@@ -3454,74 +2833,72 @@
+@@ -3454,74 +2825,72 @@
  		return -1;
  
  	zp = zpfirst + zonecount - 1;
@@ -3146,7 +3071,7 @@
  	if (!offsetlen)
  	{
  		result[0] = '\0';
-@@ -3530,12 +2907,12 @@
+@@ -3530,12 +2899,12 @@
  	len += offsetlen;
  	if (dstrp == NULL)
  		return compat;
@@ -3161,7 +3086,7 @@
  		if (!offsetlen)
  		{
  			result[0] = '\0';
-@@ -3544,7 +2921,7 @@
+@@ -3544,7 +2913,7 @@
  		len += offsetlen;
  	}
  	result[len++] = ',';
@@ -3170,7 +3095,7 @@
  	if (c < 0)
  	{
  		result[0] = '\0';
-@@ -3554,7 +2931,7 @@
+@@ -3554,7 +2923,7 @@
  		compat = c;
  	len += strlen(result + len);
  	result[len++] = ',';
@@ -3179,7 +3104,7 @@
  	if (c < 0)
  	{
  		result[0] = '\0';
-@@ -3568,31 +2945,38 @@
+@@ -3568,31 +2937,38 @@
  static void
  outzone(const struct zone *zpfirst, ptrdiff_t zonecount)
  {
@@ -3224,7 +3149,7 @@
  	startbuf = emalloc(max_abbr_len + 1);
  	ab = emalloc(max_abbr_len + 1);
  	envvar = emalloc(max_envvar_len + 1);
-@@ -3605,6 +2989,7 @@
+@@ -3605,6 +2981,7 @@
  	timecnt = 0;
  	typecnt = 0;
  	charcnt = 0;
@@ -3232,7 +3157,7 @@
  
  	/*
  	 * Thanks to Earl Chew for noting the need to unconditionally initialize
-@@ -3620,17 +3005,18 @@
+@@ -3620,17 +2997,18 @@
  	}
  	for (i = 0; i < zonecount; ++i)
  	{
@@ -3256,7 +3181,7 @@
  		}
  	}
  
-@@ -3638,14 +3024,13 @@
+@@ -3638,14 +3016,13 @@
  	 * Generate lots of data if a rule can't cover all future times.
  	 */
  	compat = stringzone(envvar, zpfirst, zonecount);
@@ -3273,7 +3198,7 @@
  					zpfirst->z_name);
  		else if (compat != 0)
  		{
-@@ -3660,6 +3045,22 @@
+@@ -3660,6 +3037,22 @@
  	}
  	if (do_extend)
  	{
@@ -3296,7 +3221,7 @@
  		if (min_year >= ZIC_MIN + years_of_observations)
  			min_year -= years_of_observations;
  		else
-@@ -3668,9 +3069,18 @@
+@@ -3668,9 +3061,18 @@
  			max_year += years_of_observations;
  		else
  			max_year = ZIC_MAX;
@@ -3317,7 +3242,7 @@
  	max_year0 = max_year;
  	if (want_bloat())
  	{
-@@ -3678,35 +3088,31 @@
+@@ -3678,35 +3080,31 @@
  		 * For the benefit of older systems, generate data from 1900 through
  		 * 2038.
  		 */
@@ -3366,7 +3291,7 @@
  			save = zp->z_save;
  			doabbr(startbuf, zp, NULL, zp->z_isdst, save, false);
  			type = addtype(oadd(zp->z_stdoff, save),
-@@ -3715,20 +3121,12 @@
+@@ -3715,20 +3113,12 @@
  			if (usestart)
  			{
  				addtt(starttime, type);
@@ -3387,7 +3312,7 @@
  			for (year = min_year; year <= max_year; ++year)
  			{
  				if (useuntil && year > zp->z_untilrule.r_hiyear)
-@@ -3741,12 +3139,9 @@
+@@ -3741,12 +3131,9 @@
  				 */
  				for (j = 0; j < zp->z_nrules; ++j)
  				{
@@ -3403,7 +3328,7 @@
  					rp->r_todo = year >= rp->r_loyear &&
  						year <= rp->r_hiyear;
  					if (rp->r_todo)
-@@ -3763,8 +3158,6 @@
+@@ -3763,8 +3150,6 @@
  					zic_t		jtime,
  								ktime;
  					zic_t		offset;
@@ -3412,7 +3337,7 @@
  
  					INITIALIZE(ktime);
  					if (useuntil)
-@@ -3789,16 +3182,15 @@
+@@ -3789,16 +3174,15 @@
  					k = -1;
  					for (j = 0; j < zp->z_nrules; ++j)
  					{
@@ -3436,7 +3361,7 @@
  						if (jtime == min_time ||
  							jtime == max_time)
  							continue;
-@@ -3813,12 +3205,12 @@
+@@ -3813,12 +3197,12 @@
  							char const *dup_rules_msg =
  								_("two rules for same instant");
  
@@ -3454,7 +3379,7 @@
  							error("%s", dup_rules_msg);
  						}
  					}
-@@ -3827,15 +3219,7 @@
+@@ -3827,15 +3211,7 @@
  					rp = &zp->z_rules[k];
  					rp->r_todo = false;
  					if (useuntil && ktime >= untiltime)
@@ -3470,7 +3395,7 @@
  					save = rp->r_save;
  					if (usestart && ktime == starttime)
  						usestart = false;
-@@ -3864,41 +3248,44 @@
+@@ -3864,41 +3240,44 @@
  								   false);
  						}
  					}
@@ -3534,7 +3459,7 @@
  				if (defaulttype < 0 && !isdst)
  					defaulttype = type;
  				addtt(starttime, type);
-@@ -3921,50 +3308,17 @@
+@@ -3921,50 +3300,17 @@
  	}
  	if (defaulttype < 0)
  		defaulttype = 0;
@@ -3592,7 +3517,7 @@
  		 * transitions up to that point.
  		 */
  		struct rule xr;
-@@ -4055,11 +3409,6 @@
+@@ -4055,11 +3401,6 @@
  		error(_("too many leap seconds"));
  		exit(EXIT_FAILURE);
  	}
@@ -3604,7 +3529,7 @@
  	for (i = 0; i < leapcnt; ++i)
  		if (t <= trans[i])
  			break;
-@@ -4094,6 +3443,13 @@
+@@ -4094,6 +3435,13 @@
  		last = corr[i] += last;
  	}
  
@@ -3618,7 +3543,7 @@
  	if (0 <= leapexpires)
  	{
  		leapexpires = oadd(leapexpires, last);
-@@ -4102,6 +3458,8 @@
+@@ -4102,6 +3450,8 @@
  			error(_("last Leap time does not precede Expires time"));
  			exit(EXIT_FAILURE);
  		}
@@ -3627,7 +3552,7 @@
  	}
  }
  
-@@ -4252,7 +3610,7 @@
+@@ -4252,7 +3602,7 @@
  }
  
  /* case-insensitive equality */
@@ -3636,7 +3561,7 @@
  ciequal(const char *ap, const char *bp)
  {
  	while (lowerit(*ap) == lowerit(*bp++))
-@@ -4261,7 +3619,7 @@
+@@ -4261,7 +3611,7 @@
  	return false;
  }
  
@@ -3645,7 +3570,7 @@
  itsabbr(const char *abbr, const char *word)
  {
  	if (lowerit(*abbr) != lowerit(*word))
-@@ -4278,7 +3636,7 @@
+@@ -4278,7 +3628,7 @@
  
  /* Return true if ABBR is an initial prefix of WORD, ignoring ASCII case.  */
  
@@ -3654,7 +3579,7 @@
  ciprefix(char const *abbr, char const *word)
  {
  	do
-@@ -4355,22 +3713,24 @@
+@@ -4355,22 +3705,24 @@
  	return foundlp;
  }
  
@@ -3684,7 +3609,7 @@
  		do
  		{
  			if ((*dp = *cp++) != '"')
-@@ -4388,53 +3748,48 @@
+@@ -4388,53 +3740,48 @@
  		if (is_space(*cp))
  			++cp;
  		*dp = '\0';
@@ -3765,7 +3690,7 @@
  }
  
  /*
-@@ -4450,31 +3805,39 @@
+@@ -4450,31 +3797,39 @@
  	zic_t		dayoff;			/* with a nod to Margaret O. */
  	zic_t		t,
  				y;
@@ -3820,7 +3745,7 @@
  	}
  	while (m != rp->r_month)
  	{
-@@ -4497,17 +3860,27 @@
+@@ -4497,17 +3852,27 @@
  	dayoff = oadd(dayoff, i);
  	if (rp->r_dycode == DC_DOWGEQ || rp->r_dycode == DC_DOWLEQ)
  	{
@@ -3852,7 +3777,7 @@
  					wday = 0;
  				++i;
  			}
-@@ -4515,7 +3888,7 @@
+@@ -4515,7 +3880,7 @@
  			{
  				dayoff = oadd(dayoff, -1);
  				if (--wday < 0)
@@ -3861,7 +3786,7 @@
  				--i;
  			}
  		if (i < 0 || i >= len_months[isleap(y)][m])
-@@ -4570,13 +3943,15 @@
+@@ -4570,13 +3935,15 @@
  /* Ensure that the directories of ARGNAME exist, by making any missing
     ones.  If ANCESTORS, do this only for ARGNAME's ancestors; otherwise,
     do it for ARGNAME too.  Exit with failure if there is trouble.
@@ -3880,7 +3805,7 @@
  	/*
  	 * On MS-Windows systems, do not worry about drive letters or backslashes,
  	 * as this should suffice in practice.  Time zone names do not use drive
-@@ -4603,20 +3978,15 @@
+@@ -4603,20 +3970,15 @@
  		if (mkdir(name, MKDIR_UMASK) != 0)
  		{
  			/*
@@ -3906,7 +3831,7 @@
  					  progname, name, strerror(err));
  				exit(EXIT_FAILURE);
  			}
-@@ -4626,3 +3996,20 @@
+@@ -4626,3 +3988,20 @@
  	}
  	free(name);
  }
--- localtime.c-master-vs-upstream.diff	2024-07-04 14:38:31.386232000 +1200
+++ localtime.c-patched-vs-upstream.diff	2024-07-04 14:37:46.783150000 +1200
@@ -1,6 +1,6 @@
 --- localtime.filtered.c	2024-07-04 13:04:23.744118000 +1200
-+++ localtime.c	2024-07-04 14:38:19.086065000 +1200
-@@ -3,64 +3,28 @@
++++ localtime.c	2024-07-04 14:17:36.438049000 +1200
+@@ -3,64 +3,29 @@
  /*
   * This file is in the public domain, so clarified as of
   * 1996-06-05 by Arthur David Olson.
@@ -25,6 +25,7 @@
 -#include "tzdir.h"
 -#include "tzfile.h"
  #include <fcntl.h>
++#include <stdint.h>
  
 -#if defined THREAD_SAFE && THREAD_SAFE
 -#include <pthread.h>
@@ -75,7 +76,7 @@
  #ifndef WILDABBR
  /*
   * Someone might make incorrect use of a time zone abbreviation:
-@@ -72,7 +36,7 @@
+@@ -72,7 +37,7 @@
   *		in which Daylight Saving Time is never observed.
   *	4.	They might reference tzname[0] after setting to a time zone
   *		in which Standard Time is never observed.
@@ -84,7 +85,7 @@
   * What's best to do in the above cases is open to debate;
   * for now, we just set things up so that in any of the five cases
   * WILDABBR is used. Another possibility: initialize tzname[0] to the
-@@ -81,89 +45,28 @@
+@@ -81,89 +46,28 @@
   * manual page of what this "time zone abbreviation" means (doing this so
   * that tzname[0] has the "normal" length of three characters).
   */
@@ -179,12 +180,8 @@
  };
  
  struct rule
-@@ -172,70 +75,37 @@
- 	int			r_day;			/* day number of rule */
- 	int			r_week;			/* week number of rule */
- 	int			r_mon;			/* month number of rule */
--	int_fast32_t r_time;		/* transition time of rule */
-+	int32		r_time;			/* transition time of rule */
+@@ -175,64 +79,31 @@
+ 	int_fast32_t r_time;		/* transition time of rule */
  };
  
 -static struct pg_tm *gmtsub(struct state const *, pg_time_t const *, int_fast32_t,
@@ -204,13 +201,13 @@
 -static struct state *lclptr;
 -static struct state *gmtptr;
 -#endif							/* defined ALL_STATE */
-+static struct pg_tm *gmtsub(pg_time_t const *timep, int32 offset,
++static struct pg_tm *gmtsub(pg_time_t const *timep, int_fast32_t offset,
 +							struct pg_tm *tmp);
 +static bool increment_overflow(int *ip, int j);
-+static bool increment_overflow_time(pg_time_t *tp, int32 j);
++static bool increment_overflow_time(pg_time_t *tp, int_fast32_t j);
 +static int64 leapcorr(struct state const *sp, pg_time_t t);
 +static struct pg_tm *timesub(pg_time_t const *timep,
-+							 int32 offset, struct state const *sp,
++							 int_fast32_t offset, struct state const *sp,
 +							 struct pg_tm *tmp);
 +static bool typesequiv(struct state const *sp, int a, int b);
  
@@ -259,12 +256,8 @@
 -
  /* Initialize *S to a value based on UTOFF, ISDST, and DESIGIDX.  */
  static void
--init_ttinfo(struct ttinfo *s, int_fast32_t utoff, bool isdst, int desigidx)
-+init_ttinfo(struct ttinfo *s, int32 utoff, bool isdst, int desigidx)
- {
- 	s->tt_utoff = utoff;
- 	s->tt_isdst = isdst;
-@@ -244,25 +114,15 @@
+ init_ttinfo(struct ttinfo *s, int_fast32_t utoff, bool isdst, int desigidx)
+@@ -244,16 +115,6 @@
  	s->tt_ttisut = false;
  }
  
@@ -278,64 +271,13 @@
 -	return memcmp(abbr, UNSPEC, sizeof UNSPEC) == 0;
 -}
 -
--static int_fast32_t
-+static int32
+ static int_fast32_t
  detzcode(const char *const codep)
  {
--	int_fast32_t result;
-+	int32		result;
- 	int			i;
--	int_fast32_t one = 1;
--	int_fast32_t halfmaxval = one << (32 - 2);
--	int_fast32_t maxval = halfmaxval - 1 + halfmaxval;
--	int_fast32_t minval = -1 - maxval;
-+	int32		one = 1;
-+	int32		halfmaxval = one << (32 - 2);
-+	int32		maxval = halfmaxval - 1 + halfmaxval;
-+	int32		minval = -1 - maxval;
- 
- 	result = codep[0] & 0x7f;
- 	for (i = 1; i < 4; ++i)
-@@ -274,21 +134,21 @@
- 		 * Do two's-complement negation even on non-two's-complement machines.
- 		 * If the result would be minval - 1, return minval.
- 		 */
--		result -= !TWOS_COMPLEMENT(int_fast32_t) && result != 0;
-+		result -= !TWOS_COMPLEMENT(int32) && result != 0;
- 		result += minval;
- 	}
+@@ -306,125 +167,25 @@
  	return result;
  }
  
--static int_fast64_t
-+static int64
- detzcode64(const char *const codep)
- {
--	int_fast64_t result;
-+	uint64		result;
- 	int			i;
--	int_fast64_t one = 1;
--	int_fast64_t halfmaxval = one << (64 - 2);
--	int_fast64_t maxval = halfmaxval - 1 + halfmaxval;
--	int_fast64_t minval = -TWOS_COMPLEMENT(int_fast64_t) - maxval;
-+	int64		one = 1;
-+	int64		halfmaxval = one << (64 - 2);
-+	int64		maxval = halfmaxval - 1 + halfmaxval;
-+	int64		minval = -TWOS_COMPLEMENT(int64) - maxval;
- 
- 	result = codep[0] & 0x7f;
- 	for (i = 1; i < 8; ++i)
-@@ -300,131 +160,31 @@
- 		 * Do two's-complement negation even on non-two's-complement machines.
- 		 * If the result would be minval - 1, return minval.
- 		 */
--		result -= !TWOS_COMPLEMENT(int_fast64_t) && result != 0;
-+		result -= !TWOS_COMPLEMENT(int64) && result != 0;
- 		result += minval;
- 	}
- 	return result;
- }
- 
 -static void
 -update_tzname_etc(struct state const *sp, struct ttinfo const *ttisp)
 +static bool
@@ -464,7 +406,7 @@
  /* Local storage needed for 'tzloadbody'.  */
  union local_storage
  {
-@@ -438,28 +198,23 @@
+@@ -438,28 +199,23 @@
  		struct state st;
  	}			u;
  
@@ -500,7 +442,7 @@
  	union input_buffer *up = &lsp->u.u;
  	int			tzheadsize = sizeof(struct tzhead);
  
-@@ -474,50 +229,10 @@
+@@ -474,50 +230,10 @@
  
  	if (name[0] == ':')
  		++name;
@@ -553,33 +495,23 @@
  
  	nread = read(fid, up->buf, sizeof up->buf);
  	if (nread < tzheadsize)
-@@ -531,17 +246,14 @@
+@@ -531,13 +247,10 @@
  		return errno;
  	for (stored = 4; stored <= 8; stored *= 2)
  	{
 -		char		version = up->tzhead.tzh_version[0];
 -		bool		skip_datablock = stored == 4 && version;
 -		int_fast32_t datablock_size;
--		int_fast32_t ttisstdcnt = detzcode(up->tzhead.tzh_ttisstdcnt);
--		int_fast32_t ttisutcnt = detzcode(up->tzhead.tzh_ttisutcnt);
+ 		int_fast32_t ttisstdcnt = detzcode(up->tzhead.tzh_ttisstdcnt);
+ 		int_fast32_t ttisutcnt = detzcode(up->tzhead.tzh_ttisutcnt);
 -		int_fast64_t prevtr = -1;
 -		int_fast32_t prevcorr;
--		int_fast32_t leapcnt = detzcode(up->tzhead.tzh_leapcnt);
--		int_fast32_t timecnt = detzcode(up->tzhead.tzh_timecnt);
--		int_fast32_t typecnt = detzcode(up->tzhead.tzh_typecnt);
--		int_fast32_t charcnt = detzcode(up->tzhead.tzh_charcnt);
-+		int32		ttisstdcnt = detzcode(up->tzhead.tzh_ttisstdcnt);
-+		int32		ttisutcnt = detzcode(up->tzhead.tzh_ttisutcnt);
-+		int64		prevtr = 0;
-+		int32		prevcorr = 0;
-+		int32		leapcnt = detzcode(up->tzhead.tzh_leapcnt);
-+		int32		timecnt = detzcode(up->tzhead.tzh_timecnt);
-+		int32		typecnt = detzcode(up->tzhead.tzh_typecnt);
-+		int32		charcnt = detzcode(up->tzhead.tzh_charcnt);
- 		char const *p = up->buf + tzheadsize;
- 
- 		/*
-@@ -553,177 +265,152 @@
++		int_fast64_t prevtr = 0;
++		int_fast32_t prevcorr = 0;
+ 		int_fast32_t leapcnt = detzcode(up->tzhead.tzh_leapcnt);
+ 		int_fast32_t timecnt = detzcode(up->tzhead.tzh_timecnt);
+ 		int_fast32_t typecnt = detzcode(up->tzhead.tzh_typecnt);
+@@ -553,177 +266,152 @@
  			  && 0 <= typecnt && typecnt < TZ_MAX_TYPES
  			  && 0 <= timecnt && timecnt < TZ_MAX_TIMES
  			  && 0 <= charcnt && charcnt < TZ_MAX_CHARS
@@ -743,8 +675,8 @@
 +		leapcnt = 0;
 +		for (i = 0; i < sp->leapcnt; ++i)
 +		{
-+			int64		tr = stored == 4 ? detzcode(p) : detzcode64(p);
-+			int32		corr = detzcode(p + stored);
++			int_fast64_t tr = stored == 4 ? detzcode(p) : detzcode64(p);
++			int_fast32_t corr = detzcode(p + stored);
  
 -			/* Read leap seconds, discarding those out of pg_time_t range.  */
 -			leapcnt = 0;
@@ -764,7 +696,7 @@
 -				 * Leap seconds cannot occur before the Epoch, or out of
 -				 * order.
 +				 * Leap seconds cannot occur more than once per UTC month, and
-+				 * UTC months are at least 28 days long (minus 1 second for a
++				 * UTC months are at least 2 days long (minus 1 second for a
 +				 * negative leap second).  Each leap second's correction must
 +				 * differ from the previous one's by 1 second.
  				 */
@@ -870,7 +802,7 @@
  	}
  	if (doextend && nread > 2 &&
  		up->buf[0] == '\n' && up->buf[nread - 1] == '\n' &&
-@@ -732,9 +419,8 @@
+@@ -732,9 +420,8 @@
  		struct state *ts = &lsp->u.st;
  
  		up->buf[nread - 1] = '\0';
@@ -881,7 +813,7 @@
  			/*
  			 * Attempt to reuse existing abbreviations. Without this,
  			 * America/Anchorage would be right on the edge after 2037 when
-@@ -785,25 +471,20 @@
+@@ -785,25 +472,20 @@
  						   == sp->types[sp->timecnt - 2]))
  					sp->timecnt--;
  
@@ -916,7 +848,7 @@
  				}
  				for (i = 0; i < ts->typecnt; i++)
  					sp->ttis[sp->typecnt++] = ts->ttis[i];
-@@ -812,6 +493,25 @@
+@@ -812,6 +494,25 @@
  	}
  	if (sp->typecnt == 0)
  		return EINVAL;
@@ -942,7 +874,7 @@
  
  	/*
  	 * Infer sp->defaulttype from the data.  Although this default type is
-@@ -826,13 +526,13 @@
+@@ -826,13 +527,13 @@
  	 */
  
  	/*
@@ -959,7 +891,7 @@
  
  	/*
  	 * Absent the above, if there are transition times and the first
-@@ -878,29 +578,49 @@
+@@ -878,29 +579,49 @@
  }
  
  /* Load tz data from the file named NAME into *SP.  Read extended
@@ -1021,7 +953,7 @@
  }
  
  static const int mon_lengths[2][MONSPERYEAR] = {
-@@ -912,20 +632,13 @@
+@@ -912,20 +633,13 @@
  	DAYSPERNYEAR, DAYSPERLYEAR
  };
  
@@ -1043,7 +975,7 @@
  getzname(const char *strp)
  {
  	char		c;
-@@ -946,7 +659,7 @@
+@@ -946,7 +660,7 @@
   * We don't do any checking here; checking is done later in common-case code.
   */
  
@@ -1052,16 +984,9 @@
  getqzname(const char *strp, const int delim)
  {
  	int			c;
-@@ -994,20 +707,19 @@
-  */
+@@ -1000,8 +714,8 @@
+ 	int_fast32_t secsperhour = SECSPERHOUR;
  
- static const char *
--getsecs(const char *strp, int_fast32_t * const secsp)
-+getsecs(const char *strp, int32 *const secsp)
- {
- 	int			num;
--	int_fast32_t secsperhour = SECSPERHOUR;
- 
  	/*
 -	 * 'HOURSPERDAY * DAYSPERWEEK - 1' allows quasi-POSIX rules like
 -	 * "M10.4.6/26", which does not conform to POSIX, but which specifies the
@@ -1070,24 +995,8 @@
  	 * equivalent of "02:00 on the first Sunday on or after 23 Oct".
  	 */
  	strp = getnum(strp, &num, 0, HOURSPERDAY * DAYSPERWEEK - 1);
- 	if (strp == NULL)
- 		return NULL;
--	*secsp = num * secsperhour;
-+	*secsp = num * (int32) SECSPERHOUR;
- 	if (*strp == ':')
- 	{
- 		++strp;
-@@ -1036,7 +748,7 @@
-  */
+@@ -1057,8 +771,7 @@
  
- static const char *
--getoffset(const char *strp, int_fast32_t * const offsetp)
-+getoffset(const char *strp, int32 *const offsetp)
- {
- 	bool		neg = false;
- 
-@@ -1057,8 +769,7 @@
- 
  /*
   * Given a pointer into a timezone string, extract a rule in the form
 - * date[/time]. See POSIX Base Definitions section 8.3 variable TZ
@@ -1096,23 +1005,7 @@
   * If a valid rule is not found, return NULL.
   * Otherwise, return a pointer to the first character not part of the rule.
   */
-@@ -1124,12 +835,12 @@
-  * effect, calculate the year-relative time that rule takes effect.
-  */
- 
--static int_fast32_t
-+static int32
- transtime(const int year, const struct rule *const rulep,
--		  const int_fast32_t offset)
-+		  const int32 offset)
- {
- 	bool		leapyear;
--	int_fast32_t value;
-+	int32		value;
- 	int			i;
- 	int			d,
- 				m1,
-@@ -1138,6 +849,7 @@
+@@ -1138,6 +851,7 @@
  				yy2,
  				dow;
  
@@ -1120,7 +1013,7 @@
  	leapyear = isleap(year);
  	switch (rulep->r_type)
  	{
-@@ -1193,7 +905,7 @@
+@@ -1193,7 +907,7 @@
  			for (i = 1; i < rulep->r_week; ++i)
  			{
  				if (d + DAYSPERWEEK >=
@@ -1129,7 +1022,7 @@
  					break;
  				d += DAYSPERWEEK;
  			}
-@@ -1203,11 +915,8 @@
+@@ -1203,11 +917,8 @@
  			 */
  			value = d * SECSPERDAY;
  			for (i = 0; i < rulep->r_mon - 1; ++i)
@@ -1142,7 +1035,7 @@
  	}
  
  	/*
-@@ -1219,64 +928,71 @@
+@@ -1219,64 +930,71 @@
  }
  
  /*
@@ -1159,14 +1052,12 @@
  {
  	const char *stdname;
 -	const char *dstname;
--	int_fast32_t stdoffset;
--	int_fast32_t dstoffset;
 +	const char *dstname = NULL;
 +	size_t		stdlen;
 +	size_t		dstlen;
 +	size_t		charcnt;
-+	int32		stdoffset;
-+	int32		dstoffset;
+ 	int_fast32_t stdoffset;
+ 	int_fast32_t dstoffset;
  	char	   *cp;
  	bool		load_ok;
 -	ptrdiff_t	stdlen,
@@ -1258,7 +1149,7 @@
  	if (*name != '\0')
  	{
  		if (*name == '<')
-@@ -1294,9 +1010,11 @@
+@@ -1294,9 +1012,11 @@
  			name = getzname(name);
  			dstlen = name - dstname;	/* length of DST abbr. */
  		}
@@ -1271,22 +1162,21 @@
  		if (*name != '\0' && *name != ',' && *name != ';')
  		{
  			name = getoffset(name, &dstoffset);
-@@ -1312,11 +1030,11 @@
+@@ -1312,11 +1032,11 @@
  			struct rule start;
  			struct rule end;
  			int			year;
 +			int			yearlim;
  			int			timecnt;
  			pg_time_t	janfirst;
--			int_fast32_t janoffset = 0;
+ 			int_fast32_t janoffset = 0;
 -			int			yearbeg,
 -						yearlim;
-+			int32		janoffset = 0;
 +			int			yearbeg;
  
  			++name;
  			if ((name = getrule(name, &start)) == NULL)
-@@ -1334,13 +1052,14 @@
+@@ -1334,6 +1054,7 @@
  			 */
  			init_ttinfo(&sp->ttis[0], -stdoffset, false, 0);
  			init_ttinfo(&sp->ttis[1], -dstoffset, true, stdlen + 1);
@@ -1294,15 +1184,7 @@
  			timecnt = 0;
  			janfirst = 0;
  			yearbeg = EPOCH_YEAR;
- 
- 			do
- 			{
--				int_fast32_t yearsecs
-+				int32		yearsecs
- 				= year_lengths[isleap(yearbeg - 1)] * SECSPERDAY;
- 
- 				yearbeg--;
-@@ -1349,72 +1068,48 @@
+@@ -1349,27 +1070,9 @@
  					janoffset = -yearsecs;
  					break;
  				}
@@ -1331,27 +1213,8 @@
 +			yearlim = yearbeg + YEARSPERREPEAT + 1;
  			for (year = yearbeg; year < yearlim; year++)
  			{
--				int_fast32_t
--					starttime = transtime(year, &start, stdoffset),
--					endtime = transtime(year, &end, dstoffset);
--				int_fast32_t
--					yearsecs = (year_lengths[isleap(year)]
--								* SECSPERDAY);
-+				int32
-+							starttime = transtime(year, &start, stdoffset),
-+							endtime = transtime(year, &end, dstoffset);
-+				int32
-+							yearsecs = (year_lengths[isleap(year)]
-+										* SECSPERDAY);
- 				bool		reversed = endtime < starttime;
- 
- 				if (reversed)
- 				{
--					int_fast32_t swap = starttime;
-+					int32		swap = starttime;
- 
- 					starttime = endtime;
- 					endtime = swap;
+ 				int_fast32_t
+@@ -1389,32 +1092,26 @@
  				}
  				if (reversed
  					|| (starttime < endtime
@@ -1390,7 +1253,7 @@
  				if (increment_overflow_time
  					(&janfirst, janoffset + yearsecs))
  					break;
-@@ -1426,14 +1121,14 @@
+@@ -1426,7 +1123,7 @@
  				sp->ttis[0] = sp->ttis[1];
  				sp->typecnt = 1;	/* Perpetual DST.  */
  			}
@@ -1399,17 +1262,7 @@
  				sp->goback = sp->goahead = true;
  		}
  		else
- 		{
--			int_fast32_t theirstdoffset;
--			int_fast32_t theirdstoffset;
--			int_fast32_t theiroffset;
-+			int32		theirstdoffset;
-+			int32		theirdstoffset;
-+			int32		theiroffset;
- 			bool		isdst;
- 			int			i;
- 			int			j;
-@@ -1471,6 +1166,7 @@
+@@ -1471,6 +1168,7 @@
  			 * Initially we're assumed to be in standard time.
  			 */
  			isdst = false;
@@ -1417,7 +1270,7 @@
  
  			/*
  			 * Now juggle transition times and types tracking offsets as you
-@@ -1495,7 +1191,7 @@
+@@ -1495,7 +1193,7 @@
  					 */
  					/*
  					 * Transitions from DST to DDST will effectively disappear
@@ -1426,7 +1279,7 @@
  					 */
  					if (isdst && !sp->ttis[j].tt_ttisstd)
  					{
-@@ -1521,6 +1217,7 @@
+@@ -1521,6 +1219,7 @@
  			init_ttinfo(&sp->ttis[0], -stdoffset, false, 0);
  			init_ttinfo(&sp->ttis[1], -dstoffset, true, stdlen + 1);
  			sp->typecnt = 2;
@@ -1434,7 +1287,7 @@
  		}
  	}
  	else
-@@ -1529,8 +1226,8 @@
+@@ -1529,8 +1228,8 @@
  		sp->typecnt = 1;		/* only standard time */
  		sp->timecnt = 0;
  		init_ttinfo(&sp->ttis[0], -stdoffset, false, 0);
@@ -1444,7 +1297,7 @@
  	sp->charcnt = charcnt;
  	cp = sp->chars;
  	memcpy(cp, stdname, stdlen);
-@@ -1547,155 +1244,19 @@
+@@ -1547,155 +1246,19 @@
  static void
  gmtload(struct state *const sp)
  {
@@ -1603,7 +1456,7 @@
  		 struct pg_tm *const tmp)
  {
  	const struct ttinfo *ttisp;
-@@ -1704,14 +1265,11 @@
+@@ -1704,14 +1267,11 @@
  	const pg_time_t t = *timep;
  
  	if (sp == NULL)
@@ -1620,7 +1473,7 @@
  		pg_time_t	seconds;
  		pg_time_t	years;
  
-@@ -1720,34 +1278,19 @@
+@@ -1720,33 +1280,18 @@
  		else
  			seconds = t - sp->ats[sp->timecnt - 1];
  		--seconds;
@@ -1655,12 +1508,10 @@
 -						  result->tm_year, years))
 -				return NULL;
 -#else
--			int_fast64_t newy;
-+			int64		newy;
+ 			int_fast64_t newy;
  
  			newy = result->tm_year;
- 			if (t < sp->ats[0])
-@@ -1757,7 +1300,6 @@
+@@ -1757,7 +1302,6 @@
  			if (!(INT_MIN <= newy && newy <= INT_MAX))
  				return NULL;
  			result->tm_year = newy;
@@ -1668,7 +1519,7 @@
  		}
  		return result;
  	}
-@@ -1779,7 +1321,7 @@
+@@ -1779,7 +1323,7 @@
  			else
  				lo = mid + 1;
  		}
@@ -1677,7 +1528,7 @@
  	}
  	ttisp = &sp->ttis[i];
  
-@@ -1792,132 +1334,76 @@
+@@ -1792,132 +1336,76 @@
  	if (result)
  	{
  		result->tm_isdst = ttisp->tt_isdst;
@@ -1745,7 +1596,7 @@
  static struct pg_tm *
 -gmtsub(ATTRIBUTE_MAYBE_UNUSED struct state const *sp, pg_time_t const *timep,
 -	   int_fast32_t offset, struct pg_tm *tmp)
-+gmtsub(pg_time_t const *timep, int32 offset,
++gmtsub(pg_time_t const *timep, int_fast32_t offset,
 +	   struct pg_tm *tmp)
  {
  	struct pg_tm *result;
@@ -1840,13 +1691,7 @@
  {
  	return (y < 0
  			? -1 - leaps_thru_end_of_nonneg(-1 - y)
-@@ -1925,28 +1411,21 @@
- }
- 
- static struct pg_tm *
--timesub(const pg_time_t *timep, int_fast32_t offset,
-+timesub(const pg_time_t *timep, int32 offset,
- 		const struct state *sp, struct pg_tm *tmp)
+@@ -1930,23 +1418,16 @@
  {
  	const struct lsinfo *lp;
  	pg_time_t	tdays;
@@ -1876,7 +1721,7 @@
  	i = (sp == NULL) ? 0 : sp->leapcnt;
  	while (--i >= 0)
  	{
-@@ -1954,175 +1433,134 @@
+@@ -1954,175 +1435,134 @@
  		if (*timep >= lp->ls_trans)
  		{
  			corr = lp->ls_corr;
@@ -2092,8 +1937,7 @@
  
  static bool
 -increment_overflow32(int_fast32_t * const lp, int const m)
-+increment_overflow_time(pg_time_t *tp, int32 j)
- {
+-{
 -#ifdef ckd_add
 -	return ckd_add(lp, *lp, m);
 -#else
@@ -2107,8 +1951,8 @@
 -}
 -
 -static bool
--increment_overflow_time(pg_time_t *tp, int_fast32_t j)
--{
+ increment_overflow_time(pg_time_t *tp, int_fast32_t j)
+ {
 -#ifdef ckd_add
 -	return ckd_add(tp, *tp, j);
 -#else
@@ -2124,7 +1968,7 @@
  	 */
  	if (!(j < 0
  		  ? (TYPE_SIGNED(pg_time_t) ? TIME_T_MIN - j <= *tp : -1 - j < *tp)
-@@ -2130,637 +1568,339 @@
+@@ -2130,637 +1570,339 @@
  		return true;
  	*tp += j;
  	return false;