The Battle for Wesnoth 1.21.0-dev
 
Loading...
Searching...
No Matches
game_version.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2008 - 2025
3 by Iris Morelle <shadowm2006@gmail.com>
4 Part of the Battle for Wesnoth Project https://www.wesnoth.org/
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY.
12
13 See the COPYING file for more details.
14*/
15
16#include "game_version.hpp"
17
18#include "utils/math.hpp"
19#include "lexical_cast.hpp"
21#include "wesconfig.h"
22
23#ifdef LOAD_REVISION
24#include "revision.h"
25#endif
26
27#include <cassert>
28#include <functional>
29#include <locale>
30
31#include <boost/algorithm/string.hpp>
32
33namespace game_config
34{
37const version_info test_version("test");
38
39#ifdef REVISION
40const std::string revision = VERSION " (" REVISION ")";
41#elif defined(VCS_SHORT_HASH) && defined(VCS_WC_MODIFIED)
42const std::string revision = std::string(VERSION) + " (" + VCS_SHORT_HASH + (VCS_WC_MODIFIED ? "-Modified" : "-Clean") + ")";
43#else
44const std::string revision = VERSION;
45#endif
46
47} // namespace game_config
48
50 : nums_(3,0), special_(""), special_separator_('\0')
51{
52}
53
55 : version_info(std::string(str))
56{
57}
58
59version_info::version_info(unsigned int major, unsigned int minor, unsigned int revision_level,
60 char special_separator, const std::string& special)
61 : nums_(3,0), special_(special), special_separator_(special_separator)
62{
63 nums_[0] = major;
64 nums_[1] = minor;
66}
67
68version_info::version_info(const std::string& str)
69 : nums_(3,0)
70 , special_("")
71 , special_separator_('\0')
72{
73 std::string v = str;
74 boost::trim(v);
75
76 if(v.empty())
77 return;
78
79 //
80 // The breakpoint is where the "special" version component begins.
81 // For 1.1.2a it would at the index of the char 'a'. For 1.1.4+dev it is at '+'.
82 //
83 // For 1.5.2 it is at npos.
84 //
85 const std::string::size_type breakpoint_pos = v.find_first_not_of(".0123456789");
86 std::string left_side;
87 if(breakpoint_pos != std::string::npos) {
88 const std::string right_side = v.substr(breakpoint_pos);
89 assert(right_side.empty() == false);
90
91 if(std::isalpha(right_side[0], std::locale::classic())) {
92 special_separator_ = '\0';
93 special_ = right_side;
94 }
95 else {
96 special_separator_ = right_side[0];
97 if(right_side.size() > 1) {
98 special_ = right_side.substr(1);
99 }
100 }
101
102 left_side = v.substr(0, breakpoint_pos);
103 }
104 else {
105 left_side = v;
106 }
107
108 const std::vector<std::string> components = utils::split(left_side, '.');
109 const std::size_t s = components.size();
110 if(s == 0) {
111 return;
112 }
113 else if(s > 3) {
114 nums_.resize(s, 0);
115 }
116
117 for(std::size_t i = 0; (i < s); ++i) {
118 nums_[i] = lexical_cast_default<unsigned int>(components[i]);
119 }
120}
121
122std::string version_info::str() const
123{
124 const std::size_t s = nums_.size();
125
126 std::ostringstream o;
127 for(std::size_t k = 0; k < s; ++k) {
128 o << nums_[k];
129
130 if(s != 1+k) {
131 o << '.';
132 }
133 }
134
135 if(! special_.empty()) {
136 if(special_separator_ != '\0') {
138 }
139
140 o << special_;
141 }
142
143 return o.str();
144}
145
147 nums_[0] = v;
148}
149
151 nums_[1] = v;
152}
153
155 nums_[2] = v;
156}
157
158unsigned int version_info::major_version() const {
159 return nums_[0];
160}
161
162unsigned int version_info::minor_version() const {
163 return nums_[1];
164}
165
166unsigned int version_info::revision_level() const {
167 return nums_[2];
168}
169
171 return nums_.size() <= 3;
172}
173
175 return is_odd(minor_version());
176}
177
178namespace {
179 template<template<typename> class Fcn>
180 bool version_comparison_internal(const version_info& l, const version_info& r)
181 {
182 std::vector<unsigned int> lc = l.components();
183 std::vector<unsigned int> rc = r.components();
184
185 const std::size_t lsize = lc.size();
186 const std::size_t rsize = rc.size();
187 const std::size_t csize = std::max(lsize, rsize);
188
189 // make compatible, missing items default to zero
190 if(lsize < csize) lc.resize(csize, 0);
191 if(rsize < csize) rc.resize(csize, 0);
192
193 using comp_list = std::vector<unsigned int>;
194 using comp_pair = std::tuple<const comp_list&, const std::string&>;
195 Fcn<comp_pair> comp;
196
197 const comp_pair& lp = std::tie(lc, l.special_version());
198 const comp_pair& rp = std::tie(rc, r.special_version());
199 return comp(lp, rp);
200 }
201} // end unnamed namespace
202
203bool operator==(const version_info& l, const version_info& r)
204{
205 return version_comparison_internal<std::equal_to>(l, r);
206}
207
208bool operator!=(const version_info& l, const version_info& r)
209{
210 return version_comparison_internal<std::not_equal_to>(l, r);
211}
212
213bool operator<(const version_info& l, const version_info& r)
214{
215 return version_comparison_internal<std::less>(l, r);
216}
217
218bool operator>(const version_info& l, const version_info& r)
219{
220 return version_comparison_internal<std::greater>(l, r);
221}
222
223bool operator<=(const version_info& l, const version_info& r)
224{
225 return version_comparison_internal<std::less_equal>(l, r);
226}
227
228bool operator>=(const version_info& l, const version_info& r)
229{
230 return version_comparison_internal<std::greater_equal>(l, r);
231}
232
233VERSION_COMP_OP parse_version_op(const std::string& op_str)
234{
235 if(op_str == "==") {
236 return OP_EQUAL;
237 } else if(op_str == "!=") {
238 return OP_NOT_EQUAL;
239 } else if(op_str == "<") {
240 return OP_LESS;
241 } else if(op_str == "<=") {
242 return OP_LESS_OR_EQUAL;
243 } else if(op_str == ">") {
244 return OP_GREATER;
245 } else if(op_str == ">=") {
246 return OP_GREATER_OR_EQUAL;
247 }
248
249 return OP_INVALID;
250}
251
253{
254 switch(op) {
255 case OP_EQUAL:
256 return a == b;
257 case OP_NOT_EQUAL:
258 return a != b;
259 case OP_LESS:
260 return a < b;
261 case OP_LESS_OR_EQUAL:
262 return a <= b;
263 case OP_GREATER:
264 return a > b;
266 return a >= b;
267 default:
268 ;
269 }
270
271 return false;
272}
Represents version numbers.
std::string special_
std::string str() const
Serializes the version number into string form.
unsigned int revision_level() const
Retrieves the revision level (x3 in "x1.x2.x3").
void set_minor_version(unsigned int)
Sets the minor version number.
const std::string & special_version() const
Retrieves the special version suffix (e.g.
void set_major_version(unsigned int)
Sets the major version number.
unsigned int minor_version() const
Retrieves the minor version number (x2 in "x1.x2.x3").
const std::vector< unsigned int > & components() const
Read-only access to all numeric components.
unsigned int major_version() const
Retrieves the major version number (x1 in "x1.x2.x3").
std::vector< unsigned int > nums_
void set_revision_level(unsigned int)
Sets the revision level.
bool is_canonical() const
Whether the version number is considered canonical for mainline Wesnoth.
version_info()
Default constructor.
bool is_dev_version() const
Whether this version represents a development version of Wesnoth aka whether the minor version odd.
bool operator>(const version_info &l, const version_info &r)
Greater-than operator for version_info.
bool do_version_check(const version_info &a, VERSION_COMP_OP op, const version_info &b)
bool operator!=(const version_info &l, const version_info &r)
Inequality operator for version_info.
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.
bool operator==(const version_info &l, const version_info &r)
Equality operator for version_info.
VERSION_COMP_OP parse_version_op(const std::string &op_str)
bool operator<(const version_info &l, const version_info &r)
Less-than operator for version_info.
Interfaces for manipulating version numbers of engine, add-ons, etc.
VERSION_COMP_OP
@ OP_INVALID
@ OP_EQUAL
@ OP_GREATER_OR_EQUAL
@ OP_LESS_OR_EQUAL
@ OP_GREATER
@ OP_NOT_EQUAL
@ OP_LESS
New lexcical_cast header.
General math utility functions.
constexpr bool is_odd(T num)
Definition math.hpp:34
Game configuration data as global variables.
const version_info min_savegame_version(MIN_SAVEGAME_VERSION)
const version_info test_version("test")
const version_info wesnoth_version(VERSION)
const std::string revision
STL namespace.
std::vector< std::string > split(const config_attribute_value &val)
static map_location::direction s
Some defines: VERSION, PACKAGE, MIN_SAVEGAME_VERSION.
#define VERSION
Definition wesconfig.h:43
#define MIN_SAVEGAME_VERSION
Some older savegames of Wesnoth cannot be loaded anymore, this variable defines the minimum required ...
Definition wesconfig.h:33
#define i
#define b