diff options
Diffstat (limited to 'Glob.cxx')
-rw-r--r-- | Glob.cxx | 516 |
1 files changed, 516 insertions, 0 deletions
diff --git a/Glob.cxx b/Glob.cxx new file mode 100644 index 0000000..513eb64 --- /dev/null +++ b/Glob.cxx @@ -0,0 +1,516 @@ +/*============================================================================ + KWSys - Kitware System Library + Copyright 2000-2009 Kitware, Inc., Insight Software Consortium + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ +#include "kwsysPrivate.h" +#include KWSYS_HEADER(Glob.hxx) + +#include KWSYS_HEADER(Configure.hxx) + +#include KWSYS_HEADER(RegularExpression.hxx) +#include KWSYS_HEADER(SystemTools.hxx) +#include KWSYS_HEADER(Directory.hxx) +#include KWSYS_HEADER(stl/string) +#include KWSYS_HEADER(stl/vector) + +// Work-around CMake dependency scanning limitation. This must +// duplicate the above list of headers. +#if 0 +# include "Glob.hxx.in" +# include "Directory.hxx.in" +# include "Configure.hxx.in" +# include "RegularExpression.hxx.in" +# include "SystemTools.hxx.in" +# include "kwsys_stl.hxx.in" +# include "kwsys_stl_string.hxx.in" +#endif + +#include <ctype.h> +#include <stdio.h> +#include <string.h> +namespace KWSYS_NAMESPACE +{ +#if defined(_WIN32) || defined(__APPLE__) || defined(__CYGWIN__) +// On Windows and apple, no difference between lower and upper case +# define KWSYS_GLOB_CASE_INDEPENDENT +#endif + +#if defined(_WIN32) || defined(__CYGWIN__) +// Handle network paths +# define KWSYS_GLOB_SUPPORT_NETWORK_PATHS +#endif + +//---------------------------------------------------------------------------- +class GlobInternals +{ +public: + kwsys_stl::vector<kwsys_stl::string> Files; + kwsys_stl::vector<kwsys::RegularExpression> Expressions; +}; + +//---------------------------------------------------------------------------- +Glob::Glob() +{ + this->Internals = new GlobInternals; + this->Recurse = false; + this->Relative = ""; + + this->RecurseThroughSymlinks = true; + // RecurseThroughSymlinks is true by default for backwards compatibility, + // not because it's a good idea... + this->FollowedSymlinkCount = 0; +} + +//---------------------------------------------------------------------------- +Glob::~Glob() +{ + delete this->Internals; +} + +//---------------------------------------------------------------------------- +kwsys_stl::vector<kwsys_stl::string>& Glob::GetFiles() +{ + return this->Internals->Files; +} + +//---------------------------------------------------------------------------- +kwsys_stl::string Glob::PatternToRegex(const kwsys_stl::string& pattern, + bool require_whole_string, + bool preserve_case) +{ + // Incrementally build the regular expression from the pattern. + kwsys_stl::string regex = require_whole_string? "^" : ""; + kwsys_stl::string::const_iterator pattern_first = pattern.begin(); + kwsys_stl::string::const_iterator pattern_last = pattern.end(); + for(kwsys_stl::string::const_iterator i = pattern_first; + i != pattern_last; ++i) + { + int c = *i; + if(c == '*') + { + // A '*' (not between brackets) matches any string. + // We modify this to not match slashes since the orignal glob + // pattern documentation was meant for matching file name + // components separated by slashes. + regex += "[^/]*"; + } + else if(c == '?') + { + // A '?' (not between brackets) matches any single character. + // We modify this to not match slashes since the orignal glob + // pattern documentation was meant for matching file name + // components separated by slashes. + regex += "[^/]"; + } + else if(c == '[') + { + // Parse out the bracket expression. It begins just after the + // opening character. + kwsys_stl::string::const_iterator bracket_first = i+1; + kwsys_stl::string::const_iterator bracket_last = bracket_first; + + // The first character may be complementation '!' or '^'. + if(bracket_last != pattern_last && + (*bracket_last == '!' || *bracket_last == '^')) + { + ++bracket_last; + } + + // If the next character is a ']' it is included in the brackets + // because the bracket string may not be empty. + if(bracket_last != pattern_last && *bracket_last == ']') + { + ++bracket_last; + } + + // Search for the closing ']'. + while(bracket_last != pattern_last && *bracket_last != ']') + { + ++bracket_last; + } + + // Check whether we have a complete bracket string. + if(bracket_last == pattern_last) + { + // The bracket string did not end, so it was opened simply by + // a '[' that is supposed to be matched literally. + regex += "\\["; + } + else + { + // Convert the bracket string to its regex equivalent. + kwsys_stl::string::const_iterator k = bracket_first; + + // Open the regex block. + regex += "["; + + // A regex range complement uses '^' instead of '!'. + if(k != bracket_last && *k == '!') + { + regex += "^"; + ++k; + } + + // Convert the remaining characters. + for(; k != bracket_last; ++k) + { + // Backslashes must be escaped. + if(*k == '\\') + { + regex += "\\"; + } + + // Store this character. + regex += *k; + } + + // Close the regex block. + regex += "]"; + + // Jump to the end of the bracket string. + i = bracket_last; + } + } + else + { + // A single character matches itself. + int ch = c; + if(!(('a' <= ch && ch <= 'z') || + ('A' <= ch && ch <= 'Z') || + ('0' <= ch && ch <= '9'))) + { + // Escape the non-alphanumeric character. + regex += "\\"; + } +#if defined(KWSYS_GLOB_CASE_INDEPENDENT) + else + { + // On case-insensitive systems file names are converted to lower + // case before matching. + if(!preserve_case) + { + ch = tolower(ch); + } + } +#endif + (void)preserve_case; + // Store the character. + regex.append(1, static_cast<char>(ch)); + } + } + + if(require_whole_string) + { + regex += "$"; + } + return regex; +} + +//---------------------------------------------------------------------------- +void Glob::RecurseDirectory(kwsys_stl::string::size_type start, + const kwsys_stl::string& dir) +{ + kwsys::Directory d; + if ( !d.Load(dir.c_str()) ) + { + return; + } + unsigned long cc; + kwsys_stl::string fullname; + kwsys_stl::string realname; + kwsys_stl::string fname; + for ( cc = 0; cc < d.GetNumberOfFiles(); cc ++ ) + { + fname = d.GetFile(cc); + if ( strcmp(fname.c_str(), ".") == 0 || + strcmp(fname.c_str(), "..") == 0 ) + { + continue; + } + + if ( start == 0 ) + { + realname = dir + fname; + } + else + { + realname = dir + "/" + fname; + } + +#if defined( KWSYS_GLOB_CASE_INDEPENDENT ) + // On Windows and apple, no difference between lower and upper case + fname = kwsys::SystemTools::LowerCase(fname); +#endif + + if ( start == 0 ) + { + fullname = dir + fname; + } + else + { + fullname = dir + "/" + fname; + } + + bool isDir = kwsys::SystemTools::FileIsDirectory(realname.c_str()); + bool isSymLink = kwsys::SystemTools::FileIsSymlink(realname.c_str()); + + if ( isDir && (!isSymLink || this->RecurseThroughSymlinks) ) + { + if (isSymLink) + { + ++this->FollowedSymlinkCount; + } + this->RecurseDirectory(start+1, realname); + } + else + { + if ( (this->Internals->Expressions.size() > 0) && + this->Internals->Expressions[ + this->Internals->Expressions.size()-1].find(fname.c_str()) ) + { + this->AddFile(this->Internals->Files, realname.c_str()); + } + } + } +} + +//---------------------------------------------------------------------------- +void Glob::ProcessDirectory(kwsys_stl::string::size_type start, + const kwsys_stl::string& dir) +{ + //kwsys_ios::cout << "ProcessDirectory: " << dir << kwsys_ios::endl; + bool last = ( start == this->Internals->Expressions.size()-1 ); + if ( last && this->Recurse ) + { + this->RecurseDirectory(start, dir); + return; + } + + if ( start >= this->Internals->Expressions.size() ) + { + return; + } + + kwsys::Directory d; + if ( !d.Load(dir.c_str()) ) + { + return; + } + unsigned long cc; + kwsys_stl::string fullname; + kwsys_stl::string realname; + kwsys_stl::string fname; + for ( cc = 0; cc < d.GetNumberOfFiles(); cc ++ ) + { + fname = d.GetFile(cc); + if ( strcmp(fname.c_str(), ".") == 0 || + strcmp(fname.c_str(), "..") == 0 ) + { + continue; + } + + if ( start == 0 ) + { + realname = dir + fname; + } + else + { + realname = dir + "/" + fname; + } + +#if defined(KWSYS_GLOB_CASE_INDEPENDENT) + // On case-insensitive file systems convert to lower case for matching. + fname = kwsys::SystemTools::LowerCase(fname); +#endif + + if ( start == 0 ) + { + fullname = dir + fname; + } + else + { + fullname = dir + "/" + fname; + } + + //kwsys_ios::cout << "Look at file: " << fname << kwsys_ios::endl; + //kwsys_ios::cout << "Match: " + // << this->Internals->TextExpressions[start].c_str() << kwsys_ios::endl; + //kwsys_ios::cout << "Full name: " << fullname << kwsys_ios::endl; + + if ( !last && + !kwsys::SystemTools::FileIsDirectory(realname.c_str()) ) + { + continue; + } + + if ( this->Internals->Expressions[start].find(fname.c_str()) ) + { + if ( last ) + { + this->AddFile(this->Internals->Files, realname.c_str()); + } + else + { + this->ProcessDirectory(start+1, realname + "/"); + } + } + } +} + +//---------------------------------------------------------------------------- +bool Glob::FindFiles(const kwsys_stl::string& inexpr) +{ + kwsys_stl::string cexpr; + kwsys_stl::string::size_type cc; + kwsys_stl::string expr = inexpr; + + this->Internals->Expressions.clear(); + this->Internals->Files.clear(); + + if ( !kwsys::SystemTools::FileIsFullPath(expr.c_str()) ) + { + expr = kwsys::SystemTools::GetCurrentWorkingDirectory(); + expr += "/" + inexpr; + } + kwsys_stl::string fexpr = expr; + + kwsys_stl::string::size_type skip = 0; + kwsys_stl::string::size_type last_slash = 0; + for ( cc = 0; cc < expr.size(); cc ++ ) + { + if ( cc > 0 && expr[cc] == '/' && expr[cc-1] != '\\' ) + { + last_slash = cc; + } + if ( cc > 0 && + (expr[cc] == '[' || expr[cc] == '?' || expr[cc] == '*') && + expr[cc-1] != '\\' ) + { + break; + } + } + if ( last_slash > 0 ) + { + //kwsys_ios::cout << "I can skip: " << fexpr.substr(0, last_slash) + //<< kwsys_ios::endl; + skip = last_slash; + } + if ( skip == 0 ) + { +#if defined( KWSYS_GLOB_SUPPORT_NETWORK_PATHS ) + // Handle network paths + if ( expr[0] == '/' && expr[1] == '/' ) + { + int cnt = 0; + for ( cc = 2; cc < expr.size(); cc ++ ) + { + if ( expr[cc] == '/' ) + { + cnt ++; + if ( cnt == 2 ) + { + break; + } + } + } + skip = int(cc + 1); + } + else +#endif + // Handle drive letters on Windows + if ( expr[1] == ':' && expr[0] != '/' ) + { + skip = 2; + } + } + + if ( skip > 0 ) + { + expr = expr.substr(skip); + } + + cexpr = ""; + for ( cc = 0; cc < expr.size(); cc ++ ) + { + int ch = expr[cc]; + if ( ch == '/' ) + { + if ( cexpr.size() > 0 ) + { + this->AddExpression(cexpr.c_str()); + } + cexpr = ""; + } + else + { + cexpr.append(1, static_cast<char>(ch)); + } + } + if ( cexpr.size() > 0 ) + { + this->AddExpression(cexpr.c_str()); + } + + // Handle network paths + if ( skip > 0 ) + { + this->ProcessDirectory(0, fexpr.substr(0, skip) + "/"); + } + else + { + this->ProcessDirectory(0, "/"); + } + return true; +} + +//---------------------------------------------------------------------------- +void Glob::AddExpression(const char* expr) +{ + this->Internals->Expressions.push_back( + kwsys::RegularExpression( + this->PatternToRegex(expr).c_str())); +} + +//---------------------------------------------------------------------------- +void Glob::SetRelative(const char* dir) +{ + if ( !dir ) + { + this->Relative = ""; + return; + } + this->Relative = dir; +} + +//---------------------------------------------------------------------------- +const char* Glob::GetRelative() +{ + if ( this->Relative.empty() ) + { + return 0; + } + return this->Relative.c_str(); +} + +//---------------------------------------------------------------------------- +void Glob::AddFile(kwsys_stl::vector<kwsys_stl::string>& files, const char* file) +{ + if ( !this->Relative.empty() ) + { + files.push_back(kwsys::SystemTools::RelativePath(this->Relative.c_str(), file)); + } + else + { + files.push_back(file); + } +} + +} // namespace KWSYS_NAMESPACE + |