|
|
|
|
|
#ifndef DLIB_CONFIG_READER_KERNEl_1_ |
|
#define DLIB_CONFIG_READER_KERNEl_1_ |
|
|
|
#include "config_reader_kernel_abstract.h" |
|
#include <string> |
|
#include <iostream> |
|
#include <sstream> |
|
#include <fstream> |
|
#include "../algs.h" |
|
#include "../stl_checked/std_vector_c.h" |
|
|
|
#ifndef DLIB_ISO_CPP_ONLY |
|
#include "config_reader_thread_safe_1.h" |
|
#endif |
|
|
|
namespace dlib |
|
{ |
|
|
|
template < |
|
typename map_string_string, |
|
typename map_string_void, |
|
typename tokenizer |
|
> |
|
class config_reader_kernel_1 |
|
{ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public: |
|
|
|
|
|
typedef config_reader_kernel_1 kernel_1a; |
|
#ifndef DLIB_ISO_CPP_ONLY |
|
typedef config_reader_thread_safe_1< |
|
config_reader_kernel_1, |
|
map_string_void |
|
> thread_safe_1a; |
|
#endif |
|
|
|
|
|
config_reader_kernel_1(); |
|
|
|
class config_reader_error : public dlib::error |
|
{ |
|
friend class config_reader_kernel_1; |
|
config_reader_error( |
|
unsigned long ln, |
|
bool r = false |
|
) : |
|
dlib::error(ECONFIG_READER), |
|
line_number(ln), |
|
redefinition(r) |
|
{ |
|
std::ostringstream sout; |
|
sout << "Error in config_reader while parsing at line number " << line_number << "."; |
|
if (redefinition) |
|
sout << "\nThe identifier on this line has already been defined in this scope."; |
|
const_cast<std::string&>(info) = sout.str(); |
|
} |
|
public: |
|
const unsigned long line_number; |
|
const bool redefinition; |
|
}; |
|
|
|
class file_not_found : public dlib::error |
|
{ |
|
friend class config_reader_kernel_1; |
|
file_not_found( |
|
const std::string& file_name_ |
|
) : |
|
dlib::error(ECONFIG_READER, "Error in config_reader, unable to open file " + file_name_), |
|
file_name(file_name_) |
|
{} |
|
|
|
~file_not_found() throw() {} |
|
|
|
public: |
|
const std::string file_name; |
|
}; |
|
|
|
class config_reader_access_error : public dlib::error |
|
{ |
|
public: |
|
config_reader_access_error( |
|
const std::string& block_name_, |
|
const std::string& key_name_ |
|
) : |
|
dlib::error(ECONFIG_READER), |
|
block_name(block_name_), |
|
key_name(key_name_) |
|
{ |
|
std::ostringstream sout; |
|
sout << "Error in config_reader.\n"; |
|
if (block_name.size() > 0) |
|
sout << " A block with the name '" << block_name << "' was expected but not found."; |
|
else if (key_name.size() > 0) |
|
sout << " A key with the name '" << key_name << "' was expected but not found."; |
|
|
|
const_cast<std::string&>(info) = sout.str(); |
|
} |
|
|
|
~config_reader_access_error() throw() {} |
|
const std::string block_name; |
|
const std::string key_name; |
|
}; |
|
|
|
config_reader_kernel_1( |
|
const std::string& config_file |
|
); |
|
|
|
config_reader_kernel_1( |
|
std::istream& in |
|
); |
|
|
|
virtual ~config_reader_kernel_1( |
|
); |
|
|
|
void clear ( |
|
); |
|
|
|
void load_from ( |
|
std::istream& in |
|
); |
|
|
|
void load_from ( |
|
const std::string& config_file |
|
); |
|
|
|
bool is_key_defined ( |
|
const std::string& key |
|
) const; |
|
|
|
bool is_block_defined ( |
|
const std::string& name |
|
) const; |
|
|
|
typedef config_reader_kernel_1 this_type; |
|
const this_type& block ( |
|
const std::string& name |
|
) const; |
|
|
|
const std::string& operator[] ( |
|
const std::string& key |
|
) const; |
|
|
|
template < |
|
typename queue_of_strings |
|
> |
|
void get_keys ( |
|
queue_of_strings& keys |
|
) const; |
|
|
|
template < |
|
typename alloc |
|
> |
|
void get_keys ( |
|
std::vector<std::string,alloc>& keys |
|
) const; |
|
|
|
template < |
|
typename alloc |
|
> |
|
void get_keys ( |
|
std_vector_c<std::string,alloc>& keys |
|
) const; |
|
|
|
template < |
|
typename queue_of_strings |
|
> |
|
void get_blocks ( |
|
queue_of_strings& blocks |
|
) const; |
|
|
|
template < |
|
typename alloc |
|
> |
|
void get_blocks ( |
|
std::vector<std::string,alloc>& blocks |
|
) const; |
|
|
|
template < |
|
typename alloc |
|
> |
|
void get_blocks ( |
|
std_vector_c<std::string,alloc>& blocks |
|
) const; |
|
|
|
private: |
|
|
|
static void parse_config_file ( |
|
config_reader_kernel_1& cr, |
|
tokenizer& tok, |
|
unsigned long& line_number, |
|
const bool top_of_recursion = true |
|
); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
map_string_string key_table; |
|
map_string_void block_table; |
|
|
|
|
|
config_reader_kernel_1(config_reader_kernel_1&); |
|
config_reader_kernel_1& operator=(config_reader_kernel_1&); |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
template < |
|
typename map_string_string, |
|
typename map_string_void, |
|
typename tokenizer |
|
> |
|
config_reader_kernel_1<map_string_string,map_string_void,tokenizer>:: |
|
config_reader_kernel_1( |
|
) |
|
{ |
|
} |
|
|
|
|
|
|
|
template < |
|
typename map_string_string, |
|
typename map_string_void, |
|
typename tokenizer |
|
> |
|
void config_reader_kernel_1<map_string_string,map_string_void,tokenizer>:: |
|
clear( |
|
) |
|
{ |
|
|
|
block_table.reset(); |
|
while (block_table.move_next()) |
|
{ |
|
delete static_cast<config_reader_kernel_1*>(block_table.element().value()); |
|
} |
|
block_table.clear(); |
|
key_table.clear(); |
|
} |
|
|
|
|
|
|
|
template < |
|
typename map_string_string, |
|
typename map_string_void, |
|
typename tokenizer |
|
> |
|
void config_reader_kernel_1<map_string_string,map_string_void,tokenizer>:: |
|
load_from( |
|
std::istream& in |
|
) |
|
{ |
|
clear(); |
|
|
|
tokenizer tok; |
|
tok.set_stream(in); |
|
tok.set_identifier_token( |
|
tok.lowercase_letters() + tok.uppercase_letters(), |
|
tok.lowercase_letters() + tok.uppercase_letters() + tok.numbers() + "_-." |
|
); |
|
|
|
unsigned long line_number = 1; |
|
try |
|
{ |
|
parse_config_file(*this,tok,line_number); |
|
} |
|
catch (...) |
|
{ |
|
clear(); |
|
throw; |
|
} |
|
} |
|
|
|
|
|
|
|
template < |
|
typename map_string_string, |
|
typename map_string_void, |
|
typename tokenizer |
|
> |
|
void config_reader_kernel_1<map_string_string,map_string_void,tokenizer>:: |
|
load_from( |
|
const std::string& config_file |
|
) |
|
{ |
|
clear(); |
|
std::ifstream fin(config_file.c_str()); |
|
if (!fin) |
|
throw file_not_found(config_file); |
|
|
|
load_from(fin); |
|
} |
|
|
|
|
|
|
|
template < |
|
typename map_string_string, |
|
typename map_string_void, |
|
typename tokenizer |
|
> |
|
config_reader_kernel_1<map_string_string,map_string_void,tokenizer>:: |
|
config_reader_kernel_1( |
|
std::istream& in |
|
) |
|
{ |
|
load_from(in); |
|
} |
|
|
|
|
|
|
|
template < |
|
typename map_string_string, |
|
typename map_string_void, |
|
typename tokenizer |
|
> |
|
config_reader_kernel_1<map_string_string,map_string_void,tokenizer>:: |
|
config_reader_kernel_1( |
|
const std::string& config_file |
|
) |
|
{ |
|
load_from(config_file); |
|
} |
|
|
|
|
|
|
|
template < |
|
typename map_string_string, |
|
typename map_string_void, |
|
typename tokenizer |
|
> |
|
void config_reader_kernel_1<map_string_string,map_string_void,tokenizer>:: |
|
parse_config_file( |
|
config_reader_kernel_1<map_string_string,map_string_void,tokenizer>& cr, |
|
tokenizer& tok, |
|
unsigned long& line_number, |
|
const bool top_of_recursion |
|
) |
|
{ |
|
int type; |
|
std::string token; |
|
bool in_comment = false; |
|
bool seen_identifier = false; |
|
std::string identifier; |
|
while (true) |
|
{ |
|
tok.get_token(type,token); |
|
|
|
if (type == tokenizer::WHITE_SPACE) |
|
continue; |
|
|
|
|
|
if (type == tokenizer::END_OF_LINE) |
|
{ |
|
++line_number; |
|
in_comment = false; |
|
continue; |
|
} |
|
|
|
|
|
if (in_comment) |
|
continue; |
|
|
|
|
|
if (type == tokenizer::CHAR && token[0] == '#') |
|
{ |
|
in_comment = true; |
|
continue; |
|
} |
|
|
|
|
|
|
|
if ( (type == tokenizer::CHAR && token[0] == '}' && !top_of_recursion) || |
|
(type == tokenizer::END_OF_FILE && top_of_recursion) ) |
|
{ |
|
break; |
|
} |
|
|
|
if (seen_identifier) |
|
{ |
|
seen_identifier = false; |
|
|
|
if (type != tokenizer::CHAR || (token[0] != '=' && token[0] != '{')) |
|
throw config_reader_error(line_number); |
|
|
|
if (token[0] == '=') |
|
{ |
|
|
|
|
|
if (tok.peek_type() == tokenizer::WHITE_SPACE) |
|
tok.get_token(type,token); |
|
|
|
std::string value; |
|
type = tok.peek_type(); |
|
token = tok.peek_token(); |
|
while (true) |
|
{ |
|
if (type == tokenizer::END_OF_FILE || type == tokenizer::END_OF_LINE) |
|
break; |
|
|
|
if (type == tokenizer::CHAR && token[0] == '\\') |
|
{ |
|
tok.get_token(type,token); |
|
if (tok.peek_type() == tokenizer::CHAR && |
|
tok.peek_token()[0] == '#') |
|
{ |
|
tok.get_token(type,token); |
|
value += '#'; |
|
} |
|
else if (tok.peek_type() == tokenizer::CHAR && |
|
tok.peek_token()[0] == '}') |
|
{ |
|
tok.get_token(type,token); |
|
value += '}'; |
|
} |
|
else |
|
{ |
|
value += '\\'; |
|
} |
|
} |
|
else if (type == tokenizer::CHAR && |
|
(token[0] == '#' || token[0] == '}')) |
|
{ |
|
break; |
|
} |
|
else |
|
{ |
|
value += token; |
|
tok.get_token(type,token); |
|
} |
|
type = tok.peek_type(); |
|
token = tok.peek_token(); |
|
} |
|
|
|
|
|
std::string::size_type pos = value.find_last_not_of(" \t\r\n"); |
|
if (pos == std::string::npos) |
|
value.clear(); |
|
else |
|
value.erase(pos+1); |
|
|
|
|
|
if (cr.key_table.is_in_domain(identifier)) |
|
throw config_reader_error(line_number,true); |
|
|
|
|
|
cr.key_table.add(identifier,value); |
|
|
|
} |
|
else |
|
{ |
|
|
|
if (cr.block_table.is_in_domain(identifier)) |
|
throw config_reader_error(line_number,true); |
|
|
|
config_reader_kernel_1* new_cr = new config_reader_kernel_1; |
|
void* vtemp = new_cr; |
|
try { cr.block_table.add(identifier,vtemp); } |
|
catch (...) { delete new_cr; throw; } |
|
|
|
|
|
parse_config_file(*new_cr,tok,line_number,false); |
|
} |
|
} |
|
else |
|
{ |
|
|
|
if (type != tokenizer::IDENTIFIER) |
|
throw config_reader_error(line_number); |
|
|
|
seen_identifier = true; |
|
identifier = token; |
|
} |
|
} |
|
} |
|
|
|
|
|
|
|
template < |
|
typename map_string_string, |
|
typename map_string_void, |
|
typename tokenizer |
|
> |
|
config_reader_kernel_1<map_string_string,map_string_void,tokenizer>:: |
|
~config_reader_kernel_1( |
|
) |
|
{ |
|
clear(); |
|
} |
|
|
|
|
|
|
|
template < |
|
typename map_string_string, |
|
typename map_string_void, |
|
typename tokenizer |
|
> |
|
bool config_reader_kernel_1<map_string_string,map_string_void,tokenizer>:: |
|
is_key_defined ( |
|
const std::string& key |
|
) const |
|
{ |
|
return key_table.is_in_domain(key); |
|
} |
|
|
|
|
|
|
|
template < |
|
typename map_string_string, |
|
typename map_string_void, |
|
typename tokenizer |
|
> |
|
bool config_reader_kernel_1<map_string_string,map_string_void,tokenizer>:: |
|
is_block_defined ( |
|
const std::string& name |
|
) const |
|
{ |
|
return block_table.is_in_domain(name); |
|
} |
|
|
|
|
|
|
|
template < |
|
typename mss, |
|
typename msv, |
|
typename tokenizer |
|
> |
|
const config_reader_kernel_1<mss,msv,tokenizer>& config_reader_kernel_1<mss,msv,tokenizer>:: |
|
block ( |
|
const std::string& name |
|
) const |
|
{ |
|
if (is_block_defined(name) == false) |
|
{ |
|
throw config_reader_access_error(name,""); |
|
} |
|
|
|
return *static_cast<config_reader_kernel_1*>(block_table[name]); |
|
} |
|
|
|
|
|
|
|
template < |
|
typename map_string_string, |
|
typename map_string_void, |
|
typename tokenizer |
|
> |
|
const std::string& config_reader_kernel_1<map_string_string,map_string_void,tokenizer>:: |
|
operator[] ( |
|
const std::string& key |
|
) const |
|
{ |
|
if (is_key_defined(key) == false) |
|
{ |
|
throw config_reader_access_error("",key); |
|
} |
|
|
|
return key_table[key]; |
|
} |
|
|
|
|
|
|
|
template < |
|
typename map_string_string, |
|
typename map_string_void, |
|
typename tokenizer |
|
> |
|
template < |
|
typename queue_of_strings |
|
> |
|
void config_reader_kernel_1<map_string_string,map_string_void,tokenizer>:: |
|
get_keys ( |
|
queue_of_strings& keys |
|
) const |
|
{ |
|
keys.clear(); |
|
key_table.reset(); |
|
std::string temp; |
|
while (key_table.move_next()) |
|
{ |
|
temp = key_table.element().key(); |
|
keys.enqueue(temp); |
|
} |
|
} |
|
|
|
|
|
|
|
template < |
|
typename map_string_string, |
|
typename map_string_void, |
|
typename tokenizer |
|
> |
|
template < |
|
typename alloc |
|
> |
|
void config_reader_kernel_1<map_string_string,map_string_void,tokenizer>:: |
|
get_keys ( |
|
std::vector<std::string,alloc>& keys |
|
) const |
|
{ |
|
keys.clear(); |
|
key_table.reset(); |
|
while (key_table.move_next()) |
|
{ |
|
keys.push_back(key_table.element().key()); |
|
} |
|
} |
|
|
|
|
|
|
|
template < |
|
typename map_string_string, |
|
typename map_string_void, |
|
typename tokenizer |
|
> |
|
template < |
|
typename alloc |
|
> |
|
void config_reader_kernel_1<map_string_string,map_string_void,tokenizer>:: |
|
get_keys ( |
|
std_vector_c<std::string,alloc>& keys |
|
) const |
|
{ |
|
keys.clear(); |
|
key_table.reset(); |
|
while (key_table.move_next()) |
|
{ |
|
keys.push_back(key_table.element().key()); |
|
} |
|
} |
|
|
|
|
|
|
|
template < |
|
typename map_string_string, |
|
typename map_string_void, |
|
typename tokenizer |
|
> |
|
template < |
|
typename queue_of_strings |
|
> |
|
void config_reader_kernel_1<map_string_string,map_string_void,tokenizer>:: |
|
get_blocks ( |
|
queue_of_strings& blocks |
|
) const |
|
{ |
|
blocks.clear(); |
|
block_table.reset(); |
|
std::string temp; |
|
while (block_table.move_next()) |
|
{ |
|
temp = block_table.element().key(); |
|
blocks.enqueue(temp); |
|
} |
|
} |
|
|
|
|
|
|
|
template < |
|
typename map_string_string, |
|
typename map_string_void, |
|
typename tokenizer |
|
> |
|
template < |
|
typename alloc |
|
> |
|
void config_reader_kernel_1<map_string_string,map_string_void,tokenizer>:: |
|
get_blocks ( |
|
std::vector<std::string,alloc>& blocks |
|
) const |
|
{ |
|
blocks.clear(); |
|
block_table.reset(); |
|
while (block_table.move_next()) |
|
{ |
|
blocks.push_back(block_table.element().key()); |
|
} |
|
} |
|
|
|
|
|
|
|
template < |
|
typename map_string_string, |
|
typename map_string_void, |
|
typename tokenizer |
|
> |
|
template < |
|
typename alloc |
|
> |
|
void config_reader_kernel_1<map_string_string,map_string_void,tokenizer>:: |
|
get_blocks ( |
|
std_vector_c<std::string,alloc>& blocks |
|
) const |
|
{ |
|
blocks.clear(); |
|
block_table.reset(); |
|
while (block_table.move_next()) |
|
{ |
|
blocks.push_back(block_table.element().key()); |
|
} |
|
} |
|
|
|
|
|
|
|
} |
|
|
|
#endif |
|
|
|
|