summaryrefslogtreecommitdiff
path: root/src/timezone/zic.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/timezone/zic.c')
-rw-r--r--src/timezone/zic.c330
1 files changed, 181 insertions, 149 deletions
diff --git a/src/timezone/zic.c b/src/timezone/zic.c
index 66c56829257..ae61264364c 100644
--- a/src/timezone/zic.c
+++ b/src/timezone/zic.c
@@ -1,3 +1,5 @@
+/* Compile .zi time zone data into TZif binary files. */
+
/*
* This file is in the public domain, so clarified as of
* 2006-07-17 by Arthur David Olson.
@@ -130,8 +132,7 @@ static void adjleap(void);
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,
- bool);
+static zic_t gethms(const char *string, const char *errstring);
static zic_t getstdoff(char *, bool *);
static void infile(const char *filename);
static void inleap(char **fields, int nfields);
@@ -162,7 +163,7 @@ enum
PERCENT_Z_LEN_BOUND = sizeof "+995959" - 1};
/* If true, work around a bug in Qt 5.6.1 and earlier, which mishandles
- tz binary files whose POSIX-TZ-style strings contain '<'; see
+ TZif files whose POSIX-TZ-style strings contain '<'; see
QTBUG-53071 <https://bugreports.qt.io/browse/QTBUG-53071>. This
workaround will no longer be needed when Qt 5.6.1 and earlier are
obsolete, say in the year 2021. */
@@ -211,7 +212,7 @@ static int typecnt;
#define ZF_RULE 3
#define ZF_FORMAT 4
#define ZF_TILYEAR 5
-#define ZF_TILMONTH 6
+#define ZF_TILMONTH 6
#define ZF_TILDAY 7
#define ZF_TILTIME 8
#define ZONE_MINFIELDS 5
@@ -224,12 +225,12 @@ static int typecnt;
#define ZFC_GMTOFF 0
#define ZFC_RULE 1
#define ZFC_FORMAT 2
-#define ZFC_TILYEAR 3
+#define ZFC_TILYEAR 3
#define ZFC_TILMONTH 4
#define ZFC_TILDAY 5
-#define ZFC_TILTIME 6
-#define ZONEC_MINFIELDS 3
-#define ZONEC_MAXFIELDS 7
+#define ZFC_TILTIME 6
+#define ZONEC_MINFIELDS 3
+#define ZONEC_MAXFIELDS 7
/*
* Which files are which on a Rule line.
@@ -244,7 +245,7 @@ static int typecnt;
#define RF_TOD 7
#define RF_STDOFF 8
#define RF_ABBRVAR 9
-#define RULE_FIELDS 10
+#define RULE_FIELDS 10
/*
* Which fields are which on a Link line.
@@ -252,7 +253,7 @@ static int typecnt;
#define LF_FROM 1
#define LF_TO 2
-#define LINK_FIELDS 3
+#define LINK_FIELDS 3
/*
* Which fields are which on a Leap line.
@@ -264,7 +265,7 @@ static int typecnt;
#define LP_TIME 4
#define LP_CORR 5
#define LP_ROLL 6
-#define LEAP_FIELDS 7
+#define LEAP_FIELDS 7
/*
* Year synonyms.
@@ -998,48 +999,6 @@ dolink(char const *fromfield, char const *tofield, bool staysymlink)
static zic_t const min_time = MINVAL(zic_t, TIME_T_BITS_IN_FILE);
static zic_t const max_time = MAXVAL(zic_t, TIME_T_BITS_IN_FILE);
-/*
- * Estimated time of the Big Bang, in seconds since the POSIX epoch.
- * rounded downward to the negation of a power of two that is
- * comfortably outside the error bounds.
- *
- * For the time of the Big Bang, see:
- *
- * Ade PAR, Aghanim N, Armitage-Caplan C et al. Planck 2013 results.
- * I. Overview of products and scientific results.
- * arXiv:1303.5062 2013-03-20 20:10:01 UTC
- * <https://arxiv.org/pdf/1303.5062v1> [PDF]
- *
- * Page 36, Table 9, row Age/Gyr, column Planck+WP+highL+BAO 68% limits
- * gives the value 13.798 plus-or-minus 0.037 billion years.
- * Multiplying this by 1000000000 and then by 31557600 (the number of
- * seconds in an astronomical year) gives a value that is comfortably
- * less than 2**59, so BIG_BANG is - 2**59.
- *
- * BIG_BANG is approximate, and may change in future versions.
- * Please do not rely on its exact value.
- */
-
-#ifndef BIG_BANG
-#define BIG_BANG (- (((zic_t) 1) << 59))
-#endif
-
-/* If true, work around GNOME bug 730332
- <https://bugzilla.gnome.org/show_bug.cgi?id=730332>
- by refusing to output time stamps before BIG_BANG.
- Such time stamps are physically suspect anyway.
-
- The GNOME bug is scheduled to be fixed in GNOME 3.22, and if so
- this workaround will no longer be needed when GNOME 3.21 and
- earlier are obsolete, say in the year 2021. */
-enum
-{
-WORK_AROUND_GNOME_BUG_730332 = true};
-
-static const zic_t early_time = (WORK_AROUND_GNOME_BUG_730332
- ? BIG_BANG
- : MINVAL(zic_t, TIME_T_BITS_IN_FILE));
-
/* Return true if NAME is a directory. */
static bool
itsdir(char const *name)
@@ -1281,8 +1240,9 @@ infile(const char *name)
* A null string maps to zero.
* Call error with errstring and return zero on errors.
*/
+
static zic_t
-gethms(char const *string, char const *errstring, bool signable)
+gethms(char const *string, char const *errstring)
{
/* PG: make hh be int not zic_t to avoid sscanf portability issues */
int hh;
@@ -1299,9 +1259,7 @@ gethms(char const *string, char const *errstring, bool signable)
if (string == NULL || *string == '\0')
return 0;
- if (!signable)
- sign = 1;
- else if (*string == '-')
+ if (*string == '-')
{
sign = -1;
++string;
@@ -1384,7 +1342,7 @@ getstdoff(char *field, bool *isdst)
break;
}
}
- stdoff = gethms(field, _("invalid saved time"), true);
+ stdoff = gethms(field, _("invalid saved time"));
*isdst = dst < 0 ? stdoff != 0 : dst;
return stdoff;
}
@@ -1399,10 +1357,29 @@ inrule(char **fields, int nfields)
error(_("wrong number of fields on Rule line"));
return;
}
- if (*fields[RF_NAME] == '\0')
+ switch (*fields[RF_NAME])
{
- error(_("nameless rule"));
- return;
+ case '\0':
+ case ' ':
+ case '\f':
+ case '\n':
+ case '\r':
+ case '\t':
+ case '\v':
+ case '+':
+ case '-':
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ error(_("Invalid rule name \"%s\""), fields[RF_NAME]);
+ return;
}
r.r_filename = filename;
r.r_linenum = linenum;
@@ -1507,7 +1484,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"), true);
+ z.z_gmtoff = gethms(fields[i_gmtoff], _("invalid UT offset"));
if ((cp = strchr(fields[i_format], '%')) != NULL)
{
if ((*++cp != 's' && *cp != 'z') || strchr(cp, '%')
@@ -1649,7 +1626,7 @@ inleap(char **fields, int nfields)
return;
}
t = dayoff * SECSPERDAY;
- tod = gethms(fields[LP_TIME], _("invalid time of day"), false);
+ tod = gethms(fields[LP_TIME], _("invalid time of day"));
cp = fields[LP_CORR];
{
bool positive;
@@ -1757,7 +1734,7 @@ rulesub(struct rule *rp, const char *loyearp, const char *hiyearp,
break;
}
}
- rp->r_tod = gethms(dp, _("invalid time of day"), false);
+ rp->r_tod = gethms(dp, _("invalid time of day"));
free(dp);
/*
@@ -1942,7 +1919,43 @@ is32(const zic_t x)
}
static void
-writezone(const char *const name, const char *const string, char version)
+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;
+ }
+}
+
+static void
+writezone(const char *const name, const char *const string, char version,
+ int defaulttype)
{
FILE *fp;
ptrdiff_t i,
@@ -1977,14 +1990,12 @@ writezone(const char *const name, const char *const string, char version)
toi = 0;
fromi = 0;
- while (fromi < timecnt && attypes[fromi].at < early_time)
- ++fromi;
for (; fromi < timecnt; ++fromi)
{
- if (toi > 1 && ((attypes[fromi].at +
- gmtoffs[attypes[toi - 1].type]) <=
- (attypes[toi - 1].at +
- gmtoffs[attypes[toi - 2].type])))
+ if (toi != 0 && ((attypes[fromi].at +
+ gmtoffs[attypes[toi - 1].type]) <=
+ (attypes[toi - 1].at + gmtoffs[toi == 1 ? 0
+ : attypes[toi - 2].type])))
{
attypes[toi - 1].type =
attypes[fromi].type;
@@ -2019,8 +2030,8 @@ writezone(const char *const name, const char *const string, char version)
}
/*
- * Work around QTBUG-53071 for time stamps less than y2038_boundary - 1,
- * by inserting a no-op transition at time y2038_boundary - 1. This works
+ * Work around QTBUG-53071 for timestamps less than y2038_boundary - 1, by
+ * inserting a no-op transition at time y2038_boundary - 1. This works
* only for timestamps before the boundary, which should be good enough in
* practice as QTBUG-53071 should be long-dead by 2038.
*/
@@ -2116,7 +2127,8 @@ writezone(const char *const name, const char *const string, char version)
int thisleapi,
thisleapcnt,
thisleaplim;
- int writetype[TZ_MAX_TYPES];
+ int old0;
+ char omittype[TZ_MAX_TYPES];
int typemap[TZ_MAX_TYPES];
int thistypecnt;
char thischars[TZ_MAX_CHARS];
@@ -2144,28 +2156,19 @@ writezone(const char *const name, const char *const string, char version)
error(_("too many transition times"));
thistimelim = thistimei + thistimecnt;
thisleaplim = thisleapi + thisleapcnt;
- for (i = 0; i < typecnt; ++i)
- writetype[i] = thistimecnt == timecnt;
- if (thistimecnt == 0)
- {
- /*
- * No transition times fall in the current (32- or 64-bit) window.
- */
- if (typecnt != 0)
- writetype[typecnt - 1] = true;
- }
- else
- {
- for (i = thistimei - 1; i < thistimelim; ++i)
- if (i >= 0)
- writetype[types[i]] = true;
+ memset(omittype, true, typecnt);
+ omittype[defaulttype] = false;
+ for (i = thistimei; i < thistimelim; i++)
+ omittype[types[i]] = false;
+
+ /*
+ * Reorder types to make DEFAULTTYPE type 0. Use TYPEMAP to swap OLD0
+ * and DEFAULTTYPE so that DEFAULTTYPE appears as type 0 in the output
+ * instead of OLD0. TYPEMAP also omits unused types.
+ */
+ old0 = strlen(omittype);
+ swaptypes(old0, defaulttype);
- /*
- * For America/Godthab and Antarctica/Palmer
- */
- if (thistimei == 0)
- writetype[0] = true;
- }
#ifndef LEAVE_SOME_PRE_2011_SYSTEMS_IN_THE_LURCH
/*
@@ -2187,8 +2190,8 @@ writezone(const char *const name, const char *const string, char version)
mrudst = types[i];
else
mrustd = types[i];
- for (i = 0; i < typecnt; ++i)
- if (writetype[i])
+ for (i = old0; i < typecnt; i++)
+ if (!omittype[i])
{
if (isdsts[i])
hidst = i;
@@ -2205,7 +2208,7 @@ writezone(const char *const name, const char *const string, char version)
ttisstds[mrudst],
ttisgmts[mrudst]);
isdsts[mrudst] = 1;
- writetype[type] = true;
+ omittype[type] = false;
}
if (histd >= 0 && mrustd >= 0 && histd != mrustd &&
gmtoffs[histd] != gmtoffs[mrustd])
@@ -2217,22 +2220,26 @@ writezone(const char *const name, const char *const string, char version)
ttisstds[mrustd],
ttisgmts[mrustd]);
isdsts[mrustd] = 0;
- writetype[type] = true;
+ omittype[type] = false;
}
}
#endif /* !defined
* LEAVE_SOME_PRE_2011_SYSTEMS_IN_THE_LURCH */
thistypecnt = 0;
- for (i = 0; i < typecnt; ++i)
- typemap[i] = writetype[i] ? thistypecnt++ : -1;
+ for (i = old0; i < typecnt; i++)
+ if (!omittype[i])
+ typemap[i == old0 ? defaulttype
+ : i == defaulttype ? old0 : i]
+ = thistypecnt++;
+
for (i = 0; i < sizeof indmap / sizeof indmap[0]; ++i)
indmap[i] = -1;
thischarcnt = 0;
- for (i = 0; i < typecnt; ++i)
+ for (i = old0; i < typecnt; i++)
{
char *thisabbr;
- if (!writetype[i])
+ if (omittype[i])
continue;
if (indmap[abbrinds[i]] >= 0)
continue;
@@ -2267,23 +2274,16 @@ writezone(const char *const name, const char *const string, char version)
DO(tzh_typecnt);
DO(tzh_charcnt);
#undef DO
- for (i = thistimei; i < thistimelim; ++i)
- if (pass == 1)
- /*
- * Output an INT32_MIN "transition" if appropriate; see above.
- */
- puttzcode(((ats[i] < PG_INT32_MIN) ?
- PG_INT32_MIN : ats[i]), fp);
- else
+ /* PG: print current timezone abbreviations if requested */
+ if (print_abbrevs && pass == 2)
+ {
+ /* Print "type" data for periods ending after print_cutoff */
+ for (i = thistimei; i < thistimelim; ++i)
{
- puttzcode64(ats[i], fp);
-
- /* Print current timezone abbreviations if requested */
- if (print_abbrevs &&
- (i == thistimelim - 1 || ats[i + 1] > print_cutoff))
+ if (i == thistimelim - 1 || ats[i + 1] > print_cutoff)
{
- unsigned char tm = typemap[types[i]];
+ unsigned char tm = types[i];
char *thisabbrev = &thischars[indmap[abbrinds[tm]]];
/* filter out assorted junk entries */
@@ -2295,6 +2295,32 @@ writezone(const char *const name, const char *const string, char version)
isdsts[tm] ? "\tD" : "");
}
}
+ /* Print the default type if we have no transitions at all */
+ if (thistimei >= thistimelim)
+ {
+ unsigned char tm = defaulttype;
+ char *thisabbrev = &thischars[indmap[abbrinds[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],
+ isdsts[tm] ? "\tD" : "");
+ }
+ }
+
+ for (i = thistimei; i < thistimelim; ++i)
+ if (pass == 1)
+
+ /*
+ * Output an INT32_MIN "transition" if appropriate; see above.
+ */
+ puttzcode(((ats[i] < PG_INT32_MIN) ?
+ PG_INT32_MIN : ats[i]), fp);
+ else
+ puttzcode64(ats[i], fp);
for (i = thistimei; i < thistimelim; ++i)
{
unsigned char uc;
@@ -2302,8 +2328,8 @@ writezone(const char *const name, const char *const string, char version)
uc = typemap[types[i]];
fwrite(&uc, sizeof uc, 1, fp);
}
- for (i = 0; i < typecnt; ++i)
- if (writetype[i])
+ for (i = old0; i < typecnt; i++)
+ if (!omittype[i])
{
puttzcode(gmtoffs[i], fp);
putc(isdsts[i], fp);
@@ -2346,12 +2372,13 @@ writezone(const char *const name, const char *const string, char version)
puttzcode64(todo, fp);
puttzcode(corr[i], fp);
}
- for (i = 0; i < typecnt; ++i)
- if (writetype[i])
+ for (i = old0; i < typecnt; i++)
+ if (!omittype[i])
putc(ttisstds[i], fp);
- for (i = 0; i < typecnt; ++i)
- if (writetype[i])
+ for (i = old0; i < typecnt; i++)
+ if (!omittype[i])
putc(ttisgmts[i], fp);
+ swaptypes(old0, defaulttype);
}
fprintf(fp, "\n%s\n", string);
close_file(fp, directory, name);
@@ -2757,6 +2784,7 @@ outzone(const struct zone *zpfirst, ptrdiff_t zonecount)
zic_t one = 1;
zic_t y2038_boundary = one << 31;
zic_t max_year0;
+ int defaulttype = -1;
max_abbr_len = 2 + max_format_len + max_abbrvar_len;
max_envvar_len = 2 * max_abbr_len + 5 * 9;
@@ -2880,9 +2908,9 @@ outzone(const struct zone *zpfirst, ptrdiff_t zonecount)
*/
stdoff = 0;
zp = &zpfirst[i];
- usestart = i > 0 && (zp - 1)->z_untiltime > early_time;
+ usestart = i > 0 && (zp - 1)->z_untiltime > min_time;
useuntil = i < (zonecount - 1);
- if (useuntil && zp->z_untiltime <= early_time)
+ if (useuntil && zp->z_untiltime <= min_time)
continue;
gmtoff = zp->z_gmtoff;
eat(zp->z_filename, zp->z_linenum);
@@ -2901,7 +2929,7 @@ outzone(const struct zone *zpfirst, ptrdiff_t zonecount)
usestart = false;
}
else
- addtt(early_time, type);
+ defaulttype = type;
}
else
for (year = min_year; year <= max_year; ++year)
@@ -3032,6 +3060,8 @@ outzone(const struct zone *zpfirst, ptrdiff_t zonecount)
offset = oadd(zp->z_gmtoff, rp->r_stdoff);
type = addtype(offset, ab, rp->r_isdst,
rp->r_todisstd, rp->r_todisgmt);
+ if (defaulttype < 0 && !rp->r_isdst)
+ defaulttype = type;
if (rp->r_hiyear == ZIC_MAX
&& !(0 <= lastatmax
&& ktime < attypes[lastatmax].at))
@@ -3050,11 +3080,15 @@ outzone(const struct zone *zpfirst, ptrdiff_t zonecount)
if (*startbuf == '\0')
error(_("cannot determine time zone abbreviation to use just after until time"));
else
- addtt(starttime,
- addtype(startoff, startbuf,
- startoff != zp->z_gmtoff,
- startttisstd,
- startttisgmt));
+ {
+ bool isdst = startoff != zp->z_gmtoff;
+
+ type = addtype(startoff, startbuf, isdst,
+ startttisstd, startttisgmt);
+ if (defaulttype < 0 && !isdst)
+ defaulttype = type;
+ addtt(starttime, type);
+ }
}
/*
@@ -3071,6 +3105,8 @@ outzone(const struct zone *zpfirst, ptrdiff_t zonecount)
starttime = tadd(starttime, -gmtoff);
}
}
+ if (defaulttype < 0)
+ defaulttype = 0;
if (0 <= lastatmax)
attypes[lastatmax].dontmerge = true;
if (do_extend)
@@ -3100,7 +3136,7 @@ outzone(const struct zone *zpfirst, ptrdiff_t zonecount)
attypes[timecnt - 1].dontmerge = true;
}
}
- writezone(zpfirst->z_name, envvar, version);
+ writezone(zpfirst->z_name, envvar, version, defaulttype);
free(startbuf);
free(ab);
free(envvar);
@@ -3109,21 +3145,6 @@ outzone(const struct zone *zpfirst, ptrdiff_t zonecount)
static void
addtt(zic_t starttime, int type)
{
- if (starttime <= early_time
- || (timecnt == 1 && attypes[0].at < early_time))
- {
- gmtoffs[0] = gmtoffs[type];
- isdsts[0] = isdsts[type];
- ttisstds[0] = ttisstds[type];
- ttisgmts[0] = ttisgmts[type];
- if (abbrinds[type] != 0)
- strcpy(chars, &chars[abbrinds[type]]);
- abbrinds[0] = 0;
- charcnt = strlen(chars) + 1;
- typecnt = 1;
- timecnt = 0;
- type = 0;
- }
attypes = growalloc(attypes, sizeof *attypes, timecnt, &timecnt_alloc);
attypes[timecnt].at = starttime;
attypes[timecnt].dontmerge = false;
@@ -3361,7 +3382,7 @@ is_alpha(char a)
}
/* If A is an uppercase character in the C locale, return its lowercase
- * counterpart. Otherwise, return A. */
+ counterpart. Otherwise, return A. */
static char
lowerit(char a)
{
@@ -3628,6 +3649,18 @@ rpytime(const struct rule *rp, zic_t wantedy)
dayoff = 0;
m = TM_JANUARY;
y = EPOCH_YEAR;
+ if (y < wantedy)
+ {
+ wantedy -= y;
+ dayoff = (wantedy / YEARSPERREPEAT) * (SECSPERREPEAT / SECSPERDAY);
+ wantedy %= YEARSPERREPEAT;
+ wantedy += y;
+ }
+ else if (wantedy < 0)
+ {
+ dayoff = (wantedy / YEARSPERREPEAT) * (SECSPERREPEAT / SECSPERDAY);
+ wantedy %= YEARSPERREPEAT;
+ }
while (wantedy != y)
{
if (wantedy > y)
@@ -3706,7 +3739,6 @@ will not work with pre-2004 versions of zic"));
if (dayoff > max_time / SECSPERDAY)
return max_time;
t = (zic_t) dayoff * SECSPERDAY;
-
return tadd(t, rp->r_tod);
}