The Battle for Wesnoth  1.15.6+dev
schema_validator.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2011 - 2018 by Sytyi Nick <nsytyi@gmail.com>
3  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY.
11 
12  See the COPYING file for more details.
13 */
14 
16 
17 #include "filesystem.hpp"
18 #include "gettext.hpp"
19 #include "log.hpp"
22 #include "wml_exception.hpp"
23 #include <tuple>
24 
25 namespace schema_validation
26 {
27 static lg::log_domain log_validation("validation");
28 
29 #define ERR_VL LOG_STREAM(err, log_validation)
30 #define WRN_VL LOG_STREAM(warn, log_validation)
31 #define LOG_VL LOG_STREAM(info, log_validation)
32 
33 static std::string at(const std::string& file, int line)
34 {
35  std::ostringstream ss;
36  ss << line << " " << file;
37  return "at " + ::lineno_string(ss.str());
38 }
39 
40 static void print_output(const std::string& message, bool flag_exception = false)
41 {
42 #ifndef VALIDATION_ERRORS_LOG
43  if(flag_exception) {
44  throw wml_exception("Validation error occurred", message);
45  } else {
46  ERR_VL << message;
47  }
48 #else
49  // dirty hack to avoid "unused" error in case of compiling with definition on
50  flag_exception = true;
51  if(flag_exception) {
52  ERR_VL << message;
53  }
54 #endif
55 }
56 
57 static void extra_tag_error(const std::string& file,
58  int line,
59  const std::string& name,
60  int n,
61  const std::string& parent,
62  bool flag_exception)
63 {
64  std::ostringstream ss;
65  ss << "Extra tag [" << name << "]; there may only be " << n << " [" << name << "] in [" << parent << "]\n"
66  << at(file, line) << "\n";
67  print_output(ss.str(), flag_exception);
68 }
69 
70 static void wrong_tag_error(
71  const std::string& file, int line, const std::string& name, const std::string& parent, bool flag_exception)
72 {
73  std::ostringstream ss;
74  ss << "Tag [" << name << "] may not be used in [" << parent << "]\n" << at(file, line) << "\n";
75  print_output(ss.str(), flag_exception);
76 }
77 
78 static void missing_tag_error(const std::string& file,
79  int line,
80  const std::string& name,
81  int n,
82  const std::string& parent,
83  bool flag_exception)
84 {
85  std::ostringstream ss;
86  ss << "Missing tag [" << name << "]; there must be " << n << " [" << name << "]s in [" << parent << "]\n"
87  << at(file, line) << "\n";
88  print_output(ss.str(), flag_exception);
89 }
90 
91 static void extra_key_error(
92  const std::string& file, int line, const std::string& tag, const std::string& key, bool flag_exception)
93 {
94  std::ostringstream ss;
95  ss << "Invalid key '" << key << "=' in tag [" << tag << "]\n" << at(file, line) << "\n";
96  print_output(ss.str(), flag_exception);
97 }
98 
99 static void missing_key_error(
100  const std::string& file, int line, const std::string& tag, const std::string& key, bool flag_exception)
101 {
102  std::ostringstream ss;
103  ss << "Missing key '" << key << "=' in tag [" << tag << "]\n" << at(file, line) << "\n";
104  print_output(ss.str(), flag_exception);
105 }
106 
107 static void wrong_value_error(const std::string& file,
108  int line,
109  const std::string& tag,
110  const std::string& key,
111  const std::string& value,
112  bool flag_exception)
113 {
114  std::ostringstream ss;
115  ss << "Invalid value '" << value << "' in key '" << key << "=' in tag [" << tag << "]\n" << at(file, line) << "\n";
116  print_output(ss.str(), flag_exception);
117 }
118 
119 static void wrong_path_error(const std::string& file,
120  int line,
121  const std::string& tag,
122  const std::string& key,
123  const std::string& value,
124  bool flag_exception)
125 {
126  std::ostringstream ss;
127  ss << "Unknown path reference '" << value << "' in key '" << key << "=' in tag [" << tag << "]\n" << at(file, line) << "\n";
128  print_output(ss.str(), flag_exception);
129 }
130 
131 static void duplicate_tag_error(const std::string& file,
132  int line,
133  const std::string& tag,
134  const std::string& pat,
135  const std::string& value,
136  bool flag_exception)
137 {
138  std::ostringstream ss;
139  ss << "Duplicate or fully-overlapping tag definition '" << value << "' (which is also matched by '" << pat << "') in tag [" << tag << "]\n" << at(file, line) << "\n";
140  print_output(ss.str(), flag_exception);
141 }
142 
143 static void duplicate_key_error(const std::string& file,
144  int line,
145  const std::string& tag,
146  const std::string& pat,
147  const std::string& value,
148  bool flag_exception)
149 {
150  std::ostringstream ss;
151  ss << "Duplicate or fully-overlapping key definition '" << value << "' (which is also matched by '" << pat << "') in tag [" << tag << "]\n" << at(file, line) << "\n";
152  print_output(ss.str(), flag_exception);
153 }
154 
155 static void wrong_type_error(const std::string & file, int line,
156  const std::string & tag,
157  const std::string & key,
158  const std::string & type,
159  bool flag_exception)
160 {
161  std::ostringstream ss;
162  ss << "Invalid type '" << type << "' in key '" << key << "=' in tag [" << tag << "]\n" << at(file, line) << "\n";
163  print_output(ss.str(), flag_exception);
164 }
165 
167 {
168 }
169 
170 schema_validator::schema_validator(const std::string& config_file_name, bool validate_schema)
171  : abstract_validator(config_file_name)
173  , config_read_(false)
174  , validate_schema_(validate_schema)
175 {
176  if(!read_config_file(config_file_name)) {
177  ERR_VL << "Schema file " << config_file_name << " was not read." << std::endl;
178  throw abstract_validator::error("Schema file " + config_file_name + " was not read.\n");
179  } else {
180  stack_.push(&root_);
181  counter_.emplace();
182  cache_.emplace();
184  LOG_VL << "Schema file " << config_file_name << " was read.\n"
185  << "Validator initialized\n";
186  }
187 }
188 
190 {
191  config cfg;
192  try {
193  std::unique_ptr<abstract_validator> validator;
194  if(validate_schema_) {
195  validator.reset(new schema_self_validator());
196  }
197  preproc_map preproc(game_config::config_cache::instance().get_preproc_map());
198  filesystem::scoped_istream stream = preprocess_file(filename, &preproc);
199  read(cfg, *stream, validator.get());
200  } catch(const config::error& e) {
201  ERR_VL << "Failed to read file " << filename << ":\n" << e.what() << "\n";
202  return false;
203  }
204 
205  for(const config& g : cfg.child_range("wml_schema")) {
206  for(const config& schema : g.child_range("tag")) {
207  if(schema["name"].str() == "root") {
208  //@NOTE Don't know, maybe merging of roots needed.
209  root_ = wml_tag(schema);
210  }
211  }
212  for(const config& type : g.child_range("type")) {
213  try {
214  types_[type["name"].str()] = wml_type::from_config(type);
215  } catch(const std::exception&) {
216  // Need to check all type values in schema-generator
217  }
218  }
219  }
220 
221  config_read_ = true;
222  return true;
223 }
224 
225 /*
226  * Please, @Note that there is some magic in pushing and poping to/from stacks.
227  * assume they all are on their place due to parser algorithm
228  * and validation logic
229  */
230 void schema_validator::open_tag(const std::string& name, const config& parent, int start_line, const std::string& file, bool addittion)
231 {
232  if(name.empty()) {
233  // Opened the root tag; nothing special to do here
234  } else if(!stack_.empty()) {
235  const wml_tag* tag = nullptr;
236 
237  if(stack_.top()) {
238  tag = active_tag().find_tag(name, root_, parent);
239 
240  if(!tag) {
241  wrong_tag_error(file, start_line, name, stack_.top()->get_name(), create_exceptions_);
242  } else {
243  if(!addittion) {
244  counter& cnt = counter_.top()[name];
245  ++cnt.cnt;
246  counter& total_cnt = counter_.top()[""];
247  ++total_cnt.cnt;
248  }
249  }
250  }
251 
252  stack_.push(tag);
253  } else {
254  stack_.push(nullptr);
255  }
256 
257  counter_.emplace();
258  cache_.emplace();
259 }
260 
262 {
263  stack_.pop();
264  counter_.pop();
265  // cache_ is cleared in another place.
266 }
267 
268 void schema_validator::validate(const config& cfg, const std::string& name, int start_line, const std::string& file)
269 {
270  // close previous errors and print them to output.
271  for(auto& m : cache_.top()) {
272  for(auto& list : m.second) {
273  print(list);
274  }
275  }
276 
277  cache_.pop();
278 
279  // clear cache
280  auto cache_it = cache_.top().find(&cfg);
281  if(cache_it != cache_.top().end()) {
282  cache_it->second.clear();
283  }
284 
285  // Please note that validating unknown tag keys the result will be false
286  // Checking all elements counters.
287  if(have_active_tag() && is_valid()) {
288  const wml_tag& active = active_tag();
289  for(const auto& tag : active.tags(cfg)) {
290  int cnt = counter_.top()[tag.first].cnt;
291 
292  if(tag.second.get_min() > cnt) {
293  queue_message(cfg, MISSING_TAG, file, start_line, tag.second.get_min(), tag.first, "", name);
294  continue;
295  }
296 
297  if(tag.second.get_max() < cnt) {
298  queue_message(cfg, EXTRA_TAG, file, start_line, tag.second.get_max(), tag.first, "", name);
299  }
300  }
301 
302  int total_cnt = counter_.top()[""].cnt;
303  if(active.get_min_children() > total_cnt) {
304  queue_message(cfg, MISSING_TAG, file, start_line, active.get_min_children(), "*", "", active.get_name());
305  } else if(active_tag().get_max_children() < total_cnt) {
306  queue_message(cfg, EXTRA_TAG, file, start_line, active.get_max_children(), "*", "", active.get_name());
307  }
308 
309  // Checking if all mandatory keys are present
310  for(const auto& key : active.keys(cfg)) {
311  if(key.second.is_mandatory()) {
312  if(cfg.get(key.first) == nullptr) {
313  queue_message(cfg, MISSING_KEY, file, start_line, 0, name, key.first);
314  }
315  }
316  }
317  }
318 }
319 
321  const config& cfg, const std::string& name, const std::string& value, int start_line, const std::string& file)
322 {
323  if(have_active_tag() && !active_tag().get_name().empty() && is_valid()) {
324  // checking existing keys
325  const wml_key* key = active_tag().find_key(name, cfg);
326  if(key) {
327  bool matched = false;
328  for(auto& possible_type : utils::split(key->get_type())) {
329  if(auto type = find_type(possible_type)) {
330  if(type->matches(value, types_)) {
331  matched = true;
332  break;
333  }
334  }
335  }
336  if(!matched) {
337  queue_message(cfg, WRONG_VALUE, file, start_line, 0, active_tag().get_name(), name, value);
338  }
339  } else {
340  queue_message(cfg, EXTRA_KEY, file, start_line, 0, active_tag().get_name(), name);
341  }
342  }
343 }
344 
345 void schema_validator::queue_message(const config& cfg, message_type t, const std::string& file, int line, int n, const std::string& tag, const std::string& key, const std::string& value)
346 {
347  cache_.top()[&cfg].emplace_back(t, file, line, n, tag, key, value);
348 }
349 
351 {
352  assert(have_active_tag() && "Tried to get active tag name when there was none");
353  return *stack_.top();
354 }
355 
357 {
358  auto it = types_.find(type);
359  if(it == types_.end()) {
360  return nullptr;
361  }
362  return it->second;
363 }
364 
366 {
367  return !stack_.empty() && stack_.top();
368 }
369 
371  std::stack<const wml_tag*> temp = stack_;
372  std::deque<std::string> path;
373  while(!temp.empty()) {
374  path.push_front(temp.top()->get_name());
375  temp.pop();
376  }
377  if(path.front() == "root") {
378  path.pop_front();
379  }
380  return utils::join(path, "/");
381 }
382 
384 {
385  switch(el.type) {
386  case WRONG_TAG:
388  break;
389  case EXTRA_TAG:
390  extra_tag_error(el.file, el.line, el.tag, el.n, el.value, create_exceptions_);
391  break;
392  case MISSING_TAG:
393  missing_tag_error(el.file, el.line, el.tag, el.n, el.value, create_exceptions_);
394  break;
395  case EXTRA_KEY:
397  break;
398  case WRONG_VALUE:
400  break;
401  case MISSING_KEY:
403  break;
404  }
405 }
406 
408  : schema_validator(filesystem::get_wml_location("schema/schema.cfg"), false)
409  , type_nesting_()
410  , condition_nesting_()
411 {}
412 
413 void schema_self_validator::open_tag(const std::string& name, const config& parent, int start_line, const std::string& file, bool addition)
414 {
415  schema_validator::open_tag(name, parent, start_line, file, addition);
416  if(name == "type") {
417  type_nesting_++;
418  }
419  if(condition_nesting_ == 0) {
420  if(name == "if" || name == "switch") {
421  condition_nesting_ = 1;
422  } else if(name == "tag") {
423  tag_stack_.emplace();
424  }
425  } else {
427  }
428 }
429 
431 {
432  if(have_active_tag()) {
433  auto tag_name = active_tag().get_name();
434  if(tag_name == "type") {
435  type_nesting_--;
436  } else if(condition_nesting_ == 0 && tag_name == "tag") {
437  tag_stack_.pop();
438  }
439  }
440  if(condition_nesting_ > 0) {
442  }
444 }
445 
447  std::vector<std::string> path = utils::split(ref.value_, '/');
448  std::string suffix = path.back();
449  path.pop_back();
450  while(!path.empty()) {
451  std::string prefix = utils::join(path, "/");
452  auto link = links_.find(prefix);
453  if(link != links_.end()) {
454  std::string new_path = link->second + "/" + suffix;
455  if(defined_tag_paths_.count(new_path) > 0) {
456  return true;
457  }
458  path = utils::split(new_path, '/');
459  suffix = path.back();
460  //suffix = link->second + "/" + suffix;
461  } else {
462  auto supers = derivations_.equal_range(prefix);
463  if(supers.first != supers.second) {
464  reference super_ref = ref;
465  for( ; supers.first != supers.second; ++supers.first) {
466  super_ref.value_ = supers.first->second + "/" + suffix;
467  if(tag_path_exists(cfg, super_ref)) {
468  return true;
469  }
470  }
471  }
472  std::string new_path = prefix + "/" + suffix;
473  if(defined_tag_paths_.count(new_path) > 0) {
474  return true;
475  }
476  suffix = path.back() + "/" + suffix;
477  }
478  path.pop_back();
479  }
480  return false;
481 }
482 
484 {
485  for(const std::string& pat : utils::split(pattern)) {
486  if(utils::wildcard_string_match(name, pat)) return true;
487  }
488  return false;
489 }
490 
491 void schema_self_validator::check_for_duplicates(const std::string& name, std::vector<std::string>& seen, const config& cfg, message_type type, const std::string& file, int line, const std::string& tag) {
492  auto split = utils::split(name);
493  for(const std::string& pattern : seen) {
494  for(const std::string& key : split) {
495  if(name_matches(pattern, key)) {
496  queue_message(cfg, type, file, line, 0, tag, pattern, name);
497  continue;
498  }
499  }
500  }
501  seen.push_back(name);
502 }
503 
504 void schema_self_validator::validate(const config& cfg, const std::string& name, int start_line, const std::string& file)
505 {
506  if(type_nesting_ == 1 && name == "type") {
507  defined_types_.insert(cfg["name"]);
508  } else if(name == "tag") {
509  bool first_tag = true, first_key = true;
510  std::vector<std::string> tag_names, key_names;
511  for(auto current : cfg.all_children_range()) {
512  if(current.key == "tag" || current.key == "link") {
513  std::string tag_name = current.cfg["name"];
514  if(current.key == "link") {
515  tag_name.erase(0, tag_name.find_last_of('/') + 1);
516  }
517  if(first_tag) {
518  tag_names.push_back(tag_name);
519  first_tag = false;
520  continue;
521  }
522  check_for_duplicates(tag_name, tag_names, current.cfg, DUPLICATE_TAG, file, start_line, current.key);
523  } else if(current.key == "key") {
524  std::string key_name = current.cfg["name"];
525  if(first_key) {
526  key_names.push_back(key_name);
527  first_key = false;
528  continue;
529  }
530  check_for_duplicates(key_name, key_names, current.cfg, DUPLICATE_KEY, file, start_line, current.key);
531  }
532  }
533  } else if(name == "wml_schema") {
534  using namespace std::placeholders;
535  std::vector<reference> missing_types = referenced_types_, missing_tags = referenced_tag_paths_;
536  // Remove all the known types
537  missing_types.erase(std::remove_if(missing_types.begin(), missing_types.end(), std::bind(&reference::match, _1, std::cref(defined_types_))), missing_types.end());
538  // Remove all the known tags. This is more complicated since links behave similar to a symbolic link.
539  // In other words, the presence of links means there may be more than one way to refer to a given tag.
540  // But that's not all! It's possible to refer to a tag through a derived tag even if it's actually defined in the base tag.
541  auto end = std::remove_if(missing_tags.begin(), missing_tags.end(), std::bind(&reference::match, _1, std::cref(defined_tag_paths_)));
542  missing_tags.erase(std::remove_if(missing_tags.begin(), end, std::bind(&schema_self_validator::tag_path_exists, this, std::ref(cfg), _1)), missing_tags.end());
543  std::sort(missing_types.begin(), missing_types.end());
544  std::sort(missing_tags.begin(), missing_tags.end());
545  static const config dummy;
546  for(auto& ref : missing_types) {
547  std::string tag_name;
548  if(ref.tag_ == "key") {
549  tag_name = "type";
550  } else {
551  tag_name = "link";
552  }
553  queue_message(dummy, WRONG_TYPE, ref.file_, ref.line_, 0, ref.tag_, tag_name, ref.value_);
554  }
555  for(auto& ref : missing_tags) {
556  std::string tag_name;
557  if(ref.tag_ == "tag") {
558  tag_name = "super";
559  } else if(ref.tag_ == "link") {
560  tag_name = "name";
561  }
562  queue_message(dummy, WRONG_PATH, ref.file_, ref.line_, 0, ref.tag_, tag_name, ref.value_);
563  }
564  }
565  schema_validator::validate(cfg, name, start_line, file);
566 }
567 
568 void schema_self_validator::validate_key(const config& cfg, const std::string& name, const std::string& value, int start_line, const std::string& file)
569 {
570  schema_validator::validate_key(cfg, name, value, start_line, file);
571  if(have_active_tag() && !active_tag().get_name().empty() && is_valid()) {
572  const std::string& tag_name = active_tag().get_name();
573  if(tag_name == "key" && name == "type" ) {
574  for(auto& possible_type : utils::split(cfg["type"])) {
575  referenced_types_.emplace_back(possible_type, file, start_line, tag_name);
576  }
577  } else if((tag_name == "type" || tag_name == "element") && name == "link") {
578  referenced_types_.emplace_back(cfg["link"], file, start_line, tag_name);
579  } else if(tag_name == "link" && name == "name") {
580  referenced_tag_paths_.emplace_back(cfg["name"], file, start_line, tag_name);
581  std::string link_name = utils::split(cfg["name"].str(), '/').back();
582  links_.emplace(current_path() + "/" + link_name, cfg["name"]);
583  } else if(tag_name == "tag" && name == "super") {
584  for(auto super : utils::split(cfg["super"])) {
585  referenced_tag_paths_.emplace_back(super, file, start_line, tag_name);
586  derivations_.emplace(std::make_pair(current_path(), super));
587  }
588  } else if(condition_nesting_ == 0 && tag_name == "tag" && name == "name") {
589  tag_stack_.top() = value;
591  }
592  }
593 }
594 
596 {
597  std::stack<std::string> temp = tag_stack_;
598  std::deque<std::string> path;
599  while(!temp.empty()) {
600  path.push_front(temp.top());
601  temp.pop();
602  }
603  if(path.front() == "root") {
604  path.pop_front();
605  }
606  return utils::join(path, "/");
607 }
608 
610 {
611  return std::make_tuple(file_, line_) < std::make_tuple(other.file_, other.line_);
612 }
613 
614 bool schema_self_validator::reference::match(const std::set<std::string>& with)
615 {
616  return with.count(value_) > 0;
617 }
618 
620 {
621  // The problem is that the schema being validated is that of the schema!!!
622  return root.find_tag(value_, root, cfg) != nullptr;
623 }
624 
626 {
628  switch(el.type) {
629  case WRONG_TYPE:
631  break;
632  case WRONG_PATH:
634  break;
635  case DUPLICATE_TAG:
637  break;
638  case DUPLICATE_KEY:
640  break;
641  }
642 }
643 
644 } // namespace schema_validation{
std::string lineno_string(const std::string &lineno)
std::stack< const wml_tag * > stack_
bool create_exceptions_
Controls the way to print errors.
static config_cache & instance()
Get reference to the singleton object.
bool match(const std::set< std::string > &with)
int get_min_children() const
Definition: tag.hpp:174
static void wrong_value_error(const std::string &file, int line, const std::string &tag, const std::string &key, const std::string &value, bool flag_exception)
void check_for_duplicates(const std::string &name, std::vector< std::string > &seen, const config &cfg, message_type type, const std::string &file, int line, const std::string &tag)
const_all_children_itors all_children_range() const
In-order iteration over all children.
Definition: config.cpp:921
cnt_stack counter_
Contains number of children.
static void wrong_tag_error(const std::string &file, int line, const std::string &name, const std::string &parent, bool flag_exception)
int dummy
Definition: lstrlib.cpp:1125
std::string join(const T &v, const std::string &s=",")
Generates a new string joining container items in a list.
std::multimap< std::string, std::string > derivations_
virtual void open_tag(const std::string &name, const config &parent, int start_line=0, const std::string &file="", bool addition=false) override
Is called when parser opens tag.
bool tag_path_exists(const config &cfg, const reference &ref)
Add a special kind of assert to validate whether the input from WML doesn&#39;t contain any problems that...
static l_noret error(LoadState *S, const char *why)
Definition: lundump.cpp:39
child_itors child_range(config_key_type key)
Definition: config.cpp:362
int get_max_children() const
Definition: tag.hpp:179
const attribute_value * get(config_key_type key) const
Returns a pointer to the attribute with the given key or nullptr if it does not exist.
Definition: config.cpp:742
Stores information about tag.
Definition: tag.hpp:46
bool wildcard_string_match(const std::string &str, const std::string &match)
Match using &#39;*&#39; as any number of characters (including none), &#39;+&#39; as one or more characters, and &#39;?&#39; as any one character.
void print(message_info &message) override
static void missing_tag_error(const std::string &file, int line, const std::string &name, int n, const std::string &parent, bool flag_exception)
std::string str
Definition: statement.cpp:110
wml_tag root_
Root of schema information.
bool config_read_
Shows, if validator is initialized with schema file.
const wml_key * find_key(const std::string &name, const config &match, bool ignore_super=false) const
Returns pointer to child key.
Definition: tag.cpp:108
boost::iterator_range< key_iterator > keys(const config &cfg_match) const
Definition: tag.hpp:303
One of the realizations of serialization/validator.hpp abstract validator.
Used in parsing config file.
Definition: validator.hpp:35
static void extra_key_error(const std::string &file, int line, const std::string &tag, const std::string &key, bool flag_exception)
std::stack< message_map > cache_
Caches error messages.
static void missing_key_error(const std::string &file, int line, const std::string &tag, const std::string &key, bool flag_exception)
static std::string at(const std::string &file, int line)
wml_type::map types_
Type validators.
bool strict_validation_enabled
Definition: validator.cpp:19
const wml_tag * find_tag(const std::string &fullpath, const wml_tag &root, const config &match, bool ignore_super=false) const
Returns pointer to tag using full path to it.
Definition: tag.cpp:164
void queue_message(const config &cfg, message_type t, const std::string &file, int line=0, int n=0, const std::string &tag="", const std::string &key="", const std::string &value="")
bool can_find(const wml_tag &root, const config &cfg)
std::unique_ptr< std::istream > scoped_istream
Definition: filesystem.hpp:39
std::string path
Definition: game_config.cpp:39
static void print_output(const std::string &message, bool flag_exception=false)
const char * what() const noexcept
Definition: exceptions.hpp:37
static void duplicate_key_error(const std::string &file, int line, const std::string &tag, const std::string &pat, const std::string &value, bool flag_exception)
const std::string & get_type() const
Definition: key.hpp:63
static void duplicate_tag_error(const std::string &file, int line, const std::string &tag, const std::string &pat, const std::string &value, bool flag_exception)
#define LOG_VL
schema_validator(const std::string &filename, bool validate_schema=false)
Initializes validator from file.
Helper class, don&#39;t construct this directly.
boost::iterator_range< tag_iterator > tags(const config &cfg_match) const
Definition: tag.hpp:298
value read(bind.buffer(), bind.length())
static std::shared_ptr< wml_type > from_config(const config &cfg)
Definition: type.cpp:40
std::string get_wml_location(const std::string &filename, const std::string &current_dir)
Returns a complete path to the actual WML file or directory or an empty string if the file isn&#39;t pres...
wml_key is used to save the information about one key.
Definition: key.hpp:35
bool read_config_file(const std::string &filename)
Reads config from input.
double g
Definition: astarsearch.cpp:64
std::string name
Definition: sdl_ttf.cpp:70
virtual void close_tag() override
As far as parser is built on stack, some realizations can store stack too.
std::shared_ptr< wml_type > ptr
Definition: type.hpp:40
Declarations for File-IO.
static int sort(lua_State *L)
Definition: ltablib.cpp:411
void expand_all(wml_tag &root)
Calls the expansion on each child.
Definition: tag.cpp:242
double t
Definition: astarsearch.cpp:64
std::vector< std::string > split(const config_attribute_value &val)
static void wrong_path_error(const std::string &file, int line, const std::string &tag, const std::string &key, const std::string &value, bool flag_exception)
virtual void validate(const config &cfg, const std::string &name, int start_line, const std::string &file) override
Validates config.
const std::string & get_name() const
Definition: tag.hpp:159
virtual void open_tag(const std::string &name, const config &parent, int start_line=0, const std::string &file="", bool addition=false) override
Is called when parser opens tag.
Standard logging facilities (interface).
virtual void close_tag() override
As far as parser is built on stack, some realizations can store stack too.
std::map< std::string, struct preproc_define > preproc_map
#define e
Realization of serialization/validator.hpp abstract validator.
virtual void validate_key(const config &cfg, const std::string &name, const std::string &value, int start_line, const std::string &file) override
Checks if key is allowed and if its value is valid What exactly is validated depends on validator rea...
wml_type::ptr find_type(const std::string &type) const
#define ERR_VL
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:68
filesystem::scoped_istream preprocess_file(const std::string &fname, preproc_map *defines)
Function to use the WML preprocessor on a file.
static void wrong_type_error(const std::string &file, int line, const std::string &tag, const std::string &key, const std::string &type, bool flag_exception)
static lg::log_domain log_validation("validation")
virtual void validate_key(const config &cfg, const std::string &name, const std::string &value, int start_line, const std::string &file) override
Checks if key is allowed and if its value is valid What exactly is validated depends on validator rea...
static map_location::DIRECTION n
static bool name_matches(const std::string &pattern, const std::string &name)
virtual void print(message_info &)
virtual void validate(const config &cfg, const std::string &name, int start_line, const std::string &file) override
Validates config.
std::map< std::string, std::string > links_
std::vector< reference > referenced_tag_paths_
auto * ss
Definition: result_set.cpp:281
static void extra_tag_error(const std::string &file, int line, const std::string &name, int n, const std::string &parent, bool flag_exception)