diff options
Diffstat (limited to 'src/timezone/zic.c')
-rw-r--r-- | src/timezone/zic.c | 74 |
1 files changed, 39 insertions, 35 deletions
diff --git a/src/timezone/zic.c b/src/timezone/zic.c index ae61264364c..4613919afe4 100644 --- a/src/timezone/zic.c +++ b/src/timezone/zic.c @@ -167,9 +167,11 @@ PERCENT_Z_LEN_BOUND = sizeof "+995959" - 1}; QTBUG-53071 <https://bugreports.qt.io/browse/QTBUG-53071>. This workaround will no longer be needed when Qt 5.6.1 and earlier are obsolete, say in the year 2021. */ +#ifndef WORK_AROUND_QTBUG_53071 enum { WORK_AROUND_QTBUG_53071 = true}; +#endif static int charcnt; static bool errors; @@ -1912,12 +1914,6 @@ atcomp(const void *avp, const void *bvp) return (a < b) ? -1 : (a > b); } -static bool -is32(const zic_t x) -{ - return x == ((zic_t) ((int32) x)); -} - static void swaptypes(int i, int j) { @@ -1971,7 +1967,12 @@ writezone(const char *const name, const char *const string, char version, zic_t one = 1; zic_t y2038_boundary = one << 31; ptrdiff_t nats = timecnt + WORK_AROUND_QTBUG_53071; - zic_t *ats = emalloc(size_product(nats, sizeof *ats + 1)); + + /* + * Allocate the ATS and TYPES arrays via a single malloc, as this is a bit + * faster. + */ + zic_t *ats = emalloc(MAXALIGN(size_product(nats, sizeof *ats + 1))); void *typesptr = ats + nats; unsigned char *types = typesptr; @@ -2030,20 +2031,6 @@ writezone(const char *const name, const char *const string, char version, } /* - * 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. */ for (i = 0; i < timecnt; ++i) @@ -2058,31 +2045,47 @@ writezone(const char *const name, const char *const string, char version, } /* + * 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 pg_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. */ timecnt32 = timecnt; timei32 = 0; leapcnt32 = leapcnt; leapi32 = 0; - while (timecnt32 > 0 && !is32(ats[timecnt32 - 1])) + while (0 < timecnt32 && PG_INT32_MAX < ats[timecnt32 - 1]) --timecnt32; - while (timecnt32 > 0 && !is32(ats[timei32])) + while (1 < timecnt32 && ats[timei32] < PG_INT32_MIN + && ats[timei32 + 1] <= PG_INT32_MIN) { + /* + * Discard too-low transitions, except keep any last too-low + * transition if no transition is exactly at PG_INT32_MIN. The kept + * transition will be output as an PG_INT32_MIN "transition" + * appropriate for buggy 32-bit clients that do not use time type 0 + * for timestamps before the first transition; see below. + */ --timecnt32; ++timei32; } - - /* - * Output an INT32_MIN "transition" if appropriate; see below. - */ - if (timei32 > 0 && ats[timei32] > PG_INT32_MIN) - { - --timei32; - ++timecnt32; - } - while (leapcnt32 > 0 && !is32(trans[leapcnt32 - 1])) + while (0 < leapcnt32 && PG_INT32_MAX < trans[leapcnt32 - 1]) --leapcnt32; - while (leapcnt32 > 0 && !is32(trans[leapi32])) + while (0 < leapcnt32 && trans[leapi32] < PG_INT32_MIN) { --leapcnt32; ++leapi32; @@ -2315,7 +2318,8 @@ writezone(const char *const name, const char *const string, char version, if (pass == 1) /* - * Output an INT32_MIN "transition" if appropriate; see above. + * Output an PG_INT32_MIN "transition" if appropriate; see + * above. */ puttzcode(((ats[i] < PG_INT32_MIN) ? PG_INT32_MIN : ats[i]), fp); |