compiled newlib, need to hook up the system calls
This commit is contained in:
190
rocklibc/src/_tzcode/_PDCLIB_timesub.c
Normal file
190
rocklibc/src/_tzcode/_PDCLIB_timesub.c
Normal file
@@ -0,0 +1,190 @@
|
||||
/* _PDCLIB_timesub( const time_t *, int_fast32_t, const struct state *, struct tm * )
|
||||
|
||||
This file is part of the Public Domain C Library (PDCLib).
|
||||
Permission is granted to use, modify, and / or redistribute at will.
|
||||
*/
|
||||
|
||||
#ifndef REGTEST
|
||||
|
||||
#include "pdclib/_PDCLIB_tzcode.h"
|
||||
|
||||
/* 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_nonneg( int y )
|
||||
{
|
||||
return y / 4 - y / 100 + y / 400;
|
||||
}
|
||||
|
||||
static int leaps_thru_end_of( const int y )
|
||||
{
|
||||
return ( y < 0
|
||||
? -1 - leaps_thru_end_of_nonneg( -1 - y )
|
||||
: leaps_thru_end_of_nonneg( y ) );
|
||||
}
|
||||
|
||||
struct tm * _PDCLIB_timesub( const time_t * timep, int_fast32_t offset, const struct state * sp, struct tm * tmp )
|
||||
{
|
||||
const struct lsinfo * lp;
|
||||
time_t tdays;
|
||||
int idays; /* unsigned would be so 2003 */
|
||||
int_fast64_t rem;
|
||||
int y;
|
||||
const int * ip;
|
||||
int_fast64_t corr;
|
||||
bool hit;
|
||||
int i;
|
||||
|
||||
corr = 0;
|
||||
hit = false;
|
||||
i = ( sp == NULL ) ? 0 : sp->leapcnt;
|
||||
|
||||
while ( --i >= 0 )
|
||||
{
|
||||
lp = &sp->lsis[ i ];
|
||||
if ( *timep >= lp->trans )
|
||||
{
|
||||
corr = lp->corr;
|
||||
hit = ( *timep == lp->trans && ( i == 0 ? 0 : lp[ -1 ].corr ) < corr );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
y = EPOCH_YEAR;
|
||||
tdays = *timep / SECSPERDAY;
|
||||
rem = *timep % SECSPERDAY;
|
||||
|
||||
while ( tdays < 0 || tdays >= year_lengths[ _PDCLIB_is_leap( y ) ] )
|
||||
{
|
||||
int newy;
|
||||
time_t tdelta;
|
||||
int idelta;
|
||||
int leapdays;
|
||||
|
||||
tdelta = tdays / DAYSPERLYEAR;
|
||||
|
||||
if ( ! ( ( ! _PDCLIB_TYPE_SIGNED( time_t ) || _PDCLIB_INT_MIN <= tdelta ) && tdelta <= _PDCLIB_INT_MAX ) )
|
||||
{
|
||||
goto out_of_range;
|
||||
}
|
||||
|
||||
idelta = tdelta;
|
||||
|
||||
if ( idelta == 0 )
|
||||
{
|
||||
idelta = ( tdays < 0 ) ? -1 : 1;
|
||||
}
|
||||
|
||||
newy = y;
|
||||
|
||||
if ( _PDCLIB_increment_overflow( &newy, idelta ) )
|
||||
{
|
||||
goto out_of_range;
|
||||
}
|
||||
|
||||
leapdays = leaps_thru_end_of( newy - 1 ) - leaps_thru_end_of( y - 1 );
|
||||
tdays -= ( (time_t)newy - y ) * DAYSPERNYEAR;
|
||||
tdays -= leapdays;
|
||||
y = newy;
|
||||
}
|
||||
|
||||
/* Given the range, we can now fearlessly cast... */
|
||||
idays = tdays;
|
||||
rem += offset - corr;
|
||||
|
||||
while ( rem < 0 )
|
||||
{
|
||||
rem += SECSPERDAY;
|
||||
--idays;
|
||||
}
|
||||
|
||||
while ( rem >= SECSPERDAY )
|
||||
{
|
||||
rem -= SECSPERDAY;
|
||||
++idays;
|
||||
}
|
||||
|
||||
while ( idays < 0 )
|
||||
{
|
||||
if ( _PDCLIB_increment_overflow( &y, -1 ) )
|
||||
{
|
||||
goto out_of_range;
|
||||
}
|
||||
|
||||
idays += year_lengths[ _PDCLIB_is_leap( y ) ];
|
||||
}
|
||||
|
||||
while ( idays >= year_lengths[ _PDCLIB_is_leap( y ) ] )
|
||||
{
|
||||
idays -= year_lengths[ _PDCLIB_is_leap( y ) ];
|
||||
|
||||
if ( _PDCLIB_increment_overflow( &y, 1 ) )
|
||||
{
|
||||
goto out_of_range;
|
||||
}
|
||||
}
|
||||
|
||||
tmp->tm_year = y;
|
||||
|
||||
if ( _PDCLIB_increment_overflow( &tmp->tm_year, -TM_YEAR_BASE ) )
|
||||
{
|
||||
goto out_of_range;
|
||||
}
|
||||
|
||||
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 );
|
||||
rem %= SECSPERHOUR;
|
||||
tmp->tm_min = (int)( rem / SECSPERMIN );
|
||||
|
||||
/* A positive leap second requires a special
|
||||
representation. This uses "... ??:59:60" et seq.
|
||||
*/
|
||||
tmp->tm_sec = (int) ( rem % SECSPERMIN ) + hit;
|
||||
ip = mon_lengths[ _PDCLIB_is_leap( y ) ];
|
||||
|
||||
for ( tmp->tm_mon = 0; idays >= ip[ tmp->tm_mon ]; ++( tmp->tm_mon ) )
|
||||
{
|
||||
idays -= ip[ tmp->tm_mon ];
|
||||
}
|
||||
|
||||
tmp->tm_mday = (int)( idays + 1 );
|
||||
tmp->tm_isdst = 0;
|
||||
#ifdef TM_GMTOFF
|
||||
tmp->TM_GMTOFF = offset;
|
||||
#endif /* defined TM_GMTOFF */
|
||||
return tmp;
|
||||
|
||||
out_of_range:
|
||||
*_PDCLIB_errno_func() = _PDCLIB_EOVERFLOW;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef TEST
|
||||
|
||||
#include "_PDCLIB_test.h"
|
||||
|
||||
int main( void )
|
||||
{
|
||||
#ifndef REGTEST
|
||||
#endif
|
||||
|
||||
return TEST_RESULTS;
|
||||
}
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user