#include "tzfile.h"#include "pgtime.h"

Go to the source code of this file.
Data Structures | |
| struct | ttinfo |
| struct | lsinfo |
| struct | state |
| struct | pg_tz |
Defines | |
| #define | BIGGEST(a, b) (((a) > (b)) ? (a) : (b)) |
Functions | |
| int | pg_open_tzfile (const char *name, char *canonname) |
| int | tzload (const char *name, char *canonname, struct state *sp, int doextend) |
| int | tzparse (const char *name, struct state *sp, int lastditch) |
| int pg_open_tzfile | ( | const char * | name, | |
| char * | canonname | |||
| ) |
Definition at line 64 of file findtimezone.c.
References MAXPGPATH, PG_BINARY, pg_TZDIR(), scan_directory_ci(), strlcpy(), and TZ_STRLEN_MAX.
Referenced by tzload().
| int tzload | ( | const char * | name, | |
| char * | canonname, | |||
| struct state * | sp, | |||
| int | doextend | |||
| ) |
Definition at line 153 of file localtime.c.
References state::ats, buf, state::charcnt, state::chars, close, detzcode(), detzcode64(), differ_by_repeat(), FALSE, state::goahead, state::goback, i, state::leapcnt, lsinfo::ls_corr, lsinfo::ls_trans, state::lsis, NULL, pg_open_tzfile(), read, state::timecnt, TRUE, ttinfo::tt_abbrind, ttinfo::tt_gmtoff, ttinfo::tt_isdst, ttinfo::tt_ttisgmt, ttinfo::tt_ttisstd, state::ttis, TYPE_INTEGRAL, TYPE_SIGNED, state::typecnt, state::types, typesequiv(), TZ_MAX_CHARS, TZ_MAX_LEAPS, TZ_MAX_TIMES, TZ_MAX_TYPES, TZDEFAULT, and tzparse().
Referenced by gmtload(), pg_load_tz(), pg_tzenumerate_next(), pg_tzset(), and tzparse().
{
const char *p;
int i;
int fid;
int stored;
int nread;
union
{
struct tzhead tzhead;
char buf[2 * sizeof(struct tzhead) +
2 * sizeof *sp +
4 * TZ_MAX_TIMES];
} u;
sp->goback = sp->goahead = FALSE;
if (name == NULL && (name = TZDEFAULT) == NULL)
return -1;
if (name[0] == ':')
++name;
fid = pg_open_tzfile(name, canonname);
if (fid < 0)
return -1;
nread = read(fid, u.buf, sizeof u.buf);
if (close(fid) != 0 || nread <= 0)
return -1;
for (stored = 4; stored <= 8; stored *= 2)
{
int ttisstdcnt;
int ttisgmtcnt;
ttisstdcnt = (int) detzcode(u.tzhead.tzh_ttisstdcnt);
ttisgmtcnt = (int) detzcode(u.tzhead.tzh_ttisgmtcnt);
sp->leapcnt = (int) detzcode(u.tzhead.tzh_leapcnt);
sp->timecnt = (int) detzcode(u.tzhead.tzh_timecnt);
sp->typecnt = (int) detzcode(u.tzhead.tzh_typecnt);
sp->charcnt = (int) detzcode(u.tzhead.tzh_charcnt);
p = u.tzhead.tzh_charcnt + sizeof u.tzhead.tzh_charcnt;
if (sp->leapcnt < 0 || sp->leapcnt > TZ_MAX_LEAPS ||
sp->typecnt <= 0 || sp->typecnt > TZ_MAX_TYPES ||
sp->timecnt < 0 || sp->timecnt > TZ_MAX_TIMES ||
sp->charcnt < 0 || sp->charcnt > TZ_MAX_CHARS ||
(ttisstdcnt != sp->typecnt && ttisstdcnt != 0) ||
(ttisgmtcnt != sp->typecnt && ttisgmtcnt != 0))
return -1;
if (nread - (p - u.buf) <
sp->timecnt * stored + /* ats */
sp->timecnt + /* types */
sp->typecnt * 6 + /* ttinfos */
sp->charcnt + /* chars */
sp->leapcnt * (stored + 4) + /* lsinfos */
ttisstdcnt + /* ttisstds */
ttisgmtcnt) /* ttisgmts */
return -1;
for (i = 0; i < sp->timecnt; ++i)
{
sp->ats[i] = (stored == 4) ? detzcode(p) : detzcode64(p);
p += stored;
}
for (i = 0; i < sp->timecnt; ++i)
{
sp->types[i] = (unsigned char) *p++;
if (sp->types[i] >= sp->typecnt)
return -1;
}
for (i = 0; i < sp->typecnt; ++i)
{
struct ttinfo *ttisp;
ttisp = &sp->ttis[i];
ttisp->tt_gmtoff = detzcode(p);
p += 4;
ttisp->tt_isdst = (unsigned char) *p++;
if (ttisp->tt_isdst != 0 && ttisp->tt_isdst != 1)
return -1;
ttisp->tt_abbrind = (unsigned char) *p++;
if (ttisp->tt_abbrind < 0 ||
ttisp->tt_abbrind > sp->charcnt)
return -1;
}
for (i = 0; i < sp->charcnt; ++i)
sp->chars[i] = *p++;
sp->chars[i] = '\0'; /* ensure '\0' at end */
for (i = 0; i < sp->leapcnt; ++i)
{
struct lsinfo *lsisp;
lsisp = &sp->lsis[i];
lsisp->ls_trans = (stored == 4) ? detzcode(p) : detzcode64(p);
p += stored;
lsisp->ls_corr = detzcode(p);
p += 4;
}
for (i = 0; i < sp->typecnt; ++i)
{
struct ttinfo *ttisp;
ttisp = &sp->ttis[i];
if (ttisstdcnt == 0)
ttisp->tt_ttisstd = FALSE;
else
{
ttisp->tt_ttisstd = *p++;
if (ttisp->tt_ttisstd != TRUE &&
ttisp->tt_ttisstd != FALSE)
return -1;
}
}
for (i = 0; i < sp->typecnt; ++i)
{
struct ttinfo *ttisp;
ttisp = &sp->ttis[i];
if (ttisgmtcnt == 0)
ttisp->tt_ttisgmt = FALSE;
else
{
ttisp->tt_ttisgmt = *p++;
if (ttisp->tt_ttisgmt != TRUE &&
ttisp->tt_ttisgmt != FALSE)
return -1;
}
}
/*
* Out-of-sort ats should mean we're running on a signed time_t system
* but using a data file with unsigned values (or vice versa).
*/
for (i = 0; i < sp->timecnt - 2; ++i)
if (sp->ats[i] > sp->ats[i + 1])
{
++i;
if (TYPE_SIGNED(pg_time_t))
{
/*
* Ignore the end (easy).
*/
sp->timecnt = i;
}
else
{
/*
* Ignore the beginning (harder).
*/
int j;
for (j = 0; j + i < sp->timecnt; ++j)
{
sp->ats[j] = sp->ats[j + i];
sp->types[j] = sp->types[j + i];
}
sp->timecnt = j;
}
break;
}
/*
* If this is an old file, we're done.
*/
if (u.tzhead.tzh_version[0] == '\0')
break;
nread -= p - u.buf;
for (i = 0; i < nread; ++i)
u.buf[i] = p[i];
/*
* If this is a narrow integer time_t system, we're done.
*/
if (stored >= (int) sizeof(pg_time_t) && TYPE_INTEGRAL(pg_time_t))
break;
}
if (doextend && nread > 2 &&
u.buf[0] == '\n' && u.buf[nread - 1] == '\n' &&
sp->typecnt + 2 <= TZ_MAX_TYPES)
{
struct state ts;
int result;
u.buf[nread - 1] = '\0';
result = tzparse(&u.buf[1], &ts, FALSE);
if (result == 0 && ts.typecnt == 2 &&
sp->charcnt + ts.charcnt <= TZ_MAX_CHARS)
{
for (i = 0; i < 2; ++i)
ts.ttis[i].tt_abbrind +=
sp->charcnt;
for (i = 0; i < ts.charcnt; ++i)
sp->chars[sp->charcnt++] =
ts.chars[i];
i = 0;
while (i < ts.timecnt &&
ts.ats[i] <=
sp->ats[sp->timecnt - 1])
++i;
while (i < ts.timecnt &&
sp->timecnt < TZ_MAX_TIMES)
{
sp->ats[sp->timecnt] =
ts.ats[i];
sp->types[sp->timecnt] =
sp->typecnt +
ts.types[i];
++sp->timecnt;
++i;
}
sp->ttis[sp->typecnt++] = ts.ttis[0];
sp->ttis[sp->typecnt++] = ts.ttis[1];
}
}
if (sp->timecnt > 1)
{
for (i = 1; i < sp->timecnt; ++i)
if (typesequiv(sp, sp->types[i], sp->types[0]) &&
differ_by_repeat(sp->ats[i], sp->ats[0]))
{
sp->goback = TRUE;
break;
}
for (i = sp->timecnt - 2; i >= 0; --i)
if (typesequiv(sp, sp->types[sp->timecnt - 1],
sp->types[i]) &&
differ_by_repeat(sp->ats[sp->timecnt - 1],
sp->ats[i]))
{
sp->goahead = TRUE;
break;
}
}
return 0;
}
| int tzparse | ( | const char * | name, | |
| struct state * | sp, | |||
| int | lastditch | |||
| ) |
Definition at line 711 of file localtime.c.
References state::ats, state::charcnt, state::chars, EPOCH_YEAR, FALSE, getoffset(), getqzname(), getrule(), getzname(), state::goahead, state::goback, i, isleap, state::leapcnt, NULL, state::timecnt, transtime(), ttinfo::tt_abbrind, ttinfo::tt_gmtoff, ttinfo::tt_isdst, ttinfo::tt_ttisgmt, ttinfo::tt_ttisstd, state::ttis, state::typecnt, state::types, TZDEFRULES, tzload(), and year_lengths.
Referenced by gmtload(), pg_load_tz(), pg_tzset(), and tzload().
{
const char *stdname;
const char *dstname = NULL;
size_t stdlen;
size_t dstlen;
long stdoffset;
long dstoffset;
pg_time_t *atp;
unsigned char *typep;
char *cp;
int load_result;
stdname = name;
if (lastditch)
{
stdlen = strlen(name); /* length of standard zone name */
name += stdlen;
if (stdlen >= sizeof sp->chars)
stdlen = (sizeof sp->chars) - 1;
stdoffset = 0;
/*
* Unlike the original zic library, do NOT invoke tzload() here; we
* can't assume pg_open_tzfile() is sane yet, and we don't care about
* leap seconds anyway.
*/
sp->goback = sp->goahead = FALSE;
load_result = -1;
}
else
{
if (*name == '<')
{
name++;
stdname = name;
name = getqzname(name, '>');
if (*name != '>')
return (-1);
stdlen = name - stdname;
name++;
}
else
{
name = getzname(name);
stdlen = name - stdname;
}
if (*name == '\0')
return -1;
name = getoffset(name, &stdoffset);
if (name == NULL)
return -1;
load_result = tzload(TZDEFRULES, NULL, sp, FALSE);
}
if (load_result != 0)
sp->leapcnt = 0; /* so, we're off a little */
if (*name != '\0')
{
if (*name == '<')
{
dstname = ++name;
name = getqzname(name, '>');
if (*name != '>')
return -1;
dstlen = name - dstname;
name++;
}
else
{
dstname = name;
name = getzname(name);
dstlen = name - dstname; /* length of DST zone name */
}
if (*name != '\0' && *name != ',' && *name != ';')
{
name = getoffset(name, &dstoffset);
if (name == NULL)
return -1;
}
else
dstoffset = stdoffset - SECSPERHOUR;
if (*name == '\0' && load_result != 0)
name = TZDEFRULESTRING;
if (*name == ',' || *name == ';')
{
struct rule start;
struct rule end;
int year;
pg_time_t janfirst;
pg_time_t starttime;
pg_time_t endtime;
++name;
if ((name = getrule(name, &start)) == NULL)
return -1;
if (*name++ != ',')
return -1;
if ((name = getrule(name, &end)) == NULL)
return -1;
if (*name != '\0')
return -1;
sp->typecnt = 2; /* standard time and DST */
/*
* Two transitions per year, from EPOCH_YEAR forward.
*/
sp->ttis[0].tt_gmtoff = -dstoffset;
sp->ttis[0].tt_isdst = 1;
sp->ttis[0].tt_abbrind = stdlen + 1;
sp->ttis[1].tt_gmtoff = -stdoffset;
sp->ttis[1].tt_isdst = 0;
sp->ttis[1].tt_abbrind = 0;
atp = sp->ats;
typep = sp->types;
janfirst = 0;
sp->timecnt = 0;
for (year = EPOCH_YEAR;
sp->timecnt + 2 <= TZ_MAX_TIMES;
++year)
{
pg_time_t newfirst;
starttime = transtime(janfirst, year, &start,
stdoffset);
endtime = transtime(janfirst, year, &end,
dstoffset);
if (starttime > endtime)
{
*atp++ = endtime;
*typep++ = 1; /* DST ends */
*atp++ = starttime;
*typep++ = 0; /* DST begins */
}
else
{
*atp++ = starttime;
*typep++ = 0; /* DST begins */
*atp++ = endtime;
*typep++ = 1; /* DST ends */
}
sp->timecnt += 2;
newfirst = janfirst;
newfirst += year_lengths[isleap(year)] *
SECSPERDAY;
if (newfirst <= janfirst)
break;
janfirst = newfirst;
}
}
else
{
long theirstdoffset;
long theirdstoffset;
long theiroffset;
int isdst;
int i;
int j;
if (*name != '\0')
return -1;
/*
* Initial values of theirstdoffset and theirdstoffset.
*/
theirstdoffset = 0;
for (i = 0; i < sp->timecnt; ++i)
{
j = sp->types[i];
if (!sp->ttis[j].tt_isdst)
{
theirstdoffset =
-sp->ttis[j].tt_gmtoff;
break;
}
}
theirdstoffset = 0;
for (i = 0; i < sp->timecnt; ++i)
{
j = sp->types[i];
if (sp->ttis[j].tt_isdst)
{
theirdstoffset =
-sp->ttis[j].tt_gmtoff;
break;
}
}
/*
* Initially we're assumed to be in standard time.
*/
isdst = FALSE;
theiroffset = theirstdoffset;
/*
* Now juggle transition times and types tracking offsets as you
* do.
*/
for (i = 0; i < sp->timecnt; ++i)
{
j = sp->types[i];
sp->types[i] = sp->ttis[j].tt_isdst;
if (sp->ttis[j].tt_ttisgmt)
{
/* No adjustment to transition time */
}
else
{
/*
* If summer time is in effect, and the transition time
* was not specified as standard time, add the summer time
* offset to the transition time; otherwise, add the
* standard time offset to the transition time.
*/
/*
* Transitions from DST to DDST will effectively disappear
* since POSIX provides for only one DST offset.
*/
if (isdst && !sp->ttis[j].tt_ttisstd)
{
sp->ats[i] += dstoffset -
theirdstoffset;
}
else
{
sp->ats[i] += stdoffset -
theirstdoffset;
}
}
theiroffset = -sp->ttis[j].tt_gmtoff;
if (sp->ttis[j].tt_isdst)
theirdstoffset = theiroffset;
else
theirstdoffset = theiroffset;
}
/*
* Finally, fill in ttis. ttisstd and ttisgmt need not be handled.
*/
sp->ttis[0].tt_gmtoff = -stdoffset;
sp->ttis[0].tt_isdst = FALSE;
sp->ttis[0].tt_abbrind = 0;
sp->ttis[1].tt_gmtoff = -dstoffset;
sp->ttis[1].tt_isdst = TRUE;
sp->ttis[1].tt_abbrind = stdlen + 1;
sp->typecnt = 2;
}
}
else
{
dstlen = 0;
sp->typecnt = 1; /* only standard time */
sp->timecnt = 0;
sp->ttis[0].tt_gmtoff = -stdoffset;
sp->ttis[0].tt_isdst = 0;
sp->ttis[0].tt_abbrind = 0;
}
sp->charcnt = stdlen + 1;
if (dstlen != 0)
sp->charcnt += dstlen + 1;
if ((size_t) sp->charcnt > sizeof sp->chars)
return -1;
cp = sp->chars;
(void) strncpy(cp, stdname, stdlen);
cp += stdlen;
*cp++ = '\0';
if (dstlen != 0)
{
(void) strncpy(cp, dstname, dstlen);
*(cp + dstlen) = '\0';
}
return 0;
}
1.7.1