Some schema code reformatting as requested by @celticminstrel
This commit is contained in:
parent
579bbc464f
commit
596edaac00
4 changed files with 663 additions and 546 deletions
|
@ -14,106 +14,112 @@
|
|||
|
||||
#include "serialization/schema_validator.hpp"
|
||||
|
||||
|
||||
#include "filesystem.hpp"
|
||||
#include "gettext.hpp"
|
||||
#include "log.hpp"
|
||||
#include "serialization/preprocessor.hpp"
|
||||
#include "wml_exception.hpp"
|
||||
|
||||
namespace schema_validation{
|
||||
|
||||
namespace schema_validation
|
||||
{
|
||||
static lg::log_domain log_validation("validation");
|
||||
|
||||
#define ERR_VL LOG_STREAM(err, log_validation)
|
||||
#define WRN_VL LOG_STREAM(warn, log_validation)
|
||||
#define LOG_VL LOG_STREAM(info, log_validation)
|
||||
|
||||
static std::string at(const std::string & file, int line){
|
||||
static std::string at(const std::string& file, int line)
|
||||
{
|
||||
std::ostringstream ss;
|
||||
ss << line << " " << file;
|
||||
return "at " + ::lineno_string(ss.str());
|
||||
}
|
||||
|
||||
static void print_output(const std::string & message,bool flag_exception = false ){
|
||||
static void print_output(const std::string& message, bool flag_exception = false)
|
||||
{
|
||||
#ifndef VALIDATION_ERRORS_LOG
|
||||
if(flag_exception){
|
||||
throw wml_exception("Validation error occurred",message);
|
||||
}else{
|
||||
ERR_VL << message;
|
||||
}
|
||||
if(flag_exception) {
|
||||
throw wml_exception("Validation error occurred", message);
|
||||
} else {
|
||||
ERR_VL << message;
|
||||
}
|
||||
#else
|
||||
// dirty hack to avoid "unused" error in case of compiling with definition on
|
||||
// dirty hack to avoid "unused" error in case of compiling with definition on
|
||||
flag_exception = true;
|
||||
if (flag_exception){ ERR_VL << message;}
|
||||
if(flag_exception) {
|
||||
ERR_VL << message;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void extra_tag_error(const std::string & file, int line,
|
||||
const std::string & name,int n,
|
||||
const std::string & parent, bool flag_exception){
|
||||
static void extra_tag_error(const std::string& file,
|
||||
int line,
|
||||
const std::string& name,
|
||||
int n,
|
||||
const std::string& parent,
|
||||
bool flag_exception)
|
||||
{
|
||||
std::ostringstream ss;
|
||||
ss << "Extra tag [" << name << "]; there may only be "
|
||||
<< n << " [" << name << "] in [" << parent << "]\n"
|
||||
ss << "Extra tag [" << name << "]; there may only be " << n << " [" << name << "] in [" << parent << "]\n"
|
||||
<< at(file, line) << "\n";
|
||||
print_output (ss.str (),flag_exception);
|
||||
print_output(ss.str(), flag_exception);
|
||||
}
|
||||
|
||||
static void wrong_tag_error(const std::string & file, int line,
|
||||
const std::string & name,const std::string & parent,
|
||||
bool flag_exception){
|
||||
static void wrong_tag_error(
|
||||
const std::string& file, int line, const std::string& name, const std::string& parent, bool flag_exception)
|
||||
{
|
||||
std::ostringstream ss;
|
||||
ss << "Tag [" << name << "] may not be used in ["
|
||||
<< parent << "]\n"
|
||||
<< at(file, line) << "\n";
|
||||
print_output (ss.str (),flag_exception);
|
||||
ss << "Tag [" << name << "] may not be used in [" << parent << "]\n" << at(file, line) << "\n";
|
||||
print_output(ss.str(), flag_exception);
|
||||
}
|
||||
|
||||
static void missing_tag_error(const std::string & file, int line,
|
||||
const std::string & name,int n,
|
||||
const std::string & parent, bool flag_exception){
|
||||
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::ostringstream ss;
|
||||
ss << "Missing tag [" << name << "]; there must be "
|
||||
<< n << " [" << name << "]s in [" << parent << "]\n"
|
||||
ss << "Missing tag [" << name << "]; there must be " << n << " [" << name << "]s in [" << parent << "]\n"
|
||||
<< at(file, line) << "\n";
|
||||
print_output (ss.str (),flag_exception);
|
||||
print_output(ss.str(), flag_exception);
|
||||
}
|
||||
|
||||
static void extra_key_error(const std::string & file, int line,
|
||||
const std::string & tag,const std::string & key,
|
||||
bool flag_exception){
|
||||
static void extra_key_error(
|
||||
const std::string& file, int line, const std::string& tag, const std::string& key, bool flag_exception)
|
||||
{
|
||||
std::ostringstream ss;
|
||||
ss << "Invalid key '" << key << "=' in tag [" << tag
|
||||
<< "]\n"
|
||||
<< at(file, line) << "\n";
|
||||
print_output (ss.str (),flag_exception);
|
||||
ss << "Invalid key '" << key << "=' in tag [" << tag << "]\n" << at(file, line) << "\n";
|
||||
print_output(ss.str(), flag_exception);
|
||||
}
|
||||
|
||||
static void missing_key_error(const std::string & file, int line,
|
||||
const std::string & tag,const std::string & key,
|
||||
bool flag_exception){
|
||||
static void missing_key_error(
|
||||
const std::string& file, int line, const std::string& tag, const std::string& key, bool flag_exception)
|
||||
{
|
||||
std::ostringstream ss;
|
||||
ss << "Missing key '" << key << "=' in tag [" << tag
|
||||
<< "]\n"
|
||||
<< at(file, line) << "\n";
|
||||
print_output (ss.str (),flag_exception);
|
||||
ss << "Missing key '" << key << "=' in tag [" << tag << "]\n" << at(file, line) << "\n";
|
||||
print_output(ss.str(), flag_exception);
|
||||
}
|
||||
|
||||
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){
|
||||
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)
|
||||
{
|
||||
std::ostringstream ss;
|
||||
ss << "Invalid value '" << value << "' in key '" << key
|
||||
<< "=' in tag [" << tag << "]\n"
|
||||
<< at(file, line) << "\n";
|
||||
print_output (ss.str (),flag_exception);
|
||||
ss << "Invalid value '" << value << "' in key '" << key << "=' in tag [" << tag << "]\n" << at(file, line) << "\n";
|
||||
|
||||
print_output(ss.str(), flag_exception);
|
||||
}
|
||||
|
||||
schema_validator::~schema_validator()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
schema_validator::~schema_validator(){}
|
||||
|
||||
schema_validator::schema_validator(const std::string & config_file_name)
|
||||
schema_validator::schema_validator(const std::string& config_file_name)
|
||||
: config_read_(false)
|
||||
, create_exceptions_(strict_validation_enabled)
|
||||
, root_()
|
||||
|
@ -122,44 +128,44 @@ schema_validator::schema_validator(const std::string & config_file_name)
|
|||
, cache_()
|
||||
, types_()
|
||||
{
|
||||
if ( !read_config_file(config_file_name) ) {
|
||||
ERR_VL << "Schema file "<< config_file_name << " was not read." << std::endl;
|
||||
throw abstract_validator::error("Schema file "+ config_file_name
|
||||
+ " was not read.\n");
|
||||
}else{
|
||||
if(!read_config_file(config_file_name)) {
|
||||
ERR_VL << "Schema file " << config_file_name << " was not read." << std::endl;
|
||||
throw abstract_validator::error("Schema file " + config_file_name + " was not read.\n");
|
||||
} else {
|
||||
stack_.push(&root_);
|
||||
counter_.emplace();
|
||||
cache_.emplace();
|
||||
root_.expand_all(root_);
|
||||
LOG_VL << "Schema file "<< config_file_name << " was read.\n"
|
||||
<< "Validator initialized\n";
|
||||
LOG_VL << "Schema file " << config_file_name << " was read.\n"
|
||||
<< "Validator initialized\n";
|
||||
}
|
||||
}
|
||||
|
||||
bool schema_validator::read_config_file(const std::string &filename){
|
||||
bool schema_validator::read_config_file(const std::string& filename)
|
||||
{
|
||||
config cfg;
|
||||
try {
|
||||
preproc_map preproc(
|
||||
game_config::config_cache::instance().get_preproc_map());
|
||||
preproc_map preproc(game_config::config_cache::instance().get_preproc_map());
|
||||
filesystem::scoped_istream stream = preprocess_file(filename, &preproc);
|
||||
read(cfg, *stream);
|
||||
} catch(config::error& e) {
|
||||
ERR_VL << "Failed to read file "<< filename << ":\n" << e.what() << "\n";
|
||||
ERR_VL << "Failed to read file " << filename << ":\n" << e.what() << "\n";
|
||||
return false;
|
||||
}
|
||||
for(const config &g : cfg.child_range("wml_schema")) {
|
||||
for(const config &schema : g.child_range("tag")) {
|
||||
if (schema["name"].str() == "root"){
|
||||
|
||||
for(const config& g : cfg.child_range("wml_schema")) {
|
||||
for(const config& schema : g.child_range("tag")) {
|
||||
if(schema["name"].str() == "root") {
|
||||
//@NOTE Don't know, maybe merging of roots needed.
|
||||
root_ = class_tag (schema);
|
||||
root_ = class_tag(schema);
|
||||
}
|
||||
}
|
||||
for(const config &type : g.child_range("type")) {
|
||||
try{
|
||||
types_[type["name"].str()] = boost::regex( type["value"].str());
|
||||
}
|
||||
catch (std::exception&){
|
||||
// Need to check all type values in schema-generator
|
||||
|
||||
for(const config& type : g.child_range("type")) {
|
||||
try {
|
||||
types_[type["name"].str()] = boost::regex(type["value"].str());
|
||||
} catch(std::exception&) {
|
||||
// Need to check all type values in schema-generator
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -167,141 +173,140 @@ bool schema_validator::read_config_file(const std::string &filename){
|
|||
config_read_ = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Please, @Note that there is some magic in pushing and poping to/from stacks.
|
||||
* assume they all are on their place due to parser algorithm
|
||||
* and validation logic
|
||||
*/
|
||||
void schema_validator::open_tag(const std::string & name,
|
||||
int start_line,
|
||||
const std::string &file,
|
||||
bool addittion){
|
||||
if (! stack_.empty()){
|
||||
const class_tag * tag = nullptr;
|
||||
if (stack_.top()){
|
||||
tag = stack_.top()->find_tag(name,root_);
|
||||
if (! tag){
|
||||
wrong_tag_error(file,start_line,name,stack_.top()->get_name(),
|
||||
create_exceptions_);
|
||||
}else{
|
||||
if (! addittion){
|
||||
counter & cnt = counter_.top()[name];
|
||||
++ cnt.cnt;
|
||||
void schema_validator::open_tag(const std::string& name, int start_line, const std::string& file, bool addittion)
|
||||
{
|
||||
if(!stack_.empty()) {
|
||||
const class_tag* tag = nullptr;
|
||||
|
||||
if(stack_.top()) {
|
||||
tag = stack_.top()->find_tag(name, root_);
|
||||
|
||||
if(!tag) {
|
||||
wrong_tag_error(file, start_line, name, stack_.top()->get_name(), create_exceptions_);
|
||||
} else {
|
||||
if(!addittion) {
|
||||
counter& cnt = counter_.top()[name];
|
||||
++cnt.cnt;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stack_.push(tag);
|
||||
}else{
|
||||
} else {
|
||||
stack_.push(nullptr);
|
||||
}
|
||||
|
||||
counter_.emplace();
|
||||
cache_.emplace();
|
||||
}
|
||||
|
||||
void schema_validator::close_tag(){
|
||||
void schema_validator::close_tag()
|
||||
{
|
||||
stack_.pop();
|
||||
counter_.pop();
|
||||
//cache_ is cleared in another place.
|
||||
// cache_ is cleared in another place.
|
||||
}
|
||||
|
||||
void schema_validator::validate(const config & cfg, const std::string & name,
|
||||
int start_line,
|
||||
const std::string &file){
|
||||
//close previous errors and print them to output.
|
||||
void schema_validator::validate(const config& cfg, const std::string& name, int start_line, const std::string& file)
|
||||
{
|
||||
// close previous errors and print them to output.
|
||||
message_map::iterator cache_it = cache_.top().begin();
|
||||
for (;cache_it != cache_.top().end();++cache_it){
|
||||
for (message_list::iterator i = cache_it->second.begin();
|
||||
i != cache_it->second.end(); ++i){
|
||||
for(; cache_it != cache_.top().end(); ++cache_it) {
|
||||
for(message_list::iterator i = cache_it->second.begin(); i != cache_it->second.end(); ++i) {
|
||||
print(*i);
|
||||
}
|
||||
}
|
||||
|
||||
cache_.pop();
|
||||
|
||||
// clear cache
|
||||
cache_it = cache_.top().find(&cfg);
|
||||
if (cache_it != cache_.top().end()){
|
||||
if(cache_it != cache_.top().end()) {
|
||||
cache_it->second.clear();
|
||||
}
|
||||
|
||||
// Please note that validating unknown tag keys the result will be false
|
||||
// Checking all elements counters.
|
||||
if (!stack_.empty() && stack_.top() && config_read_){
|
||||
if(!stack_.empty() && stack_.top() && config_read_) {
|
||||
class_tag::all_const_tag_iterators p = stack_.top()->tags();
|
||||
for (class_tag::const_tag_iterator tag = p.first;
|
||||
tag != p.second ; ++tag){
|
||||
|
||||
for(class_tag::const_tag_iterator tag = p.first; tag != p.second; ++tag) {
|
||||
int cnt = counter_.top()[tag->first].cnt;
|
||||
if (tag->second.get_min() > cnt){
|
||||
|
||||
if(tag->second.get_min() > cnt) {
|
||||
cache_.top()[&cfg].emplace_back(
|
||||
MISSING_TAG,file,start_line,tag->second.get_min(),tag->first,"",name);
|
||||
MISSING_TAG, file, start_line, tag->second.get_min(), tag->first, "", name);
|
||||
continue;
|
||||
}
|
||||
if (tag->second.get_max() < cnt){
|
||||
|
||||
if(tag->second.get_max() < cnt) {
|
||||
cache_.top()[&cfg].emplace_back(
|
||||
EXTRA_TAG,file,start_line,tag->second.get_max(),tag->first,"",name);
|
||||
EXTRA_TAG, file, start_line, tag->second.get_max(), tag->first, "", name);
|
||||
}
|
||||
}
|
||||
|
||||
// Checking if all mandatory keys are present
|
||||
class_tag::all_const_key_iterators k = stack_.top()->keys();
|
||||
for (class_tag::const_key_iterator key = k.first;
|
||||
key != k.second ; ++key){
|
||||
if (key->second.is_mandatory()){
|
||||
if (cfg.get(key->first) == nullptr){
|
||||
cache_.top()[&cfg].emplace_back(
|
||||
MISSING_KEY,file,start_line,0,name,key->first );
|
||||
for(class_tag::const_key_iterator key = k.first; key != k.second; ++key) {
|
||||
if(key->second.is_mandatory()) {
|
||||
if(cfg.get(key->first) == nullptr) {
|
||||
cache_.top()[&cfg].emplace_back(MISSING_KEY, file, start_line, 0, name, key->first);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void schema_validator::validate_key(const config & cfg,
|
||||
const std::string & name,
|
||||
const std::string & value,
|
||||
int start_line,
|
||||
const std::string &file){
|
||||
if (!stack_.empty() && stack_.top() && config_read_){
|
||||
void schema_validator::validate_key(
|
||||
const config& cfg, const std::string& name, const std::string& value, int start_line, const std::string& file)
|
||||
{
|
||||
if(!stack_.empty() && stack_.top() && config_read_) {
|
||||
// checking existing keys
|
||||
const class_key * key =stack_.top()->find_key(name);
|
||||
if (key){
|
||||
std::map<std::string,boost::regex>::iterator itt =
|
||||
types_.find(key->get_type());
|
||||
if (itt != types_.end()){
|
||||
const class_key* key = stack_.top()->find_key(name);
|
||||
if(key) {
|
||||
std::map<std::string, boost::regex>::iterator itt = types_.find(key->get_type());
|
||||
|
||||
if(itt != types_.end()) {
|
||||
boost::smatch sub;
|
||||
bool res = boost::regex_match(value,sub,itt->second);
|
||||
if (!res ) {
|
||||
bool res = boost::regex_match(value, sub, itt->second);
|
||||
|
||||
if(!res) {
|
||||
cache_.top()[&cfg].emplace_back(
|
||||
WRONG_VALUE,file,start_line,0,stack_.top()->get_name(),name,value);
|
||||
WRONG_VALUE, file, start_line, 0, stack_.top()->get_name(), name, value);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
cache_.top()[&cfg].emplace_back(EXTRA_KEY, file, start_line, 0, stack_.top()->get_name(), name);
|
||||
}
|
||||
else{
|
||||
cache_.top()[&cfg].emplace_back(
|
||||
EXTRA_KEY,file,start_line,0, stack_.top()->get_name(),name);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void schema_validator::print(message_info & el){
|
||||
switch (el.type){
|
||||
void schema_validator::print(message_info& el)
|
||||
{
|
||||
switch(el.type) {
|
||||
case WRONG_TAG:
|
||||
wrong_tag_error(el.file,el.line,el.tag,el.value,create_exceptions_);
|
||||
wrong_tag_error(el.file, el.line, el.tag, el.value, create_exceptions_);
|
||||
break;
|
||||
case EXTRA_TAG:
|
||||
extra_tag_error(el.file,el.line,el.tag,el.n,el.value,create_exceptions_);
|
||||
extra_tag_error(el.file, el.line, el.tag, el.n, el.value, create_exceptions_);
|
||||
break;
|
||||
case MISSING_TAG:
|
||||
missing_tag_error(el.file,el.line,el.tag,el.n,el.value,
|
||||
create_exceptions_);
|
||||
missing_tag_error(el.file, el.line, el.tag, el.n, el.value, create_exceptions_);
|
||||
break;
|
||||
case EXTRA_KEY:
|
||||
extra_key_error(el.file,el.line,el.tag,el.key,create_exceptions_);
|
||||
extra_key_error(el.file, el.line, el.tag, el.key, create_exceptions_);
|
||||
break;
|
||||
case WRONG_VALUE:
|
||||
wrong_value_error(el.file,el.line,el.tag,el.key,el.value,
|
||||
create_exceptions_);
|
||||
wrong_value_error(el.file, el.line, el.tag, el.key, el.value, create_exceptions_);
|
||||
break;
|
||||
case MISSING_KEY:
|
||||
missing_key_error(el.file,el.line,el.tag,el.key,create_exceptions_);
|
||||
missing_key_error(el.file, el.line, el.tag, el.key, create_exceptions_);
|
||||
}
|
||||
}
|
||||
}//namespace schema_validation{
|
||||
} // namespace schema_validation{
|
||||
|
|
|
@ -14,85 +14,87 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "serialization/validator.hpp"
|
||||
#include "serialization/tag.hpp"
|
||||
|
||||
#include "config_cache.hpp"
|
||||
#include "serialization/parser.hpp"
|
||||
#include "serialization/tag.hpp"
|
||||
#include "serialization/validator.hpp"
|
||||
|
||||
#include <boost/regex.hpp>
|
||||
|
||||
#include <iostream>
|
||||
#include <queue>
|
||||
#include <string>
|
||||
#include <stack>
|
||||
#include <string>
|
||||
|
||||
class config;
|
||||
|
||||
/** @file
|
||||
* One of the realizations of serialization/validator.hpp abstract validator.
|
||||
*/
|
||||
namespace schema_validation{
|
||||
namespace schema_validation
|
||||
{
|
||||
/**
|
||||
* Realization of serialization/validator.hpp abstract validator.
|
||||
* Based on stack. Uses some stacks to store different info.
|
||||
*/
|
||||
class schema_validator : public abstract_validator{
|
||||
class schema_validator : public abstract_validator
|
||||
{
|
||||
public:
|
||||
virtual ~schema_validator();
|
||||
|
||||
/**
|
||||
* Initializes validator from file.
|
||||
* Throws abstract_validator::error if any error.
|
||||
*/
|
||||
schema_validator(const std::string & filename);
|
||||
void set_create_exceptions(bool value){
|
||||
schema_validator(const std::string& filename);
|
||||
|
||||
void set_create_exceptions(bool value)
|
||||
{
|
||||
create_exceptions_ = value;
|
||||
}
|
||||
|
||||
virtual void open_tag(const std::string & name,
|
||||
int start_line=0,
|
||||
const std::string &file="",
|
||||
bool addittion = false);
|
||||
virtual void open_tag(
|
||||
const std::string& name, int start_line = 0, const std::string& file = "", bool addittion = false);
|
||||
virtual void close_tag();
|
||||
virtual void validate(const config & cfg,
|
||||
const std::string & name,
|
||||
int start_line,
|
||||
const std::string &file);
|
||||
virtual void validate_key(const config & cfg,
|
||||
const std::string & name,
|
||||
const std::string & value,
|
||||
int start_line,
|
||||
const std::string &file);
|
||||
private:
|
||||
// types section
|
||||
// Just some magic to ensure zero initialization.
|
||||
struct counter{
|
||||
int cnt;
|
||||
counter(): cnt(0){}
|
||||
};
|
||||
/**
|
||||
* Counters are mapped by tag name
|
||||
*/
|
||||
typedef std::map<std::string,counter> cnt_map;
|
||||
virtual void validate(const config& cfg, const std::string& name, int start_line, const std::string& file);
|
||||
virtual void validate_key(const config& cfg,
|
||||
const std::string& name,
|
||||
const std::string& value,
|
||||
int start_line,
|
||||
const std::string& file);
|
||||
|
||||
/**
|
||||
* And counter maps are organize in stack.
|
||||
*/
|
||||
private:
|
||||
// types section
|
||||
// Just some magic to ensure zero initialization.
|
||||
struct counter
|
||||
{
|
||||
int cnt;
|
||||
counter()
|
||||
: cnt(0)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
/** Counters are mapped by tag name. */
|
||||
typedef std::map<std::string, counter> cnt_map;
|
||||
|
||||
/** And counter maps are organize in stack. */
|
||||
typedef std::stack<cnt_map> cnt_stack;
|
||||
|
||||
enum message_type{WRONG_TAG,EXTRA_TAG,MISSING_TAG,
|
||||
EXTRA_KEY,MISSING_KEY,WRONG_VALUE};
|
||||
//error_cache
|
||||
enum message_type { WRONG_TAG, EXTRA_TAG, MISSING_TAG, EXTRA_KEY, MISSING_KEY, WRONG_VALUE };
|
||||
// error_cache
|
||||
|
||||
/**
|
||||
* Messages are cached.
|
||||
* The reason is next: in file where [tag]...[/tag][+tag]...[/tag]
|
||||
* config object will be validated each [/tag]. So message can be as wrong
|
||||
* (when [+tag] section contains missed elements) as duplicated.
|
||||
*
|
||||
* Messages are mapped by config*. That ensures uniqueness.
|
||||
* Also message-maps are organized in stack to avoid memory leaks.
|
||||
*/
|
||||
struct message_info{
|
||||
* Messages are cached.
|
||||
* The reason is next: in file where [tag]...[/tag][+tag]...[/tag]
|
||||
* config object will be validated each [/tag]. So message can be as wrong
|
||||
* (when [+tag] section contains missed elements) as duplicated.
|
||||
*
|
||||
* Messages are mapped by config*. That ensures uniqueness.
|
||||
* Also message-maps are organized in stack to avoid memory leaks.
|
||||
*/
|
||||
struct message_info
|
||||
{
|
||||
message_type type;
|
||||
std::string file;
|
||||
int line;
|
||||
|
@ -100,49 +102,51 @@ private:
|
|||
std::string tag;
|
||||
std::string key;
|
||||
std::string value;
|
||||
message_info(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 = "")
|
||||
:type(t),file(file),line(line),n(n),tag(tag),key(key),
|
||||
value(value){}
|
||||
};
|
||||
typedef std::deque<message_info> message_list;
|
||||
typedef std::map<const config *, message_list> message_map;
|
||||
|
||||
void print(message_info &);
|
||||
/**
|
||||
* Reads config from input.
|
||||
*/
|
||||
bool read_config_file(const std::string & filename);
|
||||
/**
|
||||
* Shows, if validator is initialized with schema file;
|
||||
*/
|
||||
message_info(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 = "")
|
||||
: type(t)
|
||||
, file(file)
|
||||
, line(line)
|
||||
, n(n)
|
||||
, tag(tag)
|
||||
, key(key)
|
||||
, value(value)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
typedef std::deque<message_info> message_list;
|
||||
typedef std::map<const config*, message_list> message_map;
|
||||
|
||||
void print(message_info&);
|
||||
|
||||
/** Reads config from input. */
|
||||
bool read_config_file(const std::string& filename);
|
||||
|
||||
/** Shows, if validator is initialized with schema file. */
|
||||
bool config_read_;
|
||||
/**
|
||||
* Controls the way to print errors.
|
||||
*/
|
||||
|
||||
/** Controls the way to print errors. */
|
||||
bool create_exceptions_;
|
||||
/**
|
||||
* Root of schema information
|
||||
*/
|
||||
|
||||
/** Root of schema information. */
|
||||
class_tag root_;
|
||||
|
||||
std::stack<const class_tag *> stack_;
|
||||
/**
|
||||
* Contains number of children
|
||||
*/
|
||||
std::stack<const class_tag*> stack_;
|
||||
|
||||
/** Contains number of children. */
|
||||
cnt_stack counter_;
|
||||
/**
|
||||
* Caches error messages.
|
||||
*/
|
||||
|
||||
/** Caches error messages. */
|
||||
std::stack<message_map> cache_;
|
||||
/**
|
||||
* Type validators.
|
||||
*/
|
||||
std::map<std::string,boost::regex> types_;
|
||||
|
||||
/** Type validators. */
|
||||
std::map<std::string, boost::regex> types_;
|
||||
};
|
||||
}//namespace schema_validation{
|
||||
} // namespace schema_validation{
|
||||
|
|
|
@ -21,8 +21,8 @@
|
|||
|
||||
#include "config.hpp"
|
||||
|
||||
namespace schema_validation{
|
||||
|
||||
namespace schema_validation
|
||||
{
|
||||
/*WIKI
|
||||
* @begin{parent}{name="wml_schema/tag/"}
|
||||
* @begin{tag}{name="key"}{min=0}{max=-1}
|
||||
|
@ -36,36 +36,40 @@ namespace schema_validation{
|
|||
* @end{parent}{name="wml_schema/tag/"}
|
||||
*/
|
||||
|
||||
class_key::class_key(const config & cfg)
|
||||
: name_(cfg["name"].str())
|
||||
class_key::class_key(const config& cfg)
|
||||
: name_(cfg["name"].str())
|
||||
, type_(cfg["type"].str())
|
||||
, default_()
|
||||
, mandatory_(false)
|
||||
{
|
||||
if (cfg.has_attribute("mandatory")){
|
||||
mandatory_ = cfg["mandatory"].to_bool();
|
||||
}else{
|
||||
if (cfg.has_attribute("default")){
|
||||
default_= cfg["default"].str();
|
||||
}
|
||||
}
|
||||
}
|
||||
void class_key::print(std::ostream& os,int level) const {
|
||||
{
|
||||
if(cfg.has_attribute("mandatory")) {
|
||||
mandatory_ = cfg["mandatory"].to_bool();
|
||||
} else {
|
||||
if(cfg.has_attribute("default")) {
|
||||
default_ = cfg["default"].str();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void class_key::print(std::ostream& os, int level) const
|
||||
{
|
||||
std::string s;
|
||||
for (int j=0;j<level;j++){
|
||||
for(int j = 0; j < level; j++) {
|
||||
s.append(" ");
|
||||
}
|
||||
os << s << "[key]\n"
|
||||
<< s << " name=\""<< name_ <<"\"\n"
|
||||
<< s << " type=\""<< type_ <<"\"\n";
|
||||
if (is_mandatory()){
|
||||
|
||||
os << s << "[key]\n" << s << " name=\"" << name_ << "\"\n" << s << " type=\"" << type_ << "\"\n";
|
||||
|
||||
if(is_mandatory()) {
|
||||
os << s << " mandatory=\"true\"\n";
|
||||
}else{
|
||||
os << s <<" default="<< default_ <<"\n";
|
||||
} else {
|
||||
os << s << " default=" << default_ << "\n";
|
||||
}
|
||||
|
||||
os << s << "[/key]\n";
|
||||
}
|
||||
class_tag::class_tag(const config & cfg)
|
||||
|
||||
class_tag::class_tag(const config& cfg)
|
||||
: name_(cfg["name"].str())
|
||||
, min_(cfg["min"].to_int())
|
||||
, max_(cfg["max"].to_int())
|
||||
|
@ -74,89 +78,108 @@ class_tag::class_tag(const config & cfg)
|
|||
, keys_()
|
||||
, links_()
|
||||
{
|
||||
if (max_ < 0){
|
||||
max_ = INT_MAX;
|
||||
}
|
||||
if (cfg.has_attribute("super")){
|
||||
super_ = cfg["super"].str();
|
||||
}
|
||||
for (const config &child : cfg.child_range("tag")) {
|
||||
class_tag child_tag (child);
|
||||
add_tag(child_tag);
|
||||
}
|
||||
for (const config &child : cfg.child_range("key")) {
|
||||
class_key child_key (child);
|
||||
add_key(child_key);
|
||||
}
|
||||
for (const config &link : cfg.child_range("link")) {
|
||||
std::string link_name = link["name"].str();
|
||||
add_link(link_name);
|
||||
}
|
||||
if(max_ < 0) {
|
||||
max_ = INT_MAX;
|
||||
}
|
||||
|
||||
if(cfg.has_attribute("super")) {
|
||||
super_ = cfg["super"].str();
|
||||
}
|
||||
|
||||
for(const config& child : cfg.child_range("tag")) {
|
||||
class_tag child_tag(child);
|
||||
add_tag(child_tag);
|
||||
}
|
||||
|
||||
for(const config& child : cfg.child_range("key")) {
|
||||
class_key child_key(child);
|
||||
add_key(child_key);
|
||||
}
|
||||
|
||||
for(const config& link : cfg.child_range("link")) {
|
||||
std::string link_name = link["name"].str();
|
||||
add_link(link_name);
|
||||
}
|
||||
}
|
||||
|
||||
void class_tag::print(std::ostream& os){
|
||||
printl(os,4,4);
|
||||
void class_tag::print(std::ostream& os)
|
||||
{
|
||||
printl(os, 4, 4);
|
||||
}
|
||||
|
||||
void class_tag::add_link(const std::string &link){
|
||||
void class_tag::add_link(const std::string& link)
|
||||
{
|
||||
std::string::size_type pos_last = link.rfind('/');
|
||||
//if (pos_last == std::string::npos) return;
|
||||
std::string name_link = link.substr(pos_last+1,link.length());
|
||||
// if (pos_last == std::string::npos) return;
|
||||
std::string name_link = link.substr(pos_last + 1, link.length());
|
||||
links_.emplace(name_link, link);
|
||||
}
|
||||
|
||||
const class_key * class_tag::find_key(const std::string &name) const{
|
||||
const class_key* class_tag::find_key(const std::string& name) const
|
||||
{
|
||||
key_map::const_iterator it_keys = keys_.find(name);
|
||||
if ( it_keys!= keys_.end() ){
|
||||
if(it_keys != keys_.end()) {
|
||||
return &(it_keys->second);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const std::string * class_tag::find_link(const std::string &name) const{
|
||||
const std::string* class_tag::find_link(const std::string& name) const
|
||||
{
|
||||
link_map::const_iterator it_links = links_.find(name);
|
||||
if ( it_links!= links_.end() ){
|
||||
if(it_links != links_.end()) {
|
||||
return &(it_links->second);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const class_tag * class_tag::find_tag(const std::string &fullpath,
|
||||
const class_tag &root) const{
|
||||
if (fullpath.empty()) return nullptr;
|
||||
std::string::size_type pos = fullpath.find('/');
|
||||
std::string name;
|
||||
std::string next_path;
|
||||
if (pos != std::string::npos) {
|
||||
name = fullpath.substr(0,pos);
|
||||
next_path = fullpath.substr(pos+1,fullpath.length());
|
||||
}else{
|
||||
name = fullpath;
|
||||
}
|
||||
tag_map::const_iterator it_tags = tags_.find(name);
|
||||
if (it_tags != tags_.end()){
|
||||
if (next_path.empty()){
|
||||
return &(it_tags->second);
|
||||
}else{
|
||||
return it_tags->second.find_tag(next_path,root);
|
||||
}
|
||||
}
|
||||
link_map::const_iterator it_links = links_.find(name);
|
||||
if (it_links != links_.end()){
|
||||
return root.find_tag(it_links->second + "/" +next_path,root);
|
||||
}
|
||||
return nullptr;
|
||||
const class_tag* class_tag::find_tag(const std::string& fullpath, const class_tag& root) const
|
||||
{
|
||||
if(fullpath.empty()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
}
|
||||
std::string::size_type pos = fullpath.find('/');
|
||||
std::string name;
|
||||
std::string next_path;
|
||||
|
||||
void class_tag::expand_all(class_tag &root){
|
||||
for (tag_map::iterator i = tags_.begin(); i!= tags_.end(); ++i){
|
||||
if(pos != std::string::npos) {
|
||||
name = fullpath.substr(0, pos);
|
||||
next_path = fullpath.substr(pos + 1, fullpath.length());
|
||||
} else {
|
||||
name = fullpath;
|
||||
}
|
||||
|
||||
tag_map::const_iterator it_tags = tags_.find(name);
|
||||
if(it_tags != tags_.end()) {
|
||||
if(next_path.empty()) {
|
||||
return &(it_tags->second);
|
||||
} else {
|
||||
return it_tags->second.find_tag(next_path, root);
|
||||
}
|
||||
}
|
||||
|
||||
link_map::const_iterator it_links = links_.find(name);
|
||||
if(it_links != links_.end()) {
|
||||
return root.find_tag(it_links->second + "/" + next_path, root);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void class_tag::expand_all(class_tag& root)
|
||||
{
|
||||
for(tag_map::iterator i = tags_.begin(); i != tags_.end(); ++i) {
|
||||
i->second.expand(root);
|
||||
i->second.expand_all(root);
|
||||
}
|
||||
}
|
||||
void class_tag::remove_keys_by_type (const std::string & type){
|
||||
key_iterator i= keys_.begin ();
|
||||
|
||||
void class_tag::remove_keys_by_type(const std::string& type)
|
||||
{
|
||||
key_iterator i = keys_.begin();
|
||||
while(i != keys_.end()) {
|
||||
if(i->second.get_type() == type) {
|
||||
keys_.erase(i++);
|
||||
|
@ -164,7 +187,8 @@ void class_tag::remove_keys_by_type (const std::string & type){
|
|||
++i;
|
||||
}
|
||||
}
|
||||
for (tag_iterator t = tags_.begin(); t!=tags_.end();++t){
|
||||
|
||||
for(tag_iterator t = tags_.begin(); t != tags_.end(); ++t) {
|
||||
t->second.remove_keys_by_type(type);
|
||||
}
|
||||
}
|
||||
|
@ -194,134 +218,158 @@ void class_tag::remove_keys_by_type (const std::string & type){
|
|||
* @end{tag}{name="type"}
|
||||
* @end{parent}{name="wml_schema/"}
|
||||
*/
|
||||
void class_tag::printl(std::ostream &os,int level, int step){
|
||||
|
||||
void class_tag::printl(std::ostream& os, int level, int step)
|
||||
{
|
||||
std::string s;
|
||||
for (int j=0;j<level;j++){
|
||||
for(int j = 0; j < level; j++) {
|
||||
s.append(" ");
|
||||
}
|
||||
|
||||
os << s << "[tag]\n"
|
||||
<< s <<" name=\""<< name_ <<"\"\n"
|
||||
<< s <<" min=\""<< min_ <<"\"\n"
|
||||
<< s <<" max=\""<< max_ <<"\"\n";
|
||||
if (! super_.empty() ){
|
||||
os<< s <<" super=\""<< super_ <<"\"\n";
|
||||
<< s << " name=\"" << name_ << "\"\n"
|
||||
<< s << " min=\"" << min_ << "\"\n"
|
||||
<< s << " max=\"" << max_ << "\"\n";
|
||||
|
||||
if(!super_.empty()) {
|
||||
os << s << " super=\"" << super_ << "\"\n";
|
||||
}
|
||||
for (tag_map::iterator i = tags_.begin();
|
||||
i != tags_.end(); ++i ){
|
||||
i->second.printl(os,level+step,step);
|
||||
|
||||
for(tag_map::iterator i = tags_.begin(); i != tags_.end(); ++i) {
|
||||
i->second.printl(os, level + step, step);
|
||||
}
|
||||
for (link_map::iterator i = links_.begin();
|
||||
i != links_.end(); ++i ){
|
||||
os << s << "" << "[link]\n"
|
||||
<< s << "" << " name=\"" <<i->second << "\"\n"
|
||||
<< s << "" << "[/link]\n";
|
||||
|
||||
for(link_map::iterator i = links_.begin(); i != links_.end(); ++i) {
|
||||
os << s << ""
|
||||
<< "[link]\n"
|
||||
<< s << ""
|
||||
<< " name=\"" << i->second << "\"\n"
|
||||
<< s << ""
|
||||
<< "[/link]\n";
|
||||
}
|
||||
for (key_map::iterator i = keys_.begin();
|
||||
i != keys_.end(); ++i ){
|
||||
i->second.print(os,level+step);
|
||||
|
||||
for(key_map::iterator i = keys_.begin(); i != keys_.end(); ++i) {
|
||||
i->second.print(os, level + step);
|
||||
}
|
||||
os<< s << "[/tag]\n";
|
||||
|
||||
os << s << "[/tag]\n";
|
||||
}
|
||||
|
||||
class_tag * class_tag::find_tag(const std::string &fullpath,
|
||||
class_tag &root) {
|
||||
if (fullpath.empty()) return nullptr;
|
||||
std::string::size_type pos = fullpath.find('/');
|
||||
std::string name;
|
||||
std::string next_path;
|
||||
if (pos != std::string::npos) {
|
||||
name = fullpath.substr(0,pos);
|
||||
next_path = fullpath.substr(pos+1,fullpath.length());
|
||||
}else{
|
||||
name = fullpath;
|
||||
}
|
||||
class_tag* class_tag::find_tag(const std::string& fullpath, class_tag& root)
|
||||
{
|
||||
if(fullpath.empty()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
tag_map::iterator it_tags = tags_.find(name);
|
||||
if (it_tags != tags_.end()){
|
||||
if (next_path.empty()){
|
||||
return &(it_tags->second);
|
||||
}else{
|
||||
return it_tags->second.find_tag(next_path,root);
|
||||
}
|
||||
}
|
||||
link_map::iterator it_links = links_.find(name);
|
||||
if (it_links != links_.end()){
|
||||
return root.find_tag(it_links->second +"/" +next_path,root);
|
||||
}
|
||||
return nullptr;
|
||||
std::string::size_type pos = fullpath.find('/');
|
||||
std::string name;
|
||||
std::string next_path;
|
||||
|
||||
}
|
||||
// class_tag & class_tag::operator= (const class_tag& t){
|
||||
// if (&t != this){
|
||||
// name_ = t.name_;
|
||||
// min_ = t.min_;
|
||||
// max_ = t.max_;
|
||||
// super_ = t.super_;
|
||||
// tags_ = t.tags_;
|
||||
// keys_ = t.keys_;
|
||||
// links_ = t.links_;
|
||||
// }
|
||||
// return *this;
|
||||
// }
|
||||
if(pos != std::string::npos) {
|
||||
name = fullpath.substr(0, pos);
|
||||
next_path = fullpath.substr(pos + 1, fullpath.length());
|
||||
} else {
|
||||
name = fullpath;
|
||||
}
|
||||
|
||||
void class_tag::add_tag(const std::string &path, const class_tag &tag,
|
||||
class_tag &root){
|
||||
if ( path.empty() || path == "/" ){
|
||||
tag_map::iterator it_tags = tags_.find(name);
|
||||
if(it_tags != tags_.end()) {
|
||||
if(next_path.empty()) {
|
||||
return &(it_tags->second);
|
||||
} else {
|
||||
return it_tags->second.find_tag(next_path, root);
|
||||
}
|
||||
}
|
||||
|
||||
link_map::iterator it_links = links_.find(name);
|
||||
if(it_links != links_.end()) {
|
||||
return root.find_tag(it_links->second + "/" + next_path, root);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
#if 0
|
||||
class_tag& class_tag::operator=(const class_tag& t)
|
||||
{
|
||||
if(&t != this) {
|
||||
name_ = t.name_;
|
||||
min_ = t.min_;
|
||||
max_ = t.max_;
|
||||
super_ = t.super_;
|
||||
tags_ = t.tags_;
|
||||
keys_ = t.keys_;
|
||||
links_ = t.links_;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
void class_tag::add_tag(const std::string& path, const class_tag& tag, class_tag& root)
|
||||
{
|
||||
if(path.empty() || path == "/") {
|
||||
tag_map::iterator it = tags_.find(tag.name_);
|
||||
if (it == tags_.end()){
|
||||
|
||||
if(it == tags_.end()) {
|
||||
tags_.emplace(tag.name_, tag);
|
||||
}else{
|
||||
} else {
|
||||
it->second.set_min(tag.min_);
|
||||
it->second.set_max(tag.max_);
|
||||
it->second.add_tags(tag.tags_);
|
||||
it->second.add_keys(tag.keys_);
|
||||
it->second.add_links(tag.links_);
|
||||
}
|
||||
links_.erase (tag.get_name ());
|
||||
return ;
|
||||
}
|
||||
std::string::size_type pos = path.find('/');
|
||||
std::string name = path.substr(0,pos);
|
||||
std::string next_path = path.substr(pos+1,path.length());
|
||||
|
||||
link_map::const_iterator it_links= links_.find(name);
|
||||
if (it_links != links_.end()){
|
||||
root.add_tag(it_links->second + "/" + next_path,tag,root);
|
||||
links_.erase(tag.get_name());
|
||||
return;
|
||||
}
|
||||
|
||||
std::string::size_type pos = path.find('/');
|
||||
std::string name = path.substr(0, pos);
|
||||
std::string next_path = path.substr(pos + 1, path.length());
|
||||
|
||||
link_map::const_iterator it_links = links_.find(name);
|
||||
if(it_links != links_.end()) {
|
||||
root.add_tag(it_links->second + "/" + next_path, tag, root);
|
||||
}
|
||||
|
||||
tag_map::iterator it_tags = tags_.find(name);
|
||||
if (it_tags == tags_.end()){
|
||||
if(it_tags == tags_.end()) {
|
||||
class_tag subtag;
|
||||
subtag.set_name(name);
|
||||
subtag.add_tag(next_path,tag,root);
|
||||
subtag.add_tag(next_path, tag, root);
|
||||
tags_.emplace(name, subtag);
|
||||
return;
|
||||
}
|
||||
it_tags->second.add_tag(next_path,tag,root);
|
||||
|
||||
it_tags->second.add_tag(next_path, tag, root);
|
||||
}
|
||||
|
||||
void class_tag::append_super(const class_tag &tag,const std::string & path){
|
||||
void class_tag::append_super(const class_tag& tag, const std::string& path)
|
||||
{
|
||||
add_keys(tag.keys_);
|
||||
add_links(tag.links_);
|
||||
for (tag_map::const_iterator i = tag.tags_.begin();i!=tag.tags_.end();++i){
|
||||
|
||||
for(tag_map::const_iterator i = tag.tags_.begin(); i != tag.tags_.end(); ++i) {
|
||||
links_.erase(i->first);
|
||||
add_link(path + "/" + i->first);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void class_tag::expand(class_tag &root){
|
||||
if (! super_.empty()){
|
||||
class_tag * super_tag = root.find_tag(super_,root);
|
||||
if (super_tag){
|
||||
if (super_tag != this){
|
||||
void class_tag::expand(class_tag& root)
|
||||
{
|
||||
if(!super_.empty()) {
|
||||
class_tag* super_tag = root.find_tag(super_, root);
|
||||
if(super_tag) {
|
||||
if(super_tag != this) {
|
||||
super_tag->expand(root);
|
||||
append_super(*super_tag,super_);
|
||||
append_super(*super_tag, super_);
|
||||
super_.clear();
|
||||
}else{
|
||||
std::cerr << "the same" << super_tag->name_ <<"\n";
|
||||
} else {
|
||||
std::cerr << "the same" << super_tag->name_ << "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}//namespace schema_generator
|
||||
|
||||
} // namespace schema_validation
|
||||
|
|
|
@ -28,54 +28,76 @@
|
|||
|
||||
class config;
|
||||
|
||||
namespace schema_validation{
|
||||
namespace schema_validation
|
||||
{
|
||||
/**
|
||||
* class_key is used to save the information about one key.
|
||||
* Key has next info: name, type, default value or key is mandatory.
|
||||
*/
|
||||
class class_key{
|
||||
* class_key is used to save the information about one key.
|
||||
* Key has next info: name, type, default value or key is mandatory.
|
||||
*/
|
||||
class class_key
|
||||
{
|
||||
public:
|
||||
class_key():name_(""),type_(""),default_("\"\""),mandatory_(false)
|
||||
{ }
|
||||
class_key(const std::string & name,
|
||||
const std::string &type,
|
||||
const std::string &def="\"\"")
|
||||
class_key()
|
||||
: name_("")
|
||||
, type_("")
|
||||
, default_("\"\"")
|
||||
, mandatory_(false)
|
||||
{
|
||||
}
|
||||
|
||||
class_key(const std::string& name, const std::string& type, const std::string& def = "\"\"")
|
||||
: name_(name)
|
||||
, type_(type)
|
||||
, default_(def)
|
||||
, mandatory_(def.empty())
|
||||
{
|
||||
}
|
||||
|
||||
class_key(const config&);
|
||||
|
||||
const std::string & get_name() const{
|
||||
return name_ ;
|
||||
}
|
||||
const std::string & get_type() const{
|
||||
return type_ ;
|
||||
}
|
||||
const std::string & get_default() const{
|
||||
return default_;
|
||||
}
|
||||
bool is_mandatory () const{
|
||||
return mandatory_ ;
|
||||
const std::string& get_name() const
|
||||
{
|
||||
return name_;
|
||||
}
|
||||
|
||||
void set_name(const std::string& name){
|
||||
const std::string& get_type() const
|
||||
{
|
||||
return type_;
|
||||
}
|
||||
|
||||
const std::string& get_default() const
|
||||
{
|
||||
return default_;
|
||||
}
|
||||
|
||||
bool is_mandatory() const
|
||||
{
|
||||
return mandatory_;
|
||||
}
|
||||
|
||||
void set_name(const std::string& name)
|
||||
{
|
||||
name_ = name;
|
||||
}
|
||||
void set_type(const std::string& type){
|
||||
|
||||
void set_type(const std::string& type)
|
||||
{
|
||||
type_ = type;
|
||||
}
|
||||
void set_default(const std::string& def){
|
||||
|
||||
void set_default(const std::string& def)
|
||||
{
|
||||
default_ = def;
|
||||
if (def.empty()){
|
||||
if(def.empty()) {
|
||||
mandatory_ = true;
|
||||
}
|
||||
}
|
||||
void set_mandatory(bool mandatory){
|
||||
|
||||
void set_mandatory(bool mandatory)
|
||||
{
|
||||
mandatory_ = mandatory;
|
||||
}
|
||||
|
||||
/** is used to print key info
|
||||
* the format is next
|
||||
* [key]
|
||||
|
@ -84,65 +106,66 @@ public:
|
|||
* default="default"
|
||||
* mandatory="true/false"
|
||||
* [/key]
|
||||
*/
|
||||
void print(std::ostream& os,int level) const;
|
||||
|
||||
/**
|
||||
*Compares keys by name. Used in std::sort, i.e.
|
||||
*/
|
||||
bool operator < ( const class_key& k) const{
|
||||
void print(std::ostream& os, int level) const;
|
||||
|
||||
/** Compares keys by name. Used in std::sort, i.e. */
|
||||
bool operator<(const class_key& k) const
|
||||
{
|
||||
return (get_name() < k.get_name());
|
||||
}
|
||||
|
||||
private:
|
||||
/** Name of key*/
|
||||
/** Name of key. */
|
||||
std::string name_;
|
||||
/** Type of key*/
|
||||
|
||||
/** Type of key. */
|
||||
std::string type_;
|
||||
/** Default value*/
|
||||
|
||||
/** Default value. */
|
||||
std::string default_;
|
||||
/** Shows, if key is a mandatory key.*/
|
||||
|
||||
/** Shows, if key is a mandatory key. */
|
||||
bool mandatory_;
|
||||
};
|
||||
|
||||
/**
|
||||
* Stores information about tag.
|
||||
* Each tags is an element of great tag tree. This tree is close to filesystem:
|
||||
* you can use links and special include directory global/
|
||||
* Normally root is not mentioned in path.
|
||||
* Each tag has name, minimum and maximum occasions number,
|
||||
* and lists of subtags, keys and links.
|
||||
*/
|
||||
class class_tag{
|
||||
* Stores information about tag.
|
||||
* Each tags is an element of great tag tree. This tree is close to filesystem:
|
||||
* you can use links and special include directory global/
|
||||
* Normally root is not mentioned in path.
|
||||
* Each tag has name, minimum and maximum occasions number,
|
||||
* and lists of subtags, keys and links.
|
||||
*/
|
||||
class class_tag
|
||||
{
|
||||
public:
|
||||
typedef std::map<std::string,class_tag> tag_map;
|
||||
typedef std::pair<std::string,class_tag> tag_map_value;
|
||||
typedef std::map<std::string, class_tag> tag_map;
|
||||
typedef std::pair<std::string, class_tag> tag_map_value;
|
||||
|
||||
typedef std::map<std::string,class_key> key_map;
|
||||
typedef std::pair<std::string,class_key> key_map_value;
|
||||
typedef std::map<std::string, class_key> key_map;
|
||||
typedef std::pair<std::string, class_key> key_map_value;
|
||||
|
||||
typedef std::map<std::string,std::string> link_map;
|
||||
typedef std::pair<std::string,std::string> link_map_value;
|
||||
typedef std::map<std::string, std::string> link_map;
|
||||
typedef std::pair<std::string, std::string> link_map_value;
|
||||
|
||||
typedef key_map::iterator key_iterator;
|
||||
typedef std::pair<key_iterator,key_iterator> all_key_iterators;
|
||||
typedef std::pair<key_iterator, key_iterator> all_key_iterators;
|
||||
|
||||
typedef key_map::const_iterator const_key_iterator;
|
||||
typedef std::pair<const_key_iterator,const_key_iterator>
|
||||
all_const_key_iterators;
|
||||
typedef std::pair<const_key_iterator, const_key_iterator> all_const_key_iterators;
|
||||
|
||||
typedef tag_map::iterator tag_iterator;
|
||||
typedef std::pair<tag_iterator,tag_iterator> all_tag_iterators;
|
||||
typedef std::pair<tag_iterator, tag_iterator> all_tag_iterators;
|
||||
|
||||
typedef tag_map::const_iterator const_tag_iterator;
|
||||
typedef std::pair<const_tag_iterator,const_tag_iterator>
|
||||
all_const_tag_iterators;
|
||||
typedef std::pair<const_tag_iterator, const_tag_iterator> all_const_tag_iterators;
|
||||
|
||||
typedef link_map::iterator link_iterator;
|
||||
typedef std::pair<link_iterator,link_iterator> all_link_iterators;
|
||||
typedef std::pair<link_iterator, link_iterator> all_link_iterators;
|
||||
|
||||
typedef link_map::const_iterator const_link_iterator;
|
||||
typedef std::pair<const_link_iterator,const_link_iterator>
|
||||
all_const_link_iterators;
|
||||
typedef std::pair<const_link_iterator, const_link_iterator> all_const_link_iterators;
|
||||
|
||||
class_tag()
|
||||
: name_("")
|
||||
|
@ -155,11 +178,7 @@ public:
|
|||
{
|
||||
}
|
||||
|
||||
class_tag(const std::string & name,
|
||||
int min,
|
||||
int max,
|
||||
const std::string & super=""
|
||||
)
|
||||
class_tag(const std::string& name, int min, int max, const std::string& super = "")
|
||||
: name_(name)
|
||||
, min_(min)
|
||||
, max_(max)
|
||||
|
@ -169,8 +188,12 @@ public:
|
|||
, links_()
|
||||
{
|
||||
}
|
||||
|
||||
class_tag(const config&);
|
||||
~class_tag(){ }
|
||||
|
||||
~class_tag()
|
||||
{
|
||||
}
|
||||
|
||||
/** Prints information about tag to outputstream, recursively
|
||||
* is used to print tag info
|
||||
|
@ -182,56 +205,81 @@ public:
|
|||
* min="min"
|
||||
* max="max"
|
||||
* [/tag]
|
||||
*/
|
||||
*/
|
||||
void print(std::ostream& os);
|
||||
|
||||
const std::string & get_name() const{
|
||||
return name_ ;
|
||||
}
|
||||
int get_min() const{
|
||||
return min_;
|
||||
}
|
||||
int get_max() const{
|
||||
return max_;
|
||||
}
|
||||
const std::string & get_super() const{
|
||||
return super_ ;
|
||||
}
|
||||
bool is_extension() const{
|
||||
return ! super_.empty();
|
||||
const std::string& get_name() const
|
||||
{
|
||||
return name_;
|
||||
}
|
||||
|
||||
void set_name(const std::string& name){
|
||||
int get_min() const
|
||||
{
|
||||
return min_;
|
||||
}
|
||||
|
||||
int get_max() const
|
||||
{
|
||||
return max_;
|
||||
}
|
||||
|
||||
const std::string& get_super() const
|
||||
{
|
||||
return super_;
|
||||
}
|
||||
|
||||
bool is_extension() const
|
||||
{
|
||||
return !super_.empty();
|
||||
}
|
||||
|
||||
void set_name(const std::string& name)
|
||||
{
|
||||
name_ = name;
|
||||
}
|
||||
void set_min(int o){
|
||||
|
||||
void set_min(int o)
|
||||
{
|
||||
min_ = o;
|
||||
}
|
||||
void set_max(int o){
|
||||
|
||||
void set_max(int o)
|
||||
{
|
||||
max_ = o;
|
||||
}
|
||||
void set_min(const std::string& s){
|
||||
|
||||
void set_min(const std::string& s)
|
||||
{
|
||||
std::istringstream i(s);
|
||||
if (!(i >> min_)){
|
||||
if(!(i >> min_)) {
|
||||
min_ = 0;
|
||||
}
|
||||
}
|
||||
void set_max(const std::string& s){
|
||||
|
||||
void set_max(const std::string& s)
|
||||
{
|
||||
std::istringstream i(s);
|
||||
if (!(i >> max_)){
|
||||
if(!(i >> max_)) {
|
||||
max_ = 0;
|
||||
}
|
||||
}
|
||||
void set_super(const std::string& s){
|
||||
super_= s;
|
||||
|
||||
void set_super(const std::string& s)
|
||||
{
|
||||
super_ = s;
|
||||
}
|
||||
void add_key(const class_key& new_key){
|
||||
|
||||
void add_key(const class_key& new_key)
|
||||
{
|
||||
keys_.emplace(new_key.get_name(), new_key);
|
||||
}
|
||||
void add_tag(const class_tag& new_tag){
|
||||
|
||||
void add_tag(const class_tag& new_tag)
|
||||
{
|
||||
tags_.emplace(new_tag.name_, new_tag);
|
||||
}
|
||||
void add_link(const std::string & link);
|
||||
|
||||
void add_link(const std::string& link);
|
||||
|
||||
/**
|
||||
* Tags are usually organized in tree.
|
||||
|
@ -242,50 +290,55 @@ public:
|
|||
* Path is getting shotter and shoter with each call.
|
||||
* Path should look like tag1/tag2/parent/ Slash at end is mandatory.
|
||||
*/
|
||||
void add_tag (const std::string & path,const class_tag & tag,
|
||||
class_tag &root);
|
||||
void add_tag(const std::string& path, const class_tag& tag, class_tag& root);
|
||||
|
||||
bool operator < ( const class_tag& t) const{
|
||||
bool operator<(const class_tag& t) const
|
||||
{
|
||||
return name_ < t.name_;
|
||||
}
|
||||
bool operator == (const class_tag & other) const {
|
||||
|
||||
bool operator==(const class_tag& other) const
|
||||
{
|
||||
return name_ == other.name_;
|
||||
}
|
||||
/**
|
||||
* Returns pointer to child key
|
||||
*/
|
||||
const class_key * find_key(const std::string & name) const;
|
||||
/**
|
||||
* Returns pointer to child link
|
||||
*/
|
||||
const std::string * find_link(const std::string & name) const;
|
||||
|
||||
/** Returns pointer to child key. */
|
||||
const class_key* find_key(const std::string& name) const;
|
||||
|
||||
/** Returns pointer to child link. */
|
||||
const std::string* find_link(const std::string& name) const;
|
||||
|
||||
/**
|
||||
* Returns pointer to tag using full path to it.
|
||||
* Also work with links
|
||||
*/
|
||||
const class_tag * find_tag(const std::string & fullpath,
|
||||
const class_tag & root) const;
|
||||
/**
|
||||
* Calls the expansion on each child
|
||||
*/
|
||||
void expand_all(class_tag &root);
|
||||
const class_tag* find_tag(const std::string& fullpath, const class_tag& root) const;
|
||||
|
||||
all_const_tag_iterators tags() const{
|
||||
return all_const_tag_iterators(tags_.begin(),tags_.end());
|
||||
}
|
||||
all_const_key_iterators keys() const{
|
||||
return all_const_key_iterators(keys_.begin(),keys_.end());
|
||||
}
|
||||
all_const_link_iterators links() const{
|
||||
return all_const_link_iterators(links_.begin(),links_.end());
|
||||
/** Calls the expansion on each child. */
|
||||
void expand_all(class_tag& root);
|
||||
|
||||
all_const_tag_iterators tags() const
|
||||
{
|
||||
return all_const_tag_iterators(tags_.begin(), tags_.end());
|
||||
}
|
||||
|
||||
void remove_key_by_name(const std::string &name){
|
||||
keys_.erase (name);
|
||||
all_const_key_iterators keys() const
|
||||
{
|
||||
return all_const_key_iterators(keys_.begin(), keys_.end());
|
||||
}
|
||||
|
||||
all_const_link_iterators links() const
|
||||
{
|
||||
return all_const_link_iterators(links_.begin(), links_.end());
|
||||
}
|
||||
|
||||
void remove_key_by_name(const std::string& name)
|
||||
{
|
||||
keys_.erase(name);
|
||||
}
|
||||
|
||||
/** Removes all keys with this type. Works recursively */
|
||||
void remove_keys_by_type(const std::string &type);
|
||||
void remove_keys_by_type(const std::string& type);
|
||||
|
||||
#ifdef _MSC_VER
|
||||
// MSVC throws an error if this method is private.
|
||||
|
@ -293,19 +346,21 @@ public:
|
|||
// error C2248: 'schema_validation::class_tag::find_tag' : cannot
|
||||
// access private member declared in class 'schema_validation::class_tag'
|
||||
|
||||
class_tag * find_tag(const std::string & fullpath,
|
||||
class_tag & root) ;
|
||||
class_tag* find_tag(const std::string& fullpath, class_tag& root);
|
||||
#endif
|
||||
|
||||
// class_tag & operator= (const class_tag&);
|
||||
// class_tag & operator= (const class_tag&);
|
||||
|
||||
private:
|
||||
/** name of tag*/
|
||||
/** name of tag. */
|
||||
std::string name_;
|
||||
/** number of minimum occasions*/
|
||||
|
||||
/** number of minimum occasions. */
|
||||
int min_;
|
||||
/** number of maximum occasions*/
|
||||
|
||||
/** number of maximum occasions. */
|
||||
int max_;
|
||||
|
||||
/**
|
||||
* name of tag to extend "super-tag"
|
||||
* Extension is smth like inheritance and is used in case
|
||||
|
@ -314,12 +369,16 @@ private:
|
|||
* so just linking that tag wouldn't help at all.
|
||||
*/
|
||||
std::string super_;
|
||||
|
||||
/** children tags*/
|
||||
tag_map tags_;
|
||||
|
||||
/** keys*/
|
||||
key_map keys_;
|
||||
|
||||
/** links to possible children. */
|
||||
link_map links_;
|
||||
|
||||
/**
|
||||
* the same as class_tag::print(std::ostream&)
|
||||
* but indents different levels with step space.
|
||||
|
@ -327,31 +386,32 @@ private:
|
|||
* @param level current level of indentation
|
||||
* @param step step to next indent
|
||||
*/
|
||||
void printl(std::ostream &os,int level, int step = 4);
|
||||
void printl(std::ostream& os, int level, int step = 4);
|
||||
|
||||
#ifndef _MSC_VER
|
||||
// this is complementary with the above #ifdef for the MSVC error
|
||||
class_tag * find_tag(const std::string & fullpath,
|
||||
class_tag & root) ;
|
||||
class_tag* find_tag(const std::string& fullpath, class_tag& root);
|
||||
#endif
|
||||
|
||||
void add_tags (const tag_map & list){
|
||||
tags_.insert(list.begin(),list.end());
|
||||
void add_tags(const tag_map& list)
|
||||
{
|
||||
tags_.insert(list.begin(), list.end());
|
||||
}
|
||||
void add_keys (const key_map & list){
|
||||
keys_.insert(list.begin(),list.end());
|
||||
}
|
||||
void add_links (const link_map & list){
|
||||
links_.insert(list.begin(),list.end());
|
||||
}
|
||||
/**
|
||||
* Copies tags, keys and links of tag to this
|
||||
*/
|
||||
void append_super(const class_tag & tag,const std::string & super);
|
||||
/**
|
||||
* Expands all "super" copying their data to this.
|
||||
*/
|
||||
void expand(class_tag & root);
|
||||
};
|
||||
|
||||
void add_keys(const key_map& list)
|
||||
{
|
||||
keys_.insert(list.begin(), list.end());
|
||||
}
|
||||
|
||||
void add_links(const link_map& list)
|
||||
{
|
||||
links_.insert(list.begin(), list.end());
|
||||
}
|
||||
|
||||
/** Copies tags, keys and links of tag to this. */
|
||||
void append_super(const class_tag& tag, const std::string& super);
|
||||
|
||||
/** Expands all "super" copying their data to this. */
|
||||
void expand(class_tag& root);
|
||||
};
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue