diff options
Diffstat (limited to 'src/timezone/zic.c')
-rw-r--r-- | src/timezone/zic.c | 330 |
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); } |