claw  1.9.0
configuration_file.cpp
Go to the documentation of this file.
1 /*
2  CLAW - a C++ Library Absolutely Wonderful
3 
4  CLAW is a free library without any particular aim but being useful to
5  anyone.
6 
7  Copyright (C) 2005-2011 Julien Jorge
8 
9  This library is free software; you can redistribute it and/or
10  modify it under the terms of the GNU Lesser General Public
11  License as published by the Free Software Foundation; either
12  version 2.1 of the License, or (at your option) any later version.
13 
14  This library is distributed in the hope that it will be useful,
15  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17  Lesser General Public License for more details.
18 
19  You should have received a copy of the GNU Lesser General Public
20  License along with this library; if not, write to the Free Software
21  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 
23  contact: julien.jorge@stuff-o-matic.com
24 */
31 
32 #include <claw/assert.hpp>
34 
39  : comment('#')
40  , assignment('=')
41  , section_name('[', ']')
42 {}
43 
49  const std::string& value) const
50 {
51  return comment + (' ' + value);
52 }
53 
60  const std::string& key, const std::string& value) const
61 {
62  return key + ' ' + assignment + ' ' + value;
63 }
64 
70  const std::string& name) const
71 {
72  return section_name.first + name + section_name.second;
73 }
74 
75 // empty string
76 const std::string claw::configuration_file::s_unknow_field_value;
77 
82 {
83  // nothing to do
84 }
85 
92  const syntax_description& syntax)
93 {
94  open(is, syntax);
95 }
96 
102 bool claw::configuration_file::open(std::istream& is,
103  const syntax_description& syntax)
104 {
105  std::string line;
106  bool ok = true;
107  section_content_ptr current_section = &m_noname_section;
108 
109  while(get_line(is, syntax, line) && ok)
110  {
111  text::trim_right(line, " \t");
112 
113  if(!line.empty())
114  ok = process_line(line, syntax, current_section);
115  }
116 
117  return ok;
118 }
119 
125 void claw::configuration_file::save(std::ostream& os,
126  const syntax_description& syntax)
127 {
128  if(!m_noname_section.empty())
129  {
130  save_section_content(m_noname_section, os, syntax);
131  os << '\n';
132  }
133 
134  file_content::const_iterator it;
135  for(it = m_sections.begin(); it != m_sections.end(); ++it)
136  {
137  os << syntax.make_section_name(it->first) << '\n';
138  save_section_content(it->second, os, syntax);
139  os << '\n';
140  }
141 }
142 
148 const std::string&
149 claw::configuration_file::operator()(const std::string& section,
150  const std::string& field) const
151 {
152  file_content::const_iterator sect = m_sections.find(section);
153 
154  if(sect == m_sections.end())
155  return s_unknow_field_value;
156  else
157  {
158  section_content::const_iterator fld = sect->second.find(field);
159 
160  if(fld == sect->second.end())
161  return s_unknow_field_value;
162  else
163  return fld->second;
164  }
165 }
166 
173 const std::string&
174 claw::configuration_file::operator()(const std::string& field) const
175 {
176  section_content::const_iterator fld = m_noname_section.find(field);
177 
178  if(fld == m_noname_section.end())
179  return s_unknow_field_value;
180  else
181  return fld->second;
182 }
183 
189 bool claw::configuration_file::has_field(const std::string& section,
190  const std::string& field) const
191 {
192  return field_begin(section, field) != field_end(section, field);
193 }
194 
201 bool claw::configuration_file::has_field(const std::string& field) const
202 {
203  return field_begin(field) != field_end(field);
204 }
205 
214 void claw::configuration_file::set_value(const std::string& section,
215  const std::string& field,
216  const std::string& val)
217 {
218  file_content::iterator it = m_sections.find(section);
219 
220  if(it != m_sections.end())
221  it->second.erase(field);
222 
223  add_value(section, field, val);
224 }
225 
235 void claw::configuration_file::set_value(const std::string& field,
236  const std::string& val)
237 {
238  m_noname_section.erase(field);
239  add_value(field, val);
240 }
241 
250 void claw::configuration_file::add_value(const std::string& section,
251  const std::string& field,
252  const std::string& val)
253 {
254  m_sections[section].insert(section_content::value_type(field, val));
255 }
256 
264 void claw::configuration_file::add_value(const std::string& field,
265  const std::string& val)
266 {
267  m_noname_section.insert(section_content::value_type(field, val));
268 }
269 
274 void claw::configuration_file::clear_section(const std::string& section)
275 {
276  m_sections.erase(section);
277 }
278 
285 claw::configuration_file::field_begin(const std::string& section,
286  const std::string& field) const
287 {
288  file_content::const_iterator it = m_sections.find(section);
289 
290  if(it == m_sections.end())
291  return const_field_iterator();
292  else
293  return const_field_iterator(it->second.lower_bound(field));
294 }
295 
302 claw::configuration_file::field_end(const std::string& section,
303  const std::string& field) const
304 {
305  file_content::const_iterator it = m_sections.find(section);
306 
307  if(it == m_sections.end())
308  return const_field_iterator();
309  else
310  return const_field_iterator(it->second.upper_bound(field));
311 }
312 
320 claw::configuration_file::field_begin(const std::string& field) const
321 {
322  return const_field_iterator(m_noname_section.lower_bound(field));
323 }
324 
332 claw::configuration_file::field_end(const std::string& field) const
333 {
334  return const_field_iterator(m_noname_section.upper_bound(field));
335 }
336 
344 {
345  return const_section_iterator(m_noname_section.begin());
346 }
347 
355 {
356  return const_section_iterator(m_noname_section.end());
357 }
358 
364 claw::configuration_file::section_begin(const std::string& section) const
365 {
366  file_content::const_iterator it = m_sections.find(section);
367 
368  if(it == m_sections.end())
369  return const_section_iterator();
370  else
371  return const_section_iterator(it->second.begin());
372 }
373 
379 claw::configuration_file::section_end(const std::string& section) const
380 {
381  file_content::const_iterator it = m_sections.find(section);
382 
383  if(it == m_sections.end())
384  return const_section_iterator();
385  else
386  return const_section_iterator(it->second.end());
387 }
388 
394 {
395  return const_file_iterator(m_sections.begin());
396 }
397 
403 {
404  return const_file_iterator(m_sections.end());
405 }
406 
413 bool claw::configuration_file::get_line(std::istream& is,
414  const syntax_description& syntax,
415  std::string& line) const
416 {
417  const bool result(text::getline(is, line));
418 
419  if(result)
420  {
421  text::trim_left(line, " \t");
422  escape_line(is, syntax, line);
423  }
424 
425  return result;
426 }
427 
434 bool claw::configuration_file::process_line(const std::string& line,
435  const syntax_description& syntax,
436  section_content_ptr& section)
437 {
438  CLAW_PRECOND(!line.empty());
439 
440  bool result = true;
441 
442  if((line.size() >= 2) && (line[0] == syntax.section_name.first)
443  && (*(--line.end()) == syntax.section_name.second))
444  {
445  std::string section_name(line.substr(1, line.length() - 2));
446  text::trim(section_name, " \t");
447  section = &m_sections[section_name];
448  }
449  else
450  {
451  std::string::size_type pos = line.find_first_of(syntax.assignment);
452 
453  if(pos != std::string::npos)
454  {
455  std::string field(line.substr(0, pos));
456  std::string value;
457 
458  if((pos + 1) != line.length())
459  {
460  value = (line.substr(pos + 1));
461  text::trim(value, " \t");
462  }
463 
464  text::trim(field, " \t");
465  section->insert(section_content::value_type(field, value));
466  }
467  else
468  result = false;
469  }
470 
471  return result;
472 }
473 
480 void claw::configuration_file::escape_line(std::istream& is,
481  const syntax_description& syntax,
482  std::string& line) const
483 {
484  std::string input_line(line);
485  std::string::iterator it, last;
486  bool stop = false;
487 
488  line.clear();
489  last = input_line.begin();
490 
491  for(it = last; (it != input_line.end()) && !stop;)
492  if(*it == syntax.comment)
493  stop = true;
494  else if(*it == '\\')
495  {
496  line += std::string(last, it);
497  ++it;
498 
499  if(it == input_line.end())
500  {
501  std::string remaining;
502  get_line(is, syntax, remaining);
503  line += remaining;
504  }
505  else
506  {
507  escape_char(*it, syntax, line);
508  ++it;
509  }
510 
511  last = it;
512  }
513  else
514  ++it;
515 
516  line += std::string(last, it);
517 }
518 
525 void claw::configuration_file::escape_char(char escaped,
526  const syntax_description& syntax,
527  std::string& str) const
528 {
529  switch(escaped)
530  {
531  case '\'':
532  str += "\'";
533  break;
534  case '\"':
535  str += "\"";
536  break;
537  case '\\':
538  str += "\\";
539  break;
540  case 'a':
541  str += "\a";
542  break;
543  case 'b':
544  str += "\b";
545  break;
546  case 'f':
547  str += "\f";
548  break;
549  case 'n':
550  str += "\n";
551  break;
552  case 'r':
553  str += "\r";
554  break;
555  case 't':
556  str += "\t";
557  break;
558  case 'v':
559  str += "\v";
560  break;
561  default:
562  if(escaped == syntax.comment)
563  str += syntax.comment;
564  else
565  (str += "\\") += escaped;
566  }
567 }
568 
575 void claw::configuration_file::save_section_content(
576  const section_content& c, std::ostream& os,
577  const syntax_description& syntax) const
578 {
579  section_content::const_iterator it;
580 
581  for(it = c.begin(); it != c.end(); ++it)
582  os << syntax.make_assignment(it->first, it->second) << '\n';
583 }
const_section_iterator section_end() const
Get an iterator past the last field name of a section.
const_file_iterator file_end() const
Get an iterator just past the last named section.
std::string make_section_name(const std::string &name) const
Create a section name from a string.
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.
std::string make_comment(const std::string &value) const
Create a comment from a string.
std::string make_assignment(const std::string &key, const std::string &value) const
Make an assignment of a value to a key.
A class to get the content of a configuration file.
Base class for wrapped iterators.
Definition: iterator.hpp:43
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.
const_file_iterator file_begin() const
Get an iterator on the first named section.
bool open(std::istream &is, const syntax_description &syntax=syntax_description())
Read the configuration from a stream.
void add_value(const std::string &section, const std::string &field, const std::string &val)
Add a value to a field.
Some assert macros to strengthen you code.
const std::string & operator()(const std::string &section, const std::string &field) const
Get the value of a field.
void save(std::ostream &os, const syntax_description &syntax=syntax_description())
Write the configuration in a stream.
void clear_section(const std::string &section)
Remove a section and its fields.
configuration_file()
Default constructor.
const_section_iterator section_begin() const
Get an iterator on the field names of a section.
bool has_field(const std::string &section, const std::string &field) const
Tell if a field exists.
This class tells us how to parse the input file.
void set_value(const std::string &section, const std::string &field, const std::string &val)
Set the value of a field.
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.
This class is an iterator on the values set for a same field name.
#define CLAW_PRECOND(b)
Abort the program if a precondition is not true.
Definition: assert.hpp:94
Generic algorithms on strings.
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.