version.cpp

Go to the documentation of this file.
00001 /* $Id: version.cpp 52533 2012-01-07 02:35:17Z shadowmaster $ */
00002 /*
00003    Copyright (C) 2008 - 2012 by Ignacio R. Morelle <shadowm2006@gmail.com>
00004    Part of the Battle for Wesnoth Project http://www.wesnoth.org/
00005 
00006    This program is free software; you can redistribute it and/or modify
00007    it under the terms of the GNU General Public License as published by
00008    the Free Software Foundation; either version 2 of the License, or
00009    (at your option) any later version.
00010    This program is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY.
00012 
00013    See the COPYING file for more details.
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     // The breakpoint is where the "special" version component begins.
00058     // For 1.1.2a it would at the index of the char 'a'. For 1.1.4+svn it is at '+'.
00059     //
00060     // For 1.5.2 it is at npos.
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         // FIXME: actually, this is virtually impossible to occur
00101         // due to the find_first_not_of() call above...
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                x         >          y
00178     x0.x1.x2.x3.[...].xN > y0.y1.y2.y3.[...].yN iff
00179 
00180     x0 > y0 || (x0 == y0 && (x1 > y1 || (x1 == y1 && (x2 > y2 || (x2 >= y2 ||
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         // make compatible, missing items default to zero
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 } // end unnamed namespace
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 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

Generated by doxygen 1.7.1 on Fri May 25 2012 01:03:14 for The Battle for Wesnoth
Gna! | Forum | Wiki | CIA | devdocs