Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files. =================================================================== RCS file: /ftp/cvs/cvsroot/src/lib/libc/time/zic.c,v rcsdiff: /ftp/cvs/cvsroot/src/lib/libc/time/zic.c,v: warning: Unknown phrases like `commitid ...;' are present. retrieving revision 1.74 retrieving revision 1.75 diff -u -p -r1.74 -r1.75 --- src/lib/libc/time/zic.c 2019/04/04 18:18:31 1.74 +++ src/lib/libc/time/zic.c 2019/07/03 15:50:16 1.75 @@ -1,8 +1,9 @@ -/* $NetBSD: zic.c,v 1.74 2019/04/04 18:18:31 christos Exp $ */ +/* $NetBSD: zic.c,v 1.75 2019/07/03 15:50:16 christos Exp $ */ /* ** This file is in the public domain, so clarified as of ** 2006-07-17 by Arthur David Olson. */ +/* Compile .zi time zone data into TZif binary files. */ #if HAVE_NBTOOL_CONFIG_H #include "nbtool_config.h" @@ -10,7 +11,7 @@ #include #ifndef lint -__RCSID("$NetBSD: zic.c,v 1.74 2019/04/04 18:18:31 christos Exp $"); +__RCSID("$NetBSD: zic.c,v 1.75 2019/07/03 15:50:16 christos Exp $"); #endif /* !defined lint */ #include "private.h" @@ -101,13 +102,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) */ @@ -127,13 +125,13 @@ struct zone { lineno 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; @@ -171,7 +169,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); @@ -242,7 +240,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 @@ -256,7 +254,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 @@ -277,7 +275,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 @@ -418,11 +416,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]; @@ -584,8 +582,9 @@ usage(FILE *stream, int status) { fprintf(stream, _("%s: usage is %s [ --version ] [ --help ] [ -v ] \\\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, REPORT_BUGS_TO); @@ -660,6 +659,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) { @@ -691,10 +705,22 @@ main(int argc, char **argv) } else if (strcmp(argv[k], "--help") == 0) { usage(stdout, EXIT_SUCCESS); } - while ((c = getopt(argc, argv, "d:l:L:p:r:st:vy:")) != EOF && c != -1) + while ((c = getopt(argc, argv, "b:d:l:L:p:r: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 = optarg; @@ -780,6 +806,8 @@ _("%s: invalid time range: %s\n"), } 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 = TZDIR; if (tzdefault == NULL) @@ -1078,8 +1106,7 @@ associate(void) { struct zone * zp; struct rule * rp; - ptrdiff_t base, out; - int i, j; + ptrdiff_t i, j, base, out; if (nrules != 0) { qsort(rules, (size_t)nrules, sizeof *rules, rcomp); @@ -1134,7 +1161,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 a bad thing. @@ -1292,10 +1319,10 @@ warning(_("values over 24 hours not hand } 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) { char *ep = field + fieldlen - 1; @@ -1304,9 +1331,9 @@ getstdoff(char *field, bool *isdst) case 's': dst = 0; *ep = '\0'; 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 @@ -1329,7 +1356,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]); @@ -1390,13 +1417,13 @@ inzsub(char **fields, int nfields, bool char * cp; char * cp1; static struct zone z; - int i_gmtoff, i_rule, i_format; + int i_stdoff, i_rule, i_format; int i_untilyear, i_untilmonth; int i_untilday, i_untiltime; bool hasuntil; if (iscont) { - i_gmtoff = ZFC_GMTOFF; + i_stdoff = ZFC_STDOFF; i_rule = ZFC_RULE; i_format = ZFC_FORMAT; i_untilyear = ZFC_TILYEAR; @@ -1407,7 +1434,7 @@ inzsub(char **fields, int nfields, bool } else if (!namecheck(fields[ZF_NAME])) return false; else { - i_gmtoff = ZF_GMTOFF; + i_stdoff = ZF_STDOFF; i_rule = ZF_RULE; i_format = ZF_FORMAT; i_untilyear = ZF_TILYEAR; @@ -1418,7 +1445,7 @@ inzsub(char **fields, int nfields, bool } 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], '%')) != 0) { if ((*++cp != 's' && *cp != 'z') || strchr(cp, '%') || strchr(fields[i_format], '/')) { @@ -1611,26 +1638,26 @@ rulesub(struct rule *rp, const char *loy } rp->r_month = lp->l_value; rp->r_todisstd = false; - rp->r_todisgmt = false; + rp->r_todisut = false; dp = ecpyalloc(timep); if (*dp != '\0') { ep = dp + strlen(dp) - 1; switch (lowerit(*ep)) { 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; } @@ -1797,17 +1824,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; ptrdiff_t base, count; @@ -1874,17 +1890,24 @@ writezone(const char *const name, const toi = 0; 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; continue; } 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; @@ -1927,7 +1950,7 @@ writezone(const char *const name, const 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 + if (WORK_AROUND_QTBUG_53071 && timecnt != 0 && want_bloat() && ats[timecnt - 1] < y2038_boundary - 1 && strchr(string, '<')) { ats[timecnt] = y2038_boundary - 1; types[timecnt] = types[timecnt - 1]; @@ -1976,7 +1999,7 @@ writezone(const char *const name, const 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; @@ -2048,7 +2071,6 @@ writezone(const char *const name, const THISDEFAULTTYPE appears as type 0 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 /* @@ -2059,7 +2081,7 @@ writezone(const char *const name, const ** (to help get global "altzone" and "timezone" variables ** set correctly). */ - { + if (want_bloat()) { int mrudst, mrustd, hidst, histd, type; hidst = histd = mrudst = mrustd = -1; @@ -2067,33 +2089,37 @@ writezone(const char *const name, const if (isdsts[types[i]]) mrudst = types[i]; else mrustd = types[i]; - for (i = old0; i < typecnt; i++) - if (!omittype[i]) { - if (isdsts[i]) - hidst = i; - else histd = i; - } + for (i = old0; i < typecnt; i++) { + int h = (i == old0 ? thisdefaulttype + : i == thisdefaulttype ? old0 : i); + if (!omittype[h]) { + 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] = true; + omittype[type] = false; } } #endif /* !defined LEAVE_SOME_PRE_2011_SYSTEMS_IN_THE_LURCH */ @@ -2106,15 +2132,19 @@ writezone(const char *const name, const for (i = 0; i < (int)(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; @@ -2122,14 +2152,20 @@ writezone(const char *const name, const 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, (size_t) 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); @@ -2137,13 +2173,22 @@ writezone(const char *const name, const 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; + } + /* Output a LO_TIME transition if needed; see limitrange. But do not go below the minimum representable value for this pass. */ @@ -2167,12 +2212,15 @@ writezone(const char *const name, const if (hicut) putc(currenttype, fp); - for (i = old0; i < typecnt; i++) - if (!omittype[i]) { - puttzcode(gmtoffs[i], fp); - putc(isdsts[i], fp); - putc((unsigned char) indmap[abbrinds[i]], fp); - } + for (i = old0; i < typecnt; i++) { + int h = (i == old0 ? thisdefaulttype + : i == thisdefaulttype ? old0 : i); + if (!omittype[h]) { + puttzcode(utoffs[h], fp); + putc(isdsts[h], fp); + putc(indmap[desigidx[h]], fp); + } + } if (thischarcnt != 0) fwrite(thischars, sizeof thischars[0], (size_t) thischarcnt, fp); @@ -2194,18 +2242,19 @@ writezone(const char *const name, const ++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 (stdcnt != 0) + for (i = old0; i < typecnt; i++) if (!omittype[i]) putc(ttisstds[i], fp); - for (i = old0; i < typecnt; i++) + if (utcnt != 0) + for (i = old0; i < typecnt; i++) if (!omittype[i]) - putc(ttisgmts[i], fp); - swaptypes(old0, thisdefaulttype); + putc(ttisuts[i], fp); } fprintf(fp, "\n%s\n", string); close_file(fp, directory, name); @@ -2250,7 +2299,7 @@ abbroffset(char *buf, zic_t offset) static size_t doabbr(char *abbr, int abbrlen, struct zone const *zp, const char *letters, - bool isdst, zic_t stdoff, bool doquotes) + bool isdst, zic_t save, bool doquotes) { char * cp; char * slashp; @@ -2261,7 +2310,7 @@ doabbr(char *abbr, int abbrlen, struct z if (slashp == NULL) { 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"; snprintf(abbr, abbrlen, format, letters); @@ -2326,8 +2375,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, const zic_t stdoff) { zic_t tod = rp->r_tod; int compat = 0; @@ -2374,10 +2422,10 @@ stringrule(char *result, const struct ru 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++ = '/'; if (! stringoffset(result, tod)) @@ -2407,10 +2455,8 @@ rule_cmp(struct rule const *a, struct ru return a->r_dayofmonth - b->r_dayofmonth; } -enum { YEAR_BY_YEAR_ZONE = 1 }; - static int -stringzone(char *result, const int resultlen, const struct zone *const zpfirst, +stringzone(char *result, int resultlen, const struct zone *const zpfirst, const int zonecount) { const struct zone * zp; @@ -2464,31 +2510,23 @@ stringzone(char *result, const int resul 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. */ dstr.r_month = TM_JANUARY; 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; @@ -2499,7 +2537,7 @@ stringzone(char *result, const int resul return -1; abbrvar = (stdrp == NULL) ? "" : stdrp->r_abbrvar; len = doabbr(result, resultlen, zp, abbrvar, false, 0, true); - offsetlen = stringoffset(result + len, -zp->z_gmtoff); + offsetlen = stringoffset(result + len, -zp->z_stdoff); if (! offsetlen) { result[0] = '\0'; return -1; @@ -2508,10 +2546,10 @@ stringzone(char *result, const int resul if (dstrp == NULL) return compat; len += doabbr(result + len, resultlen - 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'; return -1; @@ -2519,7 +2557,7 @@ stringzone(char *result, const int resul 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'; return -1; @@ -2528,7 +2566,7 @@ stringzone(char *result, const int resul 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'; return -1; @@ -2546,12 +2584,12 @@ outzone(const struct zone *zpfirst, ptrd ptrdiff_t i, j; bool usestart, 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; @@ -2561,7 +2599,7 @@ outzone(const struct zone *zpfirst, ptrd bool prodstic; /* all rules are min to max */ int compat; bool do_extend; - int version; + char version; ptrdiff_t lastatmax = -1; zic_t one = 1; zic_t y2038_boundary = one << 31; @@ -2587,7 +2625,7 @@ outzone(const struct zone *zpfirst, ptrd ** for noting the need to unconditionally initialize startttisstd. */ startttisstd = false; - startttisgmt = false; + startttisut = false; min_year = max_year = EPOCH_YEAR; if (leapseen) { updateminmax(leapminyear); @@ -2612,13 +2650,13 @@ outzone(const struct zone *zpfirst, ptrd */ compat = stringzone(envvar, max_envvar_len + 1, 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 this zone when given dates before 1970 or after 2038. */ @@ -2660,36 +2698,38 @@ outzone(const struct zone *zpfirst, ptrd 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) + 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, max_abbr_len + 1, zp, - NULL, zp->z_isdst, stdoff, false); - type = addtype(oadd(zp->z_gmtoff, stdoff), + save = zp->z_save; + doabbr(startbuf, max_abbr_len + 1, + 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); usestart = false; @@ -2725,16 +2765,16 @@ outzone(const struct zone *zpfirst, ptrd if (useuntil) { /* ** Turn untiltime into UT - ** assuming the current gmtoff and - ** stdoff values. + ** 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); } /* ** Find the rule (of those to do, if any) @@ -2747,9 +2787,9 @@ outzone(const struct zone *zpfirst, ptrd 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) @@ -2776,41 +2816,46 @@ outzone(const struct zone *zpfirst, ptrd 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, max_abbr_len + 1, 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, max_abbr_len + 1, 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, max_abbr_len + 1, 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 @@ -2818,6 +2863,7 @@ outzone(const struct zone *zpfirst, ptrd && ktime < attypes[lastatmax].at)) lastatmax = timecnt; addtt(ktime, type); + prevrp = rp; } } if (usestart) { @@ -2831,9 +2877,9 @@ outzone(const struct zone *zpfirst, ptrd if (*startbuf == '\0') error(_("can't 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); @@ -2844,12 +2890,12 @@ error(_("can't determine time zone abbre */ 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, -stdoff); - if (!startttisgmt) - starttime = tadd(starttime, -gmtoff); + starttime = tadd(starttime, -save); + if (!startttisut) + starttime = tadd(starttime, -stdoff); } } if (defaulttype < 0) @@ -2900,20 +2946,28 @@ 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 (gmtoff == gmtoffs[i] && isdst == isdsts[i] && - strcmp(abbr, &chars[abbrinds[i]]) == 0 && - ttisstd == ttisstds[i] && - ttisgmt == ttisgmts[i]) - return 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 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; } /* ** There isn't one; add a new one, unless there are already too @@ -2923,22 +2977,12 @@ addtype(zic_t gmtoff, char const *abbr, 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; } @@ -3159,8 +3203,8 @@ byword(const char *word, const struct lo else 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++) if (itsabbr(word, lp->l_word)) {