conf.hpp

Go to the documentation of this file.
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 &section_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 &section_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 &section_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 &section)
03907   {
03908     m_stack.push_back(&section);
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 &section) 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 &section) 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 &section) 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 &section)
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 &section)
04799   {
04800     const Section *parent = section.parent();
04801 
04802     if (parent && !parent->sections.empty()
04803       && &parent->sections.front() == &section)
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 &section)
04820   {
04821     const Section *parent = section.parent();
04822 
04823     if (parent && !parent->sections.empty()
04824       && &parent->sections.back() == &section)
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> &section)
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_

Generated on Wed Jun 6 17:27:46 2007 for OMNI by  doxygen 1.5.2