[PROPOSED 1/4] Fix zdump diagnostic for missing timezone
* zdump.c (main): Fix typo in diagnostic for ‘zdump -i nosuchzone’. --- zdump.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zdump.c b/zdump.c index 6f9573ec..7d99cc74 100644 --- a/zdump.c +++ b/zdump.c @@ -602,7 +602,7 @@ main(int argc, char *argv[]) if (!tz) { char const *e = strerror(errno); fprintf(stderr, _("%s: unknown timezone '%s': %s\n"), - progname, argv[1], e); + progname, argv[i], e); return EXIT_FAILURE; } if (now) { -- 2.41.0
To reproduce the bug, use the following file foo.zi: Rule R 2073 max - Mar Sat<=30 2:00 1:00 S Rule R 2073 max - Oct Sat<=30 2:00 0 - Zone Z 2:00 R EE%sT and run ‘zic foo.zi; zdump -i -c 2072,2073 Z’. Without the fix, this incorrectly outputs the following two lines: 2072-03-26 03 +03 EEST 1 2072-10-29 01 +02 EET even though there are no transitions in 2072. * localtime.c (tzloadbody): Compute sp->goahead from ts->goahead. Do not guess goahead and goback from the timestamps, as that was just a guess that predates having TZ strings in the TZif file, and the guess is no longer needed and sometimes guesses wrong. (typesequiv): Remove; no longer used. (tzparse): Last arg is now pointer to const. This is just for clarity; it doesn’t affect behavior. --- NEWS | 4 ++++ localtime.c | 62 ++++++++--------------------------------------------- 2 files changed, 13 insertions(+), 53 deletions(-) diff --git a/NEWS b/NEWS index 411935a5..44ed20f3 100644 --- a/NEWS +++ b/NEWS @@ -11,6 +11,10 @@ Unreleased, experimental changes Changes to code + localtime.c no longer mishandles TZif files that contain a single + transition into a DST regime. Previously, it incorrectly assumed + DST was in effect before the transition too. + zic now works again on Linux 2.6.16 and 2.6.17 (2006). (Problem reported by Rune Torgersen.) diff --git a/localtime.c b/localtime.c index 7cd43dc1..a54d3ae4 100644 --- a/localtime.c +++ b/localtime.c @@ -153,8 +153,7 @@ static int_fast32_t leapcorr(struct state const *, time_t); static bool normalize_overflow32(int_fast32_t *, int *, int); static struct tm *timesub(time_t const *, int_fast32_t, struct state const *, struct tm *); -static bool typesequiv(struct state const *, int, int); -static bool tzparse(char const *, struct state *, struct state *); +static bool tzparse(char const *, struct state *, struct state const *); #ifdef ALL_STATE static struct state * lclptr; @@ -674,14 +673,18 @@ tzloadbody(char const *name, struct state *sp, bool doextend, == sp->types[sp->timecnt - 2])) sp->timecnt--; - for (i = 0; - i < ts->timecnt && sp->timecnt < TZ_MAX_TIMES; - i++) { + sp->goahead = ts->goahead; + + for (i = 0; i < ts->timecnt; i++) { time_t t = ts->ats[i]; if (increment_overflow_time(&t, leapcorr(sp, t)) || (0 < sp->timecnt && t <= sp->ats[sp->timecnt - 1])) continue; + if (TZ_MAX_TIMES <= sp->timecnt) { + sp->goahead = false; + break; + } sp->ats[sp->timecnt] = t; sp->types[sp->timecnt] = (sp->typecnt + ts->types[i]); @@ -694,28 +697,6 @@ tzloadbody(char const *name, struct state *sp, bool doextend, } if (sp->typecnt == 0) return EINVAL; - if (sp->timecnt > 1) { - if (sp->ats[0] <= TIME_T_MAX - SECSPERREPEAT) { - time_t repeatat = sp->ats[0] + SECSPERREPEAT; - int repeattype = sp->types[0]; - for (i = 1; i < sp->timecnt; ++i) - if (sp->ats[i] == repeatat - && typesequiv(sp, sp->types[i], repeattype)) { - sp->goback = true; - break; - } - } - if (TIME_T_MIN + SECSPERREPEAT <= sp->ats[sp->timecnt - 1]) { - time_t repeatat = sp->ats[sp->timecnt - 1] - SECSPERREPEAT; - int repeattype = sp->types[sp->timecnt - 1]; - for (i = sp->timecnt - 2; i >= 0; --i) - if (sp->ats[i] == repeatat - && typesequiv(sp, sp->types[i], repeattype)) { - sp->goahead = true; - break; - } - } - } /* Infer sp->defaulttype from the data. Although this default type is always zero for data from recent tzdb releases, @@ -792,31 +773,6 @@ tzload(char const *name, struct state *sp, bool doextend) #endif } -static bool -typesequiv(const struct state *sp, int a, int b) -{ - register bool result; - - if (sp == NULL || - a < 0 || a >= sp->typecnt || - b < 0 || b >= sp->typecnt) - result = false; - else { - /* Compare the relevant members of *AP and *BP. - Ignore tt_ttisstd and tt_ttisut, as they are - irrelevant now and counting them could cause - sp->goahead to mistakenly remain false. */ - register const struct ttinfo * ap = &sp->ttis[a]; - register const struct ttinfo * bp = &sp->ttis[b]; - result = (ap->tt_utoff == bp->tt_utoff - && ap->tt_isdst == bp->tt_isdst - && (strcmp(&sp->chars[ap->tt_desigidx], - &sp->chars[bp->tt_desigidx]) - == 0)); - } - return result; -} - static const int mon_lengths[2][MONSPERYEAR] = { { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } @@ -1116,7 +1072,7 @@ transtime(const int year, register const struct rule *const rulep, */ static bool -tzparse(const char *name, struct state *sp, struct state *basep) +tzparse(const char *name, struct state *sp, struct state const *basep) { const char * stdname; const char * dstname; -- 2.41.0
The bug can be observed when processing the following .zi data, adapted from the current ‘asia’ file: Rule Palestine 2075 max - Mar Sat<=30 2:00 1:00 S Rule Palestine 2075 max - Oct Sat<=30 2:00 0 - Rule Palestine 2076 only - Jul 25 2:00 0 - Rule Palestine 2076 only - Sep 5 2:00 1:00 S Zone Asia/Gaza 2:00 - EET 2012 2:00 Palestine EE%sT Without the fix, zic generates an incorrect TZif file, in which the special-case 2076 transitions are omitted. This causes ‘zdump -ic 2076,2077 Asia/Gaza’ to mistakenly omit the lines: 2076-07-25 01 +02 EET 2076-09-05 03 +03 EEST 1 * zic.c (outzone): Redo algorithm to work even when the effect of a Rule that never ends (TO="max") is interspersed with the effect of a one-shot rule (TO="only"). --- NEWS | 4 ++++ zic.c | 57 +++++++++++++++++++++++++++++++++++++++------------------ 2 files changed, 43 insertions(+), 18 deletions(-) diff --git a/NEWS b/NEWS index 44ed20f3..115aff7b 100644 --- a/NEWS +++ b/NEWS @@ -15,6 +15,10 @@ Unreleased, experimental changes transition into a DST regime. Previously, it incorrectly assumed DST was in effect before the transition too. + zic no longer mishandles data for Palestine after the year 2075. + Previously, it incorrectly omitted post-2075 transitions that are + predicted for just before and just after Ramadan. + zic now works again on Linux 2.6.16 and 2.6.17 (2006). (Problem reported by Rune Torgersen.) diff --git a/zic.c b/zic.c index 4293637d..38685f62 100644 --- a/zic.c +++ b/zic.c @@ -2980,6 +2980,10 @@ rule_cmp(struct rule const *a, struct rule const *b) return a->r_dayofmonth - b->r_dayofmonth; } +/* Store into RESULT a POSIX TZ string that represent the future + predictions for the zone ZPFIRST with ZONECOUNT entries. Return a + compatibility indicator (a TZDB release year) if successful, a + negative integer if no such TZ string exissts. */ static int stringzone(char *result, struct zone const *zpfirst, ptrdiff_t zonecount) { @@ -3119,7 +3123,8 @@ outzone(const struct zone *zpfirst, ptrdiff_t zonecount) register int compat; register bool do_extend; register char version; - ptrdiff_t lastatmax = -1; + zic_t nonTZlimtime = ZIC_MIN; + int nonTZlimtype = -1; zic_t max_year0; int defaulttype = -1; @@ -3235,7 +3240,6 @@ outzone(const struct zone *zpfirst, ptrdiff_t zonecount) unspecifiedtype = addtype(0, "-00", false, false, false); for (i = 0; i < zonecount; ++i) { - struct rule *prevrp = NULL; /* ** A guess that may well be corrected later. */ @@ -3245,8 +3249,6 @@ outzone(const struct zone *zpfirst, ptrdiff_t zonecount) bool useuntil = i < (zonecount - 1); zic_t stdoff = zp->z_stdoff; zic_t startoff = stdoff; - zic_t prevktime; - INITIALIZE(prevktime); if (useuntil && zp->z_untiltime <= min_time) continue; eat(zp->z_filenum, zp->z_linenum); @@ -3260,6 +3262,10 @@ outzone(const struct zone *zpfirst, ptrdiff_t zonecount) startttisut); if (usestart) { addtt(starttime, type); + if (useuntil && nonTZlimtime < starttime) { + nonTZlimtime = starttime; + nonTZlimtype = type; + } usestart = false; } else defaulttype = type; @@ -3387,23 +3393,16 @@ outzone(const struct zone *zpfirst, ptrdiff_t zonecount) doabbr(ab, zp, rp->r_abbrvar, rp->r_isdst, rp->r_save, false); offset = oadd(zp->z_stdoff, rp->r_save); - if (!want_bloat() && !useuntil && !do_extend - && prevrp && lo_time <= prevktime - && redundant_time <= ktime - && rp->r_hiyear == ZIC_MAX - && prevrp->r_hiyear == ZIC_MAX) - break; type = addtype(offset, ab, rp->r_isdst, rp->r_todisstd, rp->r_todisut); if (defaulttype < 0 && !rp->r_isdst) defaulttype = type; - if (rp->r_hiyear == ZIC_MAX - && ! (0 <= lastatmax - && ktime < attypes[lastatmax].at)) - lastatmax = timecnt; addtt(ktime, type); - prevrp = rp; - prevktime = ktime; + if (nonTZlimtime < ktime + && (useuntil || rp->r_hiyear != ZIC_MAX)) { + nonTZlimtime = ktime; + nonTZlimtype = type; + } } } } @@ -3438,8 +3437,30 @@ error(_("can't determine time zone abbreviation to use just after until time")); } if (defaulttype < 0) defaulttype = 0; - if (0 <= lastatmax) - attypes[lastatmax].dontmerge = true; + if (!do_extend && !want_bloat()) { + /* The earliest transition into a time governed by the TZ string. */ + zic_t TZstarttime = ZIC_MAX; + for (i = 0; i < timecnt; i++) { + zic_t at = attypes[i].at; + if (nonTZlimtime < at && at < TZstarttime) + TZstarttime = at; + } + if (TZstarttime == ZIC_MAX) + TZstarttime = nonTZlimtime; + + /* Omit trailing transitions deducible from the TZ string. */ + for (i = j = 0; i < timecnt; i++) + if (redundant_time <= attypes[i].at + && attypes[i].at <= TZstarttime) { + attypes[j].at = attypes[i].at; + attypes[j].dontmerge = (attypes[i].at == TZstarttime + && (nonTZlimtype != attypes[i].type + || strchr(envvar, ','))); + attypes[j].type = attypes[i].type; + j++; + } + timecnt = j; + } if (do_extend) { /* ** If we're extending the explicitly listed observations -- 2.41.0
* zic.c: Indent strings more consistently. The old indenting dates back to when we could not assume C89 or later. --- zic.c | 41 ++++++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/zic.c b/zic.c index 38685f62..cb473bdc 100644 --- a/zic.c +++ b/zic.c @@ -1020,7 +1020,8 @@ main(int argc, char **argv) directory = optarg; else { fprintf(stderr, -_("%s: More than one -d option specified\n"), + _("%s: More than one -d option" + " specified\n"), progname); return EXIT_FAILURE; } @@ -1030,7 +1031,8 @@ _("%s: More than one -d option specified\n"), lcltime = optarg; else { fprintf(stderr, -_("%s: More than one -l option specified\n"), + _("%s: More than one -l option" + " specified\n"), progname); return EXIT_FAILURE; } @@ -1040,7 +1042,8 @@ _("%s: More than one -l option specified\n"), psxrules = optarg; else { fprintf(stderr, -_("%s: More than one -p option specified\n"), + _("%s: More than one -p option" + " specified\n"), progname); return EXIT_FAILURE; } @@ -1063,7 +1066,8 @@ _("%s: More than one -p option specified\n"), leapsec = optarg; else { fprintf(stderr, -_("%s: More than one -L option specified\n"), + _("%s: More than one -L option" + " specified\n"), progname); return EXIT_FAILURE; } @@ -1074,13 +1078,14 @@ _("%s: More than one -L option specified\n"), case 'r': if (timerange_given) { fprintf(stderr, -_("%s: More than one -r option specified\n"), + _("%s: More than one -r option" + " specified\n"), progname); return EXIT_FAILURE; } if (! timerange_option(optarg)) { fprintf(stderr, -_("%s: invalid time range: %s\n"), + _("%s: invalid time range: %s\n"), progname, optarg); return EXIT_FAILURE; } @@ -1875,16 +1880,14 @@ inzone(char **fields, int nfields) return false; } if (lcltime != NULL && strcmp(fields[ZF_NAME], tzdefault) == 0) { - error( -_("\"Zone %s\" line and -l option are mutually exclusive"), - tzdefault); - return false; + error(_("\"Zone %s\" line and -l option are mutually exclusive"), + tzdefault); + return false; } if (strcmp(fields[ZF_NAME], TZDEFRULES) == 0 && psxrules != NULL) { - error( -_("\"Zone %s\" line and -p option are mutually exclusive"), - TZDEFRULES); - return false; + error(_("\"Zone %s\" line and -p option are mutually exclusive"), + TZDEFRULES); + return false; } for (i = 0; i < nzones; ++i) if (zones[i].z_name != NULL && @@ -1976,10 +1979,9 @@ inzsub(char **fields, int nfields, bool iscont) zones[nzones - 1].z_untiltime > min_time && zones[nzones - 1].z_untiltime < max_time && zones[nzones - 1].z_untiltime >= z.z_untiltime) { - error(_( -"Zone continuation line end time is not after end time of previous line" - )); - return false; + error(_("Zone continuation line end time is" + " not after end time of previous line")); + return false; } } z.z_name = iscont ? NULL : estrdup(fields[ZF_NAME]); @@ -3413,7 +3415,8 @@ outzone(const struct zone *zpfirst, ptrdiff_t zonecount) isdst, save, false); eat(zp->z_filenum, zp->z_linenum); if (*startbuf == '\0') -error(_("can't determine time zone abbreviation to use just after until time")); + error(_("can't determine time zone abbreviation" + " to use just after until time")); else { int type = addtype(startoff, startbuf, isdst, startttisstd, startttisut); -- 2.41.0
participants (1)
-
Paul Eggert