>From 1fc2ef332648a33458775fd8c432d01637941e78 Mon Sep 17 00:00:00 2001
From: Paul Eggert <eggert@cs.ucla.edu>
Date: Thu, 25 Oct 2018 01:02:53 -0700
Subject: [PROPOSED] Fix zic to work with 2015f and earlier clients

Without this fix, clients that read only 32-bit TZif data, such as
2015f zdump with 32-bit time_t, can mishandle zones containing
leap second data.  Problem reported by Daniel Fischer in:
https://mm.icann.org/pipermail/tz/2018-October/027084.html
Also, fix a related bug where the QTBUG-53071 bug workaround does
not work for TZif files containing leap seconds.
* NEWS: Mention this.
* zic.c (is32): Remove; no longer used.
(writezone): Do QTBUG-53071 bug workaround after adjusting
for leap seconds, not before.  Tighten test for out-of-32-bit
range transitions, to give more opportunity to output an
INT32_MIN "transition".
---
 NEWS  |  5 +++++
 zic.c | 42 ++++++++++++++++++++----------------------
 2 files changed, 25 insertions(+), 22 deletions(-)

diff --git a/NEWS b/NEWS
index 68f826e..b4bdf11 100644
--- a/NEWS
+++ b/NEWS
@@ -4,6 +4,11 @@ Unreleased, experimental changes
 
   Changes to code
 
+    When generating TZif files with leap seconds, zic no longer uses a
+    format that trips up older 32-bit clients, fixing a bug introduced
+    in 2018f.  (Reported by Daniel Fischer.)  Also, the zic workaround
+    for QTBUG-53071 now also works for TZif files with leap seconds.
+
     The translator to rearguard format now rewrites the line
     "Rule Japan 1948 1951 - Sep Sat>=8 25:00 0 S" to
     "Rule Japan 1948 1951 - Sep Sun>=9  1:00 0 S".
diff --git a/zic.c b/zic.c
index 06becc2..4c94254 100644
--- a/zic.c
+++ b/zic.c
@@ -1714,12 +1714,6 @@ atcomp(const void *avp, const void *bvp)
 	return (a < b) ? -1 : (a > b);
 }
 
-static bool
-is32(const zic_t x)
-{
-	return INT32_MIN <= x && x <= INT32_MAX;
-}
-
 static void
 swaptypes(int i, int j)
 {
@@ -1797,18 +1791,6 @@ writezone(const char *const name, const char *const string, char version,
 		types[i] = attypes[i].type;
 	}
 
-	/* Work around QTBUG-53071 for timestamps less than y2038_boundary - 1,
-	   by inserting a no-op transition at time y2038_boundary - 1.
-	   This works only for timestamps before the boundary, which
-	   should be good enough in practice as QTBUG-53071 should be
-	   long-dead by 2038.  */
-	if (WORK_AROUND_QTBUG_53071 && timecnt != 0
-	    && ats[timecnt - 1] < y2038_boundary - 1 && strchr(string, '<')) {
-	  ats[timecnt] = y2038_boundary - 1;
-	  types[timecnt] = types[timecnt - 1];
-	  timecnt++;
-	}
-
 	/*
 	** Correct for leap seconds.
 	*/
@@ -1820,6 +1802,22 @@ writezone(const char *const name, const char *const string, char version,
 				break;
 			}
 	}
+
+	/* Work around QTBUG-53071 for timestamps less than y2038_boundary - 1,
+	   by inserting a no-op transition at time y2038_boundary - 1.
+	   This works only for timestamps before the boundary, which
+	   should be good enough in practice as QTBUG-53071 should be
+	   long-dead by 2038.  Do this after correcting for leap
+	   seconds, as the idea is to insert a transition just before
+	   32-bit time_t rolls around, and this occurs at a slightly
+	   different moment if transitions are leap-second corrected.  */
+	if (WORK_AROUND_QTBUG_53071 && timecnt != 0
+	    && ats[timecnt - 1] < y2038_boundary - 1 && strchr(string, '<')) {
+	  ats[timecnt] = y2038_boundary - 1;
+	  types[timecnt] = types[timecnt - 1];
+	  timecnt++;
+	}
+
 	/*
 	** Figure out 32-bit-limited starts and counts.
 	*/
@@ -1827,9 +1825,9 @@ writezone(const char *const name, const char *const string, char version,
 	timei32 = 0;
 	leapcnt32 = leapcnt;
 	leapi32 = 0;
-	while (timecnt32 > 0 && !is32(ats[timecnt32 - 1]))
+	while (0 < timecnt32 && INT32_MAX < ats[timecnt32 - 1])
 		--timecnt32;
-	while (timecnt32 > 0 && !is32(ats[timei32])) {
+	while (0 < timecnt32 && ats[timei32] < INT32_MIN) {
 		--timecnt32;
 		++timei32;
 	}
@@ -1840,9 +1838,9 @@ writezone(const char *const name, const char *const string, char version,
 		--timei32;
 		++timecnt32;
 	}
-	while (leapcnt32 > 0 && !is32(trans[leapcnt32 - 1]))
+	while (0 < leapcnt32 && INT32_MAX < trans[leapcnt32 - 1])
 		--leapcnt32;
-	while (leapcnt32 > 0 && !is32(trans[leapi32])) {
+	while (0 < leapcnt32 && trans[leapi32] < INT32_MIN) {
 		--leapcnt32;
 		++leapi32;
 	}
-- 
2.17.1

