[tz] [PROPOSED] Simplify zic's handling of -r
Paul Eggert
eggert at cs.ucla.edu
Mon Sep 13 01:16:14 UTC 2021
This is refactoring; it should not affect user-visible behavior.
* zic.c (struct timerange): New member pretrans.
(limitrange): New arg locut. Use it to set r.pretrans.
All callers changed.
(writezone): Initialize the new member, to avoid undefined behavior.
Simplify by using the new member.
---
zic.c | 70 +++++++++++++++++++++++++++++------------------------------
1 file changed, 34 insertions(+), 36 deletions(-)
diff --git a/zic.c b/zic.c
index a4406cb..e2a7e13 100644
--- a/zic.c
+++ b/zic.c
@@ -1958,29 +1958,44 @@ struct timerange {
int defaulttype;
ptrdiff_t base, count;
int leapbase, leapcount;
- bool leapexpiry;
+ bool pretrans, leapexpiry;
};
static struct timerange
-limitrange(struct timerange r, zic_t lo, zic_t hi,
+limitrange(struct timerange r, bool locut, zic_t lo, zic_t hi,
zic_t const *ats, unsigned char const *types)
{
+ /* Omit ordinary transitions < LO. */
while (0 < r.count && ats[r.base] < lo) {
r.defaulttype = types[r.base];
r.count--;
r.base++;
}
+
+ /* Omit as many leap seconds < LO as possible, such that the first
+ leap second in the truncated list is <= LO. */
while (1 < r.leapcount && trans[r.leapbase + 1] <= lo) {
r.leapcount--;
r.leapbase++;
}
+ /* Omit ordinary and leap second transitions greater than HI + 1. */
if (hi < ZIC_MAX) {
while (0 < r.count && hi + 1 < ats[r.base + r.count - 1])
r.count--;
while (0 < r.leapcount && hi + 1 < trans[r.leapbase + r.leapcount - 1])
r.leapcount--;
}
+
+ /* Determine whether to keep the last too-low transition if no
+ transition is exactly at LO. The kept transition will be output
+ as a LO "transition"; see "Output a LO_TIME transition" below.
+ This is needed when the output is truncated at the start, and is
+ also useful when catering to buggy 32-bit clients that do not use
+ time type 0 for timestamps before the first transition. */
+ r.pretrans = locut && ! (r.count && ats[r.base] == lo);
+
+ /* Determine whether to append an expiration to the leap second table. */
r.leapexpiry = 0 <= leapexpires && leapexpires - 1 <= hi;
return r;
@@ -2092,9 +2107,11 @@ writezone(const char *const name, const char *const string, char version,
rangeall.base = rangeall.leapbase = 0;
rangeall.count = timecnt;
rangeall.leapcount = leapcnt;
- rangeall.leapexpiry = false;
- range64 = limitrange(rangeall, lo_time, hi_time, ats, types);
- range32 = limitrange(range64, INT32_MIN, INT32_MAX, ats, types);
+ rangeall.pretrans = rangeall.leapexpiry = false;
+ range64 = limitrange(rangeall, min_time < lo_time,
+ lo_time, hi_time, ats, types);
+ range32 = limitrange(range64, INT32_MIN < lo_time,
+ INT32_MIN, INT32_MAX, ats, types);
/* TZif version 4 is needed if a no-op transition is appended to
indicate the expiration of the leap second table, or if the first
@@ -2129,7 +2146,7 @@ writezone(const char *const name, const char *const string, char version,
register int thisleapi, thisleapcnt, thisleaplim;
struct tzhead tzh;
int currenttype, thisdefaulttype;
- bool locut, hicut, thisleapexpiry;
+ bool hicut, pretrans, thisleapexpiry;
zic_t lo;
int old0;
char omittype[TZ_MAX_TYPES];
@@ -2160,8 +2177,8 @@ writezone(const char *const name, const char *const string, char version,
toomanytimes = thistimecnt >> 31 >> 1 != 0;
thisleapi = range32.leapbase;
thisleapcnt = range32.leapcount;
+ pretrans = range32.pretrans;
thisleapexpiry = range32.leapexpiry;
- locut = INT32_MIN < lo_time;
hicut = hi_time < INT32_MAX;
} else {
thisdefaulttype = range64.defaulttype;
@@ -2170,33 +2187,17 @@ writezone(const char *const name, const char *const string, char version,
toomanytimes = thistimecnt >> 31 >> 31 >> 2 != 0;
thisleapi = range64.leapbase;
thisleapcnt = range64.leapcount;
+ pretrans = range64.pretrans;
thisleapexpiry = range64.leapexpiry;
- locut = min_time < lo_time;
hicut = hi_time < max_time;
}
if (toomanytimes)
error(_("too many transition times"));
- /* Keep the last too-low transition if no transition is
- exactly at LO. The kept transition will be output as
- a LO "transition"; see "Output a LO_TIME transition"
- below. This is needed when the output is truncated at
- the start, and is also useful when catering to buggy
- 32-bit clients that do not use time type 0 for
- timestamps before the first transition. */
- if (0 < thistimei && ats[thistimei] != lo_time) {
- thistimei--;
- thistimecnt++;
- locut = false;
- }
-
thistimelim = thistimei + thistimecnt;
- if (thistimecnt != 0) {
- if (ats[thistimei] == lo_time)
- locut = false;
- if (hi_time < ZIC_MAX && ats[thistimelim - 1] == hi_time + 1)
- hicut = false;
- }
+ if (thistimecnt && hi_time < ZIC_MAX
+ && ats[thistimelim - 1] == hi_time + 1)
+ hicut = false;
memset(omittype, true, typecnt);
omittype[thisdefaulttype] = false;
for (i = thistimei; i < thistimelim; i++)
@@ -2291,11 +2292,9 @@ writezone(const char *const name, const char *const string, char version,
indmap[desigidx[i]] = j;
}
if (pass == 1 && !want_bloat()) {
- thisleapcnt = 0;
- thisleapexpiry = false;
- thistimecnt = - (locut + hicut);
+ pretrans = hicut = thisleapexpiry = false;
+ thistimecnt = thisleapcnt = 0;
thistypecnt = thischarcnt = 1;
- thistimelim = thistimei;
}
#define DO(field) fwrite(tzh.field, sizeof tzh.field, 1, fp)
memset(&tzh, 0, sizeof tzh);
@@ -2304,7 +2303,7 @@ writezone(const char *const name, const char *const string, char version,
convert(utcnt, tzh.tzh_ttisutcnt);
convert(stdcnt, tzh.tzh_ttisstdcnt);
convert(thisleapcnt + thisleapexpiry, tzh.tzh_leapcnt);
- convert(locut + thistimecnt + hicut, tzh.tzh_timecnt);
+ convert(pretrans + thistimecnt + hicut, tzh.tzh_timecnt);
convert(thistypecnt, tzh.tzh_typecnt);
convert(thischarcnt, tzh.tzh_charcnt);
DO(tzh_magic);
@@ -2331,16 +2330,15 @@ writezone(const char *const name, const char *const string, char version,
for this pass. */
lo = pass == 1 && lo_time < INT32_MIN ? INT32_MIN : lo_time;
- if (locut)
+ if (pretrans)
puttzcodepass(lo, fp, pass);
for (i = thistimei; i < thistimelim; ++i) {
- zic_t at = ats[i] < lo ? lo : ats[i];
- puttzcodepass(at, fp, pass);
+ puttzcodepass(ats[i], fp, pass);
}
if (hicut)
puttzcodepass(hi_time + 1, fp, pass);
currenttype = 0;
- if (locut)
+ if (pretrans)
putc(currenttype, fp);
for (i = thistimei; i < thistimelim; ++i) {
currenttype = typemap[types[i]];
--
2.31.1
More information about the tz
mailing list