Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:50:18

0001 // ----------------------------------------------------------------------------
0002 // Copyright (C) 2002-2006 Marcin Kalicinski
0003 // Copyright (C) 2009 Sebastian Redl
0004 //
0005 // Distributed under the Boost Software License, Version 1.0. 
0006 // (See accompanying file LICENSE_1_0.txt or copy at 
0007 // http://www.boost.org/LICENSE_1_0.txt)
0008 //
0009 // For more information, see www.boost.org
0010 // ----------------------------------------------------------------------------
0011 #ifndef BOOST_PROPERTY_TREE_INI_PARSER_HPP_INCLUDED
0012 #define BOOST_PROPERTY_TREE_INI_PARSER_HPP_INCLUDED
0013 
0014 #include <boost/property_tree/ptree.hpp>
0015 #include <boost/property_tree/detail/ptree_utils.hpp>
0016 #include <boost/property_tree/detail/file_parser_error.hpp>
0017 #include <fstream>
0018 #include <string>
0019 #include <sstream>
0020 #include <stdexcept>
0021 #include <locale>
0022 
0023 namespace boost { namespace property_tree { namespace ini_parser
0024 {
0025 
0026     /**
0027      * Determines whether the @c flags are valid for use with the ini_parser.
0028      * @param flags value to check for validity as flags to ini_parser.
0029      * @return true if the flags are valid, false otherwise.
0030      */
0031     inline bool validate_flags(int flags)
0032     {
0033         return flags == 0;
0034     }
0035 
0036     /** Indicates an error parsing INI formatted data. */
0037     class ini_parser_error: public file_parser_error
0038     {
0039     public:
0040         /**
0041          * Construct an @c ini_parser_error
0042          * @param message Message describing the parser error.
0043          * @param filename The name of the file being parsed containing the
0044          *                 error.
0045          * @param line The line in the given file where an error was
0046          *             encountered.
0047          */
0048         ini_parser_error(const std::string &message,
0049                          const std::string &filename,
0050                          unsigned long line)
0051             : file_parser_error(message, filename, line)
0052         {
0053         }
0054     };
0055 
0056     /**
0057      * Read INI from a the given stream and translate it to a property tree.
0058      * @note Clears existing contents of property tree. In case of error
0059      *       the property tree is not modified.
0060      * @throw ini_parser_error If a format violation is found.
0061      * @param stream Stream from which to read in the property tree.
0062      * @param[out] pt The property tree to populate.
0063      */
0064     template<class Ptree>
0065     void read_ini(std::basic_istream<
0066                     typename Ptree::key_type::value_type> &stream,
0067                   Ptree &pt)
0068     {
0069         typedef typename Ptree::key_type::value_type Ch;
0070         typedef std::basic_string<Ch> Str;
0071         const Ch semicolon = stream.widen(';');
0072         const Ch hash = stream.widen('#');
0073         const Ch lbracket = stream.widen('[');
0074         const Ch rbracket = stream.widen(']');
0075 
0076         Ptree local;
0077         unsigned long line_no = 0;
0078         Ptree *section = 0;
0079         Str line;
0080 
0081         // For all lines
0082         while (stream.good())
0083         {
0084 
0085             // Get line from stream
0086             ++line_no;
0087             std::getline(stream, line);
0088             if (!stream.good() && !stream.eof())
0089                 BOOST_PROPERTY_TREE_THROW(ini_parser_error(
0090                     "read error", "", line_no));
0091 
0092             // If line is non-empty
0093             line = property_tree::detail::trim(line, stream.getloc());
0094             if (!line.empty())
0095             {
0096                 // Comment, section or key?
0097                 if (line[0] == semicolon || line[0] == hash)
0098                 {
0099                     // Ignore comments
0100                 }
0101                 else if (line[0] == lbracket)
0102                 {
0103                     // If the previous section was empty, drop it again.
0104                     if (section && section->empty())
0105                         local.pop_back();
0106                     typename Str::size_type end = line.find(rbracket);
0107                     if (end == Str::npos)
0108                         BOOST_PROPERTY_TREE_THROW(ini_parser_error(
0109                             "unmatched '['", "", line_no));
0110                     Str key = property_tree::detail::trim(
0111                         line.substr(1, end - 1), stream.getloc());
0112                     if (local.find(key) != local.not_found())
0113                         BOOST_PROPERTY_TREE_THROW(ini_parser_error(
0114                             "duplicate section name", "", line_no));
0115                     section = &local.push_back(
0116                         std::make_pair(key, Ptree()))->second;
0117                 }
0118                 else
0119                 {
0120                     Ptree &container = section ? *section : local;
0121                     typename Str::size_type eqpos = line.find(Ch('='));
0122                     if (eqpos == Str::npos)
0123                         BOOST_PROPERTY_TREE_THROW(ini_parser_error(
0124                             "'=' character not found in line", "", line_no));
0125                     if (eqpos == 0)
0126                         BOOST_PROPERTY_TREE_THROW(ini_parser_error(
0127                             "key expected", "", line_no));
0128                     Str key = property_tree::detail::trim(
0129                         line.substr(0, eqpos), stream.getloc());
0130                     Str data = property_tree::detail::trim(
0131                         line.substr(eqpos + 1, Str::npos), stream.getloc());
0132                     if (container.find(key) != container.not_found())
0133                         BOOST_PROPERTY_TREE_THROW(ini_parser_error(
0134                             "duplicate key name", "", line_no));
0135                     container.push_back(std::make_pair(key, Ptree(data)));
0136                 }
0137             }
0138         }
0139         // If the last section was empty, drop it again.
0140         if (section && section->empty())
0141             local.pop_back();
0142 
0143         // Swap local ptree with result ptree
0144         pt.swap(local);
0145 
0146     }
0147 
0148     /**
0149      * Read INI from a the given file and translate it to a property tree.
0150      * @note Clears existing contents of property tree.  In case of error the
0151      *       property tree unmodified.
0152      * @throw ini_parser_error In case of error deserializing the property tree.
0153      * @param filename Name of file from which to read in the property tree.
0154      * @param[out] pt The property tree to populate.
0155      * @param loc The locale to use when reading in the file contents.
0156      */
0157     template<class Ptree>
0158     void read_ini(const std::string &filename, 
0159                   Ptree &pt,
0160                   const std::locale &loc = std::locale())
0161     {
0162         std::basic_ifstream<typename Ptree::key_type::value_type>
0163             stream(filename.c_str());
0164         if (!stream)
0165             BOOST_PROPERTY_TREE_THROW(ini_parser_error(
0166                 "cannot open file", filename, 0));
0167         stream.imbue(loc);
0168         try {
0169             read_ini(stream, pt);
0170         }
0171         catch (ini_parser_error &e) {
0172             BOOST_PROPERTY_TREE_THROW(ini_parser_error(
0173                 e.message(), filename, e.line()));
0174         }
0175     }
0176 
0177     namespace detail
0178     {
0179         template<class Ptree>
0180         void check_dupes(const Ptree &pt)
0181         {
0182             if(pt.size() <= 1)
0183                 return;
0184             const typename Ptree::key_type *lastkey = 0;
0185             typename Ptree::const_assoc_iterator it = pt.ordered_begin(),
0186                                                  end = pt.not_found();
0187             lastkey = &it->first;
0188             for(++it; it != end; ++it) {
0189                 if(*lastkey == it->first)
0190                     BOOST_PROPERTY_TREE_THROW(ini_parser_error(
0191                         "duplicate key", "", 0));
0192                 lastkey = &it->first;
0193             }
0194         }
0195 
0196         template <typename Ptree>
0197         void write_keys(std::basic_ostream<
0198                                       typename Ptree::key_type::value_type
0199                                   > &stream,
0200                                   const Ptree& pt,
0201                                   bool throw_on_children)
0202         {
0203             typedef typename Ptree::key_type::value_type Ch;
0204             for (typename Ptree::const_iterator it = pt.begin(), end = pt.end();
0205                  it != end; ++it)
0206             {
0207                 if (!it->second.empty()) {
0208                     if (throw_on_children) {
0209                         BOOST_PROPERTY_TREE_THROW(ini_parser_error(
0210                             "ptree is too deep", "", 0));
0211                     }
0212                     continue;
0213                 }
0214                 stream << it->first << Ch('=')
0215                     << it->second.template get_value<
0216                         std::basic_string<Ch> >()
0217                     << Ch('\n');
0218             }
0219         }
0220 
0221         template <typename Ptree>
0222         void write_top_level_keys(std::basic_ostream<
0223                                       typename Ptree::key_type::value_type
0224                                   > &stream,
0225                                   const Ptree& pt)
0226         {
0227             write_keys(stream, pt, false);
0228         }
0229 
0230         template <typename Ptree>
0231         void write_sections(std::basic_ostream<
0232                                 typename Ptree::key_type::value_type
0233                             > &stream,
0234                             const Ptree& pt)
0235         {
0236             typedef typename Ptree::key_type::value_type Ch;
0237             for (typename Ptree::const_iterator it = pt.begin(), end = pt.end();
0238                  it != end; ++it)
0239             {
0240                 if (!it->second.empty()) {
0241                     check_dupes(it->second);
0242                     if (!it->second.data().empty())
0243                         BOOST_PROPERTY_TREE_THROW(ini_parser_error(
0244                             "mixed data and children", "", 0));
0245                     stream << Ch('[') << it->first << Ch(']') << Ch('\n');
0246                     write_keys(stream, it->second, true);
0247                 }
0248             }
0249         }
0250     }
0251 
0252     /**
0253      * Translates the property tree to INI and writes it the given output
0254      * stream.
0255      * @pre @e pt cannot have data in its root.
0256      * @pre @e pt cannot have keys both data and children.
0257      * @pre @e pt cannot be deeper than two levels.
0258      * @pre There cannot be duplicate keys on any given level of @e pt.
0259      * @throw ini_parser_error In case of error translating the property tree to
0260      *                         INI or writing to the output stream.
0261      * @param stream The stream to which to write the INI representation of the 
0262      *               property tree.
0263      * @param pt The property tree to tranlsate to INI and output.
0264      * @param flags The flags to use when writing the INI file.
0265      *              No flags are currently supported.
0266      */
0267     template<class Ptree>
0268     void write_ini(std::basic_ostream<
0269                        typename Ptree::key_type::value_type
0270                    > &stream,
0271                    const Ptree &pt,
0272                    int flags = 0)
0273     {
0274         BOOST_ASSERT(validate_flags(flags));
0275         (void)flags;
0276 
0277         if (!pt.data().empty())
0278             BOOST_PROPERTY_TREE_THROW(ini_parser_error(
0279                 "ptree has data on root", "", 0));
0280         detail::check_dupes(pt);
0281 
0282         detail::write_top_level_keys(stream, pt);
0283         detail::write_sections(stream, pt);
0284     }
0285 
0286     /**
0287      * Translates the property tree to INI and writes it the given file.
0288      * @pre @e pt cannot have data in its root.
0289      * @pre @e pt cannot have keys both data and children.
0290      * @pre @e pt cannot be deeper than two levels.
0291      * @pre There cannot be duplicate keys on any given level of @e pt.
0292      * @throw info_parser_error In case of error translating the property tree
0293      *                          to INI or writing to the file.
0294      * @param filename The name of the file to which to write the INI
0295      *                 representation of the property tree.
0296      * @param pt The property tree to tranlsate to INI and output.
0297      * @param flags The flags to use when writing the INI file.
0298      *              The following flags are supported:
0299      * @li @c skip_ini_validity_check -- Skip check if ptree is a valid ini. The
0300      *     validity check covers the preconditions but takes <tt>O(n log n)</tt>
0301      *     time.
0302      * @param loc The locale to use when writing the file.
0303      */
0304     template<class Ptree>
0305     void write_ini(const std::string &filename,
0306                    const Ptree &pt,
0307                    int flags = 0,
0308                    const std::locale &loc = std::locale())
0309     {
0310         std::basic_ofstream<typename Ptree::key_type::value_type>
0311             stream(filename.c_str());
0312         if (!stream)
0313             BOOST_PROPERTY_TREE_THROW(ini_parser_error(
0314                 "cannot open file", filename, 0));
0315         stream.imbue(loc);
0316         try {
0317             write_ini(stream, pt, flags);
0318         }
0319         catch (ini_parser_error &e) {
0320             BOOST_PROPERTY_TREE_THROW(ini_parser_error(
0321                 e.message(), filename, e.line()));
0322         }
0323         stream.flush();
0324         if (!stream)
0325             BOOST_PROPERTY_TREE_THROW(ini_parser_error(
0326                 "write error", filename, 0));
0327     }
0328 
0329 } } }
0330 
0331 namespace boost { namespace property_tree
0332 {
0333     using ini_parser::ini_parser_error;
0334     using ini_parser::read_ini;
0335     using ini_parser::write_ini;
0336 } }
0337 
0338 #endif