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/Regex.h"
00017 #include "base/Exception.h"
00018
00019 #include "zypp/Edition.h"
00020
00021 using namespace std;
00022
00024 namespace zypp
00025 {
00026
00028
00029
00030
00032 namespace
00033 {
00040 int rpmverscmp( const std::string & lhs, const std::string & rhs )
00041 {
00042 int num1, num2;
00043 char oldch1, oldch2;
00044 char * str1, * str2;
00045 char * one, * two;
00046 int rc;
00047 int isnum;
00048
00049
00050 if ( lhs == rhs ) return 0;
00051
00052
00053 if ( lhs.empty() ) return -1;
00054 if ( rhs.empty() ) return 1;
00055
00056 str1 = (char*)alloca( lhs.size() + 1 );
00057 str2 = (char*)alloca( rhs.size() + 1 );
00058
00059 strcpy( str1, lhs.c_str() );
00060 strcpy( str2, rhs.c_str() );
00061
00062 one = str1;
00063 two = str2;
00064
00065
00066
00067 while ( *one && *two ) {
00068
00069
00070 while ( *one && ! isalnum( *one ) ) ++one;
00071 while ( *two && ! isalnum( *two ) ) ++two;
00072 if ( ! ( *one && *two ) )
00073 break;
00074
00075
00076 str1 = one;
00077 str2 = two;
00078
00079
00080 if ( isdigit( *str1 ) ) {
00081 while ( isdigit( *str1 ) ) ++str1;
00082 while ( isdigit( *str2 ) ) ++str2;
00083 isnum = 1;
00084 } else {
00085 while ( isalpha( *str1 ) ) ++str1;
00086 while ( isalpha( *str2 ) ) ++str2;
00087 isnum = 0;
00088 }
00089
00090
00091
00092 if ( two == str2 ) return( isnum ? 1 : -1 );
00093
00094
00095 if ( isnum ) {
00096
00097
00098 while ( *one == '0' ) ++one;
00099 while ( *two == '0' ) ++two;
00100
00101 num1 = str1 - one;
00102 num2 = str2 - two;
00103 if ( num1 != num2 ) return( num1 < num2 ? -1 : 1 );
00104 }
00105
00106
00107
00108 oldch1 = *str1;
00109 *str1 = '\0';
00110 oldch2 = *str2;
00111 *str2 = '\0';
00112
00113 rc = strcmp( one, two );
00114 if ( rc ) return rc;
00115
00116
00117 *str1 = oldch1;
00118 *str2 = oldch2;
00119
00120
00121 one = str1;
00122 two = str2;
00123 }
00124
00125
00126 if ( !*one ) {
00127 return( !*two ? 0 : -1 );
00128 }
00129 return 1;
00130 }
00131 }
00133
00135
00136
00137
00141 struct Edition::Impl
00142 {
00143 Impl()
00144 : _epoch( noepoch )
00145 {}
00146
00147 Impl( const std::string & edition_r )
00148 : _epoch( noepoch )
00149 {
00150
00151 str::smatch what;
00152
00153 if( str::regex_match( edition_r, what, _rxEdition )
00154 && what[3].size() != 1)
00155 {
00156 if ( what[1].size() > 1 )
00157 _epoch = strtoul( what[1].c_str(), NULL, 10 );
00158 if ( what[2].size() )
00159 _version = what[2];
00160 if (what[3].size() )
00161 _release = what[3].substr(1);
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 if ( vr_r.find('-') != string::npos )
00206 ZYPP_THROW( Exception(string("Invalid version/release: ")+vr_r) );
00207
00208 return vr_r;
00209 }
00210
00211 epoch_t _epoch;
00212 std::string _version;
00213 std::string _release;
00214
00215 static const str::regex _rxEdition;
00216 };
00218
00219 const str::regex Edition::Impl::_rxEdition( "([0-9]+:)?([^-]*)(-[^-]*)?" );
00220
00222
00224
00225
00226
00228
00229 const Edition Edition::noedition;
00230
00232
00233 Edition::Edition()
00234 : _pimpl( new Impl )
00235 {}
00236
00237 Edition::Edition( const std::string & edition_r )
00238 : _pimpl( new Impl( edition_r ) )
00239 {}
00240
00241 Edition::Edition( const std::string & version_r,
00242 const std::string & release_r,
00243 epoch_t epoch_r )
00244 : _pimpl( new Impl( version_r, release_r, epoch_r ) )
00245 {}
00246
00247 Edition::Edition( const std::string & version_r,
00248 const std::string & release_r,
00249 const std::string & epoch_r )
00250 : _pimpl( new Impl( version_r, release_r, epoch_r ) )
00251 {}
00252
00253 Edition::~Edition()
00254 {}
00255
00256 Edition::epoch_t Edition::epoch() const
00257 { return _pimpl->_epoch; }
00258
00259 const std::string & Edition::version() const
00260 { return _pimpl->_version; }
00261
00262 const std::string & Edition::release() const
00263 { return _pimpl->_release; }
00264
00265 std::string Edition::asString() const
00266 {
00267 string ret;
00268
00269 if ( _pimpl->_epoch )
00270 ret += str::form( "%d:", _pimpl->_epoch );
00271
00272 ret += _pimpl->_version;
00273
00274 if ( ! _pimpl->_release.empty() )
00275 {
00276 ret += '-';
00277 ret += _pimpl->_release;
00278 }
00279
00280 if ( ret.empty() )
00281 return "";
00282
00283 return ret;
00284 }
00285
00286 int Edition::compare( const Edition & lhs, const Edition & rhs )
00287 {
00288
00289 if ( lhs.epoch() != rhs.epoch() )
00290 return lhs.epoch() < rhs.epoch() ? -1 : 1;
00291
00292
00293 int res = rpmverscmp( lhs.version(), rhs.version() );
00294 if ( res )
00295 return res;
00296
00297 return rpmverscmp( lhs.release(), rhs.release() );
00298 }
00299
00300 int Edition::match( const Edition & lhs, const Edition & rhs )
00301 {
00302
00303 if ( lhs.epoch() != rhs.epoch() )
00304 return lhs.epoch() < rhs.epoch() ? -1 : 1;
00305
00306
00307 if ( lhs.version().empty() || rhs.version().empty() )
00308 return 0;
00309
00310 int res = rpmverscmp( lhs.version(), rhs.version() );
00311 if ( res )
00312 return res;
00313
00314
00315 if ( lhs.release().empty() || rhs.release().empty() )
00316 return 0;
00317
00318 return rpmverscmp( lhs.release(), rhs.release() );
00319 }
00320
00322 }
00324
00325