Add initial version of the schema validator.
Committing Sytyi's patch.
This commit is contained in:
parent
da07123866
commit
3c5b34d214
9 changed files with 1472 additions and 3 deletions
|
@ -185,7 +185,7 @@ if(MSVC)
|
|||
SOURCE_GROUP("src tests gui" REGULAR_EXPRESSION "tests/gui/.*")
|
||||
SOURCE_GROUP("src tests utils" REGULAR_EXPRESSION "tests/utils/.*")
|
||||
SOURCE_GROUP("src tools" REGULAR_EXPRESSION "tools/.*")
|
||||
SOURCE_GROUP("src tools" REGULAR_EXPRESSION "tools/.*")
|
||||
SOURCE_GROUP("src tools schema" REGULAR_EXPRESSION "tools/schema/.*")
|
||||
SOURCE_GROUP("src whiteboard" REGULAR_EXPRESSION "whiteboard/.*")
|
||||
|
||||
endif(MSVC)
|
||||
|
@ -794,8 +794,21 @@ set_target_properties(cutter PROPERTIES OUTPUT_NAME ${BINARY_PREFIX}cutter${BINA
|
|||
|
||||
install(TARGETS cutter DESTINATION ${BINDIR})
|
||||
|
||||
endif(ENABLE_TOOLS)
|
||||
set(schema_generator_SRC
|
||||
tools/schema/schema_generator.cpp
|
||||
tools/schema/sourceparser.cpp
|
||||
tools/schema/error_container.cpp
|
||||
tools/schema/tag.cpp
|
||||
filesystem.cpp
|
||||
loadscreen_empty.cpp
|
||||
)
|
||||
|
||||
add_executable(schema_generator ${schema_generator_SRC})
|
||||
target_link_libraries(schema_generator wesnoth-core ${tools-external-libs} ${Boost_REGEX_LIBRARY})
|
||||
set_target_properties(schema_generator PROPERTIES OUTPUT_NAME ${BINARY_PREFIX}schema_generator${BINARY_SUFFIX})
|
||||
|
||||
install(TARGETS schema_generator DESTINATION ${BINDIR})
|
||||
endif(ENABLE_TOOLS)
|
||||
########### Unit tests ###############
|
||||
|
||||
if(ENABLE_TESTS)
|
||||
|
|
74
src/tools/schema/error_container.cpp
Normal file
74
src/tools/schema/error_container.cpp
Normal file
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
Copyright (C) 2011 - 2011 by Sytyi Nick <nsytyi@gmail.com>
|
||||
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY.
|
||||
|
||||
See the COPYING file for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* This file contains implementation of error_container.hpp.
|
||||
*/
|
||||
|
||||
#include "./tools/schema/error_container.hpp"
|
||||
|
||||
namespace schema_generator{
|
||||
|
||||
void class_error_container::add_simple_error(const std::string & message){
|
||||
list_.push_back(message);
|
||||
}
|
||||
|
||||
void class_error_container::add_read_error(const std::string & file,int line){
|
||||
std::ostringstream s;
|
||||
s << file << ":" << line <<": Read error at line "<< line <<".\n";
|
||||
list_.push_back(s.str());
|
||||
}
|
||||
|
||||
void class_error_container::add_opened_entity_error(
|
||||
const std::string & file,int line,const std::string & name){
|
||||
std::ostringstream s;
|
||||
s << file << ":" << line <<": Entity "<< name
|
||||
<<" is opened but not closed.\n";
|
||||
list_.push_back(s.str());
|
||||
}
|
||||
|
||||
void class_error_container::add_unopened_entity_error(
|
||||
const std::string & file,int line,const std::string & name){
|
||||
std::ostringstream s;
|
||||
s << file << ":" << line <<": Entity "<< name
|
||||
<<" is being closed but was not opened.\n";
|
||||
list_.push_back(s.str());
|
||||
}
|
||||
|
||||
void class_error_container::add_second_parent_error(
|
||||
const std::string & file,int line,const std::string & first,
|
||||
const std::string & second){
|
||||
std::ostringstream s;
|
||||
s << file << ":" << line <<": Parent "<< first <<" is closed due to parent"
|
||||
<< second << "is opened here. \n";
|
||||
list_.push_back(s.str());
|
||||
}
|
||||
|
||||
void class_error_container::add_orphan_error(const std::string & file,int line,
|
||||
const std::string & name){
|
||||
std::ostringstream s;
|
||||
s << file << ":" << line <<": Tag "<< name <<" has no parent \n";
|
||||
list_.push_back(s.str());
|
||||
}
|
||||
|
||||
void class_error_container::print_errors(std::ostream & s) const{
|
||||
for (unsigned int i = 0; i< list_.size(); i++){
|
||||
s << list_.at(i);
|
||||
}
|
||||
}
|
||||
void class_error_container::sort(){
|
||||
std::sort(list_.begin(),list_.end());
|
||||
}
|
||||
}
|
113
src/tools/schema/error_container.hpp
Normal file
113
src/tools/schema/error_container.hpp
Normal file
|
@ -0,0 +1,113 @@
|
|||
/*
|
||||
Copyright (C) 2011 - 2011 by Sytyi Nick <nsytyi@gmail.com>
|
||||
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY.
|
||||
|
||||
See the COPYING file for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* This file contains object "error_container", which are used to store error
|
||||
* messages while annotation parsing.
|
||||
* Also the another part of his job is to create GCC:styled error messages.
|
||||
*/
|
||||
|
||||
#ifndef TOOLS_ERROR_CONTAINER_HPP_INCLUDED
|
||||
#define TOOLS_ERROR_CONTAINER_HPP_INCLUDED
|
||||
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <queue>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
namespace schema_generator{
|
||||
/**
|
||||
* Container of errors, which are generated while schema generator tool
|
||||
* is parsing source files.
|
||||
* These errors are collected here, to be print on screen after parsing.
|
||||
*/
|
||||
class class_error_container{
|
||||
public:
|
||||
class_error_container(){}
|
||||
|
||||
/**
|
||||
*Puts simple error message in container
|
||||
* @param message Message to print.
|
||||
*/
|
||||
void add_simple_error(const std::string & message);
|
||||
|
||||
/**
|
||||
* Generate and put GCC-style error message about error read file error
|
||||
* @param file Filename
|
||||
* @param line Number of line with error
|
||||
*/
|
||||
void add_read_error(const std::string & file,int line);
|
||||
|
||||
/**
|
||||
* Generate and put GCC-style error message about annotation block
|
||||
* somebody missed to close
|
||||
* @param file Filename
|
||||
* @param line Number of line with error
|
||||
* @param name Name of open block
|
||||
*/
|
||||
void add_opened_entity_error(const std::string & file,int line,
|
||||
const std::string & name);
|
||||
|
||||
/**
|
||||
* Generate and put GCC-style error message about closing block
|
||||
* that wasn't opened
|
||||
* @param file Filename
|
||||
* @param line Number of line with error
|
||||
* @param name of block
|
||||
*/
|
||||
void add_unopened_entity_error(const std::string & file,int line,
|
||||
const std::string & name);
|
||||
|
||||
/**
|
||||
* Generate and put GCC-style error message about opening parent block
|
||||
* before before closing previous block
|
||||
* @param file Filename
|
||||
* @param line Number with error
|
||||
* @param first Name of open parent
|
||||
* @param second Name of parent is opening
|
||||
*/
|
||||
void add_second_parent_error(
|
||||
const std::string & file,int line, const std::string & first,
|
||||
const std::string & second);
|
||||
|
||||
/**
|
||||
* Generate and put GCC-style error message about tag without parent
|
||||
* @param file Filename
|
||||
* @param line Number with error
|
||||
* @param name Name of tag
|
||||
*/
|
||||
void add_orphan_error(const std::string & file,int line,
|
||||
const std::string & name);
|
||||
|
||||
/**
|
||||
* Prints errors to output stream
|
||||
* @param s Output
|
||||
*/
|
||||
void print_errors(std::ostream & s) const;
|
||||
void sort();
|
||||
|
||||
/** Checks, if container is empty.*/
|
||||
bool is_empty() const {
|
||||
return list_.empty();
|
||||
}
|
||||
private:
|
||||
/** Container to store error messages.*/
|
||||
std::vector<std::string> list_;
|
||||
};
|
||||
|
||||
|
||||
}//namespace schema_generator
|
||||
#endif // TOOLS_ERROR_CONTAINER_HPP_INCLUDED
|
170
src/tools/schema/schema_generator.cpp
Normal file
170
src/tools/schema/schema_generator.cpp
Normal file
|
@ -0,0 +1,170 @@
|
|||
/*
|
||||
Copyright (C) 2011 - 2011 by Sytyi Nick <nsytyi@gmail.com>
|
||||
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY.
|
||||
|
||||
See the COPYING file for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* This file parses the input parameters, prepares a list of files to be parsed
|
||||
* and calls parser for each of them.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "tools/schema/sourceparser.hpp"
|
||||
|
||||
#include "filesystem.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
|
||||
std::string version = "0.6.0";
|
||||
|
||||
using namespace schema_generator;
|
||||
/**
|
||||
* Parses the command line.
|
||||
* @retval 0 Everything's OK!
|
||||
* @retval 1 Errors found. User decided to exit.
|
||||
* @retval 2 No input files found. Please, check your input directory.
|
||||
* @retval 3 Output file for schema cannot be created.
|
||||
* @retval 4 Output file for regex list cannot be created.
|
||||
*/
|
||||
int main(int argc, char *argv[]){
|
||||
std::string input_dir = "./src/gui/";
|
||||
std::string output_file = "./data/gui/schema.cfg";
|
||||
std::string regex_file = "./utils/regex_list.txt";
|
||||
for (int arg = 1; arg != argc; ++arg) {
|
||||
const std::string val(argv[arg]);
|
||||
if (val.empty()) {
|
||||
continue;
|
||||
}
|
||||
else if ((val == "--src-dir" || val == "-s") && arg+1 != argc) {
|
||||
input_dir = argv[++arg];
|
||||
}
|
||||
else if ((val == "--output" || val == "-o") && arg+1 != argc) {
|
||||
output_file = argv[++arg];
|
||||
}
|
||||
else if ((val == "--regex" || val == "-r") ) {
|
||||
if (arg+1 != argc){
|
||||
regex_file = argv[++arg];
|
||||
}
|
||||
std::fstream f;
|
||||
f.open(regex_file.c_str(),std::ios::out|std::ios::trunc);
|
||||
if (f.fail()){
|
||||
return 4;
|
||||
}
|
||||
test_regex(f);
|
||||
f.close();
|
||||
return 0;
|
||||
}
|
||||
else if (val == "--help" || val == "-h") {
|
||||
std::cout << "usage: " << argv[0]
|
||||
<< " [-rhV] [-i input_dir] [-o output_file]\n"
|
||||
<< " -r, --regex <regex_file>\t"
|
||||
<< "List of used regexes.\n"
|
||||
<< " -h, --help\t\t\t"
|
||||
<< "Shows this usage message.\n"
|
||||
<< " -s, --src-dir <input_dir>\t"
|
||||
<<"Select the input directory.\n"
|
||||
<< " -o, --output <output_dir>\t"
|
||||
<<"Select the input directory.\n"
|
||||
<< " -V, --version\t"
|
||||
<< "Returns the version of schema generator tool\n";
|
||||
return 0;
|
||||
} else if (val == "--version" || val == "-V") {
|
||||
std::cout << "Battle for Wesnoth schema generator tool, version "
|
||||
<< version << "\n";
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (! file_exists(input_dir)){
|
||||
return 2;
|
||||
}
|
||||
|
||||
std::vector<std::string> files;
|
||||
std::vector<std::string> dirs;
|
||||
|
||||
if (is_directory(input_dir)){
|
||||
get_files_in_dir(input_dir, &files, &dirs, ENTIRE_FILE_PATH);
|
||||
|
||||
if (files.empty() && dirs.empty()){
|
||||
std::cout << "Some problem with input directory "
|
||||
<< input_dir << "\n"
|
||||
<< "No files found\n";
|
||||
return 2;
|
||||
}
|
||||
/** Getting full list of files recursively.*/
|
||||
while (!dirs.empty()){
|
||||
std::string temp_dir = dirs.back();
|
||||
dirs.pop_back();
|
||||
get_files_in_dir(temp_dir, &files, &dirs, ENTIRE_FILE_PATH);
|
||||
}
|
||||
}else{
|
||||
files.push_back(input_dir);
|
||||
}
|
||||
class_source_parser parser;
|
||||
parser.set_output(output_file);
|
||||
std::vector<std::string>::iterator i = files.begin();
|
||||
|
||||
|
||||
for (;i != files.end(); ++i){
|
||||
|
||||
if (file_name((*i)).find(".cpp")!=std::string::npos){
|
||||
parser.set_input((*i));
|
||||
parser.parse_source();
|
||||
continue;
|
||||
}
|
||||
if (file_name((*i)).find(".hpp")!=std::string::npos){
|
||||
parser.set_input((*i));
|
||||
parser.parse_source();
|
||||
}
|
||||
}
|
||||
|
||||
// check errors
|
||||
if (! parser.see_errors().is_empty()) {
|
||||
/**
|
||||
* Let the user decide whether error are great or just misprints.
|
||||
* If any error found, waits for a Yy or Nn to continue or not.
|
||||
*/
|
||||
std::cout << "There are some errors\n";
|
||||
parser.see_errors().print_errors(std::cout);
|
||||
// Take user response
|
||||
char c;
|
||||
std::cout << "Continue with errors? Y/N ";
|
||||
while (true) {
|
||||
std::cin.get(c);
|
||||
const char *r = strchr("yYnN",c);
|
||||
if (r == NULL){
|
||||
std::cout << "Please, choose your answer " << std::endl;
|
||||
continue;
|
||||
}
|
||||
if (c == 'n' || c=='N'){
|
||||
std::cout << "I'll take that as a NO" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
if (c == 'y' || c=='Y'){
|
||||
std::cout << "I'll take that as a Yes" << std::endl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// save schema information
|
||||
if ( ! parser.save_schema()){
|
||||
return 4;
|
||||
}
|
||||
return 0;
|
||||
}
|
501
src/tools/schema/sourceparser.cpp
Normal file
501
src/tools/schema/sourceparser.cpp
Normal file
|
@ -0,0 +1,501 @@
|
|||
/*
|
||||
Copyright (C) 2011 - 2011 by Sytyi Nick <nsytyi@gmail.com>
|
||||
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY.
|
||||
|
||||
See the COPYING file for more details.
|
||||
*/
|
||||
/**
|
||||
* @file
|
||||
* This file contains implementation of sourceparser.cpp.
|
||||
*/
|
||||
|
||||
#include "./tools/schema/sourceparser.hpp"
|
||||
|
||||
#include "boost/regex.hpp"
|
||||
|
||||
namespace schema_generator{
|
||||
/** Little parts of regex templates used to parse Wml annoations.
|
||||
*For details, look http://wiki.wesnoth.org/WML_Annotation_Format , please
|
||||
*/
|
||||
/** line is valid*/
|
||||
const std::string valid_ = "^\\s*\\*\\s*";
|
||||
/** begining of wiki block*/
|
||||
const std::string wiki_ ="^\\s*/\\*(?:WIKI|SCHEMA)";
|
||||
/** whitespace is possible*/
|
||||
const std::string space_ ="\\s*";
|
||||
/** sigh "="*/
|
||||
const std::string equals_ ="=";
|
||||
/** non-mandatory sign "*/
|
||||
const std::string quote_ ="\"?";
|
||||
/** begining of the block.*/
|
||||
const std::string block_begin_="@begin" ;
|
||||
/** end of block*/
|
||||
const std::string block_end_ ="@end";
|
||||
/** allow directive*/
|
||||
const std::string allow_="@allow";
|
||||
/** sign "{" - curly bracket*/
|
||||
const std::string property_open_="\\{";
|
||||
/** sign "}" - another curly bracket*/
|
||||
const std::string property_close_= "\\}";
|
||||
/** type of possible name identificator*/
|
||||
const std::string name_type_= "[a-z][a-zA-Z0-9_-]*" ;
|
||||
/** type of possible parent indentificator*/
|
||||
const std::string parent_type_= "/|(?:[a-z][a-zA-Z0-9_-]*/)+";
|
||||
/** type of possible link indentificator*/
|
||||
const std::string link_type_="(?:[a-z][a-zA-Z0-9_-]*/)*(?:[a-z][a-zA-Z0-9_-]*)";
|
||||
/** template to number regex*/
|
||||
const std::string number_="\\d*";
|
||||
/** sign "-" - hyphen-minus used to set sign of signed integer*/
|
||||
const std::string sign_="-?";
|
||||
|
||||
/**
|
||||
* end of line + possible various character before.
|
||||
* Used to close template. ".*" is used cause I dont want to get error
|
||||
* every misprint whitespace
|
||||
* after annotation element
|
||||
*/
|
||||
const std::string eol_=".*$";
|
||||
|
||||
/** Private function to surround an argument with brackets.
|
||||
* This allows substitutions :-)
|
||||
*/
|
||||
std::string sub (const std::string & s){
|
||||
return "(" + s + ")";
|
||||
}
|
||||
|
||||
/** Private function to surround argument with not mandatory quotes.
|
||||
* Is used when creating properties
|
||||
*/
|
||||
std::string quote(const std::string & s){
|
||||
return quote_ + s + quote_ ;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a property template
|
||||
* @param name Name of property
|
||||
* @param value Type of property value
|
||||
* If value is empty creates simple property like {table}
|
||||
* Else creates a named property like {name="[name_type_template]"}
|
||||
*/
|
||||
std::string property(const std::string & name, const std::string & value = ""){
|
||||
if (value == ""){
|
||||
return property_open_ + name + property_close_;
|
||||
}
|
||||
return property_open_ + name + equals_ + quote(value) + property_close_;
|
||||
}
|
||||
|
||||
|
||||
const std::string & get_valid() {
|
||||
return valid_;
|
||||
}
|
||||
|
||||
const std::string & get_wiki() {
|
||||
static std::string wiki = wiki_ + eol_;
|
||||
return wiki;
|
||||
}
|
||||
|
||||
const std::string & get_parent_begin() {
|
||||
static std::string parent_begin = valid_ + block_begin_
|
||||
+ property("parent")
|
||||
+ property("name",sub(parent_type_))
|
||||
+ eol_;
|
||||
return parent_begin;
|
||||
}
|
||||
|
||||
const std::string & get_parent_end() {
|
||||
static std::string parent_end = valid_ + block_end_ + property("parent")
|
||||
+ property("name",sub(parent_type_))+ eol_;
|
||||
return parent_end;
|
||||
}
|
||||
|
||||
const std::string & get_tag_begin() {
|
||||
static std::string tag_begin = valid_ + block_begin_ + property("tag")
|
||||
+ property("name",sub(name_type_))
|
||||
+ property("min",sub(number_))
|
||||
+ property("max",sub(sign_ + number_))
|
||||
+ sub(property("super",sub(link_type_)))
|
||||
+"?" + eol_;
|
||||
/* sub(property("super"),sub(link_type))+"?"
|
||||
* property super is not mandatory
|
||||
*/
|
||||
return tag_begin;
|
||||
}
|
||||
|
||||
|
||||
const std::string & get_tag_end() {
|
||||
static std::string tag_end = valid_ + block_end_ + property("tag")
|
||||
+ property("name",sub(name_type_)) + eol_;
|
||||
return tag_end;
|
||||
}
|
||||
|
||||
|
||||
const std::string & get_allow_link(){
|
||||
static std::string allow_link = valid_ + allow_ + property("link")
|
||||
+property("name",sub(link_type_)) + eol_;
|
||||
return allow_link;
|
||||
}
|
||||
|
||||
const std::string & get_allow_global(){
|
||||
static std::string global_link = valid_ + allow_ + property("global")
|
||||
+property("name",sub(name_type_)) + eol_;
|
||||
return global_link;
|
||||
}
|
||||
|
||||
|
||||
const std::string & get_table_key_begin() {
|
||||
static std::string keys_begin = valid_ + block_begin_ + property("table")
|
||||
+ property("config")+ eol_;
|
||||
return keys_begin;
|
||||
}
|
||||
|
||||
const std::string & get_table_end() {
|
||||
static std::string table_end = valid_ + block_end_ + property("table")
|
||||
+ eol_;
|
||||
return table_end;
|
||||
}
|
||||
|
||||
|
||||
const std::string & get_key_value(){
|
||||
static std::string key_value = valid_ + sub("[a-zA-z][a-zA-Z\\d_+-]*")
|
||||
+ "\\s*&\\s*"+sub("[a-z][a-z_]*")
|
||||
+"\\s*&\\s?"+ sub(quote("[a-zA-Z._0-9+-]*"))
|
||||
+"\\s&"+ eol_;
|
||||
return key_value;
|
||||
}
|
||||
|
||||
void test_regex( std::ostream & f ){
|
||||
f << get_valid() << "\n"
|
||||
<< get_wiki() << "\n"
|
||||
<< get_parent_begin() << "\n"
|
||||
<< get_parent_end() << "\n"
|
||||
<< get_tag_begin() << "\n"
|
||||
<< get_tag_end() << "\n"
|
||||
<< get_allow_link() << "\n"
|
||||
<< get_allow_global() << "\n"
|
||||
<< get_table_key_begin() << "\n"
|
||||
<< get_table_end() << "\n"
|
||||
<< get_key_value() << std::endl;
|
||||
}
|
||||
|
||||
bool class_source_parser::save_schema(){
|
||||
std::fstream out;
|
||||
if (output_.empty()){
|
||||
return false;
|
||||
}
|
||||
out.open(output_.c_str(),std::ios::out|std::ios::trunc);
|
||||
if (out.fail()){
|
||||
errors_.add_simple_error("Can not open file "+output_+
|
||||
"\n Output woulfd not be stored\n");
|
||||
return false;
|
||||
}
|
||||
out << "[wml_schema]\n";
|
||||
root_.print(out);
|
||||
out << "[/wml_schema]\n";
|
||||
out.close();
|
||||
return true; // @TODO add error support
|
||||
}
|
||||
|
||||
|
||||
bool class_source_parser::getline(std::string &s){
|
||||
if (f_.fail()){
|
||||
errors_.add_read_error(input_,line_);
|
||||
return false;
|
||||
}
|
||||
std::getline(f_,s);
|
||||
line_ ++;
|
||||
if (! f_.eof()){
|
||||
if (f_.fail()){
|
||||
errors_.add_read_error(input_,line_);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// call without arg when you want to closethem all
|
||||
void class_source_parser::add_open_tag_error(int i = INT_MAX){
|
||||
std::vector<class_tag>::iterator it;
|
||||
for (it = current_.begin(); it != current_.end() && i > 0; ++it){
|
||||
errors_.add_opened_entity_error(input_,line_,it->get_name());
|
||||
--i;
|
||||
}
|
||||
}
|
||||
// call without arg when you want to closethem all
|
||||
void class_source_parser::close_opened_tags(int i = INT_MAX){
|
||||
if (current_.empty()){
|
||||
return;
|
||||
}
|
||||
while (current_.size() > 1){
|
||||
if (i==0){
|
||||
return;
|
||||
}
|
||||
class_tag tag (current_.back());
|
||||
current_.pop_back();
|
||||
current_.back().add_tag(tag);
|
||||
i--;
|
||||
}
|
||||
if (i==0){
|
||||
return;
|
||||
}
|
||||
//adding to parent
|
||||
if (parent_name_.empty()) {
|
||||
orphan_tags_.push_back(current_.back());
|
||||
errors_.add_orphan_error(input_,line_,current_.back().get_name());
|
||||
}else{
|
||||
std::string path = parent_name_;
|
||||
do {
|
||||
path = root_.add_tag(path,current_.back());
|
||||
//std::cout << path;
|
||||
}while (! path.empty());
|
||||
}
|
||||
current_.pop_back();
|
||||
}
|
||||
|
||||
|
||||
bool class_source_parser::parse_source(){
|
||||
if (input_.empty()){
|
||||
errors_.add_simple_error("File was not defined\n");
|
||||
// Use to hack sorting errors.
|
||||
// Item with will be at the end of error list.
|
||||
return false;
|
||||
}
|
||||
f_.open(input_.c_str(),std::ios::in);
|
||||
if (f_.fail()){
|
||||
errors_.add_simple_error("File "+input_ + " can not be opened\n");
|
||||
return false;
|
||||
}
|
||||
line_ = 0;
|
||||
bool result = true;
|
||||
while (!f_.eof()){
|
||||
std::string line;
|
||||
if (! getline(line) ) {
|
||||
close_opened_tags();
|
||||
parent_name_.clear();
|
||||
return false;
|
||||
} // is used to avoid exceptions.
|
||||
|
||||
if (check_wiki(line)) {
|
||||
result = parse_block();
|
||||
if (! result) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
f_.close();
|
||||
close_opened_tags();
|
||||
parent_name_.clear();
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
bool class_source_parser::parse_block(){
|
||||
while (!f_.eof()){
|
||||
std::string line;
|
||||
if (! getline(line) ) { return false; }
|
||||
if ( check_valid(line)) {
|
||||
if (check_parent_begin(line)) continue;
|
||||
|
||||
if (check_tag_begin(line)){
|
||||
parse_tag();
|
||||
continue;
|
||||
}
|
||||
check_parent_end(line);
|
||||
}
|
||||
else{
|
||||
// wiki-block is closed. checking stack of opened tags
|
||||
if (current_.size() != 0 ){
|
||||
add_open_tag_error();
|
||||
close_opened_tags();
|
||||
// continue working
|
||||
}
|
||||
// block is closed and all tags are closed.
|
||||
return true;
|
||||
|
||||
}
|
||||
}// end while
|
||||
return false;
|
||||
}
|
||||
|
||||
bool class_source_parser::parse_tag(){
|
||||
while (!f_.eof()){
|
||||
std::string line;
|
||||
if (! getline(line) ) { return false; }
|
||||
if (check_valid(line)) {
|
||||
if (check_tag_begin(line)){
|
||||
parse_tag();
|
||||
}
|
||||
if (check_tag_end(line)){
|
||||
return true;
|
||||
}
|
||||
if (check_keys_begin(line)){
|
||||
parse_keys();
|
||||
}
|
||||
if (check_allow_link(line)){
|
||||
}
|
||||
if (check_allow_global(line)){
|
||||
}
|
||||
}else{
|
||||
if (current_.size() != 0 ){
|
||||
// adding error messages for each unclosed entity
|
||||
add_open_tag_error();
|
||||
close_opened_tags();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool class_source_parser::parse_keys(){
|
||||
std::string line;
|
||||
do{
|
||||
if (! getline(line) ) { return false; }
|
||||
if (! check_valid(line)) {
|
||||
errors_.add_opened_entity_error(input_,line_,"Table config");
|
||||
add_open_tag_error();
|
||||
close_opened_tags();
|
||||
return false;
|
||||
}
|
||||
static const boost::regex value (get_key_value() );
|
||||
boost::smatch sub;
|
||||
bool res = boost::regex_match(line,sub,value);
|
||||
if (res){
|
||||
class_key key;
|
||||
key.set_name(sub[1]);
|
||||
key.set_type(sub[2]);
|
||||
key.set_default(sub[3]);
|
||||
current_.back().add_key(key);
|
||||
}
|
||||
}while (! check_keys_end(line));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool class_source_parser::check_valid(const std::string &s){
|
||||
// s must be like " *" or "*"
|
||||
static const boost::regex valid (get_valid());
|
||||
return boost::regex_search(s,valid);
|
||||
}
|
||||
|
||||
bool class_source_parser::check_wiki(const std::string& s){
|
||||
boost::regex wiki (get_wiki());
|
||||
return boost::regex_match(s,wiki);
|
||||
}
|
||||
|
||||
bool class_source_parser::check_tag_begin(const std::string &s){
|
||||
// read tag;
|
||||
static boost::regex tag (get_tag_begin());
|
||||
boost::smatch sub;
|
||||
bool res = boost::regex_match(s,sub,tag);
|
||||
if (res){
|
||||
class_tag new_tag;
|
||||
new_tag.set_name(sub[1]);
|
||||
new_tag.set_min(sub[2]);
|
||||
new_tag.set_max(sub[3]);
|
||||
new_tag.set_super(sub[5]);
|
||||
current_.push_back(new_tag);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool class_source_parser::check_tag_end(const std::string &s){
|
||||
static const boost::regex endtag (get_tag_end());
|
||||
boost::smatch sub;
|
||||
bool res = boost::regex_match(s,sub,endtag);
|
||||
if (res){
|
||||
std::string name = sub[1];
|
||||
if (current_.empty()){
|
||||
errors_.add_unopened_entity_error(input_,line_,name);
|
||||
return false;
|
||||
}
|
||||
std::vector<class_tag>::iterator ii = current_.end();
|
||||
int count_opened = 0;
|
||||
do{
|
||||
--ii;
|
||||
if (ii->get_name() == name){
|
||||
add_open_tag_error(count_opened);
|
||||
close_opened_tags(++count_opened);
|
||||
return true;
|
||||
}else{
|
||||
count_opened ++;
|
||||
}
|
||||
}while (ii != current_.begin()) ;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool class_source_parser::check_allow_link(const std::string &s){
|
||||
static const boost::regex allow_link (get_allow_link());
|
||||
boost::smatch sub;
|
||||
bool res = boost::regex_match(s,sub,allow_link);
|
||||
if (res){
|
||||
if (!current_.empty()){
|
||||
current_.back().add_link(sub[1]);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
bool class_source_parser::check_allow_global(const std::string &s){
|
||||
static const boost::regex allow_global (get_allow_global());
|
||||
boost::smatch sub;
|
||||
bool res = boost::regex_match(s,sub,allow_global);
|
||||
if (res){
|
||||
if (!current_.empty()){
|
||||
current_.back().add_link("global/"+sub[1]);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
bool class_source_parser::check_parent_begin(const std::string &s){
|
||||
static const boost::regex parent (get_parent_begin());
|
||||
boost::smatch sub;
|
||||
bool res = boost::regex_match(s,sub,parent);
|
||||
if (res){
|
||||
std::string name = sub[1];
|
||||
if (!parent_name_.empty()) {
|
||||
errors_.add_second_parent_error(input_,line_,parent_name_,name);
|
||||
}
|
||||
parent_name_ = name;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
bool class_source_parser::check_parent_end(const std::string &s){
|
||||
static const boost::regex parent (get_parent_end());
|
||||
boost::smatch sub;
|
||||
bool res = boost::regex_match(s,sub,parent);
|
||||
if (res){
|
||||
std::string name = sub[1];
|
||||
if (parent_name_ == name) {
|
||||
parent_name_.clear();
|
||||
}else{
|
||||
errors_.add_unopened_entity_error(input_,line_,name);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool class_source_parser::check_keys_begin(const std::string &s){
|
||||
static const boost::regex keys (get_table_key_begin());
|
||||
return boost::regex_match(s,keys);
|
||||
|
||||
}
|
||||
|
||||
bool class_source_parser::check_keys_end(const std::string &s){
|
||||
static const boost::regex endkeys (get_table_end());
|
||||
bool res = boost::regex_match(s,endkeys);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
} // namespace schema_generator
|
194
src/tools/schema/sourceparser.hpp
Normal file
194
src/tools/schema/sourceparser.hpp
Normal file
|
@ -0,0 +1,194 @@
|
|||
/*
|
||||
Copyright (C) 2011 - 2011 by Sytyi Nick <nsytyi@gmail.com>
|
||||
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY.
|
||||
|
||||
See the COPYING file for more details.
|
||||
*/
|
||||
/**
|
||||
* @file
|
||||
* This file contains sourceparser object, collecting annotations
|
||||
* and building a tag tree.
|
||||
* Also here are declared fuctions that return regex templates.
|
||||
* And a fuction to create a file with list of templates.
|
||||
*/
|
||||
|
||||
#ifndef TOOLS_SCHEMA_SOURCEPARSER_HPP_INCLUDED
|
||||
#define TOOLS_SCHEMA_SOURCEPARSER_HPP_INCLUDED
|
||||
|
||||
#include "./tools/schema/error_container.hpp"
|
||||
#include "./tools/schema/tag.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <map>
|
||||
#include <queue>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace schema_generator{
|
||||
/** A few regex templates. Please notice, that adding any regex template,
|
||||
* schould be called in test_regexes()
|
||||
*/
|
||||
|
||||
/** Template to check line of beeing valid*/
|
||||
const std::string & get_valid();
|
||||
/** Template to check line is beginnnig of Wiki block*/
|
||||
const std::string & get_wiki();
|
||||
/** Template to check begining of parent block*/
|
||||
const std::string & get_parent_begin() ;
|
||||
/** Template to check closing of parent block*/
|
||||
const std::string & get_parent_end() ;
|
||||
/** Template to check if line contains opening of tag block*/
|
||||
const std::string & get_tag_begin() ;
|
||||
/** Template to check end of tag block*/
|
||||
|
||||
const std::string & get_tag_end() ;
|
||||
|
||||
/** Template to check allow{link} block*/
|
||||
const std::string & get_allow_link();
|
||||
/** Template to check allow{global} block*/
|
||||
const std::string & get_allow_global();
|
||||
|
||||
/** Template to check begining of table{config} storing key values*/
|
||||
const std::string & get_table_key_begin() ;
|
||||
/** Template to check if table is closed*/
|
||||
const std::string & get_table_end() ;
|
||||
|
||||
/** Template to get key value*/
|
||||
const std::string & get_key_value();
|
||||
/** Writes to the file regex templates list.*/
|
||||
void test_regex(std::ostream & f );
|
||||
|
||||
class class_source_parser{
|
||||
public:
|
||||
class_source_parser():
|
||||
input_ (""),
|
||||
output_(""),
|
||||
root_(class_tag("root",1,1)),
|
||||
parent_name_("")
|
||||
{}
|
||||
|
||||
~class_source_parser(){
|
||||
}
|
||||
void set_input(const std::string &s){
|
||||
input_ = s;
|
||||
}
|
||||
void set_output(const std::string &s){
|
||||
output_ = s;
|
||||
}
|
||||
/**
|
||||
* Parses file line-by-line, checking every line to open WIKI block
|
||||
* Please, notice that main input work is made in check_*** methods.
|
||||
* Methods parse_*** are used to organize alhoritm and set which
|
||||
* regex template can be used in this context.
|
||||
* The only exception is parse_keys, where table of keys is read
|
||||
* and add to top of stack tags.
|
||||
*/
|
||||
bool parse_source();
|
||||
/**
|
||||
* Saves tag tree to schema file.
|
||||
*/
|
||||
bool save_schema();
|
||||
const std::vector<class_tag> & see_orphans() const{
|
||||
return orphan_tags_;
|
||||
}
|
||||
/** Grants access to error container*/
|
||||
const class_error_container & see_errors() {
|
||||
errors_.sort();
|
||||
return errors_;
|
||||
}
|
||||
private:
|
||||
/** name of input file to be parsed*/
|
||||
std::string input_;
|
||||
/** name of output file to print schema*/
|
||||
std::string output_;
|
||||
std::fstream f_;
|
||||
//current line number
|
||||
/** number of current read line. Is used when generating errors*/
|
||||
int line_;
|
||||
//vector-based stack. The element on top is current opened tag.
|
||||
/** Stack of opened tags.*/
|
||||
std::vector<class_tag> current_;
|
||||
/** Root of the schema tree*/
|
||||
class_tag root_;
|
||||
/** Name of current parent*/
|
||||
std::string parent_name_;
|
||||
/** List of tags without parents.*/
|
||||
std::vector<class_tag> orphan_tags_;
|
||||
/** used to store errors*/
|
||||
class_error_container errors_;
|
||||
|
||||
/**
|
||||
* Parses WIKI block line-by-line, checking every line
|
||||
* to open annotation block
|
||||
*/
|
||||
bool parse_block();
|
||||
/**
|
||||
* Parses lines inside tag block.
|
||||
* Calls checkers that are allowed in tag block
|
||||
*/
|
||||
bool parse_tag();
|
||||
/**
|
||||
* Read key table and add keys to tag on the top of the stack.
|
||||
*/
|
||||
bool parse_keys();
|
||||
|
||||
/** check the input line with a template
|
||||
* check if the line is valid (still in block)
|
||||
*/
|
||||
bool check_valid(const std::string& s);
|
||||
/**
|
||||
* Gets a line from file and returns it.
|
||||
* Is used to manage exceptions while IO.
|
||||
*/
|
||||
bool getline(std::string & s);
|
||||
/**
|
||||
* Сhecks stack of opened tags. If any tags is opened - closes it
|
||||
*and adds to sublist of next tag in stack.
|
||||
* Add last tag in stack to parent
|
||||
* @param i number of tags in stack to close.
|
||||
*/
|
||||
void close_opened_tags(int i);
|
||||
/** Generates errors for each opened tag.
|
||||
* @param i number of tags in stack to complain.
|
||||
*/
|
||||
void add_open_tag_error(int i);
|
||||
|
||||
|
||||
/**
|
||||
* Read tag form the line and add it to stack
|
||||
*/
|
||||
bool check_wiki(const std::string& s);
|
||||
|
||||
/** Checks line for tag annotation. Reads tag and puts in into stack.*/
|
||||
bool check_tag_begin(const std::string& s);
|
||||
/**
|
||||
* Puts closed tag to child list of previous tag.
|
||||
* Also closes all opened child tags, if they are, and generates warnings.
|
||||
*/
|
||||
bool check_tag_end(const std::string& s);
|
||||
|
||||
/** Opens parrent block*/
|
||||
bool check_parent_begin(const std::string& s);
|
||||
/** Closes parent block*/
|
||||
bool check_parent_end(const std::string& s);
|
||||
/** Checks beginning of keys*/
|
||||
bool check_keys_begin(const std::string&s);
|
||||
/** Checks end of keys*/
|
||||
bool check_keys_end(const std::string&s);
|
||||
/** Checks links*/
|
||||
bool check_allow_link(const std::string & s);
|
||||
/** Checks allowed global tags*/
|
||||
bool check_allow_global(const std::string &s);
|
||||
|
||||
};
|
||||
} // namespace SchemaGenerator
|
||||
|
||||
#endif // TOOLS_SCHEMA_SOURCEPARSER_HPP_INCLUDED
|
127
src/tools/schema/tag.cpp
Normal file
127
src/tools/schema/tag.cpp
Normal file
|
@ -0,0 +1,127 @@
|
|||
/*
|
||||
Copyright (C) 2011 - 2011 by Sytyi Nick <nsytyi@gmail.com>
|
||||
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY.
|
||||
|
||||
See the COPYING file for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Implementation of tag.hpp.
|
||||
*/
|
||||
|
||||
#include "./tools/schema/tag.hpp"
|
||||
|
||||
namespace schema_generator{
|
||||
void class_key::print(std::ostream& os,int level) const {
|
||||
std::string s;
|
||||
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 << "mandatory=\"true\"\n";
|
||||
}else{
|
||||
os << s <<"default="<< default_ <<"\n";
|
||||
}
|
||||
os << s << "[/key]\n";
|
||||
}
|
||||
|
||||
void class_tag::print(std::ostream& os){
|
||||
printl(os,4,4);
|
||||
}
|
||||
|
||||
|
||||
void class_tag::printl(std::ostream &os,int level, int step){
|
||||
std::sort (keys_.begin(), keys_.end());
|
||||
std::sort (tags_.begin(), tags_.end());
|
||||
std::sort (links_.begin(), links_.end());
|
||||
std::string s;
|
||||
|
||||
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";
|
||||
}
|
||||
for (std::vector<class_tag>::iterator i = tags_.begin();
|
||||
i != tags_.end(); ++i ){
|
||||
i->printl(os,level+step,step);
|
||||
}
|
||||
for (std::vector<std::string>::iterator i = links_.begin();
|
||||
i != links_.end(); ++i ){
|
||||
os << s << "" << "[link]\n"
|
||||
<< s << "" << "name=\"" <<*i << "\"\n"
|
||||
<< s << "" << "[/link]\n";
|
||||
}
|
||||
for (std::vector<class_key>::iterator i = keys_.begin();
|
||||
i != keys_.end(); ++i ){
|
||||
i->print(os,level+step);
|
||||
}
|
||||
os<< s << "[/tag]\n";
|
||||
}
|
||||
|
||||
const std::string class_tag::add_tag(const std::string &path,
|
||||
const class_tag &tag){
|
||||
if ( path.empty() || path == "/" ){
|
||||
std::vector<class_tag>::iterator it =
|
||||
std::find(tags_.begin(),tags_.end(),tag);
|
||||
if (it == tags_.end()){
|
||||
tags_.push_back(tag);
|
||||
}else{
|
||||
it->add_tags(tag.tags_);
|
||||
it->set_min(tag.min_);
|
||||
it->set_max(tag.max_);
|
||||
it->add_keys(tag.keys_);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
int pos = path.find('/');
|
||||
std::string name = path.substr(0,pos);
|
||||
std::string next_path = path.substr(++pos,path.length());
|
||||
std::vector<std::string>::iterator it_links= links_.begin();
|
||||
for (;it_links != links_.end();++it_links){
|
||||
std::string::size_type pos_last = it_links->rfind('/');
|
||||
// if (pos_last > it_links->length()) {
|
||||
//continue;
|
||||
//}
|
||||
std::string name_link = it_links->substr(++pos_last,path.length());
|
||||
if (name_link == name) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (it_links != links_.end()){
|
||||
return *it_links + "/" + next_path;
|
||||
}
|
||||
std::vector<class_tag>::iterator it_tags = tags_.begin();
|
||||
// = std::find(tags_.begin(),tags_.end(),class_tag(name,0,0);
|
||||
for (;it_tags!=tags_.end(); ++it_tags){
|
||||
if ( it_tags->name_ == name ){
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (it_tags == tags_.end()){
|
||||
class_tag subtag;
|
||||
subtag.set_name(name);
|
||||
subtag.add_tag(next_path,tag);
|
||||
tags_.push_back(subtag);
|
||||
return "";
|
||||
}
|
||||
return it_tags->add_tag(next_path,tag);
|
||||
}
|
||||
|
||||
|
||||
}//namespace schema_generator
|
275
src/tools/schema/tag.hpp
Normal file
275
src/tools/schema/tag.hpp
Normal file
|
@ -0,0 +1,275 @@
|
|||
|
||||
/*
|
||||
Copyright (C) 2011 - 2011 by Sytyi Nick <nsytyi@gmail.com>
|
||||
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY.
|
||||
|
||||
See the COPYING file for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* This file contains objects "tag" and "key", which are used to store
|
||||
* information about tags and keys while annotation parsing.
|
||||
*/
|
||||
|
||||
#ifndef TOOLS_SCHEMA_TAG_HPP_INCLUDED
|
||||
#define TOOLS_SCHEMA_TAG_HPP_INCLUDED
|
||||
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
|
||||
|
||||
namespace schema_generator{
|
||||
/**
|
||||
* 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,
|
||||
bool mandatory)
|
||||
{
|
||||
name_ = name;
|
||||
type_ = type;
|
||||
default_ = def;
|
||||
mandatory_ = mandatory;
|
||||
}
|
||||
|
||||
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_ ;
|
||||
}
|
||||
|
||||
void set_name(const std::string& name){
|
||||
name_ = name;
|
||||
}
|
||||
void set_type(const std::string& type){
|
||||
type_ = type;
|
||||
}
|
||||
void set_default(const std::string& def){
|
||||
default_ = def;
|
||||
if (def.empty()){
|
||||
mandatory_ = true;
|
||||
}
|
||||
}
|
||||
void set_mandatory(bool mandatory){
|
||||
mandatory_ = mandatory;
|
||||
}
|
||||
/** is used to print key info
|
||||
* the format is next
|
||||
* [key]
|
||||
* name="name"
|
||||
* type="type"
|
||||
* 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{
|
||||
return (get_name() < k.get_name());
|
||||
}
|
||||
private:
|
||||
/** Name of key*/
|
||||
std::string name_;
|
||||
/** Type of key*/
|
||||
std::string type_;
|
||||
/** Default value*/
|
||||
std::string default_;
|
||||
/** 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{
|
||||
public:
|
||||
class_tag():name_(""),min_(0),max_(0),super_("")
|
||||
{ }
|
||||
|
||||
class_tag(const std::string & name,
|
||||
int min,
|
||||
int max
|
||||
)
|
||||
{
|
||||
name_ = name;
|
||||
min_ = min;
|
||||
max_ = max;
|
||||
}
|
||||
class_tag(const std::string & name,
|
||||
int min,
|
||||
int max,
|
||||
const std::string & super
|
||||
)
|
||||
{
|
||||
name_ = name;
|
||||
min_ = min;
|
||||
max_ = max;
|
||||
super_ = super;
|
||||
}
|
||||
~class_tag(){ }
|
||||
|
||||
/** Prints information about tag to outputstream, recursively
|
||||
* is used to print tag info
|
||||
* the format is next
|
||||
* [tag]
|
||||
* subtags
|
||||
* keys
|
||||
* name="name"
|
||||
* 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();
|
||||
}
|
||||
|
||||
void set_name(const std::string& name){
|
||||
name_ = name;
|
||||
}
|
||||
void set_min(int o){
|
||||
min_ = o;
|
||||
}
|
||||
void set_max(int o){
|
||||
max_ = o;
|
||||
}
|
||||
void set_min( std::string const& s){
|
||||
std::istringstream i(s);
|
||||
if (!(i >> min_)){
|
||||
min_ = 0;
|
||||
}
|
||||
}
|
||||
void set_max( std::string const & s){
|
||||
std::istringstream i(s);
|
||||
if (!(i >> max_)){
|
||||
max_ = 0;
|
||||
}
|
||||
}
|
||||
void set_super(std::string const & s){
|
||||
super_= s;
|
||||
}
|
||||
void add_key(const class_key& new_key){
|
||||
keys_.push_back(new_key);
|
||||
}
|
||||
void add_tag(const class_tag& new_tag){
|
||||
tags_.push_back(new_tag);
|
||||
}
|
||||
void add_link(const std::string & link){
|
||||
links_.push_back(link);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tags are usually organized in tree.
|
||||
* This fuction helps to add tag to his exact place in tree
|
||||
* @param path - path in subtree to exact place of tag
|
||||
* @param tag - tag to add
|
||||
* @todo make support of adding to link. Probably by returning exact path,
|
||||
* i.e we wan add to foo/bar/example, but /foo/bar is a link to bar.
|
||||
* Probably fuction schould return right path , i.this.e. bar/example
|
||||
* and caller schould call one's more
|
||||
* Path is getting shotter and shoter with each call.
|
||||
* Path schould look like tag1/tag2/parent/ Slash at end is mandatory.
|
||||
* @return Pointer to name of the full path.
|
||||
* @retval NULL add successful.
|
||||
* @retval Not NULL you try add a child to a link,
|
||||
* here is a right path, please, use it.
|
||||
*/
|
||||
const std::string add_tag (const std::string & path,
|
||||
const class_tag & tag);
|
||||
|
||||
bool operator < ( const class_tag& t) const{
|
||||
return name_ < t.name_;
|
||||
}
|
||||
bool operator == (const class_tag & other){
|
||||
return name_ == other.name_;
|
||||
}
|
||||
|
||||
private:
|
||||
/** name of tag*/
|
||||
std::string name_;
|
||||
/** number of minimum occasions*/
|
||||
int min_;
|
||||
/** number of maximum occasions*/
|
||||
int max_;
|
||||
/**
|
||||
* name of tag to extend "super-tag"
|
||||
* Extension is smth like inheritance and is used in case
|
||||
* when you need to use another tag with all his
|
||||
* keys, childs, etc. But you also want to allow extra subtags of that tags,
|
||||
* so just linking that tag wouldn't help at all.
|
||||
*/
|
||||
std::string super_;
|
||||
/** children tags*/
|
||||
std::vector<class_tag> tags_;
|
||||
/** keys*/
|
||||
std::vector<class_key> keys_;
|
||||
/** links to possible children.
|
||||
* @todo make support of key section. which takes mandatory links usually.
|
||||
*/
|
||||
std::vector<std::string> links_;
|
||||
/**
|
||||
* the same as class_tag::print(std::ostream&)
|
||||
* but indents different levels with step space.
|
||||
* @param os stream to print
|
||||
* @param level current level of indentation
|
||||
* @param step step to next indent
|
||||
*/
|
||||
void printl(std::ostream &os,int level, int step);
|
||||
|
||||
void add_tags (const std::vector<class_tag> & list){
|
||||
tags_.insert(tags_.end(),list.begin(),list.end());
|
||||
}
|
||||
void add_keys (const std::vector<class_key> & list){
|
||||
keys_.insert(keys_.end(),list.begin(),list.end());
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
#endif // TOOLS_SCHEMA_TAG_HPP_INCLUDED
|
|
@ -108,7 +108,9 @@ if __name__ == "__main__":
|
|||
|
||||
# strip
|
||||
data = re.sub(" \*(?: |)", "", data)
|
||||
|
||||
|
||||
#annotation
|
||||
data = re.sub(r'@(?:begin|end|allow)\{(?:parent|tag|link|global)\}(?:\{.*\})',"",data)
|
||||
return data
|
||||
|
||||
def get_value(data, key):
|
||||
|
|
Loading…
Add table
Reference in a new issue