aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAvatar Ciaran McCreesh <ciaran.mccreesh@googlemail.com> 2007-03-04 11:58:35 +0000
committerAvatar Ciaran McCreesh <ciaran.mccreesh@googlemail.com> 2007-03-04 11:58:35 +0000
commit373ad6796f4d74e3ae8a580957097f4164c4ddeb (patch)
tree6cfead78c35d0b9bf7ec54e6100a866f052cc6a1
parentca4cc9bc1667b31c5504c816527d21e936433fd5 (diff)
downloadpaludis-373ad6796f4d74e3ae8a580957097f4164c4ddeb.tar.gz
paludis-373ad6796f4d74e3ae8a580957097f4164c4ddeb.tar.xz
New ConfigFile implementation
-rw-r--r--paludis/config_file.cc702
-rw-r--r--paludis/config_file.hh288
-rw-r--r--paludis/config_file_TEST.cc113
-rw-r--r--paludis/environments/paludis/paludis_config.cc2
-rw-r--r--paludis/repositories/gentoo/ebuild.cc2
-rwxr-xr-xpaludis/repositories/gentoo/ebuild/ebuild.bash4
-rw-r--r--paludis/repositories/gentoo/portage_repository_news.cc35
-rw-r--r--paludis/repositories/gentoo/portage_repository_news.hh4
8 files changed, 549 insertions, 601 deletions
diff --git a/paludis/config_file.cc b/paludis/config_file.cc
index 7b60aa5..5da302c 100644
--- a/paludis/config_file.cc
+++ b/paludis/config_file.cc
@@ -39,165 +39,141 @@
using namespace paludis;
-ConfigFileError::ConfigFileError(const std::string & our_message) throw () :
- ConfigurationError("Config file error: " + our_message)
+ConfigFileError::ConfigFileError(const std::string & f, const std::string & m) throw () :
+ ConfigurationError("Configuration file error: " + (f.empty() ? m : f + ": " + m))
{
}
-ConfigFile::ConfigFile(std::istream * const stream) :
- _stream(stream),
- _has_lines(false),
- _destroy_stream(false)
+ConfigFileError::ConfigFileError(const std::string & m) throw () :
+ ConfigurationError("Configuration file error: " + m)
{
}
-ConfigFile::ConfigFile(const std::string & our_filename) try :
- _stream(_make_stream(our_filename)),
- _has_lines(false),
- _filename(our_filename),
- _destroy_stream(true)
+ConfigFile::ConfigFile(const Source &)
{
}
-catch (...)
-{
- _destroy_stream = false;
- throw;
-}
-
-ConfigFile::ConfigFile(const FSEntry & our_filename) try :
- _stream(_make_stream(stringify(our_filename))),
- _has_lines(false),
- _filename(stringify(our_filename)),
- _destroy_stream(true)
-{
-}
-catch (...)
-{
- _destroy_stream = false;
- throw;
-}
ConfigFile::~ConfigFile()
{
- if (_stream && _destroy_stream)
- delete _stream;
}
-std::istream *
-ConfigFile::_make_stream(const std::string & filename)
+namespace paludis
{
- Context context("When creating the filestream for a ConfigFile from file '" + filename + "':");
-
- std::ifstream * result(new std::ifstream(filename.c_str()));
- if (! *result)
+ template<>
+ struct Implementation<ConfigFile::Source>
{
- delete result;
- throw ConfigFileError("Could not open '" + filename + "'");
- }
+ std::tr1::shared_ptr<std::istream> stream_to_delete;
+ std::istream & stream;
+ std::string filename;
- return result;
-}
-
-void
-ConfigFile::need_lines() const
-{
- if (_has_lines)
- return;
-
- std::string line, accum;
- unsigned line_number(0);
- while (std::getline(*_stream, line))
- {
- Context c("When handling line " + stringify(++line_number) +
- (_filename.empty() ? std::string(":") : " in file '" + _filename + "':"));
- normalise_line(line);
+ Implementation(std::istream & s) :
+ stream(s)
+ {
+ }
- if (line.empty() || skip_line(line))
+ Implementation(const FSEntry & f) :
+ stream_to_delete(new std::ifstream(stringify(f).c_str())),
+ stream(*stream_to_delete),
+ filename(stringify(f))
{
- if (!accum.empty())
- throw ConfigFileError("Line-continuation followed by a blank line or comment is invalid.");
+ }
- continue;
+ Implementation(const std::string & s) :
+ stream_to_delete(new std::ifstream(s.c_str())),
+ stream(*stream_to_delete),
+ filename(s)
+ {
}
- if ('\\' == line.at(line.length() - 1))
+
+ Implementation(std::tr1::shared_ptr<std::istream> s, std::istream & t, const std::string & f) :
+ stream_to_delete(s),
+ stream(t),
+ filename(f)
{
- line.erase(line.length() - 1);
- accum += line;
- continue;
}
+ };
+}
- accept_line(accum + line);
- accum.clear();
- }
- if (! _stream->eof())
- throw ConfigFileError("Error reading from file");
- if (! accum.empty())
- throw ConfigFileError("Line-continuation needs a continuation.");
+ConfigFile::Source::Source(const FSEntry & f) :
+ PrivateImplementationPattern<ConfigFile::Source>(new Implementation<ConfigFile::Source>(f))
+{
+}
+
+ConfigFile::Source::Source(const std::string & s) :
+ PrivateImplementationPattern<ConfigFile::Source>(new Implementation<ConfigFile::Source>(s))
+{
+}
+
+ConfigFile::Source::Source(std::istream & s) :
+ PrivateImplementationPattern<ConfigFile::Source>(new Implementation<ConfigFile::Source>(s))
+{
+}
- _has_lines = true;
- done_reading_lines();
+ConfigFile::Source::Source(const Source & s) :
+ PrivateImplementationPattern<ConfigFile::Source>(new Implementation<ConfigFile::Source>(
+ s._imp->stream_to_delete, s._imp->stream, s._imp->filename))
+{
+}
+
+const ConfigFile::Source &
+ConfigFile::Source::operator= (const Source & s)
+{
+ if (&s != this)
+ _imp.reset(new Implementation<ConfigFile::Source>(s._imp->stream_to_delete, s._imp->stream, s._imp->filename));
+ return *this;
}
-void
-ConfigFile::done_reading_lines() const
+ConfigFile::Source::~Source()
{
}
-void
-ConfigFile::normalise_line(std::string & s) const
+std::istream &
+ConfigFile::Source::stream() const
{
- s = strip_leading(strip_trailing(s, " \t\n"), " \t\n");
+ return _imp->stream;
}
-bool
-ConfigFile::skip_line(const std::string & s) const
+std::string
+ConfigFile::Source::filename() const
{
- return (s.empty() || '#' == s.at(0));
+ return _imp->filename;
}
namespace paludis
{
- /**
- * Implementation data for LineConfigFile.
- *
- * \ingroup grplineconfigfile
- */
template<>
struct Implementation<LineConfigFile>
{
- mutable std::list<std::string> lines;
+ std::list<std::string> lines;
};
}
-LineConfigFile::LineConfigFile(std::istream * const s) :
+LineConfigFile::LineConfigFile(const Source & s) :
ConfigFile(s),
PrivateImplementationPattern<LineConfigFile>(new Implementation<LineConfigFile>)
{
- need_lines();
-}
+ Context context("When parsing line configuration file" + (s.filename().empty() ? ":" :
+ "'" + s.filename() + "':"));
-LineConfigFile::LineConfigFile(const std::string & our_filename) :
- ConfigFile(our_filename),
- PrivateImplementationPattern<LineConfigFile>(new Implementation<LineConfigFile>)
-{
- need_lines();
-}
+ if (! s.stream())
+ throw ConfigFileError(s.filename(), "Cannot read input");
-LineConfigFile::LineConfigFile(const FSEntry & our_filename) :
- ConfigFile(our_filename),
- PrivateImplementationPattern<LineConfigFile>(new Implementation<LineConfigFile>)
-{
- need_lines();
-}
+ std::string line;
+ while (std::getline(s.stream(), line))
+ {
+ line = strip_leading(strip_trailing(line, " \t\r\n"), " \t\r\n");
+ if (line.empty())
+ continue;
-LineConfigFile::~LineConfigFile()
-{
+ if ('#' == line.at(0))
+ continue;
+
+ _imp->lines.push_back(line);
+ }
}
-void
-LineConfigFile::accept_line(const std::string & s) const
+LineConfigFile::~LineConfigFile()
{
- _imp->lines.push_back(s);
}
LineConfigFile::Iterator
@@ -212,240 +188,440 @@ LineConfigFile::end() const
return Iterator(_imp->lines.end());
}
-KeyValueConfigFileError::KeyValueConfigFileError(const std::string & msg,
- const std::string & filename) throw () :
- ConfigurationError("Key/Value config file error" +
- (filename.empty() ? ": " : " in file '" + filename + "': ") + msg)
-{
-}
-
namespace paludis
{
- /**
- * Implementation data for KeyValueConfigFile.
- *
- * \ingroup grpkvconfigfile
- */
- template <>
- struct Implementation<KeyValueConfigFile>
+ template<>
+ struct Implementation<KeyValueConfigFile::Defaults>
{
- mutable std::map<std::string, std::string> entries;
- mutable std::string accum;
- mutable std::string accum_key;
+ std::tr1::shared_ptr<const KeyValueConfigFile> kv;
+ std::tr1::shared_ptr<const AssociativeCollection<std::string, std::string> > a;
+ std::string (* f)(const std::string &, const std::string &);
+
+ Implementation(std::tr1::shared_ptr<const KeyValueConfigFile> kvv,
+ std::tr1::shared_ptr<const AssociativeCollection<std::string, std::string> > av,
+ std::string (* fv)(const std::string &, const std::string &)) :
+ kv(kvv),
+ a(av),
+ f(fv)
+ {
+ }
};
}
-KeyValueConfigFile::KeyValueConfigFile(std::istream * const s) :
- ConfigFile(s),
- PrivateImplementationPattern<KeyValueConfigFile>(new Implementation<KeyValueConfigFile>)
+template<>
+KeyValueConfigFile::Defaults::Defaults(std::tr1::shared_ptr<const KeyValueConfigFile> v) :
+ PrivateImplementationPattern<KeyValueConfigFile::Defaults>(new Implementation<KeyValueConfigFile::Defaults>(v,
+ std::tr1::shared_ptr<const AssociativeCollection<std::string, std::string> >(), 0))
{
- need_lines();
}
-KeyValueConfigFile::KeyValueConfigFile(const std::string & our_filename) :
- ConfigFile(our_filename),
- PrivateImplementationPattern<KeyValueConfigFile>(new Implementation<KeyValueConfigFile>)
+template<>
+KeyValueConfigFile::Defaults::Defaults(std::tr1::shared_ptr<const AssociativeCollection<std::string, std::string> > a) :
+ PrivateImplementationPattern<KeyValueConfigFile::Defaults>(new Implementation<KeyValueConfigFile::Defaults>(
+ std::tr1::shared_ptr<const KeyValueConfigFile>(), a, 0))
{
- need_lines();
}
-KeyValueConfigFile::KeyValueConfigFile(const FSEntry & our_filename) :
- ConfigFile(our_filename),
- PrivateImplementationPattern<KeyValueConfigFile>(new Implementation<KeyValueConfigFile>)
+template<>
+KeyValueConfigFile::Defaults::Defaults(std::tr1::shared_ptr<KeyValueConfigFile> v) :
+ PrivateImplementationPattern<KeyValueConfigFile::Defaults>(new Implementation<KeyValueConfigFile::Defaults>(v,
+ std::tr1::shared_ptr<const AssociativeCollection<std::string, std::string> >(), 0))
{
- need_lines();
}
-KeyValueConfigFile::KeyValueConfigFile(std::istream * const s,
- std::tr1::shared_ptr<const AssociativeCollection<std::string, std::string> > m) :
- ConfigFile(s),
- PrivateImplementationPattern<KeyValueConfigFile>(new Implementation<KeyValueConfigFile>)
+template<>
+KeyValueConfigFile::Defaults::Defaults(std::tr1::shared_ptr<AssociativeCollection<std::string, std::string> > a) :
+ PrivateImplementationPattern<KeyValueConfigFile::Defaults>(new Implementation<KeyValueConfigFile::Defaults>(
+ std::tr1::shared_ptr<const KeyValueConfigFile>(), a, 0))
{
- _imp->entries.insert(m->begin(), m->end());
- need_lines();
}
-KeyValueConfigFile::KeyValueConfigFile(const std::string & our_filename,
- std::tr1::shared_ptr<const AssociativeCollection<std::string, std::string> > m) :
- ConfigFile(our_filename),
- PrivateImplementationPattern<KeyValueConfigFile>(new Implementation<KeyValueConfigFile>)
+KeyValueConfigFile::Defaults::Defaults(std::string (* f) (const std::string &, const std::string &)) :
+ PrivateImplementationPattern<KeyValueConfigFile::Defaults>(new Implementation<KeyValueConfigFile::Defaults>(
+ std::tr1::shared_ptr<const KeyValueConfigFile>(),
+ std::tr1::shared_ptr<const AssociativeCollection<std::string, std::string> >(), f))
{
- _imp->entries.insert(m->begin(), m->end());
- need_lines();
}
-KeyValueConfigFile::KeyValueConfigFile(const FSEntry & our_filename,
- std::tr1::shared_ptr<const AssociativeCollection<std::string, std::string> > m):
- ConfigFile(our_filename),
- PrivateImplementationPattern<KeyValueConfigFile>(new Implementation<KeyValueConfigFile>)
+KeyValueConfigFile::Defaults::Defaults() :
+ PrivateImplementationPattern<KeyValueConfigFile::Defaults>(new Implementation<KeyValueConfigFile::Defaults>(
+ std::tr1::shared_ptr<const KeyValueConfigFile>(),
+ std::tr1::shared_ptr<const AssociativeCollection<std::string, std::string> >(), 0))
{
- _imp->entries.insert(m->begin(), m->end());
- need_lines();
}
-KeyValueConfigFile::~KeyValueConfigFile()
+KeyValueConfigFile::Defaults::Defaults(const Defaults & v) :
+ PrivateImplementationPattern<KeyValueConfigFile::Defaults>(new Implementation<KeyValueConfigFile::Defaults>(
+ v._imp->kv, v._imp->a, v._imp->f))
{
}
-void
-KeyValueConfigFile::accept_line(const std::string & line) const
+const KeyValueConfigFile::Defaults &
+KeyValueConfigFile::Defaults::operator= (const Defaults & v)
{
- if (! _imp->accum.empty())
- {
- std::string value(line);
- normalise_line(value);
-
- if (value.empty())
- return;
+ if (this != &v)
+ _imp.reset(new Implementation<KeyValueConfigFile::Defaults>(v._imp->kv, v._imp->a, v._imp->f));
+ return *this;
+}
- _imp->accum += " ";
- _imp->accum += value;
+KeyValueConfigFile::Defaults::~Defaults()
+{
+}
- 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();
- }
+std::string
+KeyValueConfigFile::Defaults::get(const std::string & k) const
+{
+ if (_imp->kv)
+ {
+ Log::get_instance()->message(ll_debug, lc_context, "KV defaults get '" + k + "' using kv");
+ return _imp->kv->get(k);
}
- else
+ else if (_imp->a)
{
- std::string::size_type p(line.find('='));
- if (std::string::npos == p)
- _imp->entries[line] = "";
+ Log::get_instance()->message(ll_debug, lc_context, "KV defaults get '" + k + "' using a");
+ AssociativeCollection<std::string, std::string>::Iterator x(_imp->a->find(k));
+ if (x == _imp->a->end())
+ return "";
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;
- }
- }
+ return x->second;
+ }
+ else if (_imp->f)
+ {
+ Log::get_instance()->message(ll_debug, lc_context, "KV defaults get '" + k + "' using f");
+ return (_imp->f)(k, "");
+ }
+ else
+ {
+ Log::get_instance()->message(ll_debug, lc_context, "KV defaults get '" + k + "' using default empty value");
+ return "";
}
}
-void
-KeyValueConfigFile::done_reading_lines() const
+namespace
{
- if (! _imp->accum.empty())
- throw KeyValueConfigFileError("Unterminated multiline quoted string");
+ static std::map<std::string, std::string> empty_map;
}
-std::string
-KeyValueConfigFile::replace_variables(const std::string & s) const
+KeyValueConfigFile::Defaults::Iterator
+KeyValueConfigFile::Defaults::begin() const
+{
+ if (_imp->kv)
+ return Iterator(_imp->kv->begin());
+ else if (_imp->a)
+ return Iterator(_imp->a->begin());
+ else
+ return Iterator(empty_map.begin());
+}
+
+KeyValueConfigFile::Defaults::Iterator
+KeyValueConfigFile::Defaults::end() const
{
- std::string r;
- std::string::size_type p(0), old_p(0);
+ if (_imp->kv)
+ return Iterator(_imp->kv->end());
+ else if (_imp->a)
+ return Iterator(_imp->a->end());
+ else
+ return Iterator(empty_map.end());
+}
- while (p < s.length())
+namespace paludis
+{
+ template<>
+ struct Implementation<KeyValueConfigFile>
{
- old_p = p;
+ KeyValueConfigFile::Defaults defaults;
+ std::map<std::string, std::string> keys;
+ std::string filename;
- if ('\\' == s[p])
+ Implementation(const KeyValueConfigFile::Defaults & d) :
+ defaults(d)
{
- if (++p >= s.length())
- throw KeyValueConfigFileError("Backslash not followed by a character", filename());
- r += s[p++];
}
- else if ('$' != s[p])
- r += s[p++];
- else
+ };
+}
+
+namespace
+{
+ void next_line(std::istreambuf_iterator<char> & c, const std::istreambuf_iterator<char> & c_end)
+ {
+ for ( ; c != c_end ; ++c)
+ if (*c == '\n')
+ break;
+ }
+
+ std::string grab_key(std::istreambuf_iterator<char> & c, const std::istreambuf_iterator<char> & c_end)
+ {
+ std::string result;
+
+ while (c != c_end)
{
- std::string name;
- if (++p >= s.length())
- throw KeyValueConfigFileError("Dollar not followed by a character", filename());
+ if (*c == '\n' || *c == '\r' || *c == ' ' || *c == '\t' || *c == '=' || *c == '$' || *c == '\\'
+ || *c == '"' || *c == '\'')
+ break;
+ else
+ result.append(stringify(*c++));
+ }
- if ('{' == s[p])
- {
- std::string::size_type q;
- if (std::string::npos == ((q = s.find("}", p))))
- throw KeyValueConfigFileError("Closing } not found", filename());
+ return result;
+ }
- name = s.substr(p + 1, q - p - 1);
- p = q + 1;
+ std::string grab_dollar(std::istreambuf_iterator<char> & c, const std::istreambuf_iterator<char> & c_end,
+ const KeyValueConfigFile & d, const std::string & f)
+ {
+ std::string result;
+
+ if (*c == '{')
+ {
+ ++c;
+ while (c != c_end)
+ {
+ if (*c == '}')
+ {
+ ++c;
+ if (result.empty())
+ throw ConfigFileError(f, "Bad empty variable name");
+ return d.get(result);
+ }
+ else if (*c == '\\')
+ {
+ ++c;
+ if (c == c_end)
+ break;
+ if (*c == '\n')
+ ++c;
+ else
+ throw ConfigFileError(f, "Bad \\escape inside ${variable}");
+ }
+ else
+ result.append(stringify(*c++));
}
- else
+
+ throw ConfigFileError(f, "Unterminated ${variable}");
+ }
+ else
+ {
+ while ((*c >= 'a' && *c <= 'z') || (*c >= 'A' && *c <= 'Z')
+ || (*c >= '0' && *c <= '9') || (*c == '_'))
{
- std::string::size_type q;
- if (std::string::npos == ((q = s.find_first_not_of(
- "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
- "abcdefghijklmnopqrstuvwxyz"
- "_0123456789", p))))
- q = s.length();
-
- name = s.substr(p, q - p);
- p = q;
+ result.append(stringify(*c++));
+ if (c == c_end)
+ break;
}
- if (name.empty())
- throw KeyValueConfigFileError("Empty variable name", filename());
- r += get(name);
+ if (result.empty())
+ throw ConfigFileError(f, "Bad empty variable name");
+ return d.get(result);
+ }
+ }
+
+ std::string grab_squoted(std::istreambuf_iterator<char> & c, const std::istreambuf_iterator<char> & c_end,
+ const KeyValueConfigFile &, const std::string & f)
+ {
+ std::string result;
+
+ while (c != c_end)
+ {
+ if (*c == '\\')
+ {
+ if (++c == c_end)
+ throw ConfigFileError(f, "Unterminated 'quoted string ending in a backslash");
+
+ if (*c == '\n')
+ {
+ result.append("\\ ");
+ c++;
+ }
+ else
+ result.append("\\" + stringify(*c++));
+ }
+ else if (*c == '\'')
+ {
+ ++c;
+ return result;
+ }
+ else
+ result.append(stringify(*c++));
}
- if (p <= old_p)
- throw InternalError(PALUDIS_HERE, "Infinite loop");
+ throw ConfigFileError(f, "Unterminated 'quoted string");
}
- return r;
-}
+ std::string grab_dquoted(std::istreambuf_iterator<char> & c, const std::istreambuf_iterator<char> & c_end,
+ const KeyValueConfigFile & d, const std::string & f)
+ {
+ std::string result;
-std::string
-KeyValueConfigFile::strip_quotes(const std::string & s) const
-{
- if (s.empty())
- return s;
- if (std::string::npos != std::string("'\"").find(s[0]))
+ while (c != c_end)
+ {
+ if (*c == '\\')
+ {
+ if (++c == c_end)
+ throw ConfigFileError(f, "Unterminated \"quoted string ending in a backslash");
+
+ if (*c == '\n')
+ ++c;
+ else if (*c == 't')
+ {
+ result.append("\t");
+ ++c;
+ }
+ else if (*c == 'n')
+ {
+ result.append("\n");
+ ++c;
+ }
+ else
+ result.append(stringify(*c++));
+ }
+ else if (*c == '$')
+ result.append(grab_dollar(++c, c_end, d, f));
+ else if (*c == '"')
+ {
+ ++c;
+ return result;
+ }
+ else
+ result.append(stringify(*c++));
+ }
+
+ throw ConfigFileError(f, "Unterminated \"quoted string");
+ }
+
+ std::string grab_value(std::istreambuf_iterator<char> & c, const std::istreambuf_iterator<char> & c_end,
+ const KeyValueConfigFile & d, const std::string & f)
{
- if (s.length() < 2)
- throw KeyValueConfigFileError("Unterminated quote", filename());
- if (s[s.length() - 1] != s[0])
- throw KeyValueConfigFileError("Mismatched quote", filename());
- return s.substr(1, s.length() - 2);
+ std::string result;
+
+ while (c != c_end)
+ {
+ if (*c == '"')
+ result.append(grab_dquoted(++c, c_end, d, f));
+ else if (*c == '\'')
+ result.append(grab_squoted(++c, c_end, d, f));
+ else if (*c == '\\')
+ {
+ if (++c == c_end)
+ throw ConfigFileError(f, "Backslash at end of input");
+
+ if (*c == '\n')
+ {
+ if (++c == c_end)
+ throw ConfigFileError(f, "Backslash at end of input");
+ else if (*c == '#')
+ throw ConfigFileError(f, "Line continuation followed by comment");
+ }
+ else
+ result.append(stringify(*c++));
+ }
+ else if (*c == '$')
+ result.append(grab_dollar(++c, c_end, d, f));
+ else if (*c == '\n')
+ {
+ ++c;
+ break;
+ }
+ else if (*c == '#')
+ {
+ ++c;
+ break;
+ }
+ else
+ result.append(stringify(*c++));
+ }
+
+ return result;
}
- else
- return s;
}
-bool
-KeyValueConfigFile::quotes_are_balanced(const std::string & s) const
+KeyValueConfigFile::KeyValueConfigFile(const Source & s, const Defaults & d) :
+ ConfigFile(s),
+ PrivateImplementationPattern<KeyValueConfigFile>(new Implementation<KeyValueConfigFile>(d))
{
- if (s.empty())
- return true;
+ Context context("When parsing key/value configuration file" + (s.filename().empty() ? ":" :
+ "'" + s.filename() + "':"));
+
+ std::copy(d.begin(), d.end(), std::inserter(_imp->keys, _imp->keys.begin()));
- if (std::string::npos != std::string("'\"").find(s[0]))
+ if (! s.stream())
+ throw ConfigFileError(s.filename(), "Cannot read input");
+
+ std::istreambuf_iterator<char> c(s.stream()), c_end;
+
+ while (c != c_end)
{
- if (s.length() < 2)
- return false;
- if (s[s.length() - 1] != s[0])
- return false;
- return true;
+ if (*c == '#')
+ next_line(c, c_end);
+ else if (*c == '\t' || *c == '\n' || *c == '\r' || *c == ' ')
+ ++c;
+ else
+ {
+ std::string key(grab_key(c, c_end));
+ if (key.empty())
+ throw ConfigFileError(s.filename(), "Syntax error: invalid identifier");
+
+ if (c == c_end)
+ throw ConfigFileError(s.filename(), "Syntax error: trailing token '" + key + "' at end of input");
+
+ if (*c != '=')
+ {
+ while (*c == '\t' || *c == ' ')
+ if (++c == c_end)
+ throw ConfigFileError(s.filename(), "Unknown command or broken variable '" + key + "' at end of input");
+
+ if (*c != '=')
+ {
+ if (key == "source")
+ throw ConfigFileError(s.filename(), "'source' not yet supported");
+ else
+ throw ConfigFileError(s.filename(), "Unknown command or broken variable '" + key + "', trailing text '"
+ + std::string(c, c_end) + "'");
+ }
+ }
+ if (++c == c_end)
+ throw ConfigFileError(s.filename(), "= at end of input");
+
+ while (*c == '\t' || *c == ' ')
+ if (++c == c_end)
+ throw ConfigFileError(s.filename(), "= at end of input");
+
+ std::string value(grab_value(c, c_end, *this, s.filename()));
+
+ Log::get_instance()->message(ll_debug, lc_context, "keys '" + key + "' is now '" + value + "'");
+ _imp->keys.erase(key);
+ _imp->keys.insert(std::make_pair(key, value));
+ }
}
- else
- return true;
+}
+
+KeyValueConfigFile::~KeyValueConfigFile()
+{
}
KeyValueConfigFile::Iterator
KeyValueConfigFile::begin() const
{
- return Iterator(_imp->entries.begin());
+ return Iterator(_imp->keys.begin());
}
KeyValueConfigFile::Iterator
KeyValueConfigFile::end() const
{
- return Iterator(_imp->entries.end());
+ return Iterator(_imp->keys.end());
}
std::string
-KeyValueConfigFile::get(const std::string & key) const
+KeyValueConfigFile::get(const std::string & s) const
{
- return _imp->entries[key];
+ std::map<std::string, std::string>::const_iterator i(_imp->keys.find(s));
+ if (_imp->keys.end() == i)
+ {
+ Log::get_instance()->message(ll_debug, lc_context, "KV get '" + s + "' not found in keys");
+ return _imp->defaults.get(s);
+ }
+ else
+ {
+ Log::get_instance()->message(ll_debug, lc_context, "KV get '" + s + "' found in keys: '" + i->second + "'");
+ return i->second;
+ }
}
diff --git a/paludis/config_file.hh b/paludis/config_file.hh
index 302d6e7..1682235 100644
--- a/paludis/config_file.hh
+++ b/paludis/config_file.hh
@@ -41,275 +41,107 @@ namespace paludis
{
class FSEntry;
- /**
- * Thrown if an error occurs when reading a ConfigFile.
- *
- * \ingroup grpexceptions
- * \ingroup grpconfigfile
- * \nosubgrouping
- */
- class ConfigFileError : public ConfigurationError
+ class ConfigFileError :
+ public ConfigurationError
{
public:
- ///\name Basic operations
- ///\{
-
+ ConfigFileError(const std::string & filename, const std::string & message) throw ();
ConfigFileError(const std::string & message) throw ();
-
- ///\}
};
- /**
- * A ConfigFile is a file containing one entry per line, with lines
- * starting with a # being ignored and leading and trailing whitespace
- * being discarded.
- *
- * \ingroup grpconfigfile
- * \nosubgrouping
- */
class ConfigFile :
- paludis::InstantiationPolicy<ConfigFile, instantiation_method::NonCopyableTag>
+ private InstantiationPolicy<ConfigFile, instantiation_method::NonCopyableTag>
{
- private:
- std::istream * const _stream;
-
- mutable bool _has_lines;
-
- std::string _filename;
-
- bool _destroy_stream;
+ public:
+ class Source :
+ private PrivateImplementationPattern<Source>
+ {
+ public:
+ Source(const FSEntry &);
+ Source(const std::string &);
+ Source(std::istream &);
- static std::istream * _make_stream(const std::string & filename);
+ Source(const Source &);
+ const Source & operator= (const Source &);
- protected:
- /**
- * In-place normalise a line. By default, trims leading and
- * trailing whitespace. Child classes may override.
- */
- virtual void normalise_line(std::string &) const;
-
- /**
- * Return whether to skip a line. By default, skips on blank
- * lines and lines starting with a #. Child classes may
- * override. This is called on a normalised line, not a raw
- * string.
- */
- virtual bool skip_line(const std::string &) const;
-
- /**
- * Accept a normalised line that is not to be skipped.
- */
- 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;
-
- ///\name Basic operations
- ///\{
-
- /**
- * Constructor.
- */
- ConfigFile(std::istream * const stream);
-
- /**
- * Constructor, from a file.
- */
- ConfigFile(const std::string & filename);
-
- /**
- * Constructor, from a file.
- */
- ConfigFile(const FSEntry & filename);
-
- ///\}
-
- /**
- * Our filename, or blank if unknown.
- */
- std::string filename() const
- {
- return _filename;
- }
+ ~Source();
- public:
- ///\name Basic operations
- ///\{
+ std::istream & stream() const;
+ std::string filename() const;
+ };
virtual ~ConfigFile();
- ///\}
+ protected:
+ ConfigFile(const Source &);
};
- /**
- * A LineConfigFile is a ConfigFile that provides access to the
- * normalised lines. Do not subclass.
- *
- * \ingroup grplineconfigfile
- * \nosubgrouping
- */
class LineConfigFile :
- protected ConfigFile,
+ public ConfigFile,
private PrivateImplementationPattern<LineConfigFile>
{
- protected:
- void accept_line(const std::string &) const;
-
public:
- ///\name Basic operations
- ///\{
-
- /**
- * Constructor, from a stream.
- */
- LineConfigFile(std::istream * const);
-
- /**
- * Constructor, from a filename.
- */
- LineConfigFile(const std::string & filename);
-
- /**
- * Constructor, from a filename.
- */
- LineConfigFile(const FSEntry & filename);
-
+ LineConfigFile(const Source &);
~LineConfigFile();
- ///\}
-
- ///\name Iterate over our lines
- ///\{
-
typedef libwrapiter::ForwardIterator<LineConfigFile, const std::string> Iterator;
- Iterator begin() const
- PALUDIS_ATTRIBUTE((warn_unused_result));
-
- Iterator end() const
- PALUDIS_ATTRIBUTE((warn_unused_result));
-
- ///\}
- };
-
- /**
- * A KeyValueConfigFileError is thrown if bad data is encountered in
- * a ConfigFile.
- *
- * \ingroup grpkvconfigfile
- * \ingroup grpexceptions
- * \nosubgrouping
- */
- class KeyValueConfigFileError : public ConfigurationError
- {
- public:
- ///\name Basic operations
- ///\{
-
- KeyValueConfigFileError(const std::string & message,
- const std::string & filename = "") throw ();
-
- ///\}
+ Iterator begin() const;
+ Iterator end() const;
};
- /**
- * A KeyValueConfigFile is a ConfigFile that provides access to the
- * normalised lines. Do not subclass.
- *
- * \ingroup grpkvconfigfile
- * \nosubgrouping
- */
class KeyValueConfigFile :
- protected ConfigFile,
+ public ConfigFile,
private PrivateImplementationPattern<KeyValueConfigFile>
{
- private:
- bool quotes_are_balanced(const std::string &) const;
+ public:
+ class Defaults :
+ private PrivateImplementationPattern<Defaults>
+ {
+ public:
+ template <typename T_>
+ Defaults(T_)
+ {
+ T_::WrongTypeForDefaults;
+ }
- protected:
- void accept_line(const std::string &) const;
+ Defaults(std::string (*)(const std::string &, const std::string &));
- /**
- * Handle variable replacement.
- */
- std::string replace_variables(const std::string &) const;
+ Defaults();
- /**
- * Handle quote removal.
- */
- std::string strip_quotes(const std::string &) const;
+ Defaults(const Defaults &);
+ const Defaults & operator= (const Defaults &);
- virtual void done_reading_lines() const;
+ ~Defaults();
- public:
- ///\name Basic operations
- ///\{
-
- /**
- * Constructor, from a stream.
- */
- KeyValueConfigFile(std::istream * const);
-
- /**
- * Constructor, from a filename.
- */
- KeyValueConfigFile(const std::string & filename);
-
- /**
- * Constructor, from a filename.
- */
- KeyValueConfigFile(const FSEntry & filename);
-
- /**
- * Constructor, from a stream, with defaults.
- */
- KeyValueConfigFile(std::istream * const,
- std::tr1::shared_ptr<const AssociativeCollection<std::string, std::string> >);
-
- /**
- * Constructor, from a filename, with defaults.
- */
- KeyValueConfigFile(const std::string & filename,
- std::tr1::shared_ptr<const AssociativeCollection<std::string, std::string> >);
-
- /**
- * Constructor, from a filename, with defaults.
- */
- KeyValueConfigFile(const FSEntry & filename,
- std::tr1::shared_ptr<const AssociativeCollection<std::string, std::string> >);
+ std::string get(const std::string &) const;
- ~KeyValueConfigFile();
+ typedef libwrapiter::ForwardIterator<Defaults, const std::pair<const std::string, std::string> > Iterator;
+ Iterator begin() const;
+ Iterator end() const;
+ };
- ///\}
+ KeyValueConfigFile(const Source &, const Defaults & = Defaults());
+ ~KeyValueConfigFile();
- ///\name Iterate over our key/values
- ///\{
+ typedef libwrapiter::ForwardIterator<KeyValueConfigFile, const std::pair<const std::string, std::string> > Iterator;
+ Iterator begin() const;
+ Iterator end() const;
- typedef libwrapiter::ForwardIterator<KeyValueConfigFile,
- std::pair<const std::string, std::string> > Iterator;
+ std::string get(const std::string &) const;
+ };
- Iterator begin() const
- PALUDIS_ATTRIBUTE((warn_unused_result));
+ template<>
+ KeyValueConfigFile::Defaults::Defaults(std::tr1::shared_ptr<const KeyValueConfigFile>);
- Iterator end() const
- PALUDIS_ATTRIBUTE((warn_unused_result));
+ template<>
+ KeyValueConfigFile::Defaults::Defaults(std::tr1::shared_ptr<const AssociativeCollection<std::string, std::string> >);
- ///\}
+ template<>
+ KeyValueConfigFile::Defaults::Defaults(std::tr1::shared_ptr<KeyValueConfigFile>);
- /**
- * Fetch the specified key, or a blank string.
- */
- std::string get(const std::string & key) const
- PALUDIS_ATTRIBUTE((warn_unused_result));
- };
+ template<>
+ KeyValueConfigFile::Defaults::Defaults(std::tr1::shared_ptr<AssociativeCollection<std::string, std::string> >);
}
#endif
diff --git a/paludis/config_file_TEST.cc b/paludis/config_file_TEST.cc
index c921f8b..9093629 100644
--- a/paludis/config_file_TEST.cc
+++ b/paludis/config_file_TEST.cc
@@ -36,55 +36,6 @@ using namespace paludis;
* \ingroup grpconfigfile
*/
-namespace
-{
- /**
- * A ConfigFile descendent for use in tests.
- *
- */
- class TestFile : protected ConfigFile
- {
- public:
- /**
- * Constructor.
- */
- TestFile(std::istream * const stream) :
- ConfigFile(stream)
- {
- need_lines();
- }
-
- /**
- * Constructor.
- */
- TestFile(const std::string & filename) :
- ConfigFile(filename)
- {
- need_lines();
- }
-
- /**
- * Constructor.
- */
- TestFile(const FSEntry & filename) :
- ConfigFile(filename)
- {
- need_lines();
- }
-
- /**
- * Our lines.
- */
- mutable std::vector<std::string> lines;
-
- protected:
- void accept_line(const std::string & s) const
- {
- lines.push_back(s);
- }
- };
-}
-
namespace test_cases
{
/**
@@ -108,12 +59,14 @@ namespace test_cases
s << "#" << std::endl;
s << " # \t " << std::endl;
s << "four four" << std::endl;
- TestFile f(&s);
- TEST_CHECK_EQUAL(f.lines.size(), 4);
- TEST_CHECK_EQUAL(f.lines.at(0), "one");
- TEST_CHECK_EQUAL(f.lines.at(1), "two");
- TEST_CHECK_EQUAL(f.lines.at(2), "three");
- TEST_CHECK_EQUAL(f.lines.at(3), "four four");
+ LineConfigFile f(s);
+ TEST_CHECK_EQUAL(std::distance(f.begin(), f.end()), 4);
+ std::vector<std::string> lines;
+ std::copy(f.begin(), f.end(), std::back_inserter(lines));
+ TEST_CHECK_EQUAL(lines.at(0), "one");
+ TEST_CHECK_EQUAL(lines.at(1), "two");
+ TEST_CHECK_EQUAL(lines.at(2), "three");
+ TEST_CHECK_EQUAL(lines.at(3), "four four");
}
} test_config_file;
@@ -129,21 +82,21 @@ namespace test_cases
{
FSEntry ff("config_file_TEST_dir/config_file");
TEST_CHECK(ff.is_regular_file());
- TestFile f(ff);
- TEST_CHECK_EQUAL(f.lines.size(), 1);
- TEST_CHECK_EQUAL(f.lines.at(0), "I am a fish.");
+ LineConfigFile f(ff);
+ TEST_CHECK_EQUAL(std::distance(f.begin(), f.end()), 1);
+ TEST_CHECK_EQUAL(*f.begin(), "I am a fish.");
FSEntry ff2("config_file_TEST_dir/not_a_config_file");
TEST_CHECK(! ff2.exists());
- TestFile * f2(0);
- TEST_CHECK_THROWS(f2 = new TestFile(ff2), ConfigFileError);
+ LineConfigFile * f2(0);
+ TEST_CHECK_THROWS(f2 = new LineConfigFile(ff2), ConfigFileError);
if (0 != geteuid())
{
FSEntry ff3("config_file_TEST_dir/unreadable_file");
TEST_CHECK(ff3.is_regular_file());
- TestFile * f3(0);
- TEST_CHECK_THROWS(f3 = new TestFile(ff3), ConfigFileError);
+ LineConfigFile * f3(0);
+ TEST_CHECK_THROWS(f3 = new LineConfigFile(ff3), ConfigFileError);
}
}
} test_config_file_open_file;
@@ -169,7 +122,7 @@ namespace test_cases
s << "#" << std::endl;
s << " # \t " << std::endl;
s << "four four" << std::endl;
- LineConfigFile ff(&s);
+ LineConfigFile ff(s);
std::vector<std::string> f(ff.begin(), ff.end());
TEST_CHECK_EQUAL(f.size(), 4);
@@ -193,15 +146,15 @@ namespace test_cases
std::stringstream s;
s << "one=first" << std::endl;
s << "two = second" << std::endl;
- s << "three" << std::endl;
+ s << "three=" << std::endl;
s << "four = \"fourth\" " << std::endl;
s << "five = ''" << std::endl;
- KeyValueConfigFile ff(&s);
+ KeyValueConfigFile ff(s);
TEST_CHECK_EQUAL(ff.get("one"), "first");
TEST_CHECK_EQUAL(ff.get("two"), "second");
TEST_CHECK_EQUAL(ff.get("three"), "");
- TEST_CHECK_EQUAL(ff.get("four"), "fourth");
+ TEST_CHECK_EQUAL(ff.get("four"), "fourth ");
TEST_CHECK_EQUAL(ff.get("five"), "");
TEST_CHECK_EQUAL(ff.get("six"), "");
}
@@ -221,9 +174,9 @@ namespace test_cases
s << "one='first" << std::endl;
s << " first " << std::endl;
s << "first'" << std::endl;
- KeyValueConfigFile ff(&s);
+ KeyValueConfigFile ff(s);
- TEST_CHECK_EQUAL(ff.get("one"), "first first first");
+ TEST_CHECK_EQUAL(ff.get("one"), "first\n first \nfirst");
}
} test_key_value_config_file_continuations;
@@ -241,7 +194,7 @@ namespace test_cases
s << "x=foo" << std::endl;
s << "y = \"${x}\\\\${y}\\$${z}\"" << std::endl;
s << "z = $x$y$z" << std::endl;
- KeyValueConfigFile ff(&s);
+ KeyValueConfigFile ff(s);
TEST_CHECK_EQUAL(ff.get("x"), "foo");
TEST_CHECK_EQUAL(ff.get("y"), "foo\\$");
@@ -260,7 +213,7 @@ namespace test_cases
t << "f = " << std::endl;
t << "g = foo \\" << std::endl;
t << " bar" << std::endl;
- KeyValueConfigFile fg(&t, t_defs);
+ KeyValueConfigFile fg(t, KeyValueConfigFile::Defaults(t_defs));
TEST_CHECK_EQUAL(fg.get("a"), "foo");
TEST_CHECK_EQUAL(fg.get("b"), "foo");
@@ -268,7 +221,7 @@ namespace test_cases
TEST_CHECK_EQUAL(fg.get("d"), "bar");
TEST_CHECK_EQUAL(fg.get("e"), "baz");
TEST_CHECK_EQUAL(fg.get("f"), "");
- TEST_CHECK_EQUAL(fg.get("g"), "foo bar");
+ TEST_CHECK_EQUAL(fg.get("g"), "foo bar");
}
} test_key_value_config_file_vars;
@@ -284,39 +237,39 @@ namespace test_cases
{
std::stringstream s1;
s1 << "x='" << std::endl;
- TEST_CHECK_THROWS(KeyValueConfigFile ff(&s1), ConfigurationError);
+ TEST_CHECK_THROWS(KeyValueConfigFile ff(s1), ConfigurationError);
std::stringstream s2;
s2 << "x='moo\"" << std::endl;
- TEST_CHECK_THROWS(KeyValueConfigFile ff(&s2), ConfigurationError);
+ TEST_CHECK_THROWS(KeyValueConfigFile ff(s2), ConfigurationError);
std::stringstream s3;
s3 << "x=${foo" << std::endl;
- TEST_CHECK_THROWS(KeyValueConfigFile ff(&s3), ConfigurationError);
+ TEST_CHECK_THROWS(KeyValueConfigFile ff(s3), ConfigurationError);
std::stringstream s4;
s4 << "x=$~" << std::endl;
- TEST_CHECK_THROWS(KeyValueConfigFile ff(&s4), ConfigurationError);
+ TEST_CHECK_THROWS(KeyValueConfigFile ff(s4), ConfigurationError);
std::stringstream s5;
s5 << "x=abc\\" << std::endl;
- TEST_CHECK_THROWS(KeyValueConfigFile ff(&s5), ConfigurationError);
+ TEST_CHECK_THROWS(KeyValueConfigFile ff(s5), ConfigurationError);
std::stringstream s6;
s6 << "x=$" << std::endl;
- TEST_CHECK_THROWS(KeyValueConfigFile ff(&s6), ConfigurationError);
+ TEST_CHECK_THROWS(KeyValueConfigFile ff(s6), ConfigurationError);
std::stringstream s7;
s7 << "x=blah \\" << std::endl;
- TEST_CHECK_THROWS(KeyValueConfigFile ff(&s7), ConfigurationError);
+ TEST_CHECK_THROWS(KeyValueConfigFile ff(s7), ConfigurationError);
std::stringstream s8;
s8 << "x=blah \\" << std::endl << "# foo" << std::endl;
- TEST_CHECK_THROWS(KeyValueConfigFile ff(&s8), ConfigurationError);
+ 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_CHECK_THROWS(KeyValueConfigFile ff(s9), ConfigurationError);
}
} test_key_value_config_file_errors;
}
diff --git a/paludis/environments/paludis/paludis_config.cc b/paludis/environments/paludis/paludis_config.cc
index d4fa184..bb165e6 100644
--- a/paludis/environments/paludis/paludis_config.cc
+++ b/paludis/environments/paludis/paludis_config.cc
@@ -339,7 +339,7 @@ PaludisConfig::PaludisConfig(PaludisEnvironment * const e, const std::string & s
{
Context local_context("When reading repository file '" + stringify(*repo_file) + "':");
- KeyValueConfigFile k(*repo_file, conf_vars);
+ KeyValueConfigFile k(*repo_file, KeyValueConfigFile::Defaults(conf_vars));
std::string format(k.get("format"));
if (format.empty())
diff --git a/paludis/repositories/gentoo/ebuild.cc b/paludis/repositories/gentoo/ebuild.cc
index 14b0741..b376113 100644
--- a/paludis/repositories/gentoo/ebuild.cc
+++ b/paludis/repositories/gentoo/ebuild.cc
@@ -175,7 +175,7 @@ bool
EbuildMetadataCommand::do_run_command(const Command & cmd)
{
PStream prog(cmd);
- KeyValueConfigFile f(&prog);
+ KeyValueConfigFile f(prog);
_metadata.reset(new EbuildVersionMetadata);
bool ok(false);
diff --git a/paludis/repositories/gentoo/ebuild/ebuild.bash b/paludis/repositories/gentoo/ebuild/ebuild.bash
index 0df0f91..9a759a1 100755
--- a/paludis/repositories/gentoo/ebuild/ebuild.bash
+++ b/paludis/repositories/gentoo/ebuild/ebuild.bash
@@ -295,7 +295,7 @@ ebuild_main()
if [[ ${#@} -ge 2 ]] ; then
ebuild_section "Running ebuild phases $@..."
- elif [[ ${1} != variable ]] ; then
+ elif [[ ${1} != variable ]] && [[ ${1} != metadata ]] ; then
ebuild_section "Running ebuild phase $@..."
fi
@@ -356,7 +356,7 @@ ebuild_main()
if [[ ${#@} -ge 2 ]] ; then
ebuild_section "Completed ebuild phases $@"
- elif [[ ${1} != variable ]] ; then
+ elif [[ ${1} != variable ]] && [[ ${1} != metadata ]] ; then
ebuild_section "Completed ebuild phase $@"
fi
}
diff --git a/paludis/repositories/gentoo/portage_repository_news.cc b/paludis/repositories/gentoo/portage_repository_news.cc
index 4f89bac..53accb2 100644
--- a/paludis/repositories/gentoo/portage_repository_news.cc
+++ b/paludis/repositories/gentoo/portage_repository_news.cc
@@ -179,7 +179,7 @@ PortageRepositoryNews::update_news() const
}
}
}
- catch (const ConfigFileError & e)
+ catch (const Exception & e)
{
Log::get_instance()->message(ll_warning, lc_no_context,
"Skipping news item '"
@@ -200,41 +200,28 @@ namespace paludis
template<>
struct Implementation<NewsFile>
{
- mutable bool in_header;
mutable std::list<std::string> display_if_installed;
mutable std::list<std::string> display_if_keyword;
mutable std::list<std::string> display_if_profile;
-
- Implementation() :
- in_header(true)
- {
- }
};
}
NewsFile::NewsFile(const FSEntry & our_filename) :
- ConfigFile(our_filename),
PrivateImplementationPattern<NewsFile>(new Implementation<NewsFile>)
{
- need_lines();
-}
-
-NewsFile::~NewsFile()
-{
-}
+ Context context("When parsing GLEP 42 news file '" + stringify(our_filename) + "':");
-void
-NewsFile::accept_line(const std::string & line) const
-{
- if (_imp->in_header)
+ LineConfigFile line_file(our_filename);
+ for (LineConfigFile::Iterator line(line_file.begin()), line_end(line_file.end()) ;
+ line != line_end ; ++line)
{
- std::string::size_type p(line.find(':'));
+ std::string::size_type p(line->find(':'));
if (std::string::npos == p)
- _imp->in_header = false;
+ break;
else
{
- std::string k(strip_leading(strip_trailing(line.substr(0, p), " \t\n"), " \t\n"));
- std::string v(strip_leading(strip_trailing(line.substr(p + 1), " \t\n"), " \t\n"));
+ std::string k(strip_leading(strip_trailing(line->substr(0, p), " \t\n"), " \t\n"));
+ std::string v(strip_leading(strip_trailing(line->substr(p + 1), " \t\n"), " \t\n"));
if (k == "Display-If-Installed")
_imp->display_if_installed.push_back(v);
else if (k == "Display-If-Keyword")
@@ -245,6 +232,10 @@ NewsFile::accept_line(const std::string & line) const
}
}
+NewsFile::~NewsFile()
+{
+}
+
NewsFile::DisplayIfInstalledIterator
NewsFile::begin_display_if_installed() const
{
diff --git a/paludis/repositories/gentoo/portage_repository_news.hh b/paludis/repositories/gentoo/portage_repository_news.hh
index bd1b67d..447c692 100644
--- a/paludis/repositories/gentoo/portage_repository_news.hh
+++ b/paludis/repositories/gentoo/portage_repository_news.hh
@@ -66,12 +66,8 @@ namespace paludis
* \nosubgrouping
*/
class PALUDIS_VISIBLE NewsFile :
- protected ConfigFile,
private PrivateImplementationPattern<NewsFile>
{
- protected:
- void accept_line(const std::string &) const;
-
public:
///\name Basic operations
///\{