[Aptitude-svn-commit] r3700 - in branches/aptitude-0.3/aptitude: . src/generic

Daniel Burrows dburrows at costa.debian.org
Wed Jul 27 15:38:51 UTC 2005


Author: dburrows
Date: Wed Jul 27 15:38:46 2005
New Revision: 3700

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:
First step towards more flexible parsing of matchers.

Modified: branches/aptitude-0.3/aptitude/ChangeLog
==============================================================================
--- branches/aptitude-0.3/aptitude/ChangeLog	(original)
+++ branches/aptitude-0.3/aptitude/ChangeLog	Wed Jul 27 15:38:46 2005
@@ -1,3 +1,14 @@
+2005-07-27  Daniel Burrows  <dburrows at debian.org>
+
+	* src/generic/matchers.cc, src/generic/matchers.h:
+
+	  Change the external and internal interfaces to use iterators
+	  rather than passing in a string and directly indexing into it.
+	  The start iterator is modified as a side-effect, which should
+	  eventually allow continuation-based parsing (i.e., just parse
+	  the first thing that looks like a match term and then stop).  I
+	  might need to think more about just how this will work, though.
+
 2005-07-26  Daniel Burrows  <dburrows at debian.org>
 
 	* tests/Makefile.am, tests/test_misc.cc:

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	Wed Jul 27 15:38:46 2005
@@ -1513,84 +1513,92 @@
     return (pkgCache::Dep::DepType) -1;
 }
 
-pkg_matcher *parse_condition_list(const string &s, unsigned int &loc,
+pkg_matcher *parse_condition_list(string::const_iterator &start,
+				  const string::const_iterator &end,
 				  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(const string &s, unsigned int &loc)
+std::string parse_substr(string::const_iterator &start,
+			 const string::const_iterator &end)
 {
   std::string rval="";
   bool done=false;
 
   do
     {
-      while(loc<s.size() &&
-	    s[loc]!='(' &&
-	    s[loc]!=')' &&
-	    s[loc]!='!' &&
-	    s[loc]!='~' &&
-	    s[loc]!='|')
+      while(start != end &&
+	    *start != '(' &&
+	    *start != ')' &&
+	    *start != '!' &&
+	    *start != '~' &&
+	    *start != '|')
 	{
-	  rval+=s[loc];
-	  ++loc;
+	  rval += *start;
+	  ++start;
 	}
 
       // We quit because we ran off the end of the string or saw a
       // metacharacter.  If the latter case and it was a tilde-escape,
       // add the escaped character to the string and continue.
-      if(loc<s.size()-1 && s[loc]=='~' &&
-	 (s[loc+1]=='(' || s[loc+1]==')' ||
-	  s[loc+1]=='!' || s[loc+1]=='~' ||
-	  s[loc+1]=='|'))
+      if(start != end && start+1 != end && *start == '~')
 	{
-	  rval+=s[loc+1];
-	  loc+=2;
+	  const char next = *(start+1);
+
+	  if(next == '(' || next == ')' ||
+	     next == '!' || next == '~' ||
+	     next == '|')
+	    {
+	      rval += next;
+	      start += 2;
+	    }
+	  else
+	    done=true;
 	}
-      else
-	done=true;
     } while(!done);
 
   return rval;
 }
 
-pkg_matcher *parse_atom(const string &s, unsigned int &loc,
+pkg_matcher *parse_atom(string::const_iterator &start,
+			const string::const_iterator &end,
 			bool search_descriptions)
 {
   std::string substr;
 
-  while(loc<s.size() && isspace(s[loc]))
-    loc++;
+  while(start != end && isspace(*start))
+    ++start;
 
-  while(loc<s.size() && s[loc]!='|' && s[loc]!=')')
+  while(start != end && *start != '|' && *start != ')')
     {
-      if(s[loc]=='!')
+      if(*start == '!')
 	{
-	  loc++;
-	  return new pkg_not_matcher(parse_atom(s, loc, search_descriptions));
+	  ++start;
+	  return new pkg_not_matcher(parse_atom(start, end,
+						search_descriptions));
 	}
-      else if(s[loc]=='(')
+      else if(*start == '(')
 	// Recur into the list
 	{
-	  loc++;
-	  auto_ptr<pkg_matcher> lst(parse_condition_list(s, loc,
+	  ++start;
+	  auto_ptr<pkg_matcher> lst(parse_condition_list(start, end,
 							 search_descriptions));
 
-	  if(!(loc<s.size() && s[loc]==')'))
+	  if(!(start != end && *start == ')'))
 	    throw CompilationException(_("Unmatched '('"));
 	  else
 	    {
-	      loc++;
+	      ++start;
 	      return lst.release();
 	    }
 	}
-      else if(s[loc]=='~')
+      else if(*start == '~')
 	{
-	  if(loc+1==s.size())
+	  if(start + 1 == end)
 	    {
-	      loc++;
+	      ++start;
 	      if(!search_descriptions)
 		return new pkg_name_matcher("~");
 	      else
@@ -1604,9 +1612,12 @@
 	    }
 	  else
 	    {
-	      unsigned int prevloc=loc;
-	      loc+=2;
-	      switch(s[prevloc+1])
+	      ++start;
+	      const char search_flag = *start;
+
+	      ++start;
+
+	      switch(search_flag)
 		// Nested switch statements, mmmm...
 		// Ok, there really is a reason here.  For all of the match
 		// types that need a string argument, some prefix code (see
@@ -1637,9 +1648,11 @@
 		case 'P':
 		case 'C':
 		  {
-		    auto_ptr<pkg_matcher> m(parse_atom(s, loc, search_descriptions));
+		    auto_ptr<pkg_matcher> m(parse_atom(start,
+						       end,
+						       search_descriptions));
 		    
-		    switch(s[prevloc+1])
+		    switch(search_flag)
 		      {
 		      case 'C':
 			return new pkg_dep_matcher(pkgCache::Dep::Conflicts, m.release());
@@ -1652,16 +1665,18 @@
 		  {
 		    bool do_provides=false;
 		    pkgCache::Dep::DepType type=pkgCache::Dep::Depends;
-		    string::size_type nextloc=loc;
 
-		    while(nextloc<s.size() && isalpha(s[nextloc]))
-		      ++nextloc;
+		    string::const_iterator nextstart = start;
+
+		    while(nextstart != end && isalpha(*nextstart))
+		      ++nextstart;
 
-		    if(nextloc<s.size() && s[nextloc]==':')
+		    if(nextstart != end && *nextstart == ':')
 		      {
-			string tname(s, loc, nextloc-loc);
+			string tname(start, nextstart);
 
-			loc=nextloc+1;
+			start = nextstart;
+			++start;
 
 			if(!strcasecmp(tname.c_str(), "provides"))
 			  do_provides=true;
@@ -1675,9 +1690,10 @@
 			  }
 		      }
 
-		    auto_ptr<pkg_matcher> m(parse_atom(s, loc, search_descriptions));
+		    auto_ptr<pkg_matcher> m(parse_atom(start, end,
+						       search_descriptions));
 
-		    switch(s[prevloc+1])
+		    switch(search_flag)
 		      {
 		      case 'D':
 			if(do_provides)
@@ -1692,8 +1708,8 @@
 		      }
 		  }
 		default:
-		  substr=parse_substr(s, loc);
-		  switch(s[prevloc+1])
+		  substr=parse_substr(start, end);
+		  switch(search_flag)
 		    {
 		    case 'a':
 		      {
@@ -1792,7 +1808,7 @@
 		    case 'V':
 		      return new pkg_version_matcher(substr);
 		    default:
-		      throw CompilationException(_("Unknown pattern type: %c"), s[1]);
+		      throw CompilationException(_("Unknown pattern type: %c"), search_flag);
 		    }
 		}
 	    }
@@ -1800,10 +1816,10 @@
       else
 	{
 	  if(!search_descriptions)
-	    return new pkg_name_matcher(parse_substr(s, loc));
+	    return new pkg_name_matcher(parse_substr(start, end));
 	  else
 	    {
-	      substr=parse_substr(s, loc);
+	      substr=parse_substr(start, end);
 	      auto_ptr<pkg_matcher> name(new pkg_name_matcher(substr));
 	      auto_ptr<pkg_matcher> desc(new pkg_description_matcher(substr));
 
@@ -1817,16 +1833,17 @@
   throw CompilationException(_("Can't search for \"\""));
 }
 
-pkg_matcher *parse_and_group(const string &s, unsigned int &loc,
+pkg_matcher *parse_and_group(string::const_iterator &start,
+			     const string::const_iterator &end,
 			     bool search_descriptions)
 {
   auto_ptr<pkg_matcher> rval(NULL);
-  while(loc<s.size() && isspace(s[loc]))
-    loc++;
+  while(start != end && isspace(*start))
+    ++start;
 
-  while(loc<s.size() && s[loc]!='|' && s[loc]!=')')
+  while(start != end && *start != '|' && *start != ')')
     {
-      auto_ptr<pkg_matcher> atom(parse_atom(s, loc,
+      auto_ptr<pkg_matcher> atom(parse_atom(start, end,
 					    search_descriptions));
 
       if(rval.get()==NULL)
@@ -1834,8 +1851,8 @@
       else
 	rval = auto_ptr<pkg_matcher>(new pkg_and_matcher(rval.release(), atom.release()));
 
-      while(loc<s.size() && isspace(s[loc]))
-	loc++;
+      while(start != end && isspace(*start))
+	++start;
     }
 
   if(rval.get()==NULL)
@@ -1844,20 +1861,22 @@
   return rval.release();
 }
 
-pkg_matcher *parse_condition_list(const string &s, unsigned int &loc,
+pkg_matcher *parse_condition_list(string::const_iterator &start,
+				  const string::const_iterator &end,
 				  bool search_descriptions)
 {
-  auto_ptr<pkg_matcher> grp(parse_and_group(s, loc, search_descriptions));
+  auto_ptr<pkg_matcher> grp(parse_and_group(start, end,
+					    search_descriptions));
 
-  while(loc<s.size() && isspace(s[loc]))
-    loc++;
+  while(start != end && isspace(*start))
+    ++start;
 
-  while(loc<s.size() && s[loc]!=')')
+  while(start != end && *start != ')')
     {
-      if(loc<s.size() && s[loc]=='|')
+      if(start != end && *start == '|')
 	{
-	  loc++;
-	  auto_ptr<pkg_matcher> grp2(parse_condition_list(s, loc,
+	  ++start;
+	  auto_ptr<pkg_matcher> grp2(parse_condition_list(start, end,
 							  search_descriptions));
 
 	  return new pkg_or_matcher(grp.release(), grp2.release());
@@ -1866,8 +1885,8 @@
 	throw CompilationException(_("Badly formed expression"));
 
       // Note that this code should never execute:
-      while(loc<s.size() && isspace(s[loc]))
-	loc++;
+      while(start != end && isspace(*start))
+	++start;
     }
 
   // If there's no second element in the condition list, return its
@@ -1875,24 +1894,25 @@
   return grp.release();
 }
 
-pkg_matcher *parse_pattern(const string &s,
-			   bool search_descriptions, bool flag_errors)
+pkg_matcher *parse_pattern(string::const_iterator &start,
+			   const string::const_iterator &end,
+			   bool search_descriptions,
+			   bool flag_errors,
+			   bool require_full_parse)
 {
-  unsigned int loc=0;
-
   // Just filter blank strings out immediately.
-  while(loc!=s.size() && isspace(s[loc]))
-    loc++;
+  while(start != end && isspace(*start))
+    ++start;
 
-  if(loc==s.size())
+  if(start == end)
     return NULL;
 
   try
     {
-      auto_ptr<pkg_matcher> rval(parse_condition_list(s, loc,
+      auto_ptr<pkg_matcher> rval(parse_condition_list(start, end,
 						      search_descriptions));
 
-      if(loc!=s.size())
+      if(require_full_parse && start != end)
 	throw CompilationException(_("Unexpected ')'"));
       else
 	return rval.release();

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	Wed Jul 27 15:38:46 2005
@@ -23,6 +23,8 @@
 #ifndef MATCHERS_H
 #define MATCHERS_H
 
+#include <string>
+
 #include <apt-pkg/pkgcache.h>
 
 /* For the cases where you want to investigate just what you matched a
@@ -57,32 +59,49 @@
   virtual ~pkg_matcher();
 };
 
-/** Parse the given pattern, returning a matcher.
+/** Parse the given pattern, returning a matcher.  start will be
+ *  modified to point to the first unparsable location.
  *
- *  \param s the pattern to parse
+ *  \param start the beginning of the range to parse
+ *  \param end the end of the range to parse
  *  \param search_descriptions if \b true, then strings without an
  *                     explicit pattern escape will be used to search
  *                     both names and descriptions rather than
  *                     names alone
  *  \param flag_errors if \b true, then error messages will be generated
  *                     for incorrect patterns.
+ *  \param require_full_parse if \b true, then an error will be signalled
+ *                            if the entire range [start,end) can't be
+ *                            parsed.
  *
  *  \return the new matcher or \b NULL if an error occurs.
  */
-pkg_matcher *parse_pattern(const string &s,
+pkg_matcher *parse_pattern(std::string::const_iterator &start,
+			   const std::string::const_iterator &end,
 			   bool search_descriptions=false,
-			   bool flag_errors=true);
+			   bool flag_errors=true,
+			   bool require_full_parse=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(), search_descriptions, flag_errors,
+		       true);
+}
+
 inline bool pkg_matches(const string &s,
 			const pkgCache::PkgIterator &pkg,
 			const pkgCache::VerIterator &ver)
 {
-  pkg_matcher *m=parse_pattern(s);
-  if(!m)
+  std::string::const_iterator start=s.begin();
+  std::auto_ptr<pkg_matcher> m(parse_pattern(start, s.end()));
+  if(m.get() == NULL)
     return false;
   else
     {
-      bool rval=m->matches(pkg, ver);
-      delete m;
+      bool rval=m.get()->matches(pkg, ver);
       return rval;
     }
 }



More information about the Aptitude-svn-commit mailing list