Squashed 'third_party/boostorg/property_tree/' content from commit bdfe275
Change-Id: I075a5e242aaddc356ecc81e756c4a0907fc38130
git-subtree-dir: third_party/boostorg/property_tree
git-subtree-split: bdfe275d172ac30bc5e89a6375a5a64dea20b3c0
diff --git a/include/boost/property_tree/ini_parser.hpp b/include/boost/property_tree/ini_parser.hpp
new file mode 100644
index 0000000..50d3c97
--- /dev/null
+++ b/include/boost/property_tree/ini_parser.hpp
@@ -0,0 +1,334 @@
+// ----------------------------------------------------------------------------
+// Copyright (C) 2002-2006 Marcin Kalicinski
+// Copyright (C) 2009 Sebastian Redl
+//
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+//
+// For more information, see www.boost.org
+// ----------------------------------------------------------------------------
+#ifndef BOOST_PROPERTY_TREE_INI_PARSER_HPP_INCLUDED
+#define BOOST_PROPERTY_TREE_INI_PARSER_HPP_INCLUDED
+
+#include <boost/property_tree/ptree.hpp>
+#include <boost/property_tree/detail/ptree_utils.hpp>
+#include <boost/property_tree/detail/file_parser_error.hpp>
+#include <fstream>
+#include <string>
+#include <sstream>
+#include <stdexcept>
+#include <locale>
+
+namespace boost { namespace property_tree { namespace ini_parser
+{
+
+ /**
+ * Determines whether the @c flags are valid for use with the ini_parser.
+ * @param flags value to check for validity as flags to ini_parser.
+ * @return true if the flags are valid, false otherwise.
+ */
+ inline bool validate_flags(int flags)
+ {
+ return flags == 0;
+ }
+
+ /** Indicates an error parsing INI formatted data. */
+ class ini_parser_error: public file_parser_error
+ {
+ public:
+ /**
+ * Construct an @c ini_parser_error
+ * @param message Message describing the parser error.
+ * @param filename The name of the file being parsed containing the
+ * error.
+ * @param line The line in the given file where an error was
+ * encountered.
+ */
+ ini_parser_error(const std::string &message,
+ const std::string &filename,
+ unsigned long line)
+ : file_parser_error(message, filename, line)
+ {
+ }
+ };
+
+ /**
+ * Read INI from a the given stream and translate it to a property tree.
+ * @note Clears existing contents of property tree. In case of error
+ * the property tree is not modified.
+ * @throw ini_parser_error If a format violation is found.
+ * @param stream Stream from which to read in the property tree.
+ * @param[out] pt The property tree to populate.
+ */
+ template<class Ptree>
+ void read_ini(std::basic_istream<
+ typename Ptree::key_type::value_type> &stream,
+ Ptree &pt)
+ {
+ typedef typename Ptree::key_type::value_type Ch;
+ typedef std::basic_string<Ch> Str;
+ const Ch semicolon = stream.widen(';');
+ const Ch hash = stream.widen('#');
+ const Ch lbracket = stream.widen('[');
+ const Ch rbracket = stream.widen(']');
+
+ Ptree local;
+ unsigned long line_no = 0;
+ Ptree *section = 0;
+ Str line;
+
+ // For all lines
+ while (stream.good())
+ {
+
+ // Get line from stream
+ ++line_no;
+ std::getline(stream, line);
+ if (!stream.good() && !stream.eof())
+ BOOST_PROPERTY_TREE_THROW(ini_parser_error(
+ "read error", "", line_no));
+
+ // If line is non-empty
+ line = property_tree::detail::trim(line, stream.getloc());
+ if (!line.empty())
+ {
+ // Comment, section or key?
+ if (line[0] == semicolon || line[0] == hash)
+ {
+ // Ignore comments
+ }
+ else if (line[0] == lbracket)
+ {
+ // If the previous section was empty, drop it again.
+ if (section && section->empty())
+ local.pop_back();
+ typename Str::size_type end = line.find(rbracket);
+ if (end == Str::npos)
+ BOOST_PROPERTY_TREE_THROW(ini_parser_error(
+ "unmatched '['", "", line_no));
+ Str key = property_tree::detail::trim(
+ line.substr(1, end - 1), stream.getloc());
+ if (local.find(key) != local.not_found())
+ BOOST_PROPERTY_TREE_THROW(ini_parser_error(
+ "duplicate section name", "", line_no));
+ section = &local.push_back(
+ std::make_pair(key, Ptree()))->second;
+ }
+ else
+ {
+ Ptree &container = section ? *section : local;
+ typename Str::size_type eqpos = line.find(Ch('='));
+ if (eqpos == Str::npos)
+ BOOST_PROPERTY_TREE_THROW(ini_parser_error(
+ "'=' character not found in line", "", line_no));
+ if (eqpos == 0)
+ BOOST_PROPERTY_TREE_THROW(ini_parser_error(
+ "key expected", "", line_no));
+ Str key = property_tree::detail::trim(
+ line.substr(0, eqpos), stream.getloc());
+ Str data = property_tree::detail::trim(
+ line.substr(eqpos + 1, Str::npos), stream.getloc());
+ if (container.find(key) != container.not_found())
+ BOOST_PROPERTY_TREE_THROW(ini_parser_error(
+ "duplicate key name", "", line_no));
+ container.push_back(std::make_pair(key, Ptree(data)));
+ }
+ }
+ }
+ // If the last section was empty, drop it again.
+ if (section && section->empty())
+ local.pop_back();
+
+ // Swap local ptree with result ptree
+ pt.swap(local);
+
+ }
+
+ /**
+ * Read INI from a the given file and translate it to a property tree.
+ * @note Clears existing contents of property tree. In case of error the
+ * property tree unmodified.
+ * @throw ini_parser_error In case of error deserializing the property tree.
+ * @param filename Name of file from which to read in the property tree.
+ * @param[out] pt The property tree to populate.
+ * @param loc The locale to use when reading in the file contents.
+ */
+ template<class Ptree>
+ void read_ini(const std::string &filename,
+ Ptree &pt,
+ const std::locale &loc = std::locale())
+ {
+ std::basic_ifstream<typename Ptree::key_type::value_type>
+ stream(filename.c_str());
+ if (!stream)
+ BOOST_PROPERTY_TREE_THROW(ini_parser_error(
+ "cannot open file", filename, 0));
+ stream.imbue(loc);
+ try {
+ read_ini(stream, pt);
+ }
+ catch (ini_parser_error &e) {
+ BOOST_PROPERTY_TREE_THROW(ini_parser_error(
+ e.message(), filename, e.line()));
+ }
+ }
+
+ namespace detail
+ {
+ template<class Ptree>
+ void check_dupes(const Ptree &pt)
+ {
+ if(pt.size() <= 1)
+ return;
+ const typename Ptree::key_type *lastkey = 0;
+ typename Ptree::const_assoc_iterator it = pt.ordered_begin(),
+ end = pt.not_found();
+ lastkey = &it->first;
+ for(++it; it != end; ++it) {
+ if(*lastkey == it->first)
+ BOOST_PROPERTY_TREE_THROW(ini_parser_error(
+ "duplicate key", "", 0));
+ lastkey = &it->first;
+ }
+ }
+
+ template <typename Ptree>
+ void write_keys(std::basic_ostream<
+ typename Ptree::key_type::value_type
+ > &stream,
+ const Ptree& pt,
+ bool throw_on_children)
+ {
+ typedef typename Ptree::key_type::value_type Ch;
+ for (typename Ptree::const_iterator it = pt.begin(), end = pt.end();
+ it != end; ++it)
+ {
+ if (!it->second.empty()) {
+ if (throw_on_children) {
+ BOOST_PROPERTY_TREE_THROW(ini_parser_error(
+ "ptree is too deep", "", 0));
+ }
+ continue;
+ }
+ stream << it->first << Ch('=')
+ << it->second.template get_value<
+ std::basic_string<Ch> >()
+ << Ch('\n');
+ }
+ }
+
+ template <typename Ptree>
+ void write_top_level_keys(std::basic_ostream<
+ typename Ptree::key_type::value_type
+ > &stream,
+ const Ptree& pt)
+ {
+ write_keys(stream, pt, false);
+ }
+
+ template <typename Ptree>
+ void write_sections(std::basic_ostream<
+ typename Ptree::key_type::value_type
+ > &stream,
+ const Ptree& pt)
+ {
+ typedef typename Ptree::key_type::value_type Ch;
+ for (typename Ptree::const_iterator it = pt.begin(), end = pt.end();
+ it != end; ++it)
+ {
+ if (!it->second.empty()) {
+ check_dupes(it->second);
+ if (!it->second.data().empty())
+ BOOST_PROPERTY_TREE_THROW(ini_parser_error(
+ "mixed data and children", "", 0));
+ stream << Ch('[') << it->first << Ch(']') << Ch('\n');
+ write_keys(stream, it->second, true);
+ }
+ }
+ }
+ }
+
+ /**
+ * Translates the property tree to INI and writes it the given output
+ * stream.
+ * @pre @e pt cannot have data in its root.
+ * @pre @e pt cannot have keys both data and children.
+ * @pre @e pt cannot be deeper than two levels.
+ * @pre There cannot be duplicate keys on any given level of @e pt.
+ * @throw ini_parser_error In case of error translating the property tree to
+ * INI or writing to the output stream.
+ * @param stream The stream to which to write the INI representation of the
+ * property tree.
+ * @param pt The property tree to tranlsate to INI and output.
+ * @param flags The flags to use when writing the INI file.
+ * No flags are currently supported.
+ */
+ template<class Ptree>
+ void write_ini(std::basic_ostream<
+ typename Ptree::key_type::value_type
+ > &stream,
+ const Ptree &pt,
+ int flags = 0)
+ {
+ BOOST_ASSERT(validate_flags(flags));
+ (void)flags;
+
+ if (!pt.data().empty())
+ BOOST_PROPERTY_TREE_THROW(ini_parser_error(
+ "ptree has data on root", "", 0));
+ detail::check_dupes(pt);
+
+ detail::write_top_level_keys(stream, pt);
+ detail::write_sections(stream, pt);
+ }
+
+ /**
+ * Translates the property tree to INI and writes it the given file.
+ * @pre @e pt cannot have data in its root.
+ * @pre @e pt cannot have keys both data and children.
+ * @pre @e pt cannot be deeper than two levels.
+ * @pre There cannot be duplicate keys on any given level of @e pt.
+ * @throw info_parser_error In case of error translating the property tree
+ * to INI or writing to the file.
+ * @param filename The name of the file to which to write the INI
+ * representation of the property tree.
+ * @param pt The property tree to tranlsate to INI and output.
+ * @param flags The flags to use when writing the INI file.
+ * The following flags are supported:
+ * @li @c skip_ini_validity_check -- Skip check if ptree is a valid ini. The
+ * validity check covers the preconditions but takes <tt>O(n log n)</tt>
+ * time.
+ * @param loc The locale to use when writing the file.
+ */
+ template<class Ptree>
+ void write_ini(const std::string &filename,
+ const Ptree &pt,
+ int flags = 0,
+ const std::locale &loc = std::locale())
+ {
+ std::basic_ofstream<typename Ptree::key_type::value_type>
+ stream(filename.c_str());
+ if (!stream)
+ BOOST_PROPERTY_TREE_THROW(ini_parser_error(
+ "cannot open file", filename, 0));
+ stream.imbue(loc);
+ try {
+ write_ini(stream, pt, flags);
+ }
+ catch (ini_parser_error &e) {
+ BOOST_PROPERTY_TREE_THROW(ini_parser_error(
+ e.message(), filename, e.line()));
+ }
+ }
+
+} } }
+
+namespace boost { namespace property_tree
+{
+ using ini_parser::ini_parser_error;
+ using ini_parser::read_ini;
+ using ini_parser::write_ini;
+} }
+
+#endif