The Battle for Wesnoth  1.15.0-dev
game_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 https://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 "game_version.hpp"
16 
17 #include "lexical_cast.hpp"
19 #include "wesconfig.h"
20 
21 #ifdef LOAD_REVISION
22 #include "revision.h"
23 #endif
24 
25 #include <cassert>
26 #include <functional>
27 #include <locale>
28 
29 #include <boost/algorithm/string.hpp>
30 
31 namespace game_config
32 {
35 const version_info test_version("test");
36 
37 #ifdef REVISION
38 const std::string revision = VERSION " (" REVISION ")";
39 #elif defined(VCS_SHORT_HASH) && defined(VCS_WC_MODIFIED)
40 const std::string revision = std::string(VERSION) + " (" + VCS_SHORT_HASH + (VCS_WC_MODIFIED ? "-Modified" : "-Clean") + ")";
41 #else
42 const std::string revision = VERSION;
43 #endif
44 
45 } // namespace game_config
46 
48  : nums_(3,0), special_(""), special_separator_('\0')
49 {
50 }
51 
52 version_info::version_info(unsigned int major, unsigned int minor, unsigned int revision_level,
53  char special_separator, const std::string& special)
54  : nums_(3,0), special_(special), special_separator_(special_separator)
55 {
56  nums_[0] = major;
57  nums_[1] = minor;
58  nums_[2] = revision_level;
59 }
60 
61 version_info::version_info(const std::string& str)
62  : nums_(3,0)
63  , special_("")
64  , special_separator_('\0')
65 {
66  std::string v = str;
67  boost::trim(v);
68 
69  if(v.empty())
70  return;
71 
72  //
73  // The breakpoint is where the "special" version component begins.
74  // For 1.1.2a it would at the index of the char 'a'. For 1.1.4+dev it is at '+'.
75  //
76  // For 1.5.2 it is at npos.
77  //
78  const std::string::size_type breakpoint_pos = v.find_first_not_of(".0123456789");
79  std::string left_side;
80  if(breakpoint_pos != std::string::npos) {
81  const std::string right_side = v.substr(breakpoint_pos);
82  assert(right_side.empty() == false);
83 
84  if(std::isalpha(right_side[0], std::locale::classic())) {
85  special_separator_ = '\0';
86  special_ = right_side;
87  }
88  else {
89  special_separator_ = right_side[0];
90  if(right_side.size() > 1) {
91  special_ = right_side.substr(1);
92  }
93  }
94 
95  left_side = v.substr(0, breakpoint_pos);
96  }
97  else {
98  left_side = v;
99  }
100 
101  const std::vector<std::string> components = utils::split(left_side, '.');
102  const std::size_t s = components.size();
103  if(s == 0) {
104  return;
105  }
106  else if(s > 3) {
107  nums_.resize(s, 0);
108  }
109 
110  for(std::size_t i = 0; (i < s); ++i) {
111  nums_[i] = lexical_cast_default<unsigned int>(components[i]);
112  }
113 }
114 
115 std::string version_info::str() const
116 {
117  const std::size_t s = nums_.size();
118 
119  std::ostringstream o;
120  for(std::size_t k = 0; k < s; ++k) {
121  o << nums_[k];
122 
123  if(s != 1+k) {
124  o << '.';
125  }
126  }
127 
128  if(! special_.empty()) {
129  if(special_separator_ != '\0') {
130  o << special_separator_;
131  }
132 
133  o << special_;
134  }
135 
136  return o.str();
137 }
138 
139 void version_info::set_major_version(unsigned int v) {
140  nums_[0] = v;
141 }
142 
143 void version_info::set_minor_version(unsigned int v) {
144  nums_[1] = v;
145 }
146 
147 void version_info::set_revision_level(unsigned int v) {
148  nums_[2] = v;
149 }
150 
151 unsigned int version_info::major_version() const {
152  return nums_[0];
153 }
154 
155 unsigned int version_info::minor_version() const {
156  return nums_[1];
157 }
158 
159 unsigned int version_info::revision_level() const {
160  return nums_[2];
161 }
162 
164  return nums_.size() <= 3;
165 }
166 
167 namespace {
168  template<template<typename> class Fcn>
169  bool version_comparison_internal(const version_info& l, const version_info& r)
170  {
171  std::vector<unsigned int> lc = l.components();
172  std::vector<unsigned int> rc = r.components();
173 
174  const std::size_t lsize = lc.size();
175  const std::size_t rsize = rc.size();
176  const std::size_t csize = std::max(lsize, rsize);
177 
178  // make compatible, missing items default to zero
179  if(lsize < csize) lc.resize(csize, 0);
180  if(rsize < csize) rc.resize(csize, 0);
181 
182  using comp_list = std::vector<unsigned int>;
183  using comp_pair = std::tuple<const comp_list&, const std::string&>;
184  Fcn<comp_pair> comp;
185 
186  const comp_pair& lp = std::tie(lc, l.special_version());
187  const comp_pair& rp = std::tie(rc, r.special_version());
188  return comp(lp, rp);
189  }
190 } // end unnamed namespace
191 
192 bool operator==(const version_info& l, const version_info& r)
193 {
194  return version_comparison_internal<std::equal_to>(l, r);
195 }
196 
197 bool operator!=(const version_info& l, const version_info& r)
198 {
199  return version_comparison_internal<std::not_equal_to>(l, r);
200 }
201 
202 bool operator<(const version_info& l, const version_info& r)
203 {
204  return version_comparison_internal<std::less>(l, r);
205 }
206 
207 bool operator>(const version_info& l, const version_info& r)
208 {
209  return version_comparison_internal<std::greater>(l, r);
210 }
211 
212 bool operator<=(const version_info& l, const version_info& r)
213 {
214  return version_comparison_internal<std::less_equal>(l, r);
215 }
216 
217 bool operator>=(const version_info& l, const version_info& r)
218 {
219  return version_comparison_internal<std::greater_equal>(l, r);
220 }
221 
222 VERSION_COMP_OP parse_version_op(const std::string& op_str)
223 {
224  if(op_str == "==") {
225  return OP_EQUAL;
226  } else if(op_str == "!=") {
227  return OP_NOT_EQUAL;
228  } else if(op_str == "<") {
229  return OP_LESS;
230  } else if(op_str == "<=") {
231  return OP_LESS_OR_EQUAL;
232  } else if(op_str == ">") {
233  return OP_GREATER;
234  } else if(op_str == ">=") {
235  return OP_GREATER_OR_EQUAL;
236  }
237 
238  return OP_INVALID;
239 }
240 
242 {
243  switch(op) {
244  case OP_EQUAL:
245  return a == b;
246  case OP_NOT_EQUAL:
247  return a != b;
248  case OP_LESS:
249  return a < b;
250  case OP_LESS_OR_EQUAL:
251  return a <= b;
252  case OP_GREATER:
253  return a > b;
254  case OP_GREATER_OR_EQUAL:
255  return a >= b;
256  default:
257  ;
258  }
259 
260  return false;
261 }
std::string special_
VERSION_COMP_OP
Interfaces for manipulating version numbers of engine, add-ons, etc.
VERSION_COMP_OP parse_version_op(const std::string &op_str)
New lexcical_cast header.
#define a
void set_major_version(unsigned int)
Sets the major version number.
unsigned int revision_level() const
Retrieves the revision level (x3 in "x1.x2.x3").
void set_revision_level(unsigned int)
Sets the revision level.
bool do_version_check(const version_info &a, VERSION_COMP_OP op, const version_info &b)
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_
#define b
const std::string & special_version() const
Retrieves the special version suffix (e.g.
unsigned int major_version() const
Retrieves the major version number (x1 in "x1.x2.x3").
bool operator>=(const version_info &l, const version_info &r)
Greater-than-or-equal operator for version_info.
bool operator<=(const version_info &l, const version_info &r)
Less-than-or-equal operator for version_info.
const version_info test_version("test")
const std::vector< unsigned int > & components() const
Read-only access to all numeric components.
bool operator==(const version_info &l, const version_info &r)
Equality operator for version_info.
bool operator<(const version_info &l, const version_info &r)
Less-than operator for version_info.
unsigned int minor_version() const
Retrieves the minor version number (x2 in "x1.x2.x3").
void set_minor_version(unsigned int)
Sets the minor version number.
bool operator!=(const version_info &l, const version_info &r)
Inequality operator for version_info.
bool is_canonical() const
Whether the version number is considered canonical for mainline Wesnoth.
#define MIN_SAVEGAME_VERSION
Some older savegames of Wesnoth cannot be loaded anymore, this variable defines the minimum required ...
Definition: wesconfig.h:33
Some defines: VERSION, PACKAGE, MIN_SAVEGAME_VERSION.
std::size_t i
Definition: function.cpp:933
const std::string revision
#define VERSION
Definition: wesconfig.h:43
Game configuration data as global variables.
Definition: build_info.cpp:46
static map_location::DIRECTION s
const version_info wesnoth_version(VERSION)
Represents version numbers.
std::string str() const
Serializes the version number into string form.
version_info()
Default constructor.
const version_info min_savegame_version(MIN_SAVEGAME_VERSION)
std::vector< unsigned int > nums_
bool operator>(const version_info &l, const version_info &r)
Greater-than operator for version_info.