2002-03-25 23:16:26 +03:00
/** \ingroup rpmtrans
* \ file lib / rpmvercmp . c
*/
# include "system.h"
2002-03-26 01:02:39 +03:00
# include "rpmlib.h"
2002-03-25 23:16:26 +03:00
# include "debug.h"
/* compare alpha and numeric segments of two versions */
/* return 1: a is newer than b */
/* 0: a and b are the same version */
/* -1: b is newer than a */
int rpmvercmp ( const char * a , const char * b )
{
char oldch1 , oldch2 ;
char * str1 , * str2 ;
char * one , * two ;
int rc ;
int isnum ;
/* easy comparison to see if versions are identical */
if ( ! strcmp ( a , b ) ) return 0 ;
str1 = alloca ( strlen ( a ) + 1 ) ;
str2 = alloca ( strlen ( b ) + 1 ) ;
strcpy ( str1 , a ) ;
strcpy ( str2 , b ) ;
one = str1 ;
two = str2 ;
/* loop through each version segment of str1 and str2 and compare them */
while ( * one & & * two ) {
while ( * one & & ! xisalnum ( * one ) ) one + + ;
while ( * two & & ! xisalnum ( * two ) ) two + + ;
2002-03-26 02:19:22 +03:00
if ( ! * one & & ! * two )
return 0 ;
2002-03-25 23:16:26 +03:00
str1 = one ;
str2 = two ;
/* grab first completely alpha or completely numeric segment */
/* leave one and two pointing to the start of the alpha or numeric */
/* segment and walk str1 and str2 to end of segment */
2002-03-26 02:19:22 +03:00
/* Also take care of the case where the two version segments are */
/* different types: one numeric and one alpha */
2002-03-25 23:16:26 +03:00
if ( xisdigit ( * str1 ) ) {
2002-03-26 02:19:22 +03:00
if ( xisalpha ( * str2 ) ) return - 1 ;
2002-03-25 23:16:26 +03:00
while ( * str1 & & xisdigit ( * str1 ) ) str1 + + ;
while ( * str2 & & xisdigit ( * str2 ) ) str2 + + ;
isnum = 1 ;
} else {
while ( * str1 & & xisalpha ( * str1 ) ) str1 + + ;
while ( * str2 & & xisalpha ( * str2 ) ) str2 + + ;
isnum = 0 ;
}
2002-03-26 02:19:22 +03:00
/* Again, take care of the case where the two version segments are */
/* different types: one numeric and one alpha */
if ( one = = str1 ) return - 1 ;
if ( two = = str2 ) return 1 ;
2002-03-25 23:16:26 +03:00
/* save character at the end of the alpha or numeric segment */
/* so that they can be restored after the comparison */
oldch1 = * str1 ;
* str1 = ' \0 ' ;
oldch2 = * str2 ;
* str2 = ' \0 ' ;
if ( isnum ) {
/* this used to be done by converting the digit segments */
/* to ints using atoi() - it's changed because long */
/* digit segments can overflow an int - this should fix that. */
/* throw away any leading zeros - it's a number, right? */
while ( * one = = ' 0 ' ) one + + ;
while ( * two = = ' 0 ' ) two + + ;
/* whichever number has more digits wins */
if ( strlen ( one ) > strlen ( two ) ) return 1 ;
if ( strlen ( two ) > strlen ( one ) ) return - 1 ;
}
/* strcmp will return which one is greater - even if the two */
/* segments are alpha or if they are numeric. don't return */
/* if they are equal because there might be more segments to */
/* compare */
rc = strcmp ( one , two ) ;
if ( rc ) return rc ;
/* restore character that was replaced by null above */
* str1 = oldch1 ;
one = str1 ;
* str2 = oldch2 ;
two = str2 ;
}
/* this catches the case where all numeric and alpha segments have */
/* compared identically but the segment sepparating characters were */
/* different */
if ( ( ! * one ) & & ( ! * two ) ) return 0 ;
/* whichever version still has characters left over wins */
if ( ! * one ) return - 1 ; else return 1 ;
}
2002-07-20 14:39:40 +04:00
2005-10-15 18:42:24 +04:00
/* Moved from depends.c, because we use it in other places, too. */
/**
* Split EVR into epoch , version , and release components .
* @ param evr [ epoch : ] version [ - release ] string
* @ retval * ep pointer to epoch
* @ retval * vp pointer to version
* @ retval * rp pointer to release
*/
void parseEVR ( char * evr ,
/*@exposed@*/ /*@out@*/ const char * * ep ,
/*@exposed@*/ /*@out@*/ const char * * vp ,
/*@exposed@*/ /*@out@*/ const char * * rp )
/*@modifies *ep, *vp, *rp @*/
{
const char * epoch ;
const char * version ; /* assume only version is present */
const char * release ;
char * s , * se ;
s = evr ;
while ( * s & & xisdigit ( * s ) ) s + + ; /* s points to epoch terminator */
se = strrchr ( s , ' - ' ) ; /* se points to version terminator */
if ( * s = = ' : ' ) {
epoch = evr ;
* s + + = ' \0 ' ;
version = s ;
if ( * epoch = = ' \0 ' ) epoch = " 0 " ;
} else {
epoch = NULL ; /* XXX disable epoch compare if missing */
version = evr ;
}
if ( se ) {
* se + + = ' \0 ' ;
release = se ;
} else {
release = NULL ;
}
if ( ep ) * ep = epoch ;
if ( vp ) * vp = version ;
if ( rp ) * rp = release ;
}
2002-07-20 14:39:40 +04:00
/* Compare {A,B} [epoch:]version[-release] */
int
rpmEVRcmp ( const char * const aE , const char * const aV , const char * const aR ,
const char * const aDepend ,
const char * const bE , const char * const bV , const char * const bR ,
const char * const bDepend )
{
int sense = 0 ;
rpmMessage ( RPMMESS_DEBUG , " cmp e=%s, v=%s, r=%s \n and e=%s, v=%s, r=%s \n " ,
aE , aV , aR , bE , bV , bR ) ;
if ( aE & & * aE & & bE & & * bE )
sense = rpmvercmp ( aE , bE ) ;
else if ( aE & & * aE & & atol ( aE ) > 0 ) {
/* XXX legacy epoch-less requires/conflicts compatibility */
rpmMessage ( RPMMESS_DEBUG , _ ( " the \" B \" dependency needs an epoch (assuming same as \" A \" ) \n \t A %s \t B %s \n " ) ,
aDepend , bDepend ) ;
sense = 0 ;
} else if ( bE & & * bE & & atol ( bE ) > 0 )
sense = - 1 ;
if ( sense = = 0 ) {
sense = rpmvercmp ( aV , bV ) ;
if ( sense = = 0 & & aR & & * aR & & bR & & * bR ) {
sense = rpmvercmp ( aR , bR ) ;
}
}
return sense ;
}
2005-10-15 18:42:24 +04:00
int isChangeNameMoreFresh ( const char * const head ,
const char * const tail [ 3 ] )
{
int result ;
const char * evr [ 3 ] ;
const char * wordAfterEmail ;
char * copy ;
rpmMessage ( RPMMESS_DEBUG , " test: is '%s' more fresh than e=%s, v=%s, r=%s? \n " ,
head , tail [ 0 ] , tail [ 1 ] , tail [ 2 ] ) ;
/* find the next to <email> word begin */
if ( ( wordAfterEmail = strrchr ( head , ' > ' ) ) )
+ + wordAfterEmail ;
else
wordAfterEmail = head ;
while ( * wordAfterEmail & & xisspace ( * wordAfterEmail ) )
+ + wordAfterEmail ;
/* found. */
copy = xstrdup ( wordAfterEmail ) ;
parseEVR ( copy , & evr [ 0 ] , & evr [ 1 ] , & evr [ 2 ] ) ;
/* The order of two argument groups is important:
if evr [ ] ( passed as B on the second place ) has no epoch ,
rpmEVRcmp ( ) assumes the same as in tail [ ] ;
This fits our needs : the epoch may be omitted in a changelog entry ( evr [ ] )
but there are no problems in specifying it in the format ( tail [ ] ) . */
result = rpmEVRcmp ( tail [ 0 ] , tail [ 1 ] , tail [ 2 ] , " " ,
evr [ 0 ] , evr [ 1 ] , evr [ 2 ] , " " ) < 0 ;
_free ( copy ) ;
return result ;
}