aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAvatar Ciaran McCreesh <ciaran.mccreesh@googlemail.com> 2009-11-10 20:21:51 +0000
committerAvatar Ciaran McCreesh <ciaran.mccreesh@googlemail.com> 2009-11-10 20:21:51 +0000
commit0b6f59ee9cfe6fb1a369905af020cac4d3832ee6 (patch)
tree76853a120de69deb05237a9edb0087c617509440
parent487da6a26c3eacf9ba1f04c226c1c5f61cfab1e4 (diff)
downloadpaludis-0b6f59ee9cfe6fb1a369905af020cac4d3832ee6.tar.gz
paludis-0b6f59ee9cfe6fb1a369905af020cac4d3832ee6.tar.xz
Split out, rewrite PaludisLikeOptionsConf.
Move use.conf / options.conf handling out of environments/paludis/ and into PaludisLikeOptionsConf. This will later be used by the Exheres profile format. Rewrite the whole thing to be less icky whilst we're at it.
-rw-r--r--paludis/environments/paludis/bashable_conf.cc14
-rw-r--r--paludis/environments/paludis/bashable_conf.hh10
-rw-r--r--paludis/environments/paludis/keywords_conf.cc2
-rw-r--r--paludis/environments/paludis/licenses_conf.cc2
-rw-r--r--paludis/environments/paludis/mirrors_conf.cc4
-rw-r--r--paludis/environments/paludis/output_conf.cc2
-rw-r--r--paludis/environments/paludis/output_managers.cc2
-rw-r--r--paludis/environments/paludis/package_mask_conf.cc2
-rw-r--r--paludis/environments/paludis/use_conf.cc446
-rw-r--r--paludis/files.m41
-rw-r--r--paludis/paludislike_options_conf-fwd.hh29
-rw-r--r--paludis/paludislike_options_conf.cc567
-rw-r--r--paludis/paludislike_options_conf.hh114
13 files changed, 747 insertions, 448 deletions
diff --git a/paludis/environments/paludis/bashable_conf.cc b/paludis/environments/paludis/bashable_conf.cc
index 43edfca..9c08aef 100644
--- a/paludis/environments/paludis/bashable_conf.cc
+++ b/paludis/environments/paludis/bashable_conf.cc
@@ -43,7 +43,7 @@ std::string defined_vars_to_kv_func(
}
std::tr1::shared_ptr<LineConfigFile>
-paludis::paludis_environment::make_bashable_conf(const FSEntry & f)
+paludis::paludis_environment::make_bashable_conf(const FSEntry & f, const LineConfigFileOptions & o)
{
Context context("When making a config file out of '" + stringify(f) + "':");
@@ -58,7 +58,7 @@ paludis::paludis_environment::make_bashable_conf(const FSEntry & f)
.with_stderr_prefix(f.basename() + "> ")
.with_captured_stdout_stream(&s));
int exit_status(run_command(cmd));
- result.reset(new LineConfigFile(s, LineConfigFileOptions()));
+ result.reset(new LineConfigFile(s, o));
if (exit_status != 0)
{
@@ -68,13 +68,15 @@ paludis::paludis_environment::make_bashable_conf(const FSEntry & f)
}
}
else
- result.reset(new LineConfigFile(f, LineConfigFileOptions()));
+ result.reset(new LineConfigFile(f, o));
return result;
}
std::tr1::shared_ptr<KeyValueConfigFile>
-paludis::paludis_environment::make_bashable_kv_conf(const FSEntry & f, const std::tr1::shared_ptr<const Map<std::string, std::string> > & predefined_variables)
+paludis::paludis_environment::make_bashable_kv_conf(const FSEntry & f,
+ const std::tr1::shared_ptr<const Map<std::string, std::string> > & predefined_variables,
+ const KeyValueConfigFileOptions & o)
{
Context context("When making a key=value config file out of '" + stringify(f) + "':");
@@ -92,7 +94,7 @@ paludis::paludis_environment::make_bashable_kv_conf(const FSEntry & f, const std
end(predefined_variables->end()); i != end; ++i)
cmd.with_setenv(i->first, i->second);
int exit_status(run_command(cmd));
- result.reset(new KeyValueConfigFile(s, KeyValueConfigFileOptions(), &KeyValueConfigFile::no_defaults,
+ result.reset(new KeyValueConfigFile(s, o, &KeyValueConfigFile::no_defaults,
&KeyValueConfigFile::no_transformation));
if (exit_status != 0)
@@ -104,7 +106,7 @@ paludis::paludis_environment::make_bashable_kv_conf(const FSEntry & f, const std
}
else
{
- result.reset(new KeyValueConfigFile(f, KeyValueConfigFileOptions(),
+ result.reset(new KeyValueConfigFile(f, o,
std::tr1::bind(
&defined_vars_to_kv_func,
predefined_variables,
diff --git a/paludis/environments/paludis/bashable_conf.hh b/paludis/environments/paludis/bashable_conf.hh
index 0b9495b..692622f 100644
--- a/paludis/environments/paludis/bashable_conf.hh
+++ b/paludis/environments/paludis/bashable_conf.hh
@@ -30,8 +30,14 @@ namespace paludis
{
namespace paludis_environment
{
- std::tr1::shared_ptr<LineConfigFile> make_bashable_conf(const FSEntry &);
- std::tr1::shared_ptr<KeyValueConfigFile> make_bashable_kv_conf(const FSEntry &, const std::tr1::shared_ptr<const Map<std::string, std::string> > &);
+ std::tr1::shared_ptr<LineConfigFile> make_bashable_conf(
+ const FSEntry &,
+ const LineConfigFileOptions &);
+
+ std::tr1::shared_ptr<KeyValueConfigFile> make_bashable_kv_conf(
+ const FSEntry &,
+ const std::tr1::shared_ptr<const Map<std::string, std::string> > &,
+ const KeyValueConfigFileOptions &);
}
}
diff --git a/paludis/environments/paludis/keywords_conf.cc b/paludis/environments/paludis/keywords_conf.cc
index 5098465..c1de53d 100644
--- a/paludis/environments/paludis/keywords_conf.cc
+++ b/paludis/environments/paludis/keywords_conf.cc
@@ -87,7 +87,7 @@ KeywordsConf::add(const FSEntry & filename)
{
Context context("When adding source '" + stringify(filename) + "' as a keywords file:");
- std::tr1::shared_ptr<LineConfigFile> f(make_bashable_conf(filename));
+ std::tr1::shared_ptr<LineConfigFile> f(make_bashable_conf(filename, LineConfigFileOptions()));
if (! f)
return;
diff --git a/paludis/environments/paludis/licenses_conf.cc b/paludis/environments/paludis/licenses_conf.cc
index f4433d3..ce642d2 100644
--- a/paludis/environments/paludis/licenses_conf.cc
+++ b/paludis/environments/paludis/licenses_conf.cc
@@ -86,7 +86,7 @@ LicensesConf::add(const FSEntry & filename)
{
Context context("When adding source '" + stringify(filename) + "' as a licenses file:");
- std::tr1::shared_ptr<LineConfigFile> f(make_bashable_conf(filename));
+ std::tr1::shared_ptr<LineConfigFile> f(make_bashable_conf(filename, LineConfigFileOptions()));
if (! f)
return;
diff --git a/paludis/environments/paludis/mirrors_conf.cc b/paludis/environments/paludis/mirrors_conf.cc
index 4eadafb..3e7e9f8 100644
--- a/paludis/environments/paludis/mirrors_conf.cc
+++ b/paludis/environments/paludis/mirrors_conf.cc
@@ -1,7 +1,7 @@
/* vim: set sw=4 sts=4 et foldmethod=syntax : */
/*
- * Copyright (c) 2007, 2008 Ciaran McCreesh
+ * Copyright (c) 2007, 2008, 2009 Ciaran McCreesh
*
* This file is part of the Paludis package manager. Paludis is free software;
* you can redistribute it and/or modify it under the terms of the GNU General
@@ -69,7 +69,7 @@ MirrorsConf::add(const FSEntry & filename)
{
Context context("When adding source '" + stringify(filename) + "' as a mirrors file:");
- std::tr1::shared_ptr<LineConfigFile> f(make_bashable_conf(filename));
+ std::tr1::shared_ptr<LineConfigFile> f(make_bashable_conf(filename, LineConfigFileOptions()));
if (! f)
return;
diff --git a/paludis/environments/paludis/output_conf.cc b/paludis/environments/paludis/output_conf.cc
index 5b30b47..826ed4a 100644
--- a/paludis/environments/paludis/output_conf.cc
+++ b/paludis/environments/paludis/output_conf.cc
@@ -199,7 +199,7 @@ OutputConf::add(const FSEntry & filename)
{
Context context("When adding source '" + stringify(filename) + "' as an output file:");
- std::tr1::shared_ptr<LineConfigFile> f(make_bashable_conf(filename));
+ std::tr1::shared_ptr<LineConfigFile> f(make_bashable_conf(filename, LineConfigFileOptions()));
if (! f)
return;
diff --git a/paludis/environments/paludis/output_managers.cc b/paludis/environments/paludis/output_managers.cc
index 350da36..24ed027 100644
--- a/paludis/environments/paludis/output_managers.cc
+++ b/paludis/environments/paludis/output_managers.cc
@@ -75,7 +75,7 @@ OutputManagers::add(const FSEntry & filename, const std::tr1::shared_ptr<const M
{
Context context("When adding source '" + stringify(filename) + "' as an output manager file:");
- std::tr1::shared_ptr<KeyValueConfigFile> f(make_bashable_kv_conf(filename, predefined_variables));
+ std::tr1::shared_ptr<KeyValueConfigFile> f(make_bashable_kv_conf(filename, predefined_variables, KeyValueConfigFileOptions()));
if (! f)
return;
diff --git a/paludis/environments/paludis/package_mask_conf.cc b/paludis/environments/paludis/package_mask_conf.cc
index dd41ee7..044216f 100644
--- a/paludis/environments/paludis/package_mask_conf.cc
+++ b/paludis/environments/paludis/package_mask_conf.cc
@@ -77,7 +77,7 @@ PackageMaskConf::add(const FSEntry & filename)
{
Context context("When adding source '" + stringify(filename) + "' as a package mask or unmask file:");
- std::tr1::shared_ptr<LineConfigFile> f(make_bashable_conf(filename));
+ std::tr1::shared_ptr<LineConfigFile> f(make_bashable_conf(filename, LineConfigFileOptions()));
if (! f)
return;
diff --git a/paludis/environments/paludis/use_conf.cc b/paludis/environments/paludis/use_conf.cc
index 63f13c7..cbb493f 100644
--- a/paludis/environments/paludis/use_conf.cc
+++ b/paludis/environments/paludis/use_conf.cc
@@ -17,91 +17,32 @@
* Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "use_conf.hh"
-#include <paludis/environment.hh>
-#include <paludis/name.hh>
-#include <paludis/dep_spec.hh>
-#include <paludis/match_package.hh>
-#include <paludis/user_dep_spec.hh>
-#include <paludis/util/config_file.hh>
-#include <paludis/util/options.hh>
-#include <paludis/package_id.hh>
+#include <paludis/environments/paludis/use_conf.hh>
#include <paludis/environments/paludis/paludis_environment.hh>
#include <paludis/environments/paludis/bashable_conf.hh>
-#include <paludis/util/log.hh>
-#include <paludis/util/tokeniser.hh>
#include <paludis/util/private_implementation_pattern-impl.hh>
-#include <paludis/util/iterator_funcs.hh>
-#include <paludis/util/strip.hh>
-#include <paludis/util/wrapped_forward_iterator.hh>
-#include <paludis/util/set.hh>
-#include <paludis/util/mutex.hh>
-#include <paludis/util/hashes.hh>
-#include <paludis/util/tribool.hh>
-#include <paludis/util/make_shared_ptr.hh>
+#include <paludis/util/fs_entry.hh>
#include <paludis/util/make_named_values.hh>
-#include <paludis/spec_tree.hh>
+#include <paludis/paludislike_options_conf.hh>
#include <paludis/choice.hh>
-#include <tr1/unordered_map>
-#include <algorithm>
-#include <list>
-#include <vector>
using namespace paludis;
using namespace paludis::paludis_environment;
namespace paludis
{
- namespace n
- {
- struct enabled;
- struct parameter;
- }
-}
-
-namespace
-{
- struct FlagNameState
- {
- NamedValue<n::enabled, Tribool> enabled;
- NamedValue<n::parameter, std::string> parameter;
- };
-
- std::pair<std::string, std::string> split_equals(const std::string & s)
- {
- std::string::size_type p(s.find('='));
- if (std::string::npos == p)
- return std::make_pair(s, "");
- else
- return std::make_pair(s.substr(0, p), s.substr(p + 1));
- }
-}
-
-typedef std::pair<ChoicePrefixName, UnprefixedChoiceName> FlagNamePair;
-
-typedef std::tr1::unordered_map<FlagNamePair, FlagNameState, Hash<FlagNamePair> > FlagNamePairWithStateMap;
-typedef std::list<ChoicePrefixName> MinusStarPrefixList;
-typedef std::pair<FlagNamePairWithStateMap, MinusStarPrefixList> UseInfo;
-typedef std::pair<std::tr1::shared_ptr<const PackageDepSpec>, UseInfo> PDSWithUseInfo;
-typedef std::pair<std::tr1::shared_ptr<const SetSpecTree>, UseInfo> DSWithUseInfo;
-typedef std::list<PDSWithUseInfo> PDSWithUseInfoList;
-typedef std::tr1::unordered_map<QualifiedPackageName, PDSWithUseInfoList, Hash<QualifiedPackageName> > Qualified;
-typedef std::list<PDSWithUseInfo> Unqualified;
-typedef std::tr1::unordered_map<SetName, DSWithUseInfo, Hash<SetName> > Sets;
-
-namespace paludis
-{
template<>
struct Implementation<UseConf>
{
const PaludisEnvironment * const env;
- Qualified qualified;
- Unqualified unqualified;
- mutable Mutex set_mutex;
- mutable Sets sets;
+ const std::tr1::shared_ptr<PaludisLikeOptionsConf> handler;
Implementation(const PaludisEnvironment * const e) :
- env(e)
+ env(e),
+ handler(new PaludisLikeOptionsConf(make_named_values<PaludisLikeOptionsConfParams>(
+ value_for<n::environment>(e),
+ value_for<n::make_config_file>(&make_bashable_conf)
+ )))
{
}
};
@@ -121,150 +62,7 @@ UseConf::add(const FSEntry & filename)
{
Context context("When adding source '" + stringify(filename) + "' as a use file:");
- std::tr1::shared_ptr<LineConfigFile> f(make_bashable_conf(filename));
- if (! f)
- return;
-
- for (LineConfigFile::ConstIterator line(f->begin()), line_end(f->end()) ;
- line != line_end ; ++line)
- {
- std::vector<std::string> tokens;
- tokenise_whitespace_quoted(*line, std::back_inserter(tokens));
-
- if (tokens.size() < 2)
- continue;
-
- try
- {
- std::tr1::shared_ptr<PackageDepSpec> d(new PackageDepSpec(parse_user_package_dep_spec(
- tokens.at(0), _imp->env,
- UserPackageDepSpecOptions() + updso_allow_wildcards + updso_no_disambiguation + updso_throw_if_set)));
-
- if (d->additional_requirements_ptr())
- {
- Log::get_instance()->message("paludis_environment.use_conf.bad_spec", ll_warning, lc_context)
- << "Dependency specification '" << stringify(*d)
- << "' includes use requirements, which cannot be used in use.conf";
- continue;
- }
-
- if (d->package_ptr())
- {
- Qualified::iterator ii(_imp->qualified.insert(std::make_pair(*d->package_ptr(), PDSWithUseInfoList())).first);
- PDSWithUseInfoList::iterator i(ii->second.insert(ii->second.end(), PDSWithUseInfo(d, UseInfo())));
-
- ChoicePrefixName prefix("");
- for (std::vector<std::string>::const_iterator t(next(tokens.begin())), t_end(tokens.end()) ;
- t != t_end ; ++t)
- {
- if (*t == "-*")
- i->second.second.push_back(prefix);
- else if ('-' == t->at(0))
- {
- std::pair<std::string, std::string> ts(split_equals(t->substr(1)));
- FlagNameState s(make_named_values<FlagNameState>(
- value_for<n::enabled>(false),
- value_for<n::parameter>(ts.second)
- ));
- i->second.first.insert(std::make_pair(
- FlagNamePair(prefix, UnprefixedChoiceName(ts.first)), s)).first->second = s;
- }
- else if (':' == t->at(t->length() - 1))
- {
- std::string p;
- std::transform(t->begin(), previous(t->end()), std::back_inserter(p), &::tolower);
- prefix = ChoicePrefixName(p);
- }
- else
- {
- std::pair<std::string, std::string> ts(split_equals(*t));
- FlagNameState s(make_named_values<FlagNameState>(
- value_for<n::enabled>(true),
- value_for<n::parameter>(ts.second)
- ));
- i->second.first.insert(std::make_pair(
- FlagNamePair(prefix, UnprefixedChoiceName(ts.first)), s)).first->second = s;
- }
- }
- }
- else
- {
- Unqualified::iterator i(_imp->unqualified.insert(_imp->unqualified.end(), PDSWithUseInfo(d, UseInfo())));
-
- ChoicePrefixName prefix("");
- for (std::vector<std::string>::const_iterator t(next(tokens.begin())), t_end(tokens.end()) ;
- t != t_end ; ++t)
- {
- if (*t == "-*")
- i->second.second.push_back(prefix);
- else if ('-' == t->at(0))
- {
- std::pair<std::string, std::string> ts(split_equals(t->substr(1)));
- FlagNameState s(make_named_values<FlagNameState>(
- value_for<n::enabled>(false),
- value_for<n::parameter>(ts.second)
- ));
- i->second.first.insert(
- std::make_pair(FlagNamePair(
- prefix, UnprefixedChoiceName(ts.first)), s)).first->second = s;
- }
- else if (':' == t->at(t->length() - 1))
- {
- std::string p;
- std::transform(t->begin(), previous(t->end()), std::back_inserter(p), &::tolower);
- prefix = ChoicePrefixName(p);
- }
- else
- {
- std::pair<std::string, std::string> ts(split_equals(*t));
- FlagNameState s(make_named_values<FlagNameState>(
- value_for<n::enabled>(true),
- value_for<n::parameter>(ts.second)
- ));
- i->second.first.insert(std::make_pair(FlagNamePair(
- prefix, UnprefixedChoiceName(ts.first)), s)).first->second = s;
- }
- }
- }
- }
- catch (const GotASetNotAPackageDepSpec &)
- {
- Sets::iterator i(_imp->sets.insert(std::make_pair(SetName(tokens.at(0)), DSWithUseInfo())).first);
- ChoicePrefixName prefix("");
- for (std::vector<std::string>::const_iterator t(next(tokens.begin())), t_end(tokens.end()) ;
- t != t_end ; ++t)
- {
- if (*t == "-*")
- i->second.second.second.push_back(prefix);
- else if ('-' == t->at(0))
- {
- std::pair<std::string, std::string> ts(split_equals(t->substr(1)));
- FlagNameState s(make_named_values<FlagNameState>(
- value_for<n::enabled>(false),
- value_for<n::parameter>(ts.second)
- ));
- i->second.second.first.insert(std::make_pair(
- FlagNamePair(prefix, UnprefixedChoiceName(ts.first)), s)).first->second = s;
- }
- else if (':' == t->at(t->length() - 1))
- {
- std::string p;
- std::transform(t->begin(), previous(t->end()), std::back_inserter(p), &::tolower);
- prefix = ChoicePrefixName(p);
- }
- else
- {
- std::pair<std::string, std::string> ts(split_equals(*t));
- FlagNameState s(make_named_values<FlagNameState>(
- value_for<n::enabled>(true),
- value_for<n::parameter>(ts.second)
- ));
- i->second.second.first.insert(std::make_pair(
- FlagNamePair(prefix, UnprefixedChoiceName(ts.first)), s)).first->second = s;
- }
- }
- }
- }
+ _imp->handler->add_file(filename);
}
const Tribool
@@ -277,109 +75,7 @@ UseConf::want_choice_enabled(
Context context("When checking state of flag prefix '" + stringify(choice->prefix()) +
"' name '" + stringify(f) + "' for '" + stringify(*id) + "':");
- Tribool result(indeterminate);
-
- bool ignore_empty_minus_star(! stringify(choice->prefix()).empty());
-
- /* highest priority: specific */
- Qualified::const_iterator q(_imp->qualified.find(id->name()));
- if (_imp->qualified.end() != q)
- {
- for (PDSWithUseInfoList::const_iterator p(q->second.begin()), p_end(q->second.end()) ; p != p_end ; ++p)
- {
- if (! match_package(*_imp->env, *p->first, *id, MatchPackageOptions()))
- continue;
-
- FlagNamePairWithStateMap::const_iterator i(p->second.first.find(std::make_pair(choice->prefix(), f)));
- if (p->second.first.end() != i)
- result = i->second.enabled();
-
- if (result.is_indeterminate())
- for (MinusStarPrefixList::const_iterator m(p->second.second.begin()), m_end(p->second.second.end()) ;
- m != m_end ; ++m)
- {
- if (stringify(*m).empty() && ignore_empty_minus_star)
- continue;
-
- if (choice->prefix() == *m)
- {
- result = false;
- break;
- }
- }
- }
- }
-
- if (! result.is_indeterminate())
- return result;
-
- /* next: named sets */
- for (Sets::iterator r(_imp->sets.begin()), r_end(_imp->sets.end()) ; r != r_end ; ++r)
- {
- Lock lock(_imp->set_mutex);
- if (! r->second.first)
- {
- r->second.first = _imp->env->set(r->first);
- if (! r->second.first)
- {
- Log::get_instance()->message("paludis_environment.use_conf.unknown_set", ll_warning, lc_no_context) << "Set name '"
- << r->first << "' does not exist";
- r->second.first.reset(new SetSpecTree(make_shared_ptr(new AllDepSpec)));
- }
- }
-
- if (! match_package_in_set(*_imp->env, *r->second.first, *id, MatchPackageOptions()))
- continue;
-
- FlagNamePairWithStateMap::const_iterator i(r->second.second.first.find(std::make_pair(choice->prefix(), f)));
- if (i != r->second.second.first.end())
- result = i->second.enabled();
-
- if (result.is_indeterminate())
- for (MinusStarPrefixList::const_iterator m(r->second.second.second.begin()), m_end(r->second.second.second.end()) ;
- m != m_end ; ++m)
- {
- if (stringify(*m).empty() && ignore_empty_minus_star)
- continue;
-
- if (choice->prefix() == *m)
- {
- result = false;
- break;
- }
- }
- }
-
- if (! result.is_indeterminate())
- return result;
-
- /* last: unspecific */
-
- for (Unqualified::const_iterator p(_imp->unqualified.begin()), p_end(_imp->unqualified.end()) ; p != p_end ; ++p)
- {
- if (! match_package(*_imp->env, *p->first, *id, MatchPackageOptions()))
- continue;
-
- FlagNamePairWithStateMap::const_iterator i(p->second.first.find(std::make_pair(choice->prefix(), f)));
- if (p->second.first.end() != i)
- result = i->second.enabled();
-
- if (result.is_indeterminate())
- for (MinusStarPrefixList::const_iterator m(p->second.second.begin()), m_end(p->second.second.end()) ;
- m != m_end ; ++m)
- {
- if (stringify(*m).empty() && ignore_empty_minus_star)
- continue;
-
- if (choice->prefix() == *m)
- {
- result = false;
- break;
- }
- }
- }
-
- return result;
+ return _imp->handler->want_choice_enabled(id, choice, f);
}
const std::string
@@ -392,72 +88,7 @@ UseConf::value_for_choice_parameter(
Context context("When checking parameter of flag prefix '" + stringify(choice->prefix()) +
"' name '" + stringify(f) + "' for '" + stringify(*id) + "':");
- std::string result;
- bool found(false);
-
- /* highest priority: specific */
- Qualified::const_iterator q(_imp->qualified.find(id->name()));
- if (_imp->qualified.end() != q)
- {
- for (PDSWithUseInfoList::const_iterator p(q->second.begin()), p_end(q->second.end()) ; p != p_end ; ++p)
- {
- if (! match_package(*_imp->env, *p->first, *id, MatchPackageOptions()))
- continue;
-
- FlagNamePairWithStateMap::const_iterator i(p->second.first.find(std::make_pair(choice->prefix(), f)));
- if (p->second.first.end() != i)
- {
- result = i->second.parameter();
- found = true;
- }
- }
- }
-
- if (found)
- return result;
-
- /* next: named sets */
- for (Sets::iterator r(_imp->sets.begin()), r_end(_imp->sets.end()) ; r != r_end ; ++r)
- {
- Lock lock(_imp->set_mutex);
- if (! r->second.first)
- {
- r->second.first = _imp->env->set(r->first);
- if (! r->second.first)
- {
- Log::get_instance()->message("paludis_environment.use_conf.unknown_set", ll_warning, lc_no_context) << "Set name '"
- << r->first << "' does not exist";
- r->second.first.reset(new SetSpecTree(make_shared_ptr(new AllDepSpec)));
- }
- }
-
- if (! match_package_in_set(*_imp->env, *r->second.first, *id, MatchPackageOptions()))
- continue;
-
- FlagNamePairWithStateMap::const_iterator i(r->second.second.first.find(std::make_pair(choice->prefix(), f)));
- if (i != r->second.second.first.end())
- {
- result = i->second.parameter();
- found = true;
- }
- }
-
- if (found)
- return result;
-
- /* last: unspecific */
-
- for (Unqualified::const_iterator p(_imp->unqualified.begin()), p_end(_imp->unqualified.end()) ; p != p_end ; ++p)
- {
- if (! match_package(*_imp->env, *p->first, *id, MatchPackageOptions()))
- continue;
-
- FlagNamePairWithStateMap::const_iterator i(p->second.first.find(std::make_pair(choice->prefix(), f)));
- if (p->second.first.end() != i)
- result = i->second.parameter();
- }
-
- return result;
+ return _imp->handler->value_for_choice_parameter(id, choice, f);
}
@@ -469,57 +100,6 @@ UseConf::known_choice_value_names(
{
Context context("When loading known use expand names for prefix '" + stringify(choice->prefix()) + "':");
- std::tr1::shared_ptr<Set<UnprefixedChoiceName> > result(new Set<UnprefixedChoiceName>);
-
- Qualified::const_iterator q(_imp->qualified.find(id->name()));
- if (_imp->qualified.end() != q)
- for (PDSWithUseInfoList::const_iterator p(q->second.begin()), p_end(q->second.end()) ; p != p_end ; ++p)
- {
- if (! match_package(*_imp->env, *p->first, *id, MatchPackageOptions()))
- continue;
-
- for (FlagNamePairWithStateMap::const_iterator i(p->second.first.begin()), i_end(p->second.first.end()) ;
- i != i_end ; ++i)
- if (i->first.first == choice->prefix())
- result->insert(i->first.second);
- }
-
- {
- Lock lock(_imp->set_mutex);
- for (Sets::iterator r(_imp->sets.begin()), r_end(_imp->sets.end()) ; r != r_end ; ++r)
- {
- if (! r->second.first)
- {
- r->second.first = _imp->env->set(r->first);
- if (! r->second.first)
- {
- Log::get_instance()->message("paludis_environment.use_conf.unknown_set", ll_warning, lc_no_context) << "Set name '"
- << r->first << "' does not exist";
- r->second.first.reset(new SetSpecTree(make_shared_ptr(new AllDepSpec)));
- }
- }
-
- if (! match_package_in_set(*_imp->env, *r->second.first, *id, MatchPackageOptions()))
- continue;
-
- for (FlagNamePairWithStateMap::const_iterator i(r->second.second.first.begin()), i_end(r->second.second.first.end()) ;
- i != i_end ; ++i)
- if (i->first.first == choice->prefix())
- result->insert(i->first.second);
- }
- }
-
- for (Unqualified::const_iterator p(_imp->unqualified.begin()), p_end(_imp->unqualified.end()) ; p != p_end ; ++p)
- {
- if (! match_package(*_imp->env, *p->first, *id, MatchPackageOptions()))
- continue;
-
- for (FlagNamePairWithStateMap::const_iterator i(p->second.first.begin()), i_end(p->second.first.end()) ;
- i != i_end ; ++i)
- if (i->first.first == choice->prefix())
- result->insert(i->first.second);
- }
-
- return result;
+ return _imp->handler->known_choice_value_names(id, choice);
}
diff --git a/paludis/files.m4 b/paludis/files.m4
index 12ac5da..91c4830 100644
--- a/paludis/files.m4
+++ b/paludis/files.m4
@@ -66,6 +66,7 @@ add(`package_database', `hh', `cc', `fwd', `test')
add(`package_dep_spec_properties', `hh', `cc', `fwd')
add(`package_id', `hh', `cc', `fwd', `se')
add(`paludis', `hh')
+add(`paludislike_options_conf', `hh', `cc', `fwd')
add(`query_visitor', `hh', `cc')
add(`range_rewriter', `hh', `cc', `test')
add(`report_task', `hh', `cc')
diff --git a/paludis/paludislike_options_conf-fwd.hh b/paludis/paludislike_options_conf-fwd.hh
new file mode 100644
index 0000000..7dcc7e6
--- /dev/null
+++ b/paludis/paludislike_options_conf-fwd.hh
@@ -0,0 +1,29 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2009 Ciaran McCreesh
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_PALUDISLIKE_OPTIONS_CONF_FWD_HH
+#define PALUDIS_GUARD_PALUDIS_PALUDISLIKE_OPTIONS_CONF_FWD_HH 1
+
+namespace paludis
+{
+ struct PaludisLikeOptionsConf;
+ struct PaludisLikeOptionsConfParams;
+}
+
+#endif
diff --git a/paludis/paludislike_options_conf.cc b/paludis/paludislike_options_conf.cc
new file mode 100644
index 0000000..d9b38f1
--- /dev/null
+++ b/paludis/paludislike_options_conf.cc
@@ -0,0 +1,567 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2009 Ciaran McCreesh
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <paludis/paludislike_options_conf.hh>
+#include <paludis/util/private_implementation_pattern-impl.hh>
+#include <paludis/util/hashes.hh>
+#include <paludis/util/validated.hh>
+#include <paludis/util/named_value.hh>
+#include <paludis/util/stringify.hh>
+#include <paludis/util/config_file.hh>
+#include <paludis/util/options.hh>
+#include <paludis/util/wrapped_forward_iterator.hh>
+#include <paludis/util/tokeniser.hh>
+#include <paludis/util/log.hh>
+#include <paludis/util/iterator_funcs.hh>
+#include <paludis/util/make_named_values.hh>
+#include <paludis/util/set.hh>
+#include <paludis/choice.hh>
+#include <paludis/dep_spec.hh>
+#include <paludis/name.hh>
+#include <paludis/user_dep_spec.hh>
+#include <paludis/match_package.hh>
+#include <paludis/package_id.hh>
+#include <paludis/environment.hh>
+#include <tr1/unordered_map>
+#include <tr1/unordered_set>
+#include <list>
+#include <vector>
+#include <algorithm>
+
+using namespace paludis;
+
+/*
+ * Syntax:
+ *
+ * spec|set foo -bar -* baz=value
+ * spec|set blah: foo -bar -* baz=value
+ *
+ * Lines in the form 'spec foo blah: baz' are treated as two lines, 'spec foo'
+ * and 'spec blah: baz'.
+ *
+ * Specific cat/pkg specs have highest priority, followed by named sets,
+ * followed by wildcards.
+ */
+
+namespace paludis
+{
+ namespace n
+ {
+ struct equals_value;
+ struct minus;
+ struct minus_star;
+ struct prefix;
+ struct set_name;
+ struct spec;
+ struct unprefixed_name;
+ struct values;
+ struct values_groups;
+ }
+}
+
+namespace
+{
+ struct Value
+ {
+ NamedValue<n::equals_value, std::string> equals_value;
+ NamedValue<n::minus, bool> minus;
+ NamedValue<n::unprefixed_name, UnprefixedChoiceName> unprefixed_name;
+
+ bool operator== (const Value & other) const
+ {
+ return unprefixed_name() == other.unprefixed_name();
+ }
+
+ std::size_t hash() const
+ {
+ return Hash<UnprefixedChoiceName>()(unprefixed_name());
+ }
+ };
+
+ typedef std::tr1::unordered_multiset<Value, Hash<Value> > Values;
+
+ struct ValuesGroup
+ {
+ NamedValue<n::minus_star, bool> minus_star;
+ NamedValue<n::prefix, ChoicePrefixName> prefix;
+ NamedValue<n::values, Values> values;
+ };
+
+ typedef std::list<ValuesGroup> ValuesGroups;
+
+ struct SpecWithValuesGroups
+ {
+ NamedValue<n::spec, PackageDepSpec> spec;
+ NamedValue<n::values_groups, ValuesGroups> values_groups;
+ };
+
+ typedef std::list<SpecWithValuesGroups> SpecsWithValuesGroups;
+
+ struct SetNameWithValuesGroups
+ {
+ NamedValue<n::set_name, SetName> set_name;
+ NamedValue<n::values_groups, ValuesGroups> values_groups;
+ };
+
+ typedef std::list<SetNameWithValuesGroups> SetNamesWithValuesGroups;
+
+ typedef std::tr1::unordered_map<QualifiedPackageName, SpecsWithValuesGroups, Hash<QualifiedPackageName> > SpecificSpecs;
+}
+
+namespace paludis
+{
+ template <>
+ struct Implementation<PaludisLikeOptionsConf>
+ {
+ const PaludisLikeOptionsConfParams params;
+
+ SpecificSpecs specific_specs;
+ SetNamesWithValuesGroups set_specs;
+ SpecsWithValuesGroups wildcard_specs;
+
+ Implementation(const PaludisLikeOptionsConfParams & p) :
+ params(p)
+ {
+ }
+ };
+}
+
+PaludisLikeOptionsConf::PaludisLikeOptionsConf(const PaludisLikeOptionsConfParams & params) :
+ PrivateImplementationPattern<PaludisLikeOptionsConf>(new Implementation<PaludisLikeOptionsConf>(params))
+{
+}
+
+PaludisLikeOptionsConf::~PaludisLikeOptionsConf()
+{
+}
+
+void
+PaludisLikeOptionsConf::add_file(const FSEntry & f)
+{
+ Context context("When adding '" + stringify(f) + "':");
+
+ const std::tr1::shared_ptr<const LineConfigFile> file(_imp->params.make_config_file()(f, LineConfigFileOptions()));
+ if (! file)
+ return;
+
+ for (LineConfigFile::ConstIterator line(file->begin()), line_end(file->end()) ;
+ line != line_end ; ++line)
+ {
+ std::vector<std::string> tokens;
+ tokenise_whitespace_quoted(*line, std::back_inserter(tokens));
+
+ if (tokens.size() < 2)
+ continue;
+
+ ValuesGroups * values_groups(0);
+ try
+ {
+ std::tr1::shared_ptr<PackageDepSpec> d(new PackageDepSpec(parse_user_package_dep_spec(
+ tokens.at(0), _imp->params.environment(),
+ UserPackageDepSpecOptions() + updso_allow_wildcards + updso_no_disambiguation + updso_throw_if_set)));
+
+ if (d->additional_requirements_ptr())
+ {
+ Log::get_instance()->message("paludislike_options_conf.bad_spec", ll_warning, lc_context)
+ << "Dependency specification '" << stringify(*d)
+ << "' includes use requirements, which cannot be used in '" << f << "'";
+ continue;
+ }
+
+ if (d->package_ptr())
+ {
+ SpecificSpecs::iterator i(_imp->specific_specs.insert(std::make_pair(
+ *d->package_ptr(),
+ SpecsWithValuesGroups())).first);
+ values_groups = &i->second.insert(i->second.end(),
+ make_named_values<SpecWithValuesGroups>(
+ value_for<n::spec>(*d),
+ value_for<n::values_groups>(ValuesGroups())
+ ))->values_groups();
+ }
+ else
+ {
+ values_groups = &_imp->wildcard_specs.insert(_imp->wildcard_specs.end(),
+ make_named_values<SpecWithValuesGroups>(
+ value_for<n::spec>(*d),
+ value_for<n::values_groups>(ValuesGroups())
+ ))->values_groups();
+ }
+ }
+ catch (const GotASetNotAPackageDepSpec &)
+ {
+ SetName n(tokens.at(0));
+
+ const std::tr1::shared_ptr<const SetSpecTree> set(_imp->params.environment()->set(n));
+ if (! set)
+ {
+ Log::get_instance()->message("paludislike_options_conf.bad_set", ll_warning, lc_context)
+ << "Set '" << n << "' in '" << f << "' does not exist";
+ continue;
+ }
+
+ values_groups = &_imp->set_specs.insert(_imp->set_specs.end(),
+ make_named_values<SetNameWithValuesGroups>(
+ value_for<n::set_name>(n),
+ value_for<n::values_groups>(ValuesGroups())
+ ))->values_groups();
+ }
+
+ if (! values_groups)
+ throw InternalError(PALUDIS_HERE, "huh?");
+
+ ValuesGroup * values_group(0);
+
+ for (std::vector<std::string>::const_iterator t(next(tokens.begin())), t_end(tokens.end()) ;
+ t != t_end ; ++t)
+ {
+ if (t->empty())
+ continue;
+
+ if (':' == t->at(t->length() - 1))
+ {
+ /* foo: */
+ std::string p;
+ std::transform(t->begin(), previous(t->end()), std::back_inserter(p), &::tolower);
+
+ values_group = &*values_groups->insert(values_groups->end(), make_named_values<ValuesGroup>(
+ value_for<n::minus_star>(false),
+ value_for<n::prefix>(ChoicePrefixName(p)),
+ value_for<n::values>(Values())
+ ));
+ }
+ else
+ {
+ /* if we don't have a foo: active, make one */
+ if (! values_group)
+ values_group = &*values_groups->insert(values_groups->end(), make_named_values<ValuesGroup>(
+ value_for<n::minus_star>(false),
+ value_for<n::prefix>(ChoicePrefixName("")),
+ value_for<n::values>(Values())
+ ));
+
+ if ("-*" == *t)
+ {
+ /* -* */
+ values_group->minus_star() = true;
+ }
+ else if ('-' == t->at(0))
+ {
+ /* -bar */
+ values_group->values().insert(make_named_values<Value>(
+ value_for<n::equals_value>(""),
+ value_for<n::minus>(true),
+ value_for<n::unprefixed_name>(UnprefixedChoiceName(t->substr(1)))
+ ));
+ }
+ else
+ {
+ std::string::size_type equals_p(t->find('='));
+ if (std::string::npos == equals_p)
+ {
+ /* foo */
+ values_group->values().insert(make_named_values<Value>(
+ value_for<n::equals_value>(""),
+ value_for<n::minus>(false),
+ value_for<n::unprefixed_name>(UnprefixedChoiceName(*t))
+ ));
+ }
+ else
+ {
+ /* foo=blah */
+ values_group->values().insert(make_named_values<Value>(
+ value_for<n::equals_value>(t->substr(equals_p + 1)),
+ value_for<n::minus>(false),
+ value_for<n::unprefixed_name>(UnprefixedChoiceName(t->substr(0, equals_p - 1)))
+ ));
+ }
+ }
+ }
+ }
+ }
+}
+
+namespace
+{
+ void check_values_groups(
+ const Environment * const,
+ const std::tr1::shared_ptr<const PackageID> &,
+ const std::tr1::shared_ptr<const Choice> & choice,
+ const UnprefixedChoiceName & unprefixed_name,
+ const ValuesGroups & values_groups,
+ bool & seen_minus_star,
+ Tribool & result_state,
+ std::string & result_value)
+ {
+
+ for (ValuesGroups::const_iterator i(values_groups.begin()), i_end(values_groups.end()) ;
+ i != i_end ; ++i)
+ {
+ if (i->prefix() != choice->prefix())
+ continue;
+
+ seen_minus_star = seen_minus_star || i->minus_star();
+
+ std::pair<Values::const_iterator, Values::const_iterator> range(i->values().equal_range(
+ make_named_values<Value>(
+ value_for<n::equals_value>(""),
+ value_for<n::minus>(false),
+ value_for<n::unprefixed_name>(unprefixed_name)
+ )));
+ for ( ; range.first != range.second ; ++range.first)
+ {
+ if (range.first->minus())
+ result_state = false;
+ else
+ result_state = true;
+
+ if (! (range.first->equals_value().empty()))
+ result_value = range.first->equals_value();
+ }
+ }
+ }
+
+ void collect_known_from_values_groups(
+ const Environment * const,
+ const std::tr1::shared_ptr<const PackageID> &,
+ const std::tr1::shared_ptr<const Choice> & choice,
+ const ValuesGroups & values_groups,
+ const std::tr1::shared_ptr<Set<UnprefixedChoiceName> > & known)
+ {
+
+ for (ValuesGroups::const_iterator i(values_groups.begin()), i_end(values_groups.end()) ;
+ i != i_end ; ++i)
+ {
+ if (i->prefix() != choice->prefix())
+ continue;
+
+ for (Values::const_iterator v(i->values().begin()), v_end(i->values().end()) ;
+ v != v_end ; ++v)
+ known->insert(v->unprefixed_name());
+ }
+ }
+
+ void check_specs_with_values_groups(
+ const Environment * const env,
+ const std::tr1::shared_ptr<const PackageID> & id,
+ const std::tr1::shared_ptr<const Choice> & choice,
+ const UnprefixedChoiceName & unprefixed_name,
+ const SpecsWithValuesGroups & specs_with_values_groups,
+ bool & seen_minus_star,
+ Tribool & result_state,
+ std::string & result_value)
+ {
+ for (SpecsWithValuesGroups::const_iterator i(specs_with_values_groups.begin()),
+ i_end(specs_with_values_groups.end()) ;
+ i != i_end ; ++i)
+ {
+ if (! match_package(*env, i->spec(), *id, MatchPackageOptions()))
+ continue;
+
+ check_values_groups(env, id, choice, unprefixed_name, i->values_groups(),
+ seen_minus_star, result_state, result_value);
+ }
+ }
+
+ void collect_known_from_specs_with_values_groups(
+ const Environment * const env,
+ const std::tr1::shared_ptr<const PackageID> & id,
+ const std::tr1::shared_ptr<const Choice> & choice,
+ const SpecsWithValuesGroups & specs_with_values_groups,
+ const std::tr1::shared_ptr<Set<UnprefixedChoiceName> > & known)
+ {
+ for (SpecsWithValuesGroups::const_iterator i(specs_with_values_groups.begin()),
+ i_end(specs_with_values_groups.end()) ;
+ i != i_end ; ++i)
+ {
+ if (! match_package(*env, i->spec(), *id, MatchPackageOptions()))
+ continue;
+
+ collect_known_from_values_groups(env, id, choice, i->values_groups(), known);
+ }
+ }
+}
+
+const Tribool
+PaludisLikeOptionsConf::want_choice_enabled(
+ const std::tr1::shared_ptr<const PackageID> & id,
+ const std::tr1::shared_ptr<const Choice> & choice,
+ const UnprefixedChoiceName & unprefixed_name
+ ) const
+{
+ Context context("When checking state of flag prefix '" + stringify(choice->prefix()) +
+ "' name '" + stringify(unprefixed_name) + "' for '" + stringify(*id) + "':");
+
+ bool seen_minus_star(false);
+ Tribool result(indeterminate);
+ std::string dummy;
+
+ /* Any specific matches? */
+ {
+ SpecificSpecs::const_iterator i(_imp->specific_specs.find(id->name()));
+ if (i != _imp->specific_specs.end())
+ {
+ check_specs_with_values_groups(_imp->params.environment(), id, choice, unprefixed_name, i->second,
+ seen_minus_star, result, dummy);
+ if (result.is_true())
+ return true;
+ else if (result.is_false())
+ return false;
+ }
+ }
+
+ /* Any set matches? */
+ {
+ for (SetNamesWithValuesGroups::const_iterator r(_imp->set_specs.begin()), r_end(_imp->set_specs.end()) ;
+ r != r_end ; ++r)
+ {
+ const std::tr1::shared_ptr<const SetSpecTree> set(_imp->params.environment()->set(r->set_name()));
+ if (! set)
+ throw InternalError(PALUDIS_HERE, "huh?");
+
+ if (! match_package_in_set(*_imp->params.environment(), *set, *id, MatchPackageOptions()))
+ continue;
+
+ check_values_groups(_imp->params.environment(), id, choice, unprefixed_name, r->values_groups(),
+ seen_minus_star, result, dummy);
+ }
+
+ if (result.is_true())
+ return true;
+ else if (result.is_false())
+ return false;
+ }
+
+ /* Wildcards? */
+ {
+ check_specs_with_values_groups(_imp->params.environment(), id, choice, unprefixed_name, _imp->wildcard_specs,
+ seen_minus_star, result, dummy);
+
+ if (result.is_true())
+ return true;
+ else if (result.is_false())
+ return false;
+ }
+
+ if (seen_minus_star)
+ return Tribool(false);
+ else
+ return indeterminate;
+}
+
+const std::string
+PaludisLikeOptionsConf::value_for_choice_parameter(
+ const std::tr1::shared_ptr<const PackageID> & id,
+ const std::tr1::shared_ptr<const Choice> & choice,
+ const UnprefixedChoiceName & unprefixed_name
+ ) const
+{
+ Context context("When checking value for flag prefix '" + stringify(choice->prefix()) +
+ "' name '" + stringify(unprefixed_name) + "' for '" + stringify(*id) + "':");
+
+ bool dummy_seen_minus_star(false);
+ Tribool dummy_result;
+ std::string equals_value;
+
+ /* Any specific matches? */
+ {
+ SpecificSpecs::const_iterator i(_imp->specific_specs.find(id->name()));
+ if (i != _imp->specific_specs.end())
+ {
+ check_specs_with_values_groups(_imp->params.environment(), id, choice, unprefixed_name, i->second,
+ dummy_seen_minus_star, dummy_result, equals_value);
+
+ if (! equals_value.empty())
+ return equals_value;
+ }
+ }
+
+ /* Any set matches? */
+ {
+ for (SetNamesWithValuesGroups::const_iterator r(_imp->set_specs.begin()), r_end(_imp->set_specs.end()) ;
+ r != r_end ; ++r)
+ {
+ const std::tr1::shared_ptr<const SetSpecTree> set(_imp->params.environment()->set(r->set_name()));
+ if (! set)
+ throw InternalError(PALUDIS_HERE, "huh?");
+
+ if (! match_package_in_set(*_imp->params.environment(), *set, *id, MatchPackageOptions()))
+ continue;
+
+ check_values_groups(_imp->params.environment(), id, choice, unprefixed_name, r->values_groups(),
+ dummy_seen_minus_star, dummy_result, equals_value);
+ }
+
+ if (! equals_value.empty())
+ return equals_value;
+ }
+
+ /* Wildcards? */
+ {
+ check_specs_with_values_groups(_imp->params.environment(), id, choice, unprefixed_name, _imp->wildcard_specs,
+ dummy_seen_minus_star, dummy_result, equals_value);
+
+ if (! equals_value.empty())
+ return equals_value;
+ }
+
+ return "";
+}
+
+const std::tr1::shared_ptr<const Set<UnprefixedChoiceName> >
+PaludisLikeOptionsConf::known_choice_value_names(
+ const std::tr1::shared_ptr<const PackageID> & id,
+ const std::tr1::shared_ptr<const Choice> & choice
+ ) const
+{
+ const std::tr1::shared_ptr<Set<UnprefixedChoiceName> > result(new Set<UnprefixedChoiceName>);
+
+ /* Any specific matches? */
+ {
+ SpecificSpecs::const_iterator i(_imp->specific_specs.find(id->name()));
+ if (i != _imp->specific_specs.end())
+ collect_known_from_specs_with_values_groups(_imp->params.environment(), id, choice, i->second, result);
+ }
+
+ /* Any set matches? */
+ {
+ for (SetNamesWithValuesGroups::const_iterator r(_imp->set_specs.begin()), r_end(_imp->set_specs.end()) ;
+ r != r_end ; ++r)
+ {
+ const std::tr1::shared_ptr<const SetSpecTree> set(_imp->params.environment()->set(r->set_name()));
+ if (! set)
+ throw InternalError(PALUDIS_HERE, "huh?");
+
+ if (! match_package_in_set(*_imp->params.environment(), *set, *id, MatchPackageOptions()))
+ continue;
+
+ collect_known_from_values_groups(_imp->params.environment(), id, choice, r->values_groups(), result);
+ }
+ }
+
+ /* Wildcards? */
+ {
+ collect_known_from_specs_with_values_groups(_imp->params.environment(), id, choice, _imp->wildcard_specs, result);
+ }
+
+ return result;
+}
+
+template class PrivateImplementationPattern<PaludisLikeOptionsConf>;
+
diff --git a/paludis/paludislike_options_conf.hh b/paludis/paludislike_options_conf.hh
new file mode 100644
index 0000000..ad31d36
--- /dev/null
+++ b/paludis/paludislike_options_conf.hh
@@ -0,0 +1,114 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2009 Ciaran McCreesh
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_PALUDISLIKE_OPTIONS_CONF_HH
+#define PALUDIS_GUARD_PALUDIS_PALUDISLIKE_OPTIONS_CONF_HH 1
+
+#include <paludis/paludislike_options_conf-fwd.hh>
+#include <paludis/util/attributes.hh>
+#include <paludis/util/private_implementation_pattern.hh>
+#include <paludis/util/named_value.hh>
+#include <paludis/util/tribool-fwd.hh>
+#include <paludis/util/set-fwd.hh>
+#include <paludis/util/fs_entry-fwd.hh>
+#include <paludis/util/config_file-fwd.hh>
+#include <paludis/choice-fwd.hh>
+#include <paludis/package_id-fwd.hh>
+#include <paludis/environment-fwd.hh>
+#include <tr1/memory>
+#include <tr1/functional>
+
+namespace paludis
+{
+ namespace n
+ {
+ struct environment;
+ struct make_config_file;
+ }
+
+ /**
+ * Turn an FSEntry into a config file for PaludisLikeOptionsConf.
+ *
+ * This might need to deal with weird things like bash config files, so we
+ * leave it up to the caller to specify how it works.
+ *
+ * \since 0.44
+ */
+ typedef std::tr1::function<
+ const std::tr1::shared_ptr<const LineConfigFile> (
+ const FSEntry &,
+ const LineConfigFileOptions &)
+ > PaludisLikeOptionsConfMakeConfigFileFunction;
+
+ /**
+ * Options for PaludisLikeOptionsConf.
+ *
+ * \since 0.44
+ */
+ struct PaludisLikeOptionsConfParams
+ {
+ NamedValue<n::environment, const Environment *> environment;
+ NamedValue<n::make_config_file, PaludisLikeOptionsConfMakeConfigFileFunction> make_config_file;
+ };
+
+ /**
+ * Common helper class for a Paludis-format use.conf or options.conf.
+ *
+ * The format is shared closely between PaludisEnvironment and the Exheres
+ * profile format for E repositories.
+ *
+ * \since 0.44
+ */
+ class PALUDIS_VISIBLE PaludisLikeOptionsConf :
+ private PrivateImplementationPattern<PaludisLikeOptionsConf>
+ {
+ public:
+ PaludisLikeOptionsConf(const PaludisLikeOptionsConfParams &);
+ ~PaludisLikeOptionsConf();
+
+ void add_file(const FSEntry &);
+
+ const Tribool want_choice_enabled(
+ const std::tr1::shared_ptr<const PackageID> &,
+ const std::tr1::shared_ptr<const Choice> &,
+ const UnprefixedChoiceName &
+ ) const
+ PALUDIS_ATTRIBUTE((warn_unused_result));
+
+ const std::string value_for_choice_parameter(
+ const std::tr1::shared_ptr<const PackageID> &,
+ const std::tr1::shared_ptr<const Choice> &,
+ const UnprefixedChoiceName &
+ ) const
+ PALUDIS_ATTRIBUTE((warn_unused_result));
+
+ const std::tr1::shared_ptr<const Set<UnprefixedChoiceName> > known_choice_value_names(
+ const std::tr1::shared_ptr<const PackageID> &,
+ const std::tr1::shared_ptr<const Choice> &
+ ) const
+ PALUDIS_ATTRIBUTE((warn_unused_result));
+ };
+
+#ifdef PALUDIS_HAVE_EXTERN_TEMPLATE
+ extern template class PrivateImplementationPattern<PaludisLikeOptionsConf>;
+#endif
+
+}
+
+#endif