aboutsummaryrefslogtreecommitdiff
path: root/src/timezone/zic.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2019-07-17 18:26:23 -0400
committerTom Lane <tgl@sss.pgh.pa.us>2019-07-17 18:26:23 -0400
commit1d1ff50d27cf32e37c5294c34d84dd4225db99a9 (patch)
tree4ce4c3f381a2cabf32519ebb07a1b96342c1b988 /src/timezone/zic.c
parent46e2a18d0dfd140bfa36e5d543feeac5f5600244 (diff)
downloadpostgresql-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.c453
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++)