[PATCH] Filtering in FindVisitor

Igor Pechtchanski pechtcha@cs.nyu.edu
Mon Mar 17 18:23:00 GMT 2003


This patch implements a FilterVisitor class that is a decorator on a
FindVisitor and filters files according to the supplied Filter class (also
implemented).  It also implements a particular filter, ExcludeNameFilter,
that excludes any files with names matching a pattern.
The two new files, FilterVisitor.cc and FilterVisitor.h, will have to be
'cvs add'ed.
	Igor
==============================================================================
ChangeLog:
2003-03-17  Igor Pechtchanski <pechtcha@cs.nyu.edu>

	* postinstall.cc (do_postinstall): Filter out '*.done'.
	* FilterVisitor.h: New header file.  Declare the
	FilterVisitor, Filter, and ExcludeNameFilter classes.
	* FilterVisitor.cc: New file.  Implement FilterVisitor,
	Filter, and ExcludeNameFilter.
	* Makefile.am: Add FilterVisitor.cc and FilterVisitor.h
	to inilint_SOURCES and setup_SOURCES.

-- 
				http://cs.nyu.edu/~pechtcha/
      |\      _,,,---,,_		pechtcha@cs.nyu.edu
ZZZzz /,`.-'`'    -.  ;-;;,_		igor@watson.ibm.com
     |,4-  ) )-,_. ,\ (  `'-'		Igor Pechtchanski
    '---''(_/--'  `-'\_) fL	a.k.a JaguaR-R-R-r-r-r-.-.-.  Meow!

Oh, boy, virtual memory! Now I'm gonna make myself a really *big* RAMdisk!
  -- /usr/games/fortune
-------------- next part --------------
Index: FilterVisitor.cc
===================================================================
RCS file: FilterVisitor.cc
diff -N FilterVisitor.cc
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ FilterVisitor.cc	17 Mar 2003 18:01:47 -0000
@@ -0,0 +1,213 @@
+/*
+ * Copyright (c) 2003 Igor Pechtchanski.
+ *
+ *     This program is free software; you can redistribute it and/or modify
+ *     it under the terms of the GNU General Public License as published by
+ *     the Free Software Foundation; either version 2 of the License, or
+ *     (at your option) any later version.
+ *
+ *     A copy of the GNU General Public License can be found at
+ *     http://www.gnu.org/
+ *
+ * Written by Igor Pechtchanski <pechtcha@cs.nyu.edu>
+ *
+ */
+
+#if 0
+static const char *cvsid =
+  "\n%%% $Id$\n";
+#endif
+
+#include "FilterVisitor.h"
+#include "String++.h"
+#include "find.h"
+
+#include <iostream>
+
+FilterVisitor::FilterVisitor(FindVisitor *visitor, Filter *filter)
+  : _visitor(visitor), _filter(filter) {}
+
+FilterVisitor::~FilterVisitor() {}
+
+void
+FilterVisitor::visitFile(String const &basePath, WIN32_FIND_DATA const *aFile)
+{
+  if (_filter->matchFile(basePath, aFile))
+    _visitor->visitFile(basePath, aFile);
+}
+
+void
+FilterVisitor::visitDirectory(String const &basePath, WIN32_FIND_DATA const *aDir)
+{
+  if (_filter->matchDirectory(basePath, aDir))
+    _visitor->visitDirectory(basePath, aDir);
+}
+
+Filter::Filter() {}
+Filter::~Filter() {}
+
+bool
+Filter::matchFile(String const &basePath, WIN32_FIND_DATA const *aFile)
+{
+  return true;
+}
+
+bool
+Filter::matchDirectory(String const &basePath, WIN32_FIND_DATA const *aDir)
+{
+  return true;
+}
+
+ExcludeNameFilter::ExcludeNameFilter() : _filePattern(""), _dirPattern("") {}
+
+ExcludeNameFilter::~ExcludeNameFilter(){}
+
+ExcludeNameFilter::ExcludeNameFilter(String const &filePattern,
+				     String const &dirPattern)
+  : _filePattern(filePattern), _dirPattern(dirPattern) {}
+
+bool
+ExcludeNameFilter::matchFile(String const &basePath, WIN32_FIND_DATA const *aFile)
+{
+  return !_filePattern.match(basePath + aFile->cFileName);
+}
+
+bool
+ExcludeNameFilter::matchDirectory(String const &basePath, WIN32_FIND_DATA const *aDir)
+{
+  return !_dirPattern.match(basePath + aDir->cFileName);
+}
+
+/*
+ * This supports two wildcard characters, '*' and '?', as well as the
+ * '[]'-style character sets ('^' to invert).
+ * Use '\' to escape special characters.
+ * Shamelessly stolen from fileutils-4.1.
+ */
+static bool
+strmatch (const char *pattern, const char *filename)
+{
+  register const char *p = pattern, *n = filename;
+  register char c;
+
+  while ((c = *p++) != '\0')
+    {
+      switch (c)
+	{
+	case '?':  /* A '?' matches exactly one character */
+	  if (*n == '\0')
+	    return false;
+	  break;
+
+	case '\\':  /* Escape next character */
+	  c = *p++;
+	  if (c == '\0')
+	    return false;
+	  if (*n != c)
+	    return false;
+	  break;
+
+	case '*':  /* A '*' matches any number of characters */
+	  for (c = *p++; c == '?' || c == '*'; c = *p++)
+	    {
+	      if (c == '?')
+		{
+		  /* A '?' needs to match one character.  */
+		  if (*n == '\0')
+		    /* There isn't another character; no match.  */
+		    return false;
+		  else
+		    /* One character of the filename is consumed in matching
+		       this ? wildcard, so *??? won't match if there are
+		       less than three characters.  */
+		    ++n;
+		}
+	    }
+
+	  if (c == '\0')
+	    return true;
+
+	  {
+	    char c1 = (c == '\\') ? *p : c;
+	    for (--p; *n != '\0'; ++n)  /* Eat up all chars */
+	      if ((c == '[' || *n == c1) && strmatch (p, n))
+		return true;
+	    return false;
+	  }
+
+	case '[':  /* A '[A-Z]' matches any char between 'A' and 'Z' */
+	  {
+	    /* Nonzero if the sense of the character class is inverted.  */
+	    register bool invert;
+
+	    if (*n == '\0')
+	      return false;
+
+	    invert = (*p == '^');
+	    if (invert)
+	      ++p;
+
+	    c = *p++;
+	    for (;;)
+	      {
+		register char cstart = c, cend = c;
+
+		if (c == '\0')
+		  /* [ (unterminated) loses.  */
+		  return false;
+
+		c = *p++;
+
+		if (c == '-' && *p != ']')
+		  {
+		    cend = *p++;
+		    if (cend == '\0')
+		      return false;
+
+		    c = *p++;
+		  }
+
+		if (*n >= cstart && *n <= cend)
+		  goto matched;
+
+		if (c == ']')
+		  break;
+	      }
+	    if (!invert)
+	      return false;
+	    break;
+
+	  matched:;
+	    /* Skip the rest of the [...] that already matched.  */
+	    while (c != ']')
+	      {
+		if (c == '\0')
+		  /* [... (unterminated) loses.  */
+		  return false;
+
+		c = *p++;
+	      }
+	    if (invert)
+	      return false;
+	  }
+	  break;
+
+	default:
+	  if (c != *n)
+	    return false;
+	}
+
+      ++n;
+    }
+
+  if (*n == '\0')
+    return true;
+
+  return false;
+}
+
+bool ExcludeNameFilter::Glob::match(String const &filename)
+{
+  return strmatch(this->_pattern.cstr_oneuse(), filename.cstr_oneuse());
+}
+
Index: FilterVisitor.h
===================================================================
RCS file: FilterVisitor.h
diff -N FilterVisitor.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ FilterVisitor.h	17 Mar 2003 18:01:47 -0000
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2003 Igor Pechtchanski.
+ *
+ *     This program is free software; you can redistribute it and/or modify
+ *     it under the terms of the GNU General Public License as published by
+ *     the Free Software Foundation; either version 2 of the License, or
+ *     (at your option) any later version.
+ *
+ *     A copy of the GNU General Public License can be found at
+ *     http://www.gnu.org/
+ *
+ * Written by Igor Pechtchanski <pechtcha@cs.nyu.edu>
+ *
+ */
+
+#ifndef _FILTERVISITOR_H_
+#define _FILTERVISITOR_H_
+
+#include "FindVisitor.h"
+#include "String++.h"
+
+/* For the wfd definition. See the TODO in find.cc */
+#include "win32.h"
+
+class Filter
+{
+public:
+  virtual bool matchFile(String const &basePath, WIN32_FIND_DATA const *);
+  virtual bool matchDirectory(String const &basePath, WIN32_FIND_DATA const *);
+  virtual ~ Filter();
+protected:
+  Filter();
+  Filter(Filter const &);
+  Filter & operator= (Filter const &);
+};
+
+class FilterVisitor : public FindVisitor
+{
+public:
+  virtual void visitFile(String const &basePath, WIN32_FIND_DATA const *);
+  virtual void visitDirectory(String const &basePath, WIN32_FIND_DATA const *);
+  FilterVisitor (FindVisitor *visitor, Filter *filter);
+  virtual ~ FilterVisitor ();
+protected:
+  FilterVisitor ();
+  FilterVisitor (FilterVisitor const &);
+  FilterVisitor & operator= (FilterVisitor const &);
+private:
+  FindVisitor *_visitor;
+  Filter *_filter;
+};
+
+class ExcludeNameFilter : public Filter
+{
+public:
+  ExcludeNameFilter (String const &filePattern, String const &dirPattern = "");
+  virtual ~ ExcludeNameFilter ();
+
+  virtual bool matchFile(String const &basePath, WIN32_FIND_DATA const *);
+  virtual bool matchDirectory(String const &basePath, WIN32_FIND_DATA const *);
+protected:
+  ExcludeNameFilter ();
+  ExcludeNameFilter (ExcludeNameFilter const &);
+  ExcludeNameFilter & operator= (ExcludeNameFilter const &);
+private:
+  class Glob
+  {
+  public:
+    Glob(String const &pattern) : _pattern(pattern) {}
+    bool match(String const &filename);
+  private:
+    String _pattern;
+  };
+
+  Glob _filePattern;
+  Glob _dirPattern;
+};
+
+#endif // _FILTERVISITOR_H_
Index: Makefile.am
===================================================================
RCS file: /cvs/cygwin-apps/setup/Makefile.am,v
retrieving revision 2.27
diff -u -p -r2.27 Makefile.am
--- Makefile.am	10 Mar 2003 15:47:53 -0000	2.27
+++ Makefile.am	17 Mar 2003 18:01:47 -0000
@@ -80,6 +80,8 @@ inilint_LDADD = libgetopt++/libgetopt++.
 inilint_SOURCES = \
   filemanip.cc \
   filemanip.h \
+  FilterVisitor.cc \
+  FilterVisitor.h \
   find.cc \
   find.h \
   FindVisitor.cc \
@@ -153,6 +155,8 @@ setup_SOURCES = \
 	find.h \
 	FindVisitor.cc \
 	FindVisitor.h \
+	FilterVisitor.cc \
+	FilterVisitor.h \
 	filemanip.cc \
 	filemanip.h \
 	fromcwd.cc \
Index: postinstall.cc
===================================================================
RCS file: /cvs/cygwin-apps/setup/postinstall.cc,v
retrieving revision 2.9
diff -u -p -r2.9 postinstall.cc
--- postinstall.cc	19 May 2002 03:07:51 -0000	2.9
+++ postinstall.cc	17 Mar 2003 18:01:51 -0000
@@ -26,6 +26,7 @@ static const char *cvsid =
 #include "mount.h"
 #include "script.h"
 #include "FindVisitor.h"
+#include "FilterVisitor.h"
 
 class RunFindVisitor : public FindVisitor
 {
@@ -48,6 +49,8 @@ do_postinstall (HINSTANCE h, HWND owner)
   init_run_script ();
   SetCurrentDirectory (get_root_dir ().cstr_oneuse());
   RunFindVisitor myVisitor;
+  ExcludeNameFilter notDone("*.done");
+  FilterVisitor excludeDoneVisitor(&myVisitor, &notDone);
   String postinst = cygpath ("/etc/postinstall");
-  Find (postinst).accept (myVisitor);
+  Find (postinst).accept (excludeDoneVisitor);
 }


More information about the Cygwin-apps mailing list