From fdc4795b9131d43bc06a4051eac1ddeb11c2bce7 Mon Sep 17 00:00:00 2001 From: Andy Cedilnik Date: Tue, 18 Oct 2005 14:08:55 -0400 Subject: ENH: Push glob to the kwsys --- Source/kwsys/CMakeLists.txt | 8 +- Source/kwsys/Glob.cxx | 428 ++++++++++++++++++++++++++++++++++++++++++++ Source/kwsys/Glob.hxx.in | 81 +++++++++ bootstrap | 2 + 4 files changed, 518 insertions(+), 1 deletion(-) create mode 100644 Source/kwsys/Glob.cxx create mode 100644 Source/kwsys/Glob.hxx.in diff --git a/Source/kwsys/CMakeLists.txt b/Source/kwsys/CMakeLists.txt index c0b4f66..38254b1 100644 --- a/Source/kwsys/CMakeLists.txt +++ b/Source/kwsys/CMakeLists.txt @@ -86,6 +86,7 @@ IF(KWSYS_STANDALONE OR CMake_SOURCE_DIR) # Enable all components. SET(KWSYS_USE_Base64 1) SET(KWSYS_USE_Directory 1) + SET(KWSYS_USE_Glob 1) SET(KWSYS_USE_Process 1) SET(KWSYS_USE_RegularExpression 1) SET(KWSYS_USE_Registry 1) @@ -416,9 +417,14 @@ SET(KWSYS_HXX_FILES Configure hashtable hash_fun hash_map hash_set) IF(KWSYS_USE_SystemTools) SET(KWSYS_USE_Directory 1) ENDIF(KWSYS_USE_SystemTools) +IF(KWSYS_USE_Glob) + SET(KWSYS_USE_Directory 1) + SET(KWSYS_USE_SystemTools 1) + SET(KWSYS_USE_RegularExpression 1) +ENDIF(KWSYS_USE_Glob) # Add selected C++ classes. -SET(cppclasses Directory RegularExpression SystemTools CommandLineArguments Registry) +SET(cppclasses Directory Glob RegularExpression SystemTools CommandLineArguments Registry) FOREACH(c ${cppclasses}) IF(KWSYS_USE_${c}) SET(KWSYS_CLASSES ${KWSYS_CLASSES} ${c}) diff --git a/Source/kwsys/Glob.cxx b/Source/kwsys/Glob.cxx new file mode 100644 index 0000000..def29d0 --- /dev/null +++ b/Source/kwsys/Glob.cxx @@ -0,0 +1,428 @@ +/*========================================================================= + + Program: KWSys - Kitware System Library + Module: $RCSfile$ + + Copyright (c) Kitware, Inc., Insight Consortium. All rights reserved. + See Copyright.txt or http://www.kitware.com/Copyright.htm for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices 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 "Configure.hxx.in" +# include "RegularExpression.hxx.in" +# include "SystemTools.hxx.in" +# include "kwsys_stl.hxx.in" +# include "kwsys_stl_string.hxx.in" +#endif + +#include +#include + +namespace KWSYS_NAMESPACE +{ +#if defined( _WIN32 ) || defined( APPLE ) || defined( __CYGWIN__ ) + // On Windows and apple, no difference between lower and upper case + #define CM_GLOB_CASE_INDEPENDENT +#endif + +#if defined( _WIN32 ) || defined( __CYGWIN__ ) + // Handle network paths + #define CM_GLOB_SUPPORT_NETWORK_PATHS +#endif + +//---------------------------------------------------------------------------- +class GlobInternals +{ +public: + std::vector Files; + std::vector Expressions; + std::vector TextExpressions; +}; + +//---------------------------------------------------------------------------- +Glob::Glob() +{ + m_Internals = new GlobInternals; + m_Recurse = false; +} + +//---------------------------------------------------------------------------- +Glob::~Glob() +{ + delete m_Internals; +} + +//---------------------------------------------------------------------------- +void Glob::Escape(int ch, char* buffer) +{ + if (! ( + 'a' <= ch && ch <= 'z' || + 'A' <= ch && ch <= 'Z' || + '0' <= ch && ch <= '9') ) + { + sprintf(buffer, "\\%c", ch); + } + else + { +#if defined( CM_GLOB_CASE_INDEPENDENT ) + // On Windows and apple, no difference between lower and upper case + sprintf(buffer, "%c", tolower(ch)); +#else + sprintf(buffer, "%c", ch); +#endif + } +} + +//---------------------------------------------------------------------------- +std::vector& Glob::GetFiles() +{ + return m_Internals->Files; +} + +//---------------------------------------------------------------------------- +std::string Glob::ConvertExpression(const std::string& expr) +{ + + std::string::size_type i = 0; + std::string::size_type n = expr.size(); + + std::string res = "^"; + std::string stuff = ""; + + while ( i < n ) + { + int c = expr[i]; + i = i+1; + if ( c == '*' ) + { + res = res + ".*"; + } + else if ( c == '?' ) + { + res = res + "."; + } + else if ( c == '[' ) + { + std::string::size_type j = i; + if ( j < n && ( expr[j] == '!' || expr[j] == '^' ) ) + { + j = j+1; + } + if ( j < n && expr[j] == ']' ) + { + j = j+1; + } + while ( j < n && expr[j] != ']' ) + { + j = j+1; + } + if ( j >= n ) + { + res = res + "\\["; + } + else + { + stuff = ""; + std::string::size_type cc; + for ( cc = i; cc < j; cc ++ ) + { + if ( expr[cc] == '\\' ) + { + stuff += "\\\\"; + } + else + { + stuff += expr[cc]; + } + } + i = j+1; + if ( stuff[0] == '!' || stuff[0] == '^' ) + { + stuff = '^' + stuff.substr(1); + } + else if ( stuff[0] == '^' ) + { + stuff = '\\' + stuff; + } + res = res + "[" + stuff + "]"; + } + } + else + { + char buffer[100]; + buffer[0] = 0; + this->Escape(c, buffer); + res = res + buffer; + } + } + return res + "$"; +} + +//---------------------------------------------------------------------------- +void Glob::RecurseDirectory(std::string::size_type start, + const std::string& dir, bool dir_only) +{ + cmsys::Directory d; + if ( !d.Load(dir.c_str()) ) + { + return; + } + unsigned long cc; + std::string fullname; + std::string realname; + std::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( CM_GLOB_CASE_INDEPENDENT ) + // On Windows and apple, no difference between lower and upper case + fname = cmsys::SystemTools::LowerCase(fname); +#endif + + if ( start == 0 ) + { + fullname = dir + fname; + } + else + { + fullname = dir + "/" + fname; + } + + if ( !dir_only || !cmsys::SystemTools::FileIsDirectory(realname.c_str()) ) + { + if ( m_Internals->Expressions[m_Internals->Expressions.size()-1].find(fname.c_str()) ) + { + m_Internals->Files.push_back(realname); + } + } + if ( cmsys::SystemTools::FileIsDirectory(realname.c_str()) ) + { + this->RecurseDirectory(start+1, realname, dir_only); + } + } +} + +//---------------------------------------------------------------------------- +void Glob::ProcessDirectory(std::string::size_type start, + const std::string& dir, bool dir_only) +{ + //std::cout << "ProcessDirectory: " << dir << std::endl; + bool last = ( start == m_Internals->Expressions.size()-1 ); + if ( last && m_Recurse ) + { + this->RecurseDirectory(start, dir, dir_only); + return; + } + cmsys::Directory d; + if ( !d.Load(dir.c_str()) ) + { + return; + } + unsigned long cc; + std::string fullname; + std::string realname; + std::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( CM_GLOB_CASE_INDEPENDENT ) + // On Windows and apple, no difference between lower and upper case + fname = cmsys::SystemTools::LowerCase(fname); +#endif + + if ( start == 0 ) + { + fullname = dir + fname; + } + else + { + fullname = dir + "/" + fname; + } + + //std::cout << "Look at file: " << fname << std::endl; + //std::cout << "Match: " << m_Internals->TextExpressions[start].c_str() << std::endl; + //std::cout << "Full name: " << fullname << std::endl; + + if ( (!dir_only || !last) && !cmsys::SystemTools::FileIsDirectory(realname.c_str()) ) + { + continue; + } + + if ( m_Internals->Expressions[start].find(fname.c_str()) ) + { + if ( last ) + { + m_Internals->Files.push_back(realname); + } + else + { + this->ProcessDirectory(start+1, realname + "/", dir_only); + } + } + } +} + +//---------------------------------------------------------------------------- +bool Glob::FindFiles(const std::string& inexpr) +{ + std::string cexpr; + std::string::size_type cc; + std::string expr = inexpr; + + m_Internals->Expressions.clear(); + m_Internals->Files.clear(); + + if ( !cmsys::SystemTools::FileIsFullPath(expr.c_str()) ) + { + expr = cmsys::SystemTools::GetCurrentWorkingDirectory(); + expr += "/" + inexpr; + } + std::string fexpr = expr; + + int skip = 0; + int 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 ) + { + //std::cout << "I can skip: " << fexpr.substr(0, last_slash) << std::endl; + skip = last_slash; + } + if ( skip == 0 ) + { +#if defined( CM_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 = 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, (char)ch); + } + } + if ( cexpr.size() > 0 ) + { + this->AddExpression(cexpr.c_str()); + } + + // Handle network paths + if ( skip > 0 ) + { + this->ProcessDirectory(0, fexpr.substr(0, skip) + "/", + true); + } + else + { + this->ProcessDirectory(0, "/", true); + } + return true; +} + +void Glob::AddExpression(const char* expr) +{ + m_Internals->Expressions.push_back( + cmsys::RegularExpression( + this->ConvertExpression(expr).c_str())); + m_Internals->TextExpressions.push_back(this->ConvertExpression(expr)); +} + +} // namespace KWSYS_NAMESPACE + diff --git a/Source/kwsys/Glob.hxx.in b/Source/kwsys/Glob.hxx.in new file mode 100644 index 0000000..ae793ef --- /dev/null +++ b/Source/kwsys/Glob.hxx.in @@ -0,0 +1,81 @@ +/*========================================================================= + + Program: KWSys - Kitware System Library + Module: $RCSfile$ + + Copyright (c) Kitware, Inc., Insight Consortium. All rights reserved. + See Copyright.txt or http://www.kitware.com/Copyright.htm for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ +#ifndef @KWSYS_NAMESPACE@_Glob_hxx +#define @KWSYS_NAMESPACE@_Glob_hxx + +#include <@KWSYS_NAMESPACE@/stl/string> +#include <@KWSYS_NAMESPACE@/stl/vector> + +#include <@KWSYS_NAMESPACE@/Configure.h> + +namespace @KWSYS_NAMESPACE@ +{ + +class GlobInternals; + +/** \class Glob + * \brief Portable globbing searches. + * + * Globbing expressions are much simpler than regular + * expressions. This class will search for files using + * globbing expressions. + * + * Finds all files that match a given globbing expression. + */ +class @KWSYS_NAMESPACE@_EXPORT Glob +{ +public: + Glob(); + ~Glob(); + + //! Find all files that match the pattern. + bool FindFiles(const std::string& inexpr); + + //! Return the list of files that matched. + std::vector& GetFiles(); + + //! Set recurse to true to match subdirectories. + void RecurseOn() { this->SetRecurse(true); } + void RecurseOff() { this->SetRecurse(false); } + void SetRecurse(bool i) { m_Recurse = i; } + bool GetRecurse() { return m_Recurse; } + +protected: + //! Process directory + void ProcessDirectory(std::string::size_type start, + const std::string& dir, bool dir_only); + + //! Process last directory, but only when recurse flags is on. That is + // effectively like saying: /path/to/file/**/file + void RecurseDirectory(std::string::size_type start, + const std::string& dir, bool dir_only); + + //! Escape all non-alphanumeric characters in pattern. + void Escape(int ch, char* buffer); + + //! + // Translate a shell PATTERN to a regular expression. + // There is no way to quote meta-characters. + std::string ConvertExpression(const std::string& expr); + + //! Add regular expression + void AddExpression(const char* expr); + + GlobInternals* m_Internals; + bool m_Recurse; +}; + +} // namespace @KWSYS_NAMESPACE@ + +#endif diff --git a/bootstrap b/bootstrap index 0070a5d..8073d1e 100755 --- a/bootstrap +++ b/bootstrap @@ -75,11 +75,13 @@ KWSYS_C_SOURCES="\ KWSYS_CXX_SOURCES="\ Directory \ + Glob \ RegularExpression \ SystemTools" KWSYS_FILES="\ Directory.hxx \ + Glob.hxx \ Process.h \ RegularExpression.hxx \ SystemTools.hxx" -- cgit v0.12