1 /*---------------------------------------------------------------------\
3 | |__ / \ / / . \ . \ |
8 \---------------------------------------------------------------------*/
9 /** \file zypp/Edition.cc
14 #include "zypp/base/Logger.h"
15 #include "base/String.h"
16 #include "base/Regex.h"
17 #include "base/Exception.h"
19 #include "zypp/Edition.h"
23 ///////////////////////////////////////////////////////////////////
25 { /////////////////////////////////////////////////////////////////
27 ///////////////////////////////////////////////////////////////////
31 ///////////////////////////////////////////////////////////////////
34 /** Rpm version comparison.
35 * \a lhs and \a rhs are expected to be either version or release
36 * strings. Not both separated by a '-'.
37 * \return <tt>-1,0,1</tt> if version strings are <tt>\<,==,\></tt>
40 int rpmverscmp( const std::string & lhs, const std::string & rhs )
50 if ( lhs == rhs ) return 0;
52 // empty is less than anything else:
53 if ( lhs.empty() ) return -1;
54 if ( rhs.empty() ) return 1;
56 str1 = (char*)alloca( lhs.size() + 1 );
57 str2 = (char*)alloca( rhs.size() + 1 );
59 strcpy( str1, lhs.c_str() );
60 strcpy( str2, rhs.c_str() );
65 // split strings into segments of alpha or digit
66 // sequences and compare them accordingly.
67 while ( *one && *two ) {
69 // skip non alphanumerical chars
70 while ( *one && ! isalnum( *one ) ) ++one;
71 while ( *two && ! isalnum( *two ) ) ++two;
72 if ( ! ( *one && *two ) )
73 break; // reached end of string
75 // remember segment start
79 // jump over segment, type determined by str1
80 if ( isdigit( *str1 ) ) {
81 while ( isdigit( *str1 ) ) ++str1;
82 while ( isdigit( *str2 ) ) ++str2;
85 while ( isalpha( *str1 ) ) ++str1;
86 while ( isalpha( *str2 ) ) ++str2;
90 // one == str1 -> can't be as strings are not empty
91 // two == str2 -> mixed segment types
92 if ( two == str2 ) return( isnum ? 1 : -1 );
94 // compare according to segment type
96 // atoi() may overflow on long segments
98 while ( *one == '0' ) ++one;
99 while ( *two == '0' ) ++two;
100 // compare number of digits
103 if ( num1 != num2 ) return( num1 < num2 ? -1 : 1 );
106 // strcmp() compares alpha AND equal sized number segments
107 // temp. \0-terminate segment
113 rc = strcmp( one, two );
116 // restore original strings
120 // prepare for next cycle
125 // check which strings are now empty
127 return( !*two ? 0 : -1 );
132 ///////////////////////////////////////////////////////////////////
134 ///////////////////////////////////////////////////////////////////
136 // CLASS NAME : Edition::Impl
138 /** Edition implementation.
139 * \todo Unifiy Impl in Edition::noedition and Edition::Edition()
147 Impl( const std::string & edition_r )
150 //[0-9]+:)?([^-]*)(-([^-]*))?" );
153 std::cout << "edition: " << edition_r << std::endl;
155 std::cout << str::regex_match( edition_r, what, _rxEdition ) << std::endl;
157 std::cout << "size: " << what.size() << std::endl;
159 for (int i = 1; i < what.size(); ++i)
160 std::cout << i << ": " << what[i] << std::endl;
163 if( str::regex_match( edition_r, what, _rxEdition ) && what.size() >= 3)
165 if ( what[1].size() > 1 )
166 _epoch = strtoul( what[1].c_str(), NULL, 10 );
167 if ( what[2].size() )
169 if ( what[3].size() )
174 ZYPP_THROW( Exception(string("Invalid Edition: ")+edition_r) );
178 Impl( const std::string & version_r,
179 const std::string & release_r,
182 , _version( validateVR(version_r) )
183 , _release( validateVR(release_r) )
186 Impl( const std::string & version_r,
187 const std::string & release_r,
188 const std::string & epoch_r )
189 : _epoch( validateE(epoch_r) )
190 , _version( validateVR(version_r) )
191 , _release( validateVR(release_r) )
198 /** return validated epoch ([0-9]*) or throw */
199 static epoch_t validateE( const std::string & epoch_r )
201 if ( epoch_r.empty() )
204 char * endptr = NULL;
205 epoch_t ret = strtoul( epoch_r.c_str(), &endptr, 10 );
206 if ( *endptr != '\0' )
207 ZYPP_THROW( Exception(string("Invalid eopch: ")+epoch_r) );
211 /** return validated version/release or throw */
212 static const std::string & validateVR( const std::string & vr_r )
214 if ( vr_r.find('-') != string::npos )
215 ZYPP_THROW( Exception(string("Invalid version/release: ")+vr_r) );
221 std::string _version;
222 std::string _release;
224 static const str::regex _rxEdition;
226 ///////////////////////////////////////////////////////////////////
228 const str::regex Edition::Impl::_rxEdition( "([0-9]+:)?([^-]*)(-[^-]*)?" );
230 ///////////////////////////////////////////////////////////////////
232 ///////////////////////////////////////////////////////////////////
234 // CLASS NAME : Edition
236 ///////////////////////////////////////////////////////////////////
238 const Edition Edition::noedition;
240 ///////////////////////////////////////////////////////////////////
246 Edition::Edition( const std::string & edition_r )
247 : _pimpl( new Impl( edition_r ) )
250 Edition::Edition( const std::string & version_r,
251 const std::string & release_r,
253 : _pimpl( new Impl( version_r, release_r, epoch_r ) )
256 Edition::Edition( const std::string & version_r,
257 const std::string & release_r,
258 const std::string & epoch_r )
259 : _pimpl( new Impl( version_r, release_r, epoch_r ) )
265 Edition::epoch_t Edition::epoch() const
266 { return _pimpl->_epoch; }
268 const std::string & Edition::version() const
269 { return _pimpl->_version; }
271 const std::string & Edition::release() const
272 { return _pimpl->_release; }
274 std::string Edition::asString() const
278 if ( _pimpl->_epoch )
279 ret += str::form( "%d:", _pimpl->_epoch );
281 ret += _pimpl->_version;
283 if ( ! _pimpl->_release.empty() )
286 ret += _pimpl->_release;
295 int Edition::compare( const Edition & lhs, const Edition & rhs )
298 if ( lhs.epoch() != rhs.epoch() )
299 return lhs.epoch() < rhs.epoch() ? -1 : 1;
301 // next compare versions
302 int res = rpmverscmp( lhs.version(), rhs.version() );
304 return res; // -1|1: not equal
306 return rpmverscmp( lhs.release(), rhs.release() );
309 int Edition::match( const Edition & lhs, const Edition & rhs )
312 if ( lhs.epoch() != rhs.epoch() )
313 return lhs.epoch() < rhs.epoch() ? -1 : 1;
315 // next compare versions
316 if ( lhs.version().empty() || rhs.version().empty() )
319 int res = rpmverscmp( lhs.version(), rhs.version() );
321 return res; // -1|1: not equal
323 // finaly compare releases
324 if ( lhs.release().empty() || rhs.release().empty() )
327 return rpmverscmp( lhs.release(), rhs.release() );
330 /////////////////////////////////////////////////////////////////
332 ///////////////////////////////////////////////////////////////////