The Battle for Wesnoth  1.13.11+dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
version.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2008 - 2018 by Iris Morelle <shadowm2006@gmail.com>
3  Part of the Battle for Wesnoth Project http://www.wesnoth.org/
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY.
11 
12  See the COPYING file for more details.
13 */
14 
15 #include "version.hpp"
16 #include "lexical_cast.hpp"
18 
19 #include <cassert>
20 #include <functional>
21 #include <locale>
22 
23 #include <boost/algorithm/string.hpp>
24 
26  : nums_(3,0), special_(""), special_separator_('\0')
27 {
28 }
29 
30 version_info::version_info(unsigned int major, unsigned int minor, unsigned int revision_level,
31  char special_separator, const std::string& special)
32  : nums_(3,0), special_(special), special_separator_(special_separator)
33 {
34  nums_[0] = major;
35  nums_[1] = minor;
36  nums_[2] = revision_level;
37 }
38 
40  : nums_(3,0)
41  , special_("")
42  , special_separator_('\0')
43 {
44  std::string v = str;
45  boost::trim(v);
46 
47  if(v.empty())
48  return;
49 
50  //
51  // The breakpoint is where the "special" version component begins.
52  // For 1.1.2a it would at the index of the char 'a'. For 1.1.4+dev it is at '+'.
53  //
54  // For 1.5.2 it is at npos.
55  //
56  const std::string::size_type breakpoint_pos = v.find_first_not_of(".0123456789");
57  std::string left_side;
58  if(breakpoint_pos != std::string::npos) {
59  const std::string right_side = v.substr(breakpoint_pos);
60  assert(right_side.empty() == false);
61 
62  if(std::isalpha(right_side[0], std::locale::classic())) {
63  special_separator_ = '\0';
64  special_ = right_side;
65  }
66  else {
67  special_separator_ = right_side[0];
68  if(right_side.size() > 1) {
69  special_ = right_side.substr(1);
70  }
71  }
72 
73  left_side = v.substr(0, breakpoint_pos);
74  }
75  else {
76  left_side = v;
77  }
78 
79  const std::vector<std::string> components = utils::split(left_side, '.');
80  const size_t s = components.size();
81  if(s == 0) {
82  return;
83  }
84  else if(s > 3) {
85  nums_.resize(s, 0);
86  }
87 
88  for(size_t i = 0; (i < s); ++i) {
89  nums_[i] = lexical_cast_default<unsigned int>(components[i]);
90  }
91 }
92 
94 {
95  const size_t s = nums_.size();
96 
97  std::ostringstream o;
98  for(size_t k = 0; k < s; ++k) {
99  o << nums_[k];
100 
101  if(s != 1+k) {
102  o << '.';
103  }
104  }
105 
106  if(! special_.empty()) {
107  if(special_separator_ != '\0') {
108  o << special_separator_;
109  }
110 
111  o << special_;
112  }
113 
114  return o.str();
115 }
116 
117 void version_info::set_major_version(unsigned int v) {
118  nums_[0] = v;
119 }
120 
121 void version_info::set_minor_version(unsigned int v) {
122  nums_[1] = v;
123 }
124 
125 void version_info::set_revision_level(unsigned int v) {
126  nums_[2] = v;
127 }
128 
129 unsigned int version_info::major_version() const {
130  return nums_[0];
131 }
132 
133 unsigned int version_info::minor_version() const {
134  return nums_[1];
135 }
136 
137 unsigned int version_info::revision_level() const {
138  return nums_[2];
139 }
140 
142  return nums_.size() <= 3;
143 }
144 
145 namespace {
146  enum COMP_TYPE {
147  EQUAL,
148  NOT_EQUAL,
149  LT, GT
150  };
151 
152  /*
153  x > y
154  x0.x1.x2.x3.[...].xN > y0.y1.y2.y3.[...].yN iff
155 
156  x0 > y0 || (x0 == y0 && (x1 > y1 || (x1 == y1 && (x2 > y2 || (x2 >= y2 ||
157 
158  */
159  template<typename _Toperator, typename _Tfallback_operator>
160  bool recursive_order_operation(const std::vector<unsigned int>& l, const std::vector<unsigned int>& r, size_t k)
161  {
162  if(k >= l.size() || k >= r.size()) {
163  return false;
164  }
165 
166  const unsigned int& lvalue = l[k];
167  const unsigned int& rvalue = r[k];
168 
169  _Toperator o;
170  _Tfallback_operator fallback_o;
171 
172  bool ret = o(lvalue, rvalue);
173  if((!ret) && fallback_o(lvalue, rvalue)) {
174  ret = recursive_order_operation<_Toperator, _Tfallback_operator>(l,r,++k);
175  }
176  return ret;
177  }
178 
179 #ifdef _MSC_VER
180 #pragma warning (push)
181 #pragma warning (disable: 4706)
182 #endif
183  bool version_numbers_comparison_internal(const version_info& l, const version_info& r, COMP_TYPE o)
184  {
185  std::vector<unsigned int> lc = l.components();
186  std::vector<unsigned int> rc = r.components();
187 
188  const size_t lsize = lc.size();
189  const size_t rsize = rc.size();
190  const size_t csize = std::max(lsize, rsize);
191 
192  // make compatible, missing items default to zero
193  if(lsize < csize) lc.resize(csize, 0);
194  if(rsize < csize) rc.resize(csize, 0);
195 
196  bool result = true;
197 
198  const std::vector<unsigned int>& lcc = lc;
199  const std::vector<unsigned int>& rcc = rc;
200 
201  switch(o)
202  {
203  case EQUAL: case NOT_EQUAL: {
204  for(size_t i = 0; i < csize; ++i) {
205  const unsigned int& lvalue = lc[i];
206  const unsigned int& rvalue = rc[i];
207  if(o == NOT_EQUAL) {
208  if((result = (lvalue != rvalue))) {
209 #ifdef _MSC_VER
210 #pragma warning (pop)
211 #endif
212  return true;
213  }
214  continue;
215  } else {
216  result = result && lvalue == rvalue;
217  if(!result) {
218  break;
219  }
220  }
221  }
222  break;
223  }
224  case LT:
225  result = recursive_order_operation<std::less<unsigned int>, std::equal_to<unsigned int> >(lcc, rcc, 0);
226  break;
227  case GT:
228  result = recursive_order_operation<std::greater<unsigned int>, std::equal_to<unsigned int> >(lcc, rcc, 0);
229  break;
230  default:
231  assert(false);
232  break;
233  }
234  return result;
235  }
236 
237 } // end unnamed namespace
238 
239 bool operator==(const version_info& l, const version_info& r)
240 {
241  return version_numbers_comparison_internal(l, r, EQUAL) && l.special_version() == r.special_version();
242 }
243 
244 bool operator!=(const version_info& l, const version_info& r)
245 {
246  return version_numbers_comparison_internal(l, r, NOT_EQUAL) || l.special_version() != r.special_version();
247 }
248 
249 bool operator<(const version_info& l, const version_info& r)
250 {
251  return version_numbers_comparison_internal(l, r, LT) || (
252  version_numbers_comparison_internal(l, r, EQUAL) && (
253  (l.special_version().empty() && !r.special_version().empty()) ||
254  (l.special_version() < r.special_version())
255  )
256  );
257 }
258 
259 bool operator>(const version_info& l, const version_info& r)
260 {
261  return version_numbers_comparison_internal(l, r, GT) || (
262  version_numbers_comparison_internal(l, r, EQUAL) && (
263  (r.special_version().empty() && !l.special_version().empty()) ||
264  (l.special_version() > r.special_version())
265  )
266  );
267 }
268 
269 bool operator<=(const version_info& l, const version_info& r)
270 {
271  return l < r || l == r;
272 }
273 
274 bool operator>=(const version_info& l, const version_info& r)
275 {
276  return l > r || l == r;
277 }
278 
280 {
281  if(op_str == "==") {
282  return OP_EQUAL;
283  } else if(op_str == "!=") {
284  return OP_NOT_EQUAL;
285  } else if(op_str == "<") {
286  return OP_LESS;
287  } else if(op_str == "<=") {
288  return OP_LESS_OR_EQUAL;
289  } else if(op_str == ">") {
290  return OP_GREATER;
291  } else if(op_str == ">=") {
292  return OP_GREATER_OR_EQUAL;
293  }
294 
295  return OP_INVALID;
296 }
297 
299 {
300  switch(op) {
301  case OP_EQUAL:
302  return a == b;
303  case OP_NOT_EQUAL:
304  return a != b;
305  case OP_LESS:
306  return a < b;
307  case OP_LESS_OR_EQUAL:
308  return a <= b;
309  case OP_GREATER:
310  return a > b;
311  case OP_GREATER_OR_EQUAL:
312  return a >= b;
313  default:
314  ;
315  }
316 
317  return false;
318 }
std::string special_
Definition: version.hpp:177
bool is_canonical() const
Whether the version number is considered canonical for mainline Wesnoth.
Definition: version.cpp:141
std::vector< char_t > string
VERSION_COMP_OP parse_version_op(const std::string &op_str)
Definition: version.cpp:279
New lexcical_cast header.
#define a
bool operator>(const version_info &l, const version_info &r)
Greater-than operator for version_info.
Definition: version.cpp:259
void set_major_version(unsigned int)
Sets the major version number.
Definition: version.cpp:117
void set_revision_level(unsigned int)
Sets the revision level.
Definition: version.cpp:125
const std::vector< unsigned int > & components() const
Read-only access to all numeric components.
Definition: version.hpp:170
COMP_TYPE
Definition: version.cpp:146
std::vector< std::string > split(const std::string &val, const char c, const int flags)
Splits a (comma-)separated string into a vector of pieces.
char special_separator_
Definition: version.hpp:178
#define b
void set_minor_version(unsigned int)
Sets the minor version number.
Definition: version.cpp:121
std::string str() const
Serializes the version number into string form.
Definition: version.cpp:93
unsigned int revision_level() const
Retrieves the revision level (x3 in "x1.x2.x3").
Definition: version.cpp:137
VERSION_COMP_OP
Definition: version.hpp:194
bool operator>=(const version_info &l, const version_info &r)
Greater-than-or-equal operator for version_info.
Definition: version.cpp:274
static map_location::DIRECTION s
unsigned int minor_version() const
Retrieves the minor version number (x2 in "x1.x2.x3").
Definition: version.cpp:133
bool operator<(const version_info &l, const version_info &r)
Less-than operator for version_info.
Definition: version.cpp:249
bool operator!=(const version_info &l, const version_info &r)
Inequality operator for version_info.
Definition: version.cpp:244
unsigned int major_version() const
Retrieves the major version number (x1 in "x1.x2.x3").
Definition: version.cpp:129
size_t i
Definition: function.cpp:933
Represents version numbers.
Definition: version.hpp:43
bool do_version_check(const version_info &a, VERSION_COMP_OP op, const version_info &b)
Definition: version.cpp:298
version_info()
Default constructor.
Definition: version.cpp:25
const std::string & special_version() const
Retrieves the special version suffix (e.g.
Definition: version.hpp:111
bool operator==(const version_info &l, const version_info &r)
Equality operator for version_info.
Definition: version.cpp:239
Interfaces for manipulating version numbers of engine, add-ons, etc.
std::vector< unsigned int > nums_
Definition: version.hpp:176
bool operator<=(const version_info &l, const version_info &r)
Less-than-or-equal operator for version_info.
Definition: version.cpp:269