30 #define ERR_VL LOG_STREAM(err, log_validation) 31 #define WRN_VL LOG_STREAM(warn, log_validation) 32 #define LOG_VL LOG_STREAM(info, log_validation) 34 static std::string
at(
const std::string& file,
int line)
36 std::ostringstream ss;
37 ss << line <<
" " << file;
41 static void print_output(
const std::string& message,
bool flag_exception =
false)
43 #ifndef VALIDATION_ERRORS_LOG 51 flag_exception =
true;
60 const std::string& name,
62 const std::string& parent,
65 std::ostringstream ss;
66 ss <<
"Extra tag [" << name <<
"]; there may only be " << n <<
" [" << name <<
"] in [" << parent <<
"]\n" 67 <<
at(file, line) <<
"\n";
72 const std::string& file,
int line,
const std::string& name,
const std::string& parent,
bool flag_exception)
74 std::ostringstream ss;
75 ss <<
"Tag [" << name <<
"] may not be used in [" << parent <<
"]\n" <<
at(file, line) <<
"\n";
81 const std::string& name,
83 const std::string& parent,
86 std::ostringstream ss;
87 ss <<
"Missing tag [" << name <<
"]; there must be " << n <<
" [" << name <<
"]s in [" << parent <<
"]\n" 88 <<
at(file, line) <<
"\n";
93 const std::string& file,
int line,
const std::string& tag,
const std::string& key,
bool flag_exception)
95 std::ostringstream ss;
96 ss <<
"Invalid key '" << key <<
"=' in tag [" << tag <<
"]\n" <<
at(file, line) <<
"\n";
101 const std::string& file,
int line,
const std::string& tag,
const std::string& key,
bool flag_exception)
103 std::ostringstream ss;
104 ss <<
"Missing key '" << key <<
"=' in tag [" << tag <<
"]\n" <<
at(file, line) <<
"\n";
110 const std::string& tag,
111 const std::string& key,
112 const std::string& value,
113 const std::string& expected,
116 std::ostringstream ss;
117 ss <<
"Invalid value '";
118 if(value.length() > 128)
119 ss << value.substr(0, 128) <<
"...";
121 ss <<
"' in key '" << key <<
"=' in tag [" << tag <<
"]\n" <<
" (expected value of type " << expected <<
") " <<
at(file, line) <<
"\n";
127 const std::string& tag,
128 const std::string& key,
129 const std::string& value,
132 std::ostringstream ss;
133 ss <<
"Unknown path reference '" << value <<
"' in key '" << key <<
"=' in tag [" << tag <<
"]\n" <<
at(file, line) <<
"\n";
139 const std::string& tag,
140 const std::string& pat,
141 const std::string& value,
144 std::ostringstream ss;
145 ss <<
"Duplicate or fully-overlapping tag definition '" << value <<
"' (which is also matched by '" << pat <<
"') in tag [" << tag <<
"]\n" <<
at(file, line) <<
"\n";
151 const std::string& tag,
152 const std::string& pat,
153 const std::string& value,
156 std::ostringstream ss;
157 ss <<
"Duplicate or fully-overlapping key definition '" << value <<
"' (which is also matched by '" << pat <<
"') in tag [" << tag <<
"]\n" <<
at(file, line) <<
"\n";
163 const std::string& tag,
164 const std::string& key,
165 const std::string& value,
169 std::ostringstream ss;
170 ss <<
"Inheritance loop " << key <<
"=" << value <<
" found (at offset " << index <<
") in tag [" << tag <<
"]\n" <<
at(file, line) <<
"\n";
175 const std::string & tag,
176 const std::string & key,
177 const std::string &
type,
180 std::ostringstream ss;
181 ss <<
"Invalid type '" << type <<
"' in key '" << key <<
"=' in tag [" << tag <<
"]\n" <<
at(file, line) <<
"\n";
196 ERR_VL <<
"Schema file " << config_file_name <<
" was not read.";
203 LOG_VL <<
"Schema file " << config_file_name <<
" was read.";
204 LOG_VL <<
"Validator initialized";
212 std::unique_ptr<abstract_validator> validator;
218 read(cfg, *stream, validator.get());
220 ERR_VL <<
"Failed to read file " << filename <<
":\n" << e.
what();
225 for(
const config& schema :
g.child_range(
"tag")) {
226 if(schema[
"name"].str() ==
"root") {
231 types_[
"t_string"] = std::make_shared<wml_type_tstring>();
235 }
catch(
const std::exception&) {
254 }
else if(!
stack_.empty()) {
294 for(
auto& m :
cache_.top()) {
295 for(
auto& list : m.second) {
309 auto cache_it =
cache_.top().find(&cfg);
310 if(cache_it !=
cache_.top().end()) {
311 cache_it->second.clear();
318 for(
const auto& tag : active.
tags(cfg)) {
319 int cnt =
counter_.top()[tag.first].cnt;
321 if(tag.second.get_min() > cnt) {
326 if(tag.second.get_max() < cnt) {
331 int total_cnt =
counter_.top()[
""].cnt;
339 for(
const auto& key : active.
keys(cfg)) {
340 if(key.second.is_mandatory()) {
341 if(cfg.
get(key.first) ==
nullptr) {
356 bool matched =
false;
376 assert(
have_active_tag() &&
"Tried to get active tag name when there was none");
382 auto it =
types_.find(type);
395 std::stack<const wml_tag*> temp =
stack_;
396 std::deque<std::string>
path;
397 while(!temp.empty()) {
398 path.push_front(temp.top()->get_name());
401 if(path.front() ==
"root") {
434 , condition_nesting_()
447 if(name ==
"if" || name ==
"switch") {
449 }
else if(name ==
"tag") {
461 if(tag_name ==
"type") {
475 std::string suffix = path.back();
477 while(!path.empty()) {
479 auto link =
links_.find(prefix);
480 if(link !=
links_.end()) {
481 std::string new_path = link->second +
"/" + suffix;
486 suffix = path.back();
490 if(supers.first != supers.second) {
492 for(
auto cur = supers.first ; cur != supers.second; ++cur) {
493 super_ref.
value_ = cur->second +
"/" + suffix;
502 std::string new_path = prefix +
"/" + suffix;
506 suffix = path.back() +
"/" + suffix;
523 for(
const std::string& pattern : seen) {
524 for(
const std::string& key :
split) {
531 seen.push_back(name);
538 }
else if(name ==
"tag") {
539 bool first_tag =
true, first_key =
true;
540 std::vector<std::string> tag_names, key_names;
542 if(current.key ==
"tag" || current.key ==
"link") {
543 std::string tag_name = current.cfg[
"name"];
544 if(current.key ==
"link") {
545 tag_name.erase(0, tag_name.find_last_of(
'/') + 1);
548 tag_names.push_back(tag_name);
553 }
else if(current.key ==
"key") {
554 std::string key_name = current.cfg[
"name"];
556 key_names.push_back(key_name);
563 }
else if(name ==
"wml_schema") {
564 using namespace std::placeholders;
567 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());
573 std::sort(missing_types.begin(), missing_types.end());
574 std::sort(missing_tags.begin(), missing_tags.end());
575 static const config dummy;
576 for(
auto& ref : missing_types) {
577 std::string tag_name;
578 if(ref.tag_ ==
"key") {
585 for(
auto& ref : missing_tags) {
586 std::string tag_name;
587 if(ref.tag_ ==
"tag") {
589 }
else if(ref.tag_ ==
"link") {
603 if(tag_name ==
"key" && name ==
"type" ) {
607 }
else if((tag_name ==
"type" || tag_name ==
"element") && name ==
"link") {
609 }
else if(tag_name ==
"link" && name ==
"name") {
611 std::string link_name =
utils::split(cfg[
"name"].str(),
'/').back();
613 }
else if(tag_name ==
"tag" && name ==
"super") {
635 std::deque<std::string>
path;
636 while(!temp.empty()) {
637 path.push_front(temp.top());
640 if(path.front() ==
"root") {
648 return std::tie(file_, line_) < std::tie(other.
file_, other.
line_);
653 return with.count(value_) > 0;
659 return root.
find_tag(value_, root, cfg) !=
nullptr;
std::set< std::string > defined_types_
std::string lineno_string(const std::string &lineno)
std::stack< const wml_tag * > stack_
bool create_exceptions_
Controls the way to print errors.
static void inheritance_loop_error(const std::string &file, int line, const std::string &tag, const std::string &key, const std::string &value, int index, bool flag_exception)
static config_cache & instance()
Get reference to the singleton object.
bool match(const std::set< std::string > &with)
int get_min_children() const
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.
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)
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)
Variant for storing WML attributes.
Add a special kind of assert to validate whether the input from WML doesn't contain any problems that...
child_itors child_range(config_key_type key)
int get_max_children() const
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.
Stores information about tag.
bool wildcard_string_match(const std::string &str, const std::string &match)
Match using '*' as any number of characters (including none), '+' as one or more characters, and '?' as any one character.
void print(message_info &message) override
bool operator<(const reference &other) const
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.
boost::iterator_range< key_iterator > keys(const config &cfg_match) const
One of the realizations of serialization/validator.hpp abstract validator.
Used in parsing config file.
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)
virtual void validate_key(const config &cfg, const std::string &name, const config_attribute_value &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...
void read(config &cfg, std::istream &in, abstract_validator *validator)
wml_type::map types_
Type validators.
Used to manage with not initialized validators Supposed to be thrown from the constructor.
bool strict_validation_enabled
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.
bool can_find(const wml_tag &root, const config &cfg)
static void wrong_value_error(const std::string &file, int line, const std::string &tag, const std::string &key, const std::string &value, const std::string &expected, bool flag_exception)
std::unique_ptr< std::istream > scoped_istream
static void print_output(const std::string &message, bool flag_exception=false)
const char * what() const noexcept
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
std::stack< std::string > tag_stack_
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)
schema_validator(const std::string &filename, bool validate_schema=false)
Initializes validator from file.
Helper class, don't construct this directly.
std::vector< reference > referenced_types_
boost::iterator_range< tag_iterator > tags(const config &cfg_match) const
virtual void validate_key(const config &cfg, const std::string &name, const config_attribute_value &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...
std::string current_path() const
std::set< std::string > defined_tag_paths_
void line(int from_x, int from_y, int to_x, int to_y)
Draw a line.
static std::shared_ptr< wml_type > from_config(const config &cfg)
std::string get_wml_location(const std::string &filename, const std::string ¤t_dir)
Returns a complete path to the actual WML file or directory or an empty string if the file isn't pres...
wml_key is used to save the information about one key.
bool read_config_file(const std::string &filename)
Reads config from input.
const wml_tag & active_tag() const
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
Declarations for File-IO.
bool have_active_tag() const
std::size_t index(const std::string &str, const std::size_t index)
Codepoint index corresponding to the nth character in a UTF-8 string.
std::string active_tag_path() const
void queue_message(const config &cfg, T &&... args)
void expand_all(wml_tag &root)
Calls the expansion on each child.
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
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
Realization of serialization/validator.hpp abstract validator.
virtual ~schema_validator()
wml_type::ptr find_type(const std::string &type) const
A config object defines a single node in a WML file, with access to child nodes.
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")
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_
std::string str(const std::string &fallback="") const
static void extra_tag_error(const std::string &file, int line, const std::string &name, int n, const std::string &parent, bool flag_exception)