00001
00002
00003
00004
00005
00006
00007
00008
00012 #include <iostream>
00013
00014 #include "zypp/base/Logger.h"
00015 #include "base/String.h"
00016 #include "base/Exception.h"
00017
00018 #include "zypp/Edition.h"
00019
00020 using namespace std;
00021
00023 namespace zypp
00024 {
00025
00027
00028
00029
00031 namespace
00032 {
00039 int rpmverscmp( const std::string & lhs, const std::string & rhs )
00040 {
00041 int num1, num2;
00042 char oldch1, oldch2;
00043 char * str1, * str2;
00044 char * one, * two;
00045 int rc;
00046 int isnum;
00047
00048
00049 if ( lhs == rhs ) return 0;
00050
00051
00052 if ( lhs.empty() ) return -1;
00053 if ( rhs.empty() ) return 1;
00054
00055 str1 = (char*)alloca( lhs.size() + 1 );
00056 str2 = (char*)alloca( rhs.size() + 1 );
00057
00058 strcpy( str1, lhs.c_str() );
00059 strcpy( str2, rhs.c_str() );
00060
00061 one = str1;
00062 two = str2;
00063
00064
00065
00066 while ( *one && *two ) {
00067
00068
00069 while ( *one && ! isalnum( *one ) ) ++one;
00070 while ( *two && ! isalnum( *two ) ) ++two;
00071 if ( ! ( *one && *two ) )
00072 break;
00073
00074
00075 str1 = one;
00076 str2 = two;
00077
00078
00079 if ( isdigit( *str1 ) ) {
00080 while ( isdigit( *str1 ) ) ++str1;
00081 while ( isdigit( *str2 ) ) ++str2;
00082 isnum = 1;
00083 } else {
00084 while ( isalpha( *str1 ) ) ++str1;
00085 while ( isalpha( *str2 ) ) ++str2;
00086 isnum = 0;
00087 }
00088
00089
00090
00091 if ( two == str2 ) return( isnum ? 1 : -1 );
00092
00093
00094 if ( isnum ) {
00095
00096
00097 while ( *one == '0' ) ++one;
00098 while ( *two == '0' ) ++two;
00099
00100 num1 = str1 - one;
00101 num2 = str2 - two;
00102 if ( num1 != num2 ) return( num1 < num2 ? -1 : 1 );
00103 }
00104
00105
00106
00107 oldch1 = *str1;
00108 *str1 = '\0';
00109 oldch2 = *str2;
00110 *str2 = '\0';
00111
00112 rc = strcmp( one, two );
00113 if ( rc ) return rc;
00114
00115
00116 *str1 = oldch1;
00117 *str2 = oldch2;
00118
00119
00120 one = str1;
00121 two = str2;
00122 }
00123
00124
00125 if ( !*one ) {
00126 return( !*two ? 0 : -1 );
00127 }
00128 return 1;
00129 }
00130 }
00132
00134
00135
00136
00140 struct Edition::Impl
00141 {
00142 Impl()
00143 : _epoch( noepoch )
00144 {}
00145
00146 Impl( const std::string & edition_r )
00147 : _epoch( noepoch )
00148 {
00149 str::smatch what;
00150 if( str::regex_match( edition_r.begin(), edition_r.end(),
00151 what, _rxEdition ) )
00152 {
00153
00154
00155
00156 if ( what[2].matched )
00157 _epoch = strtoul( what[2].str().c_str(), NULL, 10 );
00158 if ( what[3].matched )
00159 _version = what[3].str();
00160 if ( what[5].matched )
00161 _release = what[5].str();
00162 }
00163 else
00164 {
00165 ZYPP_THROW( Exception(string("Invalid Edition: ")+edition_r) );
00166 }
00167 }
00168
00169 Impl( const std::string & version_r,
00170 const std::string & release_r,
00171 epoch_t epoch_r )
00172 : _epoch( epoch_r )
00173 , _version( validateVR(version_r) )
00174 , _release( validateVR(release_r) )
00175 {}
00176
00177 Impl( const std::string & version_r,
00178 const std::string & release_r,
00179 const std::string & epoch_r )
00180 : _epoch( validateE(epoch_r) )
00181 , _version( validateVR(version_r) )
00182 , _release( validateVR(release_r) )
00183 {}
00184
00186 ~Impl()
00187 {}
00188
00190 static epoch_t validateE( const std::string & epoch_r )
00191 {
00192 if ( epoch_r.empty() )
00193 return noepoch;
00194
00195 char * endptr = NULL;
00196 epoch_t ret = strtoul( epoch_r.c_str(), &endptr, 10 );
00197 if ( *endptr != '\0' )
00198 ZYPP_THROW( Exception(string("Invalid eopch: ")+epoch_r) );
00199 return ret;
00200 }
00201
00203 static const std::string & validateVR( const std::string & vr_r )
00204 {
00205 str::smatch what;
00206 if( ! str::regex_match( vr_r.begin(), vr_r.end(), what, _rxVR ) )
00207 ZYPP_THROW( Exception(string("Invalid version/release: ")+vr_r) );
00208 return vr_r;
00209 }
00210
00211 epoch_t _epoch;
00212 std::string _version;
00213 std::string _release;
00214
00215 static const str::regex _rxVR;
00216 static const str::regex _rxEdition;
00217 };
00219
00220 const str::regex Edition::Impl::_rxVR( "([^-]*)" );
00221
00222 const str::regex Edition::Impl::_rxEdition( "(([0-9]+):)?([^-]*)(-([^-]*))?" );
00223
00225
00227
00228
00229
00231
00232 const Edition Edition::noedition;
00233
00235
00236 Edition::Edition()
00237 : _pimpl( new Impl )
00238 {}
00239
00240 Edition::Edition( const std::string & edition_r )
00241 : _pimpl( new Impl( edition_r ) )
00242 {}
00243
00244 Edition::Edition( const std::string & version_r,
00245 const std::string & release_r,
00246 epoch_t epoch_r )
00247 : _pimpl( new Impl( version_r, release_r, epoch_r ) )
00248 {}
00249
00250 Edition::Edition( const std::string & version_r,
00251 const std::string & release_r,
00252 const std::string & epoch_r )
00253 : _pimpl( new Impl( version_r, release_r, epoch_r ) )
00254 {}
00255
00256 Edition::~Edition()
00257 {}
00258
00259 Edition::epoch_t Edition::epoch() const
00260 { return _pimpl->_epoch; }
00261
00262 const std::string & Edition::version() const
00263 { return _pimpl->_version; }
00264
00265 const std::string & Edition::release() const
00266 { return _pimpl->_release; }
00267
00268 std::string Edition::asString() const
00269 {
00270 string ret;
00271
00272 if ( _pimpl->_epoch )
00273 ret += str::form( "%d:", _pimpl->_epoch );
00274
00275 ret += _pimpl->_version;
00276
00277 if ( ! _pimpl->_release.empty() )
00278 {
00279 ret += '-';
00280 ret += _pimpl->_release;
00281 }
00282
00283 if ( ret.empty() )
00284 return "";
00285
00286 return ret;
00287 }
00288
00289 int Edition::compare( const Edition & lhs, const Edition & rhs )
00290 {
00291
00292 if ( lhs.epoch() != rhs.epoch() )
00293 return lhs.epoch() < rhs.epoch() ? -1 : 1;
00294
00295
00296 int res = rpmverscmp( lhs.version(), rhs.version() );
00297 if ( res )
00298 return res;
00299
00300 return rpmverscmp( lhs.release(), rhs.release() );
00301 }
00302
00303 int Edition::match( const Edition & lhs, const Edition & rhs )
00304 {
00305
00306 if ( lhs.epoch() != rhs.epoch() )
00307 return lhs.epoch() < rhs.epoch() ? -1 : 1;
00308
00309
00310 if ( lhs.version().empty() || rhs.version().empty() )
00311 return 0;
00312
00313 int res = rpmverscmp( lhs.version(), rhs.version() );
00314 if ( res )
00315 return res;
00316
00317
00318 if ( lhs.release().empty() || rhs.release().empty() )
00319 return 0;
00320
00321 return rpmverscmp( lhs.release(), rhs.release() );
00322 }
00323
00325 }