[Aptitude-svn-commit] r3663 - in branches/aptitude-0.3/aptitude: .
src/generic
Daniel Burrows
dburrows at costa.debian.org
Sat Jul 23 19:11:05 UTC 2005
Author: dburrows
Date: Sat Jul 23 19:11:02 2005
New Revision: 3663
Modified:
branches/aptitude-0.3/aptitude/ChangeLog
branches/aptitude-0.3/aptitude/src/generic/matchers.cc
branches/aptitude-0.3/aptitude/src/generic/matchers.h
Log:
Add basic support for retrieving the string(s) corresponding to a pattern match.
Modified: branches/aptitude-0.3/aptitude/ChangeLog
==============================================================================
--- branches/aptitude-0.3/aptitude/ChangeLog (original)
+++ branches/aptitude-0.3/aptitude/ChangeLog Sat Jul 23 19:11:02 2005
@@ -1,3 +1,9 @@
+2005-07-23 Daniel Burrows <dburrows at debian.org>
+
+ * src/generic/matchers.cc, src/generic/matchers.h:
+
+ Add support for retrieving a string corresponding to a match.
+
2005-07-22 Daniel Burrows <dburrows at debian.org>
* doc/en/aptitude.xml:
Modified: branches/aptitude-0.3/aptitude/src/generic/matchers.cc
==============================================================================
--- branches/aptitude-0.3/aptitude/src/generic/matchers.cc (original)
+++ branches/aptitude-0.3/aptitude/src/generic/matchers.cc Sat Jul 23 19:11:02 2005
@@ -36,6 +36,8 @@
#include "../aptitude.h"
+#include <stdarg.h>
+
#include <apt-pkg/error.h>
#include <apt-pkg/pkgcache.h>
#include <apt-pkg/pkgrecords.h>
@@ -50,181 +52,491 @@
using namespace std;
-inline bool string_matches(regex_t *pattern, string s)
- // Altering this to support globs or regexps is all that's needed to add
- // support for those to the program (if that's done, the inline should be
- // removed :) )
+/** Used to cleanly abort without having to contort the code. */
+class CompilationException
{
- regmatch_t amount;
+ string reason;
+public:
+ CompilationException(const char *format,
+ ...)
+#ifdef __GNUG__
+ __attribute__ ((format (printf, 2, 3)))
+#endif
+ {
+ // eh, I should really move this to common code.
+ char buf[1024];
+ va_list args;
+
+ va_start(args, format);
+
+ vsnprintf(buf, sizeof(buf), format, args);
+
+ reason.assign(buf, 1024);
+ }
+
+ const string &get_msg() {return reason;}
+};
- return !regexec(pattern, s.c_str(), 1, &amount, 0);
+pkg_match_result::~pkg_match_result()
+{
}
-typedef bool (*mfunc)(regex_t *pattern, pkgCache::PkgIterator pkg, pkgCache::VerIterator ver);
+/** A common class to use when there's no interesting result. This is
+ * distinct from a match failure: an example would be the
+ * auto_matcher.
+ */
+class empty_match_result : public pkg_match_result
+{
+public:
+ unsigned int num_groups() {return 0;}
+
+ const string &group(unsigned int n) {abort();}
+};
-template<mfunc f>
-class pkg_string_matcher:public pkg_matcher
+class pkg_nonstring_matcher : public pkg_matcher
{
- regex_t pattern;
+public:
+ pkg_match_result *get_match(const pkgCache::PkgIterator &pkg,
+ const pkgCache::VerIterator &ver)
+ {
+ return matches(pkg, ver) ? new empty_match_result : NULL;
+ }
+};
+
+class unitary_result : public pkg_match_result
+{
+ string s;
+public:
+ unitary_result(const string &_s):s(_s) {}
+
+ unsigned int num_groups() {return 1;}
+
+ const string &group(unsigned int n)
+ {
+ if(n != 0)
+ abort();
+
+ return s;
+ }
+};
+
+class result_pair : public pkg_match_result
+{
+ pkg_match_result *r1, *r2;
+public:
+ result_pair(pkg_match_result *_r1,
+ pkg_match_result *_r2)
+ :r1(_r1), r2(_r2)
+ {
+ }
+
+ ~result_pair()
+ {
+ delete r1;
+ delete r2;
+ }
+
+ unsigned int num_groups()
+ {
+ return r1->num_groups() + r2->num_groups();
+ }
+
+ const string &group(unsigned int n)
+ {
+ unsigned int num_groups_r1 = r1->num_groups();
+
+ if(n < num_groups_r1)
+ return r1->group(n);
+ else
+ return r2->group(n - num_groups_r1);
+ }
+};
+
+class pkg_string_matcher : public pkg_matcher
+{
+ regex_t pattern_nogroup;
+ regex_t pattern_group;
+ bool pattern_nogroup_initialized:1;
+ bool pattern_group_initialized:1;
pkg_string_matcher()
{
}
- bool compile(string _pattern, bool flag_errors)
+ void do_compile(const string &_pattern,
+ regex_t &pattern,
+ int cflags)
{
- int err=regcomp(&pattern, _pattern.c_str(), REG_ICASE|REG_EXTENDED|REG_NOSUB);
+ int err=regcomp(&pattern, _pattern.c_str(), cflags);
if(err!=0)
{
- if(flag_errors)
- {
- size_t needed=regerror(err, &pattern, NULL, 0);
+ size_t needed=regerror(err, &pattern, NULL, 0);
- char *buf=new char[needed+1];
+ auto_ptr<char> buf(new char[needed+1]);
- regerror(err, &pattern, buf, needed+1);
+ regerror(err, &pattern, buf.get(), needed+1);
- _error->Error("Regex compilation error: %s", buf);
+ throw CompilationException("Regex compilation error: %s", buf.get());
+ }
+ }
- delete buf;
- }
+ void compile(const string &_pattern)
+ {
+ do_compile(_pattern, pattern_nogroup, REG_ICASE|REG_EXTENDED|REG_NOSUB);
+ pattern_nogroup_initialized=true;
- return false;
- }
+ do_compile(_pattern, pattern_group, REG_ICASE|REG_EXTENDED);
+ pattern_group_initialized=true;
+ }
+
+ class match_result : public pkg_match_result
+ {
+ // well, it's pretty much necessary to copy all the groups anyway
+ // :(
+ vector<string> matches;
+ public:
+ match_result(const char *s, regmatch_t *pmatch, int matches_len)
+ {
+ for(int i=0; i<matches_len && pmatch[i].rm_so>=0; ++i)
+ {
+ matches.push_back(string());
+ matches.back().assign(s, pmatch[i].rm_so,
+ pmatch[i].rm_eo-pmatch[i].rm_so);
+ }
+ }
+
+ unsigned int num_groups() {return matches.size();}
+ const string &group(unsigned int n) {return matches[n];}
+ };
+public:
+ pkg_string_matcher (const string &_pattern)
+ :pattern_nogroup_initialized(false),
+ pattern_group_initialized(false)
+ {
+ compile(_pattern);
+ }
+
+ ~pkg_string_matcher()
+ {
+ if(pattern_nogroup_initialized)
+ regfree(&pattern_nogroup);
+ if(pattern_group_initialized)
+ regfree(&pattern_group);
+ }
+
+ bool string_matches(const char *s)
+ {
+ return !regexec(&pattern_nogroup, s, 0, NULL, 0);
+ }
+
+ pkg_match_result *get_string_match(const char *s)
+ {
+ // ew. You need a hard limit here.
+ regmatch_t matches[30];
+
+ bool matched = (regexec(&pattern_group, s,
+ sizeof(matches)/sizeof(regmatch_t),
+ matches, 0) == 0);
+
+ if(!matched)
+ return NULL;
else
- return true;
+ return new match_result(s, matches,
+ sizeof(matches)/sizeof(regmatch_t));
}
+};
+
+typedef pair<bool, const char *> match_target;
+
+class pkg_trivial_string_matcher : public pkg_string_matcher
+{
public:
- static pkg_string_matcher<f> *init(string _pattern,
- bool flag_errors)
+ pkg_trivial_string_matcher (const string &s) : pkg_string_matcher(s)
{
- pkg_string_matcher<f> *rval=new pkg_string_matcher<f>;
+ }
- if(!rval->compile(_pattern, flag_errors))
- {
- delete rval;
- return NULL;
- }
+ // If the first element is false, the match fails; otherwise, it
+ // proceeds using the second element.
+ virtual match_target val(const pkgCache::PkgIterator &pkg,
+ const pkgCache::VerIterator &ver)=0;
+
+ bool matches(const pkgCache::PkgIterator &pkg,
+ const pkgCache::VerIterator &ver)
+ {
+ match_target v = val(pkg, ver);
+
+ if(!v.first)
+ return false;
else
- return rval;
+ return string_matches(v.second);
}
- ~pkg_string_matcher()
+ pkg_match_result *get_match(const pkgCache::PkgIterator &pkg,
+ const pkgCache::VerIterator &ver)
{
- regfree(&pattern);
+ match_target v = val(pkg, ver);
+
+ if(!v.first)
+ return NULL;
+ else
+ return get_string_match(v.second);
}
+};
+
+class pkg_name_matcher:public pkg_trivial_string_matcher
+{
+public:
+ pkg_name_matcher(const string &s):pkg_trivial_string_matcher(s) {}
- bool matches(pkgCache::PkgIterator pkg, pkgCache::VerIterator ver)
+ match_target val(const pkgCache::PkgIterator &pkg,
+ const pkgCache::VerIterator &ver)
{
- return f(&pattern, pkg, ver);
+ return match_target(true, pkg.Name());
}
};
-bool name_matches(regex_t *pattern, pkgCache::PkgIterator pkg, pkgCache::VerIterator ver)
+class pkg_description_matcher:public pkg_trivial_string_matcher
{
- return string_matches(pattern, pkg.Name());
-}
-typedef pkg_string_matcher<name_matches> pkg_name_matcher;
+public:
+ pkg_description_matcher(const string &s):pkg_trivial_string_matcher(s) {}
-bool description_matches(regex_t *pattern, pkgCache::PkgIterator pkg, pkgCache::VerIterator ver)
-{
- return !ver.end() && string_matches(pattern, apt_package_records->Lookup(ver.FileList()).LongDesc());
-}
-typedef pkg_string_matcher<description_matches> pkg_description_matcher;
+ match_target val(const pkgCache::PkgIterator &pkg,
+ const pkgCache::VerIterator &ver)
+ {
+ if(ver.end())
+ return match_target(false, "");
+ else
+ return match_target(true, apt_package_records->Lookup(ver.FileList()).LongDesc().c_str());
+ }
+};
-bool maintainer_matches(regex_t *pattern, pkgCache::PkgIterator pkg, pkgCache::VerIterator ver)
+class pkg_maintainer_matcher : public pkg_trivial_string_matcher
{
- return !ver.end() && string_matches(pattern, apt_package_records->Lookup(ver.FileList()).Maintainer());
-}
-typedef pkg_string_matcher<maintainer_matches> pkg_maintainer_matcher;
+public:
+ pkg_maintainer_matcher(const string &s):pkg_trivial_string_matcher(s)
+ {
+ }
+
+ match_target val(const pkgCache::PkgIterator &pkg,
+ const pkgCache::VerIterator &ver)
+ {
+ if(ver.end())
+ return match_target(false, "");
+ else
+ return match_target(true, apt_package_records->Lookup(ver.FileList()).Maintainer().c_str());
+ }
+};
-bool section_matches(regex_t *pattern, pkgCache::PkgIterator pkg, pkgCache::VerIterator ver)
+class pkg_section_matcher : public pkg_trivial_string_matcher
{
- return !ver.end() && ver.Section() && string_matches(pattern, ver.Section());
-}
-typedef pkg_string_matcher<section_matches> pkg_section_matcher;
+public:
+ pkg_section_matcher(const string &s):pkg_trivial_string_matcher(s)
+ {
+ }
+
+ match_target val(const pkgCache::PkgIterator &pkg,
+ const pkgCache::VerIterator &ver)
+ {
+ if(ver.end())
+ return match_target(false, "");
-bool version_matches(regex_t *pattern, pkgCache::PkgIterator pkg, pkgCache::VerIterator ver)
+ const char *s=ver.Section();
+
+ if(!s)
+ return match_target(false, "");
+
+ return match_target(true, s);
+ }
+};
+
+class pkg_version_matcher : public pkg_trivial_string_matcher
{
- return !ver.end() && ver.VerStr() && string_matches(pattern, ver.VerStr());
-}
-typedef pkg_string_matcher<version_matches> pkg_version_matcher;
+public:
+ pkg_version_matcher(const string &s) : pkg_trivial_string_matcher(s)
+ {
+ }
+
+ match_target val(const pkgCache::PkgIterator &pkg,
+ const pkgCache::VerIterator &ver)
+ {
+ if(ver.end())
+ return match_target(false, "");
+
+ const char *s=ver.VerStr();
+
+ if(!s)
+ return match_target(false, "");
+
+ return match_target(true, s);
+ }
+};
-bool task_matches(regex_t *pattern, pkgCache::PkgIterator pkg, pkgCache::VerIterator ver)
+class pkg_task_matcher : public pkg_string_matcher
{
- list<string> *l=get_tasks(pkg);
+public:
+ pkg_task_matcher(const string &s) : pkg_string_matcher(s)
+ {
+ }
+
+ bool matches(const pkgCache::PkgIterator &pkg,
+ const pkgCache::VerIterator &v)
+ {
+ list<string> *l=get_tasks(pkg);
+
+ if(!l)
+ return false;
+
+ for(list<string>::iterator i=l->begin();
+ i!=l->end();
+ ++i)
+ if(string_matches(i->c_str()))
+ return true;
- if(!l)
return false;
+ }
- for(list<string>::iterator i=l->begin();
- i!=l->end();
- ++i)
- if(string_matches(pattern, *i))
- return true;
+ // Uses the fact that the result returns NULL <=> nothing matched
+ pkg_match_result *get_match(pkgCache::PkgIterator &pkg,
+ pkgCache::VerIterator &ver)
+ {
+ list<string> *l=get_tasks(pkg);
- return false;
-}
-typedef pkg_string_matcher<task_matches> pkg_task_matcher;
+ if(!l)
+ return NULL;
+
+ for(list<string>::iterator i=l->begin();
+ i!=l->end();
+ ++i)
+ {
+ pkg_match_result *r=get_string_match(i->c_str());
+
+ if(r != NULL)
+ return r;
+ }
+
+ return NULL;
+ }
+};
// Package-file info matchers. Match a package if any of its
// available files (for all versions) match the given criteria.
//
// Should I use templates?
-bool origin_matches(regex_t *pattern,
- pkgCache::PkgIterator pkg,
- pkgCache::VerIterator ver)
+class pkg_origin_matcher : public pkg_string_matcher
{
- for(pkgCache::VerIterator v=pkg.VersionList(); !v.end(); ++v)
- for(pkgCache::VerFileIterator f=v.FileList(); !f.end(); ++f)
- {
- pkgCache::PkgFileIterator cur=f.File();
+public:
+ pkg_origin_matcher(const string &s) : pkg_string_matcher(s)
+ {
+ }
- if(!cur.end() && cur.Origin() && string_matches(pattern,
- cur.Origin()))
- return true;
- }
+ bool matches(const pkgCache::PkgIterator &pkg,
+ const pkgCache::VerIterator &ver)
+ {
+ for(pkgCache::VerIterator v=pkg.VersionList(); !v.end(); ++v)
+ for(pkgCache::VerFileIterator f=v.FileList(); !f.end(); ++f)
+ {
+ pkgCache::PkgFileIterator cur=f.File();
- return false;
-}
-typedef pkg_string_matcher<origin_matches> pkg_origin_matcher;
+ if(!cur.end() && cur.Origin() && string_matches(cur.Origin()))
+ return true;
+ }
+
+ return false;
+ }
+
+ pkg_match_result *get_match(const pkgCache::PkgIterator &pkg,
+ const pkgCache::VerIterator &ver)
+ {
+ for(pkgCache::VerIterator v=pkg.VersionList(); !v.end(); ++v)
+ for(pkgCache::VerFileIterator f=v.FileList(); !f.end(); ++f)
+ {
+ pkgCache::PkgFileIterator cur=f.File();
+
+ if(!cur.end() && cur.Origin())
+ {
+ pkg_match_result *r = get_string_match(cur.Origin());
+
+ if(r != NULL)
+ return r;
+ }
+ }
+
+ return NULL;
+ }
+};
-bool archive_matches(regex_t *pattern,
- pkgCache::PkgIterator pkg,
- pkgCache::VerIterator ver)
+class pkg_archive_matcher : public pkg_string_matcher
{
- if(ver.end() || ver.FileList().end())
+public:
+ pkg_archive_matcher(const string &s) : pkg_string_matcher(s)
+ {
+ }
+
+ bool matches(const pkgCache::PkgIterator &pkg,
+ const pkgCache::VerIterator &ver)
+ {
+ if(ver.end() || ver.FileList().end())
+ return false;
+
+ for(pkgCache::VerIterator v=pkg.VersionList(); !v.end(); ++v)
+ for(pkgCache::VerFileIterator f=v.FileList(); !f.end(); ++f)
+ {
+ pkgCache::PkgFileIterator cur=f.File();
+
+ if(!cur.end() && cur.Archive() && string_matches(cur.Archive()))
+ return true;
+ }
+
return false;
+ }
- for(pkgCache::VerIterator v=pkg.VersionList(); !v.end(); ++v)
- for(pkgCache::VerFileIterator f=v.FileList(); !f.end(); ++f)
- {
- pkgCache::PkgFileIterator cur=f.File();
+ pkg_match_result *get_match(const pkgCache::PkgIterator &pkg,
+ const pkgCache::VerIterator &ver)
+ {
+ if(ver.end() || ver.FileList().end())
+ return NULL;
- if(!cur.end() && cur.Archive() && string_matches(pattern,
- cur.Archive()))
- return true;
- }
+ for(pkgCache::VerIterator v=pkg.VersionList(); !v.end(); ++v)
+ for(pkgCache::VerFileIterator f=v.FileList(); !f.end(); ++f)
+ {
+ pkgCache::PkgFileIterator cur=f.File();
- return false;
-}
-typedef pkg_string_matcher<archive_matches> pkg_archive_matcher;
+ if(!cur.end() && cur.Archive())
+ {
+ pkg_match_result *r=get_string_match(cur.Archive());
+
+ if(r != NULL)
+ return r;
+ }
+ }
+
+ return NULL;
+ }
+};
class pkg_auto_matcher:public pkg_matcher
{
public:
- bool matches(pkgCache::PkgIterator pkg, pkgCache::VerIterator ver)
+ bool matches(const pkgCache::PkgIterator &pkg,
+ const pkgCache::VerIterator &ver)
{
return
(!pkg.CurrentVer().end() || (*apt_cache_file)[pkg].Install()) &&
((*apt_cache_file)->get_ext_state(pkg).install_reason!=aptitudeDepCache::manual);
}
+
+ pkg_match_result *get_match(const pkgCache::PkgIterator &pkg,
+ const pkgCache::VerIterator &ver)
+ {
+ return matches(pkg, ver) ? new unitary_result(_("Automatically Installed")) : NULL;
+ }
};
class pkg_broken_matcher:public pkg_matcher
{
public:
- bool matches(pkgCache::PkgIterator pkg, pkgCache::VerIterator ver)
+ bool matches(const pkgCache::PkgIterator &pkg,
+ const pkgCache::VerIterator &ver)
{
if(ver.end())
return false;
@@ -234,6 +546,12 @@
return state.NowBroken() || state.InstBroken();
}
}
+
+ pkg_match_result *get_match(const pkgCache::PkgIterator &pkg,
+ const pkgCache::VerIterator &ver)
+ {
+ return matches(pkg, ver) ? new unitary_result(_("Broken")) : NULL;
+ }
};
class pkg_priority_matcher:public pkg_matcher
@@ -243,15 +561,59 @@
pkg_priority_matcher(pkgCache::State::VerPriority _type)
:type(_type) {}
- bool matches(pkgCache::PkgIterator pkg, pkgCache::VerIterator ver)
+ bool matches(const pkgCache::PkgIterator &pkg,
+ const pkgCache::VerIterator &ver)
{
if(ver.end())
return false;
else
return ver->Priority == type;
}
+
+ pkg_match_result *get_match(const pkgCache::PkgIterator &pkg,
+ const pkgCache::VerIterator &ver)
+ {
+ if(ver.end())
+ return NULL;
+ else if(ver->Priority != type)
+ return NULL;
+ else
+ return new unitary_result(const_cast<pkgCache::VerIterator &>(ver).PriorityType());
+ }
};
+pkg_match_result *dep_match(const pkgCache::DepIterator &dep)
+{
+ string realization;
+
+ pkgCache::DepIterator start, end;
+
+ surrounding_or(dep, start, end);
+
+ bool first;
+
+ while(start != end)
+ {
+ if(!first)
+ realization += " | ";
+
+ realization += start.TargetPkg().Name();
+
+ if(start.TargetVer())
+ {
+ realization += " (";
+ realization += start.CompType();
+ realization += " ";
+ realization += start.TargetVer();
+ realization += ")";
+ }
+ }
+
+ // erm...
+ return new result_pair(new unitary_result(const_cast<pkgCache::DepIterator &>(dep).DepType()),
+ new unitary_result(realization));
+}
+
// Matches packages with unmet dependencies of a particular type.
class pkg_broken_type_matcher:public pkg_matcher
{
@@ -260,7 +622,8 @@
pkg_broken_type_matcher(pkgCache::Dep::DepType _type)
:type(_type) {}
- bool matches(pkgCache::PkgIterator pkg, pkgCache::VerIterator ver)
+ bool matches(const pkgCache::PkgIterator &pkg,
+ const pkgCache::VerIterator &ver)
{
if(ver.end())
return false;
@@ -284,6 +647,33 @@
}
return false;
}
+
+ pkg_match_result * get_match(const pkgCache::PkgIterator &pkg,
+ const pkgCache::VerIterator &ver)
+ {
+ if(ver.end())
+ return NULL;
+ else
+ {
+ pkgCache::DepIterator dep=ver.DependsList();
+
+ while(!dep.end())
+ {
+ // Skip to the end of the Or group to check GInstall
+ while(dep->CompareOp & pkgCache::Dep::Or)
+ ++dep;
+
+ if(dep->Type==type &&
+ !((*apt_cache_file)[dep]&pkgDepCache::DepGInstall))
+ // Oops, it's broken..
+ return dep_match(dep);
+
+ ++dep;
+ }
+ }
+
+ return NULL;
+ }
};
// This matches packages based on the action that will be taken with them.
@@ -300,7 +690,8 @@
{
}
- bool matches(pkgCache::PkgIterator pkg, pkgCache::VerIterator ver)
+ bool matches(const pkgCache::PkgIterator &pkg,
+ const pkgCache::VerIterator &ver)
{
if(require_purge &&
((*apt_cache_file)[pkg].iFlags & pkgDepCache::Purge) == 0)
@@ -332,24 +723,82 @@
}
}
}
+
+ pkg_match_result *get_match(const pkgCache::PkgIterator &pkg,
+ const pkgCache::VerIterator &ver)
+ {
+ if(!matches(pkg, ver))
+ return NULL;
+ else
+ switch(type)
+ {
+ case pkg_unchanged: // shouldn't happen (?)
+ return new unitary_result(_("Unchanged"));
+ case pkg_broken:
+ return new unitary_result(_("Broken"));
+ case pkg_unused_remove:
+ return new unitary_result(_("Remove [unused]"));
+ case pkg_auto_hold:
+ return new unitary_result(_("Hold [auto]"));
+ case pkg_auto_install:
+ return new unitary_result(_("Install [auto]"));
+ case pkg_auto_remove:
+ return new unitary_result(_("Remove [auto]"));
+ case pkg_downgrade:
+ return new unitary_result(_("Downgrade"));
+ case pkg_hold:
+ return new unitary_result(_("Hold"));
+ case pkg_reinstall:
+ return new unitary_result(_("Reinstall"));
+ case pkg_install:
+ return new unitary_result(_("Install"));
+ case pkg_remove:
+ return new unitary_result(_("Remove"));
+ case pkg_upgrade:
+ return new unitary_result(_("Upgrade"));
+ default:
+ // should never happen.
+ abort();
+ }
+ }
};
class pkg_keep_matcher:public pkg_matcher
{
- bool matches(pkgCache::PkgIterator pkg, pkgCache::VerIterator ver)
+ bool matches(const pkgCache::PkgIterator &pkg,
+ const pkgCache::VerIterator &ver)
{
return !pkg.CurrentVer().end() && (*apt_cache_file)[pkg].Keep();
}
+
+ pkg_match_result *get_match(const pkgCache::PkgIterator &pkg,
+ const pkgCache::VerIterator &ver)
+ {
+ if(!pkg.CurrentVer().end() && (*apt_cache_file)[pkg].Keep())
+ return new unitary_result(_("Keep"));
+ else
+ return NULL;
+ }
};
class pkg_virtual_matcher:public pkg_matcher
// Matches *pure* virtual packages -- ie, those that /have/ no versions.
{
public:
- bool matches(pkgCache::PkgIterator pkg, pkgCache::VerIterator ver)
+ bool matches(const pkgCache::PkgIterator &pkg,
+ const pkgCache::VerIterator &ver)
{
return pkg.VersionList().end();
}
+
+ pkg_match_result *get_match(const pkgCache::PkgIterator &pkg,
+ const pkgCache::VerIterator &ver)
+ {
+ if(!pkg.VersionList().end())
+ return NULL;
+ else
+ return new unitary_result(_("Virtual"));
+ }
};
class pkg_installed_matcher:public pkg_matcher
@@ -357,36 +806,66 @@
// *any* version of an installed package.
{
public:
- bool matches(pkgCache::PkgIterator pkg, pkgCache::VerIterator ver)
+ bool matches(const pkgCache::PkgIterator &pkg,
+ const pkgCache::VerIterator &ver)
{
return !pkg.CurrentVer().end();
}
+
+ pkg_match_result *get_match(const pkgCache::PkgIterator &pkg,
+ const pkgCache::VerIterator &ver)
+ {
+ if(pkg.CurrentVer().end())
+ return NULL;
+ else
+ return new unitary_result(_("Installed"));
+ }
};
class pkg_essential_matcher:public pkg_matcher
// Matches essential packages
{
public:
- bool matches(pkgCache::PkgIterator pkg, pkgCache::VerIterator ver)
+ bool matches(const pkgCache::PkgIterator &pkg,
+ const pkgCache::VerIterator &ver)
{
return
(pkg->Flags&pkgCache::Flag::Essential)==pkgCache::Flag::Essential ||
(pkg->Flags&pkgCache::Flag::Important)==pkgCache::Flag::Important;
}
+
+ pkg_match_result *get_match(const pkgCache::PkgIterator &pkg,
+ const pkgCache::VerIterator &ver)
+ {
+ if(!matches(pkg, ver))
+ return NULL;
+ else
+ return new unitary_result(_("Essential"));
+ }
};
class pkg_configfiles_matcher:public pkg_matcher
// Matches a package which was removed but has config files remaining
{
public:
- bool matches(pkgCache::PkgIterator pkg, pkgCache::VerIterator ver)
+ bool matches(const pkgCache::PkgIterator &pkg,
+ const pkgCache::VerIterator &ver)
{
return pkg->CurrentState==pkgCache::State::ConfigFiles;
}
+
+ // ???
+ pkg_match_result *get_match(const pkgCache::PkgIterator &pkg,
+ const pkgCache::VerIterator &ver)
+ {
+ if(pkg->CurrentState == pkgCache::State::ConfigFiles)
+ return new unitary_result(_("Config Files Remain"));
+ else
+ return NULL;
+ }
};
// Matches packages with a dependency on the given pattern.
-// FIXME: make this more general (for recommends, eg?)
class pkg_dep_matcher:public pkg_matcher
{
private:
@@ -401,7 +880,8 @@
}
~pkg_dep_matcher() {delete pattern;}
- bool matches(pkgCache::PkgIterator pkg, pkgCache::VerIterator ver)
+ bool matches(const pkgCache::PkgIterator &pkg,
+ const pkgCache::VerIterator &ver)
{
assert(!pkg.end());
if(ver.end())
@@ -410,8 +890,8 @@
for(pkgCache::DepIterator dep=ver.DependsList(); !dep.end(); ++dep)
{
if( (type == dep->Type) ||
- (type==pkgCache::Dep::Depends &&
- dep->Type==pkgCache::Dep::PreDepends))
+ (type == pkgCache::Dep::Depends &&
+ dep->Type == pkgCache::Dep::PreDepends))
{
// See if a versionless match works,.
if(dep.TargetPkg().VersionList().end() &&
@@ -429,41 +909,141 @@
return false;
}
+
+ pkg_match_result *get_match(const pkgCache::PkgIterator &pkg,
+ const pkgCache::VerIterator &ver)
+ {
+ assert(!pkg.end());
+ if(ver.end())
+ return NULL;
+
+ for(pkgCache::DepIterator dep=ver.DependsList(); !dep.end(); ++dep)
+ {
+ if( (type == dep->Type) ||
+ (type == pkgCache::Dep::Depends &&
+ dep->Type == pkgCache::Dep::PreDepends))
+ {
+ // See if a versionless match works,.
+ if(dep.TargetPkg().VersionList().end())
+ {
+ pkg_match_result *r=pattern->get_match(dep.TargetPkg(), dep.TargetPkg().VersionList());
+
+ if(r)
+ return new result_pair(r, dep_match(dep));
+ }
+
+ for(pkgCache::VerIterator i=dep.TargetPkg().VersionList(); !i.end(); i++)
+ if(_system->VS->CheckDep(i.VerStr(), dep->CompareOp, dep.TargetVer()))
+ {
+ pkg_match_result *r = pattern->get_match(dep.TargetPkg(), i);
+
+ if(r)
+ return new result_pair(r, dep_match(dep));
+ }
+ }
+ }
+
+ return false;
+ }
};
class pkg_or_matcher:public pkg_matcher
{
pkg_matcher *left,*right;
public:
- pkg_or_matcher(pkg_matcher *_left, pkg_matcher *_right):left(_left),right(_right) {}
- bool matches(pkgCache::PkgIterator pkg, pkgCache::VerIterator ver)
+ pkg_or_matcher(pkg_matcher *_left, pkg_matcher *_right)
+ :left(_left),right(_right)
+ {
+ }
+
+ bool matches(const pkgCache::PkgIterator &pkg,
+ const pkgCache::VerIterator &ver)
{
return left->matches(pkg, ver) || right->matches(pkg, ver);
}
- ~pkg_or_matcher() {delete left; delete right;}
+
+ pkg_match_result *get_match(const pkgCache::PkgIterator &pkg,
+ const pkgCache::VerIterator &ver)
+ {
+ pkg_match_result *lr = left->get_match(pkg, ver);
+
+ if(lr != NULL)
+ return lr;
+ else
+ return right->get_match(pkg, ver);
+ }
+
+ ~pkg_or_matcher()
+ {
+ delete left;
+ delete right;
+ }
};
class pkg_and_matcher:public pkg_matcher
{
pkg_matcher *left,*right;
public:
- pkg_and_matcher(pkg_matcher *_left, pkg_matcher *_right):left(_left),right(_right) {}
- bool matches(pkgCache::PkgIterator pkg, pkgCache::VerIterator ver)
+ pkg_and_matcher(pkg_matcher *_left, pkg_matcher *_right)
+ :left(_left),right(_right)
+ {
+ }
+
+ bool matches(const pkgCache::PkgIterator &pkg,
+ const pkgCache::VerIterator &ver)
{
return left->matches(pkg, ver) && right->matches(pkg, ver);
}
- ~pkg_and_matcher() {delete left; delete right;}
+
+ pkg_match_result *get_match(const pkgCache::PkgIterator &pkg,
+ const pkgCache::VerIterator &ver)
+ {
+ pkg_match_result *r1 = left->get_match(pkg, ver);
+
+ if(r1 == NULL)
+ return NULL;
+
+ pkg_match_result *r2 = right->get_match(pkg, ver);
+
+ if(r2 == NULL)
+ {
+ delete r1;
+ return NULL;
+ }
+
+ return new result_pair(r1, r2);
+ }
+
+ ~pkg_and_matcher()
+ {
+ delete left;
+ delete right;
+ }
};
class pkg_not_matcher:public pkg_matcher
{
pkg_matcher *child;
public:
- pkg_not_matcher(pkg_matcher *_child):child(_child) {}
- bool matches(pkgCache::PkgIterator pkg, pkgCache::VerIterator ver)
+ pkg_not_matcher(pkg_matcher *_child)
+ :child(_child)
+ {
+ }
+
+ bool matches(const pkgCache::PkgIterator &pkg,
+ const pkgCache::VerIterator &ver)
{
return !child->matches(pkg, ver);
}
+
+ // Eh, there isn't really a good choice about what to return here...
+ // just return what the child does. :(
+ pkg_match_result *get_match(const pkgCache::PkgIterator &pkg,
+ const pkgCache::VerIterator &ver)
+ {
+ return child->get_match(pkg, ver);
+ }
+
~pkg_not_matcher() {delete child;}
};
@@ -473,13 +1053,23 @@
public:
pkg_garbage_matcher() {}
- bool matches(pkgCache::PkgIterator pkg, pkgCache::VerIterator ver)
+ bool matches(const pkgCache::PkgIterator &pkg,
+ const pkgCache::VerIterator &ver)
{
if(ver.end())
return false;
else
return (*apt_cache_file)->get_ext_state(pkg).garbage;
}
+
+ pkg_match_result *get_match(const pkgCache::PkgIterator &pkg,
+ const pkgCache::VerIterator &ver)
+ {
+ if(!matches(pkg, ver))
+ return NULL;
+ else
+ return new unitary_result(_("Garbage"));
+ }
};
// A dummy matcher that matches any package.
@@ -488,10 +1078,17 @@
public:
pkg_true_matcher() {}
- bool matches(pkgCache::PkgIterator pkg, pkgCache::VerIterator ver)
+ bool matches(const pkgCache::PkgIterator &pkg,
+ const pkgCache::VerIterator &ver)
{
return true;
}
+
+ pkg_match_result *get_match(const pkgCache::PkgIterator &pkg,
+ const pkgCache::VerIterator &ver)
+ {
+ return new empty_match_result;
+ }
};
// A dummy matcher that matches no packages.
@@ -500,10 +1097,17 @@
public:
pkg_false_matcher() {}
- bool matches(pkgCache::PkgIterator pkg, pkgCache::VerIterator ver)
+ bool matches(const pkgCache::PkgIterator &pkg,
+ const pkgCache::VerIterator &ver)
{
return false;
}
+
+ pkg_match_result *get_match(const pkgCache::PkgIterator &pkg,
+ const pkgCache::VerIterator &ver)
+ {
+ return NULL;
+ }
};
// Matches packages which have a dependency of the given type declared
@@ -516,7 +1120,8 @@
pkg_matcher *pattern;
public:
pkg_revdep_matcher(pkgCache::Dep::DepType _type,
- pkg_matcher *_pattern):type(_type), pattern(_pattern)
+ pkg_matcher *_pattern)
+ :type(_type), pattern(_pattern)
{
}
@@ -525,7 +1130,8 @@
delete pattern;
}
- bool matches(pkgCache::PkgIterator pkg, pkgCache::VerIterator ver)
+ bool matches(const pkgCache::PkgIterator &pkg,
+ const pkgCache::VerIterator &ver)
{
// Check direct dependencies.
for(pkgCache::DepIterator d=pkg.RevDependsList(); !d.end(); ++d)
@@ -555,6 +1161,52 @@
return false;
}
+
+ // Too much duplication, can I factor out the common stuff here?
+ // C++ doesn't make it easy..
+ //
+ // Maybe I should just forget trying to be efficient and base
+ // everything on match results..
+ pkg_match_result *get_match(const pkgCache::PkgIterator &pkg,
+ const pkgCache::VerIterator &ver)
+ {
+ // Check direct dependencies.
+ for(pkgCache::DepIterator d=pkg.RevDependsList(); !d.end(); ++d)
+ {
+ if((d->Type==type ||
+ (type==pkgCache::Dep::Depends && d->Type==pkgCache::Dep::PreDepends)) &&
+ (!d.TargetVer() || (!ver.end() &&
+ _system->VS->CheckDep(ver.VerStr(), d->CompareOp, d.TargetVer()))))
+ {
+ pkg_match_result *r = pattern->get_match(d.ParentPkg(),
+ d.ParentVer());
+
+ if(r != NULL)
+ return new result_pair(r, dep_match(d));
+ }
+ }
+
+ // Check dependencies through virtual packages. ie, things that Depend
+ // on stuff this package [version] Provides.
+ if(!ver.end())
+ for(pkgCache::PrvIterator p=ver.ProvidesList(); !p.end(); ++p)
+ {
+ for(pkgCache::DepIterator d=p.ParentPkg().RevDependsList();
+ !d.end(); ++d)
+ {
+ // Only unversioned dependencies can match here.
+ if(d->Type==type && !d.TargetVer())
+ {
+ pkg_match_result *r = pattern->get_match(d.ParentPkg(),
+ d.ParentVer());
+ if(r != NULL)
+ return new result_pair(r, dep_match(d));
+ }
+ }
+ }
+
+ return NULL;
+ }
};
@@ -565,14 +1217,18 @@
{
pkg_matcher *pattern;
public:
- pkg_provides_matcher(pkg_matcher *_pattern):pattern(_pattern) {}
+ pkg_provides_matcher(pkg_matcher *_pattern)
+ :pattern(_pattern)
+ {
+ }
~pkg_provides_matcher()
{
delete pattern;
}
- bool matches(pkgCache::PkgIterator pkg, pkgCache::VerIterator ver)
+ bool matches(const pkgCache::PkgIterator &pkg,
+ const pkgCache::VerIterator &ver)
{
if(ver.end())
return false;
@@ -586,6 +1242,23 @@
return false;
}
+
+ pkg_match_result *get_match(const pkgCache::PkgIterator &pkg,
+ const pkgCache::VerIterator &ver)
+ {
+ if(ver.end())
+ return NULL;
+
+ for(pkgCache::PrvIterator p=ver.ProvidesList(); !p.end(); ++p)
+ {
+ pkg_match_result *r = pattern->get_match(p.ParentPkg(), pkgCache::VerIterator(*apt_cache_file));
+
+ if(r != NULL)
+ return new result_pair(r, new unitary_result(_("Provides")));
+ }
+
+ return false;
+ }
};
/** Matches packages which are provided by a package that fits the
@@ -595,14 +1268,18 @@
{
pkg_matcher *pattern;
public:
- pkg_revprv_matcher(pkg_matcher *_pattern):pattern(_pattern) {}
+ pkg_revprv_matcher(pkg_matcher *_pattern)
+ :pattern(_pattern)
+ {
+ }
~pkg_revprv_matcher()
{
delete pattern;
}
- bool matches(pkgCache::PkgIterator pkg, pkgCache::VerIterator ver)
+ bool matches(const pkgCache::PkgIterator &pkg,
+ const pkgCache::VerIterator &ver)
{
for(pkgCache::PrvIterator p=pkg.ProvidesList(); !p.end(); ++p)
{
@@ -612,21 +1289,40 @@
return false;
}
+
+ pkg_match_result *get_match(const pkgCache::PkgIterator &pkg,
+ const pkgCache::VerIterator &ver)
+ {
+ for(pkgCache::PrvIterator p=pkg.ProvidesList(); !p.end(); ++p)
+ {
+ pkg_match_result *r = pattern->get_match(p.OwnerPkg(),
+ p.OwnerVer());
+
+ if(r != NULL)
+ return new result_pair(r,
+ new unitary_result(_("Provided by")));
+ }
+
+ return false;
+ }
};
// Now back from the dead..it seems some people were actually using it ;-)
//
// Matches (non-virtual) packages which no installed package declares
-// an "important" dependency of the given type on.
+// an "important" dependency on.
//
// Note that the notion of "importantness" is affected by the current
// settings!
class pkg_norevdep_matcher:public pkg_matcher
{
public:
- pkg_norevdep_matcher() {}
+ pkg_norevdep_matcher()
+ {
+ }
- bool matches(pkgCache::PkgIterator pkg, pkgCache::VerIterator ver)
+ bool matches(const pkgCache::PkgIterator &pkg,
+ const pkgCache::VerIterator &ver)
{
if(ver.end())
return false;
@@ -646,6 +1342,15 @@
return true;
}
}
+
+ pkg_match_result *get_match(const pkgCache::PkgIterator &pkg,
+ const pkgCache::VerIterator &ver)
+ {
+ if(!matches(pkg, ver))
+ return NULL;
+ else
+ return new unitary_result(_("No reverse dependencies"));
+ }
};
// Matches (non-virtual) packages which no installed package declares
@@ -655,9 +1360,12 @@
pkgCache::Dep::DepType type; // Which type to match
public:
pkg_norevdep_type_matcher(pkgCache::Dep::DepType _type)
- :type(_type) {}
+ :type(_type)
+ {
+ }
- bool matches(pkgCache::PkgIterator pkg, pkgCache::VerIterator ver)
+ bool matches(const pkgCache::PkgIterator &pkg,
+ const pkgCache::VerIterator &ver)
{
if(ver.end())
return false;
@@ -677,12 +1385,22 @@
}
return true;
}
+
+ pkg_match_result *get_match(const pkgCache::PkgIterator &pkg,
+ const pkgCache::VerIterator &ver)
+ {
+ if(!matches(pkg, ver))
+ return NULL;
+ else
+ return new unitary_result(pkgCache::DepType(type));
+ }
};
class pkg_new_matcher:public pkg_matcher
{
public:
- bool matches(pkgCache::PkgIterator pkg, pkgCache::VerIterator ver)
+ bool matches(const pkgCache::PkgIterator &pkg,
+ const pkgCache::VerIterator &ver)
{
// Don't match virtual packages.
if(pkg.VersionList().end())
@@ -690,20 +1408,39 @@
else
return (*apt_cache_file)->get_ext_state(pkg).new_package;
}
+
+ pkg_match_result *get_match(const pkgCache::PkgIterator &pkg,
+ const pkgCache::VerIterator &ver)
+ {
+ if(!matches(pkg, ver))
+ return NULL;
+ else
+ return new unitary_result(_("New Package"));
+ }
};
class pkg_upgradable_matcher:public pkg_matcher
{
public:
- bool matches(pkgCache::PkgIterator pkg, pkgCache::VerIterator ver)
+ bool matches(const pkgCache::PkgIterator &pkg,
+ const pkgCache::VerIterator &ver)
{
return !pkg.CurrentVer().end() && (*apt_cache_file)[pkg].Upgradable();
}
+
+ pkg_match_result *get_match(const pkgCache::PkgIterator &pkg,
+ const pkgCache::VerIterator &ver)
+ {
+ if(!matches(pkg, ver))
+ return NULL;
+ else
+ return new unitary_result(_("Upgradable"));
+ }
};
// Parses a dependency type. Returns (ick) -1 if the type is not
// recognized.
-pkgCache::Dep::DepType parse_deptype(string s)
+pkgCache::Dep::DepType parse_deptype(const string &s)
{
if(!strcasecmp(s.c_str(), "depends"))
return pkgCache::Dep::Depends;
@@ -721,14 +1458,14 @@
return (pkgCache::Dep::DepType) -1;
}
-pkg_matcher *parse_condition_list(string s, unsigned int &loc,
- bool match_descriptions, bool flag_errors);
+pkg_matcher *parse_condition_list(const string &s, unsigned int &loc,
+ bool match_descriptions);
// Returns a substring up to the first metacharacter, including escaped
// metacharacters (parentheses, ~, |, and !)
//
// Advances loc to the first character of 's' following the escaped string.
-std::string parse_substr(string s, unsigned int &loc)
+std::string parse_substr(const string &s, unsigned int &loc)
{
std::string rval="";
bool done=false;
@@ -764,8 +1501,8 @@
return rval;
}
-pkg_matcher *parse_atom(string s, unsigned int &loc,
- bool search_descriptions, bool flag_errors)
+pkg_matcher *parse_atom(const string &s, unsigned int &loc,
+ bool search_descriptions)
{
std::string substr;
@@ -777,32 +1514,21 @@
if(s[loc]=='!')
{
loc++;
- pkg_matcher *atom=parse_atom(s, loc, search_descriptions, flag_errors);
- if(!atom)
- return NULL;
- return new pkg_not_matcher(atom);
+ return new pkg_not_matcher(parse_atom(s, loc, search_descriptions));
}
else if(s[loc]=='(')
// Recur into the list
{
loc++;
- pkg_matcher *lst=parse_condition_list(s, loc,
- search_descriptions,
- flag_errors);
- if(!lst)
- return NULL;
+ auto_ptr<pkg_matcher> lst(parse_condition_list(s, loc,
+ search_descriptions));
if(!(loc<s.size() && s[loc]==')'))
- {
- if(flag_errors)
- _error->Error(_("Unmatched '('"));
- delete lst;
- return NULL;
- }
+ throw CompilationException(_("Unmatched '('"));
else
{
loc++;
- return lst;
+ return lst.release();
}
}
else if(s[loc]=='~')
@@ -810,7 +1536,16 @@
if(loc+1==s.size())
{
loc++;
- return pkg_name_matcher::init("~", flag_errors);
+ if(!search_descriptions)
+ return new pkg_name_matcher("~");
+ else
+ {
+ auto_ptr<pkg_matcher> name(new pkg_name_matcher("~"));
+ auto_ptr<pkg_matcher> desc(new pkg_description_matcher(substr));
+
+ return new pkg_or_matcher(name.release(),
+ desc.release());
+ }
}
else
{
@@ -847,17 +1582,14 @@
case 'P':
case 'C':
{
- pkg_matcher *m=parse_atom(s, loc, search_descriptions, flag_errors);
-
- if(!m)
- return NULL;
+ auto_ptr<pkg_matcher> m(parse_atom(s, loc, search_descriptions));
switch(s[prevloc+1])
{
case 'C':
- return new pkg_dep_matcher(pkgCache::Dep::Conflicts, m);
+ return new pkg_dep_matcher(pkgCache::Dep::Conflicts, m.release());
case 'P':
- return new pkg_provides_matcher(m);
+ return new pkg_provides_matcher(m.release());
}
}
case 'D':
@@ -883,34 +1615,25 @@
type=parse_deptype(tname.c_str());
if(type==-1)
- {
- char buf[512];
- snprintf(buf, 512, _("Unknown dependency type: %s"),
- tname.c_str());
- if(flag_errors)
- _error->Error("%s", buf);
- return NULL;
- }
+ throw CompilationException(_("Unknown dependency type: %s"),
+ tname.c_str());
}
}
- pkg_matcher *m=parse_atom(s, loc, search_descriptions, flag_errors);
-
- if(!m)
- return NULL;
+ auto_ptr<pkg_matcher> m(parse_atom(s, loc, search_descriptions));
switch(s[prevloc+1])
{
case 'D':
if(do_provides)
- return new pkg_provides_matcher(m);
+ return new pkg_provides_matcher(m.release());
else
- return new pkg_dep_matcher(type, m);
+ return new pkg_dep_matcher(type, m.release());
case 'R':
if(do_provides)
- return new pkg_revprv_matcher(m);
+ return new pkg_revprv_matcher(m.release());
else
- return new pkg_revdep_matcher(type, m);
+ return new pkg_revdep_matcher(type, m.release());
}
}
default:
@@ -946,17 +1669,11 @@
return new pkg_keep_matcher;
else
- {
- char buf[512];
- snprintf(buf, 512, _("Unknown action type: %s"),
- substr.c_str());
- if(flag_errors)
- _error->Error("%s", buf);
- return NULL;
- }
+ throw CompilationException(_("Unknown action type: %s"),
+ substr.c_str());
}
case 'A':
- return pkg_archive_matcher::init(substr, flag_errors);
+ return new pkg_archive_matcher(substr);
case 'B':
{
pkgCache::Dep::DepType ptype=parse_deptype(substr);
@@ -964,25 +1681,19 @@
if(ptype!=-1)
return new pkg_broken_type_matcher(ptype);
else
- {
- char buf[512];
- snprintf(buf, 512, _("Unknown dependency type: %s"),
- substr.c_str());
- if(flag_errors)
- _error->Error("%s", buf);
- return NULL;
- }
+ throw CompilationException(_("Unknown dependency type: %s"),
+ substr.c_str());
}
case 'd':
- return pkg_description_matcher::init(substr, flag_errors);
+ return new pkg_description_matcher(substr);
case 'F':
return new pkg_false_matcher;
case 'm':
- return pkg_maintainer_matcher::init(substr, flag_errors);
+ return new pkg_maintainer_matcher(substr);
case 'n':
- return pkg_name_matcher::init(substr, flag_errors);
+ return new pkg_name_matcher(substr);
case 'O':
- return pkg_origin_matcher::init(substr, flag_errors);
+ return new pkg_origin_matcher(substr);
case 'p':
{
pkgCache::State::VerPriority type;
@@ -1010,38 +1721,21 @@
strcasecmp(s, (*apt_cache_file)->GetCache().Priority(pkgCache::State::Extra)) == 0))
type=pkgCache::State::Extra;
else
- {
- if(flag_errors)
- {
- char buf[512];
-
- snprintf(buf, 512, _("Unknown priority %s"),
- substr.c_str());
-
- _error->Error("%s", buf);
- }
-
- return NULL;
- }
+ throw CompilationException(_("Unknown priority %s"),
+ substr.c_str());
return new pkg_priority_matcher(type);
}
case 's':
- return pkg_section_matcher::init(substr, flag_errors);
+ return new pkg_section_matcher(substr);
case 't':
- return pkg_task_matcher::init(substr, flag_errors);
+ return new pkg_task_matcher(substr);
case 'T':
return new pkg_true_matcher;
case 'V':
- return pkg_version_matcher::init(substr, flag_errors);
+ return new pkg_version_matcher(substr);
default:
- {
- char buf[512];
- snprintf(buf, 512, _("Unknown pattern type: %c"), s[1]);
- if(flag_errors)
- _error->Error("%s", buf);
- return NULL;
- }
+ throw CompilationException(_("Unknown pattern type: %c"), s[1]);
}
}
}
@@ -1049,73 +1743,54 @@
else
{
if(!search_descriptions)
- return pkg_name_matcher::init(parse_substr(s, loc),
- flag_errors);
+ return new pkg_name_matcher(parse_substr(s, loc));
else
{
substr=parse_substr(s, loc);
- pkg_matcher *name=pkg_name_matcher::init(substr,
- flag_errors);
- pkg_matcher *desc=pkg_description_matcher::init(substr,
- flag_errors);
+ auto_ptr<pkg_matcher> name(new pkg_name_matcher(substr));
+ auto_ptr<pkg_matcher> desc(new pkg_description_matcher(substr));
- if(!name || !desc)
- {
- delete name;
- delete desc;
- return NULL;
- }
- else
- return new pkg_or_matcher(name, desc);
+ return new pkg_or_matcher(name.release(),
+ desc.release());
}
}
}
// If we get here, the string was empty.
- return NULL;
+ throw CompilationException(_("Can't search for \"\""));
}
-pkg_matcher *parse_and_group(string s, unsigned int &loc,
- bool search_descriptions,
- bool flag_errors)
+pkg_matcher *parse_and_group(const string &s, unsigned int &loc,
+ bool search_descriptions)
{
- pkg_matcher *rval=NULL;
+ auto_ptr<pkg_matcher> rval(NULL);
while(loc<s.size() && isspace(s[loc]))
loc++;
while(loc<s.size() && s[loc]!='|' && s[loc]!=')')
{
- pkg_matcher *atom=parse_atom(s, loc,
- search_descriptions, flag_errors);
- if(!atom)
- {
- delete rval;
- return NULL;
- }
+ auto_ptr<pkg_matcher> atom(parse_atom(s, loc,
+ search_descriptions));
- if(rval==NULL)
- rval=atom;
+ if(rval.get()==NULL)
+ rval = atom;
else
- rval=new pkg_and_matcher(rval, atom);
+ rval = auto_ptr<pkg_matcher>(new pkg_and_matcher(rval.release(), atom.release()));
while(loc<s.size() && isspace(s[loc]))
loc++;
}
- if(rval==NULL && flag_errors)
- _error->Error(_("Unexpected empty expression"));
- return rval;
+
+ if(rval.get()==NULL)
+ throw CompilationException(_("Unexpected empty expression"));
+
+ return rval.release();
}
-pkg_matcher *parse_condition_list(string s, unsigned int &loc,
- bool search_descriptions,
- bool flag_errors)
- // This (and the grammer) should be optimized to avoid deep recursion
- // what does the above line mean? -- DNB 11/21/01
-{
- pkg_matcher *grp=parse_and_group(s, loc, search_descriptions,
- flag_errors);
- if(!grp)
- return NULL;
+pkg_matcher *parse_condition_list(const string &s, unsigned int &loc,
+ bool search_descriptions)
+{
+ auto_ptr<pkg_matcher> grp(parse_and_group(s, loc, search_descriptions));
while(loc<s.size() && isspace(s[loc]))
loc++;
@@ -1125,33 +1800,25 @@
if(loc<s.size() && s[loc]=='|')
{
loc++;
- pkg_matcher *grp2=parse_condition_list(s, loc,
- search_descriptions,
- flag_errors);
- if(!grp2)
- {
- delete grp;
- return NULL;
- }
- return new pkg_or_matcher(grp, grp2);
+ auto_ptr<pkg_matcher> grp2(parse_condition_list(s, loc,
+ search_descriptions));
+
+ return new pkg_or_matcher(grp.release(), grp2.release());
}
else
- // We should never come here in a well-formed expression
- {
- delete grp;
- if(flag_errors)
- _error->Error(_("Badly formed expression"));
- return NULL;
- }
- // Or here.
+ throw CompilationException(_("Badly formed expression"));
+
+ // Note that this code should never execute:
while(loc<s.size() && isspace(s[loc]))
loc++;
}
- // Nothing else? Well..
- return grp;
+
+ // If there's no second element in the condition list, return its
+ // head.
+ return grp.release();
}
-pkg_matcher *parse_pattern(string s,
+pkg_matcher *parse_pattern(const string &s,
bool search_descriptions, bool flag_errors)
{
unsigned int loc=0;
@@ -1163,19 +1830,21 @@
if(loc==s.size())
return NULL;
- pkg_matcher *rval=parse_condition_list(s, loc,
- search_descriptions,
- flag_errors);
+ try
+ {
+ auto_ptr<pkg_matcher> rval(parse_condition_list(s, loc,
+ search_descriptions));
- if(rval==NULL)
- return NULL;
- else if(loc!=s.size())
+ if(loc!=s.size())
+ throw CompilationException(_("Unexpected ')'"));
+ else
+ return rval.release();
+ }
+ catch(CompilationException e)
{
if(flag_errors)
- _error->Error(_("Unexpected ')'"));
- delete rval;
+ _error->Error("%s", e.get_msg().c_str());
+
return NULL;
}
- else
- return rval;
}
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 Sat Jul 23 19:11:02 2005
@@ -25,13 +25,35 @@
#include <apt-pkg/pkgcache.h>
+/* For the cases where you want to investigate just what you matched a
+ * bit more thoroughly.
+ *
+ * A "group" is a string associated with this match. Matches may have
+ * any nonnegative number of groups, including 0 (in the case that
+ * there's no interesting string associated with the match).
+ */
+class pkg_match_result
+{
+public:
+ virtual unsigned int num_groups()=0;
+ virtual const std::string &group(unsigned int n)=0;
+ virtual ~pkg_match_result();
+};
+
class pkg_matcher
-// A closure describing a matching rule. Note that we match on a particular
-// version, not just on the package (this is because some attributes are pretty
-// meaningless for only a package)
+/** An object describing a matching rule. Note that we match on a
+ * particular version, not just on the package (this is because some
+ * attributes are pretty meaningless for only a package)
+ */
{
public:
- virtual bool matches(pkgCache::PkgIterator pkg, pkgCache::VerIterator ver)=0;
+ virtual bool matches(const pkgCache::PkgIterator &pkg,
+ const pkgCache::VerIterator &ver)=0;
+ /** \return a match result, or \b NULL if there is no match. It's
+ * the caller's responsibility to delete this.
+ */
+ virtual pkg_match_result *get_match(const pkgCache::PkgIterator &pkg,
+ const pkgCache::VerIterator &ver);
virtual ~pkg_matcher() {}
};
@@ -47,9 +69,12 @@
*
* \return the new matcher or \b NULL if an error occurs.
*/
-pkg_matcher *parse_pattern(string s, bool search_descriptions=false,
+pkg_matcher *parse_pattern(const string &s,
+ bool search_descriptions=false,
bool flag_errors=true);
-inline bool pkg_matches(string s, pkgCache::PkgIterator pkg, pkgCache::VerIterator ver)
+inline bool pkg_matches(const string &s,
+ const pkgCache::PkgIterator &pkg,
+ const pkgCache::VerIterator &ver)
{
pkg_matcher *m=parse_pattern(s);
if(!m)
More information about the Aptitude-svn-commit
mailing list