diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2019-07-17 18:26:23 -0400 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2019-07-17 18:26:23 -0400 |
commit | 1d1ff50d27cf32e37c5294c34d84dd4225db99a9 (patch) | |
tree | 4ce4c3f381a2cabf32519ebb07a1b96342c1b988 /src/timezone/zic.c | |
parent | 46e2a18d0dfd140bfa36e5d543feeac5f5600244 (diff) | |
download | postgresql-1d1ff50d27cf32e37c5294c34d84dd4225db99a9.tar.gz postgresql-1d1ff50d27cf32e37c5294c34d84dd4225db99a9.zip |
Sync our copy of the timezone library with IANA release tzcode2019b.
A large fraction of this diff is just due to upstream's somewhat
random decision to rename a bunch of internal variables and struct
fields. However, there is an interesting new feature in zic:
it's grown a "-b slim" option that emits zone files without 32-bit
data and other backwards-compatibility hacks. We should consider
whether we wish to enable that.
Diffstat (limited to 'src/timezone/zic.c')
-rw-r--r-- | src/timezone/zic.c | 453 |
1 files changed, 243 insertions, 210 deletions
diff --git a/src/timezone/zic.c b/src/timezone/zic.c index de8daaee5c9..f440065bd91 100644 --- a/src/timezone/zic.c +++ b/src/timezone/zic.c @@ -77,12 +77,10 @@ struct rule int r_wday; zic_t r_tod; /* time from midnight */ - bool r_todisstd; /* above is standard time if 1 or wall clock - * time if 0 */ - bool r_todisgmt; /* above is GMT if 1 or local time if 0 */ + bool r_todisstd; /* is r_tod standard time? */ + bool r_todisut; /* is r_tod UT? */ bool r_isdst; /* is this daylight saving time? */ - zic_t r_stdoff; /* offset from default time (which is usually - * standard time) */ + zic_t r_save; /* offset from standard time */ const char *r_abbrvar; /* variable part of abbreviation */ bool r_todo; /* a rule to do (used in outzone) */ @@ -103,13 +101,13 @@ struct zone lineno_t z_linenum; const char *z_name; - zic_t z_gmtoff; + zic_t z_stdoff; char *z_rule; const char *z_format; char z_format_specifier; bool z_isdst; - zic_t z_stdoff; + zic_t z_save; struct rule *z_rules; ptrdiff_t z_nrules; @@ -133,7 +131,7 @@ static void associate(void); static void dolink(const char *, const char *, bool); static char **getfields(char *buf); static zic_t gethms(const char *string, const char *errstring); -static zic_t getstdoff(char *, bool *); +static zic_t getsave(char *, bool *); static void infile(const char *filename); static void inleap(char **fields, int nfields); static void inlink(char **fields, int nfields); @@ -210,7 +208,7 @@ static int typecnt; */ #define ZF_NAME 1 -#define ZF_GMTOFF 2 +#define ZF_STDOFF 2 #define ZF_RULE 3 #define ZF_FORMAT 4 #define ZF_TILYEAR 5 @@ -224,7 +222,7 @@ static int typecnt; * Which fields are which on a Zone continuation line. */ -#define ZFC_GMTOFF 0 +#define ZFC_STDOFF 0 #define ZFC_RULE 1 #define ZFC_FORMAT 2 #define ZFC_TILYEAR 3 @@ -245,7 +243,7 @@ static int typecnt; #define RF_MONTH 5 #define RF_DAY 6 #define RF_TOD 7 -#define RF_STDOFF 8 +#define RF_SAVE 8 #define RF_ABBRVAR 9 #define RULE_FIELDS 10 @@ -389,11 +387,11 @@ static struct attype bool dontmerge; unsigned char type; } *attypes; -static zic_t gmtoffs[TZ_MAX_TYPES]; +static zic_t utoffs[TZ_MAX_TYPES]; static char isdsts[TZ_MAX_TYPES]; -static unsigned char abbrinds[TZ_MAX_TYPES]; +static unsigned char desigidx[TZ_MAX_TYPES]; static bool ttisstds[TZ_MAX_TYPES]; -static bool ttisgmts[TZ_MAX_TYPES]; +static bool ttisuts[TZ_MAX_TYPES]; static char chars[TZ_MAX_CHARS]; static zic_t trans[TZ_MAX_LEAPS]; static zic_t corr[TZ_MAX_LEAPS]; @@ -540,8 +538,9 @@ usage(FILE *stream, int status) { fprintf(stream, _("%s: usage is %s [ --version ] [ --help ] [ -v ] [ -P ] \\\n" - "\t[ -l localtime ] [ -p posixrules ] [ -d directory ] \\\n" - "\t[ -t localtime-link ] [ -L leapseconds ] [ -r '[@lo][/@hi]' ] \\\n" + "\t[ -b {slim|fat} ] [ -d directory ] [ -l localtime ]" + " [ -L leapseconds ] \\\n" + "\t[ -p posixrules ] [ -r '[@lo][/@hi]' ] [ -t localtime-link ] \\\n" "\t[ filename ... ]\n\n" "Report bugs to %s.\n"), progname, progname, PACKAGE_BUGREPORT); @@ -625,6 +624,21 @@ static const char *leapsec; static const char *tzdefault; static const char *yitcommand; +/* -1 if the TZif output file should be slim, 0 if default, 1 if the + output should be fat for backward compatibility. Currently the + default is fat, although this may change. */ +static int bloat; + +static bool +want_bloat(void) +{ + return 0 <= bloat; +} + +#ifndef ZIC_BLOAT_DEFAULT +#define ZIC_BLOAT_DEFAULT "fat" +#endif + int main(int argc, char **argv) { @@ -655,11 +669,27 @@ main(int argc, char **argv) { usage(stdout, EXIT_SUCCESS); } - while ((c = getopt(argc, argv, "d:l:L:p:Pr:st:vy:")) != EOF && c != -1) + while ((c = getopt(argc, argv, "b:d:l:L:p:Pr:st:vy:")) != EOF && c != -1) switch (c) { default: usage(stderr, EXIT_FAILURE); + case 'b': + if (strcmp(optarg, "slim") == 0) + { + if (0 < bloat) + error(_("incompatible -b options")); + bloat = -1; + } + else if (strcmp(optarg, "fat") == 0) + { + if (bloat < 0) + error(_("incompatible -b options")); + bloat = 1; + } + else + error(_("invalid option: -b '%s'"), optarg); + break; case 'd': if (directory == NULL) directory = strdup(optarg); @@ -759,6 +789,8 @@ main(int argc, char **argv) } if (optind == argc - 1 && strcmp(argv[optind], "=") == 0) usage(stderr, EXIT_FAILURE); /* usage message by request */ + if (bloat == 0) + bloat = strcmp(ZIC_BLOAT_DEFAULT, "slim") == 0 ? -1 : 1; if (directory == NULL) directory = "data"; if (tzdefault == NULL) @@ -1183,7 +1215,7 @@ associate(void) * Maybe we have a local standard time offset. */ eat(zp->z_filename, zp->z_linenum); - zp->z_stdoff = getstdoff(zp->z_rule, &zp->z_isdst); + zp->z_save = getsave(zp->z_rule, &zp->z_isdst); /* * Note, though, that if there's no rule, a '%s' in the format is @@ -1380,10 +1412,10 @@ gethms(char const *string, char const *errstring) } static zic_t -getstdoff(char *field, bool *isdst) +getsave(char *field, bool *isdst) { int dst = -1; - zic_t stdoff; + zic_t save; size_t fieldlen = strlen(field); if (fieldlen != 0) @@ -1402,9 +1434,9 @@ getstdoff(char *field, bool *isdst) break; } } - stdoff = gethms(field, _("invalid saved time")); - *isdst = dst < 0 ? stdoff != 0 : dst; - return stdoff; + save = gethms(field, _("invalid saved time")); + *isdst = dst < 0 ? save != 0 : dst; + return save; } static void @@ -1443,7 +1475,7 @@ inrule(char **fields, int nfields) } r.r_filename = filename; r.r_linenum = linenum; - r.r_stdoff = getstdoff(fields[RF_STDOFF], &r.r_isdst); + r.r_save = getsave(fields[RF_SAVE], &r.r_isdst); rulesub(&r, fields[RF_LOYEAR], fields[RF_HIYEAR], fields[RF_COMMAND], fields[RF_MONTH], fields[RF_DAY], fields[RF_TOD]); r.r_name = ecpyalloc(fields[RF_NAME]); @@ -1509,7 +1541,7 @@ inzsub(char **fields, int nfields, bool iscont) char *cp; char *cp1; static struct zone z; - int i_gmtoff, + int i_stdoff, i_rule, i_format; int i_untilyear, @@ -1520,7 +1552,7 @@ inzsub(char **fields, int nfields, bool iscont) if (iscont) { - i_gmtoff = ZFC_GMTOFF; + i_stdoff = ZFC_STDOFF; i_rule = ZFC_RULE; i_format = ZFC_FORMAT; i_untilyear = ZFC_TILYEAR; @@ -1533,7 +1565,7 @@ inzsub(char **fields, int nfields, bool iscont) return false; else { - i_gmtoff = ZF_GMTOFF; + i_stdoff = ZF_STDOFF; i_rule = ZF_RULE; i_format = ZF_FORMAT; i_untilyear = ZF_TILYEAR; @@ -1544,7 +1576,7 @@ inzsub(char **fields, int nfields, bool iscont) } z.z_filename = filename; z.z_linenum = linenum; - z.z_gmtoff = gethms(fields[i_gmtoff], _("invalid UT offset")); + z.z_stdoff = gethms(fields[i_stdoff], _("invalid UT offset")); if ((cp = strchr(fields[i_format], '%')) != NULL) { if ((*++cp != 's' && *cp != 'z') || strchr(cp, '%') @@ -1768,7 +1800,7 @@ rulesub(struct rule *rp, const char *loyearp, const char *hiyearp, } rp->r_month = lp->l_value; rp->r_todisstd = false; - rp->r_todisgmt = false; + rp->r_todisut = false; dp = ecpyalloc(timep); if (*dp != '\0') { @@ -1777,19 +1809,19 @@ rulesub(struct rule *rp, const char *loyearp, const char *hiyearp, { case 's': /* Standard */ rp->r_todisstd = true; - rp->r_todisgmt = false; + rp->r_todisut = false; *ep = '\0'; break; case 'w': /* Wall */ rp->r_todisstd = false; - rp->r_todisgmt = false; + rp->r_todisut = false; *ep = '\0'; break; case 'g': /* Greenwich */ case 'u': /* Universal */ case 'z': /* Zulu */ rp->r_todisstd = true; - rp->r_todisgmt = true; + rp->r_todisut = true; *ep = '\0'; break; } @@ -1977,41 +2009,6 @@ atcomp(const void *avp, const void *bvp) return (a < b) ? -1 : (a > b); } -static void -swaptypes(int i, int j) -{ - { - zic_t t = gmtoffs[i]; - - gmtoffs[i] = gmtoffs[j]; - gmtoffs[j] = t; - } - { - char t = isdsts[i]; - - isdsts[i] = isdsts[j]; - isdsts[j] = t; - } - { - unsigned char t = abbrinds[i]; - - abbrinds[i] = abbrinds[j]; - abbrinds[j] = t; - } - { - bool t = ttisstds[i]; - - ttisstds[i] = ttisstds[j]; - ttisstds[j] = t; - } - { - bool t = ttisgmts[i]; - - ttisgmts[i] = ttisgmts[j]; - ttisgmts[j] = t; - } -} - struct timerange { int defaulttype; @@ -2091,10 +2088,12 @@ writezone(const char *const name, const char *const string, char version, fromi = 0; for (; fromi < timecnt; ++fromi) { - if (toi != 0 && ((attypes[fromi].at + - gmtoffs[attypes[toi - 1].type]) <= - (attypes[toi - 1].at + gmtoffs[toi == 1 ? 0 - : attypes[toi - 2].type]))) + if (toi != 0 + && ((attypes[fromi].at + + utoffs[attypes[toi - 1].type]) + <= (attypes[toi - 1].at + + utoffs[toi == 1 ? 0 + : attypes[toi - 2].type]))) { attypes[toi - 1].type = attypes[fromi].type; @@ -2102,7 +2101,12 @@ writezone(const char *const name, const char *const string, char version, } if (toi == 0 || attypes[fromi].dontmerge - || attypes[toi - 1].type != attypes[fromi].type) + || (utoffs[attypes[toi - 1].type] + != utoffs[attypes[fromi].type]) + || (isdsts[attypes[toi - 1].type] + != isdsts[attypes[fromi].type]) + || (desigidx[attypes[toi - 1].type] + != desigidx[attypes[fromi].type])) attypes[toi++] = attypes[fromi]; } timecnt = toi; @@ -2151,7 +2155,7 @@ writezone(const char *const name, const char *const string, char version, * 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 + if (WORK_AROUND_QTBUG_53071 && timecnt != 0 && want_bloat() && ats[timecnt - 1] < y2038_boundary - 1 && strchr(string, '<')) { ats[timecnt] = y2038_boundary - 1; @@ -2213,7 +2217,9 @@ writezone(const char *const name, const char *const string, char version, int old0; char omittype[TZ_MAX_TYPES]; int typemap[TZ_MAX_TYPES]; - int thistypecnt; + int thistypecnt, + stdcnt, + utcnt; char thischars[TZ_MAX_CHARS]; int thischarcnt; bool toomanytimes; @@ -2293,7 +2299,6 @@ writezone(const char *const name, const char *const string, char version, * in the output instead of OLD0. TYPEMAP also omits unused types. */ old0 = strlen(omittype); - swaptypes(old0, thisdefaulttype); #ifndef LEAVE_SOME_PRE_2011_SYSTEMS_IN_THE_LURCH @@ -2303,6 +2308,7 @@ writezone(const char *const name, const char *const string, char version, * offset, append an (unused) copy of the most recently used type (to * help get global "altzone" and "timezone" variables set correctly). */ + if (want_bloat()) { int mrudst, mrustd, @@ -2317,34 +2323,39 @@ writezone(const char *const name, const char *const string, char version, else mrustd = types[i]; for (i = old0; i < typecnt; i++) - if (!omittype[i]) + { + int h = (i == old0 ? thisdefaulttype + : i == thisdefaulttype ? old0 : i); + + if (!omittype[h]) { - if (isdsts[i]) + if (isdsts[h]) hidst = i; else histd = i; } + } if (hidst >= 0 && mrudst >= 0 && hidst != mrudst && - gmtoffs[hidst] != gmtoffs[mrudst]) + utoffs[hidst] != utoffs[mrudst]) { isdsts[mrudst] = -1; - type = addtype(gmtoffs[mrudst], - &chars[abbrinds[mrudst]], + type = addtype(utoffs[mrudst], + &chars[desigidx[mrudst]], true, ttisstds[mrudst], - ttisgmts[mrudst]); + ttisuts[mrudst]); isdsts[mrudst] = 1; omittype[type] = false; } if (histd >= 0 && mrustd >= 0 && histd != mrustd && - gmtoffs[histd] != gmtoffs[mrustd]) + utoffs[histd] != utoffs[mrustd]) { isdsts[mrustd] = -1; - type = addtype(gmtoffs[mrustd], - &chars[abbrinds[mrustd]], + type = addtype(utoffs[mrustd], + &chars[desigidx[mrustd]], false, ttisstds[mrustd], - ttisgmts[mrustd]); + ttisuts[mrustd]); isdsts[mrustd] = 0; omittype[type] = false; } @@ -2360,16 +2371,20 @@ writezone(const char *const name, const char *const string, char version, for (i = 0; i < sizeof indmap / sizeof indmap[0]; ++i) indmap[i] = -1; - thischarcnt = 0; + thischarcnt = stdcnt = utcnt = 0; for (i = old0; i < typecnt; i++) { char *thisabbr; if (omittype[i]) continue; - if (indmap[abbrinds[i]] >= 0) + if (ttisstds[i]) + stdcnt = thistypecnt; + if (ttisuts[i]) + utcnt = thistypecnt; + if (indmap[desigidx[i]] >= 0) continue; - thisabbr = &chars[abbrinds[i]]; + thisabbr = &chars[desigidx[i]]; for (j = 0; j < thischarcnt; ++j) if (strcmp(&thischars[j], thisabbr) == 0) break; @@ -2378,14 +2393,21 @@ writezone(const char *const name, const char *const string, char version, strcpy(&thischars[thischarcnt], thisabbr); thischarcnt += strlen(thisabbr) + 1; } - indmap[abbrinds[i]] = j; + indmap[desigidx[i]] = j; + } + if (pass == 1 && !want_bloat()) + { + utcnt = stdcnt = thisleapcnt = 0; + thistimecnt = -locut - hicut; + thistypecnt = thischarcnt = 1; + thistimelim = thistimei; } #define DO(field) fwrite(tzh.field, sizeof tzh.field, 1, fp) tzh = tzh0; memcpy(tzh.tzh_magic, TZ_MAGIC, sizeof tzh.tzh_magic); tzh.tzh_version[0] = version; - convert(thistypecnt, tzh.tzh_ttisgmtcnt); - convert(thistypecnt, tzh.tzh_ttisstdcnt); + convert(utcnt, tzh.tzh_ttisutcnt); + convert(stdcnt, tzh.tzh_ttisstdcnt); convert(thisleapcnt, tzh.tzh_leapcnt); convert(locut + thistimecnt + hicut, tzh.tzh_timecnt); convert(thistypecnt, tzh.tzh_typecnt); @@ -2393,13 +2415,22 @@ writezone(const char *const name, const char *const string, char version, DO(tzh_magic); DO(tzh_version); DO(tzh_reserved); - DO(tzh_ttisgmtcnt); + DO(tzh_ttisutcnt); DO(tzh_ttisstdcnt); DO(tzh_leapcnt); DO(tzh_timecnt); DO(tzh_typecnt); DO(tzh_charcnt); #undef DO + if (pass == 1 && !want_bloat()) + { + /* Output a minimal data block with just one time type. */ + puttzcode(0, fp); /* utoff */ + putc(0, fp); /* dst */ + putc(0, fp); /* index of abbreviation */ + putc(0, fp); /* empty-string abbreviation */ + continue; + } /* PG: print current timezone abbreviations if requested */ if (print_abbrevs && pass == 2) @@ -2410,14 +2441,14 @@ writezone(const char *const name, const char *const string, char version, if (i == thistimelim - 1 || ats[i + 1] > print_cutoff) { unsigned char tm = types[i]; - char *thisabbrev = &thischars[indmap[abbrinds[tm]]]; + char *thisabbrev = &thischars[indmap[desigidx[tm]]]; /* filter out assorted junk entries */ if (strcmp(thisabbrev, GRANDPARENTED) != 0 && strcmp(thisabbrev, "zzz") != 0) fprintf(stdout, "%s\t" INT64_FORMAT "%s\n", thisabbrev, - gmtoffs[tm], + utoffs[tm], isdsts[tm] ? "\tD" : ""); } } @@ -2425,14 +2456,14 @@ writezone(const char *const name, const char *const string, char version, if (thistimei >= thistimelim) { unsigned char tm = defaulttype; - char *thisabbrev = &thischars[indmap[abbrinds[tm]]]; + char *thisabbrev = &thischars[indmap[desigidx[tm]]]; /* filter out assorted junk entries */ if (strcmp(thisabbrev, GRANDPARENTED) != 0 && strcmp(thisabbrev, "zzz") != 0) fprintf(stdout, "%s\t" INT64_FORMAT "%s\n", thisabbrev, - gmtoffs[tm], + utoffs[tm], isdsts[tm] ? "\tD" : ""); } } @@ -2465,12 +2496,17 @@ writezone(const char *const name, const char *const string, char version, putc(currenttype, fp); for (i = old0; i < typecnt; i++) - if (!omittype[i]) + { + int h = (i == old0 ? thisdefaulttype + : i == thisdefaulttype ? old0 : i); + + if (!omittype[h]) { - puttzcode(gmtoffs[i], fp); - putc(isdsts[i], fp); - putc((unsigned char) indmap[abbrinds[i]], fp); + puttzcode(utoffs[h], fp); + putc(isdsts[h], fp); + putc(indmap[desigidx[h]], fp); } + } if (thischarcnt != 0) fwrite(thischars, sizeof thischars[0], thischarcnt, fp); @@ -2498,20 +2534,21 @@ writezone(const char *const name, const char *const string, char version, ++j; j = types[j - 1]; } - todo = tadd(trans[i], -gmtoffs[j]); + todo = tadd(trans[i], -utoffs[j]); } else todo = trans[i]; puttzcodepass(todo, fp, pass); puttzcode(corr[i], fp); } - for (i = old0; i < typecnt; i++) - if (!omittype[i]) - putc(ttisstds[i], fp); - for (i = old0; i < typecnt; i++) - if (!omittype[i]) - putc(ttisgmts[i], fp); - swaptypes(old0, thisdefaulttype); + if (stdcnt != 0) + for (i = old0; i < typecnt; i++) + if (!omittype[i]) + putc(ttisstds[i], fp); + if (utcnt != 0) + for (i = old0; i < typecnt; i++) + if (!omittype[i]) + putc(ttisuts[i], fp); } fprintf(fp, "\n%s\n", string); close_file(fp, directory, name); @@ -2564,7 +2601,7 @@ abbroffset(char *buf, zic_t offset) static size_t doabbr(char *abbr, struct zone const *zp, char const *letters, - bool isdst, zic_t stdoff, bool doquotes) + bool isdst, zic_t save, bool doquotes) { char *cp; char *slashp; @@ -2577,7 +2614,7 @@ doabbr(char *abbr, struct zone const *zp, char const *letters, char letterbuf[PERCENT_Z_LEN_BOUND + 1]; if (zp->z_format_specifier == 'z') - letters = abbroffset(letterbuf, zp->z_gmtoff + stdoff); + letters = abbroffset(letterbuf, zp->z_stdoff + save); else if (!letters) letters = "%s"; sprintf(abbr, format, letters); @@ -2649,8 +2686,7 @@ stringoffset(char *result, zic_t offset) } static int -stringrule(char *result, const struct rule *const rp, const zic_t dstoff, - const zic_t gmtoff) +stringrule(char *result, struct rule *const rp, zic_t save, zic_t stdoff) { zic_t tod = rp->r_tod; int compat = 0; @@ -2707,10 +2743,10 @@ stringrule(char *result, const struct rule *const rp, const zic_t dstoff, result += sprintf(result, "M%d.%d.%d", rp->r_month + 1, week, wday); } - if (rp->r_todisgmt) - tod += gmtoff; + if (rp->r_todisut) + tod += stdoff; if (rp->r_todisstd && !rp->r_isdst) - tod += dstoff; + tod += save; if (tod != 2 * SECSPERMIN * MINSPERHOUR) { *result++ = '/'; @@ -2744,10 +2780,6 @@ rule_cmp(struct rule const *a, struct rule const *b) return a->r_dayofmonth - b->r_dayofmonth; } -enum -{ -YEAR_BY_YEAR_ZONE = 1}; - static int stringzone(char *result, struct zone const *zpfirst, ptrdiff_t zonecount) { @@ -2813,15 +2845,6 @@ stringzone(char *result, struct zone const *zpfirst, ptrdiff_t zonecount) if (rule_cmp(stdrp, rp) < 0) stdrp = rp; } - - /* - * Horrid special case: if year is 2037, presume this is a zone - * handled on a year-by-year basis; do not try to apply a rule to the - * zone. - */ - if (stdrp != NULL && stdrp->r_hiyear == 2037) - return YEAR_BY_YEAR_ZONE; - if (stdrp != NULL && stdrp->r_isdst) { /* Perpetual DST. */ @@ -2829,17 +2852,17 @@ stringzone(char *result, struct zone const *zpfirst, ptrdiff_t zonecount) dstr.r_dycode = DC_DOM; dstr.r_dayofmonth = 1; dstr.r_tod = 0; - dstr.r_todisstd = dstr.r_todisgmt = false; + dstr.r_todisstd = dstr.r_todisut = false; dstr.r_isdst = stdrp->r_isdst; - dstr.r_stdoff = stdrp->r_stdoff; + dstr.r_save = stdrp->r_save; dstr.r_abbrvar = stdrp->r_abbrvar; stdr.r_month = TM_DECEMBER; stdr.r_dycode = DC_DOM; stdr.r_dayofmonth = 31; - stdr.r_tod = SECSPERDAY + stdrp->r_stdoff; - stdr.r_todisstd = stdr.r_todisgmt = false; + stdr.r_tod = SECSPERDAY + stdrp->r_save; + stdr.r_todisstd = stdr.r_todisut = false; stdr.r_isdst = false; - stdr.r_stdoff = 0; + stdr.r_save = 0; stdr.r_abbrvar = (stdabbrrp ? stdabbrrp->r_abbrvar : ""); dstrp = &dstr; @@ -2850,7 +2873,7 @@ stringzone(char *result, struct zone const *zpfirst, ptrdiff_t zonecount) return -1; abbrvar = (stdrp == NULL) ? "" : stdrp->r_abbrvar; len = doabbr(result, zp, abbrvar, false, 0, true); - offsetlen = stringoffset(result + len, -zp->z_gmtoff); + offsetlen = stringoffset(result + len, -zp->z_stdoff); if (!offsetlen) { result[0] = '\0'; @@ -2860,11 +2883,11 @@ stringzone(char *result, struct zone const *zpfirst, ptrdiff_t zonecount) if (dstrp == NULL) return compat; len += doabbr(result + len, zp, dstrp->r_abbrvar, - dstrp->r_isdst, dstrp->r_stdoff, true); - if (dstrp->r_stdoff != SECSPERMIN * MINSPERHOUR) + dstrp->r_isdst, dstrp->r_save, true); + if (dstrp->r_save != SECSPERMIN * MINSPERHOUR) { offsetlen = stringoffset(result + len, - -(zp->z_gmtoff + dstrp->r_stdoff)); + -(zp->z_stdoff + dstrp->r_save)); if (!offsetlen) { result[0] = '\0'; @@ -2873,7 +2896,7 @@ stringzone(char *result, struct zone const *zpfirst, ptrdiff_t zonecount) len += offsetlen; } result[len++] = ','; - c = stringrule(result + len, dstrp, dstrp->r_stdoff, zp->z_gmtoff); + c = stringrule(result + len, dstrp, dstrp->r_save, zp->z_stdoff); if (c < 0) { result[0] = '\0'; @@ -2883,7 +2906,7 @@ stringzone(char *result, struct zone const *zpfirst, ptrdiff_t zonecount) compat = c; len += strlen(result + len); result[len++] = ','; - c = stringrule(result + len, stdrp, dstrp->r_stdoff, zp->z_gmtoff); + c = stringrule(result + len, stdrp, dstrp->r_save, zp->z_stdoff); if (c < 0) { result[0] = '\0'; @@ -2905,12 +2928,12 @@ outzone(const struct zone *zpfirst, ptrdiff_t zonecount) useuntil; zic_t starttime, untiltime; - zic_t gmtoff; zic_t stdoff; + zic_t save; zic_t year; zic_t startoff; bool startttisstd; - bool startttisgmt; + bool startttisut; int type; char *startbuf; char *ab; @@ -2948,7 +2971,7 @@ outzone(const struct zone *zpfirst, ptrdiff_t zonecount) * startttisstd. */ startttisstd = false; - startttisgmt = false; + startttisut = false; min_year = max_year = EPOCH_YEAR; if (leapseen) { @@ -2977,14 +3000,14 @@ outzone(const struct zone *zpfirst, ptrdiff_t zonecount) */ compat = stringzone(envvar, zpfirst, zonecount); version = compat < 2013 ? ZIC_VERSION_PRE_2013 : ZIC_VERSION; - do_extend = compat < 0 || compat == YEAR_BY_YEAR_ZONE; + do_extend = compat < 0; if (noise) { if (!*envvar) warning("%s %s", _("no POSIX environment variable for zone"), zpfirst->z_name); - else if (compat != 0 && compat != YEAR_BY_YEAR_ZONE) + else if (compat != 0) { /* * Circa-COMPAT clients, and earlier clients, might not work for @@ -3033,37 +3056,43 @@ outzone(const struct zone *zpfirst, ptrdiff_t zonecount) max_year = min_year + years_of_observations; } } - - /* - * For the benefit of older systems, generate data from 1900 through 2038. - */ - if (min_year > 1900) - min_year = 1900; max_year0 = max_year; - if (max_year < 2038) - max_year = 2038; + if (want_bloat()) + { + /* + * For the benefit of older systems, generate data from 1900 through + * 2038. + */ + if (min_year > 1900) + min_year = 1900; + if (max_year < 2038) + max_year = 2038; + } + for (i = 0; i < zonecount; ++i) { + struct rule *prevrp = NULL; + /* * A guess that may well be corrected later. */ - stdoff = 0; + save = 0; zp = &zpfirst[i]; usestart = i > 0 && (zp - 1)->z_untiltime > min_time; useuntil = i < (zonecount - 1); if (useuntil && zp->z_untiltime <= min_time) continue; - gmtoff = zp->z_gmtoff; + stdoff = zp->z_stdoff; eat(zp->z_filename, zp->z_linenum); *startbuf = '\0'; - startoff = zp->z_gmtoff; + startoff = zp->z_stdoff; if (zp->z_nrules == 0) { - stdoff = zp->z_stdoff; - doabbr(startbuf, zp, NULL, zp->z_isdst, stdoff, false); - type = addtype(oadd(zp->z_gmtoff, stdoff), + save = zp->z_save; + doabbr(startbuf, zp, NULL, zp->z_isdst, save, false); + type = addtype(oadd(zp->z_stdoff, save), startbuf, zp->z_isdst, startttisstd, - startttisgmt); + startttisut); if (usestart) { addtt(starttime, type); @@ -3109,16 +3138,16 @@ outzone(const struct zone *zpfirst, ptrdiff_t zonecount) if (useuntil) { /* - * Turn untiltime into UT assuming the current gmtoff - * and stdoff values. + * Turn untiltime into UT assuming the current stdoff + * and save values. */ untiltime = zp->z_untiltime; - if (!zp->z_untilrule.r_todisgmt) + if (!zp->z_untilrule.r_todisut) untiltime = tadd(untiltime, - -gmtoff); + -stdoff); if (!zp->z_untilrule.r_todisstd) untiltime = tadd(untiltime, - -stdoff); + -save); } /* @@ -3133,9 +3162,9 @@ outzone(const struct zone *zpfirst, ptrdiff_t zonecount) continue; eats(zp->z_filename, zp->z_linenum, rp->r_filename, rp->r_linenum); - offset = rp->r_todisgmt ? 0 : gmtoff; + offset = rp->r_todisut ? 0 : stdoff; if (!rp->r_todisstd) - offset = oadd(offset, stdoff); + offset = oadd(offset, save); jtime = rp->r_temp; if (jtime == min_time || jtime == max_time) @@ -3166,41 +3195,46 @@ outzone(const struct zone *zpfirst, ptrdiff_t zonecount) rp->r_todo = false; if (useuntil && ktime >= untiltime) break; - stdoff = rp->r_stdoff; + save = rp->r_save; if (usestart && ktime == starttime) usestart = false; if (usestart) { if (ktime < starttime) { - startoff = oadd(zp->z_gmtoff, - stdoff); + startoff = oadd(zp->z_stdoff, + save); doabbr(startbuf, zp, rp->r_abbrvar, rp->r_isdst, - rp->r_stdoff, + rp->r_save, false); continue; } - if (*startbuf == '\0' && - startoff == oadd(zp->z_gmtoff, - stdoff)) + if (*startbuf == '\0' + && startoff == oadd(zp->z_stdoff, + save)) { doabbr(startbuf, zp, rp->r_abbrvar, rp->r_isdst, - rp->r_stdoff, + rp->r_save, false); } } eats(zp->z_filename, zp->z_linenum, rp->r_filename, rp->r_linenum); doabbr(ab, zp, rp->r_abbrvar, - rp->r_isdst, rp->r_stdoff, false); - offset = oadd(zp->z_gmtoff, rp->r_stdoff); + rp->r_isdst, rp->r_save, false); + offset = oadd(zp->z_stdoff, rp->r_save); + if (!want_bloat() && !useuntil && !do_extend + && prevrp + && rp->r_hiyear == ZIC_MAX + && prevrp->r_hiyear == ZIC_MAX) + break; type = addtype(offset, ab, rp->r_isdst, - rp->r_todisstd, rp->r_todisgmt); + rp->r_todisstd, rp->r_todisut); if (defaulttype < 0 && !rp->r_isdst) defaulttype = type; if (rp->r_hiyear == ZIC_MAX @@ -3208,6 +3242,7 @@ outzone(const struct zone *zpfirst, ptrdiff_t zonecount) && ktime < attypes[lastatmax].at)) lastatmax = timecnt; addtt(ktime, type); + prevrp = rp; } } if (usestart) @@ -3222,10 +3257,10 @@ outzone(const struct zone *zpfirst, ptrdiff_t zonecount) error(_("cannot determine time zone abbreviation to use just after until time")); else { - bool isdst = startoff != zp->z_gmtoff; + bool isdst = startoff != zp->z_stdoff; type = addtype(startoff, startbuf, isdst, - startttisstd, startttisgmt); + startttisstd, startttisut); if (defaulttype < 0 && !isdst) defaulttype = type; addtt(starttime, type); @@ -3238,12 +3273,12 @@ outzone(const struct zone *zpfirst, ptrdiff_t zonecount) if (useuntil) { startttisstd = zp->z_untilrule.r_todisstd; - startttisgmt = zp->z_untilrule.r_todisgmt; + startttisut = zp->z_untilrule.r_todisut; starttime = zp->z_untiltime; if (!startttisstd) + starttime = tadd(starttime, -save); + if (!startttisut) starttime = tadd(starttime, -stdoff); - if (!startttisgmt) - starttime = tadd(starttime, -gmtoff); } } if (defaulttype < 0) @@ -3295,22 +3330,31 @@ addtt(zic_t starttime, int type) } static int -addtype(zic_t gmtoff, char const *abbr, bool isdst, bool ttisstd, bool ttisgmt) +addtype(zic_t utoff, char const *abbr, bool isdst, bool ttisstd, bool ttisut) { int i, j; - /* - * See if there's already an entry for this zone type. If so, just return - * its index. - */ - for (i = 0; i < typecnt; ++i) + if (!(-1L - 2147483647L <= utoff && utoff <= 2147483647L)) + { + error(_("UT offset out of range")); + exit(EXIT_FAILURE); + } + if (!want_bloat()) + ttisstd = ttisut = false; + + for (j = 0; j < charcnt; ++j) + if (strcmp(&chars[j], abbr) == 0) + break; + if (j == charcnt) + newabbr(abbr); + else { - if (gmtoff == gmtoffs[i] && isdst == isdsts[i] && - strcmp(abbr, &chars[abbrinds[i]]) == 0 && - ttisstd == ttisstds[i] && - ttisgmt == ttisgmts[i]) - return i; + /* If there's already an entry, return its index. */ + for (i = 0; i < typecnt; i++) + if (utoff == utoffs[i] && isdst == isdsts[i] && j == desigidx[i] + && ttisstd == ttisstds[i] && ttisut == ttisuts[i]) + return i; } /* @@ -3321,23 +3365,12 @@ addtype(zic_t gmtoff, char const *abbr, bool isdst, bool ttisstd, bool ttisgmt) error(_("too many local time types")); exit(EXIT_FAILURE); } - if (!(-1L - 2147483647L <= gmtoff && gmtoff <= 2147483647L)) - { - error(_("UT offset out of range")); - exit(EXIT_FAILURE); - } - gmtoffs[i] = gmtoff; + i = typecnt++; + utoffs[i] = utoff; isdsts[i] = isdst; ttisstds[i] = ttisstd; - ttisgmts[i] = ttisgmt; - - for (j = 0; j < charcnt; ++j) - if (strcmp(&chars[j], abbr) == 0) - break; - if (j == charcnt) - newabbr(abbr); - abbrinds[i] = j; - ++typecnt; + ttisuts[i] = ttisut; + desigidx[i] = j; return i; } @@ -3671,9 +3704,9 @@ byword(const char *word, const struct lookup *table) return NULL; /* multiple inexact matches */ } - /* Warn about any backward-compatibility issue with pre-2017c zic. */ - if (foundlp) + if (foundlp && noise) { + /* Warn about any backward-compatibility issue with pre-2017c zic. */ bool pre_2017c_match = false; for (lp = table; lp->l_word; lp++) |