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.
This commit is contained in:
Tom Lane 2019-07-17 18:26:23 -04:00
parent fec0778c80
commit f285322f9c
5 changed files with 306 additions and 268 deletions

View File

@ -55,7 +55,7 @@ match properly on the old version.
Time Zone code Time Zone code
============== ==============
The code in this directory is currently synced with tzcode release 2019a. The code in this directory is currently synced with tzcode release 2019b.
There are many cosmetic (and not so cosmetic) differences from the There are many cosmetic (and not so cosmetic) differences from the
original tzcode library, but diffs in the upstream version should usually original tzcode library, but diffs in the upstream version should usually
be propagated to our version. Here are some notes about that. be propagated to our version. Here are some notes about that.
@ -127,4 +127,7 @@ and then run them through pgindent. (The first three sed patterns deal
with conversion of their block comment style to something pgindent with conversion of their block comment style to something pgindent
won't make a hash of; the remainder address other points noted above.) won't make a hash of; the remainder address other points noted above.)
After that, the files can be diff'd directly against our corresponding After that, the files can be diff'd directly against our corresponding
files. files. Also, it's typically helpful to diff against the previous tzcode
release (after processing that the same way), and then try to apply the
diff to our files. This will take care of most of the changes
mechanically.

View File

@ -107,15 +107,15 @@ static bool typesequiv(struct state const *, int, int);
static struct pg_tm tm; static struct pg_tm tm;
/* Initialize *S to a value based on GMTOFF, ISDST, and ABBRIND. */ /* Initialize *S to a value based on UTOFF, ISDST, and DESIGIDX. */
static void static void
init_ttinfo(struct ttinfo *s, int32 gmtoff, bool isdst, int abbrind) init_ttinfo(struct ttinfo *s, int32 utoff, bool isdst, int desigidx)
{ {
s->tt_gmtoff = gmtoff; s->tt_utoff = utoff;
s->tt_isdst = isdst; s->tt_isdst = isdst;
s->tt_abbrind = abbrind; s->tt_desigidx = desigidx;
s->tt_ttisstd = false; s->tt_ttisstd = false;
s->tt_ttisgmt = false; s->tt_ttisut = false;
} }
static int32 static int32
@ -251,7 +251,7 @@ tzloadbody(char const *name, char *canonname, struct state *sp, bool doextend,
for (stored = 4; stored <= 8; stored *= 2) for (stored = 4; stored <= 8; stored *= 2)
{ {
int32 ttisstdcnt = detzcode(up->tzhead.tzh_ttisstdcnt); int32 ttisstdcnt = detzcode(up->tzhead.tzh_ttisstdcnt);
int32 ttisgmtcnt = detzcode(up->tzhead.tzh_ttisgmtcnt); int32 ttisutcnt = detzcode(up->tzhead.tzh_ttisutcnt);
int64 prevtr = 0; int64 prevtr = 0;
int32 prevcorr = 0; int32 prevcorr = 0;
int32 leapcnt = detzcode(up->tzhead.tzh_leapcnt); int32 leapcnt = detzcode(up->tzhead.tzh_leapcnt);
@ -270,7 +270,7 @@ tzloadbody(char const *name, char *canonname, struct state *sp, bool doextend,
&& 0 <= timecnt && timecnt < TZ_MAX_TIMES && 0 <= timecnt && timecnt < TZ_MAX_TIMES
&& 0 <= charcnt && charcnt < TZ_MAX_CHARS && 0 <= charcnt && charcnt < TZ_MAX_CHARS
&& (ttisstdcnt == typecnt || ttisstdcnt == 0) && (ttisstdcnt == typecnt || ttisstdcnt == 0)
&& (ttisgmtcnt == typecnt || ttisgmtcnt == 0))) && (ttisutcnt == typecnt || ttisutcnt == 0)))
return EINVAL; return EINVAL;
if (nread if (nread
< (tzheadsize /* struct tzhead */ < (tzheadsize /* struct tzhead */
@ -280,7 +280,7 @@ tzloadbody(char const *name, char *canonname, struct state *sp, bool doextend,
+ charcnt /* chars */ + charcnt /* chars */
+ leapcnt * (stored + 4) /* lsinfos */ + leapcnt * (stored + 4) /* lsinfos */
+ ttisstdcnt /* ttisstds */ + ttisstdcnt /* ttisstds */
+ ttisgmtcnt)) /* ttisgmts */ + ttisutcnt)) /* ttisuts */
return EINVAL; return EINVAL;
sp->leapcnt = leapcnt; sp->leapcnt = leapcnt;
sp->timecnt = timecnt; sp->timecnt = timecnt;
@ -332,19 +332,19 @@ tzloadbody(char const *name, char *canonname, struct state *sp, bool doextend,
{ {
struct ttinfo *ttisp; struct ttinfo *ttisp;
unsigned char isdst, unsigned char isdst,
abbrind; desigidx;
ttisp = &sp->ttis[i]; ttisp = &sp->ttis[i];
ttisp->tt_gmtoff = detzcode(p); ttisp->tt_utoff = detzcode(p);
p += 4; p += 4;
isdst = *p++; isdst = *p++;
if (!(isdst < 2)) if (!(isdst < 2))
return EINVAL; return EINVAL;
ttisp->tt_isdst = isdst; ttisp->tt_isdst = isdst;
abbrind = *p++; desigidx = *p++;
if (!(abbrind < sp->charcnt)) if (!(desigidx < sp->charcnt))
return EINVAL; return EINVAL;
ttisp->tt_abbrind = abbrind; ttisp->tt_desigidx = desigidx;
} }
for (i = 0; i < sp->charcnt; ++i) for (i = 0; i < sp->charcnt; ++i)
sp->chars[i] = *p++; sp->chars[i] = *p++;
@ -398,13 +398,13 @@ tzloadbody(char const *name, char *canonname, struct state *sp, bool doextend,
struct ttinfo *ttisp; struct ttinfo *ttisp;
ttisp = &sp->ttis[i]; ttisp = &sp->ttis[i];
if (ttisgmtcnt == 0) if (ttisutcnt == 0)
ttisp->tt_ttisgmt = false; ttisp->tt_ttisut = false;
else else
{ {
if (*p != true && *p != false) if (*p != true && *p != false)
return EINVAL; return EINVAL;
ttisp->tt_ttisgmt = *p++; ttisp->tt_ttisut = *p++;
} }
} }
@ -438,13 +438,13 @@ tzloadbody(char const *name, char *canonname, struct state *sp, bool doextend,
for (i = 0; i < ts->typecnt; i++) for (i = 0; i < ts->typecnt; i++)
{ {
char *tsabbr = ts->chars + ts->ttis[i].tt_abbrind; char *tsabbr = ts->chars + ts->ttis[i].tt_desigidx;
int j; int j;
for (j = 0; j < charcnt; j++) for (j = 0; j < charcnt; j++)
if (strcmp(sp->chars + j, tsabbr) == 0) if (strcmp(sp->chars + j, tsabbr) == 0)
{ {
ts->ttis[i].tt_abbrind = j; ts->ttis[i].tt_desigidx = j;
gotabbr++; gotabbr++;
break; break;
} }
@ -456,7 +456,7 @@ tzloadbody(char const *name, char *canonname, struct state *sp, bool doextend,
{ {
strcpy(sp->chars + j, tsabbr); strcpy(sp->chars + j, tsabbr);
charcnt = j + tsabbrlen + 1; charcnt = j + tsabbrlen + 1;
ts->ttis[i].tt_abbrind = j; ts->ttis[i].tt_desigidx = j;
gotabbr++; gotabbr++;
} }
} }
@ -614,12 +614,13 @@ typesequiv(const struct state *sp, int a, int b)
const struct ttinfo *ap = &sp->ttis[a]; const struct ttinfo *ap = &sp->ttis[a];
const struct ttinfo *bp = &sp->ttis[b]; const struct ttinfo *bp = &sp->ttis[b];
result = ap->tt_gmtoff == bp->tt_gmtoff && result = (ap->tt_utoff == bp->tt_utoff
ap->tt_isdst == bp->tt_isdst && && ap->tt_isdst == bp->tt_isdst
ap->tt_ttisstd == bp->tt_ttisstd && && ap->tt_ttisstd == bp->tt_ttisstd
ap->tt_ttisgmt == bp->tt_ttisgmt && && ap->tt_ttisut == bp->tt_ttisut
strcmp(&sp->chars[ap->tt_abbrind], && (strcmp(&sp->chars[ap->tt_desigidx],
&sp->chars[bp->tt_abbrind]) == 0; &sp->chars[bp->tt_desigidx])
== 0));
} }
return result; return result;
} }
@ -1176,7 +1177,7 @@ tzparse(const char *name, struct state *sp, bool lastditch)
if (!sp->ttis[j].tt_isdst) if (!sp->ttis[j].tt_isdst)
{ {
theirstdoffset = theirstdoffset =
-sp->ttis[j].tt_gmtoff; -sp->ttis[j].tt_utoff;
break; break;
} }
} }
@ -1187,7 +1188,7 @@ tzparse(const char *name, struct state *sp, bool lastditch)
if (sp->ttis[j].tt_isdst) if (sp->ttis[j].tt_isdst)
{ {
theirdstoffset = theirdstoffset =
-sp->ttis[j].tt_gmtoff; -sp->ttis[j].tt_utoff;
break; break;
} }
} }
@ -1206,7 +1207,7 @@ tzparse(const char *name, struct state *sp, bool lastditch)
{ {
j = sp->types[i]; j = sp->types[i];
sp->types[i] = sp->ttis[j].tt_isdst; sp->types[i] = sp->ttis[j].tt_isdst;
if (sp->ttis[j].tt_ttisgmt) if (sp->ttis[j].tt_ttisut)
{ {
/* No adjustment to transition time */ /* No adjustment to transition time */
} }
@ -1234,7 +1235,7 @@ tzparse(const char *name, struct state *sp, bool lastditch)
theirstdoffset; theirstdoffset;
} }
} }
theiroffset = -sp->ttis[j].tt_gmtoff; theiroffset = -sp->ttis[j].tt_utoff;
if (sp->ttis[j].tt_isdst) if (sp->ttis[j].tt_isdst)
theirdstoffset = theiroffset; theirdstoffset = theiroffset;
else else
@ -1357,14 +1358,14 @@ localsub(struct state const *sp, pg_time_t const *timep,
/* /*
* To get (wrong) behavior that's compatible with System V Release 2.0 * To get (wrong) behavior that's compatible with System V Release 2.0
* you'd replace the statement below with t += ttisp->tt_gmtoff; * you'd replace the statement below with t += ttisp->tt_utoff;
* timesub(&t, 0L, sp, tmp); * timesub(&t, 0L, sp, tmp);
*/ */
result = timesub(&t, ttisp->tt_gmtoff, sp, tmp); result = timesub(&t, ttisp->tt_utoff, sp, tmp);
if (result) if (result)
{ {
result->tm_isdst = ttisp->tt_isdst; result->tm_isdst = ttisp->tt_isdst;
result->tm_zone = unconstify(char *, &sp->chars[ttisp->tt_abbrind]); result->tm_zone = unconstify(char *, &sp->chars[ttisp->tt_desigidx]);
} }
return result; return result;
} }
@ -1647,7 +1648,7 @@ pg_next_dst_boundary(const pg_time_t *timep,
break; break;
} }
ttisp = &sp->ttis[i]; ttisp = &sp->ttis[i];
*before_gmtoff = ttisp->tt_gmtoff; *before_gmtoff = ttisp->tt_utoff;
*before_isdst = ttisp->tt_isdst; *before_isdst = ttisp->tt_isdst;
return 0; return 0;
} }
@ -1700,7 +1701,7 @@ pg_next_dst_boundary(const pg_time_t *timep,
/* No known transition > t, so use last known segment's type */ /* No known transition > t, so use last known segment's type */
i = sp->types[sp->timecnt - 1]; i = sp->types[sp->timecnt - 1];
ttisp = &sp->ttis[i]; ttisp = &sp->ttis[i];
*before_gmtoff = ttisp->tt_gmtoff; *before_gmtoff = ttisp->tt_utoff;
*before_isdst = ttisp->tt_isdst; *before_isdst = ttisp->tt_isdst;
return 0; return 0;
} }
@ -1715,13 +1716,13 @@ pg_next_dst_boundary(const pg_time_t *timep,
break; break;
} }
ttisp = &sp->ttis[i]; ttisp = &sp->ttis[i];
*before_gmtoff = ttisp->tt_gmtoff; *before_gmtoff = ttisp->tt_utoff;
*before_isdst = ttisp->tt_isdst; *before_isdst = ttisp->tt_isdst;
*boundary = sp->ats[0]; *boundary = sp->ats[0];
/* And for "after", use the first segment's type */ /* And for "after", use the first segment's type */
i = sp->types[0]; i = sp->types[0];
ttisp = &sp->ttis[i]; ttisp = &sp->ttis[i];
*after_gmtoff = ttisp->tt_gmtoff; *after_gmtoff = ttisp->tt_utoff;
*after_isdst = ttisp->tt_isdst; *after_isdst = ttisp->tt_isdst;
return 1; return 1;
} }
@ -1743,12 +1744,12 @@ pg_next_dst_boundary(const pg_time_t *timep,
} }
j = sp->types[i - 1]; j = sp->types[i - 1];
ttisp = &sp->ttis[j]; ttisp = &sp->ttis[j];
*before_gmtoff = ttisp->tt_gmtoff; *before_gmtoff = ttisp->tt_utoff;
*before_isdst = ttisp->tt_isdst; *before_isdst = ttisp->tt_isdst;
*boundary = sp->ats[i]; *boundary = sp->ats[i];
j = sp->types[i]; j = sp->types[i];
ttisp = &sp->ttis[j]; ttisp = &sp->ttis[j];
*after_gmtoff = ttisp->tt_gmtoff; *after_gmtoff = ttisp->tt_utoff;
*after_isdst = ttisp->tt_isdst; *after_isdst = ttisp->tt_isdst;
return 1; return 1;
} }
@ -1832,9 +1833,9 @@ pg_interpret_timezone_abbrev(const char *abbrev,
for (i = cutoff - 1; i >= 0; i--) for (i = cutoff - 1; i >= 0; i--)
{ {
ttisp = &sp->ttis[sp->types[i]]; ttisp = &sp->ttis[sp->types[i]];
if (ttisp->tt_abbrind == abbrind) if (ttisp->tt_desigidx == abbrind)
{ {
*gmtoff = ttisp->tt_gmtoff; *gmtoff = ttisp->tt_utoff;
*isdst = ttisp->tt_isdst; *isdst = ttisp->tt_isdst;
return true; return true;
} }
@ -1846,9 +1847,9 @@ pg_interpret_timezone_abbrev(const char *abbrev,
for (i = cutoff; i < sp->timecnt; i++) for (i = cutoff; i < sp->timecnt; i++)
{ {
ttisp = &sp->ttis[sp->types[i]]; ttisp = &sp->ttis[sp->types[i]];
if (ttisp->tt_abbrind == abbrind) if (ttisp->tt_desigidx == abbrind)
{ {
*gmtoff = ttisp->tt_gmtoff; *gmtoff = ttisp->tt_utoff;
*isdst = ttisp->tt_isdst; *isdst = ttisp->tt_isdst;
return true; return true;
} }
@ -1875,10 +1876,10 @@ pg_get_timezone_offset(const pg_tz *tz, long int *gmtoff)
sp = &tz->state; sp = &tz->state;
for (i = 1; i < sp->typecnt; i++) for (i = 1; i < sp->typecnt; i++)
{ {
if (sp->ttis[i].tt_gmtoff != sp->ttis[0].tt_gmtoff) if (sp->ttis[i].tt_utoff != sp->ttis[0].tt_utoff)
return false; return false;
} }
*gmtoff = sp->ttis[0].tt_gmtoff; *gmtoff = sp->ttis[0].tt_utoff;
return true; return true;
} }

View File

@ -25,11 +25,11 @@
struct ttinfo struct ttinfo
{ /* time type information */ { /* time type information */
int32 tt_gmtoff; /* UT offset in seconds */ int32 tt_utoff; /* UT offset in seconds */
bool tt_isdst; /* used to set tm_isdst */ bool tt_isdst; /* used to set tm_isdst */
int tt_abbrind; /* abbreviation list index */ int tt_desigidx; /* abbreviation list index */
bool tt_ttisstd; /* transition is std time */ bool tt_ttisstd; /* transition is std time */
bool tt_ttisgmt; /* transition is UT */ bool tt_ttisut; /* transition is UT */
}; };
struct lsinfo struct lsinfo

View File

@ -41,7 +41,7 @@ struct tzhead
char tzh_magic[4]; /* TZ_MAGIC */ char tzh_magic[4]; /* TZ_MAGIC */
char tzh_version[1]; /* '\0' or '2' or '3' as of 2013 */ char tzh_version[1]; /* '\0' or '2' or '3' as of 2013 */
char tzh_reserved[15]; /* reserved; must be zero */ char tzh_reserved[15]; /* reserved; must be zero */
char tzh_ttisgmtcnt[4]; /* coded number of trans. time flags */ char tzh_ttisutcnt[4]; /* coded number of trans. time flags */
char tzh_ttisstdcnt[4]; /* coded number of trans. time flags */ char tzh_ttisstdcnt[4]; /* coded number of trans. time flags */
char tzh_leapcnt[4]; /* coded number of leap seconds */ char tzh_leapcnt[4]; /* coded number of leap seconds */
char tzh_timecnt[4]; /* coded number of transition times */ char tzh_timecnt[4]; /* coded number of transition times */
@ -64,14 +64,15 @@ struct tzhead
* one (char [4]) total correction after above * one (char [4]) total correction after above
* tzh_ttisstdcnt (char)s indexed by type; if 1, transition * tzh_ttisstdcnt (char)s indexed by type; if 1, transition
* time is standard time, if 0, * time is standard time, if 0,
* transition time is wall clock time * transition time is local (wall clock)
* if absent, transition times are * time; if absent, transition times are
* assumed to be wall clock time
* tzh_ttisgmtcnt (char)s indexed by type; if 1, transition
* time is UT, if 0,
* transition time is local time
* if absent, transition times are
* assumed to be local time * assumed to be local time
* tzh_ttisutcnt (char)s indexed by type; if 1, transition
* time is UT, if 0, transition time is
* local time; if absent, transition
* times are assumed to be local time.
* When this is 1, the corresponding
* std/wall indicator must also be 1.
*/ */
/* /*

View File

@ -77,12 +77,10 @@ struct rule
int r_wday; int r_wday;
zic_t r_tod; /* time from midnight */ zic_t r_tod; /* time from midnight */
bool r_todisstd; /* above is standard time if 1 or wall clock bool r_todisstd; /* is r_tod standard time? */
* time if 0 */ bool r_todisut; /* is r_tod UT? */
bool r_todisgmt; /* above is GMT if 1 or local time if 0 */
bool r_isdst; /* is this daylight saving time? */ bool r_isdst; /* is this daylight saving time? */
zic_t r_stdoff; /* offset from default time (which is usually zic_t r_save; /* offset from standard time */
* standard time) */
const char *r_abbrvar; /* variable part of abbreviation */ const char *r_abbrvar; /* variable part of abbreviation */
bool r_todo; /* a rule to do (used in outzone) */ bool r_todo; /* a rule to do (used in outzone) */
@ -103,13 +101,13 @@ struct zone
lineno_t z_linenum; lineno_t z_linenum;
const char *z_name; const char *z_name;
zic_t z_gmtoff; zic_t z_stdoff;
char *z_rule; char *z_rule;
const char *z_format; const char *z_format;
char z_format_specifier; char z_format_specifier;
bool z_isdst; bool z_isdst;
zic_t z_stdoff; zic_t z_save;
struct rule *z_rules; struct rule *z_rules;
ptrdiff_t z_nrules; ptrdiff_t z_nrules;
@ -133,7 +131,7 @@ static void associate(void);
static void dolink(const char *, const char *, bool); static void dolink(const char *, const char *, bool);
static char **getfields(char *buf); static char **getfields(char *buf);
static zic_t gethms(const char *string, const char *errstring); 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 infile(const char *filename);
static void inleap(char **fields, int nfields); static void inleap(char **fields, int nfields);
static void inlink(char **fields, int nfields); static void inlink(char **fields, int nfields);
@ -210,7 +208,7 @@ static int typecnt;
*/ */
#define ZF_NAME 1 #define ZF_NAME 1
#define ZF_GMTOFF 2 #define ZF_STDOFF 2
#define ZF_RULE 3 #define ZF_RULE 3
#define ZF_FORMAT 4 #define ZF_FORMAT 4
#define ZF_TILYEAR 5 #define ZF_TILYEAR 5
@ -224,7 +222,7 @@ static int typecnt;
* Which fields are which on a Zone continuation line. * Which fields are which on a Zone continuation line.
*/ */
#define ZFC_GMTOFF 0 #define ZFC_STDOFF 0
#define ZFC_RULE 1 #define ZFC_RULE 1
#define ZFC_FORMAT 2 #define ZFC_FORMAT 2
#define ZFC_TILYEAR 3 #define ZFC_TILYEAR 3
@ -245,7 +243,7 @@ static int typecnt;
#define RF_MONTH 5 #define RF_MONTH 5
#define RF_DAY 6 #define RF_DAY 6
#define RF_TOD 7 #define RF_TOD 7
#define RF_STDOFF 8 #define RF_SAVE 8
#define RF_ABBRVAR 9 #define RF_ABBRVAR 9
#define RULE_FIELDS 10 #define RULE_FIELDS 10
@ -389,11 +387,11 @@ static struct attype
bool dontmerge; bool dontmerge;
unsigned char type; unsigned char type;
} *attypes; } *attypes;
static zic_t gmtoffs[TZ_MAX_TYPES]; static zic_t utoffs[TZ_MAX_TYPES];
static char isdsts[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 ttisstds[TZ_MAX_TYPES];
static bool ttisgmts[TZ_MAX_TYPES]; static bool ttisuts[TZ_MAX_TYPES];
static char chars[TZ_MAX_CHARS]; static char chars[TZ_MAX_CHARS];
static zic_t trans[TZ_MAX_LEAPS]; static zic_t trans[TZ_MAX_LEAPS];
static zic_t corr[TZ_MAX_LEAPS]; static zic_t corr[TZ_MAX_LEAPS];
@ -540,8 +538,9 @@ usage(FILE *stream, int status)
{ {
fprintf(stream, fprintf(stream,
_("%s: usage is %s [ --version ] [ --help ] [ -v ] [ -P ] \\\n" _("%s: usage is %s [ --version ] [ --help ] [ -v ] [ -P ] \\\n"
"\t[ -l localtime ] [ -p posixrules ] [ -d directory ] \\\n" "\t[ -b {slim|fat} ] [ -d directory ] [ -l localtime ]"
"\t[ -t localtime-link ] [ -L leapseconds ] [ -r '[@lo][/@hi]' ] \\\n" " [ -L leapseconds ] \\\n"
"\t[ -p posixrules ] [ -r '[@lo][/@hi]' ] [ -t localtime-link ] \\\n"
"\t[ filename ... ]\n\n" "\t[ filename ... ]\n\n"
"Report bugs to %s.\n"), "Report bugs to %s.\n"),
progname, progname, PACKAGE_BUGREPORT); progname, progname, PACKAGE_BUGREPORT);
@ -625,6 +624,21 @@ static const char *leapsec;
static const char *tzdefault; static const char *tzdefault;
static const char *yitcommand; 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 int
main(int argc, char **argv) main(int argc, char **argv)
{ {
@ -655,11 +669,27 @@ main(int argc, char **argv)
{ {
usage(stdout, EXIT_SUCCESS); 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) switch (c)
{ {
default: default:
usage(stderr, EXIT_FAILURE); 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': case 'd':
if (directory == NULL) if (directory == NULL)
directory = strdup(optarg); directory = strdup(optarg);
@ -759,6 +789,8 @@ main(int argc, char **argv)
} }
if (optind == argc - 1 && strcmp(argv[optind], "=") == 0) if (optind == argc - 1 && strcmp(argv[optind], "=") == 0)
usage(stderr, EXIT_FAILURE); /* usage message by request */ usage(stderr, EXIT_FAILURE); /* usage message by request */
if (bloat == 0)
bloat = strcmp(ZIC_BLOAT_DEFAULT, "slim") == 0 ? -1 : 1;
if (directory == NULL) if (directory == NULL)
directory = "data"; directory = "data";
if (tzdefault == NULL) if (tzdefault == NULL)
@ -1183,7 +1215,7 @@ associate(void)
* Maybe we have a local standard time offset. * Maybe we have a local standard time offset.
*/ */
eat(zp->z_filename, zp->z_linenum); 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 * 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 static zic_t
getstdoff(char *field, bool *isdst) getsave(char *field, bool *isdst)
{ {
int dst = -1; int dst = -1;
zic_t stdoff; zic_t save;
size_t fieldlen = strlen(field); size_t fieldlen = strlen(field);
if (fieldlen != 0) if (fieldlen != 0)
@ -1402,9 +1434,9 @@ getstdoff(char *field, bool *isdst)
break; break;
} }
} }
stdoff = gethms(field, _("invalid saved time")); save = gethms(field, _("invalid saved time"));
*isdst = dst < 0 ? stdoff != 0 : dst; *isdst = dst < 0 ? save != 0 : dst;
return stdoff; return save;
} }
static void static void
@ -1443,7 +1475,7 @@ inrule(char **fields, int nfields)
} }
r.r_filename = filename; r.r_filename = filename;
r.r_linenum = linenum; 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], rulesub(&r, fields[RF_LOYEAR], fields[RF_HIYEAR], fields[RF_COMMAND],
fields[RF_MONTH], fields[RF_DAY], fields[RF_TOD]); fields[RF_MONTH], fields[RF_DAY], fields[RF_TOD]);
r.r_name = ecpyalloc(fields[RF_NAME]); r.r_name = ecpyalloc(fields[RF_NAME]);
@ -1509,7 +1541,7 @@ inzsub(char **fields, int nfields, bool iscont)
char *cp; char *cp;
char *cp1; char *cp1;
static struct zone z; static struct zone z;
int i_gmtoff, int i_stdoff,
i_rule, i_rule,
i_format; i_format;
int i_untilyear, int i_untilyear,
@ -1520,7 +1552,7 @@ inzsub(char **fields, int nfields, bool iscont)
if (iscont) if (iscont)
{ {
i_gmtoff = ZFC_GMTOFF; i_stdoff = ZFC_STDOFF;
i_rule = ZFC_RULE; i_rule = ZFC_RULE;
i_format = ZFC_FORMAT; i_format = ZFC_FORMAT;
i_untilyear = ZFC_TILYEAR; i_untilyear = ZFC_TILYEAR;
@ -1533,7 +1565,7 @@ inzsub(char **fields, int nfields, bool iscont)
return false; return false;
else else
{ {
i_gmtoff = ZF_GMTOFF; i_stdoff = ZF_STDOFF;
i_rule = ZF_RULE; i_rule = ZF_RULE;
i_format = ZF_FORMAT; i_format = ZF_FORMAT;
i_untilyear = ZF_TILYEAR; i_untilyear = ZF_TILYEAR;
@ -1544,7 +1576,7 @@ inzsub(char **fields, int nfields, bool iscont)
} }
z.z_filename = filename; z.z_filename = filename;
z.z_linenum = linenum; 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 = strchr(fields[i_format], '%')) != NULL)
{ {
if ((*++cp != 's' && *cp != 'z') || strchr(cp, '%') 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_month = lp->l_value;
rp->r_todisstd = false; rp->r_todisstd = false;
rp->r_todisgmt = false; rp->r_todisut = false;
dp = ecpyalloc(timep); dp = ecpyalloc(timep);
if (*dp != '\0') if (*dp != '\0')
{ {
@ -1777,19 +1809,19 @@ rulesub(struct rule *rp, const char *loyearp, const char *hiyearp,
{ {
case 's': /* Standard */ case 's': /* Standard */
rp->r_todisstd = true; rp->r_todisstd = true;
rp->r_todisgmt = false; rp->r_todisut = false;
*ep = '\0'; *ep = '\0';
break; break;
case 'w': /* Wall */ case 'w': /* Wall */
rp->r_todisstd = false; rp->r_todisstd = false;
rp->r_todisgmt = false; rp->r_todisut = false;
*ep = '\0'; *ep = '\0';
break; break;
case 'g': /* Greenwich */ case 'g': /* Greenwich */
case 'u': /* Universal */ case 'u': /* Universal */
case 'z': /* Zulu */ case 'z': /* Zulu */
rp->r_todisstd = true; rp->r_todisstd = true;
rp->r_todisgmt = true; rp->r_todisut = true;
*ep = '\0'; *ep = '\0';
break; break;
} }
@ -1977,41 +2009,6 @@ atcomp(const void *avp, const void *bvp)
return (a < b) ? -1 : (a > b); 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 struct timerange
{ {
int defaulttype; int defaulttype;
@ -2091,10 +2088,12 @@ writezone(const char *const name, const char *const string, char version,
fromi = 0; fromi = 0;
for (; fromi < timecnt; ++fromi) for (; fromi < timecnt; ++fromi)
{ {
if (toi != 0 && ((attypes[fromi].at + if (toi != 0
gmtoffs[attypes[toi - 1].type]) <= && ((attypes[fromi].at
(attypes[toi - 1].at + gmtoffs[toi == 1 ? 0 + utoffs[attypes[toi - 1].type])
: attypes[toi - 2].type]))) <= (attypes[toi - 1].at
+ utoffs[toi == 1 ? 0
: attypes[toi - 2].type])))
{ {
attypes[toi - 1].type = attypes[toi - 1].type =
attypes[fromi].type; attypes[fromi].type;
@ -2102,7 +2101,12 @@ writezone(const char *const name, const char *const string, char version,
} }
if (toi == 0 if (toi == 0
|| attypes[fromi].dontmerge || 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]; attypes[toi++] = attypes[fromi];
} }
timecnt = toi; 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 * before 32-bit pg_time_t rolls around, and this occurs at a slightly
* different moment if transitions are leap-second corrected. * 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 - 1] < y2038_boundary - 1 && strchr(string, '<'))
{ {
ats[timecnt] = y2038_boundary - 1; ats[timecnt] = y2038_boundary - 1;
@ -2213,7 +2217,9 @@ writezone(const char *const name, const char *const string, char version,
int old0; int old0;
char omittype[TZ_MAX_TYPES]; char omittype[TZ_MAX_TYPES];
int typemap[TZ_MAX_TYPES]; int typemap[TZ_MAX_TYPES];
int thistypecnt; int thistypecnt,
stdcnt,
utcnt;
char thischars[TZ_MAX_CHARS]; char thischars[TZ_MAX_CHARS];
int thischarcnt; int thischarcnt;
bool toomanytimes; 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. * in the output instead of OLD0. TYPEMAP also omits unused types.
*/ */
old0 = strlen(omittype); old0 = strlen(omittype);
swaptypes(old0, thisdefaulttype);
#ifndef LEAVE_SOME_PRE_2011_SYSTEMS_IN_THE_LURCH #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 * offset, append an (unused) copy of the most recently used type (to
* help get global "altzone" and "timezone" variables set correctly). * help get global "altzone" and "timezone" variables set correctly).
*/ */
if (want_bloat())
{ {
int mrudst, int mrudst,
mrustd, mrustd,
@ -2317,34 +2323,39 @@ writezone(const char *const name, const char *const string, char version,
else else
mrustd = types[i]; mrustd = types[i];
for (i = old0; i < typecnt; 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; hidst = i;
else else
histd = i; histd = i;
} }
}
if (hidst >= 0 && mrudst >= 0 && hidst != mrudst && if (hidst >= 0 && mrudst >= 0 && hidst != mrudst &&
gmtoffs[hidst] != gmtoffs[mrudst]) utoffs[hidst] != utoffs[mrudst])
{ {
isdsts[mrudst] = -1; isdsts[mrudst] = -1;
type = addtype(gmtoffs[mrudst], type = addtype(utoffs[mrudst],
&chars[abbrinds[mrudst]], &chars[desigidx[mrudst]],
true, true,
ttisstds[mrudst], ttisstds[mrudst],
ttisgmts[mrudst]); ttisuts[mrudst]);
isdsts[mrudst] = 1; isdsts[mrudst] = 1;
omittype[type] = false; omittype[type] = false;
} }
if (histd >= 0 && mrustd >= 0 && histd != mrustd && if (histd >= 0 && mrustd >= 0 && histd != mrustd &&
gmtoffs[histd] != gmtoffs[mrustd]) utoffs[histd] != utoffs[mrustd])
{ {
isdsts[mrustd] = -1; isdsts[mrustd] = -1;
type = addtype(gmtoffs[mrustd], type = addtype(utoffs[mrustd],
&chars[abbrinds[mrustd]], &chars[desigidx[mrustd]],
false, false,
ttisstds[mrustd], ttisstds[mrustd],
ttisgmts[mrustd]); ttisuts[mrustd]);
isdsts[mrustd] = 0; isdsts[mrustd] = 0;
omittype[type] = false; 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) for (i = 0; i < sizeof indmap / sizeof indmap[0]; ++i)
indmap[i] = -1; indmap[i] = -1;
thischarcnt = 0; thischarcnt = stdcnt = utcnt = 0;
for (i = old0; i < typecnt; i++) for (i = old0; i < typecnt; i++)
{ {
char *thisabbr; char *thisabbr;
if (omittype[i]) if (omittype[i])
continue; continue;
if (indmap[abbrinds[i]] >= 0) if (ttisstds[i])
stdcnt = thistypecnt;
if (ttisuts[i])
utcnt = thistypecnt;
if (indmap[desigidx[i]] >= 0)
continue; continue;
thisabbr = &chars[abbrinds[i]]; thisabbr = &chars[desigidx[i]];
for (j = 0; j < thischarcnt; ++j) for (j = 0; j < thischarcnt; ++j)
if (strcmp(&thischars[j], thisabbr) == 0) if (strcmp(&thischars[j], thisabbr) == 0)
break; break;
@ -2378,14 +2393,21 @@ writezone(const char *const name, const char *const string, char version,
strcpy(&thischars[thischarcnt], thisabbr); strcpy(&thischars[thischarcnt], thisabbr);
thischarcnt += strlen(thisabbr) + 1; 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) #define DO(field) fwrite(tzh.field, sizeof tzh.field, 1, fp)
tzh = tzh0; tzh = tzh0;
memcpy(tzh.tzh_magic, TZ_MAGIC, sizeof tzh.tzh_magic); memcpy(tzh.tzh_magic, TZ_MAGIC, sizeof tzh.tzh_magic);
tzh.tzh_version[0] = version; tzh.tzh_version[0] = version;
convert(thistypecnt, tzh.tzh_ttisgmtcnt); convert(utcnt, tzh.tzh_ttisutcnt);
convert(thistypecnt, tzh.tzh_ttisstdcnt); convert(stdcnt, tzh.tzh_ttisstdcnt);
convert(thisleapcnt, tzh.tzh_leapcnt); convert(thisleapcnt, tzh.tzh_leapcnt);
convert(locut + thistimecnt + hicut, tzh.tzh_timecnt); convert(locut + thistimecnt + hicut, tzh.tzh_timecnt);
convert(thistypecnt, tzh.tzh_typecnt); 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_magic);
DO(tzh_version); DO(tzh_version);
DO(tzh_reserved); DO(tzh_reserved);
DO(tzh_ttisgmtcnt); DO(tzh_ttisutcnt);
DO(tzh_ttisstdcnt); DO(tzh_ttisstdcnt);
DO(tzh_leapcnt); DO(tzh_leapcnt);
DO(tzh_timecnt); DO(tzh_timecnt);
DO(tzh_typecnt); DO(tzh_typecnt);
DO(tzh_charcnt); DO(tzh_charcnt);
#undef DO #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 */ /* PG: print current timezone abbreviations if requested */
if (print_abbrevs && pass == 2) 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) if (i == thistimelim - 1 || ats[i + 1] > print_cutoff)
{ {
unsigned char tm = types[i]; unsigned char tm = types[i];
char *thisabbrev = &thischars[indmap[abbrinds[tm]]]; char *thisabbrev = &thischars[indmap[desigidx[tm]]];
/* filter out assorted junk entries */ /* filter out assorted junk entries */
if (strcmp(thisabbrev, GRANDPARENTED) != 0 && if (strcmp(thisabbrev, GRANDPARENTED) != 0 &&
strcmp(thisabbrev, "zzz") != 0) strcmp(thisabbrev, "zzz") != 0)
fprintf(stdout, "%s\t" INT64_FORMAT "%s\n", fprintf(stdout, "%s\t" INT64_FORMAT "%s\n",
thisabbrev, thisabbrev,
gmtoffs[tm], utoffs[tm],
isdsts[tm] ? "\tD" : ""); isdsts[tm] ? "\tD" : "");
} }
} }
@ -2425,14 +2456,14 @@ writezone(const char *const name, const char *const string, char version,
if (thistimei >= thistimelim) if (thistimei >= thistimelim)
{ {
unsigned char tm = defaulttype; unsigned char tm = defaulttype;
char *thisabbrev = &thischars[indmap[abbrinds[tm]]]; char *thisabbrev = &thischars[indmap[desigidx[tm]]];
/* filter out assorted junk entries */ /* filter out assorted junk entries */
if (strcmp(thisabbrev, GRANDPARENTED) != 0 && if (strcmp(thisabbrev, GRANDPARENTED) != 0 &&
strcmp(thisabbrev, "zzz") != 0) strcmp(thisabbrev, "zzz") != 0)
fprintf(stdout, "%s\t" INT64_FORMAT "%s\n", fprintf(stdout, "%s\t" INT64_FORMAT "%s\n",
thisabbrev, thisabbrev,
gmtoffs[tm], utoffs[tm],
isdsts[tm] ? "\tD" : ""); isdsts[tm] ? "\tD" : "");
} }
} }
@ -2465,12 +2496,17 @@ writezone(const char *const name, const char *const string, char version,
putc(currenttype, fp); putc(currenttype, fp);
for (i = old0; i < typecnt; i++) 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); puttzcode(utoffs[h], fp);
putc(isdsts[i], fp); putc(isdsts[h], fp);
putc((unsigned char) indmap[abbrinds[i]], fp); putc(indmap[desigidx[h]], fp);
} }
}
if (thischarcnt != 0) if (thischarcnt != 0)
fwrite(thischars, sizeof thischars[0], fwrite(thischars, sizeof thischars[0],
thischarcnt, fp); thischarcnt, fp);
@ -2498,20 +2534,21 @@ writezone(const char *const name, const char *const string, char version,
++j; ++j;
j = types[j - 1]; j = types[j - 1];
} }
todo = tadd(trans[i], -gmtoffs[j]); todo = tadd(trans[i], -utoffs[j]);
} }
else else
todo = trans[i]; todo = trans[i];
puttzcodepass(todo, fp, pass); puttzcodepass(todo, fp, pass);
puttzcode(corr[i], fp); puttzcode(corr[i], fp);
} }
for (i = old0; i < typecnt; i++) if (stdcnt != 0)
if (!omittype[i]) for (i = old0; i < typecnt; i++)
putc(ttisstds[i], fp); if (!omittype[i])
for (i = old0; i < typecnt; i++) putc(ttisstds[i], fp);
if (!omittype[i]) if (utcnt != 0)
putc(ttisgmts[i], fp); for (i = old0; i < typecnt; i++)
swaptypes(old0, thisdefaulttype); if (!omittype[i])
putc(ttisuts[i], fp);
} }
fprintf(fp, "\n%s\n", string); fprintf(fp, "\n%s\n", string);
close_file(fp, directory, name); close_file(fp, directory, name);
@ -2564,7 +2601,7 @@ abbroffset(char *buf, zic_t offset)
static size_t static size_t
doabbr(char *abbr, struct zone const *zp, char const *letters, 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 *cp;
char *slashp; char *slashp;
@ -2577,7 +2614,7 @@ doabbr(char *abbr, struct zone const *zp, char const *letters,
char letterbuf[PERCENT_Z_LEN_BOUND + 1]; char letterbuf[PERCENT_Z_LEN_BOUND + 1];
if (zp->z_format_specifier == 'z') if (zp->z_format_specifier == 'z')
letters = abbroffset(letterbuf, zp->z_gmtoff + stdoff); letters = abbroffset(letterbuf, zp->z_stdoff + save);
else if (!letters) else if (!letters)
letters = "%s"; letters = "%s";
sprintf(abbr, format, letters); sprintf(abbr, format, letters);
@ -2649,8 +2686,7 @@ stringoffset(char *result, zic_t offset)
} }
static int static int
stringrule(char *result, const struct rule *const rp, const zic_t dstoff, stringrule(char *result, struct rule *const rp, zic_t save, zic_t stdoff)
const zic_t gmtoff)
{ {
zic_t tod = rp->r_tod; zic_t tod = rp->r_tod;
int compat = 0; 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", result += sprintf(result, "M%d.%d.%d",
rp->r_month + 1, week, wday); rp->r_month + 1, week, wday);
} }
if (rp->r_todisgmt) if (rp->r_todisut)
tod += gmtoff; tod += stdoff;
if (rp->r_todisstd && !rp->r_isdst) if (rp->r_todisstd && !rp->r_isdst)
tod += dstoff; tod += save;
if (tod != 2 * SECSPERMIN * MINSPERHOUR) if (tod != 2 * SECSPERMIN * MINSPERHOUR)
{ {
*result++ = '/'; *result++ = '/';
@ -2744,10 +2780,6 @@ rule_cmp(struct rule const *a, struct rule const *b)
return a->r_dayofmonth - b->r_dayofmonth; return a->r_dayofmonth - b->r_dayofmonth;
} }
enum
{
YEAR_BY_YEAR_ZONE = 1};
static int static int
stringzone(char *result, struct zone const *zpfirst, ptrdiff_t zonecount) 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) if (rule_cmp(stdrp, rp) < 0)
stdrp = rp; 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) if (stdrp != NULL && stdrp->r_isdst)
{ {
/* Perpetual DST. */ /* Perpetual DST. */
@ -2829,17 +2852,17 @@ stringzone(char *result, struct zone const *zpfirst, ptrdiff_t zonecount)
dstr.r_dycode = DC_DOM; dstr.r_dycode = DC_DOM;
dstr.r_dayofmonth = 1; dstr.r_dayofmonth = 1;
dstr.r_tod = 0; 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_isdst = stdrp->r_isdst;
dstr.r_stdoff = stdrp->r_stdoff; dstr.r_save = stdrp->r_save;
dstr.r_abbrvar = stdrp->r_abbrvar; dstr.r_abbrvar = stdrp->r_abbrvar;
stdr.r_month = TM_DECEMBER; stdr.r_month = TM_DECEMBER;
stdr.r_dycode = DC_DOM; stdr.r_dycode = DC_DOM;
stdr.r_dayofmonth = 31; stdr.r_dayofmonth = 31;
stdr.r_tod = SECSPERDAY + stdrp->r_stdoff; stdr.r_tod = SECSPERDAY + stdrp->r_save;
stdr.r_todisstd = stdr.r_todisgmt = false; stdr.r_todisstd = stdr.r_todisut = false;
stdr.r_isdst = false; stdr.r_isdst = false;
stdr.r_stdoff = 0; stdr.r_save = 0;
stdr.r_abbrvar stdr.r_abbrvar
= (stdabbrrp ? stdabbrrp->r_abbrvar : ""); = (stdabbrrp ? stdabbrrp->r_abbrvar : "");
dstrp = &dstr; dstrp = &dstr;
@ -2850,7 +2873,7 @@ stringzone(char *result, struct zone const *zpfirst, ptrdiff_t zonecount)
return -1; return -1;
abbrvar = (stdrp == NULL) ? "" : stdrp->r_abbrvar; abbrvar = (stdrp == NULL) ? "" : stdrp->r_abbrvar;
len = doabbr(result, zp, abbrvar, false, 0, true); len = doabbr(result, zp, abbrvar, false, 0, true);
offsetlen = stringoffset(result + len, -zp->z_gmtoff); offsetlen = stringoffset(result + len, -zp->z_stdoff);
if (!offsetlen) if (!offsetlen)
{ {
result[0] = '\0'; result[0] = '\0';
@ -2860,11 +2883,11 @@ stringzone(char *result, struct zone const *zpfirst, ptrdiff_t zonecount)
if (dstrp == NULL) if (dstrp == NULL)
return compat; return compat;
len += doabbr(result + len, zp, dstrp->r_abbrvar, len += doabbr(result + len, zp, dstrp->r_abbrvar,
dstrp->r_isdst, dstrp->r_stdoff, true); dstrp->r_isdst, dstrp->r_save, true);
if (dstrp->r_stdoff != SECSPERMIN * MINSPERHOUR) if (dstrp->r_save != SECSPERMIN * MINSPERHOUR)
{ {
offsetlen = stringoffset(result + len, offsetlen = stringoffset(result + len,
-(zp->z_gmtoff + dstrp->r_stdoff)); -(zp->z_stdoff + dstrp->r_save));
if (!offsetlen) if (!offsetlen)
{ {
result[0] = '\0'; result[0] = '\0';
@ -2873,7 +2896,7 @@ stringzone(char *result, struct zone const *zpfirst, ptrdiff_t zonecount)
len += offsetlen; len += offsetlen;
} }
result[len++] = ','; 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) if (c < 0)
{ {
result[0] = '\0'; result[0] = '\0';
@ -2883,7 +2906,7 @@ stringzone(char *result, struct zone const *zpfirst, ptrdiff_t zonecount)
compat = c; compat = c;
len += strlen(result + len); len += strlen(result + len);
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) if (c < 0)
{ {
result[0] = '\0'; result[0] = '\0';
@ -2905,12 +2928,12 @@ outzone(const struct zone *zpfirst, ptrdiff_t zonecount)
useuntil; useuntil;
zic_t starttime, zic_t starttime,
untiltime; untiltime;
zic_t gmtoff;
zic_t stdoff; zic_t stdoff;
zic_t save;
zic_t year; zic_t year;
zic_t startoff; zic_t startoff;
bool startttisstd; bool startttisstd;
bool startttisgmt; bool startttisut;
int type; int type;
char *startbuf; char *startbuf;
char *ab; char *ab;
@ -2948,7 +2971,7 @@ outzone(const struct zone *zpfirst, ptrdiff_t zonecount)
* startttisstd. * startttisstd.
*/ */
startttisstd = false; startttisstd = false;
startttisgmt = false; startttisut = false;
min_year = max_year = EPOCH_YEAR; min_year = max_year = EPOCH_YEAR;
if (leapseen) if (leapseen)
{ {
@ -2977,14 +3000,14 @@ outzone(const struct zone *zpfirst, ptrdiff_t zonecount)
*/ */
compat = stringzone(envvar, zpfirst, zonecount); compat = stringzone(envvar, zpfirst, zonecount);
version = compat < 2013 ? ZIC_VERSION_PRE_2013 : ZIC_VERSION; 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 (noise)
{ {
if (!*envvar) if (!*envvar)
warning("%s %s", warning("%s %s",
_("no POSIX environment variable for zone"), _("no POSIX environment variable for zone"),
zpfirst->z_name); 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 * 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; 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; max_year0 = max_year;
if (max_year < 2038) if (want_bloat())
max_year = 2038; {
/*
* 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) for (i = 0; i < zonecount; ++i)
{ {
struct rule *prevrp = NULL;
/* /*
* A guess that may well be corrected later. * A guess that may well be corrected later.
*/ */
stdoff = 0; save = 0;
zp = &zpfirst[i]; zp = &zpfirst[i];
usestart = i > 0 && (zp - 1)->z_untiltime > min_time; usestart = i > 0 && (zp - 1)->z_untiltime > min_time;
useuntil = i < (zonecount - 1); useuntil = i < (zonecount - 1);
if (useuntil && zp->z_untiltime <= min_time) if (useuntil && zp->z_untiltime <= min_time)
continue; continue;
gmtoff = zp->z_gmtoff; stdoff = zp->z_stdoff;
eat(zp->z_filename, zp->z_linenum); eat(zp->z_filename, zp->z_linenum);
*startbuf = '\0'; *startbuf = '\0';
startoff = zp->z_gmtoff; startoff = zp->z_stdoff;
if (zp->z_nrules == 0) if (zp->z_nrules == 0)
{ {
stdoff = zp->z_stdoff; save = zp->z_save;
doabbr(startbuf, zp, NULL, zp->z_isdst, stdoff, false); doabbr(startbuf, zp, NULL, zp->z_isdst, save, false);
type = addtype(oadd(zp->z_gmtoff, stdoff), type = addtype(oadd(zp->z_stdoff, save),
startbuf, zp->z_isdst, startttisstd, startbuf, zp->z_isdst, startttisstd,
startttisgmt); startttisut);
if (usestart) if (usestart)
{ {
addtt(starttime, type); addtt(starttime, type);
@ -3109,16 +3138,16 @@ outzone(const struct zone *zpfirst, ptrdiff_t zonecount)
if (useuntil) if (useuntil)
{ {
/* /*
* Turn untiltime into UT assuming the current gmtoff * Turn untiltime into UT assuming the current stdoff
* and stdoff values. * and save values.
*/ */
untiltime = zp->z_untiltime; untiltime = zp->z_untiltime;
if (!zp->z_untilrule.r_todisgmt) if (!zp->z_untilrule.r_todisut)
untiltime = tadd(untiltime,
-gmtoff);
if (!zp->z_untilrule.r_todisstd)
untiltime = tadd(untiltime, untiltime = tadd(untiltime,
-stdoff); -stdoff);
if (!zp->z_untilrule.r_todisstd)
untiltime = tadd(untiltime,
-save);
} }
/* /*
@ -3133,9 +3162,9 @@ outzone(const struct zone *zpfirst, ptrdiff_t zonecount)
continue; continue;
eats(zp->z_filename, zp->z_linenum, eats(zp->z_filename, zp->z_linenum,
rp->r_filename, rp->r_linenum); rp->r_filename, rp->r_linenum);
offset = rp->r_todisgmt ? 0 : gmtoff; offset = rp->r_todisut ? 0 : stdoff;
if (!rp->r_todisstd) if (!rp->r_todisstd)
offset = oadd(offset, stdoff); offset = oadd(offset, save);
jtime = rp->r_temp; jtime = rp->r_temp;
if (jtime == min_time || if (jtime == min_time ||
jtime == max_time) jtime == max_time)
@ -3166,41 +3195,46 @@ outzone(const struct zone *zpfirst, ptrdiff_t zonecount)
rp->r_todo = false; rp->r_todo = false;
if (useuntil && ktime >= untiltime) if (useuntil && ktime >= untiltime)
break; break;
stdoff = rp->r_stdoff; save = rp->r_save;
if (usestart && ktime == starttime) if (usestart && ktime == starttime)
usestart = false; usestart = false;
if (usestart) if (usestart)
{ {
if (ktime < starttime) if (ktime < starttime)
{ {
startoff = oadd(zp->z_gmtoff, startoff = oadd(zp->z_stdoff,
stdoff); save);
doabbr(startbuf, zp, doabbr(startbuf, zp,
rp->r_abbrvar, rp->r_abbrvar,
rp->r_isdst, rp->r_isdst,
rp->r_stdoff, rp->r_save,
false); false);
continue; continue;
} }
if (*startbuf == '\0' && if (*startbuf == '\0'
startoff == oadd(zp->z_gmtoff, && startoff == oadd(zp->z_stdoff,
stdoff)) save))
{ {
doabbr(startbuf, doabbr(startbuf,
zp, zp,
rp->r_abbrvar, rp->r_abbrvar,
rp->r_isdst, rp->r_isdst,
rp->r_stdoff, rp->r_save,
false); false);
} }
} }
eats(zp->z_filename, zp->z_linenum, eats(zp->z_filename, zp->z_linenum,
rp->r_filename, rp->r_linenum); rp->r_filename, rp->r_linenum);
doabbr(ab, zp, rp->r_abbrvar, doabbr(ab, zp, rp->r_abbrvar,
rp->r_isdst, rp->r_stdoff, false); rp->r_isdst, rp->r_save, false);
offset = oadd(zp->z_gmtoff, rp->r_stdoff); 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, 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) if (defaulttype < 0 && !rp->r_isdst)
defaulttype = type; defaulttype = type;
if (rp->r_hiyear == ZIC_MAX if (rp->r_hiyear == ZIC_MAX
@ -3208,6 +3242,7 @@ outzone(const struct zone *zpfirst, ptrdiff_t zonecount)
&& ktime < attypes[lastatmax].at)) && ktime < attypes[lastatmax].at))
lastatmax = timecnt; lastatmax = timecnt;
addtt(ktime, type); addtt(ktime, type);
prevrp = rp;
} }
} }
if (usestart) 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")); error(_("cannot determine time zone abbreviation to use just after until time"));
else else
{ {
bool isdst = startoff != zp->z_gmtoff; bool isdst = startoff != zp->z_stdoff;
type = addtype(startoff, startbuf, isdst, type = addtype(startoff, startbuf, isdst,
startttisstd, startttisgmt); startttisstd, startttisut);
if (defaulttype < 0 && !isdst) if (defaulttype < 0 && !isdst)
defaulttype = type; defaulttype = type;
addtt(starttime, type); addtt(starttime, type);
@ -3238,12 +3273,12 @@ outzone(const struct zone *zpfirst, ptrdiff_t zonecount)
if (useuntil) if (useuntil)
{ {
startttisstd = zp->z_untilrule.r_todisstd; startttisstd = zp->z_untilrule.r_todisstd;
startttisgmt = zp->z_untilrule.r_todisgmt; startttisut = zp->z_untilrule.r_todisut;
starttime = zp->z_untiltime; starttime = zp->z_untiltime;
if (!startttisstd) if (!startttisstd)
starttime = tadd(starttime, -save);
if (!startttisut)
starttime = tadd(starttime, -stdoff); starttime = tadd(starttime, -stdoff);
if (!startttisgmt)
starttime = tadd(starttime, -gmtoff);
} }
} }
if (defaulttype < 0) if (defaulttype < 0)
@ -3295,22 +3330,31 @@ addtt(zic_t starttime, int type)
} }
static int 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, int i,
j; j;
/* if (!(-1L - 2147483647L <= utoff && utoff <= 2147483647L))
* 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] && error(_("UT offset out of range"));
strcmp(abbr, &chars[abbrinds[i]]) == 0 && exit(EXIT_FAILURE);
ttisstd == ttisstds[i] && }
ttisgmt == ttisgmts[i]) if (!want_bloat())
return i; 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;
} }
/* /*
@ -3321,23 +3365,12 @@ addtype(zic_t gmtoff, char const *abbr, bool isdst, bool ttisstd, bool ttisgmt)
error(_("too many local time types")); error(_("too many local time types"));
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
if (!(-1L - 2147483647L <= gmtoff && gmtoff <= 2147483647L)) i = typecnt++;
{ utoffs[i] = utoff;
error(_("UT offset out of range"));
exit(EXIT_FAILURE);
}
gmtoffs[i] = gmtoff;
isdsts[i] = isdst; isdsts[i] = isdst;
ttisstds[i] = ttisstd; ttisstds[i] = ttisstd;
ttisgmts[i] = ttisgmt; ttisuts[i] = ttisut;
desigidx[i] = j;
for (j = 0; j < charcnt; ++j)
if (strcmp(&chars[j], abbr) == 0)
break;
if (j == charcnt)
newabbr(abbr);
abbrinds[i] = j;
++typecnt;
return i; return i;
} }
@ -3671,9 +3704,9 @@ byword(const char *word, const struct lookup *table)
return NULL; /* multiple inexact matches */ return NULL; /* multiple inexact matches */
} }
/* Warn about any backward-compatibility issue with pre-2017c zic. */ if (foundlp && noise)
if (foundlp)
{ {
/* Warn about any backward-compatibility issue with pre-2017c zic. */
bool pre_2017c_match = false; bool pre_2017c_match = false;
for (lp = table; lp->l_word; lp++) for (lp = table; lp->l_word; lp++)