[Aptitude-svn-commit] r3704 - in branches/aptitude-0.3/aptitude: .
src src/generic
Daniel Burrows
dburrows at costa.debian.org
Fri Aug 5 05:04:30 UTC 2005
Author: dburrows
Date: Fri Aug 5 05:04:26 2005
New Revision: 3704
Modified:
branches/aptitude-0.3/aptitude/ChangeLog
branches/aptitude-0.3/aptitude/src/generic/matchers.h
branches/aptitude-0.3/aptitude/src/load_grouppolicy.cc
branches/aptitude-0.3/aptitude/src/pkg_grouppolicy.h
Log:
Rewrite the load_grouppolicy code to be a bit more general: it's now possible
to have actual syntactic entities inside a grouping policy -- say,
for instance, pattern matchers in the pattern match policy.
Modified: branches/aptitude-0.3/aptitude/ChangeLog
==============================================================================
--- branches/aptitude-0.3/aptitude/ChangeLog (original)
+++ branches/aptitude-0.3/aptitude/ChangeLog Fri Aug 5 05:04:26 2005
@@ -1,5 +1,16 @@
2005-08-04 Daniel Burrows <dburrows at debian.org>
+ * src/generic/matchers.h, src/load_grouppolicy.cc, src/pkg_grouppolicy.h:
+
+ Total rewrite of the load_grouppolicy code, and a few interface
+ changes to accomodate it. Instead of assuming a fully regular
+ syntax and splitting grouping declarations up-front,
+ load_grouppolicy now works by chaining parsers together, where
+ each parser implicitly pulls its text off as a side effect.
+ This will make nested policies feasible; it also means that the
+ pattern grouping policy should now work correctly even in the
+ presence of things like parentheses within the pattern.
+
* src/generic/matchers.cc, src/generic/matchers.h:
Change the parse_pattern interface again (and make it less
Modified: branches/aptitude-0.3/aptitude/src/generic/matchers.h
==============================================================================
--- branches/aptitude-0.3/aptitude/src/generic/matchers.h (original)
+++ branches/aptitude-0.3/aptitude/src/generic/matchers.h Fri Aug 5 05:04:26 2005
@@ -90,7 +90,7 @@
bool require_full_parse=true);
inline pkg_matcher *parse_pattern(const std::string &s,
- const std::vector<const char *> &terminators = std::vector<const char *>(),
+ const std::vector<const char *> &terminators,
bool search_descriptions = false,
bool flag_errors = true)
{
@@ -100,6 +100,16 @@
true);
}
+inline pkg_matcher *parse_pattern(const std::string &s,
+ bool search_descriptions = false,
+ bool flag_errors = true)
+{
+ std::string::const_iterator start = s.begin();
+ return parse_pattern(start, s.end(),
+ std::vector<const char *>(),
+ search_descriptions, flag_errors, true);
+}
+
inline bool pkg_matches(const string &s,
const pkgCache::PkgIterator &pkg,
const pkgCache::VerIterator &ver)
Modified: branches/aptitude-0.3/aptitude/src/load_grouppolicy.cc
==============================================================================
--- branches/aptitude-0.3/aptitude/src/load_grouppolicy.cc (original)
+++ branches/aptitude-0.3/aptitude/src/load_grouppolicy.cc Fri Aug 5 05:04:26 2005
@@ -9,6 +9,18 @@
// The parsers take an arglist and a chain argument, and return either a
// new pkg_grouppolicy_factory, or (if an error was encountered) NULL.
// (note: the chain argument will be NULL if the policy is the tail of a list)
+//
+// The astute observer will wonder why I don't just use bison or
+// something similar. The main reason is also the main reason I can't
+// just do a straightforward parse: the matcher grammar.
+// Unfortunately, it's hard to assemble grammars modularly in yacc,
+// and I don't want to duplicate the matchers' grammar in several
+// places; there's also the "minor" problem that the lexical analysis
+// of matchers is radically different from the rest of the constructs.
+//
+// TODO: a lot of classes just exist to complain about having
+// arguments and then creating a new instance of a policy0;
+// commonalize this.
#include "load_grouppolicy.h"
@@ -30,296 +42,598 @@
using namespace std;
-typedef vector<string> arglist;
-typedef pkg_grouppolicy_factory * (*pkg_grouppolicy_parser)(const arglist &,
- pkg_grouppolicy_factory *);
-typedef map<string, pkg_grouppolicy_parser> parser_map;
-
-static pkg_grouppolicy_factory *parse_section_policy(const arglist &args,
- pkg_grouppolicy_factory *chain)
-{
- int split_mode=pkg_grouppolicy_section_factory::split_none;
- bool passthrough=false;
-
- if(args.size()>=1)
- {
- if(!strcasecmp(args[0].c_str(), "none"))
- split_mode=pkg_grouppolicy_section_factory::split_none;
- else if(!strcasecmp(args[0].c_str(), "topdir"))
- split_mode=pkg_grouppolicy_section_factory::split_topdir;
- else if(!strcasecmp(args[0].c_str(), "subdir"))
- split_mode=pkg_grouppolicy_section_factory::split_subdir;
- else
- {
- _error->Error(_("Bad section name '%s' (use 'none', 'topdir', or 'subdir')"), args[0].c_str());
- return NULL;
- }
- }
-
- if(args.size()>=2)
- {
- if(!strcasecmp(args[1].c_str(), "passthrough"))
- passthrough=true;
- else if(!strcasecmp(args[1].c_str(), "nopassthrough"))
- passthrough=false;
- else
- {
- _error->Error(_("Bad passthrough setting '%s' (use 'passthrough' or 'nopassthrough')"),
- args[1].c_str());
- return NULL;
- }
- }
-
- if(args.size()>2)
- {
- _error->Error(_("Too many arguments to by-section grouping policy"));
- return NULL;
- }
-
- if(!chain)
- chain=new pkg_grouppolicy_end_factory;
-
- return new pkg_grouppolicy_section_factory(split_mode, passthrough, chain);
-}
-
-static pkg_grouppolicy_factory *parse_status_policy(const arglist &args,
- pkg_grouppolicy_factory *chain)
-{
- if(args.size()!=0)
- {
- _error->Error(_("By-status grouping policies take no arguments"));
- return NULL;
- }
-
- if(!chain)
- chain=new pkg_grouppolicy_end_factory;
-
- return new pkg_grouppolicy_status_factory(chain);
-}
-
-static pkg_grouppolicy_factory *parse_filter_policy(const arglist &args,
- pkg_grouppolicy_factory *chain)
-{
- if(args.size()!=1)
- {
- _error->Error(_("Exactly one filter name must be provided as an argument to a filter policy"));
- return NULL;
- }
-
- string s=args[0];
- stripws(s);
- // Backwards compatibility cruft:
- if(!strcasecmp(s.c_str(), "missing"))
- s = "~T";
-
- pkg_matcher *m = parse_pattern(s);
-
- if(m == NULL)
- {
- _error->Error(_("Bad pattern in filter policy: %s"), s.c_str());
- return NULL;
- }
- else
- return new pkg_grouppolicy_filter_factory(m, chain);
-}
-
-static pkg_grouppolicy_factory *parse_mode_policy(const arglist &args,
- pkg_grouppolicy_factory *chain)
-{
- if(args.size()!=0)
- {
- _error->Error(_("By-mode grouping policies take no arguments"));
- return NULL;
- }
-
- if(!chain)
- chain=new pkg_grouppolicy_end_factory;
-
- return new pkg_grouppolicy_mode_factory(chain);
-}
-
-static pkg_grouppolicy_factory *parse_firstchar_policy(const arglist &args,
- pkg_grouppolicy_factory *chain)
-{
- if(args.size()!=0)
- {
- _error->Error(_("First-character grouping policies take no arguments"));
- return NULL;
- }
-
- if(!chain)
- chain=new pkg_grouppolicy_end_factory;
-
- return new pkg_grouppolicy_firstchar_factory(chain);
-}
-
-static pkg_grouppolicy_factory *parse_ver_policy(const arglist &args,
- pkg_grouppolicy_factory *chain)
-{
- if(args.size()!=0)
- {
- _error->Error(_("Version-generating grouping policies take no arguments"));
- return NULL;
- }
-
- if(chain)
- {
- _error->Error(_("Version-generating grouping policies must be the tail of a chain"));
- return NULL;
- }
-
- return new pkg_grouppolicy_ver_factory;
-}
-
-static pkg_grouppolicy_factory *parse_dep_policy(const arglist &args,
- pkg_grouppolicy_factory *chain)
-{
- if(args.size()!=0)
- {
- _error->Error(_("Dep-generating grouping policies take no arguments"));
- return NULL;
- }
-
- if(chain)
- {
- _error->Error(_("Dep-generating grouping policies must be the tail of a chain"));
- return NULL;
- }
-
- return new pkg_grouppolicy_dep_factory;
-}
-
-static pkg_grouppolicy_factory *parse_priority_policy(const arglist &args,
- pkg_grouppolicy_factory *chain)
+class GroupParseException
{
- if(args.size()!=0)
- {
- _error->Error(_("By-priority grouping policies take no arguments"));
- return NULL;
- }
-
- if(!chain)
- chain=new pkg_grouppolicy_end_factory;
+ string msg;
+public:
+ GroupParseException(const char *format,
+ ...)
+#ifdef __GNUG__
+ __attribute__ ((format (printf, 2, 3)))
+#endif
+ {
+ va_list args;
+
+ va_start(args, format);
+
+ msg = vssprintf(format, args);
+
+ va_end(args);
+ }
+
+ const string &get_msg() const {return msg;}
+};
+
+// Since I fully parse grouping policies before instantiating them,
+// it's necessary to represent the parse "tree" here:
+
+/** Generic representation of a node in the grouping policy parse tree. */
+class group_policy_parse_node
+{
+public:
+ virtual ~group_policy_parse_node()
+ {
+ }
+
+ /** If \b true, the policy must be at the end of a chain and is
+ * expected to properly handle a \b NULL chain value. If \b false,
+ * it must not be at the end of a chain (chains will be
+ * automatically capped as necessary).
+ *
+ * By default, this returns \b false.
+ */
+ virtual bool terminal() {return false;}
+
+
+ /** Instantiates the corresponding grouping policy; chain will be
+ * \b NULL if no chain was created.
+ */
+ virtual pkg_grouppolicy_factory *instantiate(pkg_grouppolicy_factory *chain)=0;
+};
+
+/** Represents a parser for a particular type of argument. */
+class group_policy_parser
+{
+public:
+ virtual ~group_policy_parser()
+ {
+ }
+
+ /** Parse the given string range into a grouping policy. */
+ virtual group_policy_parse_node *parse(string::const_iterator &begin,
+ const string::const_iterator &end)=0;
+};
+
+
+
+template<class F>
+class policy_terminal_node0 : public group_policy_parse_node
+{
+public:
+ bool terminal()
+ {
+ return true;
+ }
+
+ pkg_grouppolicy_factory *instantiate(pkg_grouppolicy_factory *chain)
+ {
+ if(chain != NULL)
+ throw GroupParseException("Internal error: non-NULL chain passed to terminal policy");
+
+ return new F;
+ }
+};
+
+// stupid; apparently you can't use string literals as template args.
+typedef policy_terminal_node0<pkg_grouppolicy_end_factory> group_policy_end_node;
+
+/** A grouping policy node that pairs two others. */
+class group_policy_pair_node : public group_policy_parse_node
+{
+ class group_policy_parse_node *left, *right;
+public:
+ group_policy_pair_node(group_policy_parse_node *_left,
+ group_policy_parse_node *_right)
+ :left(_left), right(_right)
+ {
+ }
+
+ bool terminal()
+ {
+ return right->terminal();
+ }
+
+ ~group_policy_pair_node()
+ {
+ delete left;
+ delete right;
+ }
+
+ pkg_grouppolicy_factory *instantiate(pkg_grouppolicy_factory *chain)
+ {
+ return left->instantiate(right->instantiate(chain));
+ }
+};
+
+/** Convenience classes to generate grouping policy nodes that
+ * generate a particular type of factory.
+ */
+template<class F>
+class policy_node0 : public group_policy_parse_node
+{
+public:
+ pkg_grouppolicy_factory *instantiate(pkg_grouppolicy_factory *chain)
+ {
+ return new F(chain);
+ }
+};
+
+template<class F, typename A1>
+class policy_node1 : public group_policy_parse_node
+{
+ A1 arg1;
+public:
+ policy_node1(const A1 &_arg1) : arg1(_arg1)
+ {
+ }
+
+ pkg_grouppolicy_factory *instantiate(pkg_grouppolicy_factory *chain)
+ {
+ return new F(arg1, chain);
+ }
+};
+
+template<class F, typename A1, typename A2>
+class policy_node2 : public group_policy_parse_node
+{
+ A1 arg1;
+ A2 arg2;
+public:
+ policy_node2(const A1 &_arg1, const A2 &_arg2)
+ : arg1(_arg1), arg2(_arg2)
+ {
+ }
+
+ pkg_grouppolicy_factory *instantiate(pkg_grouppolicy_factory *chain)
+ {
+ return new F(arg1, arg2, chain);
+ }
+};
+
+
+
+
+// Generic parsers:
+
+/** Parse a grouping policy with no arguments. */
+template<class PN>
+class null_policy_parser : public group_policy_parser
+{
+public:
+ group_policy_parse_node *parse(string::const_iterator &,
+ const string::const_iterator &)
+ {
+ return new PN;
+ }
+};
+
+/** Parse a grouping policy based on a list. Looks for policy names,
+ * then starts parsing their parameters as necessary according to a
+ * table of parsers. Names must be alphanumeric; the occurance
+ * of a nonalphanumeric at the top level will terminate the parse.
+ */
+class list_policy_parser : public group_policy_parser
+{
+public:
+ typedef map<string, group_policy_parser *> parsemap;
+
+private:
+ const parsemap &parsers;
+public:
+ list_policy_parser(const parsemap &_parsers)
+ :parsers(_parsers)
+ {
+ }
+
+ group_policy_parse_node *parse(string::const_iterator &begin,
+ const string::const_iterator &end)
+ {
+ string name;
+ auto_ptr<group_policy_parse_node> rval(NULL);
+
+ while(begin != end)
+ {
+ string last = name;
+ name.clear();
+
+ // This might be a bit overly eager to eat commas, but it
+ // shouldn't do any harm.
+ while(begin != end && (isspace(*begin) || *begin == ','))
+ ++begin;
+
+ if(begin != end && !isalnum(*begin))
+ throw GroupParseException(_("Expected policy identifier, got '%c'"), *begin);
+
+ while(begin != end && isalnum(*begin))
+ {
+ name += *begin;
+ ++begin;
+ }
+
+ while(begin != end && isspace(*begin))
+ ++begin;
+
+ if(begin != end && *begin != ',' && *begin != '(')
+ throw GroupParseException(_("Expected ',' or '(', got '%c'"), *begin);
+
+ if(!name.empty())
+ {
+ parsemap::const_iterator found = parsers.find(name);
+
+ if(found == parsers.end())
+ throw GroupParseException(_("Unknown grouping policy \"%s\""),
+ name.c_str());
+ else
+ {
+ auto_ptr<group_policy_parse_node> curr(found->second->parse(begin, end));
+
+ if(rval.get() != NULL && rval.get()->terminal())
+ throw GroupParseException(_("Terminal policy \"%s\" should be the last policy in the list"), last.c_str());
+
+
+ if(rval.get() == NULL)
+ rval = curr;
+ else
+ rval = auto_ptr<group_policy_parse_node>(new group_policy_pair_node(rval.release(), curr.release()));
+ }
+ }
+ }
+
+ if(!rval->terminal())
+ rval = auto_ptr<group_policy_parse_node>(new group_policy_pair_node(rval.release(), new group_policy_end_node));
+
+ assert(rval->terminal());
+ return rval.release();
+ }
+};
+
+/** Parse a grouping policy based on a list of bare strings. */
+class string_policy_parser : public group_policy_parser
+{
+public:
+ virtual group_policy_parse_node *create_node(const vector<string> &args)=0;
+
+ group_policy_parse_node *parse(string::const_iterator &begin,
+ const string::const_iterator &end)
+ {
+ vector<string> args;
+
+ while(begin != end && isspace(*begin))
+ ++begin;
+
+ if(begin != end && *begin == '(')
+ {
+ ++begin;
+
+ while(begin != end && *begin != ')')
+ {
+ string::const_iterator oldbegin=begin;
+
+ while(begin != end && *begin != ')' && *begin != ',')
+ ++begin;
+
+ string val(oldbegin, begin);
+ stripws(val);
+ args.push_back(val);
+
+ if(begin != end && *begin == ',')
+ {
+ ++begin;
+ if(begin != end && *begin == ')')
+ args.push_back(string());
+ }
+ }
+ }
+
+ if(begin != end)
+ ++begin;
+
+ return create_node(args);
+ }
+};
+
+class section_policy_parser : public string_policy_parser
+{
+public:
+ group_policy_parse_node *create_node(const vector<string> &args)
+ {
+ int split_mode=pkg_grouppolicy_section_factory::split_none;
+ bool passthrough=false;
+
+ if(args.size() >= 1)
+ {
+ if(!strcasecmp(args[0].c_str(), "none"))
+ split_mode=pkg_grouppolicy_section_factory::split_none;
+ else if(!strcasecmp(args[0].c_str(), "topdir"))
+ split_mode=pkg_grouppolicy_section_factory::split_topdir;
+ else if(!strcasecmp(args[0].c_str(), "subdir"))
+ split_mode=pkg_grouppolicy_section_factory::split_subdir;
+ else
+ throw GroupParseException(_("Bad section name '%s' (use 'none', 'topdir', or 'subdir')"), args[0].c_str());
+ }
+
+ if(args.size() >= 2)
+ {
+ if(!strcasecmp(args[1].c_str(), "passthrough"))
+ passthrough=true;
+ else if(!strcasecmp(args[1].c_str(), "nopassthrough"))
+ passthrough=false;
+ else
+ throw GroupParseException(_("Bad passthrough setting '%s' (use 'passthrough' or 'nopassthrough')"),
+ args[1].c_str());
+ }
+
+ if(args.size()>2)
+ throw GroupParseException(_("Too many arguments to by-section grouping policy"));
+
+ return new policy_node2<pkg_grouppolicy_section_factory,
+ int, bool>(split_mode, passthrough);
+ }
+};
+
+class status_policy_parser : public string_policy_parser
+{
+public:
+ group_policy_parse_node *create_node(const vector<string> &args)
+ {
+ if(args.size()!=0)
+ throw GroupParseException(_("By-status grouping policies take no arguments"));
+
+ return new policy_node0<pkg_grouppolicy_status_factory>;
+ }
+};
+
+class filter_policy_parser : public group_policy_parser
+{
+public:
+ group_policy_parse_node *parse(string::const_iterator &begin,
+ const string::const_iterator &end)
+ {
+ // Backwards compatibility cruft:
+ static const string missing = "missing";
+ bool is_missing = true;
+
+ string::const_iterator begin2 = begin;
+ while(isspace(*begin2))
+ ++begin2;
+
+ for(string::const_iterator begin3 = missing.begin();
+ is_missing && begin2 != end && begin3 != missing.end(); ++begin2, ++begin3)
+ if(*begin2 != *begin3)
+ is_missing = false;
+
+ while(begin2 != end && isspace(*begin2))
+ ++begin2;
+
+ if(begin2 == end || *begin2 != ')')
+ is_missing = false;
+
+ if(is_missing)
+ {
+ pkg_matcher *m = parse_pattern("~T");
+ begin = begin2;
+ ++begin;
+
+ return new policy_node1<pkg_grouppolicy_filter_factory, pkg_matcher *>(m);
+ }
+ else
+ {
+ vector<const char *> terminators;
+ terminators.push_back(",");
+ terminators.push_back(")");
+
+ auto_ptr<pkg_matcher> m(parse_pattern(begin, end, terminators,
+ false, true, false));
+
+ if(m.get() == NULL)
+ throw GroupParseException(_("Unable to parse pattern at '%s'"),
+ string(begin, end).c_str());
+ else if(begin != end && *begin != ')')
+ {
+ assert(*begin == ',');
+ throw GroupParseException(_("Exactly one filter must be provided as an argument to a filter policy"));
+ }
+ else
+ {
+ if(begin != end)
+ ++begin;
+
+ return new policy_node1<pkg_grouppolicy_filter_factory, pkg_matcher *>(m.release());
+ }
+ }
+ }
+};
+
+class mode_policy_parser : public string_policy_parser
+{
+public:
+ group_policy_parse_node *create_node(const vector<string> &args)
+ {
+ if(args.size()!=0)
+ throw GroupParseException(_("By-mode grouping policies take no arguments"));
+
+ return new policy_node0<pkg_grouppolicy_mode_factory>;
+ }
+};
+
+class firstchar_policy_parser : public string_policy_parser
+{
+ group_policy_parse_node *create_node(const vector<string> &args)
+ {
+ if(args.size()!=0)
+ throw GroupParseException(_("First-character grouping policies take no arguments"));
+
+
+ return new policy_node0<pkg_grouppolicy_firstchar_factory>;
+ }
+};
+
+class ver_policy_parser : public string_policy_parser
+{
+ group_policy_parse_node *create_node(const vector<string> &args)
+ {
+ if(args.size()!=0)
+ throw GroupParseException(_("Version-generating grouping policies take no arguments"));
+
+ return new policy_terminal_node0<pkg_grouppolicy_ver_factory>;
+ }
+};
+
+class dep_policy_parser: public string_policy_parser
+{
+ group_policy_parse_node *create_node(const vector<string> &args)
+ {
+ if(args.size()!=0)
+ throw GroupParseException(_("Dep-generating grouping policies take no arguments"));
+
+ return new policy_terminal_node0<pkg_grouppolicy_dep_factory>;
+ }
+};
+
+class priority_policy_parser : public string_policy_parser
+{
+ group_policy_parse_node *create_node(const vector<string> &args)
+ {
+ if(args.size()!=0)
+ throw GroupParseException(_("By-priority grouping policies take no arguments"));
+
+ return new policy_node0<pkg_grouppolicy_priority_factory>;
+ }
+};
+
+class hier_policy_parser : public string_policy_parser
+{
+ group_policy_parse_node *create_node(const vector<string> &args)
+ {
+ if(!args.empty())
+ {
+ // FIXME: who deletes this??
+ pkg_hier *hier=new pkg_hier;
+
+ for(vector<string>::const_iterator i = args.begin();
+ i != args.end(); ++i)
+ hier->input_file(*i);
+
+ return new policy_node2<pkg_grouppolicy_hier_factory, pkg_hier *, bool>(hier, true);
+ }
+ else
+ return new policy_node2<pkg_grouppolicy_hier_factory, pkg_hier *, bool>(get_user_pkg_hier(), false);
+ }
+};
+
+class task_policy_parser : public string_policy_parser
+{
+ group_policy_parse_node *create_node(const vector<string> &args)
+ {
+ if(args.size()!=0)
+ throw GroupParseException(_("Task grouping policies take no arguments"));
+
+ return new policy_node0<pkg_grouppolicy_task_factory>;
+ }
+};
+
+class pattern_policy_parser : public group_policy_parser
+{
+ group_policy_parse_node *parse(string::const_iterator &begin,
+ const string::const_iterator &end)
+ {
+ while(begin != end && isspace(*begin))
+ ++begin;
+
+ if(begin == end || *begin != '(')
+ throw GroupParseException(_("Expected '(' after 'pattern'"));
+
+ ++begin;
+
+ while(begin != end && isspace(*begin))
+ ++begin;
+
+ if(begin == end || *begin == ')')
+ throw GroupParseException(_("Missing arguments to 'pattern'"));
+
+ vector<pkg_grouppolicy_matchers_factory::match_pair> subgroups;
+
+ vector<const char *> terminators;
+ terminators.push_back(",");
+ terminators.push_back("=>");
+
+ try
+ {
+ while(begin != end && *begin != ')')
+ {
+ string format = "\\1";
+
+ const string::const_iterator begin0 = begin;
+
+ auto_ptr<pkg_matcher> matcher(parse_pattern(begin, end,
+ terminators,
+ false, true, false));
+
+ if(matcher.get() == NULL)
+ throw GroupParseException(_("Unable to parse pattern after \"%s\""),
+ string(begin0, end).c_str());
+
+ if(begin != end && *begin == '=')
+ {
+ ++begin;
+
+ assert(begin != end && *begin == '>');
+
+ ++begin;
+
+ format.clear();
+
+ while(begin != end && *begin != ',' && *begin != ')')
+ {
+ format += *begin;
+ ++begin;
+ }
+
+ stripws(format);
+
+ if(format.empty())
+ throw GroupParseException(_("Unexpectedly empty tree title after \"%s\""),
+ string(begin0, end).c_str());
+ }
+
+ subgroups.push_back(pkg_grouppolicy_matchers_factory::match_pair(matcher.release(), transcode(format)));
+
+ if(begin != end && *begin == ',')
+ ++begin;
+ }
+
+ if(begin == end)
+ throw GroupParseException(_("Unmatched '(' in pattern grouping policy"));
+ else
+ {
+ assert(*begin == ')');
+ ++begin;
+ }
+
+ return new policy_node1<pkg_grouppolicy_matchers_factory, vector<pkg_grouppolicy_matchers_factory::match_pair> >(subgroups);
+ }
+ catch(...)
+ {
+ for(vector<pkg_grouppolicy_matchers_factory::match_pair>::const_iterator i = subgroups.begin();
+ i != subgroups.end(); ++i)
+ delete i->matcher;
+
+ throw;
+ }
+ }
+};
- return new pkg_grouppolicy_priority_factory(chain);
-}
-
-static pkg_grouppolicy_factory *parse_hier_policy(const arglist &args,
- pkg_grouppolicy_factory *chain)
-{
- if(!chain)
- chain=new pkg_grouppolicy_end_factory;
-
- if(!args.empty())
- {
- // FIXME: who deletes this??
- pkg_hier *hier=new pkg_hier;
-
- for(arglist::size_type i=0; i<args.size(); ++i)
- hier->input_file(args[i]);
-
- return new pkg_grouppolicy_hier_factory(hier, chain, true);
- }
- else
- return new pkg_grouppolicy_hier_factory(get_user_pkg_hier(), chain, false);
-}
-
-static pkg_grouppolicy_factory *parse_task_policy(const arglist &args,
- pkg_grouppolicy_factory *chain)
-{
- if(args.size()!=0)
- {
- _error->Error(_("Task grouping policies take no arguments"));
- return NULL;
- }
-
- if(!chain)
- chain=new pkg_grouppolicy_end_factory;
-
- return new pkg_grouppolicy_task_factory(chain);
-}
-
-static pkg_grouppolicy_factory *parse_matchers_policy(const arglist &args,
- pkg_grouppolicy_factory *chain)
-{
- if(args.size() == 0)
- {
- _error->Error(_("Match-based grouping policies require at least one parameter"));
- return NULL;
- }
-
- vector<pkg_grouppolicy_matchers_factory :: match_pair> subgroups;
-
- for(arglist::const_iterator i = args.begin();
- i != args.end(); ++i)
- {
- // Split each argument at the first occurance of "=>".
- string matcher, format="\\1";
- bool in_matcher=true;
-
- string::const_iterator j = i->begin();
-
- while(j != i->end() && in_matcher)
- {
- while(j != i->end() && *j != '=')
- {
- matcher+=*j;
- ++j;
- }
-
- if(j != i->end())
- {
- assert((*j) == '=');
-
- ++j;
-
- if(j == i->end() || *j != '>')
- matcher += '=';
- else
- {
- ++j;
- in_matcher = false;
- }
- }
- }
-
- if(!in_matcher)
- {
- format.clear();
-
- while(j != i->end())
- {
- format += *j;
- ++j;
- }
- }
-
- assert(j == i->end());
-
- stripws(format);
- stripws(matcher);
-
- pkg_matcher *m = parse_pattern(matcher);
-
- if(m == NULL)
- {
- for(vector<pkg_grouppolicy_matchers_factory :: match_pair> :: const_iterator i = subgroups.begin();
- i != subgroups.end(); ++i)
- delete i->matcher;
-
- return NULL;
- }
-
- subgroups.push_back(pkg_grouppolicy_matchers_factory :: match_pair(m, transcode(format)));
- }
-
- if(!chain)
- chain = new pkg_grouppolicy_end_factory;
-
- return new pkg_grouppolicy_matchers_factory(chain, subgroups);
-}
-
-static parser_map parse_types;
+static map<string, group_policy_parser *> parse_types;
static void init_parse_types()
{
@@ -327,19 +641,19 @@
if(!initted_parse_types)
{
- parse_types["section"]=parse_section_policy;
- parse_types["status"]=parse_status_policy;
- parse_types["action"]=parse_mode_policy;
- parse_types["filter"]=parse_filter_policy;
- parse_types["firstchar"]=parse_firstchar_policy;
-
- parse_types["versions"]=parse_ver_policy;
- parse_types["deps"]=parse_dep_policy;
- parse_types["priority"]=parse_priority_policy;
- parse_types["hier"]=parse_hier_policy;
- parse_types["task"]=parse_task_policy;
+ parse_types["section"]=new section_policy_parser;
+ parse_types["status"]=new status_policy_parser;
+ parse_types["action"]=new mode_policy_parser;
+ parse_types["filter"]=new filter_policy_parser;
+ parse_types["firstchar"]=new firstchar_policy_parser;
+
+ parse_types["versions"]=new ver_policy_parser;
+ parse_types["deps"]=new dep_policy_parser;
+ parse_types["priority"]=new priority_policy_parser;
+ parse_types["hier"]=new hier_policy_parser;
+ parse_types["task"]=new task_policy_parser;
- parse_types["pattern"]=parse_matchers_policy;
+ parse_types["pattern"]=new pattern_policy_parser;
initted_parse_types=true;
}
@@ -350,87 +664,22 @@
{
init_parse_types();
- typedef vector<pair<string, arglist> > temp_parse_list;
- temp_parse_list parsed;
-
- string::size_type i=0;
+ string::const_iterator begin = s.begin();
- while(i<s.size())
+ try
{
- pair<string, arglist> current;
+ auto_ptr<group_policy_parse_node> node(list_policy_parser(parse_types).parse(begin, s.end()));
- // Find the first name. Use tolower for nice case-insensitivity.
- while(i<s.size() && s[i]!=',' && s[i]!='(')
- current.first+=tolower(s[i++]);
-
- if(current.first.size()==0)
- {
- _error->Error(_("Invalid zero-length grouping policy name"));
- return NULL;
- }
-
- if(i<s.size() && s[i]=='(') // Parse argument list
- {
- while(i<s.size() && s[i]!=')')
- {
- ++i; // Clear out the leading '(' or ','
- string curarg;
- while(i<s.size() && s[i]!=',' && s[i]!=')')
- curarg+=s[i++];
-
- current.second.push_back(curarg);
- }
-
- if(!(i<s.size() && s[i]==')')) // Unexpected EOT, bail
- {
- _error->Error(_("Unmatched '(' in grouping policy description"));
- return NULL;
- }
+ assert(begin == s.end());
- ++i; // Clear out the ')'
- }
+ pkg_grouppolicy_factory *rval = node->instantiate(NULL);
- parsed.push_back(current);
-
- if(i<s.size() && s[i]==',')
- i++; // Clear out trailing commas.
+ return rval;
}
-
- // Now run through the parsed stuff from back-to-front and instantiate it.
- pkg_grouppolicy_factory *rval=NULL;
- temp_parse_list::reverse_iterator j=parsed.rbegin();
-
- while(j!=parsed.rend())
+ catch(GroupParseException e)
{
- // Look up the parse function
- parser_map::iterator found=parse_types.find(j->first);
-
- // Die gracefully if it's bad.
- if(found==parse_types.end())
- {
- _error->Error(_("Invalid grouping policy type '%s'"),
- j->first.c_str());
- delete rval;
- return NULL;
- }
-
- // Apply it to the argument list
- pkg_grouppolicy_factory *new_rval=found->second(j->second,
- rval);
-
- // Check for failure
- if(!new_rval)
- {
- delete rval;
- return NULL;
- }
+ _error->Error("%s", e.get_msg().c_str());
- rval=new_rval;
- ++j;
+ return NULL;
}
-
- if(!rval)
- rval=new pkg_grouppolicy_end_factory;
-
- return rval;
}
Modified: branches/aptitude-0.3/aptitude/src/pkg_grouppolicy.h
==============================================================================
--- branches/aptitude-0.3/aptitude/src/pkg_grouppolicy.h (original)
+++ branches/aptitude-0.3/aptitude/src/pkg_grouppolicy.h Fri Aug 5 05:04:26 2005
@@ -230,8 +230,8 @@
bool del_hier;
public:
pkg_grouppolicy_hier_factory(pkg_hier *_hier,
- pkg_grouppolicy_factory *_chain,
- bool _del_hier)
+ bool _del_hier,
+ pkg_grouppolicy_factory *_chain)
:hier(_hier), chain(_chain), del_hier(_del_hier)
{
}
@@ -281,8 +281,8 @@
std::vector<match_pair> subgroups;
public:
- pkg_grouppolicy_matchers_factory(pkg_grouppolicy_factory *_chain,
- const std::vector<match_pair> &_subgroups)
+ pkg_grouppolicy_matchers_factory(const std::vector<match_pair> &_subgroups,
+ pkg_grouppolicy_factory *_chain)
:chain(_chain), subgroups(_subgroups)
{
}
More information about the Aptitude-svn-commit
mailing list