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