The Battle for Wesnoth  1.13.4+dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
variable.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2003 by David White <[email protected]>
3  Copyright (C) 2005 - 2016 by Philippe Plantier <[email protected]>
4 
5  Part of the Battle for Wesnoth Project http://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 "global.hpp"
23 
24 #include "variable.hpp"
25 
26 #include "config_assign.hpp"
27 #include "formula/string_utils.hpp"
28 #include "game_data.hpp"
29 #include "log.hpp"
30 #include "resources.hpp"
31 #include "units/unit.hpp"
32 #include "units/map.hpp"
33 #include "team.hpp"
34 
35 #include <boost/variant/static_visitor.hpp>
36 
37 static lg::log_domain log_engine("engine");
38 #define LOG_NG LOG_STREAM(info, log_engine)
39 #define WRN_NG LOG_STREAM(warn, log_engine)
40 #define ERR_NG LOG_STREAM(err, log_engine)
41 namespace
42 {
43  const config as_nonempty_range_default = config_of("_", config());
44  config::const_child_itors as_nonempty_range(const std::string& varname)
45  {
46  assert(resources::gamedata);
48 
49  if(range.first == range.second)
50  {
51  return as_nonempty_range_default.child_range("_");
52  }
53  else
54  {
55  return range;
56  }
57  }
58 }
59 
61 
62 
64  cache_(), cfg_(&default_empty_config)
65 {
66 }
67 
69  cache_(cache), cfg_(&cfg)
70 {
71 }
72 
73 /**
74  * Constructor from a config, with an option to manage memory.
75  * @param[in] cfg The "WML source" of the vconfig being constructed.
76  * @param[in] manage_memory If true, a copy of @a cfg will be made, allowing the
77  * vconfig to safely persist after @a cfg is destroyed.
78  * If false, no copy is made, so @a cfg must be
79  * guaranteed to persist as long as the vconfig will.
80  * If in doubt, set to true; it is less efficient, but safe.
81  * See also make_safe().
82  */
83 vconfig::vconfig(const config &cfg, bool manage_memory) :
84  cache_(manage_memory ? new config(cfg) : nullptr),
85  cfg_(manage_memory ? cache_.get() : &cfg)
86 {
87 }
88 
89 /**
90  * Default destructor, but defined here for possibly faster compiles
91  * (templates sometimes can be rough on the compiler).
92  */
94 {
95 }
96 
98 {
99  static const config empty_config;
100  return vconfig(empty_config, false);
101 }
102 
103 /**
104  * This is just a wrapper for the default constructor; it exists for historical
105  * reasons and to make it clear that default construction cannot be dereferenced
106  * (in contrast to an empty vconfig).
107  */
109 {
110  return vconfig();
111 }
112 
113 /**
114  * Ensures that *this manages its own memory, making it safe for *this to
115  * outlive the config it was ultimately constructed from.
116  * It is perfectly safe to call this for a vconfig that already manages its memory.
117  * This does not work on a null() vconfig.
118  */
119 void vconfig::make_safe() const
120 {
121  // Nothing to do if we already manage our own memory.
122  if ( memory_managed() )
123  return;
124 
125  // Make a copy of our config.
126  cache_.reset(new config(*cfg_));
127  // Use our copy instead of the original.
128  cfg_ = cache_.get();
129 }
130 
132 {
133  // Keeps track of insert_tag variables.
134  static std::set<std::string> vconfig_recursion;
135 
136  config res;
137 
138  for (const config::attribute &i : cfg_->attribute_range()) {
139  res[i.first] = expand(i.first);
140  }
141 
143  {
144  if (child.key == "insert_tag") {
145  vconfig insert_cfg(child.cfg);
146  const t_string& name = insert_cfg["name"];
147  const t_string& vname = insert_cfg["variable"];
148  if(!vconfig_recursion.insert(vname).second) {
149  throw recursion_error("vconfig::get_parsed_config() infinite recursion detected, aborting");
150  }
151  try
152  {
153  config::const_child_itors range = as_nonempty_range(vname);
154  for (const config& child : range)
155  {
157  }
158  }
159  catch(const invalid_variablename_exception&)
160  {
161  res.add_child(name);
162  }
163  catch(recursion_error &err) {
164  vconfig_recursion.erase(vname);
165  WRN_NG << err.message << std::endl;
166  if(vconfig_recursion.empty()) {
167  res.add_child("insert_tag", insert_cfg.get_config());
168  } else {
169  // throw to the top [insert_tag] which started the recursion
170  throw;
171  }
172  }
173  vconfig_recursion.erase(vname);
174  } else {
175  res.add_child(child.key, vconfig(child.cfg).get_parsed_config());
176  }
177  }
178  return res;
179 }
180 
182 {
184 
186  {
187  if (child.key == key) {
188  res.push_back(vconfig(child.cfg, cache_));
189  } else if (child.key == "insert_tag") {
190  vconfig insert_cfg(child.cfg);
191  if(insert_cfg["name"] == key)
192  {
193  try
194  {
195  config::const_child_itors range = as_nonempty_range(insert_cfg["variable"]);
196  for (const config& child : range)
197  {
198  res.push_back(vconfig(child, true));
199  }
200  }
201  catch(const invalid_variablename_exception&)
202  {
203  res.push_back(empty_vconfig());
204  }
205  }
206  }
207  }
208  return res;
209 }
210 
211 size_t vconfig::count_children(const std::string& key) const
212 {
213  size_t n = 0;
214 
216  {
217  if (child.key == key) {
218  n++;
219  } else if (child.key == "insert_tag") {
220  vconfig insert_cfg(child.cfg);
221  if(insert_cfg["name"] == key)
222  {
223  try
224  {
225  config::const_child_itors range = as_nonempty_range(insert_cfg["variable"]);
226  n += range.second - range.first;
227  }
228  catch(const invalid_variablename_exception&)
229  {
230  n++;
231  }
232  }
233  }
234  }
235  return n;
236 }
237 
238 /**
239  * Returns a child of *this whose key is @a key.
240  * If no such child exists, returns an unconstructed vconfig (use null() to test
241  * for this).
242  */
244 {
245  if (const config &natural = cfg_->child(key)) {
246  return vconfig(natural, cache_);
247  }
248  for (const config &ins : cfg_->child_range("insert_tag"))
249  {
250  vconfig insert_cfg(ins);
251  if(insert_cfg["name"] == key)
252  {
253  try
254  {
255  config::const_child_itors range = as_nonempty_range(insert_cfg["variable"]);
256  return vconfig(*range.first, true);
257  }
258  catch(const invalid_variablename_exception&)
259  {
260  return empty_vconfig();
261  }
262  }
263  }
264  return unconstructed_vconfig();
265 }
266 
267 /**
268  * Returns whether or not *this has a child whose key is @a key.
269  */
270 bool vconfig::has_child(const std::string& key) const
271 {
272  if (cfg_->child(key)) {
273  return true;
274  }
275  for (const config &ins : cfg_->child_range("insert_tag"))
276  {
277  vconfig insert_cfg(ins);
278  if(insert_cfg["name"] == key) {
279  return true;
280  }
281  }
282  return false;
283 }
284 
285 namespace {
286  struct vconfig_expand_visitor : boost::static_visitor<void>
287  {
289 
290  vconfig_expand_visitor(config::attribute_value &r): result(r) {}
291  template<typename T> void operator()(T const &) const {}
292  void operator()(const std::string &s) const
293  {
295  }
296  void operator()(const t_string &s) const
297  {
299  }
300  };
301 }//unnamed namespace
302 
304 {
305  config::attribute_value val = (*cfg_)[key];
307  val.apply_visitor(vconfig_expand_visitor(val));
308  return val;
309 }
310 
312  i_(i), inner_index_(0), cache_()
313 {
314 }
315 
317  i_(i), inner_index_(0), cache_(cache)
318 {
319 }
320 
322 {
323  if (inner_index_ >= 0 && i_->key == "insert_tag")
324  {
325  try
326  {
328 
330 
331  if (++inner_index_ < std::distance(range.first, range.second))
332  {
333  return *this;
334  }
335 
336  }
337  catch(const invalid_variablename_exception&)
338  {
339  }
340  inner_index_ = 0;
341  }
342  ++i_;
343  return *this;
344 }
345 
347 {
349  this->operator++();
350  return i;
351 }
352 
354 {
355  return value_type(get_key(), get_child());
356 }
357 
359 {
360  pointer_proxy p = { value_type(get_key(), get_child()) };
361  return p;
362 }
363 
364 
366 {
367  const std::string &key = i_->key;
368  if (inner_index_ >= 0 && key == "insert_tag") {
369  return vconfig(i_->cfg)["name"];
370  }
371  return key;
372 }
373 
375 {
376  if (inner_index_ >= 0 && i_->key == "insert_tag")
377  {
378  try
379  {
380  config::const_child_itors range = as_nonempty_range(vconfig(i_->cfg)["variable"]);
381 
382  std::advance(range.first, inner_index_);
383  return vconfig(*range.first, true);
384  }
385  catch(const invalid_variablename_exception&)
386  {
387  return empty_vconfig();
388  }
389  }
390  return vconfig(i_->cfg, cache_);
391 }
392 
394 {
395  return i_ == i.i_ && inner_index_ == i.inner_index_;
396 }
397 
399 {
401 }
402 
404 {
406 }
407 
409  previous_val_(),
410  var_name_(var_name),
411  activated_(false)
412 {
414  resources::gamedata->scoped_variables.push_back(this);
415 }
416 
418 {
419  try
420  {
421  for (const config &i : resources::gamedata->get_variables().child_range(var_name_)) {
423  }
426  LOG_NG << "scoped_wml_variable: var_name \"" << var_name_ << "\" has been auto-stored.\n";
427  activated_ = true;
428  return res;
429  }
430  catch(const invalid_variablename_exception&)
431  {
432  assert(false && "invalid variable name of autostored varaible");
433  throw "assertion ignored";
434  }
435 
436 }
437 
439 {
440  assert(resources::gamedata);
441 
442  if(activated_) {
445  {
446  try
447  {
449  }
450  catch(const invalid_variablename_exception&)
451  {
452  }
453  }
454  LOG_NG << "scoped_wml_variable: var_name \"" << var_name_ << "\" has been reverted.\n";
455  }
456 
457  assert(resources::gamedata->scoped_variables.back() == this);
459 }
460 
462 {
463  map_location loc = map_location(x_, y_);
465  if(itor != umap_.end()) {
466  config &tmp_cfg = store();
467  itor->write(tmp_cfg);
468  tmp_cfg["x"] = x_ + 1;
469  tmp_cfg["y"] = y_ + 1;
470  LOG_NG << "auto-storing $" << name() << " at (" << loc << ")\n";
471  } else {
472  ERR_NG << "failed to auto-store $" << name() << " at (" << loc << ")" << std::endl;
473  }
474 }
475 
477 {
478  if (data_) {
479  store(data_);
480  }
481 }
482 
484 {
485  assert(resources::teams);
486 
487  const std::vector<team>& teams = *resources::teams;
488 
489  std::vector<team>::const_iterator team_it;
490  for (team_it = teams.begin(); team_it != teams.end(); ++team_it) {
491  if (team_it->save_id() == player_ )
492  break;
493  }
494 
495  if(team_it != teams.end()) {
496  if(team_it->recall_list().size() > recall_index_) {
497  config &tmp_cfg = store();
498  team_it->recall_list()[recall_index_]->write(tmp_cfg);
499  tmp_cfg["x"] = "recall";
500  tmp_cfg["y"] = "recall";
501  LOG_NG << "auto-storing $" << name() << " for player: " << player_
502  << " at recall index: " << recall_index_ << '\n';
503  } else {
504  ERR_NG << "failed to auto-store $" << name() << " for player: " << player_
505  << " at recall index: " << recall_index_ << '\n';
506  }
507  } else {
508  ERR_NG << "failed to auto-store $" << name() << " for player: " << player_ << '\n';
509  }
510 }
511 
512 
child_itors child_range(const std::string &key)
Definition: config.cpp:613
void activate()
Definition: variable.cpp:461
size_t count_children(const std::string &key) const
Definition: variable.cpp:211
vconfig()
Definition: variable.cpp:63
unit_iterator end()
Definition: map.hpp:311
std::string interpolate_variables_into_string(const std::string &str, const string_map *const symbols)
Function which will interpolate variables, starting with '$' in the string 'str' with the equivalent ...
all_children_iterator ordered_end() const
Definition: config.cpp:1122
variable_info_detail::maybe_const< vit, config::child_itors >::type as_array() const
might throw invalid_variablename_exception
GLenum GLint * range
Definition: glew.h:3025
vconfig get_child() const
Definition: variable.cpp:374
vconfig child(const std::string &key) const
Returns a child of *this whose key is key.
Definition: variable.cpp:243
config get_parsed_config() const
Definition: variable.cpp:131
const std::string & name() const
Definition: variable.hpp:174
all_children_iterator ordered_end() const
Definition: variable.cpp:403
attribute_map::value_type attribute
Definition: config.hpp:393
GLuint const GLfloat * val
Definition: glew.h:2614
~vconfig()
Default destructor, but defined here for possibly faster compiles (templates sometimes can be rough o...
Definition: variable.cpp:93
#define LOG_NG
Definition: variable.cpp:38
all_children_iterator(const Itor &i)
Definition: variable.cpp:311
V::result_type apply_visitor(const V &visitor) const
Applies a visitor to the underlying variant.
Definition: config.hpp:377
-file sdl_utils.hpp
std::pair< std::string, vconfig > value_type
Definition: variable.hpp:97
static lg::log_domain log_engine("engine")
std::pair< const_child_iterator, const_child_iterator > const_child_itors
Definition: config.hpp:214
scoped_wml_variable(const std::string &var_name)
Definition: variable.cpp:408
const int x_
Definition: variable.hpp:201
Variant for storing WML attributes.
Definition: config.hpp:223
game_data * gamedata
Definition: resources.cpp:22
bool memory_managed() const
Returns true if *this has made a copy of its config.
Definition: variable.hpp:152
unsigned int recall_index_
Definition: variable.hpp:214
const config * cfg_
Used to access our config (original or copy, as appropriate).
Definition: variable.hpp:158
static std::vector< team > *& teams
Definition: team.cpp:50
#define WRN_NG
Definition: variable.cpp:39
GLuint64EXT * result
Definition: glew.h:10727
std::vector< team > * teams
Definition: resources.cpp:29
child_list get_children(const std::string &key) const
Definition: variable.cpp:181
static text_list cache_
Definition: font.cpp:772
all_children_itors all_children_range() const
In-order iteration over all children.
Definition: config.cpp:1127
bool has_child(const std::string &key) const
Returns whether or not *this has a child whose key is key.
Definition: variable.cpp:270
config & add_child(const std::string &key)
Definition: config.cpp:743
GLfloat GLfloat p
Definition: glew.h:12766
Encapsulates the map of the game.
Definition: location.hpp:38
config & store(const config &var_value=config())
Definition: variable.cpp:417
GLuint res
Definition: glew.h:9258
const int y_
Definition: variable.hpp:201
std::vector< scoped_wml_variable * > scoped_variables
Definition: game_data.hpp:35
std::map< std::string, tfilter >::iterator itor
Definition: filter.cpp:199
logger & err()
Definition: log.cpp:79
config::attribute_value expand(const std::string &) const
Definition: variable.cpp:303
boost::shared_ptr< const config > cache_
Keeps a copy of our config alive when we manage our own memory.
Definition: variable.hpp:156
const config & get_config() const
Definition: variable.hpp:68
const_attr_itors attribute_range() const
Definition: config.cpp:984
config const & data_
Definition: variable.hpp:191
static tcache cache
Definition: minimap.cpp:139
Information on a WML variable.
size_t i
Definition: function.cpp:1057
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:110
CURSOR_TYPE get()
Definition: cursor.cpp:194
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:49
GLdouble GLdouble GLdouble r
Definition: glew.h:1374
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:108
int i_
Definition: formula.cpp:667
const config & get_child(const std::string &key)
#define ERR_NG
Definition: variable.cpp:40
GLuint const GLchar * name
Definition: glew.h:1782
reference operator*() const
Definition: variable.cpp:353
const std::string player_
Definition: variable.hpp:213
GLclampd n
Definition: glew.h:5903
bool operator==(const all_children_iterator &i) const
Definition: variable.cpp:393
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...
Definition: config.cpp:658
A variable-expanding proxy for the config class.
Definition: variable.hpp:36
Standard logging facilities (interface).
pointer operator->() const
Definition: variable.cpp:358
std::string message
Definition: exceptions.hpp:29
static vconfig empty_vconfig()
Definition: variable.cpp:97
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:104
static const config default_empty_config
Definition: variable.hpp:159
unit_iterator find(size_t id)
Definition: map.cpp:285
std::vector< vconfig > child_list
Definition: variable.hpp:71
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:83
void make_safe() const
instruct the vconfig to make a private copy of its underlying data.
Definition: variable.cpp:119
GLdouble s
Definition: glew.h:1358
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:180
GLsizei const GLcharARB ** string
Definition: glew.h:4503
virtual ~scoped_wml_variable()
Definition: variable.cpp:438
std::string get_key() const
Definition: variable.cpp:365
all_children_iterator ordered_begin() const
In-order iteration over all children.
Definition: variable.cpp:398
const value_type reference
Definition: variable.hpp:103
all_children_iterator ordered_begin() const
Definition: config.cpp:1117
const unit_map & umap_
Definition: variable.hpp:202
all_children_iterator & operator++()
Definition: variable.cpp:321