localtime 1.78

This commit is contained in:
Corinna Vinschen 2020-04-28 21:14:01 +02:00
parent b8aa5f7a0f
commit 0a41de2725

View File

@ -1,4 +1,4 @@
/* $NetBSD: localtime.c,v 1.77 2013/07/30 15:30:37 joerg Exp $ */ /* $NetBSD: localtime.c,v 1.78 2013/09/20 19:06:54 christos Exp $ */
/* /*
** This file is in the public domain, so clarified as of ** This file is in the public domain, so clarified as of
@ -71,6 +71,11 @@ static char privatehid[] = "@(#)private.h 7.48";
#include "limits.h" /* for CHAR_BIT */ #include "limits.h" /* for CHAR_BIT */
#include "stdlib.h" #include "stdlib.h"
#include "unistd.h" /* for F_OK and R_OK */ #include "unistd.h" /* for F_OK and R_OK */
#if 0
#include <assert.h>
#endif
#define time_t_min LONG_MIN
#define time_t_max LONG_MAX
/* Unlike <ctype.h>'s isdigit, this also works if c < 0 | c > UCHAR_MAX. */ /* Unlike <ctype.h>'s isdigit, this also works if c < 0 | c > UCHAR_MAX. */
#define is_digit(c) ((unsigned)(c) - '0' <= 9) #define is_digit(c) ((unsigned)(c) - '0' <= 9)
@ -85,7 +90,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.77 2013/07/30 15:30:37 joerg Exp $"); __RCSID("$NetBSD: localtime.c,v 1.78 2013/09/20 19:06:54 christos Exp $");
#endif #endif
/* /*
@ -406,11 +411,11 @@ static const char gmt[] = "GMT";
#endif /* !defined TZDEFDST */ #endif /* !defined TZDEFDST */
struct ttinfo { /* time type information */ struct ttinfo { /* time type information */
int_fast32_t tt_gmtoff; /* UTC offset in seconds */ int_fast32_t tt_gmtoff; /* UT offset in seconds */
int tt_isdst; /* used to set tm_isdst */ int tt_isdst; /* used to set tm_isdst */
int tt_abbrind; /* abbreviation list index */ int tt_abbrind; /* abbreviation list index */
int tt_ttisstd; /* TRUE if transition is std time */ int tt_ttisstd; /* TRUE if transition is std time */
int tt_ttisgmt; /* TRUE if transition is UTC */ int tt_ttisgmt; /* TRUE if transition is UT */
}; };
struct lsinfo { /* leap second information */ struct lsinfo { /* leap second information */
@ -642,9 +647,8 @@ settzname (void)
static int static int
differ_by_repeat(const time_t t1, const time_t t0) differ_by_repeat(const time_t t1, const time_t t0)
{ {
if (TYPE_INTEGRAL(time_t) && if (TYPE_BIT(time_t) - TYPE_SIGNED(time_t) < SECSPERREPEAT_BITS)
TYPE_BIT(time_t) - TYPE_SIGNED(time_t) < SECSPERREPEAT_BITS) return 0;
return 0;
return (int_fast64_t)t1 - (int_fast64_t)t0 == SECSPERREPEAT; return (int_fast64_t)t1 - (int_fast64_t)t0 == SECSPERREPEAT;
} }
@ -864,11 +868,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 integer time_t system, we're done. ** If this is a narrow time_t system, we're done.
*/ */
if (stored >= (int) sizeof(time_t) if (stored >= (int) sizeof(time_t))
/* CONSTCOND */
&& TYPE_INTEGRAL(time_t))
break; break;
} }
if (doextend && nread > 2 && if (doextend && nread > 2 &&
@ -1191,14 +1193,14 @@ getrule(const char *strp, struct rule *const rulep)
** Time specified. ** Time specified.
*/ */
++strp; ++strp;
strp = getsecs(strp, &rulep->r_time); strp = getoffset(strp, &rulep->r_time);
} else rulep->r_time = 2 * SECSPERHOUR; /* default = 2:00:00 */ } else rulep->r_time = 2 * SECSPERHOUR; /* default = 2:00:00 */
return strp; return strp;
} }
/* /*
** Given the Epoch-relative time of January 1, 00:00:00 UTC, in a year, the ** Given the Epoch-relative time of January 1, 00:00:00 UTC, in a year, the
** year, a rule, and the offset from UTC at the time that rule takes effect, ** year, a rule, and the offset from UT at the time that rule takes effect,
** calculate the Epoch-relative time that rule takes effect. ** calculate the Epoch-relative time that rule takes effect.
*/ */
@ -1281,10 +1283,10 @@ transtime(const time_t janfirst, const int year, const struct rule *const rulep,
} }
/* /*
** "value" is the Epoch-relative time of 00:00:00 UTC on the day in ** "value" is the Epoch-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 Epoch-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 UTC. ** from UT.
*/ */
return (time_t)(value + rulep->r_time + offset); return (time_t)(value + rulep->r_time + offset);
} }
@ -1361,8 +1363,9 @@ tzparse(timezone_t sp, const char *name, const int lastditch)
if (*name == ',' || *name == ';') { if (*name == ',' || *name == ';') {
struct rule start; struct rule start;
struct rule end; struct rule end;
int year; int year;
time_t janfirst; int yearlim;
time_t janfirst;
time_t starttime; time_t starttime;
time_t endtime; time_t endtime;
@ -1390,33 +1393,39 @@ tzparse(timezone_t sp, const char *name, const int lastditch)
typep = sp->types; typep = sp->types;
janfirst = 0; janfirst = 0;
sp->timecnt = 0; sp->timecnt = 0;
for (year = EPOCH_YEAR; yearlim = EPOCH_YEAR + YEARSPERREPEAT;
sp->timecnt + 2 <= TZ_MAX_TIMES; for (year = EPOCH_YEAR; year < yearlim; year++) {
++year) { int_fast32_t yearsecs;
time_t newfirst;
starttime = transtime(janfirst, year, &start, starttime = transtime(janfirst, year, &start,
stdoffset); stdoffset);
endtime = transtime(janfirst, year, &end, endtime = transtime(janfirst, year, &end,
dstoffset); dstoffset);
if (starttime > endtime) { yearsecs = (year_lengths[isleap(year)]
*atp++ = endtime; * SECSPERDAY);
*typep++ = 1; /* DST ends */ if (starttime > endtime
*atp++ = starttime; || (starttime < endtime
*typep++ = 0; /* DST begins */ && (endtime - starttime
} else { < (yearsecs
*atp++ = starttime; + (stdoffset - dstoffset))))) {
*typep++ = 0; /* DST begins */ if (&sp->ats[TZ_MAX_TIMES - 2] < atp)
*atp++ = endtime; break;
*typep++ = 1; /* DST ends */ yearlim = year + YEARSPERREPEAT + 1;
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; if (time_t_max - janfirst < yearsecs)
newfirst = janfirst;
newfirst += (time_t)
(year_lengths[isleap(year)] * SECSPERDAY);
if (newfirst <= janfirst)
break; break;
janfirst = newfirst; janfirst += yearsecs;
} }
/* /*
** Get zone offsets into tzinfo (for newlib). . . ** Get zone offsets into tzinfo (for newlib). . .
@ -1428,6 +1437,10 @@ 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 = (int)(atp - sp->ats);
if (!sp->timecnt)
sp->typecnt = 1; /* Perpetual DST. */
} else { } else {
int_fast32_t theirstdoffset; int_fast32_t theirstdoffset;
int_fast32_t theirdstoffset; int_fast32_t theirdstoffset;
@ -1759,22 +1772,14 @@ localsub(const timezone_t sp, const time_t * const timep, const int_fast32_t off
(sp->goahead && t > sp->ats[sp->timecnt - 1])) { (sp->goahead && t > sp->ats[sp->timecnt - 1])) {
time_t newt = t; time_t newt = t;
time_t seconds; time_t seconds;
time_t tcycles; time_t years;
int_fast64_t icycles;
if (t < sp->ats[0]) if (t < sp->ats[0])
seconds = sp->ats[0] - t; seconds = sp->ats[0] - t;
else seconds = t - sp->ats[sp->timecnt - 1]; else seconds = t - sp->ats[sp->timecnt - 1];
--seconds; --seconds;
tcycles = (time_t) years = (time_t)((seconds / SECSPERREPEAT + 1) * YEARSPERREPEAT);
(seconds / YEARSPERREPEAT / AVGSECSPERYEAR); seconds = (time_t)(years * AVGSECSPERYEAR);
++tcycles;
icycles = tcycles;
if (tcycles - icycles >= 1 || icycles - tcycles >= 1)
return NULL;
seconds = (time_t) icycles;
seconds *= YEARSPERREPEAT;
seconds *= AVGSECSPERYEAR;
if (t < sp->ats[0]) if (t < sp->ats[0])
newt += seconds; newt += seconds;
else newt -= seconds; else newt -= seconds;
@ -1787,8 +1792,8 @@ localsub(const timezone_t sp, const time_t * const timep, const int_fast32_t off
newy = tmp->tm_year; newy = tmp->tm_year;
if (t < sp->ats[0]) if (t < sp->ats[0])
newy -= (time_t)icycles * YEARSPERREPEAT; newy -= years;
else newy += (time_t)icycles * YEARSPERREPEAT; else newy += years;
tmp->tm_year = (int)newy; tmp->tm_year = (int)newy;
if (tmp->tm_year != newy) if (tmp->tm_year != newy)
return NULL; return NULL;
@ -1873,7 +1878,7 @@ gmtsub(const timezone_t sp, const time_t *const timep,
#ifdef TM_ZONE #ifdef TM_ZONE
/* /*
** Could get fancy here and deliver something such as ** Could get fancy here and deliver something such as
** "UTC+xxxx" or "UTC-xxxx" if offset is non-zero, ** "UT+xxxx" or "UT-xxxx" if offset is non-zero,
** but this is no time for a treasure hunt. ** but this is no time for a treasure hunt.
*/ */
if (CYGWIN_VERSION_CHECK_FOR_EXTRA_TM_MEMBERS) if (CYGWIN_VERSION_CHECK_FOR_EXTRA_TM_MEMBERS)
@ -1997,9 +2002,10 @@ timesub(const timezone_t sp, const time_t *const timep,
int leapdays; int leapdays;
tdelta = tdays / DAYSPERLYEAR; tdelta = tdays / DAYSPERLYEAR;
idelta = (int) tdelta; if (! ((! TYPE_SIGNED(time_t) || INT_MIN <= tdelta)
if (tdelta - idelta >= 1 || idelta - tdelta >= 1) && tdelta <= INT_MAX))
return NULL; return NULL;
idelta = tdelta;
if (idelta == 0) if (idelta == 0)
idelta = (tdays < 0) ? -1 : 1; idelta = (tdays < 0) ? -1 : 1;
newy = y; newy = y;
@ -2013,9 +2019,8 @@ timesub(const timezone_t sp, const time_t *const timep,
} }
{ {
int_fast32_t seconds; int_fast32_t seconds;
const time_t half_second = (time_t)0.5;
seconds = (int_fast32_t)(tdays * SECSPERDAY + half_second); seconds = (int_fast32_t)(tdays * SECSPERDAY);
tdays = (time_t)(seconds / SECSPERDAY); tdays = (time_t)(seconds / SECSPERDAY);
rem += (int_fast64_t)(seconds - tdays * SECSPERDAY); rem += (int_fast64_t)(seconds - tdays * SECSPERDAY);
} }
@ -2179,8 +2184,9 @@ tmcomp(const struct tm *const atmp, const struct tm *const btmp)
{ {
int result; int result;
if ((result = (atmp->tm_year - btmp->tm_year)) == 0 && if (atmp->tm_year != btmp->tm_year)
(result = (atmp->tm_mon - btmp->tm_mon)) == 0 && return atmp->tm_year < btmp->tm_year ? -1 : 1;
if ((result = (atmp->tm_mon - btmp->tm_mon)) == 0 &&
(result = (atmp->tm_mday - btmp->tm_mday)) == 0 && (result = (atmp->tm_mday - btmp->tm_mday)) == 0 &&
(result = (atmp->tm_hour - btmp->tm_hour)) == 0 && (result = (atmp->tm_hour - btmp->tm_hour)) == 0 &&
(result = (atmp->tm_min - btmp->tm_min)) == 0) (result = (atmp->tm_min - btmp->tm_min)) == 0)
@ -2283,7 +2289,6 @@ again:
if (!TYPE_SIGNED(time_t)) { if (!TYPE_SIGNED(time_t)) {
lo = 0; lo = 0;
hi = lo - 1; hi = lo - 1;
/* LINTED const not */
} else { } else {
lo = 1; lo = 1;
for (i = 0; i < (int) TYPE_BIT(time_t) - 1; ++i) for (i = 0; i < (int) TYPE_BIT(time_t) - 1; ++i)
@ -2309,14 +2314,14 @@ again:
} else dir = tmcomp(&mytm, &yourtm); } else dir = tmcomp(&mytm, &yourtm);
if (dir != 0) { if (dir != 0) {
if (t == lo) { if (t == lo) {
++t; if (t == time_t_max)
if (t <= lo)
goto overflow; goto overflow;
++t;
++lo; ++lo;
} else if (t == hi) { } else if (t == hi) {
--t; if (t == time_t_min)
if (t >= hi)
goto overflow; goto overflow;
--t;
--hi; --hi;
} }
#ifdef NO_ERROR_IN_DST_GAP #ifdef NO_ERROR_IN_DST_GAP
@ -2541,8 +2546,7 @@ timeoff(struct tm *const tmp, long offset)
** previous versions of the CMUCS runtime library. ** previous versions of the CMUCS runtime library.
*/ */
extern "C" extern "C" long
int_fast32_t
gtime(struct tm *const tmp) gtime(struct tm *const tmp)
{ {
const time_t t = mktime(tmp); const time_t t = mktime(tmp);