summaryrefslogtreecommitdiff
path: root/tz/zic.c
diff options
context:
space:
mode:
Diffstat (limited to 'tz/zic.c')
-rw-r--r--tz/zic.c410
1 files changed, 227 insertions, 183 deletions
diff --git a/tz/zic.c b/tz/zic.c
index 4bafe5d..8bf5628 100644
--- a/tz/zic.c
+++ b/tz/zic.c
@@ -92,13 +92,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) */
@@ -118,13 +115,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;
@@ -162,7 +159,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);
@@ -233,7 +230,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
@@ -247,7 +244,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
@@ -268,7 +265,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
@@ -409,11 +406,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];
@@ -574,8 +571,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);
@@ -650,6 +648,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)
{
@@ -681,10 +694,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;
@@ -770,6 +795,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)
@@ -1123,7 +1150,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.
@@ -1281,10 +1308,10 @@ warning(_("values over 24 hours not handled by pre-2007 versions of zic"));
}
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;
@@ -1293,9 +1320,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
@@ -1318,7 +1345,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]);
@@ -1379,13 +1406,13 @@ inzsub(char **fields, int nfields, bool iscont)
register char * cp;
char * cp1;
static struct zone z;
- register int i_gmtoff, i_rule, i_format;
+ register int i_stdoff, i_rule, i_format;
register int i_untilyear, i_untilmonth;
register int i_untilday, i_untiltime;
register bool hasuntil;
if (iscont) {
- i_gmtoff = ZFC_GMTOFF;
+ i_stdoff = ZFC_STDOFF;
i_rule = ZFC_RULE;
i_format = ZFC_FORMAT;
i_untilyear = ZFC_TILYEAR;
@@ -1396,7 +1423,7 @@ inzsub(char **fields, int nfields, bool iscont)
} 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;
@@ -1407,7 +1434,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], '%')) != 0) {
if ((*++cp != 's' && *cp != 'z') || strchr(cp, '%')
|| strchr(fields[i_format], '/')) {
@@ -1600,26 +1627,26 @@ 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') {
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;
}
@@ -1786,17 +1813,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;
@@ -1863,17 +1879,24 @@ writezone(const char *const name, const char *const string, char version,
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;
@@ -1916,7 +1939,7 @@ writezone(const char *const name, const char *const string, char version,
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];
@@ -1965,7 +1988,7 @@ writezone(const char *const name, const char *const string, char version,
int old0;
char omittype[TZ_MAX_TYPES];
int typemap[TZ_MAX_TYPES];
- register int thistypecnt;
+ int thistypecnt, stdcnt, utcnt;
char thischars[TZ_MAX_CHARS];
int thischarcnt;
bool toomanytimes;
@@ -2037,7 +2060,6 @@ writezone(const char *const name, const char *const string, char version,
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
/*
@@ -2048,7 +2070,7 @@ writezone(const char *const name, const char *const string, char version,
** (to help get global "altzone" and "timezone" variables
** set correctly).
*/
- {
+ if (want_bloat()) {
register int mrudst, mrustd, hidst, histd, type;
hidst = histd = mrudst = mrustd = -1;
@@ -2056,31 +2078,35 @@ writezone(const char *const name, const char *const string, char version,
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] = false;
}
@@ -2095,15 +2121,19 @@ 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++) {
register 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;
@@ -2111,14 +2141,20 @@ 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);
@@ -2126,13 +2162,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;
+ }
+
/* Output a LO_TIME transition if needed; see limitrange.
But do not go below the minimum representable value
for this pass. */
@@ -2156,12 +2201,15 @@ writezone(const char *const name, const char *const string, char version,
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],
thischarcnt, fp);
@@ -2183,18 +2231,19 @@ 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 (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);
@@ -2239,7 +2288,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)
{
register char * cp;
register char * slashp;
@@ -2250,7 +2299,7 @@ doabbr(char *abbr, struct zone const *zp, char const *letters,
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";
sprintf(abbr, format, letters);
@@ -2315,8 +2364,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)
{
register zic_t tod = rp->r_tod;
register int compat = 0;
@@ -2363,10 +2411,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++ = '/';
if (! stringoffset(result, tod))
@@ -2396,8 +2444,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)
{
@@ -2452,31 +2498,23 @@ 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. */
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;
@@ -2487,7 +2525,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';
return -1;
@@ -2496,10 +2534,10 @@ 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';
return -1;
@@ -2507,7 +2545,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';
return -1;
@@ -2516,7 +2554,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';
return -1;
@@ -2534,12 +2572,12 @@ outzone(const struct zone *zpfirst, ptrdiff_t zonecount)
register ptrdiff_t i, j;
register bool usestart, useuntil;
register zic_t starttime, untiltime;
- register zic_t gmtoff;
register zic_t stdoff;
+ register zic_t save;
register zic_t year;
register zic_t startoff;
register bool startttisstd;
- register bool startttisgmt;
+ register bool startttisut;
register int type;
register char * startbuf;
register char * ab;
@@ -2575,7 +2613,7 @@ outzone(const struct zone *zpfirst, ptrdiff_t zonecount)
** for noting the need to unconditionally initialize startttisstd.
*/
startttisstd = false;
- startttisgmt = false;
+ startttisut = false;
min_year = max_year = EPOCH_YEAR;
if (leapseen) {
updateminmax(leapminyear);
@@ -2600,13 +2638,13 @@ 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 this zone when given dates before
1970 or after 2038. */
@@ -2648,35 +2686,37 @@ 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)
+ 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);
usestart = false;
@@ -2712,16 +2752,16 @@ outzone(const struct zone *zpfirst, ptrdiff_t zonecount)
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)
@@ -2734,9 +2774,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)
@@ -2763,38 +2803,43 @@ 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
@@ -2802,6 +2847,7 @@ outzone(const struct zone *zpfirst, ptrdiff_t zonecount)
&& ktime < attypes[lastatmax].at))
lastatmax = timecnt;
addtt(ktime, type);
+ prevrp = rp;
}
}
if (usestart) {
@@ -2814,9 +2860,9 @@ outzone(const struct zone *zpfirst, ptrdiff_t zonecount)
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);
@@ -2827,12 +2873,12 @@ error(_("can't determine time zone abbreviation to use just after until time"));
*/
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)
@@ -2882,20 +2928,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)
{
register 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
@@ -2905,22 +2959,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;
}
@@ -3140,8 +3184,8 @@ byword(const char *word, const struct lookup *table)
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)) {