localtime 1.81

This commit is contained in:
Corinna Vinschen 2020-04-28 21:26:45 +02:00
parent 9e29639ca0
commit 3003c3dacd
1 changed files with 101 additions and 104 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: localtime.c,v 1.80 2013/12/13 10:37:24 christos Exp $ */ /* $NetBSD: localtime.c,v 1.81 2013/12/26 18:34:28 christos Exp $ */
/* /*
** This file is in the public domain, so clarified as of ** This file is in the public domain, so clarified as of
@ -88,7 +88,7 @@ static char privatehid[] = "@(#)private.h 7.48";
#if 0 #if 0
static char elsieid[] = "@(#)localtime.cc 8.17"; static char elsieid[] = "@(#)localtime.cc 8.17";
#else #else
__RCSID("$NetBSD: localtime.c,v 1.80 2013/12/13 10:37:24 christos Exp $"); __RCSID("$NetBSD: localtime.c,v 1.81 2013/12/26 18:34:28 christos Exp $");
#endif #endif
/* /*
@ -480,7 +480,7 @@ typedef struct tm *(*subfun_t)(const timezone_t sp, const time_t *timep,
*/ */
static int_fast32_t detzcode(const char * codep); static int_fast32_t detzcode(const char * codep);
static time_t detzcode64(const char * codep); static int_fast64_t detzcode64(const char * codep);
static int differ_by_repeat(time_t t1, time_t t0); static int differ_by_repeat(time_t t1, time_t t0);
static const char * getzname(const char * strp) ATTRIBUTE_PURE; static const char * getzname(const char * strp) ATTRIBUTE_PURE;
static const char * getqzname(const char * strp, const int delim) ATTRIBUTE_PURE; static const char * getqzname(const char * strp, const int delim) ATTRIBUTE_PURE;
@ -496,6 +496,7 @@ static struct tm * localsub(const timezone_t sp, const time_t *timep,
const int_fast32_t offset, struct tm *tmp); const int_fast32_t offset, struct tm *tmp);
static int increment_overflow(int * number, int delta); static int increment_overflow(int * number, int delta);
static int increment_overflow32(int_fast32_t * number, int delta); static int increment_overflow32(int_fast32_t * number, int delta);
static int increment_overflow_time(time_t *t, int_fast32_t delta);
static int leaps_thru_end_of(int y) ATTRIBUTE_PURE; static int leaps_thru_end_of(int y) ATTRIBUTE_PURE;
static int normalize_overflow(int * tensptr, int * unitsptr, static int normalize_overflow(int * tensptr, int * unitsptr,
int base); int base);
@ -514,9 +515,9 @@ static struct tm * timesub(const timezone_t sp, const time_t * timep,
const int_fast32_t offset, struct tm * tmp); const int_fast32_t offset, struct tm * tmp);
static int tmcomp(const struct tm * atmp, static int tmcomp(const struct tm * atmp,
const struct tm * btmp); const struct tm * btmp);
static time_t transtime(time_t janfirst, int year, static int_fast32_t transtime(int year, const struct rule * rulep,
const struct rule * rulep, int_fast32_t offset)
const int_fast32_t offset) ATTRIBUTE_PURE; ATTRIBUTE_PURE;
static int typesequiv(const timezone_t sp, int a, int b); static int typesequiv(const timezone_t sp, int a, int b);
static int tzload(timezone_t sp, const char * name, static int tzload(timezone_t sp, const char * name,
int doextend); int doextend);
@ -578,7 +579,7 @@ int daylight;
#endif /* defined USG_COMPAT */ #endif /* defined USG_COMPAT */
#ifdef ALTZONE #ifdef ALTZONE
time_t altzone = 0; long altzone = 0;
#endif /* defined ALTZONE */ #endif /* defined ALTZONE */
static int_fast32_t static int_fast32_t
@ -593,15 +594,15 @@ detzcode(const char *const codep)
return result; return result;
} }
static time_t static int_fast64_t
detzcode64(const char *const codep) detzcode64(const char *const codep)
{ {
time_t result; int_fast64_t result;
int i; int i;
result = (time_t)((codep[0] & 0x80) ? (~(int_fast64_t) 0) : 0); result = (codep[0] & 0x80) ? -1 : 0;
for (i = 0; i < 8; ++i) for (i = 0; i < 8; ++i)
result = result * 256 + (codep[i] & 0xff); result = (result << 8) | (codep[i] & 0xff);
return result; return result;
} }
@ -742,6 +743,7 @@ tzload(timezone_t sp, const char *name, const int doextend)
for (stored = 4; stored <= 8; stored *= 2) { for (stored = 4; stored <= 8; stored *= 2) {
int ttisstdcnt; int ttisstdcnt;
int ttisgmtcnt; int ttisgmtcnt;
int timecnt;
ttisstdcnt = (int) detzcode(up->tzhead.tzh_ttisstdcnt); ttisstdcnt = (int) detzcode(up->tzhead.tzh_ttisstdcnt);
ttisgmtcnt = (int) detzcode(up->tzhead.tzh_ttisgmtcnt); ttisgmtcnt = (int) detzcode(up->tzhead.tzh_ttisgmtcnt);
@ -766,15 +768,36 @@ tzload(timezone_t sp, const char *name, const int doextend)
ttisstdcnt + /* ttisstds */ ttisstdcnt + /* ttisstds */
ttisgmtcnt) /* ttisgmts */ ttisgmtcnt) /* ttisgmts */
goto oops; goto oops;
timecnt = 0;
for (i = 0; i < sp->timecnt; ++i) { for (i = 0; i < sp->timecnt; ++i) {
sp->ats[i] = (time_t)((stored == 4) ? int_fast64_t at
detzcode(p) : detzcode64(p)); = stored == 4 ? detzcode(p) : detzcode64(p);
sp->types[i] = ((TYPE_SIGNED(time_t)
? time_t_min <= at
: 0 <= at)
&& at <= time_t_max);
if (sp->types[i]) {
if (i && !timecnt && at != time_t_min) {
/*
** Keep the earlier record, but tweak
** it so that it starts with the
** minimum time_t value.
*/
sp->types[i - 1] = 1;
sp->ats[timecnt++] = time_t_min;
}
//_DIAGASSERT(__type_fit(time_t, at));
sp->ats[timecnt++] = (time_t)at;
}
p += stored; p += stored;
} }
timecnt = 0;
for (i = 0; i < sp->timecnt; ++i) { for (i = 0; i < sp->timecnt; ++i) {
sp->types[i] = (unsigned char) *p++; unsigned char typ = *p++;
if (sp->types[i] >= sp->typecnt) if (sp->typecnt <= typ)
goto oops; goto oops;
if (sp->types[i])
sp->types[timecnt++] = typ;
} }
for (i = 0; i < sp->typecnt; ++i) { for (i = 0; i < sp->typecnt; ++i) {
struct ttinfo * ttisp; struct ttinfo * ttisp;
@ -830,44 +853,6 @@ tzload(timezone_t sp, const char *name, const int doextend)
} }
} }
/* /*
** 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; ++i)
if ((i < sp->timecnt - 1 &&
sp->ats[i] > sp->ats[i + 1]) ||
(i == sp->timecnt - 1 && !TYPE_SIGNED(time_t) &&
sp->ats[i] >
((stored == 4) ? INT32_MAX : INT64_MAX))) {
if (TYPE_SIGNED(time_t)) {
/*
** Ignore the end (easy).
*/
sp->timecnt = i + 1;
} else {
/*
** Ignore the beginning (harder).
*/
int j;
/*
** Keep the record right before the
** epoch boundary,
** but tweak it so that it starts
** right with the epoch
** (thanks to Doug Bailey).
*/
sp->ats[i] = 0;
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 this is an old file, we're done.
*/ */
if (up->tzhead.tzh_version[0] == '\0') if (up->tzhead.tzh_version[0] == '\0')
@ -876,9 +861,9 @@ tzload(timezone_t sp, const char *name, const int doextend)
for (i = 0; i < nread; ++i) for (i = 0; i < nread; ++i)
up->buf[i] = p[i]; up->buf[i] = p[i];
/* /*
** If this is a narrow time_t system, we're done. ** If this is a signed narrow time_t system, we're done.
*/ */
if (stored >= (int) sizeof(time_t)) if (TYPE_SIGNED(time_t) && stored >= (int) sizeof(time_t))
break; break;
} }
if (doextend && nread > 2 && if (doextend && nread > 2 &&
@ -1207,17 +1192,16 @@ getrule(const char *strp, struct rule *const rulep)
} }
/* /*
** Given the Epoch-relative time of January 1, 00:00:00 UTC, in a year, the ** Given a year, a rule, and the offset from UT at the time that rule takes
** year, a rule, and the offset from UT at the time that rule takes effect, ** effect, calculate the year-relative time that rule takes effect.
** calculate the Epoch-relative time that rule takes effect.
*/ */
static time_t static int_fast32_t
transtime(const time_t janfirst, const int year, const struct rule *const rulep, transtime(const int year, const struct rule *const rulep,
const int_fast32_t offset) const int_fast32_t offset)
{ {
int leapyear; int leapyear;
time_t value; int_fast32_t value;
int i; int i;
int d, m1, yy0, yy1, yy2, dow; int d, m1, yy0, yy1, yy2, dow;
@ -1233,7 +1217,7 @@ transtime(const time_t janfirst, const int year, const struct rule *const rulep,
** add SECSPERDAY times the day number-1 to the time of ** add SECSPERDAY times the day number-1 to the time of
** January 1, midnight, to get the day. ** January 1, midnight, to get the day.
*/ */
value = (time_t)(janfirst + (rulep->r_day - 1) * SECSPERDAY); value = (rulep->r_day - 1) * SECSPERDAY;
if (leapyear && rulep->r_day >= 60) if (leapyear && rulep->r_day >= 60)
value += SECSPERDAY; value += SECSPERDAY;
break; break;
@ -1244,16 +1228,13 @@ transtime(const time_t janfirst, const int year, const struct rule *const rulep,
** Just add SECSPERDAY times the day number to the time of ** Just add SECSPERDAY times the day number to the time of
** January 1, midnight, to get the day. ** January 1, midnight, to get the day.
*/ */
value = (time_t)(janfirst + rulep->r_day * SECSPERDAY); value = rulep->r_day * SECSPERDAY;
break; break;
case MONTH_NTH_DAY_OF_WEEK: case MONTH_NTH_DAY_OF_WEEK:
/* /*
** Mm.n.d - nth "dth day" of month m. ** Mm.n.d - nth "dth day" of month m.
*/ */
value = janfirst;
for (i = 0; i < rulep->r_mon - 1; ++i)
value += (time_t)(mon_lengths[leapyear][i] * SECSPERDAY);
/* /*
** Use Zeller's Congruence to get day-of-week of first day of ** Use Zeller's Congruence to get day-of-week of first day of
@ -1286,17 +1267,19 @@ transtime(const time_t janfirst, const int year, const struct rule *const rulep,
/* /*
** "d" is the day-of-month (zero-origin) of the day we want. ** "d" is the day-of-month (zero-origin) of the day we want.
*/ */
value += (time_t)(d * SECSPERDAY); value = d * SECSPERDAY;
for (i = 0; i < rulep->r_mon - 1; ++i)
value += mon_lengths[leapyear][i] * SECSPERDAY;
break; break;
} }
/* /*
** "value" is the Epoch-relative time of 00:00:00 UT on the day in ** "value" is the year-relative time of 00:00:00 UT on the day in
** question. To get the Epoch-relative time of the specified local ** question. To get the year-relative time of the specified local
** time on that day, add the transition time and the current offset ** time on that day, add the transition time and the current offset
** from UT. ** from UT.
*/ */
return (time_t)(value + rulep->r_time + offset); return value + rulep->r_time + offset;
} }
/* /*
@ -1313,8 +1296,6 @@ tzparse(timezone_t sp, const char *name, const int lastditch)
size_t dstlen; size_t dstlen;
int_fast32_t stdoffset; int_fast32_t stdoffset;
int_fast32_t dstoffset; int_fast32_t dstoffset;
time_t * atp;
unsigned char * typep;
char * cp; char * cp;
int load_result; int load_result;
@ -1373,9 +1354,8 @@ tzparse(timezone_t sp, const char *name, const int lastditch)
struct rule end; struct rule end;
int year; int year;
int yearlim; int yearlim;
int timecnt;
time_t janfirst; time_t janfirst;
time_t starttime;
time_t endtime;
++name; ++name;
if ((name = getrule(name, &start)) == NULL) if ((name = getrule(name, &start)) == NULL)
@ -1397,43 +1377,44 @@ tzparse(timezone_t sp, const char *name, const int lastditch)
sp->ttis[1].tt_gmtoff = -stdoffset; sp->ttis[1].tt_gmtoff = -stdoffset;
sp->ttis[1].tt_isdst = 0; sp->ttis[1].tt_isdst = 0;
sp->ttis[1].tt_abbrind = 0; sp->ttis[1].tt_abbrind = 0;
atp = sp->ats; timecnt = 0;
typep = sp->types;
janfirst = 0; janfirst = 0;
sp->timecnt = 0; sp->timecnt = 0;
yearlim = EPOCH_YEAR + YEARSPERREPEAT; yearlim = EPOCH_YEAR + YEARSPERREPEAT;
for (year = EPOCH_YEAR; year < yearlim; year++) { for (year = EPOCH_YEAR; year < yearlim; year++) {
int_fast32_t yearsecs; int_fast32_t
starttime = transtime(year, &start, stdoffset),
starttime = transtime(janfirst, year, &start, endtime = transtime(year, &end, dstoffset);
stdoffset); int_fast32_t
endtime = transtime(janfirst, year, &end, yearsecs = (year_lengths[isleap(year)]
dstoffset); * SECSPERDAY);
yearsecs = (year_lengths[isleap(year)] int reversed = endtime < starttime;
* SECSPERDAY); if (reversed) {
if (starttime > endtime int_fast32_t swap = starttime;
starttime = endtime;
endtime = swap;
}
if (reversed
|| (starttime < endtime || (starttime < endtime
&& (endtime - starttime && (endtime - starttime
< (yearsecs < (yearsecs
+ (stdoffset - dstoffset))))) { + (stdoffset - dstoffset))))) {
if (&sp->ats[TZ_MAX_TIMES - 2] < atp) if (TZ_MAX_TIMES - 2 < timecnt)
break; break;
yearlim = year + YEARSPERREPEAT + 1; yearlim = year + YEARSPERREPEAT + 1;
if (starttime > endtime) { sp->ats[timecnt] = janfirst;
*atp++ = endtime; if (increment_overflow_time
*typep++ = 1; /* DST ends */ (&sp->ats[timecnt], starttime))
*atp++ = starttime; break;
*typep++ = 0; /* DST begins */ sp->types[timecnt++] = reversed;
} else { sp->ats[timecnt] = janfirst;
*atp++ = starttime; if (increment_overflow_time
*typep++ = 0; /* DST begins */ (&sp->ats[timecnt], endtime))
*atp++ = endtime; break;
*typep++ = 1; /* DST ends */ sp->types[timecnt++] = !reversed;
}
} }
if (time_t_max - janfirst < yearsecs) if (increment_overflow_time(&janfirst, yearsecs))
break; break;
janfirst += (time_t)yearsecs;
} }
/* /*
** Get zone offsets into tzinfo (for newlib). . . ** Get zone offsets into tzinfo (for newlib). . .
@ -1445,9 +1426,8 @@ tzparse(timezone_t sp, const char *name, const int lastditch)
__gettzinfo ()->__tzrule[1].offset __gettzinfo ()->__tzrule[1].offset
= -sp->ttis[0].tt_gmtoff; = -sp->ttis[0].tt_gmtoff;
} }
//_DIAGASSERT(__type_fit(int, atp - sp->ats)); sp->timecnt = timecnt;
sp->timecnt = (int)(atp - sp->ats); if (!timecnt)
if (!sp->timecnt)
sp->typecnt = 1; /* Perpetual DST. */ sp->typecnt = 1; /* Perpetual DST. */
} else { } else {
int_fast32_t theirstdoffset; int_fast32_t theirstdoffset;
@ -2013,7 +1993,8 @@ timesub(const timezone_t sp, const time_t *const timep,
if (! ((! TYPE_SIGNED(time_t) || INT_MIN <= tdelta) if (! ((! TYPE_SIGNED(time_t) || INT_MIN <= tdelta)
&& tdelta <= INT_MAX)) && tdelta <= INT_MAX))
return NULL; return NULL;
idelta = tdelta; //_DIAGASSERT(__type_fit(int, tdelta));
idelta = (int)tdelta;
if (idelta == 0) if (idelta == 0)
idelta = (tdays < 0) ? -1 : 1; idelta = (tdays < 0) ? -1 : 1;
newy = y; newy = y;
@ -2162,6 +2143,22 @@ increment_overflow32(int_fast32_t *const lp, int const m)
return FALSE; return FALSE;
} }
static int
increment_overflow_time(time_t *tp, int_fast32_t j)
{
/*
** This is like
** 'if (! (time_t_min <= *tp + j && *tp + j <= time_t_max)) ...',
** except that it does the right thing even if *tp + j would overflow.
*/
if (! (j < 0
? (TYPE_SIGNED(time_t) ? time_t_min - j <= *tp : -1 - j < *tp)
: *tp <= time_t_max - j))
return TRUE;
*tp += j;
return FALSE;
}
static int static int
normalize_overflow(int *const tensptr, int *const unitsptr, const int base) normalize_overflow(int *const tensptr, int *const unitsptr, const int base)
{ {