00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
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 }
00043
00044
00049 std::string claw::configuration_file::syntax_description::make_comment
00050 ( const std::string& value ) const
00051 {
00052 return comment + (' ' + value);
00053 }
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 }
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 }
00077
00078
00079
00080
00081
00082
00083 const std::string claw::configuration_file::s_unknow_field_value;
00084
00085
00089 claw::configuration_file::configuration_file()
00090 {
00091
00092 }
00093
00094
00100 claw::configuration_file::configuration_file
00101 ( std::istream& is, const syntax_description& syntax )
00102 {
00103 open(is, syntax);
00104 }
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 }
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 }
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 }
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 }
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 }
00207
00208
00215 bool claw::configuration_file::has_field( const std::string& field ) const
00216 {
00217 return field_begin( field ) != field_end( field );
00218 }
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 }
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 }
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 }
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 }
00285
00286
00291 void claw::configuration_file::clear_section( const std::string& section )
00292 {
00293 m_sections.erase(section);
00294 }
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 }
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 }
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 }
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 }
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 }
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 }
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 }
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 }
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 }
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 }
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 }
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 }
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 }
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 }
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 }