1 /*---------------------------------------------------------------------\
3 | |__ / \ / / . \ . \ |
8 \---------------------------------------------------------------------*/
9 /** \file zypp/Edition.cc
14 #include "zypp/base/Logger.h"
15 #include "base/String.h"
16 #include "base/Exception.h"
18 #include "zypp/Edition.h"
22 ///////////////////////////////////////////////////////////////////
24 { /////////////////////////////////////////////////////////////////
26 ///////////////////////////////////////////////////////////////////
30 ///////////////////////////////////////////////////////////////////
33 /** Rpm version comparison.
34 * \a lhs and \a rhs are expected to be either version or release
35 * strings. Not both separated by a '-'.
36 * \return <tt>-1,0,1</tt> if version strings are <tt>\<,==,\></tt>
39 int rpmverscmp( const std::string & lhs, const std::string & rhs )
49 if ( lhs == rhs ) return 0;
51 // empty is less than anything else:
52 if ( lhs.empty() ) return -1;
53 if ( rhs.empty() ) return 1;
55 str1 = (char*)alloca( lhs.size() + 1 );
56 str2 = (char*)alloca( rhs.size() + 1 );
58 strcpy( str1, lhs.c_str() );
59 strcpy( str2, rhs.c_str() );
64 // split strings into segments of alpha or digit
65 // sequences and compare them accordingly.
66 while ( *one && *two ) {
68 // skip non alphanumerical chars
69 while ( *one && ! isalnum( *one ) ) ++one;
70 while ( *two && ! isalnum( *two ) ) ++two;
71 if ( ! ( *one && *two ) )
72 break; // reached end of string
74 // remember segment start
78 // jump over segment, type determined by str1
79 if ( isdigit( *str1 ) ) {
80 while ( isdigit( *str1 ) ) ++str1;
81 while ( isdigit( *str2 ) ) ++str2;
84 while ( isalpha( *str1 ) ) ++str1;
85 while ( isalpha( *str2 ) ) ++str2;
89 // one == str1 -> can't be as strings are not empty
90 // two == str2 -> mixed segment types
91 if ( two == str2 ) return( isnum ? 1 : -1 );
93 // compare according to segment type
95 // atoi() may overflow on long segments
97 while ( *one == '0' ) ++one;
98 while ( *two == '0' ) ++two;
99 // compare number of digits
102 if ( num1 != num2 ) return( num1 < num2 ? -1 : 1 );
105 // strcmp() compares alpha AND equal sized number segments
106 // temp. \0-terminate segment
112 rc = strcmp( one, two );
115 // restore original strings
119 // prepare for next cycle
124 // check which strings are now empty
126 return( !*two ? 0 : -1 );
131 ///////////////////////////////////////////////////////////////////
133 ///////////////////////////////////////////////////////////////////
135 // CLASS NAME : Edition::Impl
137 /** Edition implementation.
138 * \todo Unifiy Impl in Edition::noedition and Edition::Edition()
146 Impl( const std::string & edition_r )
150 if( str::regex_match( edition_r.begin(), edition_r.end(),
153 // what[2] contains the epoch
154 // what[3] contains the version
155 // what[5] contains the release
156 if ( what[2].matched )
157 _epoch = strtoul( what[2].str().c_str(), NULL, 10 );
158 if ( what[3].matched )
159 _version = what[3].str();
160 if ( what[5].matched )
161 _release = what[5].str();
165 ZYPP_THROW( Exception(string("Invalid Edition: ")+edition_r) );
169 Impl( const std::string & version_r,
170 const std::string & release_r,
173 , _version( validateVR(version_r) )
174 , _release( validateVR(release_r) )
177 Impl( const std::string & version_r,
178 const std::string & release_r,
179 const std::string & epoch_r )
180 : _epoch( validateE(epoch_r) )
181 , _version( validateVR(version_r) )
182 , _release( validateVR(release_r) )
189 /** return validated epoch ([0-9]*) or throw */
190 static epoch_t validateE( const std::string & epoch_r )
192 if ( epoch_r.empty() )
195 char * endptr = NULL;
196 epoch_t ret = strtoul( epoch_r.c_str(), &endptr, 10 );
197 if ( *endptr != '\0' )
198 ZYPP_THROW( Exception(string("Invalid eopch: ")+epoch_r) );
202 /** return validated version/release or throw */
203 static const std::string & validateVR( const std::string & vr_r )
205 if ( vr_r.find('-') != string::npos )
206 ZYPP_THROW( Exception(string("Invalid version/release: ")+vr_r) );
212 std::string _version;
213 std::string _release;
215 static const str::regex _rxEdition;
217 ///////////////////////////////////////////////////////////////////
219 const str::regex Edition::Impl::_rxEdition( "(([0-9]+):)?([^-]*)(-([^-]*))?" );
221 ///////////////////////////////////////////////////////////////////
223 ///////////////////////////////////////////////////////////////////
225 // CLASS NAME : Edition
227 ///////////////////////////////////////////////////////////////////
229 const Edition Edition::noedition;
231 ///////////////////////////////////////////////////////////////////
237 Edition::Edition( const std::string & edition_r )
238 : _pimpl( new Impl( edition_r ) )
241 Edition::Edition( const std::string & version_r,
242 const std::string & release_r,
244 : _pimpl( new Impl( version_r, release_r, epoch_r ) )
247 Edition::Edition( const std::string & version_r,
248 const std::string & release_r,
249 const std::string & epoch_r )
250 : _pimpl( new Impl( version_r, release_r, epoch_r ) )
256 Edition::epoch_t Edition::epoch() const
257 { return _pimpl->_epoch; }
259 const std::string & Edition::version() const
260 { return _pimpl->_version; }
262 const std::string & Edition::release() const
263 { return _pimpl->_release; }
265 std::string Edition::asString() const
269 if ( _pimpl->_epoch )
270 ret += str::form( "%d:", _pimpl->_epoch );
272 ret += _pimpl->_version;
274 if ( ! _pimpl->_release.empty() )
277 ret += _pimpl->_release;
286 int Edition::compare( const Edition & lhs, const Edition & rhs )
289 if ( lhs.epoch() != rhs.epoch() )
290 return lhs.epoch() < rhs.epoch() ? -1 : 1;
292 // next compare versions
293 int res = rpmverscmp( lhs.version(), rhs.version() );
295 return res; // -1|1: not equal
297 return rpmverscmp( lhs.release(), rhs.release() );
300 int Edition::match( const Edition & lhs, const Edition & rhs )
303 if ( lhs.epoch() != rhs.epoch() )
304 return lhs.epoch() < rhs.epoch() ? -1 : 1;
306 // next compare versions
307 if ( lhs.version().empty() || rhs.version().empty() )
310 int res = rpmverscmp( lhs.version(), rhs.version() );
312 return res; // -1|1: not equal
314 // finaly compare releases
315 if ( lhs.release().empty() || rhs.release().empty() )
318 return rpmverscmp( lhs.release(), rhs.release() );
321 /////////////////////////////////////////////////////////////////
323 ///////////////////////////////////////////////////////////////////