Edition.cc

Go to the documentation of this file.
00001 /*---------------------------------------------------------------------\
00002 |                          ____ _   __ __ ___                          |
00003 |                         |__  / \ / / . \ . \                         |
00004 |                           / / \ V /|  _/  _/                         |
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   //    hidden details
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       // equal?
00049       if ( lhs == rhs )  return 0;
00050 
00051       // empty is less than anything else:
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       // split strings into segments of alpha or digit
00065       // sequences and compare them accordingly.
00066       while ( *one && *two ) {
00067 
00068         // skip non alphanumerical chars
00069         while ( *one && ! isalnum( *one ) ) ++one;
00070         while ( *two && ! isalnum( *two ) ) ++two;
00071         if ( ! ( *one && *two ) )
00072           break; // reached end of string
00073 
00074         // remember segment start
00075         str1 = one;
00076         str2 = two;
00077 
00078         // jump over segment, type determined by str1
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         // one == str1 -> can't be as strings are not empty
00090         // two == str2 -> mixed segment types
00091         if ( two == str2 ) return( isnum ? 1 : -1 );
00092 
00093         // compare according to segment type
00094         if ( isnum ) {
00095           // atoi() may overflow on long segments
00096           // skip leading zeros
00097           while ( *one == '0' ) ++one;
00098           while ( *two == '0' ) ++two;
00099           // compare number of digits
00100           num1 = str1 - one;
00101           num2 = str2 - two;
00102           if ( num1 != num2 ) return( num1 < num2 ? -1 : 1 );
00103         }
00104 
00105         // strcmp() compares alpha AND equal sized number segments
00106         // temp. \0-terminate segment
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         // restore original strings
00116         *str1 = oldch1;
00117         *str2 = oldch2;
00118 
00119         // prepare for next cycle
00120         one = str1;
00121         two = str2;
00122       }
00123 
00124       // check which strings are now empty
00125       if ( !*one ) {
00126         return( !*two ? 0 : -1 );
00127       }
00128       return 1;
00129     }
00130   } // namespace
00132 
00134   //
00135   //    CLASS NAME : Edition::Impl
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           // what[2] contains the epoch
00154           // what[3] contains the version
00155           // what[5] contains the release
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   //    CLASS NAME : Edition
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     // compare epoch
00292     if ( lhs.epoch() != rhs.epoch() )
00293       return lhs.epoch() < rhs.epoch() ? -1 : 1;
00294 
00295     // next compare versions
00296     int res = rpmverscmp( lhs.version(), rhs.version() );
00297     if ( res )
00298       return res; // -1|1: not equal
00299 
00300     return rpmverscmp( lhs.release(), rhs.release() );
00301   }
00302 
00303   int Edition::match( const Edition & lhs, const Edition & rhs )
00304   {
00305     // compare epoch
00306     if ( lhs.epoch() != rhs.epoch() )
00307       return lhs.epoch() < rhs.epoch() ? -1 : 1;
00308 
00309     // next compare versions
00310     if ( lhs.version().empty() || rhs.version().empty() )
00311       return 0; //equal
00312 
00313     int res = rpmverscmp( lhs.version(), rhs.version() );
00314     if ( res )
00315       return res; // -1|1: not equal
00316 
00317     // finaly compare releases
00318     if ( lhs.release().empty() || rhs.release().empty() )
00319       return 0; //equal
00320 
00321     return rpmverscmp( lhs.release(), rhs.release() );
00322   }
00323 
00325 } // namespace zypp

Generated on Thu Jul 6 00:07:21 2006 for zypp by  doxygen 1.4.6