Updated to tzcode2005c.tar.gz

git-svn-id: file:///srv/svn/repos/haiku/trunk/current@11228 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Jérôme Duval
2005-02-02 22:42:24 +00:00
parent fa12e0eeff
commit aafd5156d4
+190 -94
View File
@@ -5,7 +5,7 @@
#ifndef lint #ifndef lint
#ifndef NOID #ifndef NOID
static char elsieid[] = "@(#)localtime.c 7.80"; static char elsieid[] = "@(#)localtime.c 7.89";
#endif /* !defined NOID */ #endif /* !defined NOID */
#endif /* !defined lint */ #endif /* !defined lint */
@@ -55,7 +55,7 @@ static char elsieid[] = "@(#)localtime.c 7.80";
#define WILDABBR " " #define WILDABBR " "
#endif /* !defined WILDABBR */ #endif /* !defined WILDABBR */
static char wildabbr[] = "WILDABBR"; static char wildabbr[] = WILDABBR;
static const char gmt[] = "GMT"; static const char gmt[] = "GMT";
@@ -129,11 +129,12 @@ static const char * getsecs P((const char * strp, long * secsp));
static const char * getoffset P((const char * strp, long * offsetp)); static const char * getoffset P((const char * strp, long * offsetp));
static const char * getrule P((const char * strp, struct rule * rulep)); static const char * getrule P((const char * strp, struct rule * rulep));
static void gmtload P((struct state * sp)); static void gmtload P((struct state * sp));
static void gmtsub P((const time_t * timep, long offset, static struct tm * gmtsub P((const time_t * timep, long offset,
struct tm * tmp)); struct tm * tmp));
static void localsub P((const time_t * timep, long offset, static struct tm * localsub P((const time_t * timep, long offset,
struct tm * tmp)); struct tm * tmp));
static int increment_overflow P((int * number, int delta)); static int increment_overflow P((int * number, int delta));
static int leaps_thru_end_of P((int y));
static int long_increment_overflow P((long * number, int delta)); static int long_increment_overflow P((long * number, int delta));
static int long_normalize_overflow P((long * tensptr, static int long_normalize_overflow P((long * tensptr,
int * unitsptr, int base)); int * unitsptr, int base));
@@ -141,18 +142,18 @@ static int normalize_overflow P((int * tensptr, int * unitsptr,
int base)); int base));
static void settzname P((void)); static void settzname P((void));
static time_t time1 P((struct tm * tmp, static time_t time1 P((struct tm * tmp,
void(*funcp) P((const time_t *, struct tm * (*funcp) P((const time_t *,
long, struct tm *)), long, struct tm *)),
long offset)); long offset));
static time_t time2 P((struct tm *tmp, static time_t time2 P((struct tm *tmp,
void(*funcp) P((const time_t *, struct tm * (*funcp) P((const time_t *,
long, struct tm*)), long, struct tm*)),
long offset, int * okayp)); long offset, int * okayp));
static time_t time2sub P((struct tm *tmp, static time_t time2sub P((struct tm *tmp,
void(*funcp) P((const time_t *, struct tm * (*funcp) P((const time_t *,
long, struct tm*)), long, struct tm*)),
long offset, int * okayp, int do_norm_secs)); long offset, int * okayp, int do_norm_secs));
static void timesub P((const time_t * timep, long offset, static struct tm * timesub P((const time_t * timep, long offset,
const struct state * sp, struct tm * tmp)); const struct state * sp, struct tm * tmp));
static int tmcomp P((const struct tm * atmp, static int tmcomp P((const struct tm * atmp,
const struct tm * btmp)); const struct tm * btmp));
@@ -409,6 +410,33 @@ register struct state * const sp;
return -1; 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(time_t)) {
/*
** Ignore the end (easy).
*/
sp->timecnt = i;
} else {
/*
** Ignore the beginning (harder).
*/
register 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;
}
} }
return 0; return 0;
} }
@@ -1010,7 +1038,7 @@ tzset P((void))
*/ */
/*ARGSUSED*/ /*ARGSUSED*/
static void static struct tm *
localsub(timep, offset, tmp) localsub(timep, offset, tmp)
const time_t * const timep; const time_t * const timep;
const long offset; const long offset;
@@ -1019,14 +1047,13 @@ struct tm * const tmp;
register struct state * sp; register struct state * sp;
register const struct ttinfo * ttisp; register const struct ttinfo * ttisp;
register int i; register int i;
register struct tm * result;
const time_t t = *timep; const time_t t = *timep;
sp = lclptr; sp = lclptr;
#ifdef ALL_STATE #ifdef ALL_STATE
if (sp == NULL) { if (sp == NULL)
gmtsub(timep, offset, tmp); return gmtsub(timep, offset, tmp);
return;
}
#endif /* defined ALL_STATE */ #endif /* defined ALL_STATE */
if (sp->timecnt == 0 || t < sp->ats[0]) { if (sp->timecnt == 0 || t < sp->ats[0]) {
i = 0; i = 0;
@@ -1039,7 +1066,7 @@ struct tm * const tmp;
for (i = 1; i < sp->timecnt; ++i) for (i = 1; i < sp->timecnt; ++i)
if (t < sp->ats[i]) if (t < sp->ats[i])
break; break;
i = sp->types[i - 1]; i = (int) sp->types[i - 1];
} }
ttisp = &sp->ttis[i]; ttisp = &sp->ttis[i];
/* /*
@@ -1048,12 +1075,13 @@ struct tm * const tmp;
** t += ttisp->tt_gmtoff; ** t += ttisp->tt_gmtoff;
** timesub(&t, 0L, sp, tmp); ** timesub(&t, 0L, sp, tmp);
*/ */
timesub(&t, ttisp->tt_gmtoff, sp, tmp); result = timesub(&t, ttisp->tt_gmtoff, sp, tmp);
tmp->tm_isdst = ttisp->tt_isdst; tmp->tm_isdst = ttisp->tt_isdst;
tzname[tmp->tm_isdst] = &sp->chars[ttisp->tt_abbrind]; tzname[tmp->tm_isdst] = &sp->chars[ttisp->tt_abbrind];
#ifdef TM_ZONE #ifdef TM_ZONE
tmp->TM_ZONE = &sp->chars[ttisp->tt_abbrind]; tmp->TM_ZONE = &sp->chars[ttisp->tt_abbrind];
#endif /* defined TM_ZONE */ #endif /* defined TM_ZONE */
return result;
} }
struct tm * struct tm *
@@ -1061,8 +1089,7 @@ localtime(timep)
const time_t * const timep; const time_t * const timep;
{ {
tzset(); tzset();
localsub(timep, 0L, &tm); return localsub(timep, 0L, &tm);
return &tm;
} }
/* /*
@@ -1070,24 +1097,25 @@ const time_t * const timep;
*/ */
struct tm * struct tm *
localtime_r(timep, tm) localtime_r(timep, tmp)
const time_t * const timep; const time_t * const timep;
struct tm * tm; struct tm * tmp;
{ {
localsub(timep, 0L, tm); return localsub(timep, 0L, tmp);
return tm;
} }
/* /*
** gmtsub is to gmtime as localsub is to localtime. ** gmtsub is to gmtime as localsub is to localtime.
*/ */
static void static struct tm *
gmtsub(timep, offset, tmp) gmtsub(timep, offset, tmp)
const time_t * const timep; const time_t * const timep;
const long offset; const long offset;
struct tm * const tmp; struct tm * const tmp;
{ {
register struct tm * result;
if (!gmt_is_set) { if (!gmt_is_set) {
gmt_is_set = TRUE; gmt_is_set = TRUE;
#ifdef ALL_STATE #ifdef ALL_STATE
@@ -1096,7 +1124,7 @@ struct tm * const tmp;
#endif /* defined ALL_STATE */ #endif /* defined ALL_STATE */
gmtload(gmtptr); gmtload(gmtptr);
} }
timesub(timep, offset, gmtptr, tmp); result = timesub(timep, offset, gmtptr, tmp);
#ifdef TM_ZONE #ifdef TM_ZONE
/* /*
** Could get fancy here and deliver something such as ** Could get fancy here and deliver something such as
@@ -1116,14 +1144,14 @@ struct tm * const tmp;
#endif /* State Farm */ #endif /* State Farm */
} }
#endif /* defined TM_ZONE */ #endif /* defined TM_ZONE */
return result;
} }
struct tm * struct tm *
gmtime(timep) gmtime(timep)
const time_t * const timep; const time_t * const timep;
{ {
gmtsub(timep, 0L, &tm); return gmtsub(timep, 0L, &tm);
return &tm;
} }
/* /*
@@ -1131,12 +1159,11 @@ const time_t * const timep;
*/ */
struct tm * struct tm *
gmtime_r(timep, tm) gmtime_r(timep, tmp)
const time_t * const timep; const time_t * const timep;
struct tm * tm; struct tm * tmp;
{ {
gmtsub(timep, 0L, tm); return gmtsub(timep, 0L, tmp);
return tm;
} }
#ifdef STD_INSPIRED #ifdef STD_INSPIRED
@@ -1146,13 +1173,25 @@ offtime(timep, offset)
const time_t * const timep; const time_t * const timep;
const long offset; const long offset;
{ {
gmtsub(timep, offset, &tm); return gmtsub(timep, offset, &tm);
return &tm;
} }
#endif /* defined STD_INSPIRED */ #endif /* defined STD_INSPIRED */
static void /*
** Return the number of leap years through the end of the given year
** where, to make the math easy, the answer for year zero is defined as zero.
*/
static int
leaps_thru_end_of(y)
register const int y;
{
return (y >= 0) ? (y / 4 - y / 100 + y / 400) :
-(leaps_thru_end_of(-(y + 1)) + 1);
}
static struct tm *
timesub(timep, offset, sp, tmp) timesub(timep, offset, sp, tmp)
const time_t * const timep; const time_t * const timep;
const long offset; const long offset;
@@ -1160,10 +1199,10 @@ register const struct state * const sp;
register struct tm * const tmp; register struct tm * const tmp;
{ {
register const struct lsinfo * lp; register const struct lsinfo * lp;
register long days; register time_t tdays;
register int idays; /* unsigned would be so 2003 */
register long rem; register long rem;
register long y; int y;
register int yleap;
register const int * ip; register const int * ip;
register long corr; register long corr;
register int hit; register int hit;
@@ -1197,60 +1236,93 @@ register struct tm * const tmp;
break; break;
} }
} }
days = *timep / SECSPERDAY; y = EPOCH_YEAR;
rem = *timep % SECSPERDAY; tdays = *timep / SECSPERDAY;
#ifdef mc68k rem = *timep - tdays * SECSPERDAY;
if (*timep == 0x80000000) { while (tdays < 0 || tdays >= year_lengths[isleap(y)]) {
/* int newy;
** A 3B1 muffs the division on the most negative number. register time_t tdelta;
*/ register int idelta;
days = -24855; register int leapdays;
rem = -11648;
tdelta = tdays / DAYSPERLYEAR;
idelta = tdelta;
if (tdelta - idelta >= 1 || idelta - tdelta >= 1)
return NULL;
if (idelta == 0)
idelta = (tdays < 0) ? -1 : 1;
newy = y;
if (increment_overflow(&newy, idelta))
return NULL;
leapdays = leaps_thru_end_of(newy - 1) -
leaps_thru_end_of(y - 1);
tdays -= ((time_t) newy - y) * DAYSPERNYEAR;
tdays -= leapdays;
y = newy;
} }
#endif /* defined mc68k */ {
rem += (offset - corr); register long seconds;
seconds = tdays * SECSPERDAY + 0.5;
tdays = seconds / SECSPERDAY;
rem += seconds - tdays * SECSPERDAY;
}
/*
** Given the range, we can now fearlessly cast...
*/
idays = tdays;
rem += offset - corr;
while (rem < 0) { while (rem < 0) {
rem += SECSPERDAY; rem += SECSPERDAY;
--days; --idays;
} }
while (rem >= SECSPERDAY) { while (rem >= SECSPERDAY) {
rem -= SECSPERDAY; rem -= SECSPERDAY;
++days; ++idays;
} }
while (idays < 0) {
if (increment_overflow(&y, -1))
return NULL;
idays += year_lengths[isleap(y)];
}
while (idays >= year_lengths[isleap(y)]) {
idays -= year_lengths[isleap(y)];
if (increment_overflow(&y, 1))
return NULL;
}
tmp->tm_year = y;
if (increment_overflow(&tmp->tm_year, -TM_YEAR_BASE))
return NULL;
tmp->tm_yday = idays;
/*
** The "extra" mods below avoid overflow problems.
*/
tmp->tm_wday = EPOCH_WDAY +
((y - EPOCH_YEAR) % DAYSPERWEEK) *
(DAYSPERNYEAR % DAYSPERWEEK) +
leaps_thru_end_of(y - 1) -
leaps_thru_end_of(EPOCH_YEAR - 1) +
idays;
tmp->tm_wday %= DAYSPERWEEK;
if (tmp->tm_wday < 0)
tmp->tm_wday += DAYSPERWEEK;
tmp->tm_hour = (int) (rem / SECSPERHOUR); tmp->tm_hour = (int) (rem / SECSPERHOUR);
rem = rem % SECSPERHOUR; rem %= SECSPERHOUR;
tmp->tm_min = (int) (rem / SECSPERMIN); tmp->tm_min = (int) (rem / SECSPERMIN);
/* /*
** A positive leap second requires a special ** A positive leap second requires a special
** representation. This uses "... ??:59:60" et seq. ** representation. This uses "... ??:59:60" et seq.
*/ */
tmp->tm_sec = (int) (rem % SECSPERMIN) + hit; tmp->tm_sec = (int) (rem % SECSPERMIN) + hit;
tmp->tm_wday = (int) ((EPOCH_WDAY + days) % DAYSPERWEEK); ip = mon_lengths[isleap(y)];
if (tmp->tm_wday < 0) for (tmp->tm_mon = 0; idays >= ip[tmp->tm_mon]; ++(tmp->tm_mon))
tmp->tm_wday += DAYSPERWEEK; idays -= ip[tmp->tm_mon];
y = EPOCH_YEAR; tmp->tm_mday = (int) (idays + 1);
#define LEAPS_THRU_END_OF(y) ((y) / 4 - (y) / 100 + (y) / 400)
while (days < 0 || days >= (long) year_lengths[yleap = isleap(y)]) {
register long newy;
newy = y + days / DAYSPERNYEAR;
if (days < 0)
--newy;
days -= (newy - y) * DAYSPERNYEAR +
LEAPS_THRU_END_OF(newy - 1) -
LEAPS_THRU_END_OF(y - 1);
y = newy;
}
tmp->tm_year = y - TM_YEAR_BASE;
tmp->tm_yday = (int) days;
ip = mon_lengths[yleap];
for (tmp->tm_mon = 0; days >= (long) ip[tmp->tm_mon]; ++(tmp->tm_mon))
days = days - (long) ip[tmp->tm_mon];
tmp->tm_mday = (int) (days + 1);
tmp->tm_isdst = 0; tmp->tm_isdst = 0;
#ifdef TM_GMTOFF #ifdef TM_GMTOFF
tmp->TM_GMTOFF = offset; tmp->TM_GMTOFF = offset;
#endif /* defined TM_GMTOFF */ #endif /* defined TM_GMTOFF */
return tmp;
} }
@@ -1345,17 +1417,18 @@ register const struct tm * const btmp;
static time_t static time_t
time2sub(tmp, funcp, offset, okayp, do_norm_secs) time2sub(tmp, funcp, offset, okayp, do_norm_secs)
struct tm * const tmp; struct tm * const tmp;
void (* const funcp) P((const time_t*, long, struct tm*)); struct tm * (* const funcp) P((const time_t*, long, struct tm*));
const long offset; const long offset;
int * const okayp; int * const okayp;
const int do_norm_secs; const int do_norm_secs;
{ {
register const struct state * sp; register const struct state * sp;
register int dir; register int dir;
register int bits;
register int i, j; register int i, j;
register int saved_seconds; register int saved_seconds;
register long li; register long li;
register time_t lo;
register time_t hi;
long y; long y;
time_t newt; time_t newt;
time_t t; time_t t;
@@ -1429,27 +1502,49 @@ const int do_norm_secs;
yourtm.tm_sec = 0; yourtm.tm_sec = 0;
} }
/* /*
** Divide the search space in half ** Do a binary search (this works whatever time_t's type is).
** (this works whether time_t is signed or unsigned).
*/ */
bits = TYPE_BIT(time_t) - 1; if (!TYPE_SIGNED(time_t)) {
/* lo = 0;
** If time_t is signed, then 0 is just above the median, hi = lo - 1;
** assuming two's complement arithmetic. } else if (!TYPE_INTEGRAL(time_t)) {
** If time_t is unsigned, then (1 << bits) is just above the median. if (sizeof(time_t) > sizeof(float))
*/ hi = (time_t) DBL_MAX;
t = TYPE_SIGNED(time_t) ? 0 : (((time_t) 1) << bits); else hi = (time_t) FLT_MAX;
lo = -hi;
} else {
lo = 1;
for (i = 0; i < (int) TYPE_BIT(time_t) - 1; ++i)
lo *= 2;
hi = -(lo + 1);
}
for ( ; ; ) { for ( ; ; ) {
(*funcp)(&t, offset, &mytm); t = lo / 2 + hi / 2;
dir = tmcomp(&mytm, &yourtm); if (t < lo)
t = lo;
else if (t > hi)
t = hi;
if ((*funcp)(&t, offset, &mytm) == NULL) {
/*
** Assume that t is too extreme to be represented in
** a struct tm; arrange things so that it is less
** extreme on the next pass.
*/
dir = (t > 0) ? 1 : -1;
} else dir = tmcomp(&mytm, &yourtm);
if (dir != 0) { if (dir != 0) {
if (bits-- < 0) if (t == lo) {
++t;
++lo;
} else if (t == hi) {
--t;
--hi;
}
if (lo > hi)
return WRONG; return WRONG;
if (bits < 0) if (dir > 0)
--t; /* may be needed if new t is minimal */ hi = t;
else if (dir > 0) else lo = t;
t -= ((time_t) 1) << bits;
else t += ((time_t) 1) << bits;
continue; continue;
} }
if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst) if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst)
@@ -1478,7 +1573,8 @@ const int do_norm_secs;
continue; continue;
newt = t + sp->ttis[j].tt_gmtoff - newt = t + sp->ttis[j].tt_gmtoff -
sp->ttis[i].tt_gmtoff; sp->ttis[i].tt_gmtoff;
(*funcp)(&newt, offset, &mytm); if ((*funcp)(&newt, offset, &mytm) == NULL)
continue;
if (tmcomp(&mytm, &yourtm) != 0) if (tmcomp(&mytm, &yourtm) != 0)
continue; continue;
if (mytm.tm_isdst != yourtm.tm_isdst) if (mytm.tm_isdst != yourtm.tm_isdst)
@@ -1497,7 +1593,7 @@ label:
if ((newt < t) != (saved_seconds < 0)) if ((newt < t) != (saved_seconds < 0))
return WRONG; return WRONG;
t = newt; t = newt;
(*funcp)(&t, offset, tmp); if ((*funcp)(&t, offset, tmp))
*okayp = TRUE; *okayp = TRUE;
return t; return t;
} }
@@ -1505,7 +1601,7 @@ label:
static time_t static time_t
time2(tmp, funcp, offset, okayp) time2(tmp, funcp, offset, okayp)
struct tm * const tmp; struct tm * const tmp;
void (* const funcp) P((const time_t*, long, struct tm*)); struct tm * (* const funcp) P((const time_t*, long, struct tm*));
const long offset; const long offset;
int * const okayp; int * const okayp;
{ {
@@ -1523,7 +1619,7 @@ int * const okayp;
static time_t static time_t
time1(tmp, funcp, offset) time1(tmp, funcp, offset)
struct tm * const tmp; struct tm * const tmp;
void (* const funcp) P((const time_t *, long, struct tm *)); struct tm * (* const funcp) P((const time_t *, long, struct tm *));
const long offset; const long offset;
{ {
register time_t t; register time_t t;