aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAvatar Ciaran McCreesh <ciaran.mccreesh@googlemail.com> 2006-08-22 15:58:07 +0000
committerAvatar Ciaran McCreesh <ciaran.mccreesh@googlemail.com> 2006-08-22 15:58:07 +0000
commitbb41a967452c70c32b24949b04c11e5a59f12002 (patch)
treec20ed7c302133d972d754cd602e76701e76bef28
parentfbd090f070e0d2e36bf93405e48ed7ae753c481d (diff)
downloadpaludis-bb41a967452c70c32b24949b04c11e5a59f12002.tar.gz
paludis-bb41a967452c70c32b24949b04c11e5a59f12002.tar.xz
Allow (with a warning) line continuations inside quoted strings without backslashes for KeyValueConfigFile
-rw-r--r--paludis/config_file.cc76
-rw-r--r--paludis/config_file.hh11
-rw-r--r--paludis/config_file_TEST.cc25
3 files changed, 105 insertions, 7 deletions
diff --git a/paludis/config_file.cc b/paludis/config_file.cc
index b6cdd1c..31fd963 100644
--- a/paludis/config_file.cc
+++ b/paludis/config_file.cc
@@ -135,6 +135,12 @@ ConfigFile::need_lines() const
throw ConfigFileError("Line-continuation needs a continuation.");
_has_lines = true;
+ done_reading_lines();
+}
+
+void
+ConfigFile::done_reading_lines() const
+{
}
void
@@ -226,6 +232,8 @@ namespace paludis
InternalCounted<Implementation<KeyValueConfigFile> >
{
mutable std::map<std::string, std::string> entries;
+ mutable std::string accum;
+ mutable std::string accum_key;
};
}
@@ -284,18 +292,54 @@ KeyValueConfigFile::~KeyValueConfigFile()
void
KeyValueConfigFile::accept_line(const std::string & line) const
{
- std::string::size_type p(line.find('='));
- if (std::string::npos == p)
- _imp->entries[line] = "";
- else
+ if (! _imp->accum.empty())
{
- std::string key(line.substr(0, p)), value(line.substr(p + 1));
- normalise_line(key);
+ std::string value(line);
normalise_line(value);
- _imp->entries[key] = replace_variables(strip_quotes(value));
+
+ if (value.empty())
+ return;
+
+ _imp->accum += " ";
+ _imp->accum += value;
+
+ if (value.at(value.length() - 1) == _imp->accum.at(0))
+ {
+ _imp->entries[_imp->accum_key] = replace_variables(strip_quotes(_imp->accum));
+ _imp->accum.clear();
+ _imp->accum_key.clear();
+ }
+ }
+ else
+ {
+ std::string::size_type p(line.find('='));
+ if (std::string::npos == p)
+ _imp->entries[line] = "";
+ else
+ {
+ std::string key(line.substr(0, p)), value(line.substr(p + 1));
+ normalise_line(key);
+ normalise_line(value);
+ if (quotes_are_balanced(value))
+ _imp->entries[key] = replace_variables(strip_quotes(value));
+ else
+ {
+ Log::get_instance()->message(ll_warning, lc_context, "Line continuations should "
+ "be indicated with a backslash");
+ _imp->accum = value;
+ _imp->accum_key = key;
+ }
+ }
}
}
+void
+KeyValueConfigFile::done_reading_lines() const
+{
+ if (! _imp->accum.empty())
+ throw KeyValueConfigFileError("Unterminated multiline quoted string");
+}
+
std::string
KeyValueConfigFile::replace_variables(const std::string & s) const
{
@@ -371,6 +415,24 @@ KeyValueConfigFile::strip_quotes(const std::string & s) const
return s;
}
+bool
+KeyValueConfigFile::quotes_are_balanced(const std::string & s) const
+{
+ if (s.empty())
+ return false;
+
+ if (std::string::npos != std::string("'\"").find(s[0]))
+ {
+ if (s.length() < 2)
+ return false;
+ if (s[s.length() - 1] != s[0])
+ return false;
+ return true;
+ }
+ else
+ return true;
+}
+
KeyValueConfigFile::Iterator
KeyValueConfigFile::begin() const
{
diff --git a/paludis/config_file.hh b/paludis/config_file.hh
index d04fa36..89e615c 100644
--- a/paludis/config_file.hh
+++ b/paludis/config_file.hh
@@ -99,6 +99,12 @@ namespace paludis
virtual void accept_line(const std::string &) const = 0;
/**
+ * Called when we've read in all our lines. By default, does
+ * nothing. Can be used for further validation.
+ */
+ virtual void done_reading_lines() const;
+
+ /**
* If we have not done so already, read in our lines.
*/
void need_lines() const;
@@ -217,6 +223,9 @@ namespace paludis
protected ConfigFile,
private PrivateImplementationPattern<KeyValueConfigFile>
{
+ private:
+ bool quotes_are_balanced(const std::string &) const;
+
protected:
void accept_line(const std::string &) const;
@@ -230,6 +239,8 @@ namespace paludis
*/
std::string strip_quotes(const std::string &) const;
+ virtual void done_reading_lines() const;
+
public:
///\name Basic operations
///\{
diff --git a/paludis/config_file_TEST.cc b/paludis/config_file_TEST.cc
index 02ae9e1..a2bf2d0 100644
--- a/paludis/config_file_TEST.cc
+++ b/paludis/config_file_TEST.cc
@@ -214,6 +214,27 @@ namespace test_cases
} test_key_value_config_file;
/**
+ * \test Test KeyValueConfigFile continuations.
+ *
+ * \ingroup grptestcases
+ */
+ struct KeyValueConfigFileContinuationsTest : TestCase
+ {
+ KeyValueConfigFileContinuationsTest() : TestCase("key value config file continuations") { }
+
+ void run()
+ {
+ std::stringstream s;
+ s << "one='first" << std::endl;
+ s << " first " << std::endl;
+ s << "first'" << std::endl;
+ KeyValueConfigFile ff(&s);
+
+ TEST_CHECK_EQUAL(ff.get("one"), "first first first");
+ }
+ } test_key_value_config_file_continuations;
+
+ /**
* \test Test KeyValueConfigFile variables.
*
* \ingroup grptestcases
@@ -301,6 +322,10 @@ namespace test_cases
std::stringstream s8;
s8 << "x=blah \\" << std::endl << "# foo" << std::endl;
TEST_CHECK_THROWS(KeyValueConfigFile ff(&s8), ConfigurationError);
+
+ std::stringstream s9;
+ s9 << "x='blah" << std::endl << "blah" << std::endl;
+ TEST_CHECK_THROWS(KeyValueConfigFile ff(&s9), ConfigurationError);
}
} test_key_value_config_file_errors;
}