The Battle for Wesnoth  1.13.4+dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
config.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2003 by David White <[email protected]>
3  Copyright (C) 2005 - 2016 by Guillaume Melquiond <[email protected]>
4  Part of the Battle for Wesnoth Project http://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 /**
17  * @file
18  * Routines related to configuration-files / WML.
19  */
20 
21 #include "config.hpp"
22 
23 #include "global.hpp"
24 
25 #include "log.hpp"
26 #include "util.hpp"
27 #include "utils/const_clone.hpp"
28 
29 #include <cstdlib>
30 #include <cstring>
31 #include <deque>
32 #include <istream>
33 
34 #include "utils/functional.hpp"
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>
39 
40 static lg::log_domain log_config("config");
41 #define ERR_CF LOG_STREAM(err, log_config)
42 #define DBG_CF LOG_STREAM(debug, log_config)
43 
44 
45 #ifdef USE_HETEROGENOUS_LOOKUPS
46 struct config_simple_key
47 {
48  const char* str;
49  int len;
50 
51  friend bool operator<(const config_simple_key& l, const std::string& r)
52  {
53  return r.compare(0, r.size(), l.str, l.len) > 0;
54  }
55  friend bool operator<(const std::string& l, const config_simple_key& r)
56  {
57  return l.compare(0, l.size(), r.str, r.len) < 0;
58  }
59 };
60 #endif
61 
63 {
64  /**
65  * Implementation for the wrappers for
66  * [const] config& child(const std::string& key, const std::string& parent);
67  *
68  * @tparam T A pointer to the config.
69  */
70  template<class T>
73  T config
74  , const std::string& key
75  , const std::string& parent)
76  {
77  config->check_valid();
78 
79  assert(!parent.empty());
80  assert(parent[0] == '[');
81  assert(parent[parent.size() - 1] == ']');
82 
83  if(config->has_child(key)) {
84  return *(config->children.find(key)->second.front());
85  }
86 
87  /**
88  * @todo Implement a proper wml_exception here.
89  *
90  * at the moment there seem to be dependency issues, which i don't want
91  * to fix right now.
92  */
93 // FAIL(missing_mandatory_wml_section(parent, key));
94 
95  std::stringstream sstr;
96  sstr << "Mandatory WML child »[" << key << "]« missing in »"
97  << parent << "«. Please report this bug.";
98 
99  throw config::error(sstr.str());
100  }
101 };
102 
103 
104 /* ** Attribute value implementation ** */
105 
106 
107 // Special string values.
112 
113 
114 /** Default implementation, but defined out-of-line for efficiency reasons. */
116  : value_()
117 {
118 }
119 
120 /** Default implementation, but defined out-of-line for efficiency reasons. */
122 {
123 }
124 
125 /** Default implementation, but defined out-of-line for efficiency reasons. */
127  : value_(that.value_)
128 {
129 }
130 
131 /** Default implementation, but defined out-of-line for efficiency reasons. */
133 {
134  value_ = that.value_;
135  return *this;
136 }
137 
139 {
140  value_ = yes_no(v);
141  return *this;
142 }
143 
145 {
146  value_ = v;
147  return *this;
148 }
149 
151 {
152  if ( v > 0 )
153  // We can store this unsigned.
154  return *this = static_cast<unsigned long long>(v);
155 
156  if ( v >= INT_MIN )
157  // We can store this as an int.
158  return *this = static_cast<int>(v);
159 
160  // Getting to this point should be rare. (Currently, getting here means
161  // something like there was so much draining in a campaign that the
162  // total damage taken is not only negative, but so negative that an
163  // int cannot hold the value.) So rare that it is not worth precise
164  // treatment; just use a double.
165  value_ = static_cast<double>(v);
166  return *this;
167 }
168 
170 {
171  // Use int for smaller numbers.
172  if ( v <= INT_MAX )
173  return *this = static_cast<int>(v);
174 
175  value_ = v;
176  return *this;
177 }
178 
180 {
181  // Try to store integers in other types.
182  if ( v > 0.0 ) {
183  // Convert to unsigned and pass this off to that assignment operator.
184  unsigned long long ull = static_cast<unsigned long long>(v);
185  if ( static_cast<double>(ull) == v )
186  return *this = ull;
187  }
188  else {
189  // Convert to integer and pass this off to that assignment operator.
190  int i = static_cast<int>(v);
191  if ( static_cast<double>(i) == v )
192  return *this = i;
193  }
194 
195  // If we get here, this does in fact get stored as a double.
196  value_ = v;
197  return *this;
198 }
199 
200 namespace {
201  /**
202  * Attempts to convert @a source to the template type.
203  * This is to avoid "overzealous reinterpretations of certain WML strings as
204  * numeric types" (c.f. bug #19201).
205  * @returns true if the conversion was successful and the source string
206  * can be reobtained by streaming the result.
207  */
208  template<typename To>
209  bool from_string_verify(const std::string & source, To & res)
210  {
211  // Check 1: convertable to the target type.
212  std::istringstream in_str(source);
213  if ( !(in_str >> res) )
214  return false;
215 
216  // Check 2: convertable back to the same string.
217  std::ostringstream out_str;
218  out_str << res;
219  return out_str.str() == source;
220  }
221 }
223 {
224  // Handle some special strings.
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; }
230 
231  // Attempt to convert to a number.
232  char *eptr;
233  double d = strtod(v.c_str(), &eptr);
234  if ( *eptr == '\0' ) {
235  // Possibly a number. See what type it should be stored in.
236  // (All conversions will be from the string since the largest integer
237  // type could have more precision than a double.)
238  if ( d > 0.0 ) {
239  // The largest type for positive integers is unsigned long long.
240  unsigned long long ull = 0;
241  if ( from_string_verify<unsigned long long>(v, ull) )
242  return *this = ull;
243  }
244  else {
245  // The largest (variant) type for negative integers is int.
246  int i = 0;
247  if ( from_string_verify<int>(v, i) )
248  return *this = i;
249  }
250 
251  // This does not look like an integer, so it should be a double.
252  // However, make sure it can convert back to the same string (in
253  // case this is a string that just looks like a numeric value).
254  std::ostringstream tester;
255  tester << d;
256  if ( tester.str() == v ) {
257  value_ = d;
258  return *this;
259  }
260  }
261 
262  // No conversion possible. Store the string.
263  value_ = v;
264  return *this;
265 }
266 
268 {
269  if (!v.translatable()) return *this = v.str();
270  value_ = v;
271  return *this;
272 }
273 
274 
276 {
277  if ( const yes_no *p = boost::get<const yes_no>(&value_) )
278  return *p;
279  if ( const true_false *p = boost::get<const true_false>(&value_) )
280  return *p;
281 
282  // No other types are ever recognized as boolean.
283  return def;
284 }
285 
286 namespace {
287  /// Visitor for converting a variant to a numeric type (T).
288  template <typename T>
289  class attribute_numeric_visitor : public boost::static_visitor<T>
290  {
291  public:
292  // Constructor stores the default value.
293  attribute_numeric_visitor(T def) : def_(def) {}
294 
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_; }
302 
303  private:
304  const T def_;
305  };
306 }
307 
309 {
310  return apply_visitor(attribute_numeric_visitor<int>(def));
311 }
312 
313 long long config::attribute_value::to_long_long(long long def) const
314 {
315  return apply_visitor(attribute_numeric_visitor<long long>(def));
316 }
317 
318 unsigned config::attribute_value::to_unsigned(unsigned def) const
319 {
320  return apply_visitor(attribute_numeric_visitor<unsigned>(def));
321 }
322 
323 size_t config::attribute_value::to_size_t(size_t def) const
324 {
325  return apply_visitor(attribute_numeric_visitor<size_t>(def));
326 }
327 
328 time_t config::attribute_value::to_time_t(time_t def) const
329 {
330  return apply_visitor(attribute_numeric_visitor<time_t>(def));
331 }
332 
333 double config::attribute_value::to_double(double def) const
334 {
335  return apply_visitor(attribute_numeric_visitor<double>(def));
336 }
337 
338 /// Visitor for converting a variant to a string.
340  : public boost::static_visitor<std::string>
341 {
342 public:
343  std::string operator()(const boost::blank &) const { return std::string(); }
344  std::string operator()(const yes_no & b) const { return b.str(); }
345  std::string operator()(const true_false & b) const { return b.str(); }
347  std::string operator()(unsigned long long u) const { return lexical_cast<std::string>(u); }
348  std::string operator()(double d) const { return lexical_cast<std::string>(d); }
349  std::string operator()(std::string const &s) const { return s; }
350  std::string operator()(t_string const &s) const { return s.str(); }
351 };
352 
354 {
355  return apply_visitor(string_visitor());
356 }
357 
359 {
360  if (const t_string *p = boost::get<const t_string>(&value_)) return *p;
361  return str();
362 }
363 
364 /**
365  * Tests for an attribute that was never set.
366  */
368 {
369  return boost::get<const boost::blank>(&value_) != nullptr;
370 }
371 
372 /**
373  * Tests for an attribute that either was never set or was set to "".
374  */
376 {
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();
379  return false;
380 }
381 
382 
383 /// Visitor handling equality checks.
385  : public boost::static_visitor<bool>
386 {
387 public:
388  // Most generic: not equal.
389  template <typename T, typename U>
390  bool operator()(const T &, const U &) const { return false; }
391 
392  // Same types are comparable and might be equal.
393  template <typename T>
394  bool operator()(const T & lhs, const T & rhs) const { return lhs == rhs; }
395 
396  // Boolean values can be compared.
397  bool operator()(const true_false & lhs, const yes_no & rhs) const { return bool(lhs) == bool(rhs); }
398  bool operator()(const yes_no & lhs, const true_false & rhs) const { return bool(lhs) == bool(rhs); }
399 };
400 
401 /**
402  * Checks for equality of the attribute values when viewed as strings.
403  * Exception: Boolean synonyms can be equal ("yes" == "true").
404  * Note: Blanks have no string representation, so do not equal "" (an empty string).
405  */
407 {
408  return boost::apply_visitor(equality_visitor(), value_, other.value_);
409 }
410 
411 /**
412  * Checks for equality of the attribute values when viewed as strings.
413  * Exception: Boolean synonyms can be equal ("yes" == "true").
414  * Note: Blanks have no string representation, so do not equal "" (an empty string).
415  * Also note that translatable string are never equal to non translatable strings.
416  */
418 {
420  v = str;
421  return *this == v;
422  // if c["a"] = "1" then this solution would have resulted in c["a"] == "1" beeing false
423  // because a["a"] is '1' and not '"1"'.
424  // return boost::apply_visitor(std::bind( equality_visitor(), _1, boost::cref(str) ), value_);
425  // that's why we don't use it.
426 }
427 
428 std::ostream &operator<<(std::ostream &os, const config::attribute_value &v)
429 {
430  // Simple implementation, but defined out-of-line because of the templating
431  // involved.
432  return os << v.value_;
433 }
434 
435 
436 /* ** config implementation ** */
437 
438 
440 
441 const char* config::diff_track_attribute = "__diff_track";
442 
444 {
445  if (!*this)
446  throw error("Mandatory WML child missing yet untested for. Please report.");
447 }
448 
449 void config::check_valid(const config &cfg) const
450 {
451  if (!*this || !cfg)
452  throw error("Mandatory WML child missing yet untested for. Please report.");
453 }
454 
456 {
457 }
458 
459 config::config(const config& cfg) : values(cfg.values), children(), ordered_children()
460 {
461  append_children(cfg);
462 }
463 
464 config::config(const std::string& child) : values(), children(), ordered_children()
465 {
466  add_child(child);
467 }
468 
470 {
471  clear();
472 }
473 
475 {
476  if(this == &cfg) {
477  return *this;
478  }
479  config tmp(cfg);
480  swap(tmp);
481  return *this;
482 }
483 
485  values(std::move(cfg.values)),
486  children(std::move(cfg.children)),
487  ordered_children(std::move(cfg.ordered_children))
488 {
489 }
490 
492 {
493  clear();
494  swap(cfg);
495  return *this;
496 }
497 
499 {
500  if (id.empty()) {
501  return false;
502  }
503  for (char c : id) {
504  if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_') {
505  //valid character.
506  }
507  else {
508  return false;
509  }
510  }
511  return true;
512 }
513 
514 bool config::has_attribute(const std::string &key) const
515 {
516  check_valid();
517  return values.find(key) != values.end();
518 }
519 
520 bool config::has_old_attribute(const std::string &key, const std::string &old_key, const std::string& msg) const
521 {
522  check_valid();
523  if (values.find(key) != values.end()) {
524  return true;
525  } else if (values.find(old_key) != values.end()) {
526  if (!msg.empty())
527  lg::wml_error() << msg;
528  return true;
529  }
530  return false;
531 }
532 
533 
535 {
536  check_valid();
537  values.erase(key);
538 }
539 
541 {
542  check_valid(cfg);
543 
544  for (const any_child &value : cfg.all_children_range()) {
545  add_child(value.key, value.cfg);
546  }
547 }
548 
550 {
551  check_valid(cfg);
552  for (const attribute &v : cfg.values) {
553  values[v.first] = v.second;
554  }
555 }
556 
557 void config::append_children(const config &cfg, const std::string& key)
558 {
559  check_valid(cfg);
560 
561  for (const config &value : cfg.child_range(key)) {
562  add_child(key, value);
563  }
564 }
565 
566 void config::append(const config &cfg)
567 {
568  append_children(cfg);
569  for (const attribute &v : cfg.values) {
570  values[v.first] = v.second;
571  }
572 }
573 
575 {
576  check_valid();
577 
578  if (child_count(key) < 2) return;
579 
580  config merged_children;
581  for (const config &cfg : child_range(key)) {
582  merged_children.append(cfg);
583  }
584 
585  clear_children(key);
586  add_child(key,merged_children);
587 }
588 
590 {
591  check_valid();
592 
593  if (child_count(key) < 2) return;
594 
595  typedef std::map<std::string, config> config_map;
596  config_map merged_children_map;
597  for (const config &cfg : child_range(key)) {
598  const std::string &value = cfg[attribute];
599  config_map::iterator m = merged_children_map.find(value);
600  if ( m!=merged_children_map.end() ) {
601  m->second.append(cfg);
602  } else {
603  merged_children_map.insert(make_pair(value, cfg));
604  }
605  }
606 
607  clear_children(key);
608  for (const config_map::value_type &i : merged_children_map) {
609  add_child(key,i.second);
610  }
611 }
612 
614 {
615  check_valid();
616 
617  child_map::iterator i = children.find(key);
618  static child_list dummy;
619  child_list *p = &dummy;
620  if (i != children.end()) p = &i->second;
621  return child_itors(child_iterator(p->begin()), child_iterator(p->end()));
622 }
623 
625 {
626  check_valid();
627 
628  child_map::const_iterator i = children.find(key);
629  static child_list dummy;
630  const child_list *p = &dummy;
631  if (i != children.end()) p = &i->second;
632  return const_child_itors(const_child_iterator(p->begin()), const_child_iterator(p->end()));
633 }
634 
635 unsigned config::child_count(const std::string &key) const
636 {
637  check_valid();
638 
639  child_map::const_iterator i = children.find(key);
640  if(i != children.end()) {
641  return i->second.size();
642  }
643  return 0;
644 }
645 
647 {
648  return ordered_children.size();
649 }
650 
651 bool config::has_child(const std::string &key) const
652 {
653  check_valid();
654 
655  return children.find(key) != children.end();
656 }
657 
659 {
660  check_valid();
661 
662  const child_map::const_iterator i = children.find(key);
663  if (i == children.end()) {
664  DBG_CF << "The config object has no child named »"
665  << key << "«.\n";
666 
667  return invalid;
668  }
669 
670  if (n < 0) n = i->second.size() + n;
671  if(size_t(n) < i->second.size()) {
672  return *i->second[n];
673  }
674  else {
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";
678 
679  return invalid;
680  }
681 }
682 
683 #ifdef USE_HETEROGENOUS_LOOKUPS
684 config &config::child_impl(const char* key, int len, int n)
685 {
686  check_valid();
687 
688  const child_map::const_iterator i = children.find(config_simple_key{ key, len });
689  if (i == children.end()) {
690  DBG_CF << "The config object has no child named »"
691  << key << "«.\n";
692 
693  return invalid;
694  }
695 
696  if (n < 0) n = i->second.size() + n;
697  if (size_t(n) < i->second.size()) {
698  return *i->second[n];
699  }
700  else {
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";
704 
705  return invalid;
706  }
707 }
708 #endif
709 
710 config& config::child(const std::string& key, const std::string& parent)
711 {
712  return tconfig_implementation::child(this, key, parent);
713 }
714 
716  const std::string& key
717  , const std::string& parent) const
718 {
719  return tconfig_implementation::child(this, key, parent);
720 }
721 
722 const config & config::child_or_empty(const std::string& key) const
723 {
724  static const config empty_cfg;
725  check_valid();
726 
727  child_map::const_iterator i = children.find(key);
728  if (i != children.end() && !i->second.empty())
729  return *i->second.front();
730 
731  return empty_cfg;
732 }
733 
735 {
736  child_map::const_iterator i = children.find(key);
737  if (i != children.end() && !i->second.empty())
738  return *i->second.front();
739 
740  return add_child(key);
741 }
742 
744 {
745  check_valid();
746 
747  child_list& v = children[key];
748  v.push_back(new config());
749  ordered_children.push_back(child_pos(children.find(key),v.size()-1));
750  return *v.back();
751 }
752 
754 {
755  check_valid(val);
756 
757  child_list& v = children[key];
758  v.push_back(new config(val));
759  ordered_children.push_back(child_pos(children.find(key),v.size()-1));
760  return *v.back();
761 }
762 
764 {
765  check_valid(val);
766 
767  child_list &v = children[key];
768  v.push_back(new config(std::move(val)));
769  ordered_children.push_back(child_pos(children.find(key), v.size() - 1));
770  return *v.back();
771 }
772 
773 config &config::add_child_at(const std::string &key, const config &val, unsigned index)
774 {
775  check_valid(val);
776 
777  child_list& v = children[key];
778  if(index > v.size()) {
779  throw error("illegal index to add child at");
780  }
781 
782  v.insert(v.begin()+index,new config(val));
783 
784  bool inserted = false;
785 
786  const child_pos value(children.find(key),index);
787 
789  for(; ord != ordered_children.end(); ++ord) {
790  if (ord->pos != value.pos) continue;
791  if (!inserted && ord->index == index) {
792  ord = ordered_children.insert(ord,value);
793  inserted = true;
794  } else if (ord->index >= index) {
795  ord->index++;
796  }
797  }
798 
799  if(!inserted) {
800  ordered_children.push_back(value);
801  }
802 
803  return *v[index];
804 }
805 
806 namespace {
807 
808 struct remove_ordered
809 {
810  remove_ordered(const config::child_map::iterator &iter) : iter_(iter) {}
811 
812  bool operator()(const config::child_pos &pos) const
813  { return pos.pos == iter_; }
814 private:
816 };
817 
818 }
819 
821 {
822  check_valid();
823 
824  child_map::iterator i = children.find(key);
825  if (i == children.end()) return;
826 
827  ordered_children.erase(std::remove_if(ordered_children.begin(),
828  ordered_children.end(), remove_ordered(i)), ordered_children.end());
829 
830  for (config *c : i->second) {
831  delete c;
832  }
833 
834  children.erase(i);
835 }
836 
838 {
839  check_valid(src);
840 
841  child_map::iterator i_src = src.children.find(key);
842  if (i_src == src.children.end()) return;
843 
844  src.ordered_children.erase(std::remove_if(src.ordered_children.begin(),
845  src.ordered_children.end(), remove_ordered(i_src)),
846  src.ordered_children.end());
847 
848  child_list &dst = children[key];
849  child_map::iterator i_dst = children.find(key);
850  unsigned before = dst.size();
851  dst.insert(dst.end(), i_src->second.begin(), i_src->second.end());
852  src.children.erase(i_src);
853  // key might be a reference to i_src->first, so it is no longer usable.
854 
855  for (unsigned j = before; j < dst.size(); ++j) {
856  ordered_children.push_back(child_pos(i_dst, j));
857  }
858 }
859 
861 {
862  check_valid();
863 
864  values.erase(key);
865 
866  for (const any_child &value : all_children_range()) {
867  const_cast<config *>(&value.cfg)->recursive_clear_value(key);
868  }
869 }
870 
872  const child_map::iterator &pos, unsigned index)
873 {
874  /* Find the position with the correct index and decrement all the
875  indices in the ordering that are above this index. */
876  unsigned found = 0;
877  for (child_pos &p : ordered_children)
878  {
879  if (p.pos != pos) continue;
880  if (p.index == index)
881  found = &p - &ordered_children.front();
882  else if (p.index > index)
883  --p.index;
884  }
885 
886  // Remove from the child map.
887  delete pos->second[index];
888  pos->second.erase(pos->second.begin() + index);
889 
890  // Erase from the ordering and return the next position.
891  return ordered_children.erase(ordered_children.begin() + found);
892 }
893 
895 {
896  return all_children_iterator(remove_child(i.i_->pos, i.i_->index));
897 }
898 
899 void config::remove_child(const std::string &key, unsigned index)
900 {
901  check_valid();
902 
903  child_map::iterator i = children.find(key);
904  if (i == children.end() || index >= i->second.size()) {
905  ERR_CF << "Error: attempting to delete non-existing child: "
906  << key << "[" << index << "]\n";
907  return;
908  }
909 
910  remove_child(i, index);
911 }
912 
914 {
915  check_valid();
916 
917  const attribute_map::const_iterator i = values.find(key);
918  if (i != values.end()) return i->second;
919  static const attribute_value empty_attribute;
920  return empty_attribute;
921 }
922 
923 #ifdef USE_HETEROGENOUS_LOOKUPS
924 const config::attribute_value& config::get_attribute(const char* key, int len) const
925 {
926  check_valid();
927 
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;
932 }
933 
934 #endif
936 {
937  check_valid();
938  attribute_map::const_iterator i = values.find(key);
939  return i != values.end() ? &i->second : nullptr;
940 }
941 
943 {
944  check_valid();
945  return values[key];
946 }
947 
949 {
950  check_valid();
951 
952  attribute_map::const_iterator i = values.find(key);
953  if (i != values.end())
954  return i->second;
955 
956  i = values.find(old_key);
957  if (i != values.end()) {
958  if (!msg.empty())
959  lg::wml_error() << msg;
960  return i->second;
961  }
962 
963  static const attribute_value empty_attribute;
964  return empty_attribute;
965 }
966 
967 
969 {
970  check_valid(cfg);
971 
972  assert(this != &cfg);
973  for (const attribute &v : cfg.values) {
974 
975  std::string key = v.first;
976  if (key.substr(0,7) == "add_to_") {
977  std::string add_to = key.substr(7);
978  values[add_to] = values[add_to].to_int() + v.second.to_int();
979  } else
980  values[v.first] = v.second;
981  }
982 }
983 
985 {
986  check_valid();
987 
990 }
991 
992 namespace {
993 
994 struct config_has_value {
995  config_has_value(const std::string& name, const std::string& value)
996  : name_(name), value_()
997  {
998  value_ = value;
999  }
1000 
1001  bool operator()(const config* cfg) const { return (*cfg)[name_] == value_; }
1002 
1003 private:
1004  std::string name_;
1005  config::attribute_value value_;
1006 };
1007 
1008 } // end namespace
1009 
1011  const std::string &value)
1012 {
1013  check_valid();
1014 
1015  const child_map::iterator i = children.find(key);
1016  if(i == children.end()) {
1017  DBG_CF << "Key »" << name << "« value »" << value
1018  << "« pair not found as child of key »" << key << "«.\n";
1019 
1020  return invalid;
1021  }
1022 
1023  const child_list::iterator j = std::find_if(i->second.begin(),
1024  i->second.end(),
1025  config_has_value(name,value));
1026  if(j != i->second.end()) {
1027  return **j;
1028  } else {
1029  DBG_CF << "Key »" << name << "« value »" << value
1030  << "« pair not found as child of key »" << key << "«.\n";
1031 
1032  return invalid;
1033  }
1034 }
1035 
1036 namespace {
1037  /**
1038  * Helper struct for iterative config clearing.
1039  */
1040  struct config_clear_state
1041  {
1042  config_clear_state()
1043  : c(nullptr)
1044  , mi()
1045  , vi(0)
1046  {
1047  }
1048 
1049  config* c; //the config being inspected
1050  config::child_map::iterator mi; //current child map entry
1051  size_t vi; //index into the child map item vector
1052  };
1053 }
1054 
1056 {
1057  // No validity check for this function.
1058 
1059  if (!children.empty()) {
1060  //start with this node, the first entry in the child map,
1061  //zeroeth element in that entry
1062  config_clear_state init;
1063  init.c = this;
1064  init.mi = children.begin();
1065  init.vi = 0;
1066  std::deque<config_clear_state> l;
1067  l.push_back(init);
1068 
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()) {
1074  config* c = v[state.vi];
1075  ++state.vi;
1076  if (c->children.empty()) {
1077  delete c; //special case for a slight speed increase?
1078  } else {
1079  //descend to the next level
1080  config_clear_state next;
1081  next.c = c;
1082  next.mi = c->children.begin();
1083  next.vi = 0;
1084  l.push_back(next);
1085  }
1086  } else {
1087  state.vi = 0;
1088  ++state.mi;
1089  }
1090  } else {
1091  //reached end of child map for this element - all child nodes
1092  //have been deleted, so it's safe to clear the map, delete the
1093  //node and move up one level
1094  state.c->children.clear();
1095  if (state.c != this) delete state.c;
1096  l.pop_back();
1097  }
1098  }
1099  }
1100 
1101  values.clear();
1102  ordered_children.clear();
1103 }
1104 
1105 bool config::empty() const
1106 {
1107  check_valid();
1108 
1109  return children.empty() && values.empty();
1110 }
1111 
1113 {
1114  return any_child(&i_->pos->first, i_->pos->second[i_->index]);
1115 }
1116 
1118 {
1119  return all_children_iterator(ordered_children.begin());
1120 }
1121 
1123 {
1125 }
1126 
1128 {
1129  return all_children_itors(
1132 }
1133 
1135 {
1136  check_valid(c);
1137 
1138  config res;
1139  get_diff(c, res);
1140  return res;
1141 }
1142 
1143 void config::get_diff(const config& c, config& res) const
1144 {
1145  check_valid(c);
1146  check_valid(res);
1147 
1148  config* inserts = nullptr;
1149 
1150  attribute_map::const_iterator i;
1151  for(i = values.begin(); i != values.end(); ++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) {
1156  inserts = &res.add_child("insert");
1157  }
1158 
1159  (*inserts)[i->first] = i->second;
1160  }
1161  }
1162 
1163  config* deletes = nullptr;
1164 
1165  for(i = c.values.begin(); i != c.values.end(); ++i) {
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) {
1170  deletes = &res.add_child("delete");
1171  }
1172 
1173  (*deletes)[i->first] = "x";
1174  }
1175  }
1176 
1177  std::vector<std::string> entities;
1178 
1179  child_map::const_iterator ci;
1180  for(ci = children.begin(); ci != children.end(); ++ci) {
1181  entities.push_back(ci->first);
1182  }
1183 
1184  for(ci = c.children.begin(); ci != c.children.end(); ++ci) {
1185  if(children.count(ci->first) == 0) {
1186  entities.push_back(ci->first);
1187  }
1188  }
1189 
1190  for(std::vector<std::string>::const_iterator itor = entities.begin(); itor != entities.end(); ++itor) {
1191 
1192  const child_map::const_iterator itor_a = children.find(*itor);
1193  const child_map::const_iterator itor_b = c.children.find(*itor);
1194 
1195  static const child_list dummy;
1196 
1197  // Get the two child lists. 'b' has to be modified to look like 'a'.
1198  const child_list& a = itor_a != children.end() ? itor_a->second : dummy;
1199  const child_list& b = itor_b != c.children.end() ? itor_b->second : dummy;
1200 
1201  size_t ndeletes = 0;
1202  size_t ai = 0, bi = 0;
1203  while(ai != a.size() || bi != b.size()) {
1204  // If the two elements are the same, nothing needs to be done.
1205  if(ai < a.size() && bi < b.size() && *a[ai] == *b[bi]) {
1206  ++ai;
1207  ++bi;
1208  } else {
1209  // We have to work out what the most appropriate operation --
1210  // delete, insert, or change is the best to get b[bi] looking like a[ai].
1211  std::stringstream buf;
1212 
1213  // If b has more elements than a, then we assume this element
1214  // is an element that needs deleting.
1215  if(b.size() - bi > a.size() - ai) {
1216  config& new_delete = res.add_child("delete_child");
1217  buf << bi - ndeletes;
1218  new_delete.values["index"] = buf.str();
1219  new_delete.add_child(*itor);
1220 
1221  ++ndeletes;
1222  ++bi;
1223  }
1224 
1225  // If b has less elements than a, then we assume this element
1226  // is an element that needs inserting.
1227  else if(b.size() - bi < a.size() - ai) {
1228  config& new_insert = res.add_child("insert_child");
1229  buf << ai;
1230  new_insert.values["index"] = buf.str();
1231  new_insert.add_child(*itor,*a[ai]);
1232 
1233  ++ai;
1234  }
1235 
1236  // Otherwise, they have the same number of elements,
1237  // so try just changing this element to match.
1238  else {
1239  config& new_change = res.add_child("change_child");
1240  buf << bi;
1241  new_change.values["index"] = buf.str();
1242  new_change.add_child(*itor,a[ai]->get_diff(*b[bi]));
1243 
1244  ++ai;
1245  ++bi;
1246  }
1247  }
1248  }
1249  }
1250 }
1251 
1252 void config::apply_diff(const config& diff, bool track /* = false */)
1253 {
1254  check_valid(diff);
1255 
1256  if (track) values[diff_track_attribute] = "modified";
1257 
1258  if (const config &inserts = diff.child("insert")) {
1259  for (const attribute &v : inserts.attribute_range()) {
1260  values[v.first] = v.second;
1261  }
1262  }
1263 
1264  if (const config &deletes = diff.child("delete")) {
1265  for (const attribute &v : deletes.attribute_range()) {
1266  values.erase(v.first);
1267  }
1268  }
1269 
1270  for (const config &i : diff.child_range("change_child"))
1271  {
1272  const size_t index = lexical_cast<size_t>(i["index"].str());
1273  for (const any_child &item : i.all_children_range())
1274  {
1275  if (item.key.empty()) {
1276  continue;
1277  }
1278 
1279  const child_map::iterator itor = children.find(item.key);
1280  if(itor == children.end() || index >= itor->second.size()) {
1281  throw error("error in diff: could not find element '" + item.key + "'");
1282  }
1283 
1284  itor->second[index]->apply_diff(item.cfg, track);
1285  }
1286  }
1287 
1288  for (const config &i : diff.child_range("insert_child"))
1289  {
1290  const size_t index = lexical_cast<size_t>(i["index"].str());
1291  for (const any_child &item : i.all_children_range()) {
1292  config& inserted = add_child_at(item.key, item.cfg, index);
1293  if (track) inserted[diff_track_attribute] = "new";
1294  }
1295  }
1296 
1297  for (const config &i : diff.child_range("delete_child"))
1298  {
1299  const size_t index = lexical_cast<size_t>(i["index"].str());
1300  for (const any_child &item : i.all_children_range()) {
1301  if (!track) {
1302  remove_child(item.key, index);
1303  } else {
1304  const child_map::iterator itor = children.find(item.key);
1305  if(itor == children.end() || index >= itor->second.size()) {
1306  throw error("error in diff: could not find element '" + item.key + "'");
1307  }
1308  itor->second[index]->values[diff_track_attribute] = "deleted";
1309  }
1310  }
1311  }
1312 }
1313 
1315 {
1317  for (const config &i : diff.child_range("delete_child"))
1318  {
1319  const size_t index = lexical_cast<size_t>(i["index"].str());
1320  for (const any_child &item : i.all_children_range()) {
1321  remove_child(item.key, index);
1322  }
1323  }
1324 
1325  for (const config &i : diff.child_range("change_child"))
1326  {
1327  const size_t index = lexical_cast<size_t>(i["index"].str());
1328  for (const any_child &item : i.all_children_range())
1329  {
1330  if (item.key.empty()) {
1331  continue;
1332  }
1333 
1334  const child_map::iterator itor = children.find(item.key);
1335  if(itor == children.end() || index >= itor->second.size()) {
1336  throw error("error in diff: could not find element '" + item.key + "'");
1337  }
1338 
1339  itor->second[index]->clear_diff_track(item.cfg);
1340  }
1341  }
1342  for (const any_child &value : all_children_range()) {
1343  const_cast<config *>(&value.cfg)->remove_attribute(diff_track_attribute);
1344  }
1345 }
1346 
1347 /**
1348  * Merge config 'c' into this config, overwriting this config's values.
1349  */
1351 {
1352  check_valid(c);
1353 
1354  std::vector<child_pos> to_remove;
1355  std::map<std::string, unsigned> visitations;
1356 
1357  // Merge attributes first
1358  merge_attributes(c);
1359 
1360  // Now merge shared tags
1362  for(i = ordered_children.begin(); i != i_end; ++i) {
1363  const std::string& tag = i->pos->first;
1364  const child_map::const_iterator j = c.children.find(tag);
1365  if (j != c.children.end()) {
1366  unsigned &visits = visitations[tag];
1367  if(visits < j->second.size()) {
1368  // Get a const config so we do not add attributes.
1369  const config & merge_child = *j->second[visits++];
1370 
1371  if ( merge_child["__remove"].to_bool() ) {
1372  to_remove.push_back(*i);
1373  } else
1374  (i->pos->second[i->index])->merge_with(merge_child);
1375  }
1376  }
1377  }
1378 
1379  // Now add any unvisited tags
1380  for(child_map::const_iterator j = c.children.begin(); j != c.children.end(); ++j) {
1381  const std::string& tag = j->first;
1382  unsigned &visits = visitations[tag];
1383  while(visits < j->second.size()) {
1384  add_child(tag, *j->second[visits++]);
1385  }
1386  }
1387 
1388  // Remove those marked so
1389  std::map<std::string, unsigned> removals;
1390  for (const child_pos& pos : to_remove) {
1391  const std::string& tag = pos.pos->first;
1392  unsigned &removes = removals[tag];
1393  remove_child(tag, pos.index - removes++);
1394  }
1395 
1396 }
1397 
1398 /**
1399  * Merge config 'c' into this config, preserving this config's values.
1400  */
1402 {
1403  // Using a scratch config and merge_with() seems to execute about as fast
1404  // as direct coding of this merge.
1405  config scratch(c);
1406  scratch.merge_with(*this);
1407  swap(scratch);
1408 }
1409 
1410 bool config::matches(const config &filter) const
1411 {
1412  check_valid(filter);
1413 
1414  for (const attribute &i : filter.attribute_range())
1415  {
1416  const attribute_value *v = get(i.first);
1417  if (!v || *v != i.second) return false;
1418  }
1419 
1420  for (const any_child &i : filter.all_children_range())
1421  {
1422  if (i.key == "not") {
1423  if (matches(i.cfg)) return false;
1424  continue;
1425  }
1426  bool found = false;
1427  for (const config &j : child_range(i.key)) {
1428  if (j.matches(i.cfg)) {
1429  found = true;
1430  break;
1431  }
1432  }
1433  if(!found) return false;
1434  }
1435  return true;
1436 }
1437 
1439 {
1440  check_valid();
1441 
1442  std::ostringstream outstream;
1443  outstream << *this;
1444  return outstream.str();
1445 }
1446 
1447 std::ostream& operator << (std::ostream& outstream, const config& cfg)
1448 {
1449  static int i = 0;
1450  i++;
1451  for (const config::attribute &val : cfg.attribute_range()) {
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';
1455  }
1456  for (const config::any_child &child : cfg.all_children_range())
1457  {
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";
1463  }
1464  i--;
1465  return outstream;
1466 }
1467 
1469 {
1470  check_valid();
1471 
1472  static const unsigned int hash_length = 128;
1473  static const char hash_string[] =
1474  "+-,.<>0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
1475  char hash_str[hash_length + 1];
1476  std::string::const_iterator c;
1477 
1478  unsigned int i;
1479  for(i = 0; i != hash_length; ++i) {
1480  hash_str[i] = 'a';
1481  }
1482  hash_str[hash_length] = 0;
1483 
1484  i = 0;
1485  for (const attribute &val : values)
1486  {
1487  for (c = val.first.begin(); c != val.first.end(); ++c) {
1488  hash_str[i] ^= *c;
1489  if (++i == hash_length) i = 0;
1490  }
1491  std::string base_str = val.second.t_str().base_str();
1492  for (c = base_str.begin(); c != base_str.end(); ++c) {
1493  hash_str[i] ^= *c;
1494  if (++i == hash_length) i = 0;
1495  }
1496  }
1497 
1498  for (const any_child &ch : all_children_range())
1499  {
1500  std::string child_hash = ch.cfg.hash();
1501  for (char c : child_hash) {
1502  hash_str[i] ^= c;
1503  ++i;
1504  if(i == hash_length) {
1505  i = 0;
1506  }
1507  }
1508  }
1509 
1510  for(i = 0; i != hash_length; ++i) {
1511  hash_str[i] = hash_string[
1512  static_cast<unsigned>(hash_str[i]) % strlen(hash_string)];
1513  }
1514 
1515  return std::string(hash_str);
1516 }
1517 
1519 {
1520  check_valid(cfg);
1521 
1522  values.swap(cfg.values);
1523  children.swap(cfg.children);
1525 }
1526 
1527 bool operator==(const config& a, const config& b)
1528 {
1529  a.check_valid(b);
1530 
1531  if (a.values != b.values)
1532  return false;
1533 
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) {
1537  return false;
1538  }
1539  }
1540 
1541  return x.first == x.second && y.first == y.second;
1542 }
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...
Definition: config.cpp:948
child_itors child_range(const std::string &key)
Definition: config.cpp:613
double to_double(double def=0.) const
Definition: config.cpp:333
void remove_attribute(const std::string &key)
Definition: config.cpp:534
std::string operator()(int i) const
Definition: config.cpp:346
std::string str() const
Definition: config.cpp:353
~attribute_value()
Default implementation, but defined out-of-line for efficiency reasons.
Definition: config.cpp:121
child_map::iterator pos
Definition: config.hpp:619
bool translatable() const
Definition: tstring.hpp:172
static const std::string s_no
Definition: config.hpp:382
std::string operator()(t_string const &s) const
Definition: config.cpp:350
bool matches(const config &filter) const
Definition: config.cpp:1410
static const std::string s_false
Definition: config.hpp:383
void append_attributes(const config &cfg)
Adds attributes from cfg.
Definition: config.cpp:549
const std::string & str() const
Definition: config.hpp:250
all_children_iterator ordered_end() const
Definition: config.cpp:1122
std::pair< const_attribute_iterator, const_attribute_iterator > const_attr_itors
Definition: config.hpp:418
size_t to_size_t(size_t def=0) const
Definition: config.cpp:323
void append(const config &cfg)
Append data from another config object to this one.
Definition: config.cpp:566
const GLfloat * c
Definition: glew.h:12741
int pos
Definition: formula.cpp:800
std::vector< child_pos >::const_iterator Itor
Definition: config.hpp:647
bool to_bool(bool def=false) const
Definition: config.cpp:275
bool operator()(const T &, const U &) const
Definition: config.cpp:390
t_string t_str() const
Definition: config.cpp:358
bool operator()(const true_false &lhs, const yes_no &rhs) const
Definition: config.cpp:397
void merge_children(const std::string &key)
All children with the given key will be merged into the first element with that key.
Definition: config.cpp:574
static l_noret error(LoadState *S, const char *why)
Definition: lundump.cpp:29
config & child_or_add(const std::string &key)
Returns a reference to the first child with the given key.
Definition: config.cpp:734
friend bool operator==(const config &a, const config &b)
Definition: config.cpp:1527
Visitor for converting a variant to a string.
Definition: config.cpp:339
std::ostream & operator<<(std::ostream &os, const config::attribute_value &v)
Definition: config.cpp:428
attribute_map::value_type attribute
Definition: config.hpp:393
GLuint const GLfloat * val
Definition: glew.h:2614
value_type value_
The stored value will always use the first type from the variant definition that can represent it and...
Definition: config.hpp:277
STL namespace.
reference operator*() const
Definition: config.cpp:1112
bool operator()(const yes_no &lhs, const true_false &rhs) const
Definition: config.cpp:398
GLint GLint GLint GLint GLint GLint y
Definition: glew.h:1220
GLenum src
Definition: glew.h:2392
void clear()
Definition: config.cpp:1055
#define d
void append_children(const config &cfg)
Adds children from cfg.
Definition: config.cpp:540
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.
Definition: config.cpp:722
void clear_diff_track(const config &diff)
Clear any tracking info from a previous apply_diff call with tracking.
Definition: config.cpp:1314
std::string debug() const
Definition: config.cpp:1438
void clear_children(const std::string &key)
Definition: config.cpp:820
bool empty() const
Definition: config.cpp:1105
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 "".
Definition: config.cpp:375
Definitions for the interface to Wesnoth Markup Language (WML).
std::pair< const_child_iterator, const_child_iterator > const_child_itors
Definition: config.hpp:214
Variant for storing WML attributes.
Definition: config.hpp:223
GLboolean GLenum GLenum GLvoid * values
Definition: glew.h:3799
GLdouble l
Definition: glew.h:6966
bool blank() const
Tests for an attribute that was never set.
Definition: config.cpp:367
GLdouble GLdouble GLdouble b
Definition: glew.h:6966
static bool valid_id(const std::string &id)
Definition: config.cpp:498
void merge_with(const config &c)
Merge config 'c' into this config, overwriting this config's values.
Definition: config.cpp:1350
void inherit_from(const config &c)
Merge config 'c' into this config, preserving this config's values.
Definition: config.cpp:1401
bool has_child(const std::string &key) const
Determine whether a config has a child or not.
Definition: config.cpp:651
static config invalid
Definition: config.hpp:88
A small explanation about what's going on here: Each action has access to two game_info objects First...
Definition: actions.cpp:57
void swap(config &cfg)
Definition: config.cpp:1518
void splice_children(config &src, const std::string &key)
Moves all the children with tag key from src to this.
Definition: config.cpp:837
void check_valid() const
Raises an exception if this is not valid.
Definition: config.cpp:443
static const std::string s_yes
Definition: config.hpp:382
const GLdouble * v
Definition: glew.h:1359
GLsizei const GLfloat * value
Definition: glew.h:1817
all_children_itors all_children_range() const
In-order iteration over all children.
Definition: config.cpp:1127
GLenum GLenum dst
Definition: glew.h:2392
GLenum GLsizei len
Definition: glew.h:5662
#define ERR_CF
Definition: config.cpp:41
GLboolean GLboolean GLboolean GLboolean a
Definition: glew.h:7319
void remove_child(const std::string &key, unsigned index)
Definition: config.cpp:899
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& ...
Definition: config.cpp:72
std::pair< all_children_iterator, all_children_iterator > all_children_itors
Definition: config.hpp:665
config & add_child(const std::string &key)
Definition: config.cpp:743
std::string operator()(std::string const &s) const
Definition: config.cpp:349
std::vector< child_pos > ordered_children
Definition: config.hpp:773
GLenum GLuint GLsizei const char * buf
Definition: glew.h:2498
A wrapper for bool to get the correct streaming ("yes"/"no").
Definition: config.hpp:243
config()
Definition: config.cpp:455
attribute_map values
All the attributes of this node.
Definition: config.hpp:768
std::string operator()(const true_false &b) const
Definition: config.cpp:345
void apply_diff(const config &diff, bool track=false)
A function to apply a diff config onto this config object.
Definition: config.cpp:1252
GLfloat GLfloat p
Definition: glew.h:12766
Templates and utility-routines for strings and numbers.
void init()
Initializes the gui subsystems.
Definition: registry.cpp:482
all_children_iterator erase(const all_children_iterator &i)
Definition: config.cpp:894
Visitor handling equality checks.
Definition: config.cpp:384
std::string operator()(unsigned long long u) const
Definition: config.cpp:347
GLuint res
Definition: glew.h:9258
std::string operator()(double d) const
Definition: config.cpp:348
config get_diff(const config &c) const
A function to get the differences between this object, and 'c', as another config object...
Definition: config.cpp:1134
std::map< std::string, tfilter >::iterator itor
Definition: filter.cpp:199
std::stringstream & wml_error()
Use this logger to send errors due to deprecated WML.
Definition: log.cpp:262
attribute_value()
Default implementation, but defined out-of-line for efficiency reasons.
Definition: config.cpp:115
const_attr_itors attribute_range() const
Definition: config.cpp:984
GLuint index
Definition: glew.h:1782
child_map children
A list of all children of this node.
Definition: config.hpp:771
attribute_value & operator[](const std::string &key)
Returns a reference to the attribute with the given key.
Definition: config.cpp:942
std::pair< child_iterator, child_iterator > child_itors
Definition: config.hpp:213
static bool operator<(const placing_info &a, const placing_info &b)
Definition: game_state.cpp:127
size_t i
Definition: function.cpp:1057
static void msg(const char *act, debug_info &i, const char *to="", const char *result="")
Definition: debugger.cpp:112
GLint GLint GLint GLint GLint x
Definition: glew.h:1220
GLdouble GLdouble GLdouble r
Definition: glew.h:1374
unsigned child_count(const std::string &key) const
Definition: config.cpp:635
void merge_attributes(const config &)
Definition: config.cpp:968
GLuint const GLchar * name
Definition: glew.h:1782
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.
Definition: config.cpp:935
attribute_value & operator=(const attribute_value &)
Default implementation, but defined out-of-line for efficiency reasons.
Definition: config.cpp:132
#define next(ls)
Definition: llex.cpp:27
std::string hash() const
Definition: config.cpp:1468
GLint GLint GLint GLint GLint GLint GLint GLbitfield GLenum filter
Definition: glew.h:3448
static const char * diff_track_attribute
The name of the attribute used for tracking diff changes.
Definition: config.hpp:686
GLclampd n
Definition: glew.h:5903
bool equals(const std::string &str) const
Checks for equality of the attribute values when viewed as strings.
Definition: config.cpp:417
static lg::log_domain log_config("config")
bool has_attribute(const std::string &key) const
Definition: config.cpp:514
const GLdouble * m
Definition: glew.h:6968
bool operator()(const T &lhs, const T &rhs) const
Definition: config.cpp:394
long long to_long_long(long long def=0) const
Definition: config.cpp:313
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
#define DBG_CF
Definition: config.cpp:42
unsigned all_children_count() const
Definition: config.cpp:646
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.
Definition: config.cpp:1010
Standard logging facilities (interface).
void recursive_clear_value(const std::string &key)
Definition: config.cpp:860
time_t to_time_t(time_t def=0) const
Definition: config.cpp:328
#define c
Definition: glew.h:12743
int to_int(int def=0) const
Definition: config.cpp:308
std::vector< config * > child_list
Definition: config.hpp:123
unsigned to_unsigned(unsigned def=0) const
Definition: config.cpp:318
bool operator==(const attribute_value &other) const
Checks for equality of the attribute values when viewed as strings.
Definition: config.cpp:406
static unsigned int hash_str(const std::string &str)
Definition: builder.cpp:1101
const std::string & str() const
Definition: tstring.hpp:170
std::string operator()(const boost::blank &) const
Definition: config.cpp:343
std::string::const_iterator iterator
Definition: tokenizer.hpp:21
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:83
GLdouble s
Definition: glew.h:1358
config & operator=(const config &)
Definition: config.cpp:474
~config()
Definition: config.cpp:469
static const std::string s_true
Definition: config.hpp:383
GLsizei const GLcharARB ** string
Definition: glew.h:4503
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 ...
Definition: config.cpp:520
GLsizei GLsizei GLchar * source
Definition: glew.h:1800
config & add_child_at(const std::string &key, const config &val, unsigned index)
Definition: config.cpp:773
A wrapper for bool to get the correct streaming ("true"/"false").
Definition: config.hpp:228
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 ...
Definition: config.cpp:589
all_children_iterator ordered_begin() const
Definition: config.cpp:1117
std::string operator()(const yes_no &b) const
Definition: config.cpp:344
const std::string & str() const
Definition: config.hpp:235