1 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
2 // -*- Mode: C++ -*-
3 //
4 // Copyright (C) 2013-2020 Red Hat, Inc.
5 //
6 // Author: Dodji Seketeli
7 
8 /// @file
9 ///
10 /// This file contains the definitions for the ini file reader used in
11 /// the libabigail library.
12 
13 #include <cassert>
14 #include <cstdlib>
15 #include <utility>
16 #include <memory>
17 #include <fstream>
18 #include <sstream>
19 
20 #include "abg-fwd.h"
21 #include "abg-internal.h"
22 // <headers defining libabigail's API go under here>
23 ABG_BEGIN_EXPORT_DECLARATIONS
24 
25 #include "abg-ini.h"
26 
27 ABG_END_EXPORT_DECLARATIONS
28 // </headers defining libabigail's API>
29 
30 namespace abigail
31 {
32 namespace ini
33 {
34 
35 using std::istream;
36 using std::pair;
37 
38 static bool
39 char_is_white_space(int b);
40 
41 static bool
42 char_is_comment_start(int b);
43 
44 /// Test if a given character is a delimiter.
45 ///
46 ///
47 ///@param b the value of the character to test for.
48 ///
49 ///@param include_white_space if true, consider white spaces as a
50 ///delimiter.
51 ///
52 ///@param include_square_bracket if true, consider square brackets as
53 /// delimiters
54 ///
55 /// @param include_equal if true, consider the equal character ('=')
56 /// as a delimiter.
57 ///
58 /// @return true iff @p b is a delimiter.
59 static bool
char_is_delimiter(int b,bool include_white_space=true,bool include_square_bracket=true,bool include_equal=true)60 char_is_delimiter(int b, bool include_white_space = true,
61 		  bool include_square_bracket = true,
62 		  bool include_equal = true)
63 {
64   return ((include_square_bracket && (b == '['))
65 	  || (include_square_bracket && (b == ']'))
66 	  || b == '{'
67 	  || b == '}'
68 	  || (include_equal && (b == '='))
69 	  || b == ','
70 	  || (include_white_space && char_is_white_space(b))
71 	  || char_is_comment_start(b));
72 }
73 
74 /// Return true iff a given character can be part of a property
75 /// value.
76 ///
77 /// Note that white spaces, square brackets and the equal character can be
78 /// part of a property value.  The reason why we accept the equal
79 /// character is because it can appear in an URL.
80 ///
81 /// @param b the character to test against.
82 ///
83 /// @return true iff @p b is a character that can be part of a
84 /// property value.
85 static bool
char_is_property_value_char(int b)86 char_is_property_value_char(int b)
87 {
88   if (char_is_delimiter(b, /*include_white_space=*/false,
89 			/*include_square_bracket=*/false,
90 			/*include_equal=*/false)
91       || b == '\n')
92     return false;
93   return true;
94 }
95 
96 /// Test if a given character is meant to be part of a section name.
97 ///
98 /// @param b the character to test against.
99 ///
100 /// @return true iff @p b is a character that is meant to be part of
101 /// a section name.
102 static bool
char_is_section_name_char(int b)103 char_is_section_name_char(int b)
104 {
105   if (b == '[' || b == ']' || b == '\n' || char_is_comment_start(b))
106     return false;
107   return true;
108 }
109 
110 /// Test if a given character is meant to be part of a property name.
111 ///
112 /// @param b the character to test against.
113 ///
114 /// @return true iff @p b is a character that is meant to be part of
115 /// a section name.
116 static bool
char_is_property_name_char(int b)117 char_is_property_name_char(int b)
118 {
119   if (char_is_delimiter(b))
120     return false;
121   return true;
122 }
123 
124 /// Test if a given character is meant to be part of a function name.
125 ///
126 /// @param b the character to test against.
127 ///
128 /// @return true iff @p b is a character that is meant to be part of a
129 /// function name.
130 static bool
char_is_function_name_char(int b)131 char_is_function_name_char(int b)
132 {
133   if (char_is_delimiter(b) || b == '(' || b == ')')
134     return false;
135   return true;
136 }
137 
138 /// Test if a given character is meant to be part of a function
139 /// argument.
140 ///
141 /// @param b the character to test against.
142 ///
143 /// @return true iff @p b is a character that is meant to be part of a
144 /// function argument.
145 static bool
char_is_function_argument_char(int b)146 char_is_function_argument_char(int b)
147 {
148   if (char_is_delimiter(b) || b == '(' || b == ')')
149     return false;
150   return true;
151 }
152 
153 /// Test if a given character is meant to be the start of a comment.
154 ///
155 /// @param b the character to test against.
156 ///
157 /// @return true iff @p b is the start of a comment.
158 static bool
char_is_comment_start(int b)159 char_is_comment_start(int b)
160 {return b == ';' || b == '#';}
161 
162 /// Test if a character is meant to be a white space.
163 ///
164 /// @param b the character to test against.
165 ///
166 /// @return true iff @p b is a white space.
167 static bool
char_is_white_space(int b)168 char_is_white_space(int b)
169 {return b == ' ' || b == '\t' || b == '\n';}
170 
171 /// Remove the spaces at the begining and at the end of a given string.
172 ///
173 /// @param str the string to remove leading and trailing white spaces from.
174 ///
175 /// @return the string resulting from the removal of white space from @p str.
176 static string
trim_white_space(const string & str)177 trim_white_space(const string& str)
178 {
179   if (str.empty())
180     return str;
181 
182   unsigned s = 0, e = str.size() -1;
183 
184   for (; s <= e; ++s)
185     if (!char_is_white_space(str[s]))
186       break;
187 
188   for (; e > s; --e)
189     if (!char_is_white_space(str[e]))
190       break;
191 
192   return str.substr(s, e - s + 1);
193 }
194 
195 // <property stuff>
196 
197 /// Private data of @ref property type.
198 struct property::priv
199 {
200   string name_;
201 
privabigail::ini::property::priv202   priv()
203   {}
204 
privabigail::ini::property::priv205   priv(const string& name)
206     : name_(name)
207   {}
208 }; // end struct property::priv
209 
210 /// Constructor of @ref property.
property()211 property::property()
212   : priv_(new priv)
213 {}
214 
215 /// Constructor of @ref property
216 ///
217 /// @param name the name of the property.
property(const string & name)218 property::property(const string& name)
219   : priv_(new priv(name))
220 {}
221 
222 /// Getter of the name of the property.
223 ///
224 /// @return the name of the property.
225 const string&
get_name() const226 property::get_name()const
227 {return priv_->name_;}
228 
229 /// Setter of the name of the property.
230 ///
231 /// @param name the new name of the property.
232 void
set_name(const string & name)233 property::set_name(const string& name)
234 {priv_->name_ = name;}
235 
236 /// Destructor of the property.
~property()237 property::~property()
238 {}
239 // </property stuff>
240 
241 // <property_value stuff>
242 
243 /// Private data for the @ref property_value type.
244 struct property_value::priv
245 {
246   enum property_value::value_kind kind_;
247 
privabigail::ini::property_value::priv248   priv(property_value::value_kind kind = ABSTRACT_PROPERTY_VALUE)
249     : kind_(kind)
250   {}
251 }; // property_value::priv
252 
253 /// Default constructor for the @ref property_value type.
254 ///
255 /// @param kind the of @ref property_value that is being constructed.
property_value()256 property_value::property_value()
257   : priv_(new priv(ABSTRACT_PROPERTY_VALUE))
258 {}
259 
260 /// Constructor for the @ref property_value type.
261 ///
262 /// @param kind the of @ref property_value that is being constructed.
property_value(value_kind kind)263 property_value::property_value(value_kind kind)
264   : priv_(new priv(kind))
265 {}
266 
267 /// Getter for the kind of the @ref property_value type.
268 ///
269 /// @return the kind of @ref property_value we are looking at.
270 property_value::value_kind
get_kind() const271 property_value::get_kind() const
272 {return priv_->kind_;}
273 
274 /// Converts the current property value to a string.
275 ///
276 /// @return the string representation of the property value.
operator const string&() const277 property_value::operator const string& () const
278 {return as_string();}
279 
280 /// Destructor for the @ref proprerty_value type.
~property_value()281 property_value::~property_value()
282 {}
283 // </property_value stuff>
284 
285 // <string_property stuff>
286 
287 /// The private data for the @ref string_property_value type.
288 struct string_property_value::priv
289 {
290   string content_;
291 
privabigail::ini::string_property_value::priv292   priv()
293   {}
294 
privabigail::ini::string_property_value::priv295   priv(const string& c)
296     : content_(c)
297   {}
298 }; // end struct string_property::priv
299 
300 /// Constructor of the @ref string_property_value type.
string_property_value()301 string_property_value::string_property_value()
302   : property_value(STRING_PROPERTY_VALUE),
303     priv_(new priv())
304 {}
305 
306 /// Constructor of the @ref string_property_value.
307 ///
308 /// @param content the string content of the property value.
string_property_value(const string & content)309 string_property_value::string_property_value(const string& content)
310   : property_value(STRING_PROPERTY_VALUE),
311     priv_(new priv(content))
312 {}
313 
314 /// Setter of the content of the string property value.
315 ///
316 /// @param c the new content.
317 void
set_content(const string & c)318 string_property_value::set_content(const string& c)
319 {priv_->content_ = c;}
320 
321 /// Convert the string property value into a string.
322 ///
323 /// @return the string contained in the string property value.
324 const string&
as_string() const325 string_property_value::as_string() const
326 {return priv_->content_;}
327 
328 /// Conversion operator to a string, for the @ref
329 /// string_property_value type.
330 ///
331 /// @return the string representing this string_property_value.
operator string() const332 string_property_value::operator string() const
333 {return as_string();}
334 
335 /// Test if a given property value is a string property value.
336 ///
337 /// @return a pointer to the @ref string_property_value sub-object of
338 /// the @ref property_value instance, if it's an instance of @ref
339 /// string_property_value too.
340 string_property_value*
is_string_property_value(const property_value * v)341 is_string_property_value(const property_value* v)
342 {return dynamic_cast<string_property_value*>(const_cast<property_value*>(v));}
343 
344 /// Test if a given property value is a string property value.
345 ///
346 /// @return a pointer to the @ref string_property_value sub-object of
347 /// the @ref property_value instance, if it's an instance of @ref
348 /// string_property_value too.
349 string_property_value_sptr
is_string_property_value(const property_value_sptr v)350 is_string_property_value(const property_value_sptr v)
351 {return dynamic_pointer_cast<string_property_value>(v);}
352 
353 /// Destructor for the @ref string_property_value
~string_property_value()354 string_property_value::~string_property_value()
355 {}
356 
357 // </string_property_value stuff>
358 
359 // <list_property_value stuff>
360 struct list_property_value::priv
361 {
362   vector<string> values_;
363   string representation_;
364 
privabigail::ini::list_property_value::priv365   priv()
366   {}
367 
privabigail::ini::list_property_value::priv368   priv(const vector<string>& vals)
369     : values_(vals)
370   {}
371 }; // end struct list_property_value::priv
372 
373 /// Default constructor of the @ref list_property_value type.
list_property_value()374 list_property_value::list_property_value()
375   : property_value(property_value::LIST_PROPERTY_VALUE),
376    priv_(new priv)
377 {}
378 
379 /// Copy constructor of the @ref list_property_value type.
380 ///
381 /// @param values the instance of @ref list_property_value to copy from.
list_property_value(const vector<string> & values)382 list_property_value::list_property_value(const vector<string>& values)
383   : property_value(property_value::LIST_PROPERTY_VALUE),
384     priv_(new priv(values))
385 {
386 }
387 
388 /// Getter of the content of the @ref list_property_value.
389 ///
390 /// The content of the @ref list_property_value is a vector of
391 /// strings.
392 ///
393 /// @return the vector of strings contained in the @ref
394 /// list_property_value.
395 const vector<string>&
get_content() const396 list_property_value::get_content() const
397 {return priv_->values_;}
398 
399 /// Setter of the content of the @ref list_property_value.
400 ///
401 /// @param values the new content, which is a vector of strings.
402 void
set_content(const vector<string> & values)403 list_property_value::set_content(const vector<string>& values)
404 {
405   priv_->values_ = values;
406   priv_->representation_.clear();
407 }
408 
409 /// Return a string representation of the @list_property_value.
410 ///
411 /// @return the string representation.
412 const string&
as_string() const413 list_property_value::as_string() const
414 {
415   if (priv_->representation_.empty())
416     {
417       for (vector<string>::const_iterator i = priv_->values_.begin();
418 	   i != priv_->values_.end();
419 	   ++i)
420 	{
421 	  if (i != priv_->values_.begin())
422 	    priv_->representation_ += ",";
423 	  priv_->representation_ += *i;
424 	}
425     }
426   return priv_->representation_;
427 }
428 
429 /// Test if an instance of @property_value is a @ref list_property_value.
430 ///
431 /// @param v the property_value to consider.
432 ///
433 /// @return the @ref property_value converted into a @ref
434 /// list_property_value if the @p v is a @ref list_property_value, nil
435 /// otherwise.
436 list_property_value*
is_list_property_value(const property_value * v)437 is_list_property_value(const property_value* v)
438 {return dynamic_cast<list_property_value*>(const_cast<property_value*>(v));}
439 
440 /// Test if an instance of @property_value is a @ref list_property_value.
441 ///
442 /// @param v the property_value to consider.
443 ///
444 /// @return the @ref property_value converted into a @ref
445 /// list_property_value if the @p v is a @ref list_property_value, nil
446 /// otherwise.
447 list_property_value_sptr
is_list_property_value(const property_value_sptr & v)448 is_list_property_value(const property_value_sptr&v)
449 {return dynamic_pointer_cast<list_property_value>(v);}
450 
451 // </list_property_value stuff>
452 
453 // <tuple_property_value>
454 
455 /// The private data of the @ref tuple_property_value type.
456 struct tuple_property_value::priv
457 {
458   vector<property_value_sptr>	value_items_;
459   string			string_rep_;
460 
privabigail::ini::tuple_property_value::priv461   priv()
462   {}
463 
privabigail::ini::tuple_property_value::priv464   priv(const vector<property_value_sptr>& value_items)
465     : value_items_(value_items)
466   {}
467 }; // end struct tuple_property_value::priv
468 
469 /// Constructor for the @ref tuple_property_value type.
470 ///
471 /// @param v the tuple content of the value.
tuple_property_value(const vector<property_value_sptr> & v)472 tuple_property_value::tuple_property_value(const vector<property_value_sptr>& v)
473   : property_value(TUPLE_PROPERTY_VALUE),
474     priv_(new priv(v))
475 {}
476 
477 /// Getter for the content of the @ref tuple_property_value instance.
478 ///
479 /// @return the content of the @ref tuple_property_value instance.
480 const vector<property_value_sptr>&
get_value_items() const481 tuple_property_value::get_value_items() const
482 {return priv_->value_items_;}
483 
484 /// Getter for the content of the @ref tuple_property_value instance.
485 ///
486 /// @return the content of the @ref tuple_property_value instance.
487 vector<property_value_sptr>&
get_value_items()488 tuple_property_value::get_value_items()
489 {return priv_->value_items_;}
490 
491 /// Destructor of the @ref tuple_property_value type.
~tuple_property_value()492 tuple_property_value::~tuple_property_value()
493 {}
494 
495 /// Convert to the instance of @ref tuple_property_value to a string.
496 ///
497 /// @return the string representation of the @ref tuple_property_value.
498 const string&
as_string() const499 tuple_property_value::as_string() const
500 {
501   if (priv_->string_rep_.empty())
502     {
503       priv_->string_rep_ += '{';
504       for (vector<property_value_sptr>::const_iterator i =
505 	     get_value_items().begin();
506 	   i != get_value_items().end();
507 	   ++i)
508 	{
509 	  if (i != get_value_items().begin())
510 	    priv_->string_rep_ += ",";
511 	  priv_->string_rep_ += (*i)->as_string();
512 	}
513       priv_->string_rep_ += '}';
514     }
515   return priv_->string_rep_;
516 }
517 
518 /// Test if a given instance of @ref property_value is an instance of
519 /// @ref tuple_property_value too.
520 ///
521 /// @return the @ref tuple_property_value sub-object of the @ref
522 /// property_value instance, if it's an instance of @ref
523 /// tuple_property_value too.
524 tuple_property_value*
is_tuple_property_value(const property_value * v)525 is_tuple_property_value(const property_value* v)
526 {return dynamic_cast<tuple_property_value*>(const_cast<property_value*>(v));}
527 
528 /// Test if a given instance of @ref property_value is an instance of
529 /// @ref tuple_property_value too.
530 ///
531 /// @return the @ref tuple_property_value sub-object of the @ref
532 /// property_value instance, if it's an instance of @ref
533 /// tuple_property_value too.
534 tuple_property_value_sptr
is_tuple_property_value(const property_value_sptr v)535 is_tuple_property_value(const property_value_sptr v)
536 {return dynamic_pointer_cast<tuple_property_value>(v);}
537 
538 // </tuple_property_value>
539 
540 // <simple_property stuff>
541 
542 /// Private data of the @ref simple_property type.
543 struct simple_property::priv
544 {
545   string_property_value_sptr value_;
546 
privabigail::ini::simple_property::priv547   priv()
548   {}
549 
privabigail::ini::simple_property::priv550   priv(const string_property_value_sptr value)
551     : value_(value)
552   {}
553 }; // end struct simple_property::priv
554 
555 /// Default constructor of the @ref simple_property type.
simple_property()556 simple_property::simple_property()
557   : property(),
558     priv_(new priv)
559 {}
560 
561 /// Constructor for the @ref simple_property type.
562 ///
563 /// @param name the name of the property.
564 ///
565 /// @param value the value of the property.
simple_property(const string & name,const string_property_value_sptr & value)566 simple_property::simple_property(const string& name,
567 				 const string_property_value_sptr& value)
568   : property(name),
569     priv_(new priv(value))
570 {}
571 
572 /// Constructor for the @ref simple_property type.
573 ///
574 /// This one constructs a property with an empty value.
575 ///
576 /// @param name the name of the property.
simple_property(const string & name)577 simple_property::simple_property(const string& name)
578   : property(name),
579     priv_(new priv)
580 {}
581 
582 /// Getter for the string value of the property.
583 ///
584 /// @return the string value of the property.
585 const string_property_value_sptr&
get_value() const586 simple_property::get_value() const
587 {return priv_->value_;}
588 
589 /// Setter for the string value of the property.
590 ///
591 /// @param value the new string value of the property.
592 void
set_value(const string_property_value_sptr & value)593 simple_property::set_value(const string_property_value_sptr& value)
594 {priv_->value_ = value;}
595 
596 /// Test if the property has an empty value.
597 ///
598 /// An empty value is either no value at all or an empty string value.
599 ///
600 /// @return true iff the property has an empty value.
601 bool
has_empty_value() const602 simple_property::has_empty_value() const
603 {
604   if (!priv_->value_)
605     return true;
606   return  priv_->value_->as_string().empty();
607 }
608 
609 /// Destructor of the @ref simple_property type.
~simple_property()610 simple_property::~simple_property()
611 {}
612 
613 /// Tests if a @ref property is a simple property.
614 ///
615 /// @return a pointer to the @ref simple_property sub-object of the
616 /// @ref property instance, iff it's an @ref simple_property
617 /// instance.
618 simple_property*
is_simple_property(const property * p)619 is_simple_property(const property* p)
620 {return dynamic_cast<simple_property*>(const_cast<property*>(p));}
621 
622 /// Tests if a @ref property is a simple property.
623 ///
624 /// @return a smart pointer to the @ref simple_property sub-object of
625 /// the @ref property instance, iff it's an @ref simple_property
626 /// instance.
627 simple_property_sptr
is_simple_property(const property_sptr p)628 is_simple_property(const property_sptr p)
629 {return dynamic_pointer_cast<simple_property>(p);}
630 
631 // </simple_property stuff>
632 
633 // <list_property stuff>
634 struct list_property::priv
635 {
636   list_property_value_sptr value_;
637 
privabigail::ini::list_property::priv638   priv()
639   {}
640 
privabigail::ini::list_property::priv641   priv(const list_property_value_sptr value)
642     : value_(value)
643   {}
644 }; //end struct list_property
645 
646 /// Default constructor for @ref list_property.
list_property()647 list_property::list_property()
648   : priv_(new priv)
649 {}
650 
651 /// Constructor for @ref list_property.
652 ///
653 /// @param name the name of the property.
654 ///
655 /// @param value the value of the property.
list_property(const string & name,const list_property_value_sptr & value)656 list_property::list_property(const string& name,
657 			     const list_property_value_sptr& value)
658   : property(name),
659     priv_(new priv(value))
660 {}
661 
662 /// Getter for the value of the @ref list_property_value
663 const list_property_value_sptr&
get_value() const664 list_property::get_value() const
665 {return priv_->value_;}
666 
667 /// Setter for the value of the @ref list_property.
668 ///
669 /// @param value the new value.
670 void
set_value(const list_property_value_sptr & value)671 list_property::set_value(const list_property_value_sptr& value)
672 {priv_->value_ = value;}
673 
674 /// Destructor of the @ref list_property type.
~list_property()675 list_property::~list_property()
676 {}
677 
678 /// Test if an instance of a @ref property is actually an instance of
679 /// @ref list_property.
680 ///
681 /// @param p the @ref property to test.
682 ///
683 /// @return the @p p converted into a @ref list_property if it's of
684 /// type @ref list_property, or nil otherwise.
685 list_property*
is_list_property(const property * p)686 is_list_property(const property* p)
687 {return dynamic_cast<list_property*>(const_cast<property*>(p));}
688 
689 /// Test if an instance of a @ref property is actually an instance of
690 /// @ref list_property.
691 ///
692 /// @param p the @ref property to test.
693 ///
694 /// @return the @p p converted into a @ref list_property if it's of
695 /// type @ref list_property, or nil otherwise.
696 list_property_sptr
is_list_property(const property_sptr p)697 is_list_property(const property_sptr p)
698 {return dynamic_pointer_cast<list_property>(p);}
699 // </list_property stuff>
700 
701 // <tuple_property stuff>
702 struct tuple_property::priv
703 {
704   tuple_property_value_sptr value_;
705 
privabigail::ini::tuple_property::priv706   priv()
707   {}
708 
privabigail::ini::tuple_property::priv709   priv(const tuple_property_value_sptr value)
710     : value_(value)
711   {}
712 }; // end struct tuple_property::priv
713 
714 /// Default constructor of the @ref tuple_property type.
tuple_property()715 tuple_property::tuple_property()
716   : property(),
717     priv_(new priv)
718 {}
719 
720 /// Constructor of the @ref tuple_property type.
721 ///
722 /// @param name the name of the property.
723 ///
724 /// @param values the tuple value of the property.
tuple_property(const string & name,const tuple_property_value_sptr value)725 tuple_property::tuple_property(const string& name,
726 			       const tuple_property_value_sptr value)
727   : property(name),
728     priv_(new priv(value))
729 {}
730 
731 /// Setter for the tuple value of the property.
732 ///
733 /// @param values the new tuple value of the property.
734 void
set_value(const tuple_property_value_sptr value)735 tuple_property::set_value(const tuple_property_value_sptr value)
736 {priv_->value_ = value;}
737 
738 /// Getter for the tuple value of the property.
739 ///
740 /// @return the tuple value of the property.
741 const tuple_property_value_sptr&
get_value() const742 tuple_property::get_value() const
743 {return priv_->value_;}
744 
745 /// Destructor for the @ref tuple_property type.
~tuple_property()746 tuple_property::~tuple_property()
747 {}
748 
749 /// Test if an instance of @ref property is an instance of @ref
750 /// tuple_property.
751 ///
752 /// @param p the instance of @ref property to test for.
753 ///
754 /// @return return a pointer to the sub-object of @ref tuple_property
755 /// iff @p p is an instance of @ref tuple_property.
756 tuple_property*
is_tuple_property(const property * p)757 is_tuple_property(const property* p)
758 {return dynamic_cast<tuple_property*>(const_cast<property*>(p));}
759 
760 /// Test if an instance of @ref property is an instance of @ref
761 /// tuple_property.
762 ///
763 /// @param p the instance of @ref property to test for.
764 ///
765 /// @return return a smart pointer to the sub-object of @ref
766 /// tuple_property iff @p p is an instance of @ref tuple_property.
767 tuple_property_sptr
is_tuple_property(const property_sptr p)768 is_tuple_property(const property_sptr p)
769 {return dynamic_pointer_cast<tuple_property>(p);}
770 
771 // </tuple_property stuff>
772 
773 class config::section::priv
774 {
775   string name_;
776   properties_type properties_;
777 
778   // Forbid this;
779   priv();
780 
781 public:
priv(const string & name)782   priv(const string& name)
783     : name_(name)
784   {}
785 
786   friend class config::section;
787 };//end struct config::section::priv
788 
789 // <config::section stuff>
790 
791 /// Constructor for config::section.
792 ///
793 /// @param name the name of the ini section.
section(const string & name)794 config::section::section(const string& name)
795   : priv_(new priv(name))
796 {}
797 
798 /// Constructor for the config::section.
799 ///
800 /// @param name the name of the ini section.
801 ///
802 /// @param properties the properties of the section.
section(const string & name,const properties_type & properties)803 config::section::section(const string& name,
804 			 const properties_type& properties)
805   : priv_(new priv(name))
806 {set_properties(properties);}
807 
808 /// Get the name of the section.
809 ///
810 /// @return the name of the section.
811 const string&
get_name() const812 config::section::get_name() const
813 {return priv_->name_;}
814 
815 /// Get the properties of the section.
816 ///
817 /// @return a vector of the properties of the section.
818 const config::properties_type&
get_properties() const819 config::section::get_properties() const
820 {return priv_->properties_;}
821 
822 /// Set the properties of the section.
823 ///
824 /// @param properties the new properties to set.
825 void
set_properties(const properties_type & properties)826 config::section::set_properties(const properties_type& properties)
827 {priv_->properties_ = properties;}
828 
829 /// Add one property to this section.
830 ///
831 /// @param prop the property to add to the section.
832 void
add_property(const property_sptr prop)833 config::section::add_property(const property_sptr prop)
834 {priv_->properties_.push_back(prop);}
835 
836 /// Find a property that has a given name.
837 ///
838 /// Note that this only returns the first property with that name.
839 ///
840 /// @param prop_name the name of the property to find.
841 ///
842 /// @return the found property, or nil if no property with the name @p
843 /// prop_name was found.
844 property_sptr
find_property(const string & prop_name) const845 config::section::find_property(const string& prop_name) const
846 {
847   for (properties_type::const_iterator i = get_properties().begin();
848        i != get_properties().end();
849        ++i)
850     if ((*i)->get_name() == prop_name)
851       return *i;
852   return property_sptr();
853 }
854 
855 /// Destructor of config::section.
~section()856 config::section::~section()
857 {}
858 // /<config::section stuff>
859 
860 // <read_context stuff>
861 
862 /// The context of the ini file parsing.
863 ///
864 /// This is a private type that is used only in the internals of the
865 /// ini file parsing.
866 class read_context
867 {
868   /// The input stream we are parsing from.
869   istream& in_;
870   /// The current line being parsed.
871   unsigned cur_line_;
872   /// The current column on the current line.
873   unsigned cur_column_;
874   vector<char> buf_;
875 
876   // Forbid this;
877   read_context();
878 
879 public:
880 
881   /// The constructor of @ref read_context.
882   ///
883   /// @param in the input stream to parse from.
read_context(istream & in)884   read_context(istream& in)
885     : in_(in),
886       cur_line_(0),
887       cur_column_(0)
888   {}
889 
890   /// @return the character that is going to be read by the next
891   /// invocation of read_next_char().
892   ///
893   /// Note that this function doesn't alter the input stream.
894   ///
895   /// Also note that this function handles escaping using the '\'
896   /// (backslash) character.
897   ///
898   /// @param escaped This is an output parameter.  It's set to true by
899   /// this function if it escaped the peeked character.  Otherwise,
900   /// it's set to false.
901   ///
902   /// @return peeked character.
903   char
peek(bool & escaped)904   peek(bool& escaped)
905   {
906     if (!buf_.empty())
907       return buf_.back();
908 
909     escaped = false;
910     char c = in_.peek();
911     if (handle_escape(c, /*peek=*/true))
912       {
913 	put_back(c);
914 	escaped = true;
915       }
916     return c;
917   }
918 
919   /// @return the character that is going to be read by the next
920   /// invocation of read_next_char().
921   ///
922   /// Note that this function doesn't alter the input stream.
923   ///
924   /// Also note that this function handles escaping using the '\'
925   /// (backslash) character.
926   ///
927   /// @return peeked character.
928   char
peek()929   peek()
930   {
931     bool escaped = false;
932     return peek(escaped);
933   }
934 
935   /// Get the next character of the input stream.
936   ///
937   /// This function knows how to handles escaped characters from the
938   /// input stream.
939   ///
940   /// @param do_handle_escape if yes, this function handles escaped
941   /// characters from the input stream.
942   ///
943   /// @return the next character of the input stream.
944   char
get(bool do_handle_escape=true)945   get(bool do_handle_escape = true)
946   {
947     char result = 0;
948     if (!buf_.empty())
949       {
950 	result = buf_.back();
951 	buf_.pop_back();
952       }
953     else
954       {
955 	result = in_.get();
956 	if (do_handle_escape)
957 	  handle_escape(result);
958       }
959     return result;
960   }
961 
962   /// Put a character that was read from the input stream, back into
963   /// that input stream, so that a subsequent call to
964   /// read_context::get() returns that same character.
965   ///
966   /// @param c the character to put back into the stream.
967   void
put_back(char c)968   put_back(char c)
969   {buf_.push_back(c);}
970 
971   /// Test if the status of the input stream is good.
972   ///
973   /// @return true iff the status of the input stream is good.
974   bool
good() const975   good() const
976   {
977     if (!buf_.empty())
978       return true;
979     return in_.good();
980   }
981 
982   /// Tests if the input stream has reached end of file.
983   ///
984   /// @return true iff the input stream has reached end of file.
985   bool
eof() const986   eof() const
987   {
988     if (!buf_.empty())
989       return false;
990     return in_.eof();
991   }
992 
993   /// Handles the escaping of a character.
994   ///
995   /// This function must be called whenever the low level character
996   /// reading function encountered a backslash character ('\').  In
997   /// that case, this function reads the subsequent characters from
998   /// the input stream, sees if it needs to escape them and then
999   /// handles the escaping if need be.  Otherwise, it does nothing.
1000   ///
1001   /// This is a subroutine of the read_context::get() and
1002   /// read_context::peek() functions.
1003   ///
1004   /// @param peek if true, it means this function was called after the
1005   /// caller issued a read_context::peek() call, rather than a
1006   /// read_context::get() call.
1007   ///
1008   /// @return true if an escaping took place.
1009   bool
handle_escape(char & c,bool peek=false)1010   handle_escape(char& c, bool peek = false)
1011   {
1012     bool escaped = false;
1013     char b = c;
1014 
1015     if (b == '\\')
1016       {
1017 	escaped = true;
1018 	b = get(/*escape=*/false);
1019 	if (!good())
1020 	  return escaped;
1021 	if (peek)
1022 	  {
1023 	    ABG_ASSERT(b == c);
1024 	    b = get(/*escape=*/false);
1025 	    if (!good())
1026 	      return escaped;
1027 	  }
1028 
1029 	switch (b)
1030 	  {
1031 	  case '0':
1032 	  case 'a':
1033 	  case 'b':
1034 	  case 'r':
1035 	    // let's replace this by a space
1036 	    c = ' ';
1037 	    break;
1038 	  case 't':
1039 	    c = '\t';
1040 	    break;
1041 	  case '\n':
1042 	    // continuation line.  So we should drop both the backslash
1043 	    // character and this end-of-line character on the floor
1044 	    // just like if they never existed.
1045 	    ++cur_column_;
1046 	    b = get(/*escape=*/false);
1047 	    if (!good())
1048 	      return escaped;
1049 	    c = b;
1050 	    break;
1051 	  case '\\':
1052 	  case ';':
1053 	  case '#':
1054 	  case '[':
1055 	  case ']':
1056 	  default:
1057 	    c = b;
1058 	    break;
1059 	  }
1060       }
1061     else
1062       c = b;
1063 
1064     return escaped;
1065   }
1066 
1067   /// Read the next character from the input stream.
1068   ///
1069   /// This method updates the current line/column number after looking
1070   /// at the actual char that got read.  Note that escaped characters
1071   /// are handled transparently at this point.
1072   ///
1073   /// @param c output parameter.  This is set by this function to the
1074   /// character that was read.  It's set iff the function returned
1075   /// true.
1076   ///
1077   /// @return true if the reading went well and if the input stream is
1078   /// in a non-erratic state.
1079   bool
read_next_char(char & c)1080   read_next_char(char& c)
1081   {
1082     char b = get();
1083     if (!good())
1084       return false;
1085 
1086     c = b;
1087 
1088     if (cur_line_ == 0)
1089       cur_line_ = 1;
1090 
1091     if (b == '\n')
1092       {
1093 	++cur_line_;
1094 	cur_column_ = 0;
1095       }
1096     else
1097       ++cur_column_;
1098 
1099     return true;
1100   }
1101 
1102   /// Skip (that is, read characters and drop them on the floor) all
1103   /// the characters up to the next line.
1104   ///
1105   /// Note that the new line character (\n' on unices) is skipped as
1106   /// well.
1107   ///
1108   /// @return true iff the skipping proceeded successfully and that
1109   /// the input stream is left in a non-erratic state.
1110   bool
skip_line()1111   skip_line()
1112   {
1113     char c = 0;
1114     for (bool is_ok = read_next_char(c);
1115 	 is_ok;
1116 	 is_ok = read_next_char(c))
1117       if (c == '\n')
1118 	break;
1119 
1120     return (c == '\n' || eof());
1121   }
1122 
1123   /// If the current character is a white space, skip it and all the
1124   /// contiguous ones that follow.
1125   ///
1126   /// @return true iff the input stream is left in a non-erratic state.
1127   bool
skip_white_spaces()1128   skip_white_spaces()
1129   {
1130     for (char c = peek(); good(); c = peek())
1131       if (char_is_white_space(c))
1132 	ABG_ASSERT(read_next_char(c));
1133       else
1134 	break;
1135     return good() || eof();
1136   }
1137 
1138   /// If the current character is the beginning of a comment, skip
1139   /// (read and drop on the floor) the entire remaining line,
1140   /// including the current character.
1141   ///
1142   /// @return true if the input stream is left in a non-erratic state.
1143   bool
skip_comments()1144   skip_comments()
1145   {
1146     for (char c = peek(); good(); c = peek())
1147       if (char_is_comment_start(c))
1148 	skip_line();
1149       else
1150 	break;
1151     return good() || eof();
1152   }
1153 
1154   /// If the current character is either the beginning of a comment or
1155   /// a white space, skip the entire commented line or the subsequent
1156   /// contiguous white spaces.
1157   ///
1158   /// @return true iff the stream is left in a non-erratic state.
1159   bool
skip_white_spaces_or_comments()1160   skip_white_spaces_or_comments()
1161   {
1162     int b = 0;
1163     while (good())
1164       {
1165 	b = peek();
1166 	if (char_is_white_space(b))
1167 	  skip_white_spaces();
1168 	else if (char_is_comment_start(b))
1169 	  skip_comments();
1170 	else
1171 	  break;
1172       }
1173     return good() || eof();
1174   }
1175 
1176   /// Read a property name.
1177   ///
1178   /// @param name out parameter.  Is set to the parsed property name,
1179   /// if any.  Note that this is set only if the function returned
1180   /// true.
1181   ///
1182   /// @return true iff the input stream is left in a non-erratic
1183   /// state.
1184   bool
read_property_name(string & name)1185   read_property_name(string& name)
1186   {
1187     char c = peek();
1188     if (!good() || !char_is_property_name_char(c))
1189       return false;
1190 
1191     ABG_ASSERT(read_next_char(c));
1192     name += c;
1193 
1194     for (c = peek(); good(); c = peek())
1195       {
1196 	if (!char_is_property_name_char(c))
1197 	  break;
1198 	ABG_ASSERT(read_next_char(c));
1199 	name += c;
1200       }
1201 
1202     return true;
1203   }
1204 
1205   /// Read a function name.
1206   ///
1207   /// @param name the name of the function.  This is an output
1208   /// parameter when this puts the function name that was read, iff
1209   /// this function returns true.
1210   ///
1211   /// @return true iff the function name was successfully read into @p
1212   /// name.
1213   bool
read_function_name(string & name)1214   read_function_name(string& name)
1215   {
1216     char c = peek();
1217     if (!good() || !char_is_function_name_char(c))
1218       return false;
1219 
1220     ABG_ASSERT(read_next_char(c));
1221     name += c;
1222 
1223     for (c = peek(); good(); c = peek())
1224       {
1225 	if (!char_is_function_name_char(c))
1226 	  break;
1227 	ABG_ASSERT(read_next_char(c));
1228 	name += c;
1229       }
1230 
1231     return true;
1232   }
1233 
1234   /// Read a function argument.
1235   ///
1236   /// @param argument the argument of the function that was just
1237   /// read.  This is an ouput parameter that is set iff the function
1238   /// returns true.
1239   ///
1240   /// @return true iff parameter @p argument was successful set.
1241   bool
read_function_argument(string & argument)1242   read_function_argument(string& argument)
1243   {
1244     char c = peek();
1245     if (!good() || !char_is_function_argument_char(c))
1246       return false;
1247 
1248     ABG_ASSERT(read_next_char(c));
1249     argument += c;
1250 
1251     for (c = peek(); good(); c = peek())
1252       {
1253 	if (!char_is_function_argument_char(c))
1254 	  break;
1255 	ABG_ASSERT(read_next_char(c));
1256 	argument += c;
1257       }
1258 
1259     return true;
1260   }
1261 
1262   /// Read a function call expression.
1263   ///
1264   /// The expression this function can read has the form:
1265   ///		'foo(bar,baz, blah)'
1266   ///
1267   /// @param expr this is an output parameter that is set with the
1268   /// resulting function call expression that was read, iff this
1269   /// function returns true.
1270   ///
1271   /// @param return true iff @p expr was successful set with the
1272   /// function call expression that was read.
1273   bool
read_function_call_expr(function_call_expr_sptr & expr)1274   read_function_call_expr(function_call_expr_sptr& expr)
1275   {
1276     if (!good())
1277       return false;
1278 
1279     skip_white_spaces_or_comments();
1280     if (!good())
1281       return false;
1282 
1283     string name;
1284     if (!read_function_name(name) || name.empty())
1285       return false;
1286 
1287     skip_white_spaces_or_comments();
1288 
1289     int b = peek();
1290     if (!good() || b != '(')
1291       return false;
1292 
1293     char c = 0;
1294     if (!read_next_char(c))
1295       return false;
1296     ABG_ASSERT(c == '(');
1297 
1298     skip_white_spaces_or_comments();
1299     if (!good())
1300       return false;
1301 
1302     // Read function call arguments.
1303     vector<string> arguments;
1304     for (;;)
1305       {
1306 	if (peek() == ')')
1307 	  break;
1308 
1309 	string arg;
1310 	if (!read_function_argument(arg))
1311 	  return true;
1312 
1313 	skip_white_spaces_or_comments();
1314 	if (!good())
1315 	  return false;
1316 
1317 	if (peek() == ',')
1318 	  {
1319 	    c = 0;
1320 	    ABG_ASSERT(read_next_char(c) && c == ',');
1321 	    skip_white_spaces_or_comments();
1322 	    if (!good())
1323 	      return false;
1324 	  }
1325 
1326 	arguments.push_back(arg);
1327       }
1328 
1329     c = 0;
1330     ABG_ASSERT(read_next_char(c) && c == ')');
1331 
1332     expr.reset(new function_call_expr(name, arguments));
1333     return true;
1334   }
1335 
1336   /// Read a property value.
1337   ///
1338   /// @return the property value read.
1339   property_value_sptr
read_property_value()1340   read_property_value()
1341   {
1342     property_value_sptr nil, result;
1343 
1344     int b = peek();
1345     if (!good())
1346       return nil;
1347 
1348     if (b == '{')
1349       {
1350 	if (tuple_property_value_sptr t = read_tuple_property_value())
1351 	  return t;
1352 	return nil;
1353       }
1354 
1355     list_property_value_sptr list = read_list_property_value();
1356     if (list->get_content().size() == 1)
1357       result.reset(new string_property_value(list->get_content()[0]));
1358     else
1359       result = list;
1360 
1361     return result;
1362   }
1363 
1364   /// Reads a string from the input stream.
1365   ///
1366   /// A string is just a contiguous set of characters that test
1367   /// positive when passed to
1368   /// read_context::char_is_property_name_char().
1369   ///
1370   /// Note that all escaped characters are suitable to be in a string.
1371   ///
1372   /// @return the string read.
1373   string
read_string()1374   read_string()
1375   {
1376     bool escaped = false;
1377     int b = peek(escaped);
1378     if (!good())
1379       return "";
1380 
1381     if (!escaped && char_is_delimiter(b, /*include_white_space=*/false))
1382       // Empty property value.  This is accepted.
1383       return "";
1384 
1385     string v;
1386     for (b = peek(escaped); good(); b = peek(escaped))
1387       {
1388 	// If the current character is not suitable to be a in string,
1389 	// then we reached the end of the string.  Note that espaced
1390 	// characters are always suitable to be a string.
1391 	if (!escaped && !char_is_property_value_char(b))
1392 	  break;
1393 	char c = 0;
1394 	ABG_ASSERT(read_next_char(c));
1395 	v += c;
1396       }
1397     return trim_white_space(v);
1398   }
1399 
1400   /// Read a string property value.
1401   ///
1402   /// @return the property value that has been parsed.
1403   string_property_value_sptr
read_string_property_value()1404   read_string_property_value()
1405   {
1406     string_property_value_sptr nil, result;
1407     if (!good())
1408       return nil;
1409 
1410     string value = read_string();
1411     result.reset(new string_property_value(value));
1412     return result;
1413   }
1414 
1415   /// Read a @ref list_property_value.
1416   ///
1417   /// @return the instance of @ref list_property_value read, or nil if
1418   /// none was read.
1419   list_property_value_sptr
read_list_property_value()1420   read_list_property_value()
1421   {
1422     list_property_value_sptr nil, result;
1423     string str;
1424     vector<string> content;
1425 
1426     for (;;)
1427       {
1428 	str = read_string();
1429 	if (str.empty())
1430 	  break;
1431 	content.push_back(str);
1432 
1433 	skip_white_spaces();
1434 
1435 	int b = peek();
1436 	if (!good() || b != ',')
1437 	  break;
1438 	skip_white_spaces();
1439 
1440 	char c = 0;
1441 	read_next_char(c);
1442 	ABG_ASSERT(c == ',');
1443       }
1444 
1445     if (!content.empty())
1446       result.reset(new list_property_value(content));
1447 
1448     return result;
1449   }
1450 
1451   /// A property value that is a tuple.
1452   ///
1453   /// @param tuple the read property tuple value.
1454   ///
1455   /// @return true iff the tuple property value could be read
1456   /// correctly.
1457   tuple_property_value_sptr
read_tuple_property_value()1458   read_tuple_property_value()
1459   {
1460     tuple_property_value_sptr nil, result;
1461     int b = peek();
1462     if (!good())
1463       return nil;
1464 
1465     if (b != '{')
1466       return nil;
1467 
1468     char c = 0;
1469     ABG_ASSERT(read_next_char(c));
1470 
1471     property_value_sptr value;
1472     vector<property_value_sptr> values;
1473     while (good() && peek() != '}')
1474       {
1475 	skip_white_spaces();
1476 	if ((value = read_property_value()))
1477 	  values.push_back(value);
1478 	skip_white_spaces();
1479 	if (good() && peek() == ',')
1480 	  {
1481 	    c = 0;
1482 	    read_next_char(c);
1483 	  }
1484       }
1485 
1486     b = peek();
1487     if (b != '}')
1488       return nil;
1489 
1490     c = 0;
1491     read_next_char(c);
1492 
1493     result.reset(new tuple_property_value(values));
1494     return result;
1495   }
1496 
1497   /// Read the name of a section.
1498   ///
1499   /// @param name out parameter.  Is set to the name of the section
1500   /// that was parsed.  Note that this is set only if the function
1501   /// returned true.
1502   ///
1503   /// @return true if the input stream was left in a non-erratic
1504   /// state.
1505   bool
read_section_name(string & name)1506   read_section_name(string& name)
1507   {
1508     int b = peek();
1509     if (!good() || !char_is_section_name_char(b))
1510       return false;
1511 
1512     char c = 0;
1513     ABG_ASSERT(read_next_char(c) || char_is_section_name_char(b));
1514     name += c;
1515 
1516     for (b = peek(); good(); b = peek())
1517       {
1518 	if (!char_is_section_name_char(b))
1519 	  break;
1520 	ABG_ASSERT(read_next_char(c));
1521 	name += c;
1522       }
1523 
1524     return true;
1525   }
1526 
1527   /// Read a property (<name> = <value>).
1528   ///
1529   /// @return the resulting pointer to property iff one could be
1530   /// parsed.
1531   property_sptr
read_property()1532   read_property()
1533   {
1534     property_sptr nil;
1535 
1536     string name;
1537     if (!read_property_name(name))
1538       return nil;
1539 
1540     skip_white_spaces();
1541 
1542     property_sptr result;
1543 
1544     char c = peek();
1545     if (c == '=')
1546       {
1547 	ABG_ASSERT(read_next_char(c));
1548 	ABG_ASSERT(c == '=');
1549 	skip_white_spaces();
1550       }
1551     else
1552       {
1553 	property_sptr empty_value_property(new simple_property(name));
1554 	return empty_value_property;
1555       }
1556 
1557     if (!good())
1558       return nil;
1559 
1560     property_value_sptr value = read_property_value();
1561     if (!value)
1562       return nil;
1563 
1564     if (tuple_property_value_sptr tv = is_tuple_property_value(value))
1565       result.reset(new tuple_property(name, tv));
1566     else if (list_property_value_sptr lv = is_list_property_value(value))
1567       result.reset(new list_property(name, lv));
1568     else if (string_property_value_sptr sv = is_string_property_value(value))
1569       result.reset(new simple_property(name, sv));
1570     else
1571       // This new kind of property is not yet supported!
1572       std::abort();
1573 
1574     return result;
1575   }
1576 
1577   /// Read an ini section.
1578   ///
1579   /// @return a pointer to a section iff it could be successfully
1580   /// parsed.
1581   config::section_sptr
read_section()1582   read_section()
1583   {
1584     config::section_sptr nil;
1585 
1586     int b = peek();
1587     if (!good())
1588       return nil;
1589 
1590     char c = 0;
1591     if (b == '[')
1592       ABG_ASSERT(read_next_char(c) && c == '[');
1593 
1594     string name;
1595     if (!read_section_name(name))
1596       return nil;
1597 
1598     if (!skip_white_spaces())
1599       return nil;
1600 
1601     if (! read_next_char(c) || c != ']')
1602       return nil;
1603 
1604     if (!skip_white_spaces_or_comments())
1605       return nil;
1606 
1607     config::properties_type properties;
1608     while (property_sptr prop = read_property())
1609       {
1610 	properties.push_back(prop);
1611 	skip_white_spaces_or_comments();
1612       }
1613 
1614     if (!properties.empty())
1615       {
1616 	config::section_sptr section(new config::section(name, properties));
1617 	return section;
1618       }
1619 
1620     return nil;
1621   }
1622 };//end struct read_context
1623 
1624 // </read_context stuff>
1625 
1626 // <config stuff>
1627 
1628 class config::priv
1629 {
1630   string path_;
1631   sections_type sections_;
1632 
1633 public:
1634   friend class config;
1635 
priv()1636   priv()
1637   {}
1638 
priv(const string & path,sections_type & sections)1639   priv(const string& path,
1640        sections_type& sections)
1641     : path_(path),
1642       sections_(sections)
1643   {}
1644 
1645 };
1646 
1647 /// @param path the path to the config file.
1648 ///
1649 /// @param sections the sections of the config file.
config(const string & path,sections_type & sections)1650 config::config(const string& path,
1651 	       sections_type& sections)
1652   : priv_(new priv(path, sections))
1653 {}
1654 
config()1655 config::config()
1656   : priv_(new priv)
1657 {}
1658 
~config()1659 config::~config()
1660 {}
1661 
1662 /// @return the path to the config file.
1663 const string&
get_path() const1664 config::get_path() const
1665 {return priv_->path_;}
1666 
1667 /// Set the path to the config file.
1668 ///
1669 /// @param the new path to the config file.
1670 void
set_path(const string & path)1671 config::set_path(const string& path)
1672 {priv_->path_ = path;}
1673 
1674 /// @return the sections of the config file.
1675 const config::sections_type&
get_sections() const1676 config::get_sections() const
1677 {return priv_->sections_;}
1678 
1679 /// Set new sections to the ini config
1680 ///
1681 /// @param sections the new sections to set.
1682 void
set_sections(const sections_type & sections)1683 config::set_sections(const sections_type& sections)
1684 {priv_->sections_ = sections;}
1685 
1686 // </config stuff>
1687 
1688 // <config reader stuff>
1689 
1690 /// Parse the sections of an *.ini file.
1691 ///
1692 /// @param input the input stream to parse the ini file from.
1693 ///
1694 /// @param section out parameter.  This is set to the vector of
1695 /// sections that have been parsed from the input stream.
1696 ///
1697 /// @return true upon successful completion and if if the stream is
1698 /// left in a non-erratic state.
1699 bool
read_sections(std::istream & input,config::sections_type & sections)1700 read_sections(std::istream& input,
1701 	      config::sections_type& sections)
1702 {
1703   read_context ctxt(input);
1704 
1705   while (input.good())
1706     {
1707       ctxt.skip_white_spaces_or_comments();
1708       if (config::section_sptr section = ctxt.read_section())
1709 	sections.push_back(section);
1710       else
1711 	break;
1712     }
1713 
1714   return input.good() || input.eof();
1715 }
1716 
1717 /// Parse the sections of an *.ini file.
1718 ///
1719 /// @param path the path of the ini file to parse.
1720 ///
1721 /// @param section out parameter.  This is set to the vector of
1722 /// sections that have been parsed from the input stream.
1723 ///
1724 /// @return true upon successful completion and if if the stream is
1725 /// left in a non-erratic state.
1726 bool
read_sections(const string & path,config::sections_type & sections)1727 read_sections(const string& path,
1728 	      config::sections_type& sections)
1729 {
1730   std::ifstream in(path.c_str(), std::ifstream::binary);
1731   if (!in.good())
1732     return false;
1733 
1734   bool is_ok = read_sections(in, sections);
1735   in.close();
1736 
1737   return is_ok;
1738 }
1739 
1740 /// Parse an ini config file from an input stream.
1741 ///
1742 /// @param input the input stream to parse the ini config file from.
1743 ///
1744 /// @return true upon successful parsing.
1745 bool
read_config(istream & input,config & conf)1746 read_config(istream& input,
1747 	    config& conf)
1748 {
1749   config::sections_type sections;
1750   if (!read_sections(input, sections))
1751     return false;
1752   conf.set_sections(sections);
1753   return true;
1754 }
1755 
1756 /// Parse an ini config file from a file on disk.
1757 ///
1758 /// @param path the path to the ini file to parse.
1759 ///
1760 /// @param conf the resulting config file to populate as a result of
1761 /// the parsing.  This is populated iff the function returns true.
1762 ///
1763 /// @return true upon succcessful completion.
1764 bool
read_config(const string & path,config & conf)1765 read_config(const string& path,
1766 	    config& conf)
1767 {
1768   config::sections_type sections;
1769   if (!read_sections(path, sections))
1770     return false;
1771   conf.set_path(path);
1772   conf.set_sections(sections);
1773   return true;
1774 }
1775 
1776 /// Parse an ini config file from an input stream.
1777 ///
1778 /// @return a shared pointer to the resulting config, or nil if it
1779 /// couldn't be parsed.
1780 config_sptr
read_config(std::istream & input)1781 read_config(std::istream& input)
1782 {
1783   config_sptr c(new config);
1784   if (!read_config(input, *c))
1785     return config_sptr();
1786   return c;
1787 }
1788 
1789 
1790 /// Parse an ini config file from an on-disk file.
1791 ///
1792 /// @return a shared pointer to the resulting config, or nil if it
1793 /// couldn't be parsed.
1794 config_sptr
read_config(const string & path)1795 read_config(const string& path)
1796 {
1797   config_sptr c(new config);
1798   if (!read_config(path, *c))
1799     return config_sptr();
1800   return c;
1801 }
1802 // <config reader stuff>
1803 
1804 // <config writer stuff>
1805 
1806 /// Serialize the value of a property to a string.
1807 ///
1808 /// @param prop the property which value to serialize.
1809 ///
1810 /// @return the string that represents the value of @p prop.
1811 static string
write_property_value(const property_sptr & prop)1812 write_property_value(const property_sptr& prop)
1813 {
1814   string result;
1815   if (simple_property_sptr simple_prop = is_simple_property(prop))
1816     {
1817       if (!simple_prop->has_empty_value())
1818 	result = simple_prop->get_value()->as_string();
1819     }
1820   else if (list_property_sptr list_prop = is_list_property(prop))
1821     result = list_prop->get_value()->as_string();
1822   else if (tuple_property_sptr tuple_prop = is_tuple_property(prop))
1823       result = tuple_prop->get_value()->as_string();
1824   else
1825     // This new kind of property is not yet supported!
1826     abort();
1827   return result;
1828 }
1829 
1830 /// Serialize an ini property to an output stream.
1831 ///
1832 /// @param prop the property to serialize to the output stream.
1833 ///
1834 /// @param out the output stream to serialize to.
1835 ///
1836 /// @return true if the ouput stream is left in a non-erratic state.
1837 static bool
write_property(const property_sptr & prop,std::ostream & out)1838 write_property(const property_sptr& prop,
1839 	       std::ostream& out)
1840 {
1841   out << prop->get_name();
1842   string value = write_property_value(prop);
1843   if (!value.empty())
1844     out << " = " << write_property_value(prop);
1845   return out.good();
1846 }
1847 
1848 /// Serialize an ini section to an output stream.
1849 ///
1850 /// @param section the ini section to serialize.
1851 ///
1852 /// @param out the output stream to serialize the section to.
1853 static bool
write_section(const config::section & section,std::ostream & out)1854 write_section(const config::section& section,
1855 	      std::ostream& out)
1856 {
1857   out << "[" << section.get_name() << "]\n";
1858   for (config::properties_type::const_iterator i =
1859 	 section.get_properties().begin();
1860        i != section.get_properties().end();
1861        ++i)
1862     {
1863       out << "  ";
1864       write_property(*i, out);
1865       out << "\n";
1866     }
1867   return out.good();
1868 }
1869 
1870 /// Serialize a vector of sections that make up an ini config file to
1871 /// an output stream.
1872 ///
1873 /// Note that an ini config is just a collection of sections.
1874 ///
1875 /// @param sections the vector of sections to serialize.
1876 ///
1877 /// @param out the output stream.
1878 ///
1879 /// @return true if the output stream is left in a non-erratic state.
1880 bool
write_sections(const config::sections_type & sections,std::ostream & out)1881 write_sections(const config::sections_type& sections,
1882 	       std::ostream& out)
1883 {
1884   for (config::sections_type::const_iterator i = sections.begin();
1885        i != sections.end();
1886        ++i)
1887     {
1888       write_section(**i, out);
1889       out << "\n";
1890     }
1891   return out.good();
1892 }
1893 
1894 /// Serialize a vector of sections that make up an ini config to a
1895 /// file.
1896 ///
1897 /// @param sections the vector of sections to serialize.
1898 ///
1899 /// @param out the output stream.
1900 ///
1901 /// @return true if the output stream is left in a non-erratic state.
1902 bool
write_sections(const config::sections_type & sections,const string & path)1903 write_sections(const config::sections_type& sections,
1904 	       const string& path)
1905 {
1906   std::ofstream f(path.c_str(), std::ofstream::binary);
1907 
1908   if (!f.good())
1909     return false;
1910 
1911   bool is_ok = write_sections(sections, f);
1912 
1913   f.close();
1914 
1915   return is_ok;
1916 }
1917 
1918 /// Serialize an instance of @ref config to an output stream.
1919 ///
1920 /// @param conf the instance of @ref config to serialize.
1921 ///
1922 /// @param output the output stream to serialize @p conf to.
1923 ///
1924 /// @return true upon successful completion.
1925 bool
write_config(const config & conf,std::ostream & output)1926 write_config(const config& conf,
1927 	     std::ostream& output)
1928 {
1929   if (!write_sections(conf.get_sections(), output))
1930     return false;
1931   return true;
1932 }
1933 
1934 /// Serialize an instance of @ref conf to an on-disk file.
1935 ///
1936 /// @param conf the instance of @ref config to serialize.
1937 ///
1938 /// @param path the path to the on-disk file to serialize to.
1939 ///
1940 /// @return true upon successful completion.
1941 bool
write_config(const config & conf,const string & path)1942 write_config(const config& conf,
1943 	     const string& path)
1944 {
1945   if (!write_sections(conf.get_sections(), path))
1946     return false;
1947   return true;
1948 }
1949 // </config writer stuff>
1950 
1951 // <function_call_expr stuff>
1952 
1953 /// The private data type of @ref function_call_expr.
1954 struct function_call_expr::priv
1955 {
1956   string		name_;
1957   vector<string>	arguments_;
1958 
privabigail::ini::function_call_expr::priv1959   priv()
1960   {}
1961 
privabigail::ini::function_call_expr::priv1962   priv(const string& name,
1963        const vector<string>& arguments)
1964     : name_(name),
1965       arguments_(arguments)
1966   {}
1967 }; // end struct function_call_expr::priv
1968 
1969 /// Constructor for the @ref function_call_expr type.
1970 ///
1971 /// @param name the name of the function being called.
1972 ///
1973 /// @param args a vector of the arguements of the function being
1974 /// called.
function_call_expr(const string & name,const vector<string> & args)1975 function_call_expr::function_call_expr(const string& name,
1976 				       const vector<string>& args)
1977   : priv_(new priv(name, args))
1978 {}
1979 
1980 /// Getter of the name of the function being called.
1981 ///
1982 /// @return the name of the function being called.
1983 const string&
get_name() const1984 function_call_expr::get_name() const
1985 {return priv_->name_;}
1986 
1987 /// Getter for the arguments of the function call expression.
1988 ///
1989 /// That is, a getter for the arguments of the function call.
1990 ///
1991 /// @return the operands of the function call expression.
1992 const vector<string>&
get_arguments() const1993 function_call_expr::get_arguments() const
1994 {return priv_->arguments_;}
1995 
1996 /// Getter for the arguments of the function call expression.
1997 ///
1998 /// That is, a getter for the arguments of the function call.
1999 ///
2000 /// @return the operands of the function call expression.
2001 vector<string>&
get_arguments()2002 function_call_expr::get_arguments()
2003 {return priv_->arguments_;}
2004 
2005 /// Read a function call expression and build its representation.
2006 ///
2007 /// @param input the input stream where to read the function call
2008 /// expression from.
2009 ///
2010 /// @param expr the expression resulting from the parsing.  This is an
2011 /// output parameter that is set iff this function returns true.
2012 ///
2013 /// @return true iff the parameter @p expr is successfully set with
2014 /// the resulting of parsing the @p input.
2015 bool
read_function_call_expr(std::istream & input,function_call_expr_sptr & expr)2016 read_function_call_expr(std::istream& input,
2017 			function_call_expr_sptr& expr)
2018 {
2019   read_context ctxt(input);
2020   return ctxt.read_function_call_expr(expr);
2021 }
2022 
2023 /// Read a function call expression and build its representation.
2024 ///
2025 /// @param input a string where to read the function call expression
2026 /// from.
2027 ///
2028 /// @param expr the expression resulting from the parsing.  This is an
2029 /// output parameter that is set iff this function returns true.
2030 ///
2031 /// @return true iff the parameter @p expr is successfully set with
2032 /// the resulting of parsing the @p input.
2033 bool
read_function_call_expr(const string & input,function_call_expr_sptr & expr)2034 read_function_call_expr(const string& input,
2035 			function_call_expr_sptr& expr)
2036 {
2037   std::istringstream in(input);
2038   return read_function_call_expr(in, expr);
2039 }
2040 
2041 /// Read a function call expression and build its representation.
2042 ///
2043 /// @param input a string where to read the function call expression
2044 /// from.
2045 ///
2046 /// @return the representation of the expression resulting from the
2047 /// parsing.
2048 function_call_expr_sptr
read_function_call_expr(const string & input)2049 read_function_call_expr(const string& input)
2050 {
2051   function_call_expr_sptr expr;
2052   read_function_call_expr(input, expr);
2053   return expr;
2054 }
2055 // </function_call_expr stuff>
2056 }// end namespace ini
2057 }// end namespace abigail
2058