Boost logo

Boost-Commit :

Subject: [Boost-commit] svn:boost r55964 - in branches/sredl_2009_05_proptree_update: boost/property_tree boost/property_tree/detail libs/property_tree/test
From: sebastian.redl_at_[hidden]
Date: 2009-09-01 16:52:25


Author: cornedbee
Date: 2009-09-01 16:52:24 EDT (Tue, 01 Sep 2009)
New Revision: 55964
URL: http://svn.boost.org/trac/boost/changeset/55964

Log:
Repair INI parser.
Text files modified:
   branches/sredl_2009_05_proptree_update/boost/property_tree/detail/ptree_implementation.hpp | 14 +++++
   branches/sredl_2009_05_proptree_update/boost/property_tree/ini_parser.hpp | 99 ++++++++++++++++++++++++---------------
   branches/sredl_2009_05_proptree_update/boost/property_tree/ptree.hpp | 5 ++
   branches/sredl_2009_05_proptree_update/libs/property_tree/test/Jamfile.v2 | 2
   branches/sredl_2009_05_proptree_update/libs/property_tree/test/test_ini_parser.cpp | 47 +++++++++---------
   5 files changed, 104 insertions(+), 63 deletions(-)

Modified: branches/sredl_2009_05_proptree_update/boost/property_tree/detail/ptree_implementation.hpp
==============================================================================
--- branches/sredl_2009_05_proptree_update/boost/property_tree/detail/ptree_implementation.hpp (original)
+++ branches/sredl_2009_05_proptree_update/boost/property_tree/detail/ptree_implementation.hpp 2009-09-01 16:52:24 EDT (Tue, 01 Sep 2009)
@@ -388,6 +388,20 @@
 
     template<class K, class D, class C> inline
     typename basic_ptree<K, D, C>::assoc_iterator
+ basic_ptree<K, D, C>::ordered_begin()
+ {
+ return assoc_iterator(subs::assoc(this).begin());
+ }
+
+ template<class K, class D, class C> inline
+ typename basic_ptree<K, D, C>::const_assoc_iterator
+ basic_ptree<K, D, C>::ordered_begin() const
+ {
+ return const_assoc_iterator(subs::assoc(this).begin());
+ }
+
+ template<class K, class D, class C> inline
+ typename basic_ptree<K, D, C>::assoc_iterator
         basic_ptree<K, D, C>::not_found()
     {
         return assoc_iterator(subs::assoc(this).end());

Modified: branches/sredl_2009_05_proptree_update/boost/property_tree/ini_parser.hpp
==============================================================================
--- branches/sredl_2009_05_proptree_update/boost/property_tree/ini_parser.hpp (original)
+++ branches/sredl_2009_05_proptree_update/boost/property_tree/ini_parser.hpp 2009-09-01 16:52:24 EDT (Tue, 01 Sep 2009)
@@ -22,9 +22,6 @@
 namespace boost { namespace property_tree { namespace ini_parser
 {
 
- /** Skip check if ptree is a valid ini */
- static const int skip_ini_validity_check = 1;
-
     /**
      * 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.
@@ -32,7 +29,7 @@
      */
     inline bool validate_flags(int flags)
     {
- return (flags & ~skip_ini_validity_check) == 0;
+ return flags == 0;
     }
 
     /** Indicates an error parsing INI formatted data. */
@@ -101,13 +98,16 @@
                 }
                 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 = detail::trim(line.substr(1, end - 1),
                                            stream.getloc());
- if (local.find(key) != local.end())
+ if (local.find(key) != local.not_found())
                         BOOST_PROPERTY_TREE_THROW(ini_parser_error(
                             "duplicate section name", "", line_no));
                     section = &local.push_back(
@@ -127,13 +127,16 @@
                                            stream.getloc());
                     Str data = detail::trim(line.substr(eqpos + 1, Str::npos),
                                             stream.getloc());
- if (container.find(key) != container.end())
+ 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);
@@ -169,11 +172,32 @@
         }
     }
 
+ 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;
+ }
+ }
+ }
+
     /**
      * Translates the property tree to INI and writes it the given output
      * stream.
- * @pre @e pt cannot have keys with data at its root level.
- * @pre @e pt cannot be deaper than two levels.
+ * @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.
@@ -181,10 +205,7 @@
      * 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.
+ * No flags are currently supported.
      */
     template<class Ptree>
     void write_ini(std::basic_ostream<
@@ -193,54 +214,54 @@
                    const Ptree &pt,
                    int flags = 0)
     {
+ using detail::check_dupes;
 
         typedef typename Ptree::key_type::value_type Ch;
         typedef std::basic_string<Ch> Str;
 
         BOOST_ASSERT(validate_flags(flags));
+ (void)flags;
 
- // Verify if ptree is not too rich to be saved as ini
- if (!(flags & skip_ini_validity_check)) {
- for (typename Ptree::const_iterator it = pt.begin(), end = pt.end();
- it != end; ++it)
- {
+ if (!pt.data().empty())
+ BOOST_PROPERTY_TREE_THROW(ini_parser_error(
+ "ptree has data on root", "", 0));
+ check_dupes(pt);
+
+ for (typename Ptree::const_iterator it = pt.begin(), end = pt.end();
+ it != end; ++it)
+ {
+ check_dupes(it->second);
+ if (it->second.empty()) {
+ stream << it->first << Ch('=')
+ << it->second.template get_value<
+ std::basic_string<Ch> >()
+ << Ch('\n');
+ } else {
                 if (!it->second.data().empty())
                     BOOST_PROPERTY_TREE_THROW(ini_parser_error(
- "ptree has data on root level keys", "", 0));
- if (pt.count(it->first) > 1)
- BOOST_PROPERTY_TREE_THROW(ini_parser_error(
- "duplicate section name", "", 0));
+ "mixed data and children", "", 0));
+ stream << Ch('[') << it->first << Ch(']') << Ch('\n');
                 for (typename Ptree::const_iterator it2 = it->second.begin(),
- end2 = it->second.end(); it2 != end2; ++it2)
+ end2 = it->second.end(); it2 != end2; ++it2)
                 {
                     if (!it2->second.empty())
                         BOOST_PROPERTY_TREE_THROW(ini_parser_error(
                             "ptree is too deep", "", 0));
- if (it->second.count(it2->first) > 1)
- BOOST_PROPERTY_TREE_THROW(ini_parser_error(
- "duplicate key name", "", 0));
+ stream << it2->first << Ch('=')
+ << it2->second.template get_value<
+ std::basic_string<Ch> >()
+ << Ch('\n');
                 }
             }
         }
 
- // Write ini
- for (typename Ptree::const_iterator it = pt.begin(), end = pt.end();
- it != end; ++it)
- {
- stream << Ch('[') << it->first << Ch(']') << Ch('\n');
- for (typename Ptree::const_iterator it2 = it->second.begin(),
- end2 = it->second.end(); it2 != end2; ++it2)
- stream << it2->first << Ch('=')
- << it2->second.template get_value<std::basic_string<Ch> >()
- << Ch('\n');
- }
-
     }
 
     /**
      * Translates the property tree to INI and writes it the given file.
- * @pre @e pt cannot have keys with data at its root level.
- * @pre @e pt cannot be deaper than two levels.
+ * @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.

Modified: branches/sredl_2009_05_proptree_update/boost/property_tree/ptree.hpp
==============================================================================
--- branches/sredl_2009_05_proptree_update/boost/property_tree/ptree.hpp (original)
+++ branches/sredl_2009_05_proptree_update/boost/property_tree/ptree.hpp 2009-09-01 16:52:24 EDT (Tue, 01 Sep 2009)
@@ -181,6 +181,11 @@
 
         // Associative view
 
+ /** Returns an iterator to the first child, in order. */
+ assoc_iterator ordered_begin();
+ /** Returns an iterator to the first child, in order. */
+ const_assoc_iterator ordered_begin() const;
+
         /** Returns the not-found iterator. Equivalent to end() in a real
          * associative container.
          */

Modified: branches/sredl_2009_05_proptree_update/libs/property_tree/test/Jamfile.v2
==============================================================================
--- branches/sredl_2009_05_proptree_update/libs/property_tree/test/Jamfile.v2 (original)
+++ branches/sredl_2009_05_proptree_update/libs/property_tree/test/Jamfile.v2 2009-09-01 16:52:24 EDT (Tue, 01 Sep 2009)
@@ -5,7 +5,7 @@
    : [ run test_property_tree.cpp /boost/serialization//boost_serialization ]
      [ run test_info_parser.cpp ]
      [ run test_json_parser.cpp ]
- #[ run test_ini_parser.cpp ] INI parser currently not working as expected
+ [ run test_ini_parser.cpp ]
      [ run test_xml_parser_rapidxml.cpp ]
 
      # danieljames: The following tests were previously missing.

Modified: branches/sredl_2009_05_proptree_update/libs/property_tree/test/test_ini_parser.cpp
==============================================================================
--- branches/sredl_2009_05_proptree_update/libs/property_tree/test/test_ini_parser.cpp (original)
+++ branches/sredl_2009_05_proptree_update/libs/property_tree/test/test_ini_parser.cpp 2009-09-01 16:52:24 EDT (Tue, 01 Sep 2009)
@@ -27,8 +27,7 @@
     "Key 3 = Data 3 \n"
     "Key4=Data4\n"
     "[Section2] ;Comment\n"
- "\t \t; Comment\n"
- " \t [ Section 3 ];Comment \n";
+ "\t \tKey1=Data4\n";
 
 // Correct data
 const char *ok_data_2 =
@@ -43,6 +42,11 @@
 const char *ok_data_4 =
     ";Comment";
 
+// Correct data
+const char *ok_data_5 =
+ "Key1=Data1\n" // No section
+ "Key2=Data2\n";
+
 // Erroneous data
 const char *error_data_1 =
     "[Section1]\n"
@@ -51,11 +55,6 @@
 
 // Erroneous data
 const char *error_data_2 =
- "Key1=Data1\n" // No section
- "Key2=Data2\n";
-
-// Erroneous data
-const char *error_data_3 =
     "[Section1]\n"
     "Key1=Data1\n"
     "=Data2\n"; // No key
@@ -106,7 +105,7 @@
     generic_parser_test_ok<Ptree, ReadFunc, WriteFunc>
     (
         ReadFunc(), WriteFunc(), ok_data_1, NULL,
- "testok1.ini", NULL, "testok1out.ini", 8, 21, 42
+ "testok1.ini", NULL, "testok1out.ini", 8, 26, 37
     );
     
     generic_parser_test_ok<Ptree, ReadFunc, WriteFunc>
@@ -127,22 +126,22 @@
         "testok4.ini", NULL, "testok4out.ini", 1, 0, 0
     );
 
- generic_parser_test_error<Ptree, ReadFunc, WriteFunc, ini_parser_error>
+ generic_parser_test_ok<Ptree, ReadFunc, WriteFunc>
     (
- ReadFunc(), WriteFunc(), error_data_1, NULL,
- "testerr1.ini", NULL, "testerr1out.ini", 2
+ ReadFunc(), WriteFunc(), ok_data_5, NULL,
+ "testok5.ini", NULL, "testok5out.ini", 3, 10, 8
     );
 
     generic_parser_test_error<Ptree, ReadFunc, WriteFunc, ini_parser_error>
     (
- ReadFunc(), WriteFunc(), error_data_2, NULL,
- "testerr2.ini", NULL, "testerr2out.ini", 1
+ ReadFunc(), WriteFunc(), error_data_1, NULL,
+ "testerr1.ini", NULL, "testerr1out.ini", 2
     );
 
     generic_parser_test_error<Ptree, ReadFunc, WriteFunc, ini_parser_error>
     (
- ReadFunc(), WriteFunc(), error_data_3, NULL,
- "testerr3.ini", NULL, "testerr3out.ini", 3
+ ReadFunc(), WriteFunc(), error_data_2, NULL,
+ "testerr2.ini", NULL, "testerr2out.ini", 3
     );
 
 }
@@ -165,29 +164,31 @@
     // Test too deep ptrees
     {
         ptree pt;
- pt.put_child("section.key.bogus", empty_ptree<ptree>());
+ pt.put_child("section.key.bogus", ptree());
         test_erroneous_write(pt);
     }
 
- // Test data in sections
+ // Test duplicate sections
     {
         ptree pt;
- pt.put("section", 1);
+ pt.push_back(std::make_pair("section", ptree()));
+ pt.push_back(std::make_pair("section", ptree()));
         test_erroneous_write(pt);
     }
 
- // Test duplicate sections
+ // Test duplicate keys
     {
         ptree pt;
- pt.push_back(std::make_pair("section", ptree()));
- pt.push_back(std::make_pair("section", ptree()));
+ ptree &child = pt.put_child("section", ptree());
+ child.push_back(std::make_pair("key", ptree()));
+ child.push_back(std::make_pair("key", ptree()));
         test_erroneous_write(pt);
     }
 
- // Test duplicate keys
+ // Test mixed data and children.
     {
         ptree pt;
- ptree &child = pt.put_child("section", empty_ptree<ptree>());
+ ptree &child = pt.put_child("section", ptree("value"));
         child.push_back(std::make_pair("key", ptree()));
         child.push_back(std::make_pair("key", ptree()));
         test_erroneous_write(pt);


Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk