File indexing completed on 2024-05-05 09:02:08
0001 /* 0002 SPDX-FileCopyrightText: 1998-2007 Sebastian Trueg <trueg@k3b.org> 0003 SPDX-License-Identifier: GPL-2.0-or-later 0004 */ 0005 0006 #include "k3bversion.h" 0007 0008 #include <QDebug> 0009 #include <QRegExp> 0010 #include <QRegularExpression> 0011 #include <QSharedData> 0012 0013 namespace { 0014 /** 0015 * splits the leading number from s and puts it in num 0016 * the dot is removed and the rest put in suffix 0017 * if s does not start with a digit or the first non-digit char is not a dot 0018 * suffix = s and num = -1 is returned 0019 */ 0020 void splitVersionString( const QString& s, int& num, QString& suffix ) 0021 { 0022 static const QRegularExpression rx("\\D"); 0023 int pos = s.indexOf( rx ); 0024 if( pos < 0 ) { 0025 num = s.toInt(); 0026 suffix = ""; 0027 } 0028 else if( pos == 0 ) { 0029 num = -1; 0030 suffix = s; 0031 } 0032 else { 0033 num = s.left( pos ).toInt(); 0034 suffix = s.mid( pos ); 0035 } 0036 } 0037 } 0038 0039 0040 class K3b::Version::Private : public QSharedData 0041 { 0042 public: 0043 Private() 0044 : m_majorVersion( -1 ), 0045 m_minorVersion( -1 ), 0046 m_patchLevel( -1 ) { 0047 } 0048 0049 QString m_versionString; 0050 int m_majorVersion; 0051 int m_minorVersion; 0052 int m_patchLevel; 0053 QString m_suffix; 0054 }; 0055 0056 0057 0058 K3b::Version::Version() 0059 :d( new Private() ) 0060 { 0061 } 0062 0063 0064 K3b::Version::Version( const K3b::Version& v ) 0065 { 0066 d = v.d; 0067 } 0068 0069 0070 K3b::Version::Version( const QString& version ) 0071 :d( new Private() ) 0072 { 0073 setVersion( version ); 0074 } 0075 0076 0077 K3b::Version::Version( int majorVersion, 0078 int minorVersion, 0079 int patchlevel, 0080 const QString& suffix ) 0081 :d( new Private() ) 0082 { 0083 setVersion( majorVersion, minorVersion, patchlevel, suffix ); 0084 } 0085 0086 0087 K3b::Version::~Version() 0088 { 0089 } 0090 0091 0092 K3b::Version& K3b::Version::operator=( const Version& other ) 0093 { 0094 d = other.d; 0095 return *this; 0096 } 0097 0098 0099 QString K3b::Version::toString() const { return d->m_versionString; } 0100 QString K3b::Version::versionString() const { return d->m_versionString; } 0101 int K3b::Version::majorVersion() const { return d->m_majorVersion; } 0102 int K3b::Version::minorVersion() const { return d->m_minorVersion; } 0103 int K3b::Version::patchLevel() const { return d->m_patchLevel; } 0104 QString K3b::Version::suffix() const { return d->m_suffix; } 0105 0106 0107 void K3b::Version::setVersion( const QString& v ) 0108 { 0109 QString suffix; 0110 splitVersionString( v.trimmed(), d->m_majorVersion, suffix ); 0111 if( d->m_majorVersion >= 0 ) { 0112 if( suffix.startsWith('.') ) { 0113 suffix = suffix.mid( 1 ); 0114 splitVersionString( suffix, d->m_minorVersion, suffix ); 0115 if( d->m_minorVersion < 0 ) { 0116 qDebug() << "(K3b::Version) suffix must not start with a dot!"; 0117 d->m_majorVersion = -1; 0118 d->m_minorVersion = -1; 0119 d->m_patchLevel = -1; 0120 d->m_suffix = ""; 0121 } 0122 else { 0123 if( suffix.startsWith('.') ) { 0124 suffix = suffix.mid( 1 ); 0125 splitVersionString( suffix, d->m_patchLevel, suffix ); 0126 if( d->m_patchLevel < 0 ) { 0127 qDebug() << "(K3b::Version) suffix must not start with a dot!"; 0128 d->m_majorVersion = -1; 0129 d->m_minorVersion = -1; 0130 d->m_patchLevel = -1; 0131 d->m_suffix = ""; 0132 } 0133 else { 0134 d->m_suffix = suffix; 0135 } 0136 } 0137 else { 0138 d->m_patchLevel = -1; 0139 d->m_suffix = suffix; 0140 } 0141 } 0142 } 0143 else { 0144 d->m_minorVersion = -1; 0145 d->m_patchLevel = -1; 0146 d->m_suffix = suffix; 0147 } 0148 } 0149 0150 d->m_versionString = createVersionString( d->m_majorVersion, d->m_minorVersion, d->m_patchLevel, d->m_suffix ); 0151 } 0152 0153 0154 bool K3b::Version::isValid() const 0155 { 0156 return (d->m_majorVersion >= 0); 0157 } 0158 0159 0160 void K3b::Version::setVersion( int majorVersion, 0161 int minorVersion, 0162 int patchlevel, 0163 const QString& suffix ) 0164 { 0165 d->m_majorVersion = majorVersion; 0166 d->m_minorVersion = minorVersion; 0167 d->m_patchLevel = patchlevel; 0168 d->m_suffix = suffix; 0169 d->m_versionString = createVersionString( majorVersion, minorVersion, patchlevel, suffix ); 0170 } 0171 0172 K3b::Version& K3b::Version::operator=( const QString& v ) 0173 { 0174 setVersion( v ); 0175 return *this; 0176 } 0177 0178 K3b::Version K3b::Version::simplify() const 0179 { 0180 K3b::Version v( *this ); 0181 v.d->m_suffix.truncate(0); 0182 return v; 0183 } 0184 0185 QString K3b::Version::createVersionString( int majorVersion, 0186 int minorVersion, 0187 int patchlevel, 0188 const QString& suffix ) 0189 { 0190 if( majorVersion >= 0 ) { 0191 QString s = QString::number(majorVersion); 0192 0193 if( minorVersion > -1 ) { 0194 s.append( QString(".%1").arg(minorVersion) ); 0195 if( patchlevel > -1 ) 0196 s.append( QString(".%1").arg(patchlevel) ); 0197 } 0198 0199 if( !suffix.isNull() ) 0200 s.append( suffix ); 0201 0202 return s; 0203 } 0204 else 0205 return ""; 0206 } 0207 0208 0209 int K3b::Version::compareSuffix( const QString& suffix1, const QString& suffix2 ) 0210 { 0211 static QRegExp rcRx( "rc(\\d+)" ); 0212 static QRegExp preRx( "pre(\\d+)" ); 0213 static QRegExp betaRx( "beta(\\d+)" ); 0214 static QRegExp alphaRx( "a(?:lpha)?(\\d+)" ); 0215 0216 // first we check if one of the suffixes (or both are empty) because that case if simple 0217 if( suffix1.isEmpty() ) { 0218 if( suffix2.isEmpty() ) 0219 return 0; 0220 else 0221 return 1; // empty greater than the non-empty (should we treat something like 1.0a as greater than 1.0?) 0222 } 0223 else if( suffix2.isEmpty() ) 0224 return -1; 0225 0226 // now search for our special suffixes 0227 if( rcRx.exactMatch( suffix1 ) ) { 0228 int v1 = rcRx.cap(1).toInt(); 0229 0230 if( rcRx.exactMatch( suffix2 ) ) { 0231 int v2 = rcRx.cap(1).toInt(); 0232 return ( v1 == v2 ? 0 : ( v1 < v2 ? -1 : 1 ) ); 0233 } 0234 else if( preRx.exactMatch( suffix2 ) || 0235 betaRx.exactMatch( suffix2 ) || 0236 alphaRx.exactMatch( suffix2 ) ) 0237 return 1; // rc > than all the others 0238 else 0239 return QString::compare( suffix1, suffix2 ); 0240 } 0241 0242 else if( preRx.exactMatch( suffix1 ) ) { 0243 int v1 = preRx.cap(1).toInt(); 0244 0245 if( rcRx.exactMatch( suffix2 ) ) { 0246 return -1; // pre is less than rc 0247 } 0248 else if( preRx.exactMatch( suffix2 ) ) { 0249 int v2 = preRx.cap(1).toInt(); 0250 return ( v1 == v2 ? 0 : ( v1 < v2 ? -1 : 1 ) ); 0251 } 0252 else if( betaRx.exactMatch( suffix2 ) || 0253 alphaRx.exactMatch( suffix2 ) ) 0254 return 1; // pre is greater than beta or alpha 0255 else 0256 return QString::compare( suffix1, suffix2 ); 0257 } 0258 0259 else if( betaRx.exactMatch( suffix1 ) ) { 0260 int v1 = betaRx.cap(1).toInt(); 0261 0262 if( rcRx.exactMatch( suffix2 ) || 0263 preRx.exactMatch( suffix2 ) ) 0264 return -1; // beta is less than rc or pre 0265 else if( betaRx.exactMatch( suffix2 ) ) { 0266 int v2 = betaRx.cap(1).toInt(); 0267 return ( v1 == v2 ? 0 : ( v1 < v2 ? -1 : 1 ) ); 0268 } 0269 else if( alphaRx.exactMatch( suffix2 ) ) 0270 return 1; // beta is greater then alpha 0271 else 0272 return QString::compare( suffix1, suffix2 ); 0273 } 0274 0275 else if( alphaRx.exactMatch( suffix1 ) ) { 0276 int v1 = alphaRx.cap(1).toInt(); 0277 0278 if( rcRx.exactMatch( suffix2 ) || 0279 preRx.exactMatch( suffix2 ) || 0280 betaRx.exactMatch( suffix2 ) ) 0281 return -1; // alpha is less than all the others 0282 else if( alphaRx.exactMatch( suffix2 ) ) { 0283 int v2 = alphaRx.cap(1).toInt(); 0284 return ( v1 == v2 ? 0 : ( v1 < v2 ? -1 : 1 ) ); 0285 } 0286 else 0287 return QString::compare( suffix1, suffix2 ); 0288 } 0289 0290 else 0291 return QString::compare( suffix1, suffix2 ); 0292 } 0293 0294 0295 bool K3b::operator<( const K3b::Version& v1, const K3b::Version& v2 ) 0296 { 0297 // both version objects need to be valid 0298 0299 if( v1.majorVersion() == v2.majorVersion() ) { 0300 0301 // 1 == 1.0 0302 if( ( v1.minorVersion() == v2.minorVersion() ) 0303 || 0304 ( v1.minorVersion() == -1 && v2.minorVersion() == 0 ) 0305 || 0306 ( v2.minorVersion() == -1 && v1.minorVersion() == 0 ) 0307 ) 0308 { 0309 // 1.0 == 1.0.0 0310 if( ( v1.patchLevel() == v2.patchLevel() ) 0311 || 0312 ( v1.patchLevel() == -1 && v2.patchLevel() == 0 ) 0313 || 0314 ( v2.patchLevel() == -1 && v1.patchLevel() == 0 ) 0315 ) 0316 { 0317 return K3b::Version::compareSuffix( v1.suffix(), v2.suffix() ) < 0; 0318 } 0319 else 0320 return ( v1.patchLevel() < v2.patchLevel() ); 0321 } 0322 else 0323 return ( v1.minorVersion() < v2.minorVersion() ); 0324 } 0325 else 0326 return ( v1.majorVersion() < v2.majorVersion() ); 0327 } 0328 0329 0330 bool K3b::operator>( const K3b::Version& v1, const K3b::Version& v2 ) 0331 { 0332 return operator<( v2, v1 ); 0333 } 0334 0335 0336 bool K3b::operator==( const K3b::Version& v1, const K3b::Version& v2 ) 0337 { 0338 return ( v1.majorVersion() == v2.majorVersion() && 0339 v1.minorVersion() == v2.minorVersion() && 0340 v1.patchLevel() == v2.patchLevel() && 0341 K3b::Version::compareSuffix( v1.suffix(), v2.suffix() ) == 0 ); 0342 } 0343 0344 0345 bool K3b::operator<=( const K3b::Version& v1, const K3b::Version& v2 ) 0346 { 0347 return ( operator<( v1, v2 ) || operator==( v1, v2 ) ); 0348 } 0349 0350 0351 bool K3b::operator>=( const K3b::Version& v1, const K3b::Version& v2 ) 0352 { 0353 return ( operator>( v1, v2 ) || operator==( v1, v2 ) ); 0354 }