|
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