00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #include "version.hpp"
00017 #include "serialization/string_utils.hpp"
00018 #include "util.hpp"
00019
00020 #include <cassert>
00021
00022 version_info::version_info(const version_info& o)
00023 : nums_ (o.nums_),
00024 special_ (o.special_),
00025 special_separator_ (o.special_separator_),
00026 sane_ (o.sane_)
00027 {
00028 }
00029
00030 version_info::version_info()
00031 : nums_(3,0), special_(""), special_separator_('\0'), sane_(true)
00032 {
00033 }
00034
00035 version_info::version_info(unsigned int major, unsigned int minor, unsigned int revision_level, bool sane,
00036 char special_separator, const std::string& special)
00037 : nums_(3,0), special_(special), special_separator_(special_separator), sane_(sane)
00038 {
00039 nums_[0] = major;
00040 nums_[1] = minor;
00041 nums_[2] = revision_level;
00042 }
00043
00044 version_info::version_info(const std::string& str)
00045 : nums_(3,0)
00046 , special_("")
00047 , special_separator_('\0')
00048 , sane_(true)
00049 {
00050 std::string v = str;
00051 utils::strip(v);
00052
00053 if(v.empty())
00054 return;
00055
00056
00057
00058
00059
00060
00061
00062 const std::string::size_type breakpoint_pos = v.find_first_not_of(".0123456789");
00063 std::string left_side;
00064 if(breakpoint_pos != std::string::npos) {
00065 const std::string right_side = v.substr(breakpoint_pos);
00066 assert(right_side.empty() == false);
00067
00068 if((right_side[0] >= 'A' && right_side[0] <= 'Z') || (right_side[0] >= 'a' && right_side[0] <= 'z')) {
00069 special_separator_ = '\0';
00070 special_ = right_side;
00071 }
00072 else {
00073 special_separator_ = right_side[0];
00074 if(right_side.size() > 1) {
00075 special_ = right_side.substr(1);
00076 }
00077 }
00078
00079 left_side = v.substr(0, breakpoint_pos);
00080 }
00081 else {
00082 left_side = v;
00083 }
00084
00085 const std::vector<std::string> components = utils::split(left_side, '.');
00086 const size_t s = components.size();
00087 if(s == 0) {
00088 return;
00089 }
00090 else if(s > 3) {
00091 nums_.resize(s, 0);
00092 }
00093
00094 try {
00095 for(size_t i = 0; (i < s); ++i) {
00096 nums_[i] = lexical_cast<unsigned int>(components[i]);
00097 }
00098 }
00099 catch(bad_lexical_cast const&) {
00100
00101
00102 sane_ = false;
00103 }
00104 }
00105
00106 void version_info::assign(const version_info& o)
00107 {
00108 if(&o == this) return;
00109
00110 this->sane_ = o.sane_;
00111 this->special_separator_ = o.special_separator_;
00112 this->special_ = o.special_;
00113 this->nums_.clear();
00114 this->nums_ = o.nums_;
00115 }
00116
00117 std::string version_info::str() const
00118 {
00119 const size_t s = nums_.size();
00120
00121 std::ostringstream o;
00122 for(size_t k = 0; k < s; ++k) {
00123 o << nums_[k];
00124
00125 if(s != 1+k) {
00126 o << '.';
00127 }
00128 }
00129
00130 if(! special_.empty()) {
00131 if(special_separator_ != '\0') {
00132 o << special_separator_;
00133 }
00134
00135 o << special_;
00136 }
00137
00138 return o.str();
00139 }
00140
00141 void version_info::set_major_version(unsigned int v) {
00142 nums_[0] = v;
00143 }
00144
00145 void version_info::set_minor_version(unsigned int v) {
00146 nums_[1] = v;
00147 }
00148
00149 void version_info::set_revision_level(unsigned int v) {
00150 nums_[2] = v;
00151 }
00152
00153 unsigned int version_info::major_version() const {
00154 return nums_[0];
00155 }
00156
00157 unsigned int version_info::minor_version() const {
00158 return nums_[1];
00159 }
00160
00161 unsigned int version_info::revision_level() const {
00162 return nums_[2];
00163 }
00164
00165 bool version_info::is_canonical() const {
00166 return nums_.size() <= 3 && sane_;
00167 }
00168
00169 namespace {
00170 enum COMP_TYPE {
00171 EQUAL,
00172 NOT_EQUAL,
00173 LT, GT
00174 };
00175
00176
00177
00178
00179
00180
00181
00182
00183 template<typename _Toperator, typename _Tfallback_operator>
00184 bool recursive_order_operation(const std::vector<unsigned int>& l, const std::vector<unsigned int>& r, size_t k)
00185 {
00186 if(k >= l.size() || k >= r.size()) {
00187 return false;
00188 }
00189
00190 unsigned int const& lvalue = l[k];
00191 unsigned int const& rvalue = r[k];
00192
00193 _Toperator o;
00194 _Tfallback_operator fallback_o;
00195
00196 bool ret = o(lvalue, rvalue);
00197 if((!ret) && fallback_o(lvalue, rvalue)) {
00198 ret = recursive_order_operation<_Toperator, _Tfallback_operator>(l,r,++k);
00199 }
00200 return ret;
00201 }
00202
00203 #ifdef _MSC_VER
00204 #pragma warning (push)
00205 #pragma warning (disable: 4706)
00206 #endif
00207 bool version_numbers_comparison_internal(const version_info& l, const version_info& r, COMP_TYPE o)
00208 {
00209 if((!l.good()) || !r.good()) throw version_info::not_sane_exception();
00210
00211 std::vector<unsigned int> lc = l.components();
00212 std::vector<unsigned int> rc = r.components();
00213
00214 const size_t lsize = lc.size();
00215 const size_t rsize = rc.size();
00216 const size_t csize = std::max(lsize, rsize);
00217
00218
00219 if(lsize < csize) lc.resize(csize, 0);
00220 if(rsize < csize) rc.resize(csize, 0);
00221
00222 bool result = true;
00223
00224 const std::vector<unsigned int>& lcc = lc;
00225 const std::vector<unsigned int>& rcc = rc;
00226
00227 switch(o)
00228 {
00229 case EQUAL: case NOT_EQUAL: {
00230 for(size_t i = 0; i < csize; ++i) {
00231 unsigned int const& lvalue = lc[i];
00232 unsigned int const& rvalue = rc[i];
00233 if(o == NOT_EQUAL) {
00234 if((result = (lvalue != rvalue))) {
00235 #ifdef _MSC_VER
00236 #pragma warning (pop)
00237 #endif
00238 return true;
00239 }
00240 continue;
00241 } else {
00242 result = result && lvalue == rvalue;
00243 if(!result) {
00244 break;
00245 }
00246 }
00247 }
00248 break;
00249 }
00250 case LT:
00251 result = recursive_order_operation<std::less<unsigned int>, std::equal_to<unsigned int> >(lcc, rcc, 0);
00252 break;
00253 case GT:
00254 result = recursive_order_operation<std::greater<unsigned int>, std::equal_to<unsigned int> >(lcc, rcc, 0);
00255 break;
00256 default:
00257 assert(0 == 1);
00258 break;
00259 }
00260 return result;
00261 }
00262
00263 }
00264
00265 bool operator==(const version_info& l, const version_info& r)
00266 {
00267 return version_numbers_comparison_internal(l, r, EQUAL) && l.special_version() == r.special_version();
00268 }
00269
00270 bool operator!=(const version_info& l, const version_info& r)
00271 {
00272 return version_numbers_comparison_internal(l, r, NOT_EQUAL) || l.special_version() != r.special_version();
00273 }
00274
00275 bool operator<(const version_info& l, const version_info& r)
00276 {
00277 return version_numbers_comparison_internal(l, r, LT) || (
00278 version_numbers_comparison_internal(l, r, EQUAL) && (
00279 (l.special_version().empty() && !r.special_version().empty()) ||
00280 (l.special_version() < r.special_version())
00281 )
00282 );
00283 }
00284
00285 bool operator>(const version_info& l, const version_info& r)
00286 {
00287 return version_numbers_comparison_internal(l, r, GT) || (
00288 version_numbers_comparison_internal(l, r, EQUAL) && (
00289 (r.special_version().empty() && !l.special_version().empty()) ||
00290 (l.special_version() > r.special_version())
00291 )
00292 );
00293 }
00294
00295 bool operator<=(const version_info& l, const version_info& r)
00296 {
00297 return l < r || l == r;
00298 }
00299
00300 bool operator>=(const version_info& l, const version_info& r)
00301 {
00302 return l > r || l == r;
00303 }
00304
00305 VERSION_COMP_OP parse_version_op(const std::string& op_str)
00306 {
00307 if(op_str == "==") {
00308 return OP_EQUAL;
00309 } else if(op_str == "!=") {
00310 return OP_NOT_EQUAL;
00311 } else if(op_str == "<") {
00312 return OP_LESS;
00313 } else if(op_str == "<=") {
00314 return OP_LESS_OR_EQUAL;
00315 } else if(op_str == ">") {
00316 return OP_GREATER;
00317 } else if(op_str == ">=") {
00318 return OP_GREATER_OR_EQUAL;
00319 }
00320
00321 return OP_INVALID;
00322 }
00323
00324 bool do_version_check(const version_info& a, VERSION_COMP_OP op, const version_info& b)
00325 {
00326 switch(op) {
00327 case OP_EQUAL:
00328 return a == b;
00329 case OP_NOT_EQUAL:
00330 return a != b;
00331 case OP_LESS:
00332 return a < b;
00333 case OP_LESS_OR_EQUAL:
00334 return a <= b;
00335 case OP_GREATER:
00336 return a > b;
00337 case OP_GREATER_OR_EQUAL:
00338 return a >= b;
00339 default:
00340 ;
00341 }
00342
00343 return false;
00344 }