CLAW Library (a C++ Library Absolutely Wonderful) 1.5.5

configuration_file.cpp

Go to the documentation of this file.
00001 /*
00002   CLAW - a C++ Library Absolutely Wonderful
00003 
00004   CLAW is a free library without any particular aim but being useful to
00005   anyone.
00006 
00007   Copyright (C) 2005-2010 Julien Jorge
00008 
00009   This library is free software; you can redistribute it and/or
00010   modify it under the terms of the GNU Lesser General Public
00011   License as published by the Free Software Foundation; either
00012   version 2.1 of the License, or (at your option) any later version.
00013 
00014   This library is distributed in the hope that it will be useful,
00015   but WITHOUT ANY WARRANTY; without even the implied warranty of
00016   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00017   Lesser General Public License for more details.
00018 
00019   You should have received a copy of the GNU Lesser General Public
00020   License along with this library; if not, write to the Free Software
00021   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00022 
00023   contact: julien_jorge@yahoo.fr
00024 */
00030 #include <claw/configuration_file.hpp>
00031 #include <claw/assert.hpp>
00032 #include <claw/string_algorithm.hpp>
00033 
00034 /*----------------------------------------------------------------------------*/
00038 claw::configuration_file::syntax_description::syntax_description()
00039   : comment('#'), assignment('='), section_name('[', ']')
00040 {
00041 
00042 } // configuration_file::syntax_description::syntax_description()
00043 
00044 /*----------------------------------------------------------------------------*/
00049 std::string claw::configuration_file::syntax_description::make_comment
00050 ( const std::string& value ) const
00051 {
00052   return comment + (' ' + value);
00053 } // configuration_file::syntax_description::make_comment()
00054 
00055 /*----------------------------------------------------------------------------*/
00061 std::string claw::configuration_file::syntax_description::make_assignment
00062 ( const std::string& key, const std::string& value ) const
00063 {
00064   return key + ' ' + assignment + ' ' + value;
00065 } // configuration_file::syntax_description::make_assignment()
00066 
00067 /*----------------------------------------------------------------------------*/
00072 std::string claw::configuration_file::syntax_description::make_section_name
00073 ( const std::string& name ) const
00074 {
00075   return section_name.first + name + section_name.second;
00076 } // configuration_file::syntax_description::make_section_name()
00077 
00078 
00079 
00080 
00081 /*----------------------------------------------------------------------------*/
00082 // empty string
00083 const std::string claw::configuration_file::s_unknow_field_value;
00084 
00085 /*----------------------------------------------------------------------------*/
00089 claw::configuration_file::configuration_file()
00090 {
00091   // nothing to do
00092 } // configuration_file::configuration_file()
00093 
00094 /*----------------------------------------------------------------------------*/
00100 claw::configuration_file::configuration_file
00101 ( std::istream& is, const syntax_description& syntax )
00102 {
00103   open(is, syntax);
00104 } // configuration_file::configuration_file()
00105 
00106 /*----------------------------------------------------------------------------*/
00112 bool claw::configuration_file::open
00113 ( std::istream& is, const syntax_description& syntax )
00114 {
00115   std::string line;
00116   bool ok = true;
00117   section_content_ptr current_section = &m_noname_section;
00118 
00119   while ( get_line(is, syntax, line) && ok )
00120     {
00121       text::trim_right(line, " \t");
00122 
00123       if ( !line.empty() )
00124         ok = process_line( line, syntax, current_section );
00125     }
00126 
00127   return ok;
00128 } // configuration_file::open()
00129 
00130 /*----------------------------------------------------------------------------*/
00136 void claw::configuration_file::save
00137 ( std::ostream& os, const syntax_description& syntax )
00138 {
00139   if ( !m_noname_section.empty() )
00140     {
00141       save_section_content( m_noname_section, os, syntax );
00142       os << '\n';
00143     }
00144 
00145   file_content::const_iterator it;
00146   for ( it=m_sections.begin(); it!=m_sections.end(); ++it )
00147     {
00148       os << syntax.make_section_name(it->first) << '\n';
00149       save_section_content( it->second, os, syntax );
00150       os << '\n';
00151     }
00152 } // configuration_file::save()
00153 
00154 /*----------------------------------------------------------------------------*/
00160 const std::string& claw::configuration_file::operator()
00161   ( const std::string& section, const std::string& field ) const
00162 {
00163   file_content::const_iterator sect = m_sections.find(section);
00164 
00165   if ( sect == m_sections.end() )
00166     return s_unknow_field_value;
00167   else
00168     {
00169       section_content::const_iterator fld = sect->second.find(field);
00170 
00171       if ( fld == sect->second.end() )
00172         return s_unknow_field_value;
00173       else
00174         return fld->second;
00175     }
00176 } // configuration_file::operator()()
00177 
00178 /*----------------------------------------------------------------------------*/
00185 const std::string&
00186 claw::configuration_file::operator()( const std::string& field ) const
00187 {
00188   section_content::const_iterator fld = m_noname_section.find(field);
00189 
00190   if ( fld == m_noname_section.end() )
00191     return s_unknow_field_value;
00192   else
00193     return fld->second;
00194 } // configuration_file::operator()()
00195 
00196 /*----------------------------------------------------------------------------*/
00202 bool claw::configuration_file::has_field
00203 ( const std::string& section, const std::string& field ) const
00204 {
00205   return field_begin( section, field ) != field_end( section, field );
00206 } // configuration_file::has_field()
00207 
00208 /*----------------------------------------------------------------------------*/
00215 bool claw::configuration_file::has_field( const std::string& field ) const
00216 {
00217   return field_begin( field ) != field_end( field );
00218 } // configuration_file::has_field()
00219 
00220 /*----------------------------------------------------------------------------*/
00229 void claw::configuration_file::set_value
00230 ( const std::string& section, const std::string& field, const std::string& val )
00231 {
00232   file_content::iterator it = m_sections.find(section);
00233 
00234   if ( it!=m_sections.end() )
00235     it->second.erase(field);
00236 
00237   add_value(section, field, val);
00238 } // configuration_file::set_value()
00239 
00240 /*----------------------------------------------------------------------------*/
00250 void claw::configuration_file::set_value
00251 ( const std::string& field, const std::string& val )
00252 {
00253   m_noname_section.erase(field);
00254   add_value(field, val);
00255 } // configuration_file::set_value()
00256 
00257 /*----------------------------------------------------------------------------*/
00266 void claw::configuration_file::add_value
00267 ( const std::string& section, const std::string& field, const std::string& val )
00268 {
00269   m_sections[section].insert( section_content::value_type(field, val) );
00270 } // configuration_file::add_value()
00271 
00272 /*----------------------------------------------------------------------------*/
00280 void claw::configuration_file::add_value
00281 ( const std::string& field, const std::string& val )
00282 {
00283   m_noname_section.insert( section_content::value_type(field, val) );
00284 } // configuration_file::add_value()
00285 
00286 /*----------------------------------------------------------------------------*/
00291 void claw::configuration_file::clear_section( const std::string& section )
00292 {
00293   m_sections.erase(section);
00294 } // configuration_file::clear_section()
00295 
00296 /*----------------------------------------------------------------------------*/
00302 claw::configuration_file::const_field_iterator
00303 claw::configuration_file::field_begin
00304 ( const std::string& section, const std::string& field ) const
00305 {
00306   file_content::const_iterator it = m_sections.find(section);
00307 
00308   if (it == m_sections.end())
00309     return const_field_iterator();
00310   else
00311     return const_field_iterator( it->second.lower_bound(field) );
00312 } // configuration_file::field_begin()
00313 
00314 /*----------------------------------------------------------------------------*/
00320 claw::configuration_file::const_field_iterator
00321 claw::configuration_file::field_end
00322 ( const std::string& section, const std::string& field ) const
00323 {
00324   file_content::const_iterator it = m_sections.find(section);
00325 
00326   if (it == m_sections.end())
00327     return const_field_iterator();
00328   else
00329     return const_field_iterator( it->second.upper_bound(field) );
00330 } // configuration_file::field_end()
00331 
00332 /*----------------------------------------------------------------------------*/
00339 claw::configuration_file::const_field_iterator
00340 claw::configuration_file::field_begin( const std::string& field ) const
00341 {
00342   return const_field_iterator( m_noname_section.lower_bound(field) );
00343 } // configuration_file::field_begin()
00344 
00345 /*----------------------------------------------------------------------------*/
00352 claw::configuration_file::const_field_iterator
00353 claw::configuration_file::field_end( const std::string& field ) const
00354 {
00355   return const_field_iterator( m_noname_section.upper_bound(field) );
00356 } // configuration_file::field_end()
00357 
00358 /*----------------------------------------------------------------------------*/
00364 claw::configuration_file::const_section_iterator
00365 claw::configuration_file::section_begin() const
00366 {
00367   return const_section_iterator( m_noname_section.begin() );
00368 } // configuration_file::section_begin()
00369 
00370 /*----------------------------------------------------------------------------*/
00376 claw::configuration_file::const_section_iterator
00377 claw::configuration_file::section_end() const
00378 {
00379   return const_section_iterator( m_noname_section.end() );
00380 } // configuration_file::section_end()
00381 
00382 /*----------------------------------------------------------------------------*/
00387 claw::configuration_file::const_section_iterator
00388 claw::configuration_file::section_begin( const std::string& section ) const
00389 {
00390   file_content::const_iterator it = m_sections.find(section);
00391 
00392   if (it == m_sections.end())
00393     return const_section_iterator();
00394   else
00395     return const_section_iterator( it->second.begin() );
00396 } // configuration_file::section_begin()
00397 
00398 /*----------------------------------------------------------------------------*/
00403 claw::configuration_file::const_section_iterator
00404 claw::configuration_file::section_end( const std::string& section ) const
00405 {
00406   file_content::const_iterator it = m_sections.find(section);
00407 
00408   if (it == m_sections.end())
00409     return const_section_iterator();
00410   else
00411     return const_section_iterator( it->second.end() );
00412 } // configuration_file::section_end()
00413 
00414 /*----------------------------------------------------------------------------*/
00418 claw::configuration_file::const_file_iterator
00419 claw::configuration_file::file_begin() const
00420 {
00421   return const_file_iterator( m_sections.begin() );
00422 } // configuration_file::file_begin()
00423 
00424 /*----------------------------------------------------------------------------*/
00428 claw::configuration_file::const_file_iterator
00429 claw::configuration_file::file_end() const
00430 {
00431   return const_file_iterator( m_sections.end() );
00432 } // configuration_file::file_end()
00433 
00434 /*----------------------------------------------------------------------------*/
00441 bool claw::configuration_file::get_line
00442 ( std::istream& is, const syntax_description& syntax, std::string& line ) const
00443 {
00444   bool result = text::getline(is, line);
00445 
00446   if ( result )
00447     {
00448       text::trim_left(line, " \t");
00449       escape_line(is, syntax, line);
00450     }
00451 
00452   return result;
00453 } // configuration_file::get_line()
00454 
00455 /*----------------------------------------------------------------------------*/
00462 bool claw::configuration_file::process_line
00463 ( const std::string& line, const syntax_description& syntax,
00464   section_content_ptr& section )
00465 {
00466   CLAW_PRECOND( !line.empty() );
00467 
00468   bool result = true;
00469 
00470   if ( (line.size() >= 2)
00471        && (line[0] == syntax.section_name.first)
00472        && ( *(--line.end()) == syntax.section_name.second) )
00473     {
00474       std::string section_name( line.substr(1, line.length()-2) );
00475       text::trim( section_name, " \t" );
00476       section = &m_sections[section_name];
00477     }
00478   else
00479     {
00480       std::string::size_type pos = line.find_first_of(syntax.assignment);
00481 
00482       if (pos != std::string::npos)
00483         {
00484           std::string field( line.substr(0, pos) );
00485           std::string value;
00486 
00487           if ( (pos+1) != line.length() )
00488             {
00489               value = ( line.substr(pos+1) );
00490               text::trim(value, " \t");
00491             }
00492 
00493           text::trim(field, " \t");
00494           section->insert( section_content::value_type(field, value) );
00495         }
00496       else
00497         result = false;
00498     }
00499 
00500   return result;
00501 } // configuration_file::process_line()
00502 
00503 /*----------------------------------------------------------------------------*/
00510 void claw::configuration_file::escape_line
00511 ( std::istream& is, const syntax_description& syntax, std::string& line ) const
00512 {
00513   std::string input_line(line);
00514   std::string::iterator it, last;
00515   bool stop = false;
00516 
00517   line.clear();
00518   last = input_line.begin();
00519 
00520   for (it = last; (it!=input_line.end()) && !stop; )
00521     if (*it == syntax.comment)
00522       stop = true;
00523     else if (*it == '\\')
00524       {
00525         line += std::string(last, it);
00526         ++it;
00527 
00528         if ( it == input_line.end() )
00529           {
00530             std::string remaining;
00531             get_line(is, syntax, remaining);
00532             line += remaining;
00533           }
00534         else
00535           {
00536             escape_char(*it, syntax, line);
00537             ++it;
00538           }
00539 
00540         last = it;
00541       }
00542     else
00543       ++it;
00544 
00545   line += std::string(last, it);
00546 } // configuration_file::escape_line()
00547 
00548 /*----------------------------------------------------------------------------*/
00555 void claw::configuration_file::escape_char
00556 ( char escaped, const syntax_description& syntax, std::string& str ) const
00557 {
00558   switch (escaped)
00559     {
00560     case '\'' : str += "\'"; break;
00561     case '\"' : str += "\""; break;
00562     case '\\' : str += "\\"; break;
00563     case 'a' : str += "\a"; break;
00564     case 'b' : str += "\b"; break;
00565     case 'f' : str += "\f"; break;
00566     case 'n' : str += "\n"; break;
00567     case 'r' : str += "\r"; break;
00568     case 't' : str += "\t"; break;
00569     case 'v' : str += "\v"; break;
00570     default :
00571       if ( escaped == syntax.comment )
00572         str += syntax.comment;
00573       else
00574         (str += "\\") += escaped;
00575     }
00576 } // configuration_file::escape_char()
00577 
00578 /*----------------------------------------------------------------------------*/
00585 void claw::configuration_file::save_section_content
00586 ( const section_content& c, std::ostream& os,
00587   const syntax_description& syntax ) const
00588 {
00589   section_content::const_iterator it;
00590 
00591   for (it=c.begin(); it!=c.end(); ++it)
00592     os << syntax.make_assignment(it->first, it->second) << '\n';
00593 } // configuration_file::save_section_content()