35 #include <boost/variant/apply_visitor.hpp>
36 #include <boost/variant/get.hpp>
37 #include <boost/variant/static_visitor.hpp>
38 #include <boost/variant/variant.hpp>
41 #define ERR_CF LOG_STREAM(err, log_config)
42 #define DBG_CF LOG_STREAM(debug, log_config)
45 #ifdef USE_HETEROGENOUS_LOOKUPS
46 struct config_simple_key
53 return r.compare(0, r.size(), l.str, l.len) > 0;
57 return l.compare(0, l.size(), r.str, r.len) < 0;
77 config->check_valid();
79 assert(!parent.empty());
80 assert(parent[0] ==
'[');
81 assert(parent[parent.size() - 1] ==
']');
83 if(config->has_child(key)) {
84 return *(config->children.find(key)->second.front());
95 std::stringstream sstr;
96 sstr <<
"Mandatory WML child »[" << key <<
"]« missing in »"
97 << parent <<
"«. Please report this bug.";
127 : value_(that.value_)
154 return *
this =
static_cast<unsigned long long>(
v);
158 return *
this =
static_cast<int>(
v);
165 value_ =
static_cast<double>(
v);
173 return *
this =
static_cast<int>(
v);
184 unsigned long long ull =
static_cast<unsigned long long>(
v);
185 if ( static_cast<double>(ull) ==
v )
190 int i =
static_cast<int>(
v);
191 if ( static_cast<double>(i) ==
v )
208 template<
typename To>
212 std::istringstream in_str(source);
213 if ( !(in_str >> res) )
217 std::ostringstream out_str;
219 return out_str.str() ==
source;
225 if (v.empty()) { value_ =
v;
return *
this; }
226 if ( v == s_yes ) { value_ =
yes_no(
true);
return *
this; }
227 if ( v == s_no ) { value_ =
yes_no(
false);
return *
this; }
228 if ( v == s_true ) { value_ =
true_false(
true);
return *
this; }
229 if ( v == s_false ) { value_ =
true_false(
false);
return *
this; }
233 double d = strtod(v.c_str(), &eptr);
234 if ( *eptr ==
'\0' ) {
240 unsigned long long ull = 0;
241 if ( from_string_verify<unsigned long long>(v, ull) )
247 if ( from_string_verify<int>(v, i) )
254 std::ostringstream tester;
256 if ( tester.str() ==
v ) {
277 if (
const yes_no *
p = boost::get<const yes_no>(&value_) )
279 if (
const true_false *
p = boost::get<const true_false>(&value_) )
288 template <
typename T>
289 class attribute_numeric_visitor :
public boost::static_visitor<T>
293 attribute_numeric_visitor(T def) : def_(def) {}
295 T operator()(boost::blank
const &)
const {
return def_; }
296 T operator()(
bool)
const {
return def_; }
297 T operator()(
int i)
const {
return static_cast<T
>(
i); }
298 T operator()(
unsigned long long u)
const {
return static_cast<T
>(u); }
299 T operator()(
double d)
const {
return static_cast<T
>(
d); }
300 T operator()(
std::string const &
s)
const {
return lexical_cast_default<T>(
s, def_); }
301 T operator()(
t_string const &)
const {
return def_; }
310 return apply_visitor(attribute_numeric_visitor<int>(def));
315 return apply_visitor(attribute_numeric_visitor<long long>(def));
320 return apply_visitor(attribute_numeric_visitor<unsigned>(def));
325 return apply_visitor(attribute_numeric_visitor<size_t>(def));
330 return apply_visitor(attribute_numeric_visitor<time_t>(def));
335 return apply_visitor(attribute_numeric_visitor<double>(def));
340 :
public boost::static_visitor<std::string>
360 if (
const t_string *
p = boost::get<const t_string>(&value_))
return *
p;
369 return boost::get<const boost::blank>(&value_) !=
nullptr;
377 if (boost::get<const boost::blank>(&value_))
return true;
378 if (
const std::string *
p = boost::get<const std::string>(&value_))
return p->empty();
385 :
public boost::static_visitor<bool>
389 template <
typename T,
typename U>
390 bool operator()(
const T &,
const U &)
const {
return false; }
393 template <
typename T>
394 bool operator()(
const T & lhs,
const T & rhs)
const {
return lhs == rhs; }
446 throw error(
"Mandatory WML child missing yet untested for. Please report.");
452 throw error(
"Mandatory WML child missing yet untested for. Please report.");
486 children(
std::move(cfg.children)),
487 ordered_children(
std::move(cfg.ordered_children))
504 if ((
c >=
'a' &&
c <=
'z') || (
c >=
'A' &&
c <=
'Z') || (
c >=
'0' &&
c <=
'9') ||
c ==
'_') {
553 values[v.first] = v.second;
570 values[v.first] = v.second;
582 merged_children.
append(cfg);
595 typedef std::map<std::string, config> config_map;
596 config_map merged_children_map;
600 if ( m!=merged_children_map.end() ) {
601 m->second.append(cfg);
603 merged_children_map.insert(make_pair(value, cfg));
608 for (
const config_map::value_type &
i : merged_children_map) {
620 if (i !=
children.end()) p = &i->second;
628 child_map::const_iterator
i =
children.find(key);
631 if (i !=
children.end()) p = &i->second;
639 child_map::const_iterator
i =
children.find(key);
641 return i->second.size();
662 const child_map::const_iterator
i =
children.find(key);
664 DBG_CF <<
"The config object has no child named »"
670 if (n < 0) n = i->second.size() +
n;
671 if(
size_t(n) < i->second.size()) {
672 return *i->second[
n];
675 DBG_CF <<
"The config object has only »" << i->second.size()
676 <<
"« children named »" << key
677 <<
"«; request for the index »" << n <<
"« cannot be honored.\n";
683 #ifdef USE_HETEROGENOUS_LOOKUPS
684 config &config::child_impl(
const char* key,
int len,
int n)
688 const child_map::const_iterator
i =
children.find(config_simple_key{ key, len });
690 DBG_CF <<
"The config object has no child named »"
696 if (n < 0) n = i->second.size() +
n;
697 if (
size_t(n) < i->second.size()) {
698 return *i->second[
n];
701 DBG_CF <<
"The config object has only »" << i->second.size()
702 <<
"« children named »" << key
703 <<
"«; request for the index »" << n <<
"« cannot be honored.\n";
724 static const config empty_cfg;
727 child_map::const_iterator i =
children.find(key);
728 if (i !=
children.end() && !i->second.empty())
729 return *i->second.front();
736 child_map::const_iterator i =
children.find(key);
737 if (i !=
children.end() && !i->second.empty())
738 return *i->second.front();
748 v.push_back(
new config());
758 v.push_back(
new config(val));
778 if(index > v.size()) {
779 throw error(
"illegal index to add child at");
784 bool inserted =
false;
790 if (ord->pos !=
value.pos)
continue;
791 if (!inserted && ord->index == index) {
794 }
else if (ord->index >= index) {
808 struct remove_ordered
813 {
return pos.
pos == iter_; }
842 if (i_src == src.
children.end())
return;
850 unsigned before = dst.size();
851 dst.insert(dst.end(), i_src->second.begin(), i_src->second.end());
855 for (
unsigned j = before; j < dst.size(); ++j) {
879 if (
p.pos != pos)
continue;
880 if (
p.index == index)
881 found = &
p - &ordered_children.front();
882 else if (
p.index > index)
887 delete pos->second[
index];
888 pos->second.erase(pos->second.begin() +
index);
891 return ordered_children.erase(ordered_children.begin() + found);
904 if (i ==
children.end() || index >= i->second.size()) {
905 ERR_CF <<
"Error: attempting to delete non-existing child: "
906 << key <<
"[" << index <<
"]\n";
917 const attribute_map::const_iterator i =
values.find(key);
918 if (i !=
values.end())
return i->second;
920 return empty_attribute;
923 #ifdef USE_HETEROGENOUS_LOOKUPS
928 const attribute_map::const_iterator i =
values.find(config_simple_key { key, len });
929 if (i !=
values.end())
return i->second;
930 static const attribute_value empty_attribute;
931 return empty_attribute;
938 attribute_map::const_iterator i =
values.find(key);
939 return i !=
values.end() ? &i->second :
nullptr;
952 attribute_map::const_iterator i =
values.find(key);
964 return empty_attribute;
972 assert(
this != &cfg);
976 if (key.substr(0,7) ==
"add_to_") {
978 values[add_to] =
values[add_to].to_int() + v.second.to_int();
980 values[v.first] = v.second;
994 struct config_has_value {
996 : name_(name), value_()
1001 bool operator()(
const config* cfg)
const {
return (*cfg)[name_] == value_; }
1017 DBG_CF <<
"Key »" << name <<
"« value »" << value
1018 <<
"« pair not found as child of key »" << key <<
"«.\n";
1025 config_has_value(name,value));
1026 if(j != i->second.end()) {
1029 DBG_CF <<
"Key »" << name <<
"« value »" << value
1030 <<
"« pair not found as child of key »" << key <<
"«.\n";
1040 struct config_clear_state
1042 config_clear_state()
1062 config_clear_state
init;
1066 std::deque<config_clear_state>
l;
1069 while (!l.empty()) {
1070 config_clear_state& state = l.back();
1071 if (state.mi != state.c->children.end()) {
1072 std::vector<config*>&
v = state.mi->second;
1073 if (state.vi < v.size()) {
1080 config_clear_state
next;
1094 state.c->children.clear();
1095 if (state.c !=
this)
delete state.c;
1148 config* inserts =
nullptr;
1150 attribute_map::const_iterator
i;
1152 if(i->second.blank())
continue;
1153 const attribute_map::const_iterator j = c.
values.find(i->first);
1154 if(j == c.
values.end() || (i->second != j->second && !i->second.blank() )) {
1155 if(inserts ==
nullptr) {
1159 (*inserts)[i->first] = i->second;
1163 config* deletes =
nullptr;
1166 if(i->second.blank())
continue;
1167 const attribute_map::const_iterator
itor =
values.find(i->first);
1168 if(itor ==
values.end() || itor->second.blank()) {
1169 if(deletes ==
nullptr) {
1173 (*deletes)[i->first] =
"x";
1177 std::vector<std::string> entities;
1179 child_map::const_iterator ci;
1181 entities.push_back(ci->first);
1185 if(
children.count(ci->first) == 0) {
1186 entities.push_back(ci->first);
1190 for(std::vector<std::string>::const_iterator
itor = entities.begin();
itor != entities.end(); ++
itor) {
1192 const child_map::const_iterator itor_a =
children.find(*
itor);
1193 const child_map::const_iterator itor_b = c.
children.find(*
itor);
1201 size_t ndeletes = 0;
1202 size_t ai = 0, bi = 0;
1203 while(ai != a.size() || bi != b.size()) {
1205 if(ai < a.size() && bi < b.size() && *a[ai] == *b[bi]) {
1211 std::stringstream
buf;
1215 if(b.size() - bi > a.size() - ai) {
1217 buf << bi - ndeletes;
1218 new_delete.
values[
"index"] = buf.str();
1227 else if(b.size() - bi < a.size() - ai) {
1230 new_insert.
values[
"index"] = buf.str();
1241 new_change.
values[
"index"] = buf.str();
1258 if (
const config &inserts = diff.
child(
"insert")) {
1259 for (
const attribute &
v : inserts.attribute_range()) {
1264 if (
const config &deletes = diff.
child(
"delete")) {
1265 for (
const attribute &
v : deletes.attribute_range()) {
1273 for (
const any_child &item : i.all_children_range())
1275 if (item.key.empty()) {
1280 if(itor ==
children.end() || index >= itor->second.size()) {
1281 throw error(
"error in diff: could not find element '" + item.key +
"'");
1284 itor->second[
index]->apply_diff(item.cfg, track);
1291 for (
const any_child &item : i.all_children_range()) {
1300 for (
const any_child &item : i.all_children_range()) {
1305 if(itor ==
children.end() || index >= itor->second.size()) {
1306 throw error(
"error in diff: could not find element '" + item.key +
"'");
1320 for (
const any_child &item : i.all_children_range()) {
1328 for (
const any_child &item : i.all_children_range())
1330 if (item.key.empty()) {
1335 if(itor ==
children.end() || index >= itor->second.size()) {
1336 throw error(
"error in diff: could not find element '" + item.key +
"'");
1339 itor->second[
index]->clear_diff_track(item.cfg);
1354 std::vector<child_pos> to_remove;
1355 std::map<std::string, unsigned> visitations;
1364 const child_map::const_iterator j = c.
children.find(tag);
1366 unsigned &visits = visitations[tag];
1367 if(visits < j->second.size()) {
1369 const config & merge_child = *j->second[visits++];
1371 if ( merge_child[
"__remove"].to_bool() ) {
1372 to_remove.push_back(*i);
1374 (i->pos->second[i->index])->merge_with(merge_child);
1380 for(child_map::const_iterator j = c.
children.begin(); j != c.
children.end(); ++j) {
1382 unsigned &visits = visitations[tag];
1383 while(visits < j->second.size()) {
1389 std::map<std::string, unsigned> removals;
1392 unsigned &removes = removals[tag];
1417 if (!v || *v != i.second)
return false;
1422 if (i.key ==
"not") {
1423 if (
matches(i.cfg))
return false;
1428 if (j.matches(i.cfg)) {
1433 if(!found)
return false;
1442 std::ostringstream outstream;
1444 return outstream.str();
1452 if(
val.second.blank())
continue;
1453 for (
int j = 0; j < i-1; j++){ outstream << char(9); }
1454 outstream <<
val.first <<
" = " <<
val.second <<
'\n';
1458 for (
int j = 0; j < i - 1; ++j) outstream <<
char(9);
1459 outstream <<
"[" <<
child.key <<
"]\n";
1460 outstream <<
child.cfg;
1461 for (
int j = 0; j < i - 1; ++j) outstream <<
char(9);
1462 outstream <<
"[/" <<
child.key <<
"]\n";
1472 static const unsigned int hash_length = 128;
1473 static const char hash_string[] =
1474 "+-,.<>0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
1476 std::string::const_iterator
c;
1479 for(i = 0; i != hash_length; ++
i) {
1482 hash_str[hash_length] = 0;
1487 for (c =
val.first.begin(); c !=
val.first.end(); ++
c) {
1489 if (++i == hash_length) i = 0;
1492 for (c = base_str.begin(); c != base_str.end(); ++
c) {
1494 if (++i == hash_length) i = 0;
1501 for (
char c : child_hash) {
1504 if(i == hash_length) {
1510 for(i = 0; i != hash_length; ++
i) {
1511 hash_str[
i] = hash_string[
1512 static_cast<unsigned>(hash_str[
i]) % strlen(hash_string)];
1535 for (; x.first != x.second &&
y.first !=
y.second; ++x.first, ++
y.first) {
1536 if (x.first->key !=
y.first->key || x.first->cfg !=
y.first->cfg) {
1541 return x.first == x.second &&
y.first ==
y.second;
const attribute_value & get_old_attribute(const std::string &key, const std::string &old_key, const std::string &msg="") const
Function to handle backward compatibility Get the value of key and if missing try old_key and log msg...
child_itors child_range(const std::string &key)
double to_double(double def=0.) const
void remove_attribute(const std::string &key)
std::string operator()(int i) const
~attribute_value()
Default implementation, but defined out-of-line for efficiency reasons.
bool translatable() const
static const std::string s_no
std::string operator()(t_string const &s) const
bool matches(const config &filter) const
static const std::string s_false
void append_attributes(const config &cfg)
Adds attributes from cfg.
const std::string & str() const
all_children_iterator ordered_end() const
std::pair< const_attribute_iterator, const_attribute_iterator > const_attr_itors
size_t to_size_t(size_t def=0) const
void append(const config &cfg)
Append data from another config object to this one.
std::vector< child_pos >::const_iterator Itor
bool to_bool(bool def=false) const
bool operator()(const T &, const U &) const
bool operator()(const true_false &lhs, const yes_no &rhs) const
void merge_children(const std::string &key)
All children with the given key will be merged into the first element with that key.
static l_noret error(LoadState *S, const char *why)
config & child_or_add(const std::string &key)
Returns a reference to the first child with the given key.
friend bool operator==(const config &a, const config &b)
Visitor for converting a variant to a string.
std::ostream & operator<<(std::ostream &os, const config::attribute_value &v)
attribute_map::value_type attribute
GLuint const GLfloat * val
value_type value_
The stored value will always use the first type from the variant definition that can represent it and...
reference operator*() const
bool operator()(const yes_no &lhs, const true_false &rhs) const
GLint GLint GLint GLint GLint GLint y
void append_children(const config &cfg)
Adds children from cfg.
const config & child_or_empty(const std::string &key) const
Returns the first child with the given key, or an empty config if there is none.
void clear_diff_track(const config &diff)
Clear any tracking info from a previous apply_diff call with tracking.
std::string debug() const
void clear_children(const std::string &key)
To lexical_cast(From value)
Lexical cast converts one type to another.
bool empty() const
Tests for an attribute that either was never set or was set to "".
Definitions for the interface to Wesnoth Markup Language (WML).
std::pair< const_child_iterator, const_child_iterator > const_child_itors
Variant for storing WML attributes.
GLboolean GLenum GLenum GLvoid * values
bool blank() const
Tests for an attribute that was never set.
GLdouble GLdouble GLdouble b
static bool valid_id(const std::string &id)
void merge_with(const config &c)
Merge config 'c' into this config, overwriting this config's values.
void inherit_from(const config &c)
Merge config 'c' into this config, preserving this config's values.
bool has_child(const std::string &key) const
Determine whether a config has a child or not.
A small explanation about what's going on here: Each action has access to two game_info objects First...
void splice_children(config &src, const std::string &key)
Moves all the children with tag key from src to this.
void check_valid() const
Raises an exception if this is not valid.
static const std::string s_yes
GLsizei const GLfloat * value
all_children_itors all_children_range() const
In-order iteration over all children.
GLboolean GLboolean GLboolean GLboolean a
void remove_child(const std::string &key, unsigned index)
static utils::tconst_clone< config, T >::reference child(T config, const std::string &key, const std::string &parent)
Implementation for the wrappers for [const] config& child(const std::string& key, const std::string& ...
std::pair< all_children_iterator, all_children_iterator > all_children_itors
config & add_child(const std::string &key)
std::string operator()(std::string const &s) const
std::vector< child_pos > ordered_children
GLenum GLuint GLsizei const char * buf
A wrapper for bool to get the correct streaming ("yes"/"no").
attribute_map values
All the attributes of this node.
std::string operator()(const true_false &b) const
void apply_diff(const config &diff, bool track=false)
A function to apply a diff config onto this config object.
Templates and utility-routines for strings and numbers.
void init()
Initializes the gui subsystems.
all_children_iterator erase(const all_children_iterator &i)
Visitor handling equality checks.
std::string operator()(unsigned long long u) const
std::string operator()(double d) const
config get_diff(const config &c) const
A function to get the differences between this object, and 'c', as another config object...
std::map< std::string, tfilter >::iterator itor
std::stringstream & wml_error()
Use this logger to send errors due to deprecated WML.
attribute_value()
Default implementation, but defined out-of-line for efficiency reasons.
const_attr_itors attribute_range() const
child_map children
A list of all children of this node.
attribute_value & operator[](const std::string &key)
Returns a reference to the attribute with the given key.
std::pair< child_iterator, child_iterator > child_itors
static bool operator<(const placing_info &a, const placing_info &b)
static void msg(const char *act, debug_info &i, const char *to="", const char *result="")
GLint GLint GLint GLint GLint x
GLdouble GLdouble GLdouble r
unsigned child_count(const std::string &key) const
void merge_attributes(const config &)
GLuint const GLchar * name
const attribute_value * get(const std::string &key) const
Returns a pointer to the attribute with the given key or nullptr if it does not exist.
attribute_value & operator=(const attribute_value &)
Default implementation, but defined out-of-line for efficiency reasons.
GLint GLint GLint GLint GLint GLint GLint GLbitfield GLenum filter
static const char * diff_track_attribute
The name of the attribute used for tracking diff changes.
bool equals(const std::string &str) const
Checks for equality of the attribute values when viewed as strings.
static lg::log_domain log_config("config")
bool has_attribute(const std::string &key) const
bool operator()(const T &lhs, const T &rhs) const
long long to_long_long(long long def=0) const
config & child(const std::string &key, int n=0)
Returns the nth child with the given key, or a reference to an invalid config if there is none...
unsigned all_children_count() const
config & find_child(const std::string &key, const std::string &name, const std::string &value)
Returns the first child of tag key with a name attribute containing value.
Standard logging facilities (interface).
void recursive_clear_value(const std::string &key)
time_t to_time_t(time_t def=0) const
int to_int(int def=0) const
std::vector< config * > child_list
unsigned to_unsigned(unsigned def=0) const
bool operator==(const attribute_value &other) const
Checks for equality of the attribute values when viewed as strings.
static unsigned int hash_str(const std::string &str)
const std::string & str() const
std::string operator()(const boost::blank &) const
A config object defines a single node in a WML file, with access to child nodes.
config & operator=(const config &)
static const std::string s_true
GLsizei const GLcharARB ** string
bool has_old_attribute(const std::string &key, const std::string &old_key, const std::string &msg="") const
Function to handle backward compatibility Check if has key or old_key and log msg as a WML error (if ...
GLsizei GLsizei GLchar * source
config & add_child_at(const std::string &key, const config &val, unsigned index)
A wrapper for bool to get the correct streaming ("true"/"false").
void merge_children_by_attribute(const std::string &key, const std::string &attribute)
All children with the given key and with equal values of the specified attribute will be merged into ...
all_children_iterator ordered_begin() const
std::string operator()(const yes_no &b) const
const std::string & str() const