configuration_file.cpp
Go to the documentation of this file.
/*
CLAW - a C++ Library Absolutely Wonderful
CLAW is a free library without any particular aim but being useful to
anyone.
Copyright (C) 2005-2011 Julien Jorge
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
contact: julien.jorge@gamned.org
*/
#include <claw/configuration_file.hpp>
#include <claw/assert.hpp>
#include <claw/string_algorithm.hpp>
/*----------------------------------------------------------------------------*/
claw::configuration_file::syntax_description::syntax_description()
: comment('#'), assignment('='), section_name('[', ']')
{
} // configuration_file::syntax_description::syntax_description()
/*----------------------------------------------------------------------------*/
std::string claw::configuration_file::syntax_description::make_comment
( const std::string& value ) const
{
return comment + (' ' + value);
} // configuration_file::syntax_description::make_comment()
/*----------------------------------------------------------------------------*/
std::string claw::configuration_file::syntax_description::make_assignment
( const std::string& key, const std::string& value ) const
{
return key + ' ' + assignment + ' ' + value;
} // configuration_file::syntax_description::make_assignment()
/*----------------------------------------------------------------------------*/
std::string claw::configuration_file::syntax_description::make_section_name
( const std::string& name ) const
{
return section_name.first + name + section_name.second;
} // configuration_file::syntax_description::make_section_name()
/*----------------------------------------------------------------------------*/
// empty string
const std::string claw::configuration_file::s_unknow_field_value;
/*----------------------------------------------------------------------------*/
claw::configuration_file::configuration_file()
{
// nothing to do
} // configuration_file::configuration_file()
/*----------------------------------------------------------------------------*/
claw::configuration_file::configuration_file
( std::istream& is, const syntax_description& syntax )
{
open(is, syntax);
} // configuration_file::configuration_file()
/*----------------------------------------------------------------------------*/
bool claw::configuration_file::open
( std::istream& is, const syntax_description& syntax )
{
std::string line;
bool ok = true;
section_content_ptr current_section = &m_noname_section;
while ( get_line(is, syntax, line) && ok )
{
text::trim_right(line, " \t");
if ( !line.empty() )
ok = process_line( line, syntax, current_section );
}
return ok;
} // configuration_file::open()
/*----------------------------------------------------------------------------*/
void claw::configuration_file::save
( std::ostream& os, const syntax_description& syntax )
{
if ( !m_noname_section.empty() )
{
save_section_content( m_noname_section, os, syntax );
os << '\n';
}
file_content::const_iterator it;
for ( it=m_sections.begin(); it!=m_sections.end(); ++it )
{
os << syntax.make_section_name(it->first) << '\n';
save_section_content( it->second, os, syntax );
os << '\n';
}
} // configuration_file::save()
/*----------------------------------------------------------------------------*/
const std::string& claw::configuration_file::operator()
( const std::string& section, const std::string& field ) const
{
file_content::const_iterator sect = m_sections.find(section);
if ( sect == m_sections.end() )
return s_unknow_field_value;
else
{
section_content::const_iterator fld = sect->second.find(field);
if ( fld == sect->second.end() )
return s_unknow_field_value;
else
return fld->second;
}
} // configuration_file::operator()()
/*----------------------------------------------------------------------------*/
const std::string&
claw::configuration_file::operator()( const std::string& field ) const
{
section_content::const_iterator fld = m_noname_section.find(field);
if ( fld == m_noname_section.end() )
return s_unknow_field_value;
else
return fld->second;
} // configuration_file::operator()()
/*----------------------------------------------------------------------------*/
bool claw::configuration_file::has_field
( const std::string& section, const std::string& field ) const
{
return field_begin( section, field ) != field_end( section, field );
} // configuration_file::has_field()
/*----------------------------------------------------------------------------*/
bool claw::configuration_file::has_field( const std::string& field ) const
{
return field_begin( field ) != field_end( field );
} // configuration_file::has_field()
/*----------------------------------------------------------------------------*/
void claw::configuration_file::set_value
( const std::string& section, const std::string& field, const std::string& val )
{
file_content::iterator it = m_sections.find(section);
if ( it!=m_sections.end() )
it->second.erase(field);
add_value(section, field, val);
} // configuration_file::set_value()
/*----------------------------------------------------------------------------*/
void claw::configuration_file::set_value
( const std::string& field, const std::string& val )
{
m_noname_section.erase(field);
add_value(field, val);
} // configuration_file::set_value()
/*----------------------------------------------------------------------------*/
void claw::configuration_file::add_value
( const std::string& section, const std::string& field, const std::string& val )
{
m_sections[section].insert( section_content::value_type(field, val) );
} // configuration_file::add_value()
/*----------------------------------------------------------------------------*/
void claw::configuration_file::add_value
( const std::string& field, const std::string& val )
{
m_noname_section.insert( section_content::value_type(field, val) );
} // configuration_file::add_value()
/*----------------------------------------------------------------------------*/
void claw::configuration_file::clear_section( const std::string& section )
{
m_sections.erase(section);
} // configuration_file::clear_section()
/*----------------------------------------------------------------------------*/
claw::configuration_file::const_field_iterator
claw::configuration_file::field_begin
( const std::string& section, const std::string& field ) const
{
file_content::const_iterator it = m_sections.find(section);
if (it == m_sections.end())
return const_field_iterator();
else
return const_field_iterator( it->second.lower_bound(field) );
} // configuration_file::field_begin()
/*----------------------------------------------------------------------------*/
claw::configuration_file::const_field_iterator
claw::configuration_file::field_end
( const std::string& section, const std::string& field ) const
{
file_content::const_iterator it = m_sections.find(section);
if (it == m_sections.end())
return const_field_iterator();
else
return const_field_iterator( it->second.upper_bound(field) );
} // configuration_file::field_end()
/*----------------------------------------------------------------------------*/
claw::configuration_file::const_field_iterator
claw::configuration_file::field_begin( const std::string& field ) const
{
return const_field_iterator( m_noname_section.lower_bound(field) );
} // configuration_file::field_begin()
/*----------------------------------------------------------------------------*/
claw::configuration_file::const_field_iterator
claw::configuration_file::field_end( const std::string& field ) const
{
return const_field_iterator( m_noname_section.upper_bound(field) );
} // configuration_file::field_end()
/*----------------------------------------------------------------------------*/
claw::configuration_file::const_section_iterator
claw::configuration_file::section_begin() const
{
return const_section_iterator( m_noname_section.begin() );
} // configuration_file::section_begin()
/*----------------------------------------------------------------------------*/
claw::configuration_file::const_section_iterator
claw::configuration_file::section_end() const
{
return const_section_iterator( m_noname_section.end() );
} // configuration_file::section_end()
/*----------------------------------------------------------------------------*/
claw::configuration_file::const_section_iterator
claw::configuration_file::section_begin( const std::string& section ) const
{
file_content::const_iterator it = m_sections.find(section);
if (it == m_sections.end())
return const_section_iterator();
else
return const_section_iterator( it->second.begin() );
} // configuration_file::section_begin()
/*----------------------------------------------------------------------------*/
claw::configuration_file::const_section_iterator
claw::configuration_file::section_end( const std::string& section ) const
{
file_content::const_iterator it = m_sections.find(section);
if (it == m_sections.end())
return const_section_iterator();
else
return const_section_iterator( it->second.end() );
} // configuration_file::section_end()
/*----------------------------------------------------------------------------*/
claw::configuration_file::const_file_iterator
claw::configuration_file::file_begin() const
{
return const_file_iterator( m_sections.begin() );
} // configuration_file::file_begin()
/*----------------------------------------------------------------------------*/
claw::configuration_file::const_file_iterator
claw::configuration_file::file_end() const
{
return const_file_iterator( m_sections.end() );
} // configuration_file::file_end()
/*----------------------------------------------------------------------------*/
bool claw::configuration_file::get_line
( std::istream& is, const syntax_description& syntax, std::string& line ) const
{
bool result = static_cast<bool>(text::getline(is, line));
if ( result )
{
text::trim_left(line, " \t");
escape_line(is, syntax, line);
}
return result;
} // configuration_file::get_line()
/*----------------------------------------------------------------------------*/
bool claw::configuration_file::process_line
( const std::string& line, const syntax_description& syntax,
section_content_ptr& section )
{
CLAW_PRECOND( !line.empty() );
bool result = true;
if ( (line.size() >= 2)
&& (line[0] == syntax.section_name.first)
&& ( *(--line.end()) == syntax.section_name.second) )
{
std::string section_name( line.substr(1, line.length()-2) );
text::trim( section_name, " \t" );
section = &m_sections[section_name];
}
else
{
std::string::size_type pos = line.find_first_of(syntax.assignment);
if (pos != std::string::npos)
{
std::string field( line.substr(0, pos) );
std::string value;
if ( (pos+1) != line.length() )
{
value = ( line.substr(pos+1) );
text::trim(value, " \t");
}
text::trim(field, " \t");
section->insert( section_content::value_type(field, value) );
}
else
result = false;
}
return result;
} // configuration_file::process_line()
/*----------------------------------------------------------------------------*/
void claw::configuration_file::escape_line
( std::istream& is, const syntax_description& syntax, std::string& line ) const
{
std::string input_line(line);
std::string::iterator it, last;
bool stop = false;
line.clear();
last = input_line.begin();
for (it = last; (it!=input_line.end()) && !stop; )
if (*it == syntax.comment)
stop = true;
else if (*it == '\\')
{
line += std::string(last, it);
++it;
if ( it == input_line.end() )
{
std::string remaining;
get_line(is, syntax, remaining);
line += remaining;
}
else
{
escape_char(*it, syntax, line);
++it;
}
last = it;
}
else
++it;
line += std::string(last, it);
} // configuration_file::escape_line()
/*----------------------------------------------------------------------------*/
void claw::configuration_file::escape_char
( char escaped, const syntax_description& syntax, std::string& str ) const
{
switch (escaped)
{
case '\'' : str += "\'"; break;
case '\"' : str += "\""; break;
case '\\' : str += "\\"; break;
case 'a' : str += "\a"; break;
case 'b' : str += "\b"; break;
case 'f' : str += "\f"; break;
case 'n' : str += "\n"; break;
case 'r' : str += "\r"; break;
case 't' : str += "\t"; break;
case 'v' : str += "\v"; break;
default :
if ( escaped == syntax.comment )
str += syntax.comment;
else
(str += "\\") += escaped;
}
} // configuration_file::escape_char()
/*----------------------------------------------------------------------------*/
void claw::configuration_file::save_section_content
( const section_content& c, std::ostream& os,
const syntax_description& syntax ) const
{
section_content::const_iterator it;
for (it=c.begin(); it!=c.end(); ++it)
os << syntax.make_assignment(it->first, it->second) << '\n';
} // configuration_file::save_section_content()
claw::configuration_file::section_end
const_section_iterator section_end() const
Get an iterator past the last field name of a section.
Definition: configuration_file.cpp:377
claw::configuration_file::file_end
const_file_iterator file_end() const
Get an iterator just past the last named section.
Definition: configuration_file.cpp:429
claw::configuration_file::syntax_description::make_section_name
std::string make_section_name(const std::string &name) const
Create a section name from a string.
Definition: configuration_file.cpp:73
claw::configuration_file::field_begin
const_field_iterator field_begin(const std::string &section, const std::string &field) const
Get an iterator on the first value set for a field.
Definition: configuration_file.cpp:304
claw::configuration_file::syntax_description::make_comment
std::string make_comment(const std::string &value) const
Create a comment from a string.
Definition: configuration_file.cpp:50
claw::configuration_file::syntax_description::make_assignment
std::string make_assignment(const std::string &key, const std::string &value) const
Make an assignment of a value to a key.
Definition: configuration_file.cpp:62
claw::configuration_file::syntax_description::assignment
char assignment
Symbol used to assign a value to a field.
Definition: configuration_file.hpp:69
configuration_file.hpp
A class to get the content of a configuration file.
claw::wrapped_iterator_by_category
Base class for wrapped iterators.
Definition: iterator.hpp:45
claw::configuration_file::syntax_description::syntax_description
syntax_description()
Default constructor.
Definition: configuration_file.cpp:38
claw::configuration_file::const_section_iterator
claw::wrapped_iterator< const section_content::key_type, section_content::const_iterator, const_pair_first< section_content::value_type > >::iterator_type const_section_iterator
Iterator on the fields of a section.
Definition: configuration_file.hpp:99
claw::configuration_file::file_begin
const_file_iterator file_begin() const
Get an iterator on the first named section.
Definition: configuration_file.cpp:419
claw::configuration_file::syntax_description::section_name
paired_symbol section_name
Pair of symbols around a section name.
Definition: configuration_file.hpp:72
claw::configuration_file::open
bool open(std::istream &is, const syntax_description &syntax=syntax_description())
Read the configuration from a stream.
Definition: configuration_file.cpp:113
claw::configuration_file::add_value
void add_value(const std::string &section, const std::string &field, const std::string &val)
Add a value to a field.
Definition: configuration_file.cpp:267
assert.hpp
Some assert macros to strengthen you code.
claw::configuration_file::operator()
const std::string & operator()(const std::string &section, const std::string &field) const
Get the value of a field.
Definition: configuration_file.cpp:161
claw::configuration_file::save
void save(std::ostream &os, const syntax_description &syntax=syntax_description())
Write the configuration in a stream.
Definition: configuration_file.cpp:137
claw::configuration_file::clear_section
void clear_section(const std::string &section)
Remove a section and its fields.
Definition: configuration_file.cpp:291
claw::configuration_file::configuration_file
configuration_file()
Default constructor.
Definition: configuration_file.cpp:89
claw::configuration_file::section_begin
const_section_iterator section_begin() const
Get an iterator on the field names of a section.
Definition: configuration_file.cpp:365
claw::configuration_file::has_field
bool has_field(const std::string &section, const std::string &field) const
Tell if a field exists.
Definition: configuration_file.cpp:203
claw::configuration_file::syntax_description
This class tells us how to parse the input file.
Definition: configuration_file.hpp:50
claw::configuration_file::set_value
void set_value(const std::string &section, const std::string &field, const std::string &val)
Set the value of a field.
Definition: configuration_file.cpp:230
claw::configuration_file::field_end
const_field_iterator field_end(const std::string &section, const std::string &field) const
Get an iterator past the last value set for a field.
Definition: configuration_file.cpp:322
claw::configuration_file::syntax_description::comment
char comment
Symbol used to comment the rest of the line.
Definition: configuration_file.hpp:66
claw::configuration_file::const_field_iterator
This class is an iterator on the values set for a same field name.
Definition: configuration_file.hpp:104
CLAW_PRECOND
#define CLAW_PRECOND(b)
Abort the program if a precondition is not true.
Definition: assert.hpp:98
string_algorithm.hpp
Generic algorithms on strings.
claw::configuration_file::const_file_iterator
claw::wrapped_iterator< const file_content::key_type, file_content::const_iterator, const_pair_first< file_content::value_type > >::iterator_type const_file_iterator
Iterator on the name of the sections.
Definition: configuration_file.hpp:92