mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-03 10:22:45 -04:00
incorporate GlobPattern
This commit is contained in:
parent
9db8ebaac7
commit
e4a4bc3034
@ -5,6 +5,7 @@ ppremake_SOURCES = \
|
||||
dSearchPath.I dSearchPath.cxx dSearchPath.h \
|
||||
executionEnvironment.cxx executionEnvironment.h \
|
||||
filename.I filename.cxx filename.h \
|
||||
globPattern.I globPattern.cxx globPattern.h \
|
||||
gnu_getopt.c gnu_getopt.h gnu_regex.c gnu_regex.h \
|
||||
ppCommandFile.cxx ppCommandFile.h ppDependableFile.cxx \
|
||||
ppDependableFile.h ppDirectory.cxx \
|
||||
|
@ -40,9 +40,6 @@
|
||||
/* Define if you have the <minmax.h> header file. */
|
||||
/* #undef HAVE_MINMAX_H */
|
||||
|
||||
/* Define if you have the <glob.h> header file. */
|
||||
/* #undef HAVE_GLOB_H */
|
||||
|
||||
/* Define if you have the <dirent.h> header file. */
|
||||
/* #undef HAVE_DIRENT_H */
|
||||
|
||||
|
@ -42,7 +42,7 @@ AC_SUBST(libm)
|
||||
|
||||
dnl Checks for header files.
|
||||
AC_HEADER_STDC
|
||||
AC_CHECK_HEADERS(malloc.h alloca.h unistd.h utime.h io.h minmax.h glob.h dirent.h sys/types.h sys/time.h sys/utime.h sys/wait.h string.h strstream.h regex.h)
|
||||
AC_CHECK_HEADERS(malloc.h alloca.h unistd.h utime.h io.h minmax.h dirent.h sys/types.h sys/time.h sys/utime.h sys/wait.h string.h strstream.h regex.h)
|
||||
|
||||
dnl Checks for typedefs, structures, and compiler characteristics.
|
||||
|
||||
|
@ -1065,7 +1065,13 @@ scan_directory(vector_string &contents) const {
|
||||
#if defined(HAVE_DIRENT_H)
|
||||
size_t orig_size = contents.size();
|
||||
|
||||
DIR *root = opendir(_filename.c_str());
|
||||
string dirname;
|
||||
if (empty()) {
|
||||
dirname = ".";
|
||||
} else {
|
||||
dirname = _filename;
|
||||
}
|
||||
DIR *root = opendir(dirname.c_str());
|
||||
if (root == (DIR *)NULL) {
|
||||
return false;
|
||||
}
|
||||
|
90
ppremake/globPattern.I
Normal file
90
ppremake/globPattern.I
Normal file
@ -0,0 +1,90 @@
|
||||
// Filename: globPattern.I
|
||||
// Created by: drose (30May00)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
|
||||
//
|
||||
// All use of this software is subject to the terms of the Panda 3d
|
||||
// Software license. You should have received a copy of this license
|
||||
// along with this source code; you will also find a current copy of
|
||||
// the license at http://www.panda3d.org/license.txt .
|
||||
//
|
||||
// To contact the maintainers of this program write to
|
||||
// panda3d@yahoogroups.com .
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: GlobPattern::Constructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE GlobPattern::
|
||||
GlobPattern(const string &pattern) : _pattern(pattern) {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: GlobPattern::Copy Constructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE GlobPattern::
|
||||
GlobPattern(const GlobPattern ©) : _pattern(copy._pattern) {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: GlobPattern::Copy Assignment Operator
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void GlobPattern::
|
||||
operator = (const GlobPattern ©) {
|
||||
_pattern = copy._pattern;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: GlobPattern::set_pattern
|
||||
// Access: Public
|
||||
// Description: Changes the pattern string that the GlobPattern
|
||||
// object matches.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void GlobPattern::
|
||||
set_pattern(const string &pattern) {
|
||||
_pattern = pattern;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: GlobPattern::get_pattern
|
||||
// Access: Public
|
||||
// Description: Returns the pattern string that the GlobPattern
|
||||
// object matches.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE const string &GlobPattern::
|
||||
get_pattern() const {
|
||||
return _pattern;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: GlobPattern::matches
|
||||
// Access: Public
|
||||
// Description: Returns true if the candidate string matches the
|
||||
// pattern, false otherwise.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool GlobPattern::
|
||||
matches(const string &candidate) const {
|
||||
return matches_substr(_pattern.begin(), _pattern.end(),
|
||||
candidate.begin(), candidate.end());
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: GlobPattern::output
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void GlobPattern::
|
||||
output(ostream &out) const {
|
||||
out << _pattern;
|
||||
}
|
309
ppremake/globPattern.cxx
Normal file
309
ppremake/globPattern.cxx
Normal file
@ -0,0 +1,309 @@
|
||||
// Filename: globPattern.cxx
|
||||
// Created by: drose (30May00)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
|
||||
//
|
||||
// All use of this software is subject to the terms of the Panda 3d
|
||||
// Software license. You should have received a copy of this license
|
||||
// along with this source code; you will also find a current copy of
|
||||
// the license at http://www.panda3d.org/license.txt .
|
||||
//
|
||||
// To contact the maintainers of this program write to
|
||||
// panda3d@yahoogroups.com .
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#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 prefix, pattern, suffix;
|
||||
|
||||
string source = _pattern;
|
||||
if (!source.empty() && source[0] == '/') {
|
||||
// If the first character is a slash, that becomes the prefix.
|
||||
prefix = "/";
|
||||
source = source.substr(1);
|
||||
}
|
||||
|
||||
size_t slash = source.find('/');
|
||||
if (slash == string::npos) {
|
||||
pattern = source;
|
||||
} else {
|
||||
pattern = source.substr(0, slash);
|
||||
suffix = source.substr(slash + 1);
|
||||
}
|
||||
|
||||
GlobPattern glob(pattern);
|
||||
return glob.r_match_files(prefix, 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
|
||||
// Description: The recursive implementation of matches(). This
|
||||
// returns true if the pattern substring [pi, pend)
|
||||
// matches the candidate substring [ci, cend), false
|
||||
// otherwise.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool GlobPattern::
|
||||
matches_substr(string::const_iterator pi, string::const_iterator pend,
|
||||
string::const_iterator ci, string::const_iterator cend) const {
|
||||
// If we run out of pattern or candidate string, it's a match only
|
||||
// if they both ran out at the same time.
|
||||
if (pi == pend || ci == cend) {
|
||||
// A special exception: we allow ci to reach the end before pi,
|
||||
// only if pi is one character before the end and that last
|
||||
// character is '*'.
|
||||
if ((ci == cend) && (pi + 1 == pend) && (*pi) == '*') {
|
||||
return true;
|
||||
}
|
||||
return (pi == pend && ci == cend);
|
||||
}
|
||||
|
||||
switch (*pi) {
|
||||
|
||||
case '*':
|
||||
// A '*' in the pattern string means to match any sequence of zero
|
||||
// or more characters in the candidate string. This means we have
|
||||
// to recurse twice: either consume one character of the candidate
|
||||
// string and continue to try matching the *, or stop trying to
|
||||
// match the * here.
|
||||
return
|
||||
matches_substr(pi, pend, ci + 1, cend) ||
|
||||
matches_substr(pi + 1, pend, ci, cend);
|
||||
|
||||
case '?':
|
||||
// A '?' in the pattern string means to match exactly one
|
||||
// character in the candidate string. That's easy.
|
||||
return matches_substr(pi + 1, pend, ci + 1, cend);
|
||||
|
||||
case '[':
|
||||
// An open square bracket begins a set.
|
||||
++pi;
|
||||
if ((*pi) == '!') {
|
||||
++pi;
|
||||
if (matches_set(pi, pend, *ci)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (!matches_set(pi, pend, *ci)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (pi == pend) {
|
||||
// Oops, there wasn't a closing square bracket.
|
||||
return false;
|
||||
}
|
||||
return matches_substr(pi + 1, pend, ci + 1, cend);
|
||||
|
||||
case '\\':
|
||||
// A backslash escapes the next special character.
|
||||
++pi;
|
||||
if (pi == pend) {
|
||||
return false;
|
||||
}
|
||||
// fall through.
|
||||
|
||||
default:
|
||||
// Anything else means to match exactly that.
|
||||
if ((*pi) != (*ci)) {
|
||||
return false;
|
||||
}
|
||||
return matches_substr(pi + 1, pend, ci + 1, cend);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: GlobPattern::matches_set
|
||||
// Access: Private
|
||||
// Description: Called when an unescaped open square bracked is
|
||||
// scanned, this is called with pi positioned after the
|
||||
// opening square bracket, scans the set sequence,
|
||||
// leaving pi positioned on the closing square bracket,
|
||||
// and returns true if the indicated character matches
|
||||
// the set of characters indicated, false otherwise.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool GlobPattern::
|
||||
matches_set(string::const_iterator &pi, string::const_iterator pend,
|
||||
char ch) const {
|
||||
bool matched = false;
|
||||
|
||||
while (pi != pend && (*pi) != ']') {
|
||||
if ((*pi) == '\\') {
|
||||
// Backslash escapes the next character.
|
||||
++pi;
|
||||
if (pi == pend) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (ch == (*pi)) {
|
||||
matched = true;
|
||||
}
|
||||
|
||||
// Maybe it's an a-z style range?
|
||||
char start = (*pi);
|
||||
++pi;
|
||||
if (pi != pend && (*pi) == '-') {
|
||||
++pi;
|
||||
if (pi != pend && (*pi) != ']') {
|
||||
// Yes, we have a range: start-end.
|
||||
|
||||
if ((*pi) == '\\') {
|
||||
// Backslash escapes.
|
||||
++pi;
|
||||
if (pi == pend) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
char end = (*pi);
|
||||
++pi;
|
||||
|
||||
if (ch >= start && ch <= end) {
|
||||
matched = true;
|
||||
}
|
||||
} else {
|
||||
// This was a - at the end of the string.
|
||||
if (ch == '-') {
|
||||
matched = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return matched;
|
||||
}
|
||||
|
||||
|
||||
|
81
ppremake/globPattern.h
Normal file
81
ppremake/globPattern.h
Normal file
@ -0,0 +1,81 @@
|
||||
// Filename: globPattern.h
|
||||
// Created by: drose (30May00)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
|
||||
//
|
||||
// All use of this software is subject to the terms of the Panda 3d
|
||||
// Software license. You should have received a copy of this license
|
||||
// along with this source code; you will also find a current copy of
|
||||
// the license at http://www.panda3d.org/license.txt .
|
||||
//
|
||||
// To contact the maintainers of this program write to
|
||||
// panda3d@yahoogroups.com .
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef GLOBPATTERN_H
|
||||
#define GLOBPATTERN_H
|
||||
|
||||
#include "ppremake.h"
|
||||
#include "filename.h"
|
||||
#include "vector_string.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : GlobPattern
|
||||
// Description : This class can be used to test for string matches
|
||||
// against standard Unix-shell filename globbing
|
||||
// conventions. It serves as a portable standin for the
|
||||
// Posix fnmatch() call.
|
||||
//
|
||||
// A GlobPattern is given a pattern string, which can
|
||||
// contain operators like *, ?, and []. Then it can be
|
||||
// tested against any number of candidate strings; for
|
||||
// each candidate, it will indicate whether the string
|
||||
// matches the pattern or not. It can be used, for
|
||||
// example, to scan a directory for all files matching a
|
||||
// particular pattern.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class EXPCL_PANDA GlobPattern {
|
||||
public:
|
||||
INLINE GlobPattern(const string &pattern = string());
|
||||
INLINE GlobPattern(const GlobPattern ©);
|
||||
INLINE void operator = (const GlobPattern ©);
|
||||
|
||||
INLINE void set_pattern(const string &pattern);
|
||||
INLINE const string &get_pattern() const;
|
||||
|
||||
INLINE bool matches(const string &candidate) const;
|
||||
|
||||
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,
|
||||
string::const_iterator ci,
|
||||
string::const_iterator cend) const;
|
||||
|
||||
bool matches_set(string::const_iterator &pi,
|
||||
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;
|
||||
};
|
||||
|
||||
INLINE ostream &operator << (ostream &out, const GlobPattern &glob) {
|
||||
glob.output(out);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
#include "globPattern.I"
|
||||
|
||||
#endif
|
@ -14,10 +14,7 @@
|
||||
#include "tokenize.h"
|
||||
#include "filename.h"
|
||||
#include "dSearchPath.h"
|
||||
|
||||
#ifdef HAVE_GLOB_H
|
||||
#include <glob.h>
|
||||
#endif
|
||||
#include "globPattern.h"
|
||||
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
@ -3102,49 +3099,19 @@ p_find_map_variable(const string &varname) {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PPScope::
|
||||
glob_string(const string &str, vector<string> &results) {
|
||||
#ifdef WIN32_VC
|
||||
cerr << "glob temporarily unsupported in Win32 without Cygwin.\n";
|
||||
|
||||
#else // WIN32_VC
|
||||
// We run glob_string() within the directory indicated by
|
||||
// $[THISDIRPREFIX]. This way, local filenames will be expanded the
|
||||
// way we expect.
|
||||
// The globbing is relative to THISDIRPREFIX, not necessarily the
|
||||
// current directory.
|
||||
string dirname = trim_blanks(expand_variable("THISDIRPREFIX"));
|
||||
bool changed_dir = false;
|
||||
if (!dirname.empty()) {
|
||||
if (chdir(dirname.c_str()) < 0) {
|
||||
perror("chdir");
|
||||
} else {
|
||||
changed_dir = true;
|
||||
}
|
||||
}
|
||||
|
||||
vector<string> words;
|
||||
tokenize_whitespace(str, words);
|
||||
|
||||
vector<string>::const_iterator wi;
|
||||
|
||||
glob_t pglob;
|
||||
memset(&pglob, 0, sizeof(pglob));
|
||||
|
||||
int flags = 0;
|
||||
for (wi = words.begin(); wi != words.end(); ++wi) {
|
||||
glob((*wi).c_str(), flags, NULL, &pglob);
|
||||
flags |= GLOB_APPEND;
|
||||
GlobPattern glob(*wi);
|
||||
glob.match_files(results, dirname);
|
||||
}
|
||||
|
||||
for (int i = 0; i < (int)pglob.gl_pathc; i++) {
|
||||
results.push_back(string(pglob.gl_pathv[i]));
|
||||
}
|
||||
|
||||
globfree(&pglob);
|
||||
|
||||
// Sort the results into alphabetical order.
|
||||
sort(results.begin(), results.end());
|
||||
|
||||
if (changed_dir) {
|
||||
// Now restore the current directory back to where it should be.
|
||||
PPMain::chdir_root();
|
||||
}
|
||||
#endif // WIN32_VC
|
||||
}
|
||||
|
@ -76,16 +76,17 @@ extern bool dry_run;
|
||||
extern bool verbose_dry_run;
|
||||
#endif
|
||||
|
||||
/* These are defined so that we may build Filename and DSearchPath,
|
||||
which are copied from dtool. We have to copy these files from
|
||||
dtool since ppremake must be built first, and stands outside of
|
||||
Panda; but we want to minimize the changes we must make to these
|
||||
files so that we can easily recopy them at need.
|
||||
/* These are defined so that we may build Filename, DSearchPath, and
|
||||
GlobPattern, which are copied from dtool and panda. We have to
|
||||
copy these files in since ppremake must be built first, and stands
|
||||
outside of Panda; but we want to minimize the changes we must make
|
||||
to these files so that we can easily recopy them at need.
|
||||
|
||||
These symbols just make the build environment a bit more
|
||||
Panda-like. */
|
||||
#define PUBLISHED public
|
||||
#define INLINE inline
|
||||
#define EXPCL_DTOOL
|
||||
#define EXPCL_PANDA
|
||||
|
||||
#endif
|
||||
|
Loading…
x
Reference in New Issue
Block a user