The Battle for Wesnoth  1.15.2+dev
variable.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2003 by David White <dave@whitevine.net>
3  Copyright (C) 2005 - 2018 by Philippe Plantier <ayin@anathas.org>
4 
5  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
6 
7  This program is free software; you can redistribute it and/or modify
8  it under the terms of the GNU General Public License as published by
9  the Free Software Foundation; either version 2 of the License, or
10  (at your option) any later version.
11  This program is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY.
13 
14  See the COPYING file for more details.
15 */
16 
17 /**
18  * @file
19  * Manage WML-variables.
20  */
21 
22 #include "variable.hpp"
23 
24 #include "formula/string_utils.hpp"
25 #include "game_board.hpp"
26 #include "game_data.hpp"
27 #include "log.hpp"
28 #include "resources.hpp"
29 #include "units/unit.hpp"
30 #include "units/map.hpp"
31 #include "team.hpp"
32 
33 #include <boost/variant/static_visitor.hpp>
34 
35 static lg::log_domain log_engine("engine");
36 #define LOG_NG LOG_STREAM(info, log_engine)
37 #define WRN_NG LOG_STREAM(warn, log_engine)
38 #define ERR_NG LOG_STREAM(err, log_engine)
39 namespace
40 {
41  const config as_nonempty_range_default("_");
42  config::const_child_itors as_nonempty_range(const std::string& varname)
43  {
44  config::const_child_itors range = as_nonempty_range_default.child_range("_");
45 
48 
49  if(!temp_range.empty()) {
50  range = temp_range;
51  }
52  }
53 
54  return range;
55  }
56 }
57 
59  try {
60  variable_access_const variable(id, cfg_);
61  return variable.as_scalar();
62  } catch(const invalid_variablename_exception&) {
63  ERR_NG << "invalid variablename " << id << "\n";
64  return config::attribute_value();
65  }
66 }
67 
69 
70 
72  cache_(), cfg_(&default_empty_config)
73 {
74 }
75 
76 vconfig::vconfig(const config & cfg, const std::shared_ptr<const config> & cache) :
77  cache_(cache), cfg_(&cfg)
78 {
79 }
80 
81 /**
82  * Constructor from a config, with an option to manage memory.
83  * @param[in] cfg The "WML source" of the vconfig being constructed.
84  * @param[in] manage_memory If true, a copy of @a cfg will be made, allowing the
85  * vconfig to safely persist after @a cfg is destroyed.
86  * If false, no copy is made, so @a cfg must be
87  * guaranteed to persist as long as the vconfig will.
88  * If in doubt, set to true; it is less efficient, but safe.
89  * See also make_safe().
90  */
91 vconfig::vconfig(const config &cfg, bool manage_memory) :
92  cache_(manage_memory ? new config(cfg) : nullptr),
93  cfg_(manage_memory ? cache_.get() : &cfg)
94 {
95 }
96 
97 /**
98  * Default destructor, but defined here for possibly faster compiles
99  * (templates sometimes can be rough on the compiler).
100  */
102 {
103 }
104 
106 {
107  static const config empty_config;
108  return vconfig(empty_config, false);
109 }
110 
111 /**
112  * This is just a wrapper for the default constructor; it exists for historical
113  * reasons and to make it clear that default construction cannot be dereferenced
114  * (in contrast to an empty vconfig).
115  */
117 {
118  return vconfig();
119 }
120 
121 /**
122  * Ensures that *this manages its own memory, making it safe for *this to
123  * outlive the config it was ultimately constructed from.
124  * It is perfectly safe to call this for a vconfig that already manages its memory.
125  * This does not work on a null() vconfig.
126  */
128 {
129  // Nothing to do if we already manage our own memory.
130  if ( memory_managed() )
131  return *this;
132 
133  // Make a copy of our config.
134  cache_.reset(new config(*cfg_));
135  // Use our copy instead of the original.
136  cfg_ = cache_.get();
137  return *this;
138 }
139 
141 {
142  // Keeps track of insert_tag variables.
143  static std::set<std::string> vconfig_recursion;
144 
145  config res;
146 
147  for (const config::attribute &i : cfg_->attribute_range()) {
148  res[i.first] = expand(i.first);
149  }
150 
152  {
153  if (child.key == "insert_tag") {
154  vconfig insert_cfg(child.cfg);
155  std::string name = insert_cfg["name"];
156  std::string vname = insert_cfg["variable"];
157  if(!vconfig_recursion.insert(vname).second) {
158  throw recursion_error("vconfig::get_parsed_config() infinite recursion detected, aborting");
159  }
160  try
161  {
162  config::const_child_itors range = as_nonempty_range(vname);
163  for (const config& ch : range)
164  {
165  res.add_child(name, vconfig(ch).get_parsed_config());
166  }
167  }
168  catch(const invalid_variablename_exception&)
169  {
170  res.add_child(name);
171  }
172  catch(const recursion_error &err) {
173  vconfig_recursion.erase(vname);
174  WRN_NG << err.message << std::endl;
175  if(vconfig_recursion.empty()) {
176  res.add_child("insert_tag", insert_cfg.get_config());
177  } else {
178  // throw to the top [insert_tag] which started the recursion
179  throw;
180  }
181  }
182  vconfig_recursion.erase(vname);
183  } else {
184  res.add_child(child.key, vconfig(child.cfg).get_parsed_config());
185  }
186  }
187  return res;
188 }
189 
190 vconfig::child_list vconfig::get_children(const std::string& key) const
191 {
193 
195  {
196  if (child.key == key) {
197  res.push_back(vconfig(child.cfg, cache_));
198  } else if (child.key == "insert_tag") {
199  vconfig insert_cfg(child.cfg);
200  if(insert_cfg["name"] == key)
201  {
202  try
203  {
204  config::const_child_itors range = as_nonempty_range(insert_cfg["variable"]);
205  for (const config& ch : range)
206  {
207  res.push_back(vconfig(ch, true));
208  }
209  }
210  catch(const invalid_variablename_exception&)
211  {
212  res.push_back(empty_vconfig());
213  }
214  }
215  }
216  }
217  return res;
218 }
219 
220 std::size_t vconfig::count_children(const std::string& key) const
221 {
222  std::size_t n = 0;
223 
225  {
226  if (child.key == key) {
227  n++;
228  } else if (child.key == "insert_tag") {
229  vconfig insert_cfg(child.cfg);
230  if(insert_cfg["name"] == key)
231  {
232  try
233  {
234  config::const_child_itors range = as_nonempty_range(insert_cfg["variable"]);
235  n += range.size();
236  }
237  catch(const invalid_variablename_exception&)
238  {
239  n++;
240  }
241  }
242  }
243  }
244  return n;
245 }
246 
247 /**
248  * Returns a child of *this whose key is @a key.
249  * If no such child exists, returns an unconstructed vconfig (use null() to test
250  * for this).
251  */
252 vconfig vconfig::child(const std::string& key) const
253 {
254  if (const config &natural = cfg_->child(key)) {
255  return vconfig(natural, cache_);
256  }
257  for (const config &ins : cfg_->child_range("insert_tag"))
258  {
259  vconfig insert_cfg(ins);
260  if(insert_cfg["name"] == key)
261  {
262  try
263  {
264  config::const_child_itors range = as_nonempty_range(insert_cfg["variable"]);
265  return vconfig(range.front(), true);
266  }
267  catch(const invalid_variablename_exception&)
268  {
269  return empty_vconfig();
270  }
271  }
272  }
273  return unconstructed_vconfig();
274 }
275 
276 /**
277  * Returns whether or not *this has a child whose key is @a key.
278  */
279 bool vconfig::has_child(const std::string& key) const
280 {
281  if (cfg_->child(key)) {
282  return true;
283  }
284  for (const config &ins : cfg_->child_range("insert_tag"))
285  {
286  vconfig insert_cfg(ins);
287  if(insert_cfg["name"] == key) {
288  return true;
289  }
290  }
291  return false;
292 }
293 
294 namespace {
295  struct vconfig_expand_visitor : boost::static_visitor<void>
296  {
297  config::attribute_value &result;
298 
299  vconfig_expand_visitor(config::attribute_value &r): result(r) {}
300  template<typename T> void operator()(const T&) const {}
301  void operator()(const std::string &s) const
302  {
304  }
305  void operator()(const t_string &s) const
306  {
308  }
309  };
310 }//unnamed namespace
311 
312 config::attribute_value vconfig::expand(const std::string &key) const
313 {
314  config::attribute_value val = (*cfg_)[key];
316  val.apply_visitor(vconfig_expand_visitor(val));
317  return val;
318 }
319 
321 {
322  config::attribute val = *i_;
323  if(resources::gamedata) {
324  val.second.apply_visitor(vconfig_expand_visitor(val.second));
325  }
326  return val;
327 }
328 
330 {
331  config::attribute val = *i_;
332  if(resources::gamedata) {
333  val.second.apply_visitor(vconfig_expand_visitor(val.second));
334  }
335  pointer_proxy p {val};
336  return p;
337 }
338 
340  i_(i), inner_index_(0), cache_()
341 {
342 }
343 
344 vconfig::all_children_iterator::all_children_iterator(const Itor &i, const std::shared_ptr<const config> & cache) :
345  i_(i), inner_index_(0), cache_(cache)
346 {
347 }
348 
350 {
351  if (inner_index_ >= 0 && i_->key == "insert_tag")
352  {
353  try
354  {
356 
357  config::const_child_itors range = vinfo.as_array();
358 
359  if (++inner_index_ < static_cast<int>(range.size()))
360  {
361  return *this;
362  }
363 
364  }
365  catch(const invalid_variablename_exception&)
366  {
367  }
368  inner_index_ = 0;
369  }
370  ++i_;
371  return *this;
372 }
373 
375 {
377  this->operator++();
378  return i;
379 }
380 
382 {
383  if(inner_index_ >= 0 && i_->key == "insert_tag") {
384  if(--inner_index_ >= 0) {
385  return *this;
386  }
387  inner_index_ = 0;
388  }
389  --i_;
390  return *this;
391 }
392 
394 {
396  this->operator--();
397  return i;
398 }
399 
401 {
402  return value_type(get_key(), get_child());
403 }
404 
406 {
408  return p;
409 }
410 
411 
413 {
414  const std::string &key = i_->key;
415  if (inner_index_ >= 0 && key == "insert_tag") {
416  return vconfig(i_->cfg)["name"];
417  }
418  return key;
419 }
420 
422 {
423  if (inner_index_ >= 0 && i_->key == "insert_tag")
424  {
425  try
426  {
427  config::const_child_itors range = as_nonempty_range(vconfig(i_->cfg)["variable"]);
428 
429  range.advance_begin(inner_index_);
430  return vconfig(range.front(), true);
431  }
432  catch(const invalid_variablename_exception&)
433  {
434  return empty_vconfig();
435  }
436  }
437  return vconfig(i_->cfg, cache_);
438 }
439 
441 {
442  return i_ == i.i_ && inner_index_ == i.inner_index_;
443 }
444 
446 {
448 }
449 
451 {
453 }
454 
455 scoped_wml_variable::scoped_wml_variable(const std::string& var_name) :
456  previous_val_(),
457  var_name_(var_name),
458  activated_(false)
459 {
461  resources::gamedata->scoped_variables.push_back(this);
462 }
463 
465 {
466  try
467  {
468  for (const config &i : resources::gamedata->get_variables().child_range(var_name_)) {
470  }
473  LOG_NG << "scoped_wml_variable: var_name \"" << var_name_ << "\" has been auto-stored.\n";
474  activated_ = true;
475  return res;
476  }
477  catch(const invalid_variablename_exception&)
478  {
479  assert(false && "invalid variable name of autostored variable");
480  throw "assertion ignored";
481  }
482 
483 }
484 
486 {
487  if(!resources::gamedata) {
488  return;
489  }
490 
491  if(activated_) {
494  {
495  try
496  {
498  }
499  catch(const invalid_variablename_exception&)
500  {
501  }
502  }
503  LOG_NG << "scoped_wml_variable: var_name \"" << var_name_ << "\" has been reverted.\n";
504  }
505 
506  assert(resources::gamedata->scoped_variables.back() == this);
508 }
509 
511 {
512  unit_map::const_iterator itor = umap_.find(loc_);
513  if(itor != umap_.end()) {
514  config &tmp_cfg = store();
515  itor->write(tmp_cfg);
516  tmp_cfg["x"] = loc_.wml_x();
517  tmp_cfg["y"] = loc_.wml_y();
518  LOG_NG << "auto-storing $" << name() << " at (" << loc_ << ")\n";
519  } else {
520  ERR_NG << "failed to auto-store $" << name() << " at (" << loc_ << ")" << std::endl;
521  }
522 }
523 
525 {
526  if (data_) {
527  store(data_);
528  }
529 }
530 
532 {
533  assert(resources::gameboard);
534 
535  const std::vector<team>& teams = resources::gameboard->teams();
536 
537  std::vector<team>::const_iterator team_it = std::find_if(teams.begin(), teams.end(), [&](const team& t) { return t.save_id_or_number() == player_; });
538 
539  if(team_it != teams.end()) {
540  if(team_it->recall_list().size() > recall_index_) {
541  config &tmp_cfg = store();
542  team_it->recall_list()[recall_index_]->write(tmp_cfg);
543  tmp_cfg["x"] = "recall";
544  tmp_cfg["y"] = "recall";
545  LOG_NG << "auto-storing $" << name() << " for player: " << player_
546  << " at recall index: " << recall_index_ << '\n';
547  } else {
548  ERR_NG << "failed to auto-store $" << name() << " for player: " << player_
549  << " at recall index: " << recall_index_ << '\n';
550  }
551  } else {
552  ERR_NG << "failed to auto-store $" << name() << " for player: " << player_ << '\n';
553  }
554 }
void activate()
Definition: variable.cpp:510
virtual config::attribute_value get_variable_const(const std::string &id) const
Definition: variable.cpp:58
config & child(config_key_type key, int n=0)
Returns the nth child with the given key, or a reference to an invalid config if there is none...
Definition: config.cpp:420
vconfig()
Definition: variable.cpp:71
const_all_children_itors all_children_range() const
In-order iteration over all children.
Definition: config.cpp:921
std::string interpolate_variables_into_string(const std::string &str, const string_map *const symbols)
Function which will interpolate variables, starting with &#39;$&#39; in the string &#39;str&#39; with the equivalent ...
virtual const std::vector< team > & teams() const override
Definition: game_board.hpp:92
vconfig child(const std::string &key) const
Returns a child of *this whose key is key.
Definition: variable.cpp:252
std::shared_ptr< const config > cache_
Definition: variable.hpp:178
reference operator*() const
Definition: variable.cpp:320
all_children_iterator ordered_begin() const
In-order iteration over all children.
Definition: variable.cpp:445
Variant for storing WML attributes.
all_children_iterator & operator--()
Definition: variable.cpp:381
maybe_const_t< config::attribute_value, V > & as_scalar() const
If instantiated with vi_policy_const, the lifetime of the returned const attribute_value reference mi...
child_itors child_range(config_key_type key)
Definition: config.cpp:362
attribute_map::value_type attribute
Definition: config.hpp:226
int wml_x() const
Definition: location.hpp:157
~vconfig()
Default destructor, but defined here for possibly faster compiles (templates sometimes can be rough o...
Definition: variable.cpp:101
#define LOG_NG
Definition: variable.cpp:36
all_children_iterator(const Itor &i)
Definition: variable.cpp:339
const config::attribute reference
Definition: variable.hpp:110
std::string get_key() const
Definition: variable.cpp:412
-file sdl_utils.hpp
static lg::log_domain log_engine("engine")
scoped_wml_variable(const std::string &var_name)
Definition: variable.cpp:455
const_attr_itors attribute_range() const
Definition: config.cpp:809
game_data * gamedata
Definition: resources.cpp:22
map_location loc_
const config * cfg_
Used to access our config (original or copy, as appropriate).
Definition: variable.hpp:200
const_all_children_iterator ordered_end() const
Definition: config.cpp:911
child_list get_children(const std::string &key) const
Definition: variable.cpp:190
This class stores all the data for a single &#39;side&#39; (in game nomenclature).
Definition: team.hpp:44
const vconfig & make_safe() const
instruct the vconfig to make a private copy of its underlying data.
Definition: variable.cpp:127
#define WRN_NG
Definition: variable.cpp:37
const std::string & name() const
Definition: variable.hpp:224
int wml_y() const
Definition: location.hpp:158
all_children_iterator ordered_end() const
Definition: variable.cpp:450
bool memory_managed() const
Returns true if *this has made a copy of its config.
Definition: variable.hpp:194
game_board * gameboard
Definition: resources.cpp:20
bool operator==(const all_children_iterator &i) const
Definition: variable.cpp:440
config get_parsed_config() const
Definition: variable.cpp:140
std::shared_ptr< const config > cache_
Keeps a copy of our config alive when we manage our own memory.
Definition: variable.hpp:198
std::size_t count_children(const std::string &key) const
Definition: variable.cpp:220
boost::iterator_range< const_child_iterator > const_child_itors
Definition: config.hpp:210
config & store(const config &var_value=config())
Definition: variable.cpp:464
std::vector< scoped_wml_variable * > scoped_variables
Definition: game_data.hpp:33
std::size_t i
Definition: function.cpp:933
logger & err()
Definition: log.cpp:78
config::attribute_value expand(const std::string &) const
Definition: variable.cpp:312
mock_party p
bool has_child(const std::string &key) const
Returns whether or not *this has a child whose key is key.
Definition: variable.cpp:279
static map_location::DIRECTION s
static tcache cache
Definition: minimap.cpp:134
void clear_variable_cfg(const std::string &varname)
Clears only the config children does nothing if varname is no valid variable name.
Definition: game_data.cpp:102
CURSOR_TYPE get()
Definition: cursor.cpp:215
static vconfig unconstructed_vconfig()
This is just a wrapper for the default constructor; it exists for historical reasons and to make it c...
Definition: variable.cpp:116
config & add_child(config_key_type key)
Definition: config.cpp:476
#define ERR_NG
Definition: variable.cpp:38
const_all_children_iterator ordered_begin() const
Definition: config.cpp:901
Information on a WML variable.
double t
Definition: astarsearch.cpp:64
const std::pair< std::string, vconfig > value_type
Definition: variable.hpp:137
const config & cfg_
Definition: variable.hpp:27
A variable-expanding proxy for the config class.
Definition: variable.hpp:42
const config & get_config() const
Definition: variable.hpp:75
Standard logging facilities (interface).
V::result_type apply_visitor(const V &visitor) const
Applies a visitor to the underlying variant.
std::string message
Definition: exceptions.hpp:31
static vconfig empty_vconfig()
Definition: variable.cpp:105
config & add_variable_cfg(const std::string &varname, const config &value=config())
throws invalid_variablename_exception if varname is no valid variable name.
Definition: game_data.cpp:96
maybe_const_t< config::child_itors, V > as_array() const
If instantiated with vi_policy_const, the lifetime of the returned const attribute_value reference mi...
static const config default_empty_config
Definition: variable.hpp:201
std::vector< vconfig > child_list
Definition: variable.hpp:78
pointer operator->() const
Definition: variable.cpp:329
config_attribute_value attribute_value
Variant for storing WML attributes.
Definition: config.hpp:219
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:68
t_string interpolate_variables_into_tstring(const t_string &tstr, const variable_set &variables)
Function that does the same as the above, for t_stringS.
const std::string var_name_
Definition: variable.hpp:230
static map_location::DIRECTION n
virtual ~scoped_wml_variable()
Definition: variable.cpp:485
reference operator*() const
Definition: variable.cpp:400
const value_type reference
Definition: variable.hpp:143
variable_access_const get_variable_access_read(const std::string &varname) const
returns a variable_access that cannot be used to change the game variables
Definition: game_data.hpp:47
all_children_iterator & operator++()
Definition: variable.cpp:349