add GlobPattern::match_files()

This commit is contained in:
David Rose 2002-05-23 02:01:57 +00:00
parent d2511eda84
commit af3861a402
4 changed files with 164 additions and 42 deletions

View File

@ -159,6 +159,7 @@
test_glob.cxx
#define LOCAL_LIBS $[LOCAL_LIBS] putil
#define OTHER_LIBS $[OTHER_LIBS] pystub
#end test_bin_target

View File

@ -18,6 +18,147 @@
#include "globPattern.h"
////////////////////////////////////////////////////////////////////
// Function: GlobPattern::has_glob_characters
// Access: Public
// Description: Returns true if the pattern includes any special
// globbing characters, or false if it is just a literal
// string.
////////////////////////////////////////////////////////////////////
bool GlobPattern::
has_glob_characters() const {
string::const_iterator pi;
pi = _pattern.begin();
while (pi != _pattern.end()) {
switch (*pi) {
case '*':
case '?':
case '[':
return true;
case '\\':
++pi;
if (pi == _pattern.end()) {
return false;
}
}
++pi;
}
return false;
}
////////////////////////////////////////////////////////////////////
// Function: GlobPattern::match_files
// Access: Public
// Description: Treats the GlobPattern as a filename pattern, and
// returns a list of any actual files that match the
// pattern. This is the behavior of the standard Posix
// glob() function. Any part of the filename may
// contain glob characters, including intermediate
// directory names.
//
// If cwd is specified, it is the directory that
// relative filenames are taken to be relative to;
// otherwise, the actual current working directory is
// assumed.
//
// The return value is the number of files matched,
// which are added to the results vector.
////////////////////////////////////////////////////////////////////
int GlobPattern::
match_files(vector_string &results, const Filename &cwd) {
string next_pattern, next_suffix;
size_t slash = _pattern.find('/');
if (slash == string::npos) {
next_pattern = _pattern;
} else {
next_pattern = _pattern.substr(0, slash);
next_suffix = _pattern.substr(slash + 1);
}
GlobPattern next_glob(next_pattern);
return next_glob.r_match_files(Filename(), next_suffix, results, cwd);
}
////////////////////////////////////////////////////////////////////
// Function: GlobPattern::r_match_files
// Access: Private
// Description: The recursive implementation of match_files().
////////////////////////////////////////////////////////////////////
int GlobPattern::
r_match_files(const Filename &prefix, const string &suffix,
vector_string &results, const Filename &cwd) {
string next_pattern, next_suffix;
size_t slash = suffix.find('/');
if (slash == string::npos) {
next_pattern = suffix;
} else {
next_pattern = suffix.substr(0, slash);
next_suffix = suffix.substr(slash + 1);
}
Filename parent_dir;
if (prefix.is_local() && !cwd.empty()) {
parent_dir = Filename(cwd, prefix);
} else {
parent_dir = prefix;
}
GlobPattern next_glob(next_pattern);
if (!has_glob_characters()) {
// If there are no special characters in the pattern, it's a
// literal match.
if (suffix.empty()) {
// Time to stop.
Filename single_filename(parent_dir, _pattern);
if (single_filename.exists()) {
results.push_back(Filename(prefix, _pattern));
return 1;
}
return 0;
}
return next_glob.r_match_files(Filename(prefix, _pattern),
next_suffix, results, cwd);
}
// If there *are* special glob characters, we must attempt to
// match the pattern against the files in this directory.
vector_string dir_files;
if (!parent_dir.scan_directory(dir_files)) {
// Not a directory, or unable to read directory; stop here.
return 0;
}
// Now go through each file in the directory looking for one that
// matches the pattern.
int num_matched = 0;
vector_string::const_iterator fi;
for (fi = dir_files.begin(); fi != dir_files.end(); ++fi) {
const string &local_file = (*fi);
if (_pattern[0] == '.' || (local_file.empty() || local_file[0] != '.')) {
if (matches(local_file)) {
// We have a match; continue.
if (suffix.empty()) {
results.push_back(Filename(prefix, local_file));
num_matched++;
} else {
num_matched += next_glob.r_match_files(Filename(prefix, local_file),
next_suffix, results, cwd);
}
}
}
}
return num_matched;
}
////////////////////////////////////////////////////////////////////
// Function: GlobPattern::matches_substr
// Access: Private

View File

@ -19,7 +19,9 @@
#ifndef GLOBPATTERN_H
#define GLOBPATTERN_H
#include <pandabase.h>
#include "pandabase.h"
#include "filename.h"
#include "vector_string.h"
////////////////////////////////////////////////////////////////////
// Class : GlobPattern
@ -49,6 +51,9 @@ public:
INLINE void output(ostream &out) const;
bool has_glob_characters() const;
int match_files(vector_string &results, const Filename &cwd = Filename());
private:
bool matches_substr(string::const_iterator pi,
string::const_iterator pend,
@ -59,6 +64,9 @@ private:
string::const_iterator pend,
char ch) const;
int r_match_files(const Filename &prefix, const string &suffix,
vector_string &results, const Filename &cwd);
string _pattern;
};

View File

@ -18,20 +18,14 @@
#include "globPattern.h"
#ifdef WIN32
#include <io.h>
#else
#include <sys/types.h>
#include <dirent.h>
#endif
int
main(int argc, char *argv[]) {
if (argc != 2) {
if (argc != 2 && argc != 3) {
cerr
<< "test_glob \"pattern\"\n\n"
<< "test_glob \"pattern\" [from-directory]\n\n"
<< "Attempts to match the pattern against each of the files in the\n"
<< "current directory. Reports all of the matching files. This is,\n"
<< "indicated directory if specified, or the current directory\n"
<< "otherwise. Reports all of the matching files. This is,\n"
<< "of course, exactly the normal behavior of the shell; this test\n"
<< "program merely exercises the Panda GlobPattern object, which\n"
<< "duplicates the shell functionality.\n\n";
@ -39,42 +33,20 @@ main(int argc, char *argv[]) {
}
GlobPattern pattern(argv[1]);
#ifdef WIN32
struct _finddata_t fd;
long dp = _findfirst("*.*", &fd);
if (dp != 0) {
do {
if (pattern.matches(fd.name)) {
cout << "Matches: " << fd.name << "\n";
} else {
cout << "Fails: " << fd.name << "\n";
}
} while (_findnext(dp, &fd) == 0);
Filename from_directory;
if (argc == 3) {
from_directory = argv[2];
}
#else // WIN32
DIR *dp = opendir(".");
if (dp == (DIR *)NULL) {
cerr << "Unable to scan directory '.'\n";
exit(1);
}
vector_string results;
int num_matched = pattern.match_files(results, from_directory);
struct dirent *ent;
ent = readdir(dp);
while (ent != (struct dirent *)NULL) {
if (pattern.matches(ent->d_name)) {
cout << "Matches: " << ent->d_name << "\n";
} else {
cout << "Fails: " << ent->d_name << "\n";
}
ent = readdir(dp);
cerr << num_matched << " results:\n";
vector_string::const_iterator si;
for (si = results.begin(); si != results.end(); ++si) {
cerr << " " << *si << "\n";
}
closedir(dp);
#endif // WIN32
return (0);
}