The Battle for Wesnoth  1.15.9+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 
189 bool schema_validator::read_config_file(const std::string& filename)
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 addition)
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(!addition) {
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 
346 {
347  assert(have_active_tag() && "Tried to get active tag name when there was none");
348  return *stack_.top();
349 }
350 
352 {
353  auto it = types_.find(type);
354  if(it == types_.end()) {
355  return nullptr;
356  }
357  return it->second;
358 }
359 
361 {
362  return !stack_.empty() && stack_.top();
363 }
364 
366  std::stack<const wml_tag*> temp = stack_;
367  std::deque<std::string> path;
368  while(!temp.empty()) {
369  path.push_front(temp.top()->get_name());
370  temp.pop();
371  }
372  if(path.front() == "root") {
373  path.pop_front();
374  }
375  return utils::join(path, "/");
376 }
377 
379 {
380  switch(el.type) {
381  case WRONG_TAG:
383  break;
384  case EXTRA_TAG:
385  extra_tag_error(el.file, el.line, el.tag, el.n, el.value, create_exceptions_);
386  break;
387  case MISSING_TAG:
388  missing_tag_error(el.file, el.line, el.tag, el.n, el.value, create_exceptions_);
389  break;
390  case EXTRA_KEY:
392  break;
393  case WRONG_VALUE:
395  break;
396  case MISSING_KEY:
398  break;
399  }
400 }
401 
403  : schema_validator(filesystem::get_wml_location("schema/schema.cfg"), false)
404  , type_nesting_()
405  , condition_nesting_()
406 {}
407 
408 void schema_self_validator::open_tag(const std::string& name, const config& parent, int start_line, const std::string& file, bool addition)
409 {
410  schema_validator::open_tag(name, parent, start_line, file, addition);
411  if(name == "type") {
412  type_nesting_++;
413  }
414  if(condition_nesting_ == 0) {
415  if(name == "if" || name == "switch") {
416  condition_nesting_ = 1;
417  } else if(name == "tag") {
418  tag_stack_.emplace();
419  }
420  } else {
422  }
423 }
424 
426 {
427  if(have_active_tag()) {
428  auto tag_name = active_tag().get_name();
429  if(tag_name == "type") {
430  type_nesting_--;
431  } else if(condition_nesting_ == 0 && tag_name == "tag") {
432  tag_stack_.pop();
433  }
434  }
435  if(condition_nesting_ > 0) {
437  }
439 }
440 
442  std::vector<std::string> path = utils::split(ref.value_, '/');
443  std::string suffix = path.back();
444  path.pop_back();
445  while(!path.empty()) {
446  std::string prefix = utils::join(path, "/");
447  auto link = links_.find(prefix);
448  if(link != links_.end()) {
449  std::string new_path = link->second + "/" + suffix;
450  if(defined_tag_paths_.count(new_path) > 0) {
451  return true;
452  }
453  path = utils::split(new_path, '/');
454  suffix = path.back();
455  //suffix = link->second + "/" + suffix;
456  } else {
457  auto supers = derivations_.equal_range(prefix);
458  if(supers.first != supers.second) {
459  reference super_ref = ref;
460  for( ; supers.first != supers.second; ++supers.first) {
461  super_ref.value_ = supers.first->second + "/" + suffix;
462  if(tag_path_exists(cfg, super_ref)) {
463  return true;
464  }
465  }
466  }
467  std::string new_path = prefix + "/" + suffix;
468  if(defined_tag_paths_.count(new_path) > 0) {
469  return true;
470  }
471  suffix = path.back() + "/" + suffix;
472  }
473  path.pop_back();
474  }
475  return false;
476 }
477 
478 bool schema_self_validator::name_matches(const std::string& pattern, const std::string& name)
479 {
480  for(const std::string& pat : utils::split(pattern)) {
481  if(utils::wildcard_string_match(name, pat)) return true;
482  }
483  return false;
484 }
485 
486 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) {
487  auto split = utils::split(name);
488  for(const std::string& pattern : seen) {
489  for(const std::string& key : split) {
490  if(name_matches(pattern, key)) {
491  queue_message(cfg, type, file, line, 0, tag, pattern, name);
492  continue;
493  }
494  }
495  }
496  seen.push_back(name);
497 }
498 
499 void schema_self_validator::validate(const config& cfg, const std::string& name, int start_line, const std::string& file)
500 {
501  if(type_nesting_ == 1 && name == "type") {
502  defined_types_.insert(cfg["name"]);
503  } else if(name == "tag") {
504  bool first_tag = true, first_key = true;
505  std::vector<std::string> tag_names, key_names;
506  for(auto current : cfg.all_children_range()) {
507  if(current.key == "tag" || current.key == "link") {
508  std::string tag_name = current.cfg["name"];
509  if(current.key == "link") {
510  tag_name.erase(0, tag_name.find_last_of('/') + 1);
511  }
512  if(first_tag) {
513  tag_names.push_back(tag_name);
514  first_tag = false;
515  continue;
516  }
517  check_for_duplicates(tag_name, tag_names, current.cfg, DUPLICATE_TAG, file, start_line, current.key);
518  } else if(current.key == "key") {
519  std::string key_name = current.cfg["name"];
520  if(first_key) {
521  key_names.push_back(key_name);
522  first_key = false;
523  continue;
524  }
525  check_for_duplicates(key_name, key_names, current.cfg, DUPLICATE_KEY, file, start_line, current.key);
526  }
527  }
528  } else if(name == "wml_schema") {
529  using namespace std::placeholders;
530  std::vector<reference> missing_types = referenced_types_, missing_tags = referenced_tag_paths_;
531  // Remove all the known types
532  missing_types.erase(std::remove_if(missing_types.begin(), missing_types.end(), std::bind(&reference::match, std::placeholders::_1, std::cref(defined_types_))), missing_types.end());
533  // Remove all the known tags. This is more complicated since links behave similar to a symbolic link.
534  // In other words, the presence of links means there may be more than one way to refer to a given tag.
535  // 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.
536  auto end = std::remove_if(missing_tags.begin(), missing_tags.end(), std::bind(&reference::match, std::placeholders::_1, std::cref(defined_tag_paths_)));
537  missing_tags.erase(std::remove_if(missing_tags.begin(), end, std::bind(&schema_self_validator::tag_path_exists, this, std::ref(cfg), std::placeholders::_1)), missing_tags.end());
538  std::sort(missing_types.begin(), missing_types.end());
539  std::sort(missing_tags.begin(), missing_tags.end());
540  static const config dummy;
541  for(auto& ref : missing_types) {
542  std::string tag_name;
543  if(ref.tag_ == "key") {
544  tag_name = "type";
545  } else {
546  tag_name = "link";
547  }
548  queue_message(dummy, WRONG_TYPE, ref.file_, ref.line_, 0, ref.tag_, tag_name, ref.value_);
549  }
550  for(auto& ref : missing_tags) {
551  std::string tag_name;
552  if(ref.tag_ == "tag") {
553  tag_name = "super";
554  } else if(ref.tag_ == "link") {
555  tag_name = "name";
556  }
557  queue_message(dummy, WRONG_PATH, ref.file_, ref.line_, 0, ref.tag_, tag_name, ref.value_);
558  }
559  }
560  schema_validator::validate(cfg, name, start_line, file);
561 }
562 
563 void schema_self_validator::validate_key(const config& cfg, const std::string& name, const std::string& value, int start_line, const std::string& file)
564 {
565  schema_validator::validate_key(cfg, name, value, start_line, file);
566  if(have_active_tag() && !active_tag().get_name().empty() && is_valid()) {
567  const std::string& tag_name = active_tag().get_name();
568  if(tag_name == "key" && name == "type" ) {
569  for(auto& possible_type : utils::split(cfg["type"])) {
570  referenced_types_.emplace_back(possible_type, file, start_line, tag_name);
571  }
572  } else if((tag_name == "type" || tag_name == "element") && name == "link") {
573  referenced_types_.emplace_back(cfg["link"], file, start_line, tag_name);
574  } else if(tag_name == "link" && name == "name") {
575  referenced_tag_paths_.emplace_back(cfg["name"], file, start_line, tag_name);
576  std::string link_name = utils::split(cfg["name"].str(), '/').back();
577  links_.emplace(current_path() + "/" + link_name, cfg["name"]);
578  } else if(tag_name == "tag" && name == "super") {
579  for(auto super : utils::split(cfg["super"])) {
580  referenced_tag_paths_.emplace_back(super, file, start_line, tag_name);
581  derivations_.emplace(current_path(), super);
582  }
583  } else if(condition_nesting_ == 0 && tag_name == "tag" && name == "name") {
584  tag_stack_.top() = value;
586  }
587  }
588 }
589 
591 {
592  std::stack<std::string> temp = tag_stack_;
593  std::deque<std::string> path;
594  while(!temp.empty()) {
595  path.push_front(temp.top());
596  temp.pop();
597  }
598  if(path.front() == "root") {
599  path.pop_front();
600  }
601  return utils::join(path, "/");
602 }
603 
605 {
606  return std::tie(file_, line_) < std::tie(other.file_, other.line_);
607 }
608 
609 bool schema_self_validator::reference::match(const std::set<std::string>& with)
610 {
611  return with.count(value_) > 0;
612 }
613 
615 {
616  // The problem is that the schema being validated is that of the schema!!!
617  return root.find_tag(value_, root, cfg) != nullptr;
618 }
619 
621 {
623  switch(el.type) {
624  case WRONG_TYPE:
626  break;
627  case WRONG_PATH:
629  break;
630  case DUPLICATE_TAG:
632  break;
633  case DUPLICATE_KEY:
635  break;
636  }
637 }
638 
639 } // 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:176
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:181
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)
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:305
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)
void read(config &cfg, std::istream &in, abstract_validator *validator)
Definition: parser.cpp:625
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
bool can_find(const wml_tag &root, const config &cfg)
std::unique_ptr< std::istream > scoped_istream
Definition: filesystem.hpp:36
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:300
static std::shared_ptr< wml_type > from_config(const config &cfg)
Definition: type.cpp:28
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 queue_message(const config &cfg, T &&... args)
void expand_all(wml_tag &root)
Calls the expansion on each child.
Definition: tag.cpp:242
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:161
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:60
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_
static void extra_tag_error(const std::string &file, int line, const std::string &name, int n, const std::string &parent, bool flag_exception)