00001 ////////////////////////////////////////////////////////////////////////// 00002 // This material is provided "as is", with absolutely no warranty 00003 // expressed or implied. Any use is at your own risk. 00004 // 00005 // Permission to use or copy this software for any purpose is hereby 00006 // granted without fee, provided the above notices are retained on all 00007 // copies. Permission to modify the code and to distribute modified code 00008 // is granted, provided the above notices are retained, and a notice that 00009 // the code was modified is included with the above copyright notice. 00010 ////////////////////////////////////////////////////////////////////////// 00011 /** @file 00012 @brief Configuration tools. 00013 00014 This header file contains a several tools, 00015 that helps to work with configurations. 00016 00017 @author Sergey Polichnoy 00018 */ 00019 #ifndef __OMNI_CONF_HPP_ 00020 #define __OMNI_CONF_HPP_ 00021 00022 #include <omni/defs.hpp> 00023 00024 #include <algorithm> 00025 #include <stdexcept> 00026 #include <assert.h> 00027 #include <sstream> 00028 #include <string> 00029 #include <vector> 00030 00031 namespace omni 00032 { 00033 // forward declarations and typedefs... 00034 namespace conf 00035 { 00036 // main classes 00037 template<typename Str> class ElementT; 00038 template<typename Str> class SectionT; 00039 template<typename Str> class ElementListT; 00040 template<typename Str> class SectionListT; 00041 00042 // exceptions 00043 namespace err 00044 { 00045 template<typename Str> class FailureT; 00046 template<typename Str> class AccessFailureT; 00047 template<typename Str> class ElementNotFoundT; 00048 template<typename Str> class NameIsAmbiguousT; 00049 template<typename Str> class ParsingFailureT; 00050 template<typename Str> class SyntaxErrorT; 00051 template<typename Str> class NameMismatchT; 00052 template<typename Str> class WritingFailureT; 00053 template<typename Str> class NameIsEmptyT; 00054 } // exceptions 00055 00056 // input/output 00057 namespace io 00058 { 00059 template<typename Str> class ParserT; 00060 template<typename Str> class WriterT; 00061 } // input/output 00062 00063 // implementation defined 00064 namespace details 00065 { 00066 template<typename Ch> class CharConst; 00067 template<typename Val> struct ConstTraits; 00068 template<typename Val> struct NConstTraits; 00069 template<typename Base, typename Tr> class Iterator; 00070 } // implementation defined 00071 00072 00073 #if OMNI_UNICODE 00074 /// @brief Default string container. 00075 typedef std::wstring String; 00076 #else 00077 /// @brief Default string container. 00078 typedef std::string String; 00079 #endif // OMNI_UNICODE 00080 00081 // main classes 00082 typedef ElementT<String> Element; ///< @brief Configuration element. 00083 typedef SectionT<String> Section; ///< @brief Configuration section. 00084 typedef ElementListT<String> ElementList; ///< @brief List of configuration elements. 00085 typedef SectionListT<String> SectionList; ///< @brief List of configuration sections. 00086 00087 namespace err 00088 { 00089 typedef FailureT<String> Failure; ///< @brief Basic exception. 00090 typedef AccessFailureT<String> AccessFailure; ///< @brief Access failure. 00091 typedef ElementNotFoundT<String> ElementNotFound; ///< @brief Element not found. 00092 typedef NameIsAmbiguousT<String> NameIsAmbiguous; ///< @brief Ambiguous element name. 00093 typedef ParsingFailureT<String> ParsingFailure; ///< @brief Basic parsing failure. 00094 typedef SyntaxErrorT<String> SyntaxError; ///< @brief Invalid syntax. 00095 typedef NameMismatchT<String> NameMismatch; ///< @brief Mismatch failure. 00096 typedef WritingFailureT<String> WritingFailure; ///< @brief Basic writing failure. 00097 typedef NameIsEmptyT<String> NameIsEmpty; ///< @brief Empty name failure. 00098 } 00099 00100 namespace io 00101 { 00102 typedef ParserT<String> Parser; ///< @brief Basic parser. 00103 typedef WriterT<String> Writer; ///< @brief Basic writer. 00104 } 00105 00106 } // forward declarations and typedefs 00107 00108 00109 // ElementT<> template class... 00110 namespace conf 00111 { 00112 00113 ////////////////////////////////////////////////////////////////////////// 00114 /// @brief Configuration element. 00115 /** 00116 This class represents a custom configuration element. The configuration 00117 element contains name, value and optional prefix and suffix comments. 00118 For example: 00119 00120 @code 00121 # prefix comment 00122 elem_name = "elem_value" # suffix comment 00123 @endcode 00124 00125 If the example will be parsed, then the element 00126 will have the following properties: 00127 - name() will be equal to the "elem_name", 00128 - val() will be equal to the "elem_value", 00129 - prefix() will be equal to the " prefix comment", 00130 - suffix() will be equal to the " suffix comment". 00131 00132 The fullName() method returns a configuration element's full name, 00133 including full path (i.e. names of all parents, see SectionT class). 00134 00135 It is possible to implicit assign the configuration element's value. 00136 00137 @code 00138 void f(Element &elem) 00139 { 00140 elem.val() = "new value"; 00141 // -or- 00142 elem = "new value"; 00143 } 00144 @endcode 00145 00146 The equal() method compares two configuration elements. 00147 Two configuration elements are equal if they have the same names, 00148 same values, and same prefix and suffix comments. 00149 The @b == and @b != operators also available. 00150 00151 The @a Str template parameter defines the string container type. 00152 A usual @a Str types are @a std::wstring or @a std::string. 00153 00154 @see @ref omni_config 00155 */ 00156 template<typename Str> 00157 class ElementT { 00158 typedef ElementT<Str> ThisType; 00159 typedef SectionT<Str> ParentType; 00160 00161 friend class io::WriterT<Str>; 00162 friend class SectionT<Str>; 00163 00164 typedef Str implementation_defined_1; 00165 typedef typename Str::traits_type Traits; 00166 typedef typename Traits::char_type implementation_defined_2; 00167 00168 ////////////////////////////////////////////////////////////////////////// 00169 /// @name Main typedefs 00170 /// @{ 00171 public: 00172 typedef implementation_defined_1 String; ///< @brief String type. 00173 typedef implementation_defined_2 Char; ///< @brief Char type. 00174 00175 /// @} 00176 ////////////////////////////////////////////////////////////////////////// 00177 00178 ////////////////////////////////////////////////////////////////////////// 00179 /// @name Constructors & destructor 00180 /// @{ 00181 public: 00182 00183 ////////////////////////////////////////////////////////////////////////// 00184 /// @brief Default constructor. 00185 /** 00186 This constructor creates a empty configuration element: 00187 the name, value, prefix and suffix comments are empty. 00188 */ 00189 ElementT() 00190 : m_parent(0) // will be set later 00191 {} 00192 00193 00194 ////////////////////////////////////////////////////////////////////////// 00195 /// @brief Create with specified name. 00196 /** 00197 This constructor initializes element name by @a element_name. 00198 The value, prefix and suffix comments are empty. 00199 00200 @param[in] element_name The element's name. 00201 */ 00202 explicit ElementT(const String &element_name) 00203 : m_parent(0), // will be set later 00204 m_name(element_name) 00205 {} 00206 00207 00208 ////////////////////////////////////////////////////////////////////////// 00209 /// @brief Create with specified name. 00210 /** 00211 This constructor initializes element name by @a element_name. 00212 The value, prefix and suffix comments are empty. 00213 00214 @param[in] element_name The element's name. 00215 */ 00216 explicit ElementT(const Char *element_name) 00217 : m_parent(0), // will be set later 00218 m_name(element_name) 00219 {} 00220 00221 00222 ////////////////////////////////////////////////////////////////////////// 00223 /// @brief Copy constructor. 00224 /** 00225 This constructor initializes the element by @a other. 00226 00227 @param[in] other The other element. 00228 */ 00229 ElementT(const ThisType &other) 00230 : m_parent(0), // will be set later 00231 m_name(other.m_name), 00232 m_val(other.m_val), 00233 m_prefix(other.m_prefix), 00234 m_suffix(other.m_suffix) 00235 {} 00236 00237 00238 ////////////////////////////////////////////////////////////////////////// 00239 /// @brief Destructor. 00240 /** 00241 The virtual destructor is used for derived classes. 00242 */ 00243 virtual ~ElementT() 00244 {} 00245 00246 /// @} 00247 ////////////////////////////////////////////////////////////////////////// 00248 00249 ////////////////////////////////////////////////////////////////////////// 00250 /// @name Assignments 00251 /// @{ 00252 public: 00253 00254 ////////////////////////////////////////////////////////////////////////// 00255 /// @brief Assignment operator. 00256 /** 00257 @param[in] other The other element. 00258 @return Self reference. 00259 */ 00260 ThisType& operator=(const ThisType &other) 00261 { 00262 ThisType t(other); 00263 swap(t); 00264 00265 return *this; 00266 } 00267 00268 00269 ////////////////////////////////////////////////////////////////////////// 00270 /// @brief Assign a new element's value. 00271 /** 00272 This assignment operator allows to implicit set the element's value. 00273 00274 @param[in] new_val The new element's value. 00275 @return Self reference. 00276 */ 00277 ThisType& operator=(const String &new_val) 00278 { 00279 m_val = new_val; 00280 return *this; 00281 } 00282 00283 00284 ////////////////////////////////////////////////////////////////////////// 00285 /// @brief Assign a new element's value. 00286 /** 00287 This assignment operator allows to implicit set the element's value. 00288 00289 @param[in] new_val The new element's value. 00290 @return Self reference. 00291 */ 00292 ThisType& operator=(const Char *new_val) 00293 { 00294 m_val = new_val; 00295 return *this; 00296 } 00297 00298 /// @} 00299 ////////////////////////////////////////////////////////////////////////// 00300 00301 ////////////////////////////////////////////////////////////////////////// 00302 /// @name Name & value 00303 /// @{ 00304 public: 00305 00306 ////////////////////////////////////////////////////////////////////////// 00307 /// @brief Get element's name. 00308 /** 00309 This method returns a constant reference to the element's name. 00310 00311 @return Constant name reference. 00312 */ 00313 const String& name() const 00314 { 00315 return m_name; 00316 } 00317 00318 00319 ////////////////////////////////////////////////////////////////////////// 00320 /// @brief Get/set element's name. 00321 /** 00322 This method returns a non-constant reference to the element's name. 00323 00324 @return Non-constant name reference. 00325 */ 00326 String& name() 00327 { 00328 return m_name; 00329 } 00330 00331 00332 ////////////////////////////////////////////////////////////////////////// 00333 /// @brief Get element's value. 00334 /** 00335 This method returns a constant reference to the element's value. 00336 00337 @return Constant value reference. 00338 */ 00339 const String& val() const 00340 { 00341 return m_val; 00342 } 00343 00344 00345 ////////////////////////////////////////////////////////////////////////// 00346 /// @brief Get/set element's value. 00347 /** 00348 This method returns a non-constant reference to the element's value. 00349 00350 @return Non-constant value reference. 00351 */ 00352 String& val() 00353 { 00354 return m_val; 00355 } 00356 00357 /// @} 00358 ////////////////////////////////////////////////////////////////////////// 00359 00360 ////////////////////////////////////////////////////////////////////////// 00361 /// @name Prefix & suffix comments 00362 /// @{ 00363 public: 00364 00365 ////////////////////////////////////////////////////////////////////////// 00366 /// @brief Get element's prefix comment. 00367 /** 00368 This method returns a constant reference 00369 to the element's prefix comment. 00370 00371 @return Constant prefix comment reference. 00372 */ 00373 const String& prefix() const 00374 { 00375 return m_prefix; 00376 } 00377 00378 00379 ////////////////////////////////////////////////////////////////////////// 00380 /// @brief Get/set element's prefix comment. 00381 /** 00382 This method returns a non-constant reference 00383 to the element's prefix comment. 00384 00385 @return Non-constant prefix comment reference. 00386 */ 00387 String& prefix() 00388 { 00389 return m_prefix; 00390 } 00391 00392 00393 ////////////////////////////////////////////////////////////////////////// 00394 /// @brief Get element's suffix comment. 00395 /** 00396 This method returns a constant reference 00397 to the element's suffix comment. 00398 00399 @return Constant suffix comment reference. 00400 */ 00401 const String& suffix() const 00402 { 00403 return m_suffix; 00404 } 00405 00406 00407 ////////////////////////////////////////////////////////////////////////// 00408 /// @brief Get/set element's suffix comment. 00409 /** 00410 This method returns a non-constant reference 00411 to the element's suffix comment. 00412 00413 @return Non-constant suffix comment reference. 00414 */ 00415 String& suffix() 00416 { 00417 return m_suffix; 00418 } 00419 00420 /// @} 00421 ////////////////////////////////////////////////////////////////////////// 00422 00423 ////////////////////////////////////////////////////////////////////////// 00424 /// @name Full name 00425 /// @{ 00426 public: 00427 00428 ////////////////////////////////////////////////////////////////////////// 00429 /// @brief Get element's full name. 00430 /** 00431 This method returns the element's full name, including all parents. 00432 The parent names are separated by @a sep string. For example, 00433 if @a sep is equal to the "|", then the full name of element "param1" 00434 will be "root|section|param1": 00435 00436 @code 00437 <root> 00438 <section> 00439 param1 = "value1" 00440 </section> 00441 </root> 00442 @endcode 00443 00444 @param[in] sep The separator. 00445 @return The element's full name. 00446 */ 00447 const String fullName(const String &sep) const 00448 { 00449 if (m_parent) 00450 { 00451 String full_name = m_parent->fullName(sep); 00452 if (!full_name.empty()) 00453 { 00454 full_name += sep; 00455 full_name += m_name; 00456 return full_name; 00457 } 00458 } 00459 00460 return m_name; 00461 } 00462 00463 00464 ////////////////////////////////////////////////////////////////////////// 00465 /// @brief Get element's full name. 00466 /** 00467 This method returns the element's full name, including all parents. 00468 The parent names are separated by @a sep string. For example, 00469 if @a sep is equal to the "|", then the full name of element "param1" 00470 will be "root|section|param1": 00471 00472 @code 00473 <root> 00474 <section> 00475 param1 = "value1" 00476 </section> 00477 </root> 00478 @endcode 00479 00480 @param[in] sep The separator. 00481 @return The element's full name. 00482 */ 00483 const String fullName(const Char *sep) const 00484 { 00485 if (m_parent) 00486 { 00487 String full_name = m_parent->fullName(sep); 00488 if (!full_name.empty()) 00489 { 00490 full_name += sep; 00491 full_name += m_name; 00492 return full_name; 00493 } 00494 } 00495 00496 return m_name; 00497 } 00498 00499 00500 ////////////////////////////////////////////////////////////////////////// 00501 /// @brief Get element's full name. 00502 /** 00503 This method returns the element's full name 00504 using default separator ":". 00505 00506 @return The element's full name. 00507 */ 00508 const String fullName() const 00509 { 00510 return fullName(details::CharConst<Char>::SEPARATOR); 00511 } 00512 00513 /// @} 00514 ////////////////////////////////////////////////////////////////////////// 00515 00516 ////////////////////////////////////////////////////////////////////////// 00517 /// @name Auxiliary 00518 /// @{ 00519 public: 00520 00521 ////////////////////////////////////////////////////////////////////////// 00522 /// @brief Are two elements equal? 00523 /** 00524 The two elements are equal if they have the same names, 00525 the same values and the same prefix and suffix comments. 00526 00527 @param[in] other The other element. 00528 @return @b true if two elements are equal, otherwise @b false. 00529 */ 00530 bool equal(const ThisType &other) const 00531 { 00532 return (m_name == other.m_name) 00533 && (m_val == other.m_val) 00534 && (m_prefix == other.m_prefix) 00535 && (m_suffix == other.m_suffix); 00536 } 00537 00538 00539 ////////////////////////////////////////////////////////////////////////// 00540 /// @brief Swap two elements. 00541 /** 00542 This method swaps the two elements. 00543 The parents are not changed. 00544 00545 @param[in,out] other The other element. 00546 */ 00547 void swap(ThisType &other) 00548 { 00549 // (!) do not swap parents 00550 00551 m_name.swap(other.m_name); 00552 m_val.swap(other.m_val); 00553 00554 m_prefix.swap(other.m_prefix); 00555 m_suffix.swap(other.m_suffix); 00556 } 00557 00558 00559 ////////////////////////////////////////////////////////////////////////// 00560 /// @brief Get empty element. 00561 /** 00562 This static method returns a constant reference to the empty element. 00563 This empty element may be used as default value. 00564 00565 @code 00566 void f(const Section &cfg) 00567 { 00568 const Element &elem = cfg.elements.get("param", Element::EMPTY()); 00569 00570 // ... 00571 } 00572 @endcode 00573 00574 @return The empty element. 00575 */ 00576 static const ThisType& EMPTY() 00577 { 00578 static ThisType g_empty; 00579 return g_empty; 00580 } 00581 00582 /// @} 00583 ////////////////////////////////////////////////////////////////////////// 00584 00585 private: 00586 00587 ////////////////////////////////////////////////////////////////////////// 00588 /// @brief Is it section? 00589 /** 00590 This method is used for dynamic type identification. 00591 00592 @return Always @b false. 00593 */ 00594 virtual bool is_section() const 00595 { 00596 return false; 00597 } 00598 00599 00600 ////////////////////////////////////////////////////////////////////////// 00601 /// @brief Get parent section. 00602 /** 00603 This method returns a pointer to the parent 00604 or null if element has no parent (i.e. element is root). 00605 00606 @return Pointer to the parent or null. 00607 */ 00608 const ParentType* parent() const 00609 { 00610 return m_parent; 00611 } 00612 00613 00614 ////////////////////////////////////////////////////////////////////////// 00615 /// @brief Set parent section. 00616 /** 00617 This method sets the new element's parent. 00618 00619 @param[in] new_parent Pointer to the parent or null. 00620 */ 00621 void set_parent(ParentType *new_parent) 00622 { 00623 m_parent = new_parent; 00624 } 00625 00626 00627 private: 00628 ParentType *m_parent; ///< @brief The parent or null. 00629 00630 String m_name; ///< @brief The name. 00631 String m_val; ///< @brief The value. 00632 00633 String m_prefix; ///< @brief The prefix comment. 00634 String m_suffix; ///< @brief The suffix comment. 00635 }; 00636 00637 00638 ////////////////////////////////////////////////////////////////////////// 00639 /// @brief Are two elements equal? 00640 /** @relates ElementT 00641 00642 This operator is equivalent to the: 00643 00644 @code 00645 x.equal(y); 00646 @endcode 00647 00648 @param[in] x The first element. 00649 @param[in] y The second element. 00650 @return @b true if two elements are equal, otherwise @b false. 00651 */ 00652 template<typename Str> inline 00653 bool operator==(const ElementT<Str> &x, const ElementT<Str> &y) 00654 { 00655 return x.equal(y); 00656 } 00657 00658 00659 ////////////////////////////////////////////////////////////////////////// 00660 /// @brief Are two elements non-equal? 00661 /** @relates ElementT 00662 00663 This operator is equivalent to the: 00664 00665 @code 00666 !x.equal(y); 00667 @endcode 00668 00669 @param[in] x The first element. 00670 @param[in] y The second element. 00671 @return @b true if two elements are non-equal, otherwise @b false. 00672 */ 00673 template<typename Str> inline 00674 bool operator!=(const ElementT<Str> &x, const ElementT<Str> &y) 00675 { 00676 return !x.equal(y); 00677 } 00678 00679 00680 ////////////////////////////////////////////////////////////////////////// 00681 /// @brief Swap two elements. 00682 /** @relates ElementT 00683 00684 This function is equivalent to the: 00685 00686 @code 00687 x.swap(y); 00688 @endcode 00689 00690 @param[in,out] x The first element. 00691 @param[in,out] y The second element. 00692 */ 00693 template<typename Str> inline 00694 void swap(ElementT<Str> &x, ElementT<Str> &y) 00695 { 00696 x.swap(y); 00697 } 00698 00699 } // ElementT<> template class 00700 00701 00702 // SectionT<> template class... 00703 namespace conf 00704 { 00705 00706 ////////////////////////////////////////////////////////////////////////// 00707 /// @brief Configuration section. 00708 /** 00709 The configuration section contains the list of the child elements 00710 and the list of the child sections. 00711 00712 Because the SectionT class is derived from the ElementT class, 00713 it also contains name, value (!), prefix and suffix comments. 00714 00715 Единый список секций и параметров служит для организации проивольного 00716 порядка секций и параметров. Т.е. секции и параметры могут чередоваться. 00717 Так, например, при чтении секции из файла конфигурации сохраняется 00718 относительный порядок дочерних секций и параметров. 00719 00720 The @a Str template parameter defines the string container type. 00721 A usual @a Str types are @a std::wstring or @a std::string. 00722 00723 @see @ref omni_config 00724 */ 00725 template<typename Str> 00726 class SectionT: public ElementT<Str> { 00727 typedef ElementT<Str> inherited; 00728 typedef SectionT<Str> ThisType; 00729 00730 friend class ElementListT<Str>; 00731 friend class SectionListT<Str>; 00732 friend class io::WriterT<Str>; 00733 00734 ////////////////////////////////////////////////////////////////////////// 00735 /// @name Main typedefs 00736 /// @{ 00737 public: 00738 typedef typename inherited::String String; ///< @brief String type. 00739 typedef typename inherited::Char Char; ///< @brief Char type. 00740 00741 typedef ElementListT<String> ElementList; ///< @brief List of child elements. 00742 typedef SectionListT<String> SectionList; ///< @brief List of child sections. 00743 00744 /// @} 00745 ////////////////////////////////////////////////////////////////////////// 00746 00747 ////////////////////////////////////////////////////////////////////////// 00748 /// @name Constructors & destructor 00749 /// @{ 00750 public: 00751 00752 ////////////////////////////////////////////////////////////////////////// 00753 /// @brief Default constructor. 00754 /** 00755 The created section has no child elements and no child sections. 00756 */ 00757 SectionT() 00758 { 00759 sections.set_owner(this); 00760 elements.set_owner(this); 00761 } 00762 00763 00764 ////////////////////////////////////////////////////////////////////////// 00765 /// @brief Create with specified name. 00766 /** 00767 This constructor creates the empty section with name @a section_name. 00768 00769 @param[in] section_name The section's name. 00770 */ 00771 explicit SectionT(const String §ion_name) 00772 : inherited(section_name) 00773 { 00774 sections.set_owner(this); 00775 elements.set_owner(this); 00776 } 00777 00778 00779 ////////////////////////////////////////////////////////////////////////// 00780 /// @brief Create with specified name. 00781 /** 00782 This constructor creates the empty section with name @a section_name. 00783 00784 @param[in] section_name The section's name. 00785 */ 00786 explicit SectionT(const Char *section_name) 00787 : inherited(section_name) 00788 { 00789 sections.set_owner(this); 00790 elements.set_owner(this); 00791 } 00792 00793 00794 ////////////////////////////////////////////////////////////////////////// 00795 /// @brief Copy constructor. 00796 /** 00797 This constructor initializes the section by @a other. 00798 00799 @param[in] other The other section. 00800 */ 00801 SectionT(const ThisType &other) 00802 : inherited(other) 00803 { 00804 sections.set_owner(this); 00805 elements.set_owner(this); 00806 00807 // TODO: speed optimization if possible? 00808 00809 // copy all child elements 00810 typename Container::const_iterator i = other.m_childs.begin(); 00811 typename Container::const_iterator ie = other.m_childs.end(); 00812 for (; i != ie; ++i) 00813 { 00814 const inherited &elem = *(*i); 00815 00816 if (elem.is_section()) 00817 sections.push_back(static_cast<const ThisType&>(elem)); 00818 else 00819 elements.push_back(elem); 00820 } 00821 } 00822 00823 00824 ////////////////////////////////////////////////////////////////////////// 00825 /// @brief Destructor. 00826 /** 00827 The destructor removes all child elements and all child sections. 00828 */ 00829 virtual ~SectionT() 00830 { 00831 sections.clear(); 00832 elements.clear(); 00833 } 00834 00835 /// @} 00836 ////////////////////////////////////////////////////////////////////////// 00837 00838 ////////////////////////////////////////////////////////////////////////// 00839 /// @name Assignments 00840 /// @{ 00841 public: 00842 00843 ////////////////////////////////////////////////////////////////////////// 00844 /// @brief Assignment operator. 00845 /** 00846 @param[in] other The other section. 00847 @return Self reference. 00848 */ 00849 ThisType& operator=(const ThisType &other) 00850 { 00851 ThisType t(other); 00852 swap(t); 00853 00854 return *this; 00855 } 00856 00857 // using inherited::operator=; 00858 00859 00860 ////////////////////////////////////////////////////////////////////////// 00861 /// @brief Merge configuration. 00862 /** 00863 This method replaces the some child elements and some child sections 00864 with corresponding child elements and child sections of @a other section. 00865 The only elements with the same names will be replaces. If element with 00866 specified name not exists yet, it will be added. 00867 00868 For examples, let two section A and B: 00869 00870 @code 00871 <A> 00872 elem1 = "A_value1" 00873 elem2 = "A_value2" 00874 </A> 00875 00876 <B> 00877 elem1 = "B_value1" 00878 elem3 = "B_value3" 00879 </B> 00880 @endcode 00881 00882 After the command @a A.merge(B), the A section will be: 00883 00884 @code 00885 <A> 00886 elem1 = "B_value1" 00887 elem2 = "A_value2" 00888 elem3 = "B_value3" 00889 </B> 00890 @endcode 00891 00892 @param[in] other The other section. 00893 @return Self reference. 00894 */ 00895 ThisType& merge(const ThisType &other) 00896 { 00897 { // merge child sections 00898 typename SectionList::const_iterator i = other.sections.begin(); 00899 typename SectionList::const_iterator ie = other.sections.end(); 00900 00901 for (; i != ie; ++i) 00902 sections[i->name()].merge(*i); 00903 } 00904 00905 { // merge child elements 00906 typename ElementList::const_iterator i = other.elements.begin(); 00907 typename ElementList::const_iterator ie = other.elements.end(); 00908 for (; i != ie; ++i) 00909 elements[i->name()] = (*i); 00910 } 00911 00912 return *this; 00913 } 00914 00915 /// @} 00916 ////////////////////////////////////////////////////////////////////////// 00917 00918 ////////////////////////////////////////////////////////////////////////// 00919 /// @name Child elements & child sections 00920 /// @{ 00921 public: 00922 00923 ////////////////////////////////////////////////////////////////////////// 00924 /// @brief List of the child elements. 00925 /** 00926 Because ElementList has operator()() and operator[]() 00927 you cat use the following code: 00928 00929 @code 00930 void f(const Section &cfg) 00931 { 00932 cfg.elements().get("elem_name"); 00933 cfg.elements.get("elem_name"); 00934 cfg.elements["elem_name"]; 00935 } 00936 @endcode 00937 00938 @see ElementListT 00939 */ 00940 ElementList elements; 00941 00942 00943 ////////////////////////////////////////////////////////////////////////// 00944 /// @brief List of the child sections. 00945 /** 00946 Because ElementList has operator()() and operator[]() 00947 you cat use the following code: 00948 00949 @code 00950 void f(const Section &cfg) 00951 { 00952 cfg.sections().get("child_name"); 00953 cfg.sections.get("child_name"); 00954 cfg.sections["child_name"]; 00955 } 00956 @endcode 00957 00958 @see SectionListT 00959 */ 00960 SectionList sections; 00961 00962 /// @} 00963 ////////////////////////////////////////////////////////////////////////// 00964 00965 ////////////////////////////////////////////////////////////////////////// 00966 /// @name Auxiliary 00967 /// @{ 00968 public: 00969 00970 ////////////////////////////////////////////////////////////////////////// 00971 /// @brief Are two sections equal? 00972 /** 00973 The two sections are equal is they have the same names, 00974 the same values, the same prefix and suffix comments and 00975 the same child elements and child sections. 00976 00977 @param[in] other The other section. 00978 @return @b true if two sections are equal, otherwise @b false. 00979 */ 00980 bool equal(const ThisType &other) const 00981 { 00982 return inherited::equal(other) 00983 && sections.equal(other.sections) 00984 && elements.equal(other.elements); 00985 } 00986 00987 00988 ////////////////////////////////////////////////////////////////////////// 00989 /// @brief Swap sections. 00990 /** 00991 This method swaps the two sections. 00992 00993 @param[in,out] other The other section. 00994 */ 00995 void swap(ThisType &other) 00996 { 00997 inherited::swap(other); 00998 00999 // change child elements 01000 m_childs.swap(other.m_childs); 01001 sections.swap(other.sections); 01002 elements.swap(other.elements); 01003 01004 { // change parent of all child elements 01005 typename Container::iterator i = this->m_childs.begin(); 01006 typename Container::iterator ie = this->m_childs.end(); 01007 01008 for (; i != ie; ++i) 01009 (*i)->set_parent(this); 01010 } 01011 01012 { // change parent of all child elements 01013 typename Container::iterator i = other.m_childs.begin(); 01014 typename Container::iterator ie = other.m_childs.end(); 01015 01016 for (; i != ie; ++i) 01017 (*i)->set_parent(&other); 01018 } 01019 } 01020 01021 01022 ////////////////////////////////////////////////////////////////////////// 01023 /// @brief Get empty section. 01024 /** 01025 This static method returns a constant reference to the empty section. 01026 This empty section may be used as default value. 01027 01028 @code 01029 void f(const Section &cfg) 01030 { 01031 const Section &sub_cfg = cfg.sections.get("child", Section::EMPTY()); 01032 01033 // ... 01034 } 01035 @endcode 01036 01037 @return The empty section. 01038 */ 01039 static const ThisType& EMPTY() 01040 { 01041 static ThisType g_empty; 01042 return g_empty; 01043 } 01044 01045 /// @} 01046 ////////////////////////////////////////////////////////////////////////// 01047 01048 private: 01049 01050 ////////////////////////////////////////////////////////////////////////// 01051 /// @brief Is it section? 01052 /** 01053 This method is used for dynamic type identification. 01054 01055 @return Always @b true. 01056 */ 01057 virtual bool is_section() const 01058 { 01059 return true; 01060 } 01061 01062 01063 ////////////////////////////////////////////////////////////////////////// 01064 /// @brief Insert child element or child section. 01065 /** 01066 The element will be inserted into the internal order list. 01067 01068 @param[in] elem The child element or child section. 01069 */ 01070 void do_insert(inherited *elem) 01071 { 01072 m_childs.push_back(elem); 01073 elem->set_parent(this); 01074 } 01075 01076 01077 ////////////////////////////////////////////////////////////////////////// 01078 /// @brief Remove child element or child section. 01079 /** 01080 The element will be removed from the internal order list. 01081 01082 @param[in] elem The child element or child section. 01083 */ 01084 void do_remove(inherited *elem) 01085 { 01086 typename Container::iterator found = std::find( 01087 m_childs.begin(), m_childs.end(), elem); 01088 assert(found != m_childs.end() 01089 && "element not exists"); 01090 01091 if (found != m_childs.end()) 01092 { 01093 m_childs.erase(found); 01094 01095 assert(this == elem->parent() 01096 && "invalid parent"); 01097 elem->set_parent(0); 01098 } 01099 } 01100 01101 01102 private: 01103 typedef std::vector<inherited*> Container; ///< @brief The order list type. 01104 01105 Container m_childs; ///< @brief The order list. 01106 }; 01107 01108 01109 ////////////////////////////////////////////////////////////////////////// 01110 /// @brief Are two sections equal? 01111 /** @relates SectionT 01112 01113 This operator is equivalent to the: 01114 01115 @code 01116 x.equal(y); 01117 @endcode 01118 01119 @param[in] x The first section. 01120 @param[in] y The second section. 01121 @return @b true if two sections are equal, otherwise @b false. 01122 */ 01123 template<typename Str> inline 01124 bool operator==(const SectionT<Str> &x, const SectionT<Str> &y) 01125 { 01126 return x.equal(y); 01127 } 01128 01129 01130 ////////////////////////////////////////////////////////////////////////// 01131 /// @brief Are two sections non-equal? 01132 /** @relates SectionT 01133 01134 This operator is equivalent to the: 01135 01136 @code 01137 !x.equal(y); 01138 @endcode 01139 01140 @param[in] x The first section. 01141 @param[in] y The second section. 01142 @return @b true if two sections are non-equal, otherwise @b false. 01143 */ 01144 template<typename Str> inline 01145 bool operator!=(const SectionT<Str> &x, const SectionT<Str> &y) 01146 { 01147 return !x.equal(y); 01148 } 01149 01150 01151 ////////////////////////////////////////////////////////////////////////// 01152 /// @brief Swap two sections. 01153 /** @relates SectionT 01154 01155 This function is equivalent to the: 01156 01157 @code 01158 x.swap(y); 01159 @endcode 01160 01161 @param[in,out] x The first section. 01162 @param[in,out] y The second section. 01163 */ 01164 template<typename Str> inline 01165 void swap(SectionT<Str> &x, SectionT<Str> &y) 01166 { 01167 x.swap(y); 01168 } 01169 01170 } // SectionT<> template class 01171 01172 01173 // ElementListT<> template classes 01174 namespace conf 01175 { 01176 01177 ////////////////////////////////////////////////////////////////////////// 01178 /// @brief List of configuration elements. 01179 /** 01180 This is auxiliary class. You can't create instances of this class. 01181 Instead use SectionT::elements property. 01182 01183 The class is a container of configuration elements. It contains 01184 a several manipulators: push_back(), remove(), exists(). It also 01185 supports iterator methods: begin() and end(). 01186 01187 The class contains operator()(), which returns self reference. 01188 So, you can use one of the following: 01189 01190 @code 01191 void f(Section &s) 01192 { 01193 s.elements().push_back(); 01194 // -or- 01195 s.elements.push_back(); 01196 } 01197 @endcode 01198 01199 To access child element by name you can use one of the overloaded 01200 get() methods. To access child element value you can use one of the 01201 overloaded getv() method. Also you can use operator[](): 01202 01203 @code 01204 // element's value access 01205 void f(const Section &s) 01206 { 01207 s.elements.get("elem_name").val(); 01208 s.elements["elem_name"].val(); 01209 s.elements.getv("elem_name"); 01210 } 01211 @endcode 01212 01213 You can access element by name only if the name is unique. Otherwise 01214 you can use begin() and end() methods to iterate all child elements. 01215 01216 @see @ref omni_config 01217 */ 01218 template<typename Str> 01219 class ElementListT: private omni::NonCopyable { 01220 typedef ElementListT<Str> ThisType; 01221 typedef SectionT<Str>* OwnerType; 01222 typedef std::vector<ElementT<Str>*> Container; 01223 01224 typedef details::Iterator<typename Container::const_iterator, 01225 details::ConstTraits< ElementT<Str> > > implementation_defined_1; 01226 typedef details::Iterator<typename Container::iterator, 01227 details::NConstTraits< ElementT<Str> > > implementation_defined_2; 01228 01229 friend class SectionT<Str>; 01230 01231 ////////////////////////////////////////////////////////////////////////// 01232 /// @name Main typedefs 01233 /// @{ 01234 public: 01235 typedef ElementT<Str> value_type; ///< @brief Value type. 01236 01237 typedef const value_type& const_reference; ///< @brief Constant reference. 01238 typedef value_type& reference; ///< @brief Non-constant reference. 01239 01240 typedef typename value_type::String String; ///< @brief String type. 01241 typedef typename value_type::Char Char; ///< @brief Char type. 01242 01243 typedef typename Container::size_type size_type; ///< @brief Size type. 01244 01245 /// @} 01246 ////////////////////////////////////////////////////////////////////////// 01247 01248 private: 01249 01250 ////////////////////////////////////////////////////////////////////////// 01251 /// @brief Default constructor. 01252 /** 01253 This constructor creates empty list. 01254 01255 Only friends may create the element list. 01256 */ 01257 ElementListT() 01258 : m_owner(0) // will be set later 01259 {} 01260 01261 01262 ////////////////////////////////////////////////////////////////////////// 01263 /// @brief Destructor. 01264 /** 01265 Only friends may destroy the element list. 01266 */ 01267 ~ElementListT() 01268 { 01269 assert(empty() && "list not empty"); 01270 } 01271 01272 01273 ////////////////////////////////////////////////////////////////////////// 01274 /// @name Iterators 01275 /// @{ 01276 public: 01277 01278 typedef implementation_defined_1 const_iterator; ///< @brief Constant iterator. 01279 typedef implementation_defined_2 iterator; ///< @brief Non-constant iterator. 01280 01281 ////////////////////////////////////////////////////////////////////////// 01282 /// @brief Begin of the list. 01283 /** 01284 @return The constant iterator. 01285 */ 01286 const const_iterator begin() const 01287 { 01288 return const_iterator(m_items.begin()); 01289 } 01290 01291 01292 ////////////////////////////////////////////////////////////////////////// 01293 /// @brief Begin of the list. 01294 /** 01295 @return The non-constant iterator. 01296 */ 01297 const iterator begin() 01298 { 01299 return iterator(m_items.begin()); 01300 } 01301 01302 01303 ////////////////////////////////////////////////////////////////////////// 01304 /// @brief End of the list. 01305 /** 01306 @return The constant iterator. 01307 */ 01308 const const_iterator end() const 01309 { 01310 return const_iterator(m_items.end()); 01311 } 01312 01313 01314 ////////////////////////////////////////////////////////////////////////// 01315 /// @brief End of the list. 01316 /** 01317 @return The non-constant iterator. 01318 */ 01319 const iterator end() 01320 { 01321 return iterator(m_items.end()); 01322 } 01323 01324 /// @} 01325 ////////////////////////////////////////////////////////////////////////// 01326 01327 ////////////////////////////////////////////////////////////////////////// 01328 /// @name Front & Back 01329 /// @{ 01330 public: 01331 01332 ////////////////////////////////////////////////////////////////////////// 01333 /// @brief First element. 01334 /** 01335 @return Constant reference. 01336 */ 01337 const_reference front() const 01338 { 01339 return *m_items.front(); 01340 } 01341 01342 01343 ////////////////////////////////////////////////////////////////////////// 01344 /// @brief First element. 01345 /** 01346 @return Non-constant reference. 01347 */ 01348 reference front() 01349 { 01350 return *m_items.front(); 01351 } 01352 01353 01354 ////////////////////////////////////////////////////////////////////////// 01355 /// @brief Last element. 01356 /** 01357 @return Constant reference. 01358 */ 01359 const_reference back() const 01360 { 01361 return *m_items.back(); 01362 } 01363 01364 01365 ////////////////////////////////////////////////////////////////////////// 01366 /// @brief Last element. 01367 /** 01368 @return Non-constant reference. 01369 */ 01370 reference back() 01371 { 01372 return *m_items.back(); 01373 } 01374 01375 /// @} 01376 ////////////////////////////////////////////////////////////////////////// 01377 01378 ////////////////////////////////////////////////////////////////////////// 01379 /// @name Get element by name 01380 /// @{ 01381 public: 01382 01383 ////////////////////////////////////////////////////////////////////////// 01384 /// @brief Get element by name. 01385 /** 01386 This method returns a element with specified name @a name. 01387 If the element with that name is not exists or the name 01388 is not unique the exception will be thrown. 01389 01390 @param[in] name The element's name. 01391 @return Constant reference. 01392 @throw omni::conf::err::ElementNotFoundT If element not found. 01393 @throw omni::conf::err::NameIsAmbiguousT If element's name is not unique. 01394 */ 01395 const_reference get(const String &name) const 01396 { 01397 const_iterator found = find(name, begin()); 01398 if (found == end()) 01399 throw err::ElementNotFoundT<String>(name, m_owner->fullName()); 01400 01401 const_reference elem = *found; 01402 if (find(name, ++found) != end()) 01403 throw err::NameIsAmbiguousT<String>(name, m_owner->fullName()); 01404 01405 return elem; 01406 } 01407 01408 01409 ////////////////////////////////////////////////////////////////////////// 01410 /// @brief Get element by name. 01411 /** 01412 This method returns a element with specified name @a name. 01413 If the element with that name is not exists or the name 01414 is not unique the exception will be thrown. 01415 01416 @param[in] name The element's name. 01417 @return Constant reference. 01418 @throw omni::conf::err::ElementNotFoundT If element not found. 01419 @throw omni::conf::err::NameIsAmbiguousT If element's name is not unique. 01420 */ 01421 const_reference get(const Char *name) const 01422 { 01423 const_iterator found = find(name, begin()); 01424 if (found == end()) 01425 throw err::ElementNotFoundT<String>(name, m_owner->fullName()); 01426 01427 const_reference elem = *found; 01428 if (find(name, ++found) != end()) 01429 throw err::NameIsAmbiguousT<String>(name, m_owner->fullName()); 01430 01431 return elem; 01432 } 01433 01434 01435 ////////////////////////////////////////////////////////////////////////// 01436 /// @brief Get element by name or default. 01437 /** 01438 This method returns a element with specified name @a name. 01439 If the element with that name is not exists, then the @a def element 01440 will be returned. If the element's name is not unique the exception 01441 will be thrown. 01442 01443 @param[in] name The element's name. 01444 @param[in] def The default element. 01445 @return Constant reference. 01446 @throw omni::conf::err::NameIsAmbiguousT If element's name is not unique. 01447 */ 01448 const_reference get(const String &name, const_reference def) const 01449 { 01450 const_iterator found = find(name, begin()); 01451 if (found == end()) 01452 return def; 01453 01454 const_reference elem = *found; 01455 if (find(name, ++found) != end()) 01456 throw err::NameIsAmbiguousT<String>(name, m_owner->fullName()); 01457 01458 return elem; 01459 } 01460 01461 01462 ////////////////////////////////////////////////////////////////////////// 01463 /// @brief Get element by name or default. 01464 /** 01465 This method returns a element with specified name @a name. 01466 If the element with that name is not exists, then the @a def element 01467 will be returned. If the element's name is not unique the exception 01468 will be thrown. 01469 01470 @param[in] name The element's name. 01471 @param[in] def The default element. 01472 @return Constant reference. 01473 @throw omni::conf::err::NameIsAmbiguousT If element's name is not unique. 01474 */ 01475 const_reference get(const Char *name, const_reference def) const 01476 { 01477 const_iterator found = find(name, begin()); 01478 if (found == end()) 01479 return def; 01480 01481 const_reference elem = *found; 01482 if (find(name, ++found) != end()) 01483 throw err::NameIsAmbiguousT<String>(name, m_owner->fullName()); 01484 01485 return elem; 01486 } 01487 01488 01489 ////////////////////////////////////////////////////////////////////////// 01490 /// @brief Get element by name or create. 01491 /** 01492 Метод возвращает элемент с именем @a name. Если элемента с таким 01493 именем нет, но установлен флаг @a create, то будет создан новый элемент. 01494 Если же флаг @a create не установлен, будет сгенерировано исключение. 01495 Если есть два или более элементов с таким именем, также будет 01496 сгенерировано исключение. 01497 01498 @param[in] name The element's name. 01499 @param[in] create Create if not exists flag. 01500 @return Non-constant reference. 01501 @throw omni::conf::err::ElementNotFoundT IF element not found and @a create flag not set. 01502 @throw omni::conf::err::NameIsAmbiguousT If element's name is not unique. 01503 */ 01504 reference get(const String &name, bool create = false) 01505 { 01506 iterator found = find(name, begin()); 01507 if (found == end()) 01508 { 01509 if (create) 01510 return push_back(name); 01511 else 01512 throw err::ElementNotFoundT<String>(name, m_owner->fullName()); 01513 } 01514 01515 reference elem = *found; 01516 if (find(name, ++found) != end()) 01517 throw err::NameIsAmbiguousT<String>(name, m_owner->fullName()); 01518 01519 return elem; 01520 } 01521 01522 01523 ////////////////////////////////////////////////////////////////////////// 01524 /// @brief Get element by name or create. 01525 /** 01526 Метод возвращает элемент с именем @a name. Если элемента с таким 01527 именем нет, но установлен флаг @a create, то будет создан новый элемент. 01528 Если же флаг @a create не установлен, будет сгенерировано исключение. 01529 Если есть два или более элементов с таким именем, также будет 01530 сгенерировано исключение. 01531 01532 @param[in] name The element's name. 01533 @param[in] create Create if not exists flag. 01534 @return Non-constant reference. 01535 @throw omni::conf::err::ElementNotFoundT IF element not found and @a create flag not set. 01536 @throw omni::conf::err::NameIsAmbiguousT If element's name is not unique. 01537 */ 01538 reference get(const Char *name, bool create = false) 01539 { 01540 iterator found = find(name, begin()); 01541 if (found == end()) 01542 { 01543 if (create) 01544 return push_back(name); 01545 else 01546 throw err::ElementNotFoundT<String>(name, m_owner->fullName()); 01547 } 01548 01549 reference elem = *found; 01550 if (find(name, ++found) != end()) 01551 throw err::NameIsAmbiguousT<String>(name, m_owner->fullName()); 01552 01553 return elem; 01554 } 01555 01556 /// @} 01557 ////////////////////////////////////////////////////////////////////////// 01558 01559 ////////////////////////////////////////////////////////////////////////// 01560 /// @name Get element's value by name 01561 /// @{ 01562 01563 public: 01564 01565 ////////////////////////////////////////////////////////////////////////// 01566 /// @brief Значение элемента с заданным именем 01567 /** 01568 Метод возвращает значение элемента с именем @a name. Если элемента с 01569 таким именем нет или есть два или более, то будет сгенерировано исключение. 01570 01571 @param[in] name Имя элемента списка 01572 @return Значение найденного элемента списка 01573 @throw omni::config::NotFoundFailureT Если элемент с таким именем не найден 01574 @throw omni::config::AmbiguousFailureT Если имя элемента не уникально 01575 */ 01576 const String& getv(const String &name) const 01577 { 01578 return get(name).val(); 01579 } 01580 01581 ////////////////////////////////////////////////////////////////////////// 01582 /// @brief Значение элемента с заданным именем 01583 /** 01584 Метод возвращает значение элемента с именем @a name. Если элемента с 01585 таким именем нет или есть два или более, то будет сгенерировано исключение. 01586 01587 @param[in] name Имя элемента списка 01588 @return Значение найденного элемента списка 01589 @throw omni::config::NotFoundFailureT Если элемент с таким именем не найден 01590 @throw omni::config::AmbiguousFailureT Если имя элемента не уникально 01591 */ 01592 const String& getv(const Char *name) const 01593 { 01594 return get(name).val(); 01595 } 01596 01597 01598 ////////////////////////////////////////////////////////////////////////// 01599 /// @brief Значение элемента с заданным именем (по умолчанию) 01600 /** 01601 Метод возвращает значение элемента с именем @a name. Если элемента 01602 с таким именем нет, то будет возвращено значение @a def. Если с таким 01603 именем есть два или более элементов, то будет сгенерировано исключение. 01604 01605 @param[in] name Имя элемента списка 01606 @param[in] def Возвращаемое значение по умолчанию 01607 @return Значение найденного элемента списка 01608 @throw omni::config::AmbiguousFailureT Если имя элемента не уникально 01609 */ 01610 const String& getv(const String &name, const String &def) const 01611 { 01612 const_iterator found = find(name, begin()); 01613 if (found == end()) 01614 return def; 01615 01616 const_reference elem = *found; 01617 if (find(name, ++found) != end()) 01618 throw err::NameIsAmbiguousT<String>(name, m_owner->fullName()); 01619 01620 return elem.val(); 01621 } 01622 01623 01624 ////////////////////////////////////////////////////////////////////////// 01625 /// @brief Значение элемента с заданным именем (по умолчанию) 01626 /** 01627 Метод возвращает значение элемента с именем @a name. Если элемента 01628 с таким именем нет, то будет возвращено значение @a def. Если с таким 01629 именем есть два или более элементов, то будет сгенерировано исключение. 01630 01631 @param[in] name Имя элемента списка 01632 @param[in] def Возвращаемое значение по умолчанию 01633 @return Значение найденного элемента списка 01634 @throw omni::config::AmbiguousFailureT Если имя элемента не уникально 01635 */ 01636 const String& getv(const Char *name, const String &def) const 01637 { 01638 const_iterator found = find(name, begin()); 01639 if (found == end()) 01640 return def; 01641 01642 const_reference elem = *found; 01643 if (find(name, ++found) != end()) 01644 throw err::NameIsAmbiguousT<String>(name, m_owner->fullName()); 01645 01646 return elem.val(); 01647 } 01648 01649 ////////////////////////////////////////////////////////////////////////// 01650 /// @brief Значение элемента с заданным именем (по умолчанию) 01651 /** 01652 Метод возвращает значение элемента с именем @a name. Если элемента 01653 с таким именем нет, то будет возвращено значение @a def. Если с таким 01654 именем есть два или более элементов, то будет сгенерировано исключение. 01655 01656 @param[in] name Имя элемента списка 01657 @param[in] def Возвращаемое значение по умолчанию 01658 @return Значение найденного элемента списка 01659 @throw omni::config::AmbiguousFailureT Если имя элемента не уникально 01660 */ 01661 const Char* getv(const Char *name, const Char *def) const 01662 { 01663 const_iterator found = find(name, begin()); 01664 if (found == end()) 01665 return def; 01666 01667 const_reference elem = *found; 01668 if (find(name, ++found) != end()) 01669 throw err::NameIsAmbiguousT<String>(name, m_owner->fullName()); 01670 01671 return elem.val().c_str(); 01672 } 01673 01674 /// @} 01675 ////////////////////////////////////////////////////////////////////////// 01676 01677 ////////////////////////////////////////////////////////////////////////// 01678 /// @name Auxiliary operators 01679 /// @{ 01680 public: 01681 01682 ////////////////////////////////////////////////////////////////////////// 01683 /// @brief Элемент с заданным именем 01684 /** 01685 Метод является псевдонимом для get(name). 01686 01687 @param[in] name Имя элемента списка 01688 @return Константная ссылка на найденный элемент списка 01689 @throw omni::config::NotFoundFailureT Если элемент с таким именем не найден 01690 @throw omni::config::AmbiguousFailureT Если имя элемента не уникально 01691 */ 01692 const_reference operator[](const String &name) const 01693 { 01694 return get(name); 01695 } 01696 01697 01698 ////////////////////////////////////////////////////////////////////////// 01699 /// @brief Элемент с заданным именем 01700 /** 01701 Метод является псевдонимом для get(name). 01702 01703 @param[in] name Имя элемента списка 01704 @return Константная ссылка на найденный элемент списка 01705 @throw omni::config::NotFoundFailureT Если элемент с таким именем не найден 01706 @throw omni::config::AmbiguousFailureT Если имя элемента не уникально 01707 */ 01708 const_reference operator[](const Char *name) const 01709 { 01710 return get(name); 01711 } 01712 01713 01714 ////////////////////////////////////////////////////////////////////////// 01715 /// @brief Элемент с заданным именем (с созданием) 01716 /** 01717 Метод является псевдонимом для get(name, true). 01718 Т.е. если элемент не существует, он будет создан! 01719 01720 @param[in] name Имя элемента списка 01721 @return Неконстантная ссылка на найденный элемент списка 01722 @throw omni::config::AmbiguousFailureT Если имя элемента не уникально 01723 */ 01724 reference operator[](const String &name) 01725 { 01726 // (!) create if not exists 01727 return get(name, true); 01728 } 01729 01730 01731 ////////////////////////////////////////////////////////////////////////// 01732 /// @brief Элемент с заданным именем (с созданием) 01733 /** 01734 Метод является псевдонимом для get(name, true). 01735 Т.е. если элемент не существует, он будет создан! 01736 01737 @param[in] name Имя элемента списка 01738 @return Неконстантная ссылка на найденный элемент списка 01739 @throw omni::config::AmbiguousFailureT Если имя элемента не уникально 01740 */ 01741 reference operator[](const Char *name) 01742 { 01743 // (!) create if not exists 01744 return get(name, true); 01745 } 01746 01747 01748 ////////////////////////////////////////////////////////////////////////// 01749 /// @brief Ссылка на себя 01750 /** 01751 Метод возвращает ссылку на себя. 01752 01753 @return Self reference. 01754 */ 01755 const ThisType& operator()() const 01756 { 01757 return *this; 01758 } 01759 01760 01761 ////////////////////////////////////////////////////////////////////////// 01762 /// @brief Ссылка на себя 01763 /** 01764 Метод возвращает ссылку на себя. 01765 01766 @return Self reference. 01767 */ 01768 ThisType& operator()() 01769 { 01770 return *this; 01771 } 01772 01773 /// @} 01774 ////////////////////////////////////////////////////////////////////////// 01775 01776 ////////////////////////////////////////////////////////////////////////// 01777 /// @name Manipulators 01778 /// @{ 01779 public: 01780 01781 ////////////////////////////////////////////////////////////////////////// 01782 /// @brief Создать новый элемент в конце списка (копия) 01783 /** 01784 Метод создаёт новый элемент копию @a prototype, 01785 который добавляется в конец списка. 01786 01787 @param[in] prototype Прототип создаваемого элемента 01788 @return Неконстантная ссылка на созданный элемент 01789 */ 01790 reference push_back(const_reference prototype) 01791 { 01792 return push(new value_type(prototype)); 01793 } 01794 01795 01796 ////////////////////////////////////////////////////////////////////////// 01797 /// @brief Создать новый элемент в конце списка (имя) 01798 /** 01799 Метод создаёт новый элемент с именем @a name, 01800 который добавляется в конец списка. 01801 01802 @param[in] name Имя элемента списка 01803 @return Неконстантная ссылка на созданный элемент 01804 */ 01805 reference push_back(const String &name) 01806 { 01807 return push(new value_type(name)); 01808 } 01809 01810 01811 ////////////////////////////////////////////////////////////////////////// 01812 /// @brief Создать новый элемент в конце списка (имя) 01813 /** 01814 Метод создаёт новый элемент с именем @a name, 01815 который добавляется в конец списка. 01816 01817 @param[in] name Имя элемента списка 01818 @return Неконстантная ссылка на созданный элемент 01819 */ 01820 reference push_back(const Char *name) 01821 { 01822 return push(new value_type(name)); 01823 } 01824 01825 01826 ////////////////////////////////////////////////////////////////////////// 01827 /// @brief Создать новый элемент в конце списка 01828 /** 01829 Метод создаёт новый элемент с именем по умолчанию, 01830 который добавляется в конец списка. 01831 01832 @return Неконстантная ссылка на созданный элемент 01833 */ 01834 reference push_back() 01835 { 01836 return push(new value_type()); 01837 } 01838 01839 01840 ////////////////////////////////////////////////////////////////////////// 01841 /// @brief Удалить существующий элемент 01842 /** 01843 Метод удаляет элемент из списка. 01844 01845 Элемент должен принадлежать этому же списку! 01846 01847 @param[in] x Неконстантная ссылка на удаляемый элемент списка 01848 */ 01849 void remove(reference x) 01850 { 01851 typename Container::iterator found = std::find( 01852 m_items.begin(), m_items.end(), &x); 01853 assert(found != m_items.end() 01854 && "element not found"); 01855 01856 if (found != m_items.end()) 01857 remove(iterator(found)); 01858 } 01859 01860 01861 ////////////////////////////////////////////////////////////////////////// 01862 /// @brief Удалить существующий элемент 01863 /** 01864 Метод удаляет элемент из списка. 01865 01866 Элемент должен принадлежать этому же списку! 01867 01868 @param[in] pos Неконстантная ссылка на удаляемый элемент списка 01869 */ 01870 void remove(iterator pos) 01871 { 01872 value_type *elem = *pos.base(); 01873 01874 m_items.erase(pos.base()); 01875 m_owner->do_remove(elem); 01876 delete elem; 01877 } 01878 01879 01880 ////////////////////////////////////////////////////////////////////////// 01881 /// @brief Удалить существующий элемент 01882 /** 01883 Метод удаляет элемент из списка. 01884 01885 Элемент должен принадлежать этому же списку! 01886 01887 @param[in] name элемент списка 01888 */ 01889 void remove(const String &name) 01890 { 01891 // TODO: speed optimization 01892 iterator found = find(name, begin()); 01893 while (found != end()) 01894 { 01895 remove(found); 01896 found = find(name, 01897 begin()); 01898 } 01899 } 01900 01901 01902 ////////////////////////////////////////////////////////////////////////// 01903 /// @brief Удалить существующий элемент 01904 /** 01905 Метод удаляет элемент из списка. 01906 01907 Элемент должен принадлежать этому же списку! 01908 01909 @param[in] name элемент списка 01910 */ 01911 void remove(const Char *name) 01912 { 01913 // TODO: speed optimization 01914 iterator found = find(name, begin()); 01915 while (found != end()) 01916 { 01917 remove(found); 01918 found = find(name, 01919 begin()); 01920 } 01921 } 01922 01923 01924 ////////////////////////////////////////////////////////////////////////// 01925 /// @brief Удалить все элементы списка 01926 /** 01927 Метод удяляет все элементы списка. 01928 */ 01929 void clear() 01930 { 01931 typename Container::reverse_iterator i = m_items.rbegin(); 01932 typename Container::reverse_iterator ie = m_items.rend(); 01933 for (; i != ie; ++i) 01934 { 01935 value_type *elem = (*i); 01936 m_owner->do_remove(elem); 01937 delete elem; 01938 } 01939 m_items.clear(); 01940 } 01941 01942 /// @} 01943 ////////////////////////////////////////////////////////////////////////// 01944 01945 ////////////////////////////////////////////////////////////////////////// 01946 /// @name Selectors 01947 /// @{ 01948 public: 01949 01950 ////////////////////////////////////////////////////////////////////////// 01951 /// @brief Проверить наличие элемента с заданным именем 01952 /** 01953 Метод проверяет, существует ли хотя бы один элемент с именем @a name. 01954 01955 @param[in] name Имя элемента списка 01956 @return @b true если существует хотя бы один элемент с заданным именем, 01957 иначе @b false 01958 */ 01959 bool exists(const String &name) const 01960 { 01961 return find(name, begin()) != end(); 01962 } 01963 01964 01965 ////////////////////////////////////////////////////////////////////////// 01966 /// @brief Проверить наличие элемента с заданным именем 01967 /** 01968 Метод проверяет, существует ли хотя бы один элемент с именем @a name. 01969 01970 @param[in] name Имя элемента списка 01971 @return @b true если существует хотя бы один элемент с заданным именем, 01972 иначе @b false 01973 */ 01974 bool exists(const Char *name) const 01975 { 01976 return find(name, begin()) != end(); 01977 } 01978 01979 01980 ////////////////////////////////////////////////////////////////////////// 01981 /// @brief Количество элементов в списке 01982 /** 01983 Метод возвращает количество элементов в списке. 01984 01985 @return Количество элементов в списке 01986 */ 01987 size_type size() const 01988 { 01989 return m_items.size(); 01990 } 01991 01992 01993 ////////////////////////////////////////////////////////////////////////// 01994 /// @brief Проверить список на пустоту 01995 /** 01996 Метод проверяет, является ли список элементов пустым. 01997 01998 @return @b true Если список пуст, иначе @b false 01999 */ 02000 bool empty() const 02001 { 02002 return m_items.empty(); 02003 } 02004 02005 private: 02006 02007 ////////////////////////////////////////////////////////////////////////// 02008 /// @brief Равенство двух списков 02009 /** 02010 Метод сравнивает два списка между собой. Два списка считаются равными, 02011 если оба имеют одинаковое количество элементов и если каждый элемент 02012 одного списка равен соответствующему элементу второго списка. 02013 02014 @param[in] x Второй список для сравнения 02015 @return @b true Если списка равны, иначе @b false 02016 */ 02017 bool equal(const ThisType &other) const 02018 { 02019 if (size() != other.size()) 02020 return false; 02021 02022 return std::equal(begin(), 02023 end(), other.begin()); 02024 } 02025 02026 02027 ////////////////////////////////////////////////////////////////////////// 02028 /// @brief Найти элемент с заданным именем 02029 /** 02030 Метод ищет элемент списка с именем @a name начиная с позиции @a where. 02031 02032 @param[in] name Имя элемента списка 02033 @param[in] pos Элемент с которого начинается поиск 02034 @return Найденный элемент списка или end(), если элемент не найден 02035 */ 02036 const const_iterator find(const String &name, const_iterator pos) const 02037 { 02038 const_iterator last = end(); 02039 for (; pos != last; ++pos) 02040 if (pos->name() == name) 02041 break; 02042 02043 return pos; 02044 } 02045 02046 ////////////////////////////////////////////////////////////////////////// 02047 /// @brief Найти элемент с заданным именем 02048 /** 02049 Метод ищет элемент списка с именем @a name начиная с позиции @a where. 02050 02051 @param[in] name Имя элемента списка 02052 @param[in] pos Элемент с которого начинается поиск 02053 @return Найденный элемент списка или end(), если элемент не найден 02054 */ 02055 const const_iterator find(const Char *name, const_iterator pos) const 02056 { 02057 const_iterator last = end(); 02058 for (; pos != last; ++pos) 02059 if (pos->name() == name) 02060 break; 02061 02062 return pos; 02063 } 02064 02065 02066 ////////////////////////////////////////////////////////////////////////// 02067 /// @brief Найти элемент с заданным именем 02068 /** 02069 Метод ищет элемент списка с именем @a name начиная с позиции @a where. 02070 02071 @param[in] name Имя элемента списка 02072 @param[in] pos Элемент с которого начинается поиск 02073 @return Найденный элемент списка или end(), если элемент не найден 02074 */ 02075 const iterator find(const String &name, iterator pos) 02076 { 02077 iterator last = end(); 02078 for (; pos != last; ++pos) 02079 if (pos->name() == name) 02080 break; 02081 02082 return pos; 02083 } 02084 02085 ////////////////////////////////////////////////////////////////////////// 02086 /// @brief Найти элемент с заданным именем 02087 /** 02088 Метод ищет элемент списка с именем @a name начиная с позиции @a where. 02089 02090 @param[in] name Имя элемента списка 02091 @param[in] pos Элемент с которого начинается поиск 02092 @return Найденный элемент списка или end(), если элемент не найден 02093 */ 02094 const iterator find(const Char *name, iterator pos) 02095 { 02096 iterator last = end(); 02097 for (; pos != last; ++pos) 02098 if (pos->name() == name) 02099 break; 02100 02101 return pos; 02102 } 02103 02104 02105 private: 02106 02107 ////////////////////////////////////////////////////////////////////////// 02108 /// @brief Добавить элемент в список 02109 /** 02110 Метод добавляет уже созданный элемент @a p в начало или конец списка. 02111 02112 @param[in] p Добавляемый элемент 02113 */ 02114 reference push(value_type *p) 02115 { 02116 std::auto_ptr<value_type> xp(p); 02117 02118 m_items.push_back(xp.get()); 02119 try 02120 { 02121 m_owner->do_insert(xp.get()); 02122 } 02123 catch (...) 02124 { 02125 m_items.pop_back(); 02126 throw; 02127 } 02128 02129 return *(xp.release()); 02130 } 02131 02132 02133 ////////////////////////////////////////////////////////////////////////// 02134 /// @brief Установить владельца списком 02135 /** 02136 Метод устанавливает нового владельца списка. 02137 02138 @param[in] owner Новый владелец списка 02139 */ 02140 void set_owner(OwnerType owner) 02141 { 02142 assert(!m_owner || !owner 02143 && "invalid operation"); 02144 m_owner = owner; 02145 } 02146 02147 02148 ////////////////////////////////////////////////////////////////////////// 02149 /// @brief Обменять два списка 02150 /** 02151 Метод меняет содержимое двух списков местами. 02152 Владельцы списка не меняются. 02153 02154 @param[in,out] x Список для обмена 02155 */ 02156 void swap(ThisType &x) 02157 { 02158 m_items.swap(x.m_items); 02159 } 02160 02161 02162 private: 02163 OwnerType m_owner; ///< @brief Владелец списка 02164 Container m_items; ///< @brief Список элементов 02165 }; 02166 02167 } // ElementListT<> template classes 02168 02169 02170 // SectionListT<> template classes 02171 namespace conf 02172 { 02173 02174 ////////////////////////////////////////////////////////////////////////// 02175 /// @brief List of configuration sections. 02176 /** 02177 This is auxiliary class. You can't create instances of this class. 02178 Instead use SectionT::sections property. 02179 02180 The class is a contains of configuration sections. It contains 02181 a several manipulators: push_back(), remove(), exists(). It also 02182 supports iterator methods: begin() and end(). 02183 02184 The class contains operator()(), which returns self reference. 02185 So, you can use one of the following: 02186 02187 @code 02188 void f(Section &s) 02189 { 02190 s.sections().push_back(); 02191 // -or- 02192 s.sections.push_back(); 02193 } 02194 @endcode 02195 02196 To access child section by name you can use one of the overloaded 02197 get() methods. To access child section value you can use one of the 02198 overloaded getv() method. Also you can use operator[](): 02199 02200 @code 02201 // child sections access 02202 void f(const Section &s) 02203 { 02204 s.sections.get("child_name"); 02205 s.sections["child_name"]; 02206 s.sections.getv("child_name"); // (!) value 02207 } 02208 @endcode 02209 02210 You can access section by name only if the name is unique. Otherwise 02211 you can use begin() and end() methods to iterate all child sections. 02212 02213 @see @ref omni_config 02214 */ 02215 template<typename Str> 02216 class SectionListT: private omni::NonCopyable { 02217 typedef SectionListT<Str> ThisType; 02218 typedef SectionT<Str>* OwnerType; 02219 typedef std::vector<SectionT<Str>*> Container; 02220 02221 typedef details::Iterator<typename Container::const_iterator, 02222 details::ConstTraits< SectionT<Str> > > implementation_defined_1; 02223 typedef details::Iterator<typename Container::iterator, 02224 details::NConstTraits< SectionT<Str> > > implementation_defined_2; 02225 02226 friend class SectionT<Str>; 02227 02228 ////////////////////////////////////////////////////////////////////////// 02229 /// @name Main typedefs 02230 /// @{ 02231 public: 02232 typedef SectionT<Str> value_type; ///< @brief Value type. 02233 02234 typedef const value_type& const_reference; ///< @brief Constant reference. 02235 typedef value_type& reference; ///< @brief Non-constant reference. 02236 02237 typedef typename value_type::String String; ///< @brief String type. 02238 typedef typename value_type::Char Char; ///< @brief Char type. 02239 02240 typedef typename Container::size_type size_type; ///< @brief Size type. 02241 02242 /// @} 02243 ////////////////////////////////////////////////////////////////////////// 02244 02245 private: 02246 02247 ////////////////////////////////////////////////////////////////////////// 02248 /// @brief Default constructor. 02249 /** 02250 This constructor creates empty list. 02251 02252 Only friends may create the section list. 02253 */ 02254 SectionListT() 02255 : m_owner(0) // will be set later 02256 {} 02257 02258 02259 ////////////////////////////////////////////////////////////////////////// 02260 /// @brief Destructor. 02261 /** 02262 Only friends may destroy the list. 02263 */ 02264 ~SectionListT() 02265 { 02266 assert(empty() && "list not empty"); 02267 } 02268 02269 02270 ////////////////////////////////////////////////////////////////////////// 02271 /// @name Iterators 02272 /// @{ 02273 public: 02274 02275 typedef implementation_defined_1 const_iterator; ///< @brief Constant iterator. 02276 typedef implementation_defined_2 iterator; ///< @brief Non-constant iterator. 02277 02278 ////////////////////////////////////////////////////////////////////////// 02279 /// @brief Begin of the list. 02280 /** 02281 @return The constant iterator. 02282 */ 02283 const const_iterator begin() const 02284 { 02285 return const_iterator(m_items.begin()); 02286 } 02287 02288 02289 ////////////////////////////////////////////////////////////////////////// 02290 /// @brief Begin of the list. 02291 /** 02292 @return The non-constant iterator. 02293 */ 02294 const iterator begin() 02295 { 02296 return iterator(m_items.begin()); 02297 } 02298 02299 02300 ////////////////////////////////////////////////////////////////////////// 02301 /// @brief End of the list. 02302 /** 02303 @return The constant iterator. 02304 */ 02305 const const_iterator end() const 02306 { 02307 return const_iterator(m_items.end()); 02308 } 02309 02310 02311 ////////////////////////////////////////////////////////////////////////// 02312 /// @brief End of the list. 02313 /** 02314 @return The non-constant iterator. 02315 */ 02316 const iterator end() 02317 { 02318 return iterator(m_items.end()); 02319 } 02320 02321 /// @} 02322 ////////////////////////////////////////////////////////////////////////// 02323 02324 ////////////////////////////////////////////////////////////////////////// 02325 /// @name Front & Back 02326 /// @{ 02327 public: 02328 02329 ////////////////////////////////////////////////////////////////////////// 02330 /// @brief First element. 02331 /** 02332 @return Constant reference. 02333 */ 02334 const_reference front() const 02335 { 02336 return *m_items.front(); 02337 } 02338 02339 02340 ////////////////////////////////////////////////////////////////////////// 02341 /// @brief First element. 02342 /** 02343 @return Non-constant reference. 02344 */ 02345 reference front() 02346 { 02347 return *m_items.front(); 02348 } 02349 02350 02351 ////////////////////////////////////////////////////////////////////////// 02352 /// @brief Last element. 02353 /** 02354 @return Constant reference. 02355 */ 02356 const_reference back() const 02357 { 02358 return *m_items.back(); 02359 } 02360 02361 02362 ////////////////////////////////////////////////////////////////////////// 02363 /// @brief Last element. 02364 /** 02365 @return Non-constant reference. 02366 */ 02367 reference back() 02368 { 02369 return *m_items.back(); 02370 } 02371 02372 /// @} 02373 ////////////////////////////////////////////////////////////////////////// 02374 02375 ////////////////////////////////////////////////////////////////////////// 02376 /// @name Get section by name 02377 /// @{ 02378 public: 02379 02380 ////////////////////////////////////////////////////////////////////////// 02381 /// @brief Get element by name. 02382 /** 02383 This method returns a element with specified name @a name. 02384 If the element with that name is not exists or the name 02385 is not unique the exception will be thrown. 02386 02387 @param[in] name The element's name. 02388 @return Constant reference. 02389 @throw omni::conf::err::ElementNotFoundT If element not found. 02390 @throw omni::conf::err::NameIsAmbiguousT If element's name is not unique. 02391 */ 02392 const_reference get(const String &name) const 02393 { 02394 const_iterator found = find(name, begin()); 02395 if (found == end()) 02396 throw err::ElementNotFoundT<String>(name, m_owner->fullName()); 02397 02398 const_reference elem = *found; 02399 if (find(name, ++found) != end()) 02400 throw err::NameIsAmbiguousT<String>(name, m_owner->fullName()); 02401 02402 return elem; 02403 } 02404 02405 02406 ////////////////////////////////////////////////////////////////////////// 02407 /// @brief Get element by name. 02408 /** 02409 This method returns a element with specified name @a name. 02410 If the element with that name is not exists or the name 02411 is not unique the exception will be thrown. 02412 02413 @param[in] name The element's name. 02414 @return Constant reference. 02415 @throw omni::conf::err::ElementNotFoundT If element not found. 02416 @throw omni::conf::err::NameIsAmbiguousT If element's name is not unique. 02417 */ 02418 const_reference get(const Char *name) const 02419 { 02420 const_iterator found = find(name, begin()); 02421 if (found == end()) 02422 throw err::ElementNotFoundT<String>(name, m_owner->fullName()); 02423 02424 const_reference elem = *found; 02425 if (find(name, ++found) != end()) 02426 throw err::NameIsAmbiguousT<String>(name, m_owner->fullName()); 02427 02428 return elem; 02429 } 02430 02431 02432 ////////////////////////////////////////////////////////////////////////// 02433 /// @brief Get element by name or default. 02434 /** 02435 This method returns a element with specified name @a name. 02436 If the element with that name is not exists, then the @a def element 02437 will be returned. If the element's name is not unique the exception 02438 will be thrown. 02439 02440 @param[in] name The element's name. 02441 @param[in] def The default element. 02442 @return Constant reference. 02443 @throw omni::conf::err::NameIsAmbiguousT If element's name is not unique. 02444 */ 02445 const_reference get(const String &name, const_reference def) const 02446 { 02447 const_iterator found = find(name, begin()); 02448 if (found == end()) 02449 return def; 02450 02451 const_reference elem = *found; 02452 if (find(name, ++found) != end()) 02453 throw err::NameIsAmbiguousT<String>(name, m_owner->fullName()); 02454 02455 return elem; 02456 } 02457 02458 02459 ////////////////////////////////////////////////////////////////////////// 02460 /// @brief Get element by name or default. 02461 /** 02462 This method returns a element with specified name @a name. 02463 If the element with that name is not exists, then the @a def element 02464 will be returned. If the element's name is not unique the exception 02465 will be thrown. 02466 02467 @param[in] name The element's name. 02468 @param[in] def The default element. 02469 @return Constant reference. 02470 @throw omni::conf::err::NameIsAmbiguousT If element's name is not unique. 02471 */ 02472 const_reference get(const Char *name, const_reference def) const 02473 { 02474 const_iterator found = find(name, begin()); 02475 if (found == end()) 02476 return def; 02477 02478 const_reference elem = *found; 02479 if (find(name, ++found) != end()) 02480 throw err::NameIsAmbiguousT<String>(name, m_owner->fullName()); 02481 02482 return elem; 02483 } 02484 02485 02486 ////////////////////////////////////////////////////////////////////////// 02487 /// @brief Get element by name or create. 02488 /** 02489 Метод возвращает элемент с именем @a name. Если элемента с таким 02490 именем нет, но установлен флаг @a create, то будет создан новый элемент. 02491 Если же флаг @a create не установлен, будет сгенерировано исключение. 02492 Если есть два или более элементов с таким именем, также будет 02493 сгенерировано исключение. 02494 02495 @param[in] name The element's name. 02496 @param[in] create Create if not exists flag. 02497 @return Non-constant reference. 02498 @throw omni::conf::err::ElementNotFoundT IF element not found and @a create flag not set. 02499 @throw omni::conf::err::NameIsAmbiguousT If element's name is not unique. 02500 */ 02501 reference get(const String &name, bool create = false) 02502 { 02503 iterator found = find(name, begin()); 02504 if (found == end()) 02505 { 02506 if (create) 02507 return push_back(name); 02508 else 02509 throw err::ElementNotFoundT<String>(name, m_owner->fullName()); 02510 } 02511 02512 reference elem = *found; 02513 if (find(name, ++found) != end()) 02514 throw err::NameIsAmbiguousT<String>(name, m_owner->fullName()); 02515 02516 return elem; 02517 } 02518 02519 02520 ////////////////////////////////////////////////////////////////////////// 02521 /// @brief Get element by name or create. 02522 /** 02523 Метод возвращает элемент с именем @a name. Если элемента с таким 02524 именем нет, но установлен флаг @a create, то будет создан новый элемент. 02525 Если же флаг @a create не установлен, будет сгенерировано исключение. 02526 Если есть два или более элементов с таким именем, также будет 02527 сгенерировано исключение. 02528 02529 @param[in] name The element's name. 02530 @param[in] create Create if not exists flag. 02531 @return Non-constant reference. 02532 @throw omni::conf::err::ElementNotFoundT IF element not found and @a create flag not set. 02533 @throw omni::conf::err::NameIsAmbiguousT If element's name is not unique. 02534 */ 02535 reference get(const Char *name, bool create = false) 02536 { 02537 iterator found = find(name, begin()); 02538 if (found == end()) 02539 { 02540 if (create) 02541 return push_back(name); 02542 else 02543 throw err::ElementNotFoundT<String>(name, m_owner->fullName()); 02544 } 02545 02546 reference elem = *found; 02547 if (find(name, ++found) != end()) 02548 throw err::NameIsAmbiguousT<String>(name, m_owner->fullName()); 02549 02550 return elem; 02551 } 02552 02553 /// @} 02554 ////////////////////////////////////////////////////////////////////////// 02555 02556 ////////////////////////////////////////////////////////////////////////// 02557 /// @name Get section's value by name 02558 /// @{ 02559 02560 public: 02561 02562 ////////////////////////////////////////////////////////////////////////// 02563 /// @brief Значение элемента с заданным именем 02564 /** 02565 Метод возвращает значение элемента с именем @a name. Если элемента с 02566 таким именем нет или есть два или более, то будет сгенерировано исключение. 02567 02568 @param[in] name Имя элемента списка 02569 @return Значение найденного элемента списка 02570 @throw omni::config::NotFoundFailureT Если элемент с таким именем не найден 02571 @throw omni::config::AmbiguousFailureT Если имя элемента не уникально 02572 */ 02573 const String& getv(const String &name) const 02574 { 02575 return get(name).val(); 02576 } 02577 02578 ////////////////////////////////////////////////////////////////////////// 02579 /// @brief Значение элемента с заданным именем 02580 /** 02581 Метод возвращает значение элемента с именем @a name. Если элемента с 02582 таким именем нет или есть два или более, то будет сгенерировано исключение. 02583 02584 @param[in] name Имя элемента списка 02585 @return Значение найденного элемента списка 02586 @throw omni::config::NotFoundFailureT Если элемент с таким именем не найден 02587 @throw omni::config::AmbiguousFailureT Если имя элемента не уникально 02588 */ 02589 const String& getv(const Char *name) const 02590 { 02591 return get(name).val(); 02592 } 02593 02594 02595 ////////////////////////////////////////////////////////////////////////// 02596 /// @brief Значение элемента с заданным именем (по умолчанию) 02597 /** 02598 Метод возвращает значение элемента с именем @a name. Если элемента 02599 с таким именем нет, то будет возвращено значение @a def. Если с таким 02600 именем есть два или более элементов, то будет сгенерировано исключение. 02601 02602 @param[in] name Имя элемента списка 02603 @param[in] def Возвращаемое значение по умолчанию 02604 @return Значение найденного элемента списка 02605 @throw omni::config::AmbiguousFailureT Если имя элемента не уникально 02606 */ 02607 const String& getv(const String &name, const String &def) const 02608 { 02609 const_iterator found = find(name, begin()); 02610 if (found == end()) 02611 return def; 02612 02613 const_reference elem = *found; 02614 if (find(name, ++found) != end()) 02615 throw err::NameIsAmbiguousT<String>(name, m_owner->fullName()); 02616 02617 return elem.val(); 02618 } 02619 02620 02621 ////////////////////////////////////////////////////////////////////////// 02622 /// @brief Значение элемента с заданным именем (по умолчанию) 02623 /** 02624 Метод возвращает значение элемента с именем @a name. Если элемента 02625 с таким именем нет, то будет возвращено значение @a def. Если с таким 02626 именем есть два или более элементов, то будет сгенерировано исключение. 02627 02628 @param[in] name Имя элемента списка 02629 @param[in] def Возвращаемое значение по умолчанию 02630 @return Значение найденного элемента списка 02631 @throw omni::config::AmbiguousFailureT Если имя элемента не уникально 02632 */ 02633 const String& getv(const Char *name, const String &def) const 02634 { 02635 const_iterator found = find(name, begin()); 02636 if (found == end()) 02637 return def; 02638 02639 const_reference elem = *found; 02640 if (find(name, ++found) != end()) 02641 throw err::NameIsAmbiguousT<String>(name, m_owner->fullName()); 02642 02643 return elem.val(); 02644 } 02645 02646 ////////////////////////////////////////////////////////////////////////// 02647 /// @brief Значение элемента с заданным именем (по умолчанию) 02648 /** 02649 Метод возвращает значение элемента с именем @a name. Если элемента 02650 с таким именем нет, то будет возвращено значение @a def. Если с таким 02651 именем есть два или более элементов, то будет сгенерировано исключение. 02652 02653 @param[in] name Имя элемента списка 02654 @param[in] def Возвращаемое значение по умолчанию 02655 @return Значение найденного элемента списка 02656 @throw omni::config::AmbiguousFailureT Если имя элемента не уникально 02657 */ 02658 const Char* getv(const Char *name, const Char *def) const 02659 { 02660 const_iterator found = find(name, begin()); 02661 if (found == end()) 02662 return def; 02663 02664 const_reference elem = *found; 02665 if (find(name, ++found) != end()) 02666 throw err::NameIsAmbiguousT<String>(name, m_owner->fullName()); 02667 02668 return elem.val().c_str(); 02669 } 02670 02671 /// @} 02672 ////////////////////////////////////////////////////////////////////////// 02673 02674 ////////////////////////////////////////////////////////////////////////// 02675 /// @name Auxiliary operators 02676 /// @{ 02677 public: 02678 02679 ////////////////////////////////////////////////////////////////////////// 02680 /// @brief Элемент с заданным именем 02681 /** 02682 Метод является псевдонимом для get(name). 02683 02684 @param[in] name Имя элемента списка 02685 @return Константная ссылка на найденный элемент списка 02686 @throw omni::config::NotFoundFailureT Если элемент с таким именем не найден 02687 @throw omni::config::AmbiguousFailureT Если имя элемента не уникально 02688 */ 02689 const_reference operator[](const String &name) const 02690 { 02691 return get(name); 02692 } 02693 02694 02695 ////////////////////////////////////////////////////////////////////////// 02696 /// @brief Элемент с заданным именем 02697 /** 02698 Метод является псевдонимом для get(name). 02699 02700 @param[in] name Имя элемента списка 02701 @return Константная ссылка на найденный элемент списка 02702 @throw omni::config::NotFoundFailureT Если элемент с таким именем не найден 02703 @throw omni::config::AmbiguousFailureT Если имя элемента не уникально 02704 */ 02705 const_reference operator[](const Char *name) const 02706 { 02707 return get(name); 02708 } 02709 02710 02711 ////////////////////////////////////////////////////////////////////////// 02712 /// @brief Элемент с заданным именем (с созданием) 02713 /** 02714 Метод является псевдонимом для get(name, true). 02715 Т.е. если элемент не существует, он будет создан! 02716 02717 @param[in] name Имя элемента списка 02718 @return Неконстантная ссылка на найденный элемент списка 02719 @throw omni::config::AmbiguousFailureT Если имя элемента не уникально 02720 */ 02721 reference operator[](const String &name) 02722 { 02723 // (!) create if not exists 02724 return get(name, true); 02725 } 02726 02727 02728 ////////////////////////////////////////////////////////////////////////// 02729 /// @brief Элемент с заданным именем (с созданием) 02730 /** 02731 Метод является псевдонимом для get(name, true). 02732 Т.е. если элемент не существует, он будет создан! 02733 02734 @param[in] name Имя элемента списка 02735 @return Неконстантная ссылка на найденный элемент списка 02736 @throw omni::config::AmbiguousFailureT Если имя элемента не уникально 02737 */ 02738 reference operator[](const Char *name) 02739 { 02740 // (!) create if not exists 02741 return get(name, true); 02742 } 02743 02744 02745 ////////////////////////////////////////////////////////////////////////// 02746 /// @brief Ссылка на себя 02747 /** 02748 Метод возвращает ссылку на себя. 02749 02750 @return Self reference. 02751 */ 02752 const ThisType& operator()() const 02753 { 02754 return *this; 02755 } 02756 02757 02758 ////////////////////////////////////////////////////////////////////////// 02759 /// @brief Ссылка на себя 02760 /** 02761 Метод возвращает ссылку на себя. 02762 02763 @return Self reference. 02764 */ 02765 ThisType& operator()() 02766 { 02767 return *this; 02768 } 02769 02770 /// @} 02771 ////////////////////////////////////////////////////////////////////////// 02772 02773 ////////////////////////////////////////////////////////////////////////// 02774 /// @name Manipulators 02775 /// @{ 02776 public: 02777 02778 ////////////////////////////////////////////////////////////////////////// 02779 /// @brief Создать новый элемент в конце списка (копия) 02780 /** 02781 Метод создаёт новый элемент копию @a prototype, 02782 который добавляется в конец списка. 02783 02784 @param[in] prototype Прототип создаваемого элемента 02785 @return Неконстантная ссылка на созданный элемент 02786 */ 02787 reference push_back(const_reference prototype) 02788 { 02789 return push(new value_type(prototype)); 02790 } 02791 02792 ////////////////////////////////////////////////////////////////////////// 02793 /// @brief Создать новый элемент в конце списка (имя) 02794 /** 02795 Метод создаёт новый элемент с именем @a name, 02796 который добавляется в конец списка. 02797 02798 @param[in] name Имя элемента списка 02799 @return Неконстантная ссылка на созданный элемент 02800 */ 02801 reference push_back(const String &name) 02802 { 02803 return push(new value_type(name)); 02804 } 02805 02806 ////////////////////////////////////////////////////////////////////////// 02807 /// @brief Создать новый элемент в конце списка (имя) 02808 /** 02809 Метод создаёт новый элемент с именем @a name, 02810 который добавляется в конец списка. 02811 02812 @param[in] name Имя элемента списка 02813 @return Неконстантная ссылка на созданный элемент 02814 */ 02815 reference push_back(const Char *name) 02816 { 02817 return push(new value_type(name)); 02818 } 02819 02820 ////////////////////////////////////////////////////////////////////////// 02821 /// @brief Создать новый элемент в конце списка 02822 /** 02823 Метод создаёт новый элемент с именем по умолчанию, 02824 который добавляется в конец списка. 02825 02826 @return Неконстантная ссылка на созданный элемент 02827 */ 02828 reference push_back() 02829 { 02830 return push(new value_type()); 02831 } 02832 02833 02834 ////////////////////////////////////////////////////////////////////////// 02835 /// @brief Удалить существующий элемент 02836 /** 02837 Метод удаляет элемент из списка. 02838 02839 Элемент должен принадлежать этому же списку! 02840 02841 @param[in] x Неконстантная ссылка на удаляемый элемент списка 02842 */ 02843 void remove(reference x) 02844 { 02845 typename Container::iterator found = std::find( 02846 m_items.begin(), m_items.end(), &x); 02847 assert(found != m_items.end() 02848 && "element not found"); 02849 02850 if (found != m_items.end()) 02851 remove(iterator(found)); 02852 } 02853 02854 02855 ////////////////////////////////////////////////////////////////////////// 02856 /// @brief Удалить существующий элемент 02857 /** 02858 Метод удаляет элемент из списка. 02859 02860 Элемент должен принадлежать этому же списку! 02861 02862 @param[in] pos Неконстантная ссылка на удаляемый элемент списка 02863 */ 02864 void remove(iterator pos) 02865 { 02866 value_type *elem = *pos.base(); 02867 02868 m_items.erase(pos.base()); 02869 m_owner->do_remove(elem); 02870 delete elem; 02871 } 02872 02873 ////////////////////////////////////////////////////////////////////////// 02874 /// @brief Удалить существующий элемент 02875 /** 02876 Метод удаляет элемент из списка. 02877 02878 Элемент должен принадлежать этому же списку! 02879 02880 @param[in] name элемент списка 02881 */ 02882 void remove(const String &name) 02883 { 02884 // TODO: speed optimization 02885 iterator found = find(name, begin()); 02886 while (found != end()) 02887 { 02888 remove(found); 02889 found = find(name, 02890 begin()); 02891 } 02892 } 02893 02894 ////////////////////////////////////////////////////////////////////////// 02895 /// @brief Удалить существующий элемент 02896 /** 02897 Метод удаляет элемент из списка. 02898 02899 Элемент должен принадлежать этому же списку! 02900 02901 @param[in] name элемент списка 02902 */ 02903 void remove(const Char *name) 02904 { 02905 // TODO: speed optimization 02906 iterator found = find(name, begin()); 02907 while (found != end()) 02908 { 02909 remove(found); 02910 found = find(name, 02911 begin()); 02912 } 02913 } 02914 02915 ////////////////////////////////////////////////////////////////////////// 02916 /// @brief Удалить все элементы списка 02917 /** 02918 Метод удяляет все элементы списка. 02919 */ 02920 void clear() 02921 { 02922 typename Container::reverse_iterator i = m_items.rbegin(); 02923 typename Container::reverse_iterator ie = m_items.rend(); 02924 for (; i != ie; ++i) 02925 { 02926 value_type *elem = (*i); 02927 m_owner->do_remove(elem); 02928 delete elem; 02929 } 02930 m_items.clear(); 02931 } 02932 02933 /// @} 02934 ////////////////////////////////////////////////////////////////////////// 02935 02936 ////////////////////////////////////////////////////////////////////////// 02937 /// @name Selectors 02938 /// @{ 02939 public: 02940 02941 ////////////////////////////////////////////////////////////////////////// 02942 /// @brief Проверить наличие элемента с заданным именем 02943 /** 02944 Метод проверяет, существует ли хотя бы один элемент с именем @a name. 02945 02946 @param[in] name Имя элемента списка 02947 @return @b true если существует хотя бы один элемент с заданным именем, 02948 иначе @b false 02949 */ 02950 bool exists(const String &name) const 02951 { 02952 return find(name, begin()) != end(); 02953 } 02954 02955 02956 ////////////////////////////////////////////////////////////////////////// 02957 /// @brief Проверить наличие элемента с заданным именем 02958 /** 02959 Метод проверяет, существует ли хотя бы один элемент с именем @a name. 02960 02961 @param[in] name Имя элемента списка 02962 @return @b true если существует хотя бы один элемент с заданным именем, 02963 иначе @b false 02964 */ 02965 bool exists(const Char *name) const 02966 { 02967 return find(name, begin()) != end(); 02968 } 02969 02970 02971 ////////////////////////////////////////////////////////////////////////// 02972 /// @brief Количество элементов в списке 02973 /** 02974 Метод возвращает количество элементов в списке. 02975 02976 @return Количество элементов в списке 02977 */ 02978 size_type size() const 02979 { 02980 return m_items.size(); 02981 } 02982 02983 02984 ////////////////////////////////////////////////////////////////////////// 02985 /// @brief Проверить список на пустоту 02986 /** 02987 Метод проверяет, является ли список элементов пустым. 02988 02989 @return @b true Если список пуст, иначе @b false 02990 */ 02991 bool empty() const 02992 { 02993 return m_items.empty(); 02994 } 02995 02996 private: 02997 02998 ////////////////////////////////////////////////////////////////////////// 02999 /// @brief Равенство двух списков 03000 /** 03001 Метод сравнивает два списка между собой. Два списка считаются равными, 03002 если оба имеют одинаковое количество элементов и если каждый элемент 03003 одного списка равен соответствующему элементу второго списка. 03004 03005 @param[in] x Второй список для сравнения 03006 @return @b true Если списка равны, иначе @b false 03007 */ 03008 bool equal(const ThisType &other) const 03009 { 03010 if (size() != other.size()) 03011 return false; 03012 03013 return std::equal(begin(), 03014 end(), other.begin()); 03015 } 03016 03017 03018 ////////////////////////////////////////////////////////////////////////// 03019 /// @brief Найти элемент с заданным именем 03020 /** 03021 Метод ищет элемент списка с именем @a name начиная с позиции @a where. 03022 03023 @param[in] name Имя элемента списка 03024 @param[in] where Элемент с которого начинается поиск 03025 @return Найденный элемент списка или end(), если элемент не найден 03026 */ 03027 const const_iterator find(const String &name, const_iterator pos) const 03028 { 03029 const_iterator last = end(); 03030 for (; pos != last; ++pos) 03031 if (pos->name() == name) 03032 break; 03033 03034 return pos; 03035 } 03036 03037 ////////////////////////////////////////////////////////////////////////// 03038 /// @brief Найти элемент с заданным именем 03039 /** 03040 Метод ищет элемент списка с именем @a name начиная с позиции @a where. 03041 03042 @param[in] name Имя элемента списка 03043 @param[in] where Элемент с которого начинается поиск 03044 @return Найденный элемент списка или end(), если элемент не найден 03045 */ 03046 const const_iterator find(const Char *name, const_iterator pos) const 03047 { 03048 const_iterator last = end(); 03049 for (; pos != last; ++pos) 03050 if (pos->name() == name) 03051 break; 03052 03053 return pos; 03054 } 03055 03056 03057 ////////////////////////////////////////////////////////////////////////// 03058 /// @brief Найти элемент с заданным именем 03059 /** 03060 Метод ищет элемент списка с именем @a name начиная с позиции @a where. 03061 03062 @param[in] name Имя элемента списка 03063 @param[in] where Элемент с которого начинается поиск 03064 @return Найденный элемент списка или end(), если элемент не найден 03065 */ 03066 const iterator find(const String &name, iterator pos) 03067 { 03068 iterator last = end(); 03069 for (; pos != last; ++pos) 03070 if (pos->name() == name) 03071 break; 03072 03073 return pos; 03074 } 03075 03076 ////////////////////////////////////////////////////////////////////////// 03077 /// @brief Найти элемент с заданным именем 03078 /** 03079 Метод ищет элемент списка с именем @a name начиная с позиции @a where. 03080 03081 @param[in] name Имя элемента списка 03082 @param[in] where Элемент с которого начинается поиск 03083 @return Найденный элемент списка или end(), если элемент не найден 03084 */ 03085 const iterator find(const Char *name, iterator pos) 03086 { 03087 iterator last = end(); 03088 for (; pos != last; ++pos) 03089 if (pos->name() == name) 03090 break; 03091 03092 return pos; 03093 } 03094 03095 03096 private: 03097 03098 ////////////////////////////////////////////////////////////////////////// 03099 /// @brief Добавить элемент в список 03100 /** 03101 Метод добавляет уже созданный элемент @a p в начало или конец списка. 03102 03103 @param[in] p Добавляемый элемент 03104 */ 03105 reference push(value_type *p) 03106 { 03107 std::auto_ptr<value_type> xp(p); 03108 03109 m_items.push_back(xp.get()); 03110 try 03111 { 03112 m_owner->do_insert(xp.get()); 03113 } 03114 catch (...) 03115 { 03116 m_items.pop_back(); 03117 throw; 03118 } 03119 03120 return *(xp.release()); 03121 } 03122 03123 03124 ////////////////////////////////////////////////////////////////////////// 03125 /// @brief Установить владельца списком 03126 /** 03127 Метод устанавливает нового владельца списка. 03128 03129 @param[in] owner Новый владелец списка 03130 */ 03131 void set_owner(OwnerType owner) 03132 { 03133 assert(!m_owner || !owner 03134 && "invalid operation"); 03135 m_owner = owner; 03136 } 03137 03138 03139 ////////////////////////////////////////////////////////////////////////// 03140 /// @brief Обменять два списка 03141 /** 03142 Метод меняет содержимое двух списков местами. 03143 Владельцы списка не меняются. 03144 03145 @param[in,out] x Список для обмена 03146 */ 03147 void swap(ThisType &x) 03148 { 03149 m_items.swap(x.m_items); 03150 } 03151 03152 03153 private: 03154 OwnerType m_owner; ///< @brief Владелец списка 03155 Container m_items; ///< @brief Список элементов 03156 }; 03157 03158 } // SectionListT<> template classes 03159 03160 03161 // exception template classes... 03162 namespace conf 03163 { 03164 namespace err 03165 { 03166 03167 ////////////////////////////////////////////////////////////////////////// 03168 /// @brief Базовое исключение 03169 /** 03170 Базовое исключение конфигураций. Класс наследует стандартное исключение 03171 @a std::runtime_error и, соответственно, его метод @b what(). Однако 03172 это сообщение не является самым информативным. Дополнительная информация 03173 об исключении содержится в свойствах производных классов. 03174 03175 Параметр шаблона @a Ch определяет тип символов строки FailureT::string_type. 03176 Допустимо использование @b wchar_t и @b char. Также в зависимости от 03177 макроса #OMNI_UNICODE определяется тип omni::config::Failure. 03178 */ 03179 template<typename Str> 03180 class FailureT: public std::runtime_error { 03181 typedef std::runtime_error inherited; 03182 protected: 03183 03184 ////////////////////////////////////////////////////////////////////////// 03185 /// @brief Создать исключение с параметрами 03186 /** 03187 @param[in] msg Сообщение об исключении 03188 */ 03189 explicit FailureT(const std::string &msg) 03190 : inherited(msg) 03191 {} 03192 03193 ////////////////////////////////////////////////////////////////////////// 03194 /// @brief Создать исключение с параметрами 03195 /** 03196 @param[in] msg Сообщение об исключении 03197 */ 03198 explicit FailureT(const char *msg) 03199 : inherited(msg) 03200 {} 03201 03202 ////////////////////////////////////////////////////////////////////////// 03203 /// @brief Destructor. 03204 virtual ~FailureT() OMNI_THROW0() 03205 {} 03206 03207 protected: 03208 typedef Str String; ///< @brief Тип строки 03209 }; 03210 03211 03212 ////////////////////////////////////////////////////////////////////////// 03213 /// @brief Ошибка доступа к элементам 03214 /** 03215 Ошибка доступа к списку секций или параметров. Класс содержит имя 03216 секции или параметра elementName(), при обращении к которому произошло 03217 исключение. Также класс содержит полное имя родительской 03218 секции parentFullName(). 03219 03220 Параметр шаблона @a Ch определяет тип символов строки AccessFailureT::string_type. 03221 Допустимо использование @b wchar_t и @b char. Также в зависимости от 03222 макроса #OMNI_UNICODE определяется тип omni::config::AccessFailure. 03223 */ 03224 template<typename Str> 03225 class AccessFailureT: public FailureT<Str> { 03226 typedef FailureT<Str> inherited; 03227 03228 public: 03229 typedef typename inherited::String String; 03230 03231 public: 03232 03233 ////////////////////////////////////////////////////////////////////////// 03234 /// @brief Создать исключение с параметрами 03235 /** 03236 @param[in] msg Сообщение об исключении 03237 @param[in] element_name Имя секции или параметра 03238 @param[in] element_path Полное имя родительской секции 03239 */ 03240 AccessFailureT(const std::string &msg, 03241 const String &element_name, 03242 const String &element_path) 03243 : inherited(msg), 03244 m_name(element_name), 03245 m_path(element_path) 03246 {} 03247 03248 03249 ////////////////////////////////////////////////////////////////////////// 03250 /// @brief Создать исключение с параметрами 03251 /** 03252 @param[in] msg Сообщение об исключении 03253 @param[in] element_name Имя секции или параметра 03254 @param[in] element_path Полное имя родительской секции 03255 */ 03256 AccessFailureT(const char *msg, 03257 const String &element_name, 03258 const String &element_path) 03259 : inherited(msg), 03260 m_name(element_name), 03261 m_path(element_path) 03262 {} 03263 03264 03265 ////////////////////////////////////////////////////////////////////////// 03266 /// @brief Virtual destructor. 03267 virtual ~AccessFailureT() OMNI_THROW0() 03268 {} 03269 03270 public: 03271 03272 ////////////////////////////////////////////////////////////////////////// 03273 /// @brief Полное имя родительской секции 03274 /** 03275 Метод возвращает полное имя секции, при доступе к элементам которой 03276 произошло исключение. 03277 03278 @brief Полное имя 03279 */ 03280 const String& path() const 03281 { 03282 return m_path; 03283 } 03284 03285 ////////////////////////////////////////////////////////////////////////// 03286 /// @brief Наименование секции или параметра 03287 /** 03288 Метод возвращает имя секции или параметра, при обращении к которому 03289 произошло исключение. 03290 03291 @return Имя элемента 03292 */ 03293 const String& name() const 03294 { 03295 return m_name; 03296 } 03297 03298 private: 03299 String m_path; ///< @brief Полное имя родительской секции 03300 String m_name; ///< @brief Наименование элемента 03301 }; 03302 03303 03304 ////////////////////////////////////////////////////////////////////////// 03305 /// @brief Элемент не найден 03306 /** 03307 Исключение генерируется если секция или параметр с заданным именем 03308 не найдены в родительской секции. Метод elementName() возвращает имя 03309 искомой секции или параметра. Метод parentFullName() возвращает полное 03310 имя родительской секции. Метод @b what() возвращает 03311 строку "element not found". 03312 03313 Параметр шаблона @a Ch определяет тип символов строки NotFoundFailureT::string_type. 03314 Допустимо использование @b wchar_t и @b char. Также в зависимости от 03315 макроса #OMNI_UNICODE определяется тип omni::config::NotFoundFailure. 03316 */ 03317 template<typename Str> 03318 class ElementNotFoundT: public AccessFailureT<Str> { 03319 typedef AccessFailureT<Str> inherited; 03320 03321 public: 03322 typedef typename inherited::String String; 03323 03324 public: 03325 03326 ////////////////////////////////////////////////////////////////////////// 03327 /// @brief Создать исключение с параметрами 03328 /** 03329 @param[in] element_name Имя секции или параметра 03330 @param[in] element_path Полное имя родительской секции 03331 */ 03332 ElementNotFoundT(const String &element_name, const String &element_path) 03333 : inherited("element not found", element_name, element_path) 03334 {} 03335 03336 03337 ////////////////////////////////////////////////////////////////////////// 03338 /// @brief Virtual destructor. 03339 virtual ~ElementNotFoundT() OMNI_THROW0() 03340 {} 03341 }; 03342 03343 03344 03345 ////////////////////////////////////////////////////////////////////////// 03346 /// @brief Неуникальное имя элемента 03347 /** 03348 Исключение генерируется если имя секции или параметра не уникальны 03349 в родительской секции. Метод elementName() возвращает имя искомой 03350 секции или параметра. Метод parentFullName() возвращает полное 03351 имя родительской секции. Метод @b what() возвращает 03352 строку "ambiguous element name". 03353 03354 Параметр шаблона @a Ch определяет тип символов строки AmbiguousFailureT::string_type. 03355 Допустимо использование @b wchar_t и @b char. Также в зависимости от 03356 макроса #OMNI_UNICODE определяется тип omni::config::AmbiguousFailure. 03357 */ 03358 template<typename Str> 03359 class NameIsAmbiguousT: public AccessFailureT<Str> { 03360 typedef AccessFailureT<Str> inherited; 03361 03362 public: 03363 typedef typename inherited::String String; 03364 03365 public: 03366 03367 ////////////////////////////////////////////////////////////////////////// 03368 /// @brief Создать исключение с параметрами 03369 /** 03370 @param[in] element_name Имя секции или параметра 03371 @param[in] element_path Полное имя родительской секции 03372 */ 03373 NameIsAmbiguousT(const String &element_name, const String &element_path) 03374 : inherited("ambiguous element name", element_name, element_path) 03375 {} 03376 03377 ////////////////////////////////////////////////////////////////////////// 03378 /// @brief Virtual destructor. 03379 virtual ~NameIsAmbiguousT() OMNI_THROW0() 03380 {} 03381 }; 03382 03383 03384 ////////////////////////////////////////////////////////////////////////// 03385 /// @brief Ошибка разбора конфигурации 03386 /** 03387 Исключение генерируется, если встретилась ошибка при разборе 03388 конфигурации из потока ввода. Метод lineNumber() возвращает номер 03389 строки, где произошла ошибка. 03390 03391 Параметр шаблона @a Ch определяет тип символов строки ParsingFailureT::string_type. 03392 Допустимо использование @b wchar_t и @b char. Также в зависимости от 03393 макроса #OMNI_UNICODE определяется тип omni::config::ParsingFailure. 03394 */ 03395 template<typename Str> 03396 class ParsingFailureT: public FailureT<Str> { 03397 typedef FailureT<Str> inherited; 03398 03399 public: 03400 typedef typename inherited::String String; 03401 03402 public: 03403 03404 ////////////////////////////////////////////////////////////////////////// 03405 /// @brief Создать исключение с параметрами 03406 /** 03407 @param[in] msg Сообщение об ошибке 03408 @param[in] line_number The line number. 03409 */ 03410 ParsingFailureT(const std::string &msg, long line_number) 03411 : inherited(msg), m_line(line_number) 03412 {} 03413 03414 ////////////////////////////////////////////////////////////////////////// 03415 /// @brief Создать исключение с параметрами 03416 /** 03417 @param[in] msg Сообщение об ошибке 03418 @param[in] line_number The line number. 03419 */ 03420 ParsingFailureT(const char *msg, long line_number) 03421 : inherited(msg), m_line(line_number) 03422 {} 03423 03424 ////////////////////////////////////////////////////////////////////////// 03425 /// @brief Virtual destructor. 03426 virtual ~ParsingFailureT() OMNI_THROW0() 03427 {} 03428 03429 public: 03430 03431 ////////////////////////////////////////////////////////////////////////// 03432 /// @brief Номер строки 03433 /** 03434 Метод возвращает номер строки, при разборе которой произошло исключение. 03435 03436 @return Номер строки 03437 */ 03438 long line() const 03439 { 03440 return m_line; 03441 } 03442 03443 private: 03444 long m_line; ///< @brief Номер строки 03445 }; 03446 03447 03448 ////////////////////////////////////////////////////////////////////////// 03449 /// @brief Синтаксическая ошибка 03450 /** 03451 Исключение генерируется, если встретилась синтаксическая ошибка при 03452 разборе конфигурации из потока ввода. Метод sectionName() возвращает 03453 полное имя текущей секции конфигурации, при разборе которой произошло 03454 исключение. 03455 03456 Параметр шаблона @a Ch определяет тип символов строки SyntaxFailureT::string_type. 03457 Допустимо использование @b wchar_t и @b char. Также в зависимости от 03458 макроса #OMNI_UNICODE определяется тип omni::config::SyntaxFailure. 03459 */ 03460 template<typename Str> 03461 class SyntaxErrorT: public ParsingFailureT<Str> { 03462 typedef ParsingFailureT<Str> inherited; 03463 03464 public: 03465 typedef typename inherited::String String; 03466 03467 public: 03468 03469 ////////////////////////////////////////////////////////////////////////// 03470 /// @brief Создать исключение с параметрами 03471 /** 03472 @param[in] msg Сообщение об ошибке 03473 @param[in] section_path Полное имя текущей секции 03474 @param[in] line Номер строки 03475 */ 03476 SyntaxErrorT(const std::string &msg, 03477 const String §ion_path, long line) 03478 : inherited(msg, line), 03479 m_path(section_path) 03480 {} 03481 03482 ////////////////////////////////////////////////////////////////////////// 03483 /// @brief Создать исключение с параметрами 03484 /** 03485 @param[in] msg Сообщение об ошибке 03486 @param[in] section_path Полное имя текущей секции 03487 @param[in] line Номер строки 03488 */ 03489 SyntaxErrorT(const char *msg, 03490 const String §ion_path, long line) 03491 : inherited(msg, line), 03492 m_path(section_path) 03493 {} 03494 03495 ////////////////////////////////////////////////////////////////////////// 03496 /// @brief Virtual destructor. 03497 virtual ~SyntaxErrorT() OMNI_THROW0() 03498 {} 03499 03500 public: 03501 03502 ////////////////////////////////////////////////////////////////////////// 03503 /// @brief Полное имя текущей секции 03504 /** 03505 Метод возвращает полное имя секции, при разборе 03506 которой произошло исключение. 03507 03508 @return Имя текущей секции 03509 */ 03510 const String& path() const 03511 { 03512 return m_path; 03513 } 03514 03515 private: 03516 String m_path; /// < @brief Имя секции 03517 }; 03518 03519 03520 ////////////////////////////////////////////////////////////////////////// 03521 /// @brief Несоответствие имени секции 03522 /** 03523 Исключение генерируется, если закрываемое имя секции не соответствует 03524 ранее открытой. Например: 03525 03526 @code 03527 <section1> 03528 # ... 03529 </section2> 03530 @endcode 03531 03532 Метод expectedName() возвращает ожидаемое имя секции, а метод 03533 foundName() возвращает встретившееся имя секции. 03534 03535 Параметр шаблона @a Ch определяет тип символов строки MismatchFailureT::string_type. 03536 Допустимо использование @b wchar_t и @b char. Также в зависимости от 03537 макроса #OMNI_UNICODE определяется тип omni::config::MismatchFailure. 03538 */ 03539 template<typename Str> 03540 class NameMismatchT: public ParsingFailureT<Str> { 03541 typedef ParsingFailureT<Str> inherited; 03542 03543 public: 03544 typedef typename inherited::String String; 03545 03546 public: 03547 03548 ////////////////////////////////////////////////////////////////////////// 03549 /// @brief Создать исключение с параметрами 03550 /** 03551 @param[in] expected_name Ожидаемое имя 03552 @param[in] found_name Найденное имя 03553 @param[in] line_number Номер строки 03554 */ 03555 NameMismatchT(const String &expected_name, 03556 const String &found_name, long line_number) 03557 : inherited("name mismatch", line_number), 03558 m_expected(expected_name), 03559 m_found(found_name) 03560 {} 03561 03562 ////////////////////////////////////////////////////////////////////////// 03563 /// @brief Virtual destructor. 03564 virtual ~NameMismatchT() OMNI_THROW0() 03565 {} 03566 03567 public: 03568 03569 ////////////////////////////////////////////////////////////////////////// 03570 /// @brief Ожидаемое имя 03571 /** 03572 Метод возвращает ожидаемое имя секции. 03573 03574 @return Имя секции 03575 */ 03576 const String& expected() const 03577 { 03578 return m_expected; 03579 } 03580 03581 03582 ////////////////////////////////////////////////////////////////////////// 03583 /// @brief Найденное имя 03584 /** 03585 Метод возвращает найденное имя секции. 03586 03587 @return Имя секции 03588 */ 03589 const String& found() const 03590 { 03591 return m_found; 03592 } 03593 03594 private: 03595 String m_expected; ///< @brief Ожидаемое имя 03596 String m_found; ///< @brief Найденное имя 03597 }; 03598 03599 03600 ////////////////////////////////////////////////////////////////////////// 03601 /// @brief Ошибка сохранения конфигурации 03602 /** @class WritingFailureT 03603 03604 Исключение генерируется, если при сохранении конфигурации в поток 03605 вывода встретилось пустое имя секции или параметра. Метод fullName() 03606 возвращает полное имя секции или параметра. 03607 03608 Параметр шаблона @a Ch определяет тип символов строки WritingFailureT::string_type. 03609 Допустимо использование @b wchar_t и @b char. Также в зависимости от 03610 макроса #OMNI_UNICODE определяется тип omni::config::WritingFailure. 03611 */ 03612 template<typename Str> 03613 class WritingFailureT: public FailureT<Str> { 03614 typedef FailureT<Str> inherited; 03615 03616 public: 03617 typedef typename inherited::String String; 03618 03619 public: 03620 03621 ////////////////////////////////////////////////////////////////////////// 03622 /// @brief Создать исключение с параметрами 03623 /** 03624 @param[in] msg Сообщение об ошибке 03625 @param[in] element_path Полное имя секции или параметра 03626 */ 03627 WritingFailureT(const std::string &msg, const String &element_path) 03628 : inherited(msg), m_path(element_path) 03629 {} 03630 03631 03632 ////////////////////////////////////////////////////////////////////////// 03633 /// @brief Создать исключение с параметрами 03634 /** 03635 @param[in] msg Сообщение об ошибке 03636 @param[in] element_path Полное имя секции или параметра 03637 */ 03638 WritingFailureT(const char *msg, const String &element_path) 03639 : inherited(msg), m_path(element_path) 03640 {} 03641 03642 03643 ////////////////////////////////////////////////////////////////////////// 03644 /// @brief Virtual destructor. 03645 virtual ~WritingFailureT() OMNI_THROW0() 03646 {} 03647 03648 03649 public: 03650 03651 ////////////////////////////////////////////////////////////////////////// 03652 /// @brief Полное имя секции или параметра 03653 /** 03654 Метод возвращает полное имя секции или параметра, при записи которого 03655 произошло исключение. 03656 03657 @return Имя секции или параметра 03658 */ 03659 const String& path() const 03660 { 03661 return m_path; 03662 } 03663 03664 03665 private: 03666 String m_path; ///< @brief Полное имя секции или параметра 03667 }; 03668 03669 03670 03671 ////////////////////////////////////////////////////////////////////////// 03672 /// @brief Name is Empty 03673 /** 03674 Исключение генерируется, если при сохранении конфигурации в поток 03675 вывода встретилось пустое имя секции или параметра. Метод fullName() 03676 возвращает полное имя секции или параметра. 03677 03678 Параметр шаблона @a Ch определяет тип символов строки WritingFailureT::string_type. 03679 Допустимо использование @b wchar_t и @b char. Также в зависимости от 03680 макроса #OMNI_UNICODE определяется тип omni::config::WritingFailure. 03681 */ 03682 template<typename Str> 03683 class NameIsEmptyT: public WritingFailureT<Str> { 03684 typedef WritingFailureT<Str> inherited; 03685 03686 public: 03687 typedef typename inherited::String String; 03688 03689 public: 03690 03691 ////////////////////////////////////////////////////////////////////////// 03692 /// @brief Создать исключение с параметрами 03693 /** 03694 @param[in] element_path Полное имя секции или параметра 03695 */ 03696 explicit NameIsEmptyT(const String &element_path) 03697 : inherited("name is empty", element_path) 03698 {} 03699 03700 03701 ////////////////////////////////////////////////////////////////////////// 03702 /// @brief Virtual destructor. 03703 virtual ~NameIsEmptyT() OMNI_THROW0() 03704 {} 03705 }; 03706 03707 } // err namespace 03708 } // exception template classes 03709 03710 03711 // ParserT template class 03712 namespace conf 03713 { 03714 namespace io 03715 { 03716 03717 ////////////////////////////////////////////////////////////////////////// 03718 /// @brief Парсер конфигурации. 03719 /* @class ParserT 03720 03721 Вспомогательный класс используется для разбора входного потока. 03722 Выполняет подсчёт строк, ассоциирование элементов и комментариев, 03723 и проверку корректности открываемых и закрываемых скобок. 03724 */ 03725 template<typename Str> 03726 class ParserT { 03727 public: 03728 typedef Str String; 03729 typedef typename String::traits_type Traits; 03730 typedef typename Traits::char_type Char; 03731 typedef std::basic_istream<Char, Traits> IStream; 03732 typedef std::basic_ostringstream<Char, Traits> OSStream; 03733 03734 typedef SectionT<String> Section; 03735 typedef ElementT<String> Element; 03736 03737 public: 03738 03739 ////////////////////////////////////////////////////////////////////////// 03740 /// @brief Инициализировать парсер 03741 /** 03742 Конструктор начинает подсчёт строк с единицы. Выполняет начальную 03743 инициализацию парсера. Делает текущей секцию @a root. 03744 03745 @param[in,out] root Текущая секция 03746 */ 03747 explicit ParserT(Section &root) 03748 : m_last_element(0), 03749 m_last_element_line(0), 03750 m_last_comment_begin(0), 03751 m_last_comment_end(0), 03752 m_line_counter(1), 03753 m_brace_depth(0) 03754 { 03755 push(root); 03756 } 03757 03758 03759 ////////////////////////////////////////////////////////////////////////// 03760 /// @brief Разобрать секцию из потока ввода 03761 /** 03762 Функция осуществляет разбор входного потока на секции и параметры 03763 конфигурации. Секция @a cfg должна быть пустой, иначе разбираемые секции 03764 и параметры будут добавляться к уже существующим. 03765 03766 @param[in] is Поток ввода 03767 @throw omni::config::ParsingFailureT Неверный поток вывода 03768 @throw omni::config::SyntaxFailureT Неверный синтаксис 03769 @throw omni::config::MismatchFailureT Если имя закрываемой секции не соответствует открываемой 03770 */ 03771 virtual void parse(IStream &is) 03772 { 03773 typedef details::CharConst<Char> ChConst; 03774 03775 String token; 03776 03777 while (is) 03778 { 03779 skip_ws(is); 03780 03781 typename Traits::int_type meta = is.peek(); 03782 if (Traits::eq_int_type(meta, Traits::eof())) 03783 break; 03784 03785 typename Traits::char_type cx = Traits::to_char_type(meta); 03786 03787 // comment (#) 03788 if (Traits::eq(cx, ChConst::COMMENT)) 03789 { 03790 parse_comment(is.ignore()); 03791 assign_suffix(); // suffix comment - the same line 03792 } 03793 03794 // open bracket '<' 03795 else if (Traits::eq(cx, ChConst::BEGIN)) 03796 { 03797 bool is_metadata = false; 03798 bool is_open = true; 03799 03800 // open or close section? '/' 03801 cx = Traits::to_char_type(is.ignore().peek()); 03802 if (Traits::eq(cx, ChConst::CLOSE)) 03803 { 03804 is_open = false; 03805 is.ignore(); 03806 } 03807 else if (Traits::eq(cx, ChConst::METADATA)) 03808 { 03809 is_metadata = true; 03810 is.ignore(); 03811 } 03812 03813 if (!is_metadata) 03814 { 03815 get_token(is, token); // section name 03816 if (token.empty()) 03817 throw err::SyntaxErrorT<String>("empty section's name", 03818 top().fullName(), lineNumber()); 03819 brace_open(); 03820 03821 if (is_open) // create new section 03822 { 03823 Section &child = top().sections.push_back(token); 03824 push(child); // push to the section stack 03825 03826 assign_prefix(child); 03827 parse_value(is, child); 03828 } 03829 else // close section 03830 { 03831 skip_ws(is); 03832 03833 cx = Traits::to_char_type(is.peek()); 03834 if (!Traits::eq(cx, ChConst::END)) // syntax error (>) 03835 throw err::SyntaxErrorT<String>("expected \">\" char", 03836 top().fullName(), lineNumber()); 03837 03838 is.ignore(); // ignore '>' char 03839 brace_close(); 03840 03841 if (token != top().name()) 03842 throw err::NameMismatchT<String>(top().name(), 03843 token, lineNumber()); 03844 03845 set_last_element(&top()); 03846 pop(); 03847 } 03848 } 03849 else // parse meta data section <? ... ?> 03850 parse_metadata(is); 03851 } 03852 03853 // close section (/>) 03854 else if (Traits::eq(cx, ChConst::CLOSE)) 03855 { 03856 cx = Traits::to_char_type(is.ignore().peek()); 03857 if (!Traits::eq(cx, ChConst::END)) // syntax error '>' 03858 throw err::SyntaxErrorT<String>("expected slash and closing bracket", 03859 top().fullName(), lineNumber()); 03860 03861 is.ignore(); // ignore '>' char 03862 brace_close(); 03863 03864 set_last_element(&top()); 03865 pop(); 03866 } 03867 03868 // close section '>' 03869 else if (Traits::eq(cx, ChConst::END)) 03870 { 03871 is.ignore(); // ignore '>' char 03872 brace_close(); 03873 } 03874 03875 // add new element 03876 else 03877 { 03878 get_token(is, token); // parse element name 03879 if (token.empty()) 03880 throw err::SyntaxErrorT<String>("empty element's name", 03881 top().fullName(), lineNumber()); 03882 03883 Element &elem = top().elements.push_back(token); 03884 set_last_element(&elem); 03885 03886 assign_prefix(elem); 03887 if (parse_value(is, elem)) 03888 set_last_element(&elem); 03889 } 03890 } 03891 03892 if (1 < m_stack.size()) 03893 throw err::ParsingFailureT<String>("unexpected end of input stream", lineNumber()); 03894 } 03895 03896 protected: /// @name Стэк секций 03897 03898 ////////////////////////////////////////////////////////////////////////// 03899 /// @brief Новая текущая секция 03900 /** 03901 Метод запоминает предыдущую секцию и делает секцию @a cfg текущей. 03902 Вызывается при открытии секции. 03903 03904 @param[in] section Новая текущая секция 03905 */ 03906 void push(Section §ion) 03907 { 03908 m_stack.push_back(§ion); 03909 } 03910 03911 03912 ////////////////////////////////////////////////////////////////////////// 03913 /// @brief Текущая секция 03914 /** 03915 Метод возвращает текущую секцию. 03916 03917 @return Текущая секция 03918 */ 03919 Section& top() const 03920 { 03921 return *m_stack.back(); 03922 } 03923 03924 03925 ////////////////////////////////////////////////////////////////////////// 03926 /// @brief Старая текущая секция 03927 /** 03928 Метод возвращается к предыдущей текущей секции. 03929 Вызывается при закрытии секции. 03930 03931 @throw omni::config::ParsingFailureT Если закрыты все секции. 03932 */ 03933 void pop() 03934 { 03935 m_stack.pop_back(); 03936 03937 if (m_stack.empty()) // if all sections are closed 03938 throw err::ParsingFailureT<String>("root section is closed", lineNumber()); 03939 } 03940 03941 protected: /// @name Скобки 03942 03943 ////////////////////////////////////////////////////////////////////////// 03944 /// @brief Открыть скобку 03945 /** 03946 Метод увеличивает на единицу количество открытых скобок. 03947 */ 03948 void brace_open() 03949 { 03950 m_brace_depth += 1; 03951 } 03952 03953 03954 ////////////////////////////////////////////////////////////////////////// 03955 /// @brief Закрыть скобку 03956 /** 03957 Метод уменьшает на единицу количество открытых скобок. Если закрытий 03958 больше чем открытий будет сгенерировано исключение. 03959 03960 @throw omni::config::SyntaxFailureT Если закрытие встретилось раньше открытия 03961 */ 03962 void brace_close() 03963 { 03964 m_brace_depth -= 1; 03965 if (m_brace_depth < 0) 03966 throw err::SyntaxErrorT<String>("unexpected symbol (>)", 03967 top().fullName(), lineNumber()); 03968 } 03969 03970 protected: /// @name Разбор потока ввода 03971 03972 ////////////////////////////////////////////////////////////////////////// 03973 /// @brief Прочитать токен из потока ввода 03974 /** 03975 Метод читает из потока ввода @a is строку, пока не встретится 03976 один из заданных символов разделителей из @a delimiters. 03977 Считанная строка сохраняется в @a token. 03978 03979 @param[in,out] is Поток ввода 03980 @param[out] token Буфер для прочитанного токена 03981 */ 03982 static void get_pure_token(IStream &is, String &token) 03983 { 03984 std::ios_base::iostate state = std::ios_base::goodbit; 03985 const typename IStream::sentry ok(is, true); 03986 03987 if (ok) 03988 { 03989 for (;;) 03990 { 03991 typename Traits::int_type meta = is.peek(); 03992 if (Traits::eq_int_type(meta, Traits::eof())) 03993 { 03994 state |= std::ios_base::eofbit; 03995 break; 03996 } 03997 03998 typename Traits::char_type cx = Traits::to_char_type(meta); 03999 if (details::CharConst<Char>::is_delim(cx)) 04000 break; 04001 04002 is.ignore(); 04003 token += cx; 04004 } 04005 } 04006 04007 is.setstate(state); 04008 } 04009 04010 04011 ////////////////////////////////////////////////////////////////////////// 04012 /// @brief Прочитать строку в кавычках из потока ввода 04013 /** 04014 Метод читает строку в кавычках. Обязательно первым символом должен 04015 быть символ кавычки! Если строка должна содержать кавычки, то они 04016 дублируются. Например, строка "Ах, эти "чёрные" глаза." должна выглядеть 04017 так: "Ах, эти ""чёрные"" глаза." При чтении двойные кавычки заменяются 04018 одинарными. 04019 04020 @param[in,out] is Поток ввода 04021 @param[out] token Буфер для прочитанной строки 04022 @param[in] quote Символ кавычки ('\"' или '\'') 04023 */ 04024 static void get_quoted_token(IStream &is, String &token, const Char quote) 04025 { 04026 std::ios_base::iostate state = std::ios_base::goodbit; 04027 const typename IStream::sentry ok(is, true); 04028 04029 if (ok) 04030 { 04031 // ignore first quote char (if present) 04032 if (Traits::eq_int_type(is.peek(), 04033 Traits::to_int_type(quote))) 04034 is.ignore(); 04035 04036 for (;;) 04037 { 04038 typename Traits::int_type meta = is.peek(); 04039 if (Traits::eq_int_type(meta, Traits::eof())) 04040 { 04041 state |= std::ios_base::eofbit; 04042 break; 04043 } 04044 04045 typename Traits::char_type cx = Traits::to_char_type(meta); 04046 if (Traits::eq(cx, quote)) 04047 { 04048 is.ignore(); 04049 04050 // test for second quote 04051 meta = is.peek(); 04052 if (Traits::eq_int_type(meta, Traits::eof())) 04053 { 04054 state |= std::ios_base::eofbit; 04055 break; 04056 } 04057 04058 cx = Traits::to_char_type(meta); 04059 if (!Traits::eq(cx, quote)) 04060 break; 04061 } 04062 04063 is.ignore(); 04064 token += cx; 04065 } 04066 } 04067 04068 is.setstate(state); 04069 } 04070 04071 04072 ////////////////////////////////////////////////////////////////////////// 04073 /// @brief Разобрать токен 04074 /** 04075 Метод читает из потока ввода @a is имя секции или параметра или их 04076 значение. Имя может быть заключено в одинарные или двойные кавычки. 04077 04078 @param[in,out] is Поток ввода 04079 @param[out] token The string token. 04080 @return Имя или значение 04081 */ 04082 void get_token(IStream &is, String &token) 04083 { 04084 typedef details::CharConst<Char> ChConst; 04085 04086 skip_ws(is); 04087 token.resize(0); // (!) clear 04088 04089 typename Traits::int_type meta = is.peek(); 04090 if (!Traits::eq_int_type(meta, Traits::eof())) 04091 { 04092 typename Traits::char_type cx = Traits::to_char_type(meta); 04093 04094 if (Traits::eq(cx, ChConst::DQUOTE)) // "token" 04095 get_quoted_token(is, token, ChConst::DQUOTE); 04096 else if (Traits::eq(cx, ChConst::SQUOTE)) // 'token' 04097 get_quoted_token(is, token, ChConst::SQUOTE); 04098 else // one word 04099 get_pure_token(is, token); 04100 } 04101 04102 { // number of lines per token 04103 typename String::size_type found = 0; 04104 04105 for (;;) 04106 { 04107 found = token.find(ChConst::ENDLINE, found); 04108 if (found != String::npos) 04109 { 04110 m_line_counter += 1; 04111 found += 1; 04112 } 04113 else 04114 break; 04115 } 04116 } 04117 } 04118 04119 04120 ////////////////////////////////////////////////////////////////////////// 04121 /// @brief Разобрать метаданные 04122 /** 04123 Метод разбирает служебную секцию. Пока секция "<? ... ?>" просто 04124 игнорируется. Вложенность не поддерживается. 04125 04126 @param[in,out] is Поток ввода 04127 @throw omni::config::SyntaxFailureT Если не найден закрывающий тэг "?>" 04128 */ 04129 void parse_metadata(IStream &is) 04130 { 04131 typedef details::CharConst<Char> ChConst; 04132 long metadata_started = m_line_counter; 04133 04134 bool section_closed = false; 04135 String metadata; 04136 for (;;) 04137 { 04138 get_token(is, metadata); 04139 04140 typename Traits::int_type meta = is.peek(); 04141 if (Traits::eq_int_type(meta, Traits::eof())) 04142 break; 04143 04144 typename Traits::char_type cx = Traits::to_char_type(meta); 04145 if (Traits::eq(cx, ChConst::METADATA)) 04146 { 04147 is.ignore(); 04148 04149 meta = is.peek(); 04150 if (Traits::eq_int_type(meta, Traits::eof())) 04151 break; 04152 04153 cx = Traits::to_char_type(meta); 04154 if (Traits::eq(cx, ChConst::END)) 04155 { 04156 section_closed = true; 04157 is.ignore(); // ignore '>' char 04158 break; 04159 } 04160 } 04161 } 04162 04163 if (!section_closed) // meta data section must be closed 04164 throw err::SyntaxErrorT<String>("metadata section must be closed", 04165 top().fullName(), metadata_started); 04166 } 04167 04168 04169 ////////////////////////////////////////////////////////////////////////// 04170 /// @brief Разобрать комментарий 04171 /** 04172 Метод читает из потока ввода блок комментариев. Блок комментариев 04173 должен быть расположен на смежных строках. 04174 04175 @param[in,out] is Поток ввода 04176 */ 04177 void parse_comment(IStream &is) 04178 { 04179 typedef details::CharConst<Char> ChConst; 04180 04181 OSStream os; 04182 os.imbue(is.getloc()); 04183 bool one_line = true; 04184 04185 String line; 04186 04187 m_last_comment_begin = m_line_counter; 04188 while (is && !is.eof()) 04189 { 04190 std::getline(is, line, ChConst::ENDLINE); 04191 m_line_counter += 1; 04192 04193 if (one_line) 04194 one_line = false; 04195 else 04196 os.put(ChConst::ENDLINE); 04197 os << line; 04198 04199 m_last_comment_end = m_line_counter; 04200 if (skip_ws(is)) 04201 break; // (!) 04202 04203 typename Traits::int_type meta = is.peek(); 04204 if (Traits::eq_int_type(meta, Traits::eof())) 04205 break; 04206 04207 typename Traits::char_type cx = Traits::to_char_type(meta); 04208 if (Traits::eq(cx, ChConst::COMMENT)) 04209 is.ignore(); // ignore (#) 04210 else 04211 break; 04212 } 04213 04214 m_last_comment = os.str(); 04215 } 04216 04217 ////////////////////////////////////////////////////////////////////////// 04218 /// @brief Разобрать значение 04219 /** 04220 Метод пытается прочитать из потока ввода @a is 04221 значение параметра @a element. 04222 04223 @param[in,out] is Поток ввода 04224 @param[in,out] element Параметр 04225 @return @b true Если присвоено значение, иначе @b false 04226 */ 04227 bool parse_value(IStream &is, Element &element) 04228 { 04229 typedef details::CharConst<Char> ChConst; 04230 04231 skip_ws(is); 04232 04233 typename Traits::int_type meta = is.peek(); 04234 if (!Traits::eq_int_type(meta, Traits::eof())) 04235 { 04236 typename Traits::char_type cx = Traits::to_char_type(meta); 04237 if (Traits::eq(cx, ChConst::EQUAL)) 04238 { 04239 is.ignore(); // ignore (=) 04240 get_token(is, element.val()); 04241 return true; 04242 } 04243 } 04244 04245 return false; 04246 } 04247 04248 04249 ////////////////////////////////////////////////////////////////////////// 04250 /// @brief Пропустить пробелы и служебные символы 04251 /** 04252 Метод пропускает пробелы и служебные символы из потока @a is. 04253 Является аналогом @a std::ws(). Подсчитывает строки. 04254 04255 @param[in,out] is Поток ввода 04256 @return Количество пропущенных строк 04257 */ 04258 long skip_ws(IStream &is) 04259 { 04260 std::ios::iostate state = std::ios::goodbit; 04261 const typename IStream::sentry guard(is, true); 04262 long N_lines = 0; 04263 04264 if (guard) 04265 { 04266 typedef details::CharConst<Char> ChConst; 04267 typedef std::ctype<Char> Facet; 04268 04269 const Facet &fac = OMNI_USE_FACET(is.getloc(), Facet); 04270 04271 try 04272 { 04273 for (typename Traits::int_type meta = is.rdbuf()->sgetc(); 04274 ; meta = is.rdbuf()->snextc()) 04275 { 04276 if (Traits::eq_int_type(meta, Traits::eof())) 04277 { 04278 state |= std::ios::eofbit; 04279 break; 04280 } 04281 04282 typename Traits::char_type cx = Traits::to_char_type(meta); 04283 if (Traits::eq(cx, ChConst::ENDLINE)) 04284 N_lines += 1; 04285 else if (!fac.is(Facet::space, cx)) 04286 break; 04287 } 04288 } 04289 catch (...) 04290 { 04291 state |= std::ios::badbit; 04292 } 04293 } 04294 04295 is.setstate(state); 04296 m_line_counter += N_lines; 04297 return N_lines; 04298 } 04299 04300 04301 ////////////////////////////////////////////////////////////////////////// 04302 /// @brief Номер текущей строки 04303 /** 04304 Метод возвращает номер текущей строки. 04305 04306 @return Номер строки 04307 */ 04308 long lineNumber() const 04309 { 04310 return m_line_counter; 04311 } 04312 04313 protected: /// @name Комментарии 04314 04315 ////////////////////////////////////////////////////////////////////////// 04316 /// @brief Новый текущий элемент 04317 /** 04318 Метод устанавливает новый текущий элемент. Используется для 04319 постфиксных комментариев. 04320 04321 @param[in] element Новый элемент 04322 */ 04323 void set_last_element(Element *element) 04324 { 04325 m_last_element_line = m_line_counter; 04326 m_last_element = element; 04327 } 04328 04329 04330 ////////////////////////////////////////////////////////////////////////// 04331 /// @brief Установить префиксный комментарий 04332 /** 04333 Метод устанавливает префиксный комментарий для элемента @a cfg. 04334 04335 @param[in,out] element Элемент конфигурации 04336 */ 04337 void assign_prefix(Element &element) 04338 { 04339 if (!m_last_comment.empty()) 04340 if (m_last_comment_end == m_line_counter) // (!) 04341 { 04342 element.prefix() = m_last_comment; 04343 m_last_comment.resize(0); 04344 } 04345 } 04346 04347 04348 ////////////////////////////////////////////////////////////////////////// 04349 /// @brief Установить постфиксный комментарий 04350 /** 04351 Метод устанавливает суффиксный комментарий для текущего элемента. 04352 */ 04353 void assign_suffix() 04354 { 04355 if (m_last_element && !m_last_comment.empty()) 04356 if (m_last_element_line == m_last_comment_begin) // (!) 04357 { 04358 m_last_element->suffix() = m_last_comment; 04359 m_last_comment.resize(0); 04360 m_last_element = 0; 04361 } 04362 } 04363 04364 private: 04365 std::vector<Section*> m_stack; ///< @brief Стэк секций 04366 04367 Element *m_last_element; ///< @brief Последний параметр или секция 04368 long m_last_element_line; ///< @brief Номер строки последнего параметра или секции 04369 String m_last_comment; ///< @brief Последний блок комментариев 04370 long m_last_comment_begin; ///< @brief Номер первой строки блока комментариев 04371 long m_last_comment_end; ///< @brief Номер последней строки блока комментариев 04372 04373 long m_line_counter; ///< @brief Счётчик строк 04374 long m_brace_depth; ///< @brief Счётчик вложенности скобок 04375 }; 04376 04377 } // io namespace 04378 04379 04380 ////////////////////////////////////////////////////////////////////////// 04381 /// @brief Разобрать из потока ввода 04382 /** @relates SectionT 04383 04384 Оператор разбирает секцию @a cfg из потока ввода @a is. 04385 04386 @param[in] is Поток ввода 04387 @param[out] cfg Секция 04388 */ 04389 template<typename Ch, typename Tr, typename Str> inline 04390 std::basic_istream<Ch, Tr>& operator>>( 04391 std::basic_istream<Ch, Tr> &is, 04392 SectionT<Str> &cfg) 04393 { 04394 SectionT<Str> tmp; 04395 io::ParserT<Str> parser(tmp); 04396 parser.parse(is); 04397 04398 tmp.swap(cfg); 04399 return is; 04400 } 04401 04402 } // ParserT template class 04403 04404 04405 // WriterT template class... 04406 namespace conf 04407 { 04408 namespace io 04409 { 04410 04411 ////////////////////////////////////////////////////////////////////////// 04412 /// @brief Форматирование вывода секций и параметров 04413 /** @class WriterT 04414 04415 Базовый класс форматирования вывода секций и параметров. Определяет 04416 несколько абстрактных методов, используемых для вывода конфигураций: 04417 open_section(), close_section(), put_element(). Определяя эти методы 04418 можно реализовать свой стиль форматирования. 04419 04420 Для сохранения секции в поток вывода используется метод print(). 04421 */ 04422 template<typename Str> 04423 class WriterT { 04424 protected: 04425 typedef Str String; 04426 typedef typename String::traits_type Traits; 04427 typedef typename Traits::char_type Char; 04428 typedef std::basic_ostream<Char, Traits> OStream; 04429 typedef std::basic_istringstream<Char, Traits> ISStream; 04430 typedef std::basic_ostringstream<Char, Traits> OSStream; 04431 04432 typedef ElementT<String> Element; 04433 typedef SectionT<String> Section; 04434 04435 public: 04436 04437 ////////////////////////////////////////////////////////////////////////// 04438 /// @brief Параметры по умолчанию 04439 /** 04440 Устанавливает параметры по умолчанию: 2 пробела на отступ. 04441 Двойные кавычки. Значения всегда в кавычках. 04442 */ 04443 WriterT() 04444 : tabSize(2), indent(0), 04445 rootName(false), 04446 newLine(true) 04447 { 04448 doubleQuote = true; 04449 } 04450 04451 04452 ////////////////////////////////////////////////////////////////////////// 04453 /// @brief Вывести конфигурацию в поток вывода 04454 /** 04455 Метод выполняет перечисление дочерних секций и параметров и вызывает 04456 для них методы open_section(), close_section() и put_element() 04457 соответственно. Порядок секций и параметров соответствует прочитанному 04458 из файла при разборе или задаваемому при создании секции. Т.е. в общем 04459 случае дочерние секции могут чередоваться с дочерними параметрами. 04460 04461 Для дочерних секций метод вызывается рекурсивно. 04462 04463 Может генерировать исключение, например, если, параметр не имеет имени. 04464 04465 @param[in,out] os Поток вывода 04466 @param[in] section Секция конфигурации 04467 @throw omni::config::WritingFailureT если какие-либо секция или параметр 04468 не соответствуют требованиям форматирования 04469 */ 04470 void print(OStream &os, const Section §ion) const 04471 { 04472 open_section(os, section); 04473 04474 typedef typename Section::Container::const_iterator item_iterator; 04475 item_iterator i = section.m_childs.begin(); 04476 item_iterator ie = section.m_childs.end(); 04477 for (; i != ie; ++i) 04478 { 04479 Element *elem = *i; 04480 04481 if (elem->is_section()) 04482 { 04483 Section *child = static_cast<Section*>(elem); 04484 print(os, *child); 04485 } 04486 else 04487 put_element(os, *elem); 04488 } 04489 04490 close_section(os, section); 04491 } 04492 04493 protected: 04494 04495 ////////////////////////////////////////////////////////////////////////// 04496 /// @brief Начало секции 04497 /** 04498 Метод выводит префиксный комментарий (если не пустой), имя секции 04499 и её значение (если не пустое). 04500 04501 @code 04502 # prefix comment 04503 # prefix comment continue 04504 <section_name = section_value> 04505 @endcode 04506 04507 Если секция является главной и флаг rootName не установлен, 04508 то имя секции не будет выводиться, как и комментарий. 04509 04510 Также, если установлено выравнивание дочерних элементов, то 04511 определяется максимальная ширина поля. 04512 04513 @param[in,out] os Поток вывода 04514 @param[in] section Секция конфигурации 04515 @throw omni::config::WritingFailureT Если нет имени секции 04516 */ 04517 virtual void open_section(OStream &os, const Section §ion) const 04518 { 04519 typedef details::CharConst<Char> ChConst; 04520 const Char quote = doubleQuote ? ChConst::DQUOTE : ChConst::SQUOTE; 04521 04522 if ((rootName || !is_root(section)) && section.name().empty()) 04523 throw err::NameIsEmptyT<String>(section.fullName()); 04524 04525 const String indent_str(indent, ChConst::SPACE); 04526 04527 if (rootName || !is_root(section)) 04528 { 04529 if (newLine && !is_front(section)) 04530 os.put(ChConst::ENDLINE); 04531 04532 if (!section.prefix().empty()) // prefix comment 04533 put_comment_block(os, section.prefix(), 04534 indent_str, false); 04535 04536 // open section 04537 (os << indent_str).put(ChConst::BEGIN); 04538 if (need_quote(section.name())) 04539 put_qstring(os, section.name(), quote); 04540 else 04541 os << section.name(); 04542 if (!section.val().empty()) 04543 { 04544 os.put(ChConst::SPACE).put(ChConst::EQUAL).put(ChConst::SPACE); 04545 put_qstring(os, section.val(), quote); 04546 } 04547 os.put(ChConst::END).put(ChConst::ENDLINE); 04548 } 04549 04550 if (rootName || !is_root(section)) 04551 indent += tabSize; 04552 } 04553 04554 04555 ////////////////////////////////////////////////////////////////////////// 04556 /// @brief Окончание секции 04557 /** 04558 Метод выводит завершение секции и постфиксный комментарий 04559 (если не пустой). 04560 04561 @code 04562 </section_name> # suffix comment 04563 # suffix comment continue 04564 @endcode 04565 04566 @param[in,out] os Поток вывода 04567 @param[in] section Секция конфигурации 04568 @throw omni::config::WritingFailureT Если нет имени секции 04569 */ 04570 virtual void close_section(OStream &os, const Section §ion) const 04571 { 04572 typedef details::CharConst<Char> ChConst; 04573 04574 const Char quote = doubleQuote ? ChConst::DQUOTE : ChConst::SQUOTE; 04575 04576 if ((rootName || !is_root(section)) && section.name().empty()) 04577 throw err::NameIsEmptyT<String>(section.fullName()); 04578 04579 if (rootName || !is_root(section)) 04580 indent -= tabSize; 04581 04582 const String indent_str(indent, ChConst::SPACE); 04583 04584 if (rootName || !is_root(section)) 04585 { 04586 // close section 04587 OSStream o_line; 04588 o_line.imbue(os.getloc()); 04589 04590 (o_line << indent_str).put(ChConst::BEGIN).put(ChConst::CLOSE); 04591 if (need_quote(section.name())) 04592 put_qstring(o_line, section.name(), quote); 04593 else 04594 o_line << section.name(); 04595 o_line.put(ChConst::END); 04596 04597 const String line_str = o_line.str(); 04598 os << line_str; 04599 04600 if (!section.suffix().empty()) // suffix comment 04601 { 04602 const String indent_str(line_str.size()+1, ChConst::SPACE); 04603 put_comment_block(os.put(ChConst::SPACE), 04604 section.suffix(), indent_str, true); 04605 } 04606 else 04607 os.put(ChConst::ENDLINE); 04608 } 04609 else 04610 os.put(ChConst::ENDLINE); 04611 } 04612 04613 04614 ////////////////////////////////////////////////////////////////////////// 04615 /// @brief Параметр 04616 /** 04617 Метод выводит параметр @a element в поток вывода @a os. Выводится 04618 префиксный комментарий (если не пустой), имя параметра, знак равно и 04619 значение параметра (если не пустое), постфиксный комментарий 04620 (если не пустой). 04621 04622 @code 04623 # prefix comment 04624 # prefix comment continue 04625 element_name = element_value # suffix comment 04626 # suffix comment continue 04627 @endcode 04628 04629 @param[in,out] os Поток вывода 04630 @param[in] element Параметр конфигурации 04631 @throw omni::config::WritingFailureT Если нет имени параметра 04632 */ 04633 virtual void put_element(OStream &os, const Element &element) const 04634 { 04635 typedef details::CharConst<Char> ChConst; 04636 04637 const Char quote = doubleQuote ? ChConst::DQUOTE : ChConst::SQUOTE; 04638 04639 if (element.name().empty()) 04640 throw err::NameIsEmptyT<String>(element.fullName()); 04641 04642 const String indent_str(indent, ChConst::SPACE); 04643 04644 if (!element.prefix().empty()) // prefix comment 04645 put_comment_block(os.put(ChConst::ENDLINE), 04646 element.prefix(), indent_str, false); 04647 04648 OSStream o_line; 04649 o_line.imbue(os.getloc()); 04650 o_line << indent_str; 04651 04652 // print "key"="val" 04653 if (need_quote(element.name())) 04654 put_qstring(o_line, element.name(), quote); 04655 else 04656 o_line << element.name(); 04657 04658 if (!element.val().empty()) 04659 { 04660 o_line.put(ChConst::SPACE).put(ChConst::EQUAL).put(ChConst::SPACE); 04661 put_qstring(o_line, element.val(), quote); 04662 } 04663 04664 const String line_str = o_line.str(); 04665 os << line_str; 04666 04667 if (!element.suffix().empty()) // suffix comment 04668 { 04669 const String indent_str(line_str.size()+1, ChConst::SPACE); 04670 put_comment_block(os.put(ChConst::SPACE), 04671 element.suffix(), indent_str, true); 04672 } 04673 else 04674 os.put(ChConst::ENDLINE); 04675 } 04676 04677 protected: // auxiliary functions 04678 04679 ////////////////////////////////////////////////////////////////////////// 04680 /// @brief Вывести блок комментариев 04681 /** 04682 Метод перед каждой строкой добавляет отступ и символ '#'. Если 04683 установлен флаг @a skip_first_indent, то отступ перед первой строкой 04684 не добавляется. Это позволяет выводить суффиксные комментарии. 04685 04686 @code 04687 ....# prefix first line 04688 ....# prefix second line 04689 ....< XXX > 04690 ....</ XXX > # suffix first line 04691 .............# suffix second line 04692 @endcode 04693 04694 Блок комментариев @a comment может содержать несколько строк, 04695 разделённых символом перевода строки. 04696 04697 @param[in,out] os Поток вывода 04698 @param[in] comment Блок комментариев 04699 @param[in] indent Текущий отступ 04700 @param[in] skip_first_indent Не выводит отступ для первой строки 04701 */ 04702 static void put_comment_block(OStream &os, const String &comment, 04703 const String &indent, bool skip_first_indent) 04704 { 04705 typedef details::CharConst<Char> ChConst; 04706 04707 ISStream is(comment); 04708 is.imbue(os.getloc()); 04709 04710 String line; 04711 04712 do { 04713 std::getline(is, line, ChConst::ENDLINE); 04714 04715 if (skip_first_indent) 04716 skip_first_indent = false; 04717 else 04718 os << indent; 04719 04720 os.put(ChConst::COMMENT); 04721 os << line; 04722 os.put(ChConst::ENDLINE); 04723 } while (is && !is.eof()); 04724 } 04725 04726 04727 ////////////////////////////////////////////////////////////////////////// 04728 /// @brief Получить строку в кавычках 04729 /** 04730 Метод позволяет преобразовать строку @a text в строку в кавычках. 04731 Если флаг @a alwaysQuoted не установлен, и исходная строка не содержит 04732 служебных символов, то кавычки не добавляются. 04733 04734 @param[in] text Исходная строка 04735 @return @b true if text need quote, otherwise @b false. 04736 */ 04737 static bool need_quote(const String &text) 04738 { 04739 typedef details::CharConst<Char> ChConst; 04740 04741 for (size_t i = 0; ChConst::DELIMITERS[i]; ++i) 04742 if (text.find(ChConst::DELIMITERS[i]) != String::npos) 04743 return true; 04744 04745 return false; 04746 } 04747 04748 04749 ////////////////////////////////////////////////////////////////////////// 04750 /// @brief Записать строку в кавычках в поток вывода 04751 /** 04752 Метод пишет строку @a str в кавычках в поток вывода @a os. Если 04753 внутри строки встречаются кавычки, то они дублируются. 04754 04755 @param[in,out] os Поток вывода 04756 @param[in] str Строка для записи 04757 @param[in] quote Символ кавычки ('\"' или '\'') 04758 */ 04759 static void put_qstring(OStream &os, const String &str, Char quote) 04760 { 04761 os.put(quote); 04762 for (size_t i = 0; i < str.size(); ++i) 04763 { 04764 if (Traits::eq(str[i], quote)) 04765 os.put(quote); 04766 os.put(str[i]); 04767 } 04768 os.put(quote); 04769 } 04770 04771 04772 protected: 04773 04774 ////////////////////////////////////////////////////////////////////////// 04775 /// @brief Главная секция? 04776 /** 04777 Метод проверяет является ли секция @a section главной, 04778 т.е. у неё нет родительской секции. 04779 04780 @param[in] section Секция конфигурации 04781 @return @b true если секция является главной 04782 */ 04783 static bool is_root(const Section §ion) 04784 { 04785 return (0 == section.parent()); 04786 } 04787 04788 04789 ////////////////////////////////////////////////////////////////////////// 04790 /// @brief Первая секция? 04791 /** 04792 Метод проверяет является ли секция @a section 04793 первой в списке её родительской секции. 04794 04795 @param[in] section Секция конфигурации 04796 @return @b true если секция является первой 04797 */ 04798 static bool is_front(const Section §ion) 04799 { 04800 const Section *parent = section.parent(); 04801 04802 if (parent && !parent->sections.empty() 04803 && &parent->sections.front() == §ion) 04804 return true; 04805 04806 return false; 04807 } 04808 04809 04810 ////////////////////////////////////////////////////////////////////////// 04811 /// @brief Последняя секция? 04812 /** 04813 Метод проверяет является ли секция @a section 04814 последней в списке её родительской секции. 04815 04816 @param[in] section Секция конфигурации 04817 @return @b true если секция является последней 04818 */ 04819 static bool is_back(const Section §ion) 04820 { 04821 const Section *parent = section.parent(); 04822 04823 if (parent && !parent->sections.empty() 04824 && &parent->sections.back() == §ion) 04825 return true; 04826 04827 return false; 04828 } 04829 04830 public: 04831 mutable size_t indent; ///< @brief Текущий размер отступа 04832 size_t tabSize; ///< @brief Количество пробелов в одном отступе 04833 04834 bool rootName; 04835 bool newLine; 04836 bool doubleQuote; 04837 }; 04838 04839 } // io namespace 04840 04841 04842 ////////////////////////////////////////////////////////////////////////// 04843 /// @brief Write to output stream. 04844 /** @relates SectionT 04845 04846 Оператор выводит секцию @a cfg в поток вывода @a os. 04847 04848 Используется простое форматирование с параметрами по умолчанию. 04849 04850 @param[in] os Output stream. 04851 @param[in] section Configuration section. 04852 @return Output stream. 04853 */ 04854 template<typename Ch, typename Tr, typename Str> inline 04855 std::basic_ostream<Ch, Tr>& operator<<( 04856 std::basic_ostream<Ch, Tr> &os, 04857 const SectionT<Str> §ion) 04858 { 04859 io::WriterT<Str> writer; 04860 writer.print(os, section); 04861 return os; 04862 } 04863 04864 } // WriterT template class 04865 04866 04867 // CharConst & Iterator... 04868 namespace conf 04869 { 04870 /// @cond details 04871 namespace details 04872 { 04873 04874 ////////////////////////////////////////////////////////////////////////// 04875 /// @brief Char constants. 04876 /** 04877 Шаблонный класс содержит набор строковых и символьных констант 04878 специализированных для @b wchar_t и @b char. 04879 04880 Разделитель CharConst::SEPARATOR используется методом 04881 omni::config::ElementT::fullName() между именами родительских 04882 и дочерних элементов. 04883 04884 Остальные константы используются при разборе конфигурации 04885 из потока ввода и при сохранении конфигурации в поток вывода. 04886 */ 04887 template<typename Ch> 04888 class CharConst { 04889 public: 04890 typedef Ch Char; ///< @brief Char type. 04891 04892 public: // string constants 04893 static const Char DELIMITERS[]; ///< @brief Delimiters string. 04894 static const Char SEPARATOR[]; ///< @brief Name separator. 04895 04896 /// @brief Is char delimiter? 04897 static bool is_delim(Char cx); 04898 04899 public: // char constants 04900 static const Char ENDLINE; ///< @brief New line char ('\n'). 04901 static const Char SPACE; ///< @brief Space char (' '). 04902 static const Char COMMENT; ///< @brief Comment char ('#'). 04903 static const Char METADATA; ///< @brief Metadata section ('?'). 04904 static const Char EQUAL; ///< @brief Equal char ('='). 04905 static const Char BEGIN; ///< @brief Section begin ('<'). 04906 static const Char CLOSE; ///< @brief Close section ('/'). 04907 static const Char END; ///< @brief Section end ('>'). 04908 static const Char SQUOTE; ///< @brief Single quote ('\''). 04909 static const Char DQUOTE; ///< @brief Double quote ('\"'). 04910 }; 04911 04912 04913 ////////////////////////////////////////////////////////////////////////// 04914 /// @brief Constants traits. 04915 template<typename Val> 04916 struct ConstTraits 04917 { 04918 typedef Val value_type; ///< @brief Value type. 04919 typedef const Val& reference; ///< @brief Reference type. 04920 typedef const Val* pointer; ///< @brief Pointer type. 04921 }; 04922 04923 04924 ////////////////////////////////////////////////////////////////////////// 04925 /// @brief Non-constant traits. 04926 template<typename Val> 04927 struct NConstTraits 04928 { 04929 typedef Val value_type; ///< @brief Value type. 04930 typedef Val& reference; ///< @brief Reference type. 04931 typedef Val* pointer; ///< @brief Pointer type. 04932 }; 04933 04934 04935 ////////////////////////////////////////////////////////////////////////// 04936 /// @brief Итератор для списка параметров или секций 04937 /** 04938 */ 04939 template<typename Base, typename Tr> 04940 class Iterator//: public std::iterator<std::random_access_iterator_tag, Val> 04941 { 04942 typedef Iterator<Base, Tr> ThisType; 04943 typedef Base BaseType; ///< @brief Базовый итератор 04944 04945 public: // typedefs 04946 typedef std::random_access_iterator_tag iterator_category; ///< @brief Категория итератора 04947 typedef ptrdiff_t difference_type; ///< @brief Расстояние между двумя итераторами 04948 typedef ptrdiff_t distance_type; ///< @brief Расстояние между двумя итераторами 04949 typedef size_t size_type; ///< @brief Смещение итератора 04950 04951 typedef typename Tr::value_type value_type; ///< @brief Итерируемый элемент 04952 typedef typename Tr::reference reference; ///< @brief Ссылка на элемент 04953 typedef typename Tr::pointer pointer; ///< @brief Указатель на элемент 04954 04955 04956 public: // constructors 04957 04958 ////////////////////////////////////////////////////////////////////////// 04959 /// @brief Default constructor. 04960 Iterator() 04961 {} 04962 04963 04964 ////////////////////////////////////////////////////////////////////////// 04965 /// @brief Конструктор с заданием значения 04966 explicit Iterator(const BaseType &x) 04967 : m_base(x) 04968 {} 04969 04970 04971 ////////////////////////////////////////////////////////////////////////// 04972 /// @brief Вспомогательный конструктор копирования 04973 template<typename Base2, typename Tr2> 04974 Iterator(const Iterator<Base2, Tr2> &other) 04975 : m_base(other.base()) 04976 {} 04977 04978 04979 ////////////////////////////////////////////////////////////////////////// 04980 /// @brief Вспомогательный оператор присваивания 04981 template<typename Base2, typename Tr2> 04982 ThisType& operator=(const Iterator<Base2, Tr2> &other) 04983 { 04984 m_base = other.base(); 04985 return *this; 04986 } 04987 04988 public: // access 04989 04990 ////////////////////////////////////////////////////////////////////////// 04991 /// @brief Доступ по индексу 04992 reference operator[](difference_type i) const 04993 { 04994 return *m_base[i]; 04995 } 04996 04997 04998 ////////////////////////////////////////////////////////////////////////// 04999 /// @brief Разъименование итератора 05000 reference operator*() const 05001 { 05002 return *(*m_base); 05003 } 05004 05005 05006 ////////////////////////////////////////////////////////////////////////// 05007 /// @brief Разъименование итератора 05008 pointer operator->() const 05009 { 05010 return *m_base; 05011 } 05012 05013 05014 ////////////////////////////////////////////////////////////////////////// 05015 /// @brief Базовый итератор 05016 const BaseType& base() const 05017 { 05018 return m_base; 05019 } 05020 05021 public: /// @name Инкремент и декремент 05022 05023 ////////////////////////////////////////////////////////////////////////// 05024 /// @brief Префиксный инкремент 05025 ThisType& operator++() 05026 { 05027 ++m_base; 05028 return *this; 05029 } 05030 05031 05032 ////////////////////////////////////////////////////////////////////////// 05033 /// @brief Префиксный декремент 05034 ThisType& operator--() 05035 { 05036 --m_base; 05037 return *this; 05038 } 05039 05040 05041 ////////////////////////////////////////////////////////////////////////// 05042 /// @brief Постфиксный инкремент 05043 const ThisType operator++(int) 05044 { 05045 return ThisType(m_base++); 05046 } 05047 05048 05049 ////////////////////////////////////////////////////////////////////////// 05050 /// @brief Постфиксный декремент 05051 const ThisType operator--(int) 05052 { 05053 return ThisType(m_base--); 05054 } 05055 05056 05057 ////////////////////////////////////////////////////////////////////////// 05058 /// @brief Смещение итератора вверх 05059 ThisType& operator+=(difference_type d) 05060 { 05061 m_base += d; 05062 return *this; 05063 } 05064 05065 05066 ////////////////////////////////////////////////////////////////////////// 05067 /// @brief Смещение итератора вниз 05068 ThisType& operator-=(difference_type d) 05069 { 05070 m_base -= d; 05071 return *this; 05072 } 05073 05074 private: 05075 BaseType m_base; ///< @brief Базовый итератор 05076 }; 05077 05078 05079 ////////////////////////////////////////////////////////////////////////// 05080 /// @brief Проверка на равенство 05081 /** @relates Iterator 05082 */ 05083 template<typename Base1, typename Tr1, typename Base2, typename Tr2> inline 05084 bool operator==(const Iterator<Base1, Tr1> &x, const Iterator<Base2, Tr2> &y) 05085 { 05086 return x.base() == y.base(); 05087 } 05088 05089 05090 ////////////////////////////////////////////////////////////////////////// 05091 /// @brief Проверка на неравенство 05092 /** @relates Iterator 05093 */ 05094 template<typename Base1, typename Tr1, typename Base2, typename Tr2> inline 05095 bool operator!=(const Iterator<Base1, Tr1> &x, const Iterator<Base2, Tr2> &y) 05096 { 05097 return x.base() != y.base(); 05098 } 05099 05100 05101 ////////////////////////////////////////////////////////////////////////// 05102 /// @brief Проверка на меньше 05103 /** @relates Iterator 05104 */ 05105 template<typename Base1, typename Tr1, typename Base2, typename Tr2> inline 05106 bool operator<(const Iterator<Base1, Tr1> &x, const Iterator<Base2, Tr2> &y) 05107 { 05108 return x.base() < y.base(); 05109 } 05110 05111 05112 ////////////////////////////////////////////////////////////////////////// 05113 /// @brief Проверка на больше 05114 /** @relates Iterator 05115 */ 05116 template<typename Base1, typename Tr1, typename Base2, typename Tr2> inline 05117 bool operator>(const Iterator<Base1, Tr1> &x, const Iterator<Base2, Tr2> &y) 05118 { 05119 return x.base() > y.base(); 05120 } 05121 05122 05123 ////////////////////////////////////////////////////////////////////////// 05124 /// @brief Проверка на меньше или равно 05125 /** @relates Iterator 05126 */ 05127 template<typename Base1, typename Tr1, typename Base2, typename Tr2> inline 05128 bool operator<=(const Iterator<Base1, Tr1> &x, const Iterator<Base2, Tr2> &y) 05129 { 05130 return x.base() <= y.base(); 05131 } 05132 05133 05134 ////////////////////////////////////////////////////////////////////////// 05135 /// @brief Проверка на больше или равно 05136 /** @relates Iterator 05137 */ 05138 template<typename Base1, typename Tr1, typename Base2, typename Tr2> inline 05139 bool operator>=(const Iterator<Base1, Tr1> &x, const Iterator<Base2, Tr2> &y) 05140 { 05141 return x.base() >= y.base(); 05142 } 05143 05144 05145 ////////////////////////////////////////////////////////////////////////// 05146 /// @brief Смещение итератора вверх 05147 /** @relates Iterator 05148 */ 05149 template<typename Base, typename Tr> inline 05150 const Iterator<Base, Tr> operator+(const Iterator<Base, Tr> &x, ptrdiff_t d) 05151 { 05152 return Iterator<Base, Tr>(x.base() + d); 05153 } 05154 05155 05156 ////////////////////////////////////////////////////////////////////////// 05157 /// @brief Смещение итератора вниз 05158 /** @relates Iterator 05159 */ 05160 template<typename Base, typename Tr> inline 05161 const Iterator<Base, Tr> operator-(const Iterator<Base, Tr> &x, ptrdiff_t d) 05162 { 05163 return Iterator<Base, Tr>(x.base() - d); 05164 } 05165 05166 05167 ////////////////////////////////////////////////////////////////////////// 05168 /// @brief Разность двух итераторов 05169 /** @relates Iterator 05170 */ 05171 template<typename Base1, typename Tr1, typename Base2, typename Tr2> inline 05172 ptrdiff_t operator-(const Iterator<Base1, Tr1> &x, const Iterator<Base2, Tr2> &y) 05173 { 05174 return x.base() - y.base(); 05175 } 05176 05177 } // details namespace 05178 /// @endcond 05179 } // CharConst & Iterator 05180 05181 } // omni namespace 05182 05183 #endif // __OMNI_CONF_HPP_