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 
53  : version_info(std::string(str))
54 {
55 }
56 
57 version_info::version_info(unsigned int major, unsigned int minor, unsigned int revision_level,
58  char special_separator, const std::string& special)
59  : nums_(3,0), special_(special), special_separator_(special_separator)
60 {
61  nums_[0] = major;
62  nums_[1] = minor;
63  nums_[2] = revision_level;
64 }
65 
66 version_info::version_info(const std::string& str)
67  : nums_(3,0)
68  , special_("")
69  , special_separator_('\0')
70 {
71  std::string v = str;
72  boost::trim(v);
73 
74  if(v.empty())
75  return;
76 
77  //
78  // The breakpoint is where the "special" version component begins.
79  // For 1.1.2a it would at the index of the char 'a'. For 1.1.4+dev it is at '+'.
80  //
81  // For 1.5.2 it is at npos.
82  //
83  const std::string::size_type breakpoint_pos = v.find_first_not_of(".0123456789");
84  std::string left_side;
85  if(breakpoint_pos != std::string::npos) {
86  const std::string right_side = v.substr(breakpoint_pos);
87  assert(right_side.empty() == false);
88 
89  if(std::isalpha(right_side[0], std::locale::classic())) {
90  special_separator_ = '\0';
91  special_ = right_side;
92  }
93  else {
94  special_separator_ = right_side[0];
95  if(right_side.size() > 1) {
96  special_ = right_side.substr(1);
97  }
98  }
99 
100  left_side = v.substr(0, breakpoint_pos);
101  }
102  else {
103  left_side = v;
104  }
105 
106  const std::vector<std::string> components = utils::split(left_side, '.');
107  const std::size_t s = components.size();
108  if(s == 0) {
109  return;
110  }
111  else if(s > 3) {
112  nums_.resize(s, 0);
113  }
114 
115  for(std::size_t i = 0; (i < s); ++i) {
116  nums_[i] = lexical_cast_default<unsigned int>(components[i]);
117  }
118 }
119 
120 std::string version_info::str() const
121 {
122  const std::size_t s = nums_.size();
123 
124  std::ostringstream o;
125  for(std::size_t k = 0; k < s; ++k) {
126  o << nums_[k];
127 
128  if(s != 1+k) {
129  o << '.';
130  }
131  }
132 
133  if(! special_.empty()) {
134  if(special_separator_ != '\0') {
135  o << special_separator_;
136  }
137 
138  o << special_;
139  }
140 
141  return o.str();
142 }
143 
144 void version_info::set_major_version(unsigned int v) {
145  nums_[0] = v;
146 }
147 
148 void version_info::set_minor_version(unsigned int v) {
149  nums_[1] = v;
150 }
151 
152 void version_info::set_revision_level(unsigned int v) {
153  nums_[2] = v;
154 }
155 
156 unsigned int version_info::major_version() const {
157  return nums_[0];
158 }
159 
160 unsigned int version_info::minor_version() const {
161  return nums_[1];
162 }
163 
164 unsigned int version_info::revision_level() const {
165  return nums_[2];
166 }
167 
169  return nums_.size() <= 3;
170 }
171 
172 namespace {
173  template<template<typename> class Fcn>
174  bool version_comparison_internal(const version_info& l, const version_info& r)
175  {
176  std::vector<unsigned int> lc = l.components();
177  std::vector<unsigned int> rc = r.components();
178 
179  const std::size_t lsize = lc.size();
180  const std::size_t rsize = rc.size();
181  const std::size_t csize = std::max(lsize, rsize);
182 
183  // make compatible, missing items default to zero
184  if(lsize < csize) lc.resize(csize, 0);
185  if(rsize < csize) rc.resize(csize, 0);
186 
187  using comp_list = std::vector<unsigned int>;
188  using comp_pair = std::tuple<const comp_list&, const std::string&>;
189  Fcn<comp_pair> comp;
190 
191  const comp_pair& lp = std::tie(lc, l.special_version());
192  const comp_pair& rp = std::tie(rc, r.special_version());
193  return comp(lp, rp);
194  }
195 } // end unnamed namespace
196 
197 bool operator==(const version_info& l, const version_info& r)
198 {
199  return version_comparison_internal<std::equal_to>(l, r);
200 }
201 
202 bool operator!=(const version_info& l, const version_info& r)
203 {
204  return version_comparison_internal<std::not_equal_to>(l, r);
205 }
206 
207 bool operator<(const version_info& l, const version_info& r)
208 {
209  return version_comparison_internal<std::less>(l, r);
210 }
211 
212 bool operator>(const version_info& l, const version_info& r)
213 {
214  return version_comparison_internal<std::greater>(l, r);
215 }
216 
217 bool operator<=(const version_info& l, const version_info& r)
218 {
219  return version_comparison_internal<std::less_equal>(l, r);
220 }
221 
222 bool operator>=(const version_info& l, const version_info& r)
223 {
224  return version_comparison_internal<std::greater_equal>(l, r);
225 }
226 
227 VERSION_COMP_OP parse_version_op(const std::string& op_str)
228 {
229  if(op_str == "==") {
230  return OP_EQUAL;
231  } else if(op_str == "!=") {
232  return OP_NOT_EQUAL;
233  } else if(op_str == "<") {
234  return OP_LESS;
235  } else if(op_str == "<=") {
236  return OP_LESS_OR_EQUAL;
237  } else if(op_str == ">") {
238  return OP_GREATER;
239  } else if(op_str == ">=") {
240  return OP_GREATER_OR_EQUAL;
241  }
242 
243  return OP_INVALID;
244 }
245 
247 {
248  switch(op) {
249  case OP_EQUAL:
250  return a == b;
251  case OP_NOT_EQUAL:
252  return a != b;
253  case OP_LESS:
254  return a < b;
255  case OP_LESS_OR_EQUAL:
256  return a <= b;
257  case OP_GREATER:
258  return a > b;
259  case OP_GREATER_OR_EQUAL:
260  return a >= b;
261  default:
262  ;
263  }
264 
265  return false;
266 }
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.
STL namespace.
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:49
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.