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 )
206 if( ! str::regex_match( vr_r.begin(), vr_r.end(), what, _rxVR ) )
207 ZYPP_THROW( Exception(string("Invalid version/release: ")+vr_r) );
212 std::string _version;
213 std::string _release;
215 static const str::regex _rxVR;
216 static const str::regex _rxEdition;
218 ///////////////////////////////////////////////////////////////////
220 const str::regex Edition::Impl::_rxVR( "([^-]*)" );
222 const str::regex Edition::Impl::_rxEdition( "(([0-9]+):)?([^-]*)(-([^-]*))?" );
224 ///////////////////////////////////////////////////////////////////
226 ///////////////////////////////////////////////////////////////////
228 // CLASS NAME : Edition
230 ///////////////////////////////////////////////////////////////////
232 const Edition Edition::noedition;
234 ///////////////////////////////////////////////////////////////////
240 Edition::Edition( const std::string & edition_r )
241 : _pimpl( new Impl( edition_r ) )
244 Edition::Edition( const std::string & version_r,
245 const std::string & release_r,
247 : _pimpl( new Impl( version_r, release_r, epoch_r ) )
250 Edition::Edition( const std::string & version_r,
251 const std::string & release_r,
252 const std::string & epoch_r )
253 : _pimpl( new Impl( version_r, release_r, epoch_r ) )
259 Edition::epoch_t Edition::epoch() const
260 { return _pimpl->_epoch; }
262 const std::string & Edition::version() const
263 { return _pimpl->_version; }
265 const std::string & Edition::release() const
266 { return _pimpl->_release; }
268 std::string Edition::asString() const
272 if ( _pimpl->_epoch )
273 ret += str::form( "%d:", _pimpl->_epoch );
275 ret += _pimpl->_version;
277 if ( ! _pimpl->_release.empty() )
280 ret += _pimpl->_release;
289 int Edition::compare( const Edition & lhs, const Edition & rhs )
292 if ( lhs.epoch() != rhs.epoch() )
293 return lhs.epoch() < rhs.epoch() ? -1 : 1;
295 // next compare versions
296 int res = rpmverscmp( lhs.version(), rhs.version() );
298 return res; // -1|1: not equal
300 return rpmverscmp( lhs.release(), rhs.release() );
303 int Edition::match( const Edition & lhs, const Edition & rhs )
306 if ( lhs.epoch() != rhs.epoch() )
307 return lhs.epoch() < rhs.epoch() ? -1 : 1;
309 // next compare versions
310 if ( lhs.version().empty() || rhs.version().empty() )
313 int res = rpmverscmp( lhs.version(), rhs.version() );
315 return res; // -1|1: not equal
317 // finaly compare releases
318 if ( lhs.release().empty() || rhs.release().empty() )
321 return rpmverscmp( lhs.release(), rhs.release() );
324 /////////////////////////////////////////////////////////////////
326 ///////////////////////////////////////////////////////////////////