@ -125,13 +125,14 @@ static void warning(const char *string,...) pg_attribute_printf(1, 2);
static void usage ( FILE * stream , int status ) pg_attribute_noreturn ( ) ;
static void addtt ( zic_t starttime , int type ) ;
static int addtype ( zic_t , char const * , bool , bool , bool ) ;
static void leapadd ( zic_t , bool , int , int ) ;
static void leapadd ( zic_t , int , int ) ;
static void adjleap ( void ) ;
static void associate ( void ) ;
static void dolink ( const char * , const char * , bool ) ;
static char * * getfields ( char * buf ) ;
static zic_t gethms ( const char * string , const char * errstring ) ;
static zic_t getsave ( char * , bool * ) ;
static void inexpires ( char * * , int ) ;
static void infile ( const char * filename ) ;
static void inleap ( char * * fields , int nfields ) ;
static void inlink ( char * * fields , int nfields ) ;
@ -202,6 +203,7 @@ static int typecnt;
# define LC_ZONE 1
# define LC_LINK 2
# define LC_LEAP 3
# define LC_EXPIRES 4
/*
* Which fields are which on a Zone line .
@ -267,6 +269,9 @@ static int typecnt;
# define LP_ROLL 6
# define LEAP_FIELDS 7
/* Expires lines are like Leap lines, except without CORR and ROLL fields. */
# define EXPIRES_FIELDS 5
/*
* Year synonyms .
*/
@ -312,6 +317,7 @@ static struct lookup const zi_line_codes[] = {
} ;
static struct lookup const leap_line_codes [ ] = {
{ " Leap " , LC_LEAP } ,
{ " Expires " , LC_EXPIRES } ,
{ NULL , 0 }
} ;
@ -584,6 +590,12 @@ static zic_t const max_time = MAXVAL(zic_t, TIME_T_BITS_IN_FILE);
static zic_t lo_time = MINVAL ( zic_t , TIME_T_BITS_IN_FILE ) ;
static zic_t hi_time = MAXVAL ( zic_t , TIME_T_BITS_IN_FILE ) ;
/* The time specified by an Expires line, or negative if no such line. */
static zic_t leapexpires = - 1 ;
/* The time specified by an #expires comment, or negative if no such line. */
static zic_t comment_leapexpires = - 1 ;
/* Set the time range of the output to TIMERANGE.
Return true if successful . */
static bool
@ -1279,7 +1291,8 @@ infile(const char *name)
}
if ( nfields = = 0 )
{
/* nothing to do */
if ( name = = leapsec & & * buf = = ' # ' )
sscanf ( buf , " #expires " INT64_FORMAT , & comment_leapexpires ) ;
}
else if ( wantcont )
{
@ -1311,6 +1324,10 @@ infile(const char *name)
inleap ( fields , nfields ) ;
wantcont = false ;
break ;
case LC_EXPIRES :
inexpires ( fields , nfields ) ;
wantcont = false ;
break ;
default : /* "cannot happen" */
fprintf ( stderr ,
_ ( " %s: panic: Invalid l_value %d \n " ) ,
@ -1634,8 +1651,8 @@ inzsub(char **fields, int nfields, bool iscont)
return hasuntil ;
}
static void
inleap ( char * * fields , int nfields )
static zic_t
getleapdatetime ( char * * fields , int nfields , bool expire_line )
{
const char * cp ;
const struct lookup * lp ;
@ -1651,11 +1668,6 @@ inleap(char **fields, int nfields)
zic_t t ;
char xs ;
if ( nfields ! = LEAP_FIELDS )
{
error ( _ ( " wrong number of fields on Leap line " ) ) ;
return ;
}
dayoff = 0 ;
cp = fields [ LP_YEAR ] ;
if ( sscanf ( cp , " %d%c " , & year , & xs ) ! = 1 )
@ -1664,13 +1676,16 @@ inleap(char **fields, int nfields)
* Leapin ' Lizards !
*/
error ( _ ( " invalid leaping year " ) ) ;
return ;
return - 1 ;
}
if ( ! expire_line )
{
if ( ! leapseen | | leapmaxyear < year )
leapmaxyear = year ;
if ( ! leapseen | | leapminyear > year )
leapminyear = year ;
leapseen = true ;
}
j = EPOCH_YEAR ;
while ( j ! = year )
{
@ -1689,7 +1704,7 @@ inleap(char **fields, int nfields)
if ( ( lp = byword ( fields [ LP_MONTH ] , mon_names ) ) = = NULL )
{
error ( _ ( " invalid month name " ) ) ;
return ;
return - 1 ;
}
month = lp - > l_value ;
j = TM_JANUARY ;
@ -1704,54 +1719,68 @@ inleap(char **fields, int nfields)
day < = 0 | | day > len_months [ isleap ( year ) ] [ month ] )
{
error ( _ ( " invalid day of month " ) ) ;
return ;
return - 1 ;
}
dayoff = oadd ( dayoff , day - 1 ) ;
if ( dayoff < min_time / SECSPERDAY )
{
error ( _ ( " time too small " ) ) ;
return ;
return - 1 ;
}
if ( dayoff > max_time / SECSPERDAY )
{
error ( _ ( " time too large " ) ) ;
return ;
return - 1 ;
}
t = dayoff * SECSPERDAY ;
tod = gethms ( fields [ LP_TIME ] , _ ( " invalid time of day " ) ) ;
cp = fields [ LP_CORR ] ;
t = tadd ( t , tod ) ;
if ( t < 0 )
error ( _ ( " leap second precedes Epoch " ) ) ;
return t ;
}
static void
inleap ( char * * fields , int nfields )
{
bool positive ;
int count ;
if ( nfields ! = LEAP_FIELDS )
error ( _ ( " wrong number of fields on Leap line " ) ) ;
else
{
zic_t t = getleapdatetime ( fields , nfields , false ) ;
if ( strcmp ( cp , " " ) = = 0 )
{ /* infile() turns "-" into "" */
positive = false ;
count = 1 ;
}
else if ( strcmp ( cp , " + " ) = = 0 )
if ( 0 < = t )
{
positive = true ;
count = 1 ;
}
struct lookup const * lp = byword ( fields [ LP_ROLL ] , leap_types ) ;
if ( ! lp )
error ( _ ( " invalid Rolling/Stationary field on Leap line " ) ) ;
else
{
error ( _ ( " illegal CORRECTION field on Leap line " ) ) ;
return ;
int correction = 0 ;
if ( ! fields [ LP_CORR ] [ 0 ] ) /* infile() turns "-" into "". */
correction = - 1 ;
else if ( strcmp ( fields [ LP_CORR ] , " + " ) = = 0 )
correction = 1 ;
else
error ( _ ( " invalid CORRECTION field on Leap line " ) ) ;
if ( correction )
leapadd ( t , correction , lp - > l_value ) ;
}
if ( ( lp = byword ( fields [ LP_ROLL ] , leap_types ) ) = = NULL )
{
error ( _ ( " illegal Rolling/Stationary field on Leap line " ) ) ;
return ;
}
t = tadd ( t , tod ) ;
if ( t < 0 )
{
error ( _ ( " leap second precedes Epoch " ) ) ;
return ;
}
leapadd ( t , positive , lp - > l_value , count ) ;
}
static void
inexpires ( char * * fields , int nfields )
{
if ( nfields ! = EXPIRES_FIELDS )
error ( _ ( " wrong number of fields on Expires line " ) ) ;
else if ( 0 < = leapexpires )
error ( _ ( " multiple Expires lines " ) ) ;
else
leapexpires = getleapdatetime ( fields , nfields , true ) ;
}
static void
@ -3369,12 +3398,11 @@ addtype(zic_t utoff, char const *abbr, bool isdst, bool ttisstd, bool ttisut)
}
static void
leapadd ( zic_t t , bool positive , int rolling , int count )
leapadd ( zic_t t , int correction , int rolling )
{
int i ,
j ;
int i ;
if ( leapcnt + ( positive ? count : 1 ) > TZ_MAX_LEAPS )
if ( TZ_MAX_LEAPS < = leapcnt )
{
error ( _ ( " too many leap seconds " ) ) ;
exit ( EXIT_FAILURE ) ;
@ -3382,19 +3410,13 @@ leapadd(zic_t t, bool positive, int rolling, int count)
for ( i = 0 ; i < leapcnt ; + + i )
if ( t < = trans [ i ] )
break ;
do
{
for ( j = leapcnt ; j > i ; - - j )
{
trans [ j ] = trans [ j - 1 ] ;
corr [ j ] = corr [ j - 1 ] ;
roll [ j ] = roll [ j - 1 ] ;
}
memmove ( & trans [ i + 1 ] , & trans [ i ] , ( leapcnt - i ) * sizeof * trans ) ;
memmove ( & corr [ i + 1 ] , & corr [ i ] , ( leapcnt - i ) * sizeof * corr ) ;
memmove ( & roll [ i + 1 ] , & roll [ i ] , ( leapcnt - i ) * sizeof * roll ) ;
trans [ i ] = t ;
corr [ i ] = positive ? 1 : - count ;
corr [ i ] = correction ;
roll [ i ] = rolling ;
+ + leapcnt ;
} while ( positive & & - - count ! = 0 ) ;
}
static void
@ -3418,6 +3440,25 @@ adjleap(void)
trans [ i ] = tadd ( trans [ i ] , last ) ;
last = corr [ i ] + = last ;
}
if ( leapexpires < 0 )
{
leapexpires = comment_leapexpires ;
if ( 0 < = leapexpires )
warning ( _ ( " \" #expires \" is obsolescent; use \" Expires \" " ) ) ;
}
if ( 0 < = leapexpires )
{
leapexpires = oadd ( leapexpires , last ) ;
if ( ! ( leapcnt = = 0 | | ( trans [ leapcnt - 1 ] < leapexpires ) ) )
{
error ( _ ( " last Leap time does not precede Expires time " ) ) ;
exit ( EXIT_FAILURE ) ;
}
if ( leapexpires < = hi_time )
hi_time = leapexpires - 1 ;
}
}
static char *