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"
73 const std::string& file,
int line,
const std::string& name,
const std::string& parent,
bool flag_exception)
75 std::ostringstream ss;
76 ss <<
"Tag [" << name <<
"] may not be used in [" << parent <<
"]\n" <<
at(file,
line) <<
"\n";
83 const std::string& name,
85 const std::string& parent,
88 std::ostringstream ss;
89 ss <<
"Missing tag [" << name <<
"]; there must be " <<
n <<
" [" << name <<
"]s in [" << parent <<
"]\n"
96 const std::string& file,
int line,
const std::string& tag,
const std::string& key,
bool flag_exception)
98 std::ostringstream ss;
99 ss <<
"Invalid key '" << key <<
"='";
101 ss <<
" in tag [" << tag <<
"]\n";
104 ss <<
at(file,
line) <<
"\n";
111 const std::string& file,
int line,
const std::string& tag,
const std::string& key,
bool flag_exception)
113 std::ostringstream ss;
114 ss <<
"Missing key '" << key <<
"='";
116 ss <<
" in tag [" << tag <<
"]\n";
119 ss <<
at(file,
line) <<
"\n";
127 const std::string& tag,
128 const std::string& key,
129 const std::string& value,
130 const std::string& expected,
133 std::ostringstream ss;
134 ss <<
"Invalid value '";
135 if(value.length() > 128)
136 ss << value.substr(0, 128) <<
"...";
138 ss <<
"' in key '" << key <<
"=' in tag [" << tag <<
"]\n" <<
" (expected value of type " << expected <<
") " <<
at(file,
line) <<
"\n";
145 const std::string& tag,
146 const std::string& key,
147 const std::string& value,
150 std::ostringstream ss;
151 ss <<
"Unknown path reference '" << value <<
"' in key '" << key <<
"=' in tag [" << tag <<
"]\n" <<
at(file,
line) <<
"\n";
157 const std::string& tag,
158 const std::string& pat,
159 const std::string& value,
162 std::ostringstream ss;
163 ss <<
"Duplicate or fully-overlapping tag definition '" << value <<
"' (which is also matched by '" << pat <<
"') in tag [" << tag <<
"]\n" <<
at(file,
line) <<
"\n";
169 const std::string& tag,
170 const std::string& pat,
171 const std::string& value,
174 std::ostringstream ss;
175 ss <<
"Duplicate or fully-overlapping key definition '" << value <<
"' (which is also matched by '" << pat <<
"') in tag [" << tag <<
"]\n" <<
at(file,
line) <<
"\n";
181 const std::string& tag,
182 const std::string& key,
183 const std::string& value,
187 std::ostringstream ss;
188 ss <<
"Inheritance loop " << key <<
"=" << value <<
" found (at offset " <<
index <<
") in tag [" << tag <<
"]\n" <<
at(file,
line) <<
"\n";
193 const std::string & tag,
194 const std::string & key,
195 const std::string &
type,
198 std::ostringstream ss;
199 ss <<
"Invalid type '" <<
type <<
"' in key '" << key <<
"=' in tag [" << tag <<
"]\n" <<
at(file,
line) <<
"\n";
210 , config_read_(false)
211 , validate_schema_(validate_schema)
215 ERR_VL <<
"Schema file " << config_file_name <<
" was not read.";
222 LOG_VL <<
"Schema file " << config_file_name <<
" was read.";
223 LOG_VL <<
"Validator initialized";
231 std::unique_ptr<abstract_validator> validator;
237 read(cfg, *stream, validator.
get());
239 ERR_VL <<
"Failed to read file " << filename <<
":\n" <<
e.what();
244 for(
const config& schema :
g.child_range(
"tag")) {
245 if(schema[
"name"].str() ==
"root") {
250 types_[
"t_string"] = std::make_shared<wml_type_tstring>();
254 }
catch(
const std::exception&) {
273 }
else if(!
stack_.empty()) {
313 for(
auto& m :
cache_.top()) {
314 for(
auto& list : m.second) {
328 auto cache_it =
cache_.top().find(&cfg);
329 if(cache_it !=
cache_.top().end()) {
330 cache_it->second.clear();
337 for(
const auto& tag : active.
tags(cfg)) {
338 int cnt =
counter_.top()[tag.first].cnt;
340 if(tag.second.get_min() > cnt) {
345 if(tag.second.get_max() < cnt) {
350 int total_cnt =
counter_.top()[
""].cnt;
353 }
else if(
active_tag().get_max_children() < total_cnt) {
358 for(
const auto& key : active.
keys(cfg)) {
359 if(key.second.is_mandatory()) {
360 if(cfg.
get(key.first) ==
nullptr) {
375 bool matched =
false;
395 assert(
have_active_tag() &&
"Tried to get active tag name when there was none");
414 std::stack<const wml_tag*> temp =
stack_;
415 std::deque<std::string>
path;
416 while(!temp.empty()) {
417 path.push_front(temp.top()->get_name());
420 if(
path.front() ==
"root") {
453 , condition_nesting_()
466 if(name ==
"if" || name ==
"switch") {
468 }
else if(name ==
"tag") {
480 if(tag_name ==
"type") {
494 std::string suffix =
path.back();
496 while(!
path.empty()) {
498 auto link =
links_.find(prefix);
499 if(link !=
links_.end()) {
500 std::string new_path = link->second +
"/" + suffix;
505 suffix =
path.back();
509 if(supers.first != supers.second) {
511 for(
auto cur = supers.first ; cur != supers.second; ++cur) {
512 super_ref.
value_ = cur->second +
"/" + suffix;
521 std::string new_path = prefix +
"/" + suffix;
525 suffix =
path.back() +
"/" + suffix;
542 for(
const std::string& pattern : seen) {
543 for(
const std::string& key :
split) {
550 seen.push_back(name);
557 }
else if(name ==
"tag") {
558 bool first_tag =
true, first_key =
true;
559 std::vector<std::string> tag_names, key_names;
561 if(current.key ==
"tag" || current.key ==
"link") {
562 std::string tag_name = current.cfg[
"name"];
563 if(current.key ==
"link") {
564 tag_name.erase(0, tag_name.find_last_of(
'/') + 1);
567 tag_names.push_back(tag_name);
572 }
else if(current.key ==
"key") {
573 std::string key_name = current.cfg[
"name"];
575 key_names.push_back(key_name);
582 }
else if(name ==
"wml_schema") {
583 using namespace std::placeholders;
586 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());
592 std::sort(missing_types.begin(), missing_types.end());
593 std::sort(missing_tags.begin(), missing_tags.end());
594 static const config dummy;
595 for(
auto& ref : missing_types) {
596 std::string tag_name;
597 if(ref.tag_ ==
"key") {
604 for(
auto& ref : missing_tags) {
605 std::string tag_name;
606 if(ref.tag_ ==
"tag") {
608 }
else if(ref.tag_ ==
"link") {
622 if(tag_name ==
"key" && name ==
"type" ) {
626 }
else if((tag_name ==
"type" || tag_name ==
"element") && name ==
"link") {
628 }
else if(tag_name ==
"link" && name ==
"name") {
630 std::string link_name =
utils::split(cfg[
"name"].str(),
'/').back();
632 }
else if(tag_name ==
"tag" && name ==
"super") {
654 std::deque<std::string>
path;
655 while(!temp.empty()) {
656 path.push_front(temp.top());
659 if(
path.front() ==
"root") {
667 return std::tie(file_, line_) < std::tie(other.
file_, other.
line_);
672 return with.count(value_) > 0;
678 return root.
find_tag(value_, root, cfg) !=
nullptr;
Used in parsing config file.
Variant for storing WML attributes.
std::string str(const std::string &fallback="") const
A config object defines a single node in a WML file, with access to child nodes.
const_all_children_itors all_children_range() const
In-order iteration over all children.
child_itors child_range(config_key_type key)
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.
static config_cache & instance()
Get reference to the singleton object.
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.
virtual void validate(const config &cfg, const std::string &name, int start_line, const std::string &file) override
Validates config.
virtual void close_tag() override
As far as parser is built on stack, some realizations can store stack too.
std::stack< std::string > tag_stack_
std::multimap< std::string, std::string > derivations_
std::vector< reference > referenced_tag_paths_
std::map< std::string, std::string > links_
bool tag_path_exists(const config &cfg, const reference &ref)
void print(message_info &message) override
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)
std::string current_path() const
std::vector< reference > referenced_types_
std::set< std::string > defined_tag_paths_
static bool name_matches(const std::string &pattern, const std::string &name)
std::set< std::string > defined_types_
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...
Realization of serialization/validator.hpp abstract validator.
bool read_config_file(const std::string &filename)
Reads config from input.
wml_type::map types_
Type validators.
wml_tag root_
Root of schema information.
std::vector< std::string > errors_
virtual void validate(const config &cfg, const std::string &name, int start_line, const std::string &file) override
Validates config.
schema_validator(const std::string &filename, bool validate_schema=false)
Initializes validator from file.
bool create_exceptions_
Controls the way to print errors.
wml_type::ptr find_type(const std::string &type) const
std::stack< message_map > cache_
Caches error messages.
void queue_message(const config &cfg, T &&... args)
cnt_stack counter_
Contains number of children.
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...
virtual ~schema_validator()
bool config_read_
Shows, if validator is initialized with schema file.
virtual void close_tag() override
As far as parser is built on stack, some realizations can store stack too.
std::string active_tag_path() const
const wml_tag & active_tag() 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.
std::stack< const wml_tag * > stack_
virtual void print(message_info &)
bool have_active_tag() const
wml_key is used to save the information about one key.
const std::string & get_type() const
Stores information about tag.
int get_min_children() const
const std::string & get_name() const
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.
int get_max_children() const
boost::iterator_range< key_iterator > keys(const config &cfg_match) const
boost::iterator_range< tag_iterator > tags(const config &cfg_match) const
const wml_key * find_key(const std::string &name, const config &match, bool ignore_super=false) const
Returns pointer to child key.
void expand_all(wml_tag &root)
Calls the expansion on each child.
static std::shared_ptr< wml_type > from_config(const config &cfg)
std::shared_ptr< wml_type > ptr
Declarations for File-IO.
Standard logging facilities (interface).
void line(int from_x, int from_y, int to_x, int to_y)
Draw a line.
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...
std::unique_ptr< std::istream > scoped_istream
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 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)
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)
static void print_output(const std::string &message, bool flag_exception=false)
static std::string extra_tag_error(const std::string &file, int line, const std::string &name, int n, const std::string &parent, bool flag_exception)
static std::string extra_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)
static std::string 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)
static std::string missing_key_error(const std::string &file, int line, const std::string &tag, const std::string &key, bool flag_exception)
static std::string wrong_tag_error(const std::string &file, int line, const std::string &name, const std::string &parent, bool flag_exception)
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 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)
static std::string missing_tag_error(const std::string &file, int line, const std::string &name, int n, const std::string &parent, bool flag_exception)
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.
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,...
std::string join(const T &v, const std::string &s=",")
Generates a new string joining container items in a list.
std::vector< std::string > split(const config_attribute_value &val)
std::string lineno_string(const std::string &lineno)
filesystem::scoped_istream preprocess_file(const std::string &fname, preproc_map *defines)
Function to use the WML preprocessor on a file.
std::map< std::string, struct preproc_define > preproc_map
One of the realizations of serialization/validator.hpp abstract validator.
void read(config &cfg, std::istream &in, abstract_validator *validator)
Used to manage with not initialized validators Supposed to be thrown from the constructor.
bool match(const std::set< std::string > &with)
bool operator<(const reference &other) const
bool can_find(const wml_tag &root, const config &cfg)
Helper class, don't construct this directly.
static map_location::DIRECTION n
bool strict_validation_enabled
Add a special kind of assert to validate whether the input from WML doesn't contain any problems that...