2002-03-25 23:16:26 +03:00
/** \ingroup rpmbuild
* \ file build / parseChangelog . c
* Parse % changelog section from spec file .
*/
# include "system.h"
# include "rpmbuild.h"
# include "debug.h"
void addChangelogEntry ( Header h , time_t time , const char * name , const char * text )
{
int_32 mytime = time ; /* XXX convert to header representation */
if ( headerIsEntry ( h , RPMTAG_CHANGELOGTIME ) ) {
( void ) headerAppendEntry ( h , RPMTAG_CHANGELOGTIME , RPM_INT32_TYPE ,
& mytime , 1 ) ;
( void ) headerAppendEntry ( h , RPMTAG_CHANGELOGNAME , RPM_STRING_ARRAY_TYPE ,
& name , 1 ) ;
( void ) headerAppendEntry ( h , RPMTAG_CHANGELOGTEXT , RPM_STRING_ARRAY_TYPE ,
& text , 1 ) ;
} else {
( void ) headerAddEntry ( h , RPMTAG_CHANGELOGTIME , RPM_INT32_TYPE ,
& mytime , 1 ) ;
( void ) headerAddEntry ( h , RPMTAG_CHANGELOGNAME , RPM_STRING_ARRAY_TYPE ,
& name , 1 ) ;
( void ) headerAddEntry ( h , RPMTAG_CHANGELOGTEXT , RPM_STRING_ARRAY_TYPE ,
& text , 1 ) ;
}
}
/**
* Parse date string to seconds .
* @ param datestr date string ( e . g . ' Wed Jan 1 1997 ' )
* @ retval secs secs since the unix epoch
* @ return 0 on success , - 1 on error
*/
static int dateToTimet ( const char * datestr , /*@out@*/ time_t * secs )
/*@modifies *secs @*/
{
struct tm time ;
char * p , * pe , * q , * * idx ;
char * date = strcpy ( alloca ( strlen ( datestr ) + 1 ) , datestr ) ;
/*@observer@*/ static char * days [ ] =
{ " Sun " , " Mon " , " Tue " , " Wed " , " Thu " , " Fri " , " Sat " , NULL } ;
/*@observer@*/ static char * months [ ] =
{ " Jan " , " Feb " , " Mar " , " Apr " , " May " , " Jun " ,
" Jul " , " Aug " , " Sep " , " Oct " , " Nov " , " Dec " , NULL } ;
/*@observer@*/ static char lengths [ ] =
{ 31 , 29 , 31 , 30 , 31 , 30 , 31 , 31 , 30 , 31 , 30 , 31 } ;
memset ( & time , 0 , sizeof ( time ) ) ;
pe = date ;
/* day of week */
p = pe ; SKIPSPACE ( p ) ;
if ( * p = = ' \0 ' ) return - 1 ;
pe = p ; SKIPNONSPACE ( pe ) ; if ( * pe ! = ' \0 ' ) * pe + + = ' \0 ' ;
for ( idx = days ; * idx & & strcmp ( * idx , p ) ; idx + + )
{ } ;
if ( * idx = = NULL ) return - 1 ;
/* month */
p = pe ; SKIPSPACE ( p ) ;
if ( * p = = ' \0 ' ) return - 1 ;
pe = p ; SKIPNONSPACE ( pe ) ; if ( * pe ! = ' \0 ' ) * pe + + = ' \0 ' ;
for ( idx = months ; * idx & & strcmp ( * idx , p ) ; idx + + )
{ } ;
if ( * idx = = NULL ) return - 1 ;
time . tm_mon = idx - months ;
/* day */
p = pe ; SKIPSPACE ( p ) ;
if ( * p = = ' \0 ' ) return - 1 ;
pe = p ; SKIPNONSPACE ( pe ) ; if ( * pe ! = ' \0 ' ) * pe + + = ' \0 ' ;
/* make this noon so the day is always right (as we make this UTC) */
time . tm_hour = 12 ;
time . tm_mday = strtol ( p , & q , 10 ) ;
if ( ! ( q & & * q = = ' \0 ' ) ) return - 1 ;
if ( time . tm_mday < 0 | | time . tm_mday > lengths [ time . tm_mon ] ) return - 1 ;
/* year */
p = pe ; SKIPSPACE ( p ) ;
if ( * p = = ' \0 ' ) return - 1 ;
pe = p ; SKIPNONSPACE ( pe ) ; if ( * pe ! = ' \0 ' ) * pe + + = ' \0 ' ;
time . tm_year = strtol ( p , & q , 10 ) ;
if ( ! ( q & & * q = = ' \0 ' ) ) return - 1 ;
if ( time . tm_year < 1997 | | time . tm_year > = 3000 ) return - 1 ;
time . tm_year - = 1900 ;
* secs = mktime ( & time ) ;
if ( * secs = = - 1 ) return - 1 ;
/* adjust to GMT */
* secs + = timezone ;
return 0 ;
}
/**
* Add % changelog section to header .
* @ param h header
* @ param sb changelog strings
* @ return 0 on success
*/
static int addChangelog ( Header h , StringBuf sb )
/*@modifies h @*/
{
char * s ;
int i ;
time_t time ;
time_t lastTime = 0 ;
char * date , * name , * text , * next ;
s = getStringBuf ( sb ) ;
/* skip space */
SKIPSPACE ( s ) ;
while ( * s ! = ' \0 ' ) {
if ( * s ! = ' * ' ) {
rpmError ( RPMERR_BADSPEC ,
_ ( " %%changelog entries must start with * \n " ) ) ;
return RPMERR_BADSPEC ;
}
/* find end of line */
date = s ;
while ( * s & & * s ! = ' \n ' ) s + + ;
if ( ! * s ) {
rpmError ( RPMERR_BADSPEC , _ ( " incomplete %%changelog entry \n " ) ) ;
return RPMERR_BADSPEC ;
}
/*@-modobserver@*/
* s = ' \0 ' ;
/*@=modobserver@*/
text = s + 1 ;
/* 4 fields of date */
date + + ;
s = date ;
for ( i = 0 ; i < 4 ; i + + ) {
SKIPSPACE ( s ) ;
SKIPNONSPACE ( s ) ;
}
SKIPSPACE ( date ) ;
if ( dateToTimet ( date , & time ) ) {
rpmError ( RPMERR_BADSPEC , _ ( " bad date in %%changelog: %s \n " ) , date ) ;
return RPMERR_BADSPEC ;
}
if ( lastTime & & lastTime < time ) {
rpmError ( RPMERR_BADSPEC ,
_ ( " %%changelog not in descending chronological order \n " ) ) ;
return RPMERR_BADSPEC ;
}
lastTime = time ;
/* skip space to the name */
SKIPSPACE ( s ) ;
if ( ! * s ) {
rpmError ( RPMERR_BADSPEC , _ ( " missing name in %%changelog \n " ) ) ;
return RPMERR_BADSPEC ;
}
/* name */
name = s ;
while ( * s ! = ' \0 ' ) s + + ;
while ( s > name & & xisspace ( * s ) ) {
* s - - = ' \0 ' ;
}
if ( s = = name ) {
rpmError ( RPMERR_BADSPEC , _ ( " missing name in %%changelog \n " ) ) ;
return RPMERR_BADSPEC ;
}
/* text */
SKIPSPACE ( text ) ;
if ( ! * text ) {
rpmError ( RPMERR_BADSPEC , _ ( " no description in %%changelog \n " ) ) ;
return RPMERR_BADSPEC ;
}
/* find the next leading '*' (or eos) */
s = text ;
do {
s + + ;
} while ( * s & & ( * ( s - 1 ) ! = ' \n ' | | * s ! = ' * ' ) ) ;
next = s ;
s - - ;
/* backup to end of description */
while ( ( s > text ) & & xisspace ( * s ) ) {
* s - - = ' \0 ' ;
}
addChangelogEntry ( h , time , name , text ) ;
s = next ;
}
return 0 ;
}
int parseChangelog ( Spec spec )
{
int nextPart , res , rc ;
StringBuf sb = newStringBuf ( ) ;
/* There are no options to %changelog */
2005-10-06 22:21:40 +04:00
if ( ( rc = readLine ( spec , STRIP_COMMENTS ) ) = = 1 ) {
2002-03-25 23:16:26 +03:00
sb = freeStringBuf ( sb ) ;
return PART_NONE ;
}
if ( rc )
return rc ;
while ( ! ( nextPart = isPart ( spec - > line ) ) ) {
appendStringBuf ( sb , spec - > line ) ;
2005-10-06 22:21:40 +04:00
if ( ( rc = readLine ( spec , STRIP_COMMENTS ) ) = = 1 ) {
2002-03-25 23:16:26 +03:00
nextPart = PART_NONE ;
break ;
}
if ( rc )
return rc ;
}
res = addChangelog ( spec - > packages - > header , sb ) ;
sb = freeStringBuf ( sb ) ;
return ( res ) ? res : nextPart ;
}