From db77d2e0192893ad9dda95bec0ebd9d6287fea14 Mon Sep 17 00:00:00 2001 From: Andy Cedilnik Date: Tue, 8 Jul 2003 14:18:17 -0400 Subject: ENH: Add globbing to FILE command --- Source/CMakeLists.txt | 1 + Source/cmFileCommand.cxx | 64 +++++++++++++ Source/cmFileCommand.h | 8 +- Source/cmGlob.cxx | 240 +++++++++++++++++++++++++++++++++++++++++++++++ Source/cmGlob.h | 61 ++++++++++++ bootstrap | 1 + 6 files changed, 373 insertions(+), 2 deletions(-) create mode 100644 Source/cmGlob.cxx create mode 100644 Source/cmGlob.h diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index de3d7f7..c1ef09c 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -15,6 +15,7 @@ cmCustomCommand.cxx cmCacheManager.cxx cmSourceGroup.cxx cmListFileCache.cxx +cmGlob.cxx cmGlobalGenerator.cxx cmGlobalUnixMakefileGenerator.cxx cmLocalGenerator.cxx diff --git a/Source/cmFileCommand.cxx b/Source/cmFileCommand.cxx index a24769f..6b7f036 100644 --- a/Source/cmFileCommand.cxx +++ b/Source/cmFileCommand.cxx @@ -16,6 +16,8 @@ =========================================================================*/ #include "cmFileCommand.h" +#include "cmGlob.h" + // cmLibraryCommand bool cmFileCommand::InitialPass(std::vector const& args) { @@ -37,6 +39,10 @@ bool cmFileCommand::InitialPass(std::vector const& args) { return this->HandleReadCommand(args); } + else if ( subCommand == "GLOB" ) + { + return this->HandleGlobCommand(args); + } std::string e = "does not recognize sub-command "+subCommand; this->SetError(e.c_str()); @@ -53,6 +59,12 @@ bool cmFileCommand::HandleWriteCommand(std::vector const& args, i++; // Get rid of subcommand std::string fileName = *i; + if ( !cmsys::SystemTools::FileIsFullPath(i->c_str()) ) + { + fileName = m_Makefile->GetCurrentDirectory(); + fileName += "/" + *i; + } + i++; for(;i != args.end(); ++i) @@ -82,9 +94,16 @@ bool cmFileCommand::HandleReadCommand(std::vector const& args) if ( args.size() != 3 ) { this->SetError("READ must be called with two additional arguments"); + return false; } std::string fileName = args[1]; + if ( !cmsys::SystemTools::FileIsFullPath(args[1].c_str()) ) + { + fileName = m_Makefile->GetCurrentDirectory(); + fileName += "/" + args[1]; + } + std::string variable = args[2]; std::ifstream file(fileName.c_str(), std::ios::in); if ( !file ) @@ -111,3 +130,48 @@ bool cmFileCommand::HandleReadCommand(std::vector const& args) return true; } +//---------------------------------------------------------------------------- +bool cmFileCommand::HandleGlobCommand(std::vector const& args) +{ + if ( args.size() < 2 ) + { + this->SetError("GLOB requires at least a variable name"); + return false; + } + + std::vector::const_iterator i = args.begin(); + + i++; // Get rid of subcommand + + std::string variable = *i; + i++; + cmGlob g; + std::string output = ""; + bool first = true; + for ( ; i != args.end(); ++i ) + { + if ( !cmsys::SystemTools::FileIsFullPath(i->c_str()) ) + { + std::string expr = m_Makefile->GetCurrentDirectory(); + expr += "/" + *i; + g.FindFiles(expr); + } + else + { + g.FindFiles(*i); + } + std::vector::size_type cc; + std::vector& files = g.GetFiles(); + for ( cc = 0; cc < files.size(); cc ++ ) + { + if ( !first ) + { + output += ";"; + } + output += files[cc]; + first = false; + } + } + m_Makefile->AddDefinition(variable.c_str(), output.c_str()); + return true; +} diff --git a/Source/cmFileCommand.h b/Source/cmFileCommand.h index a3bb48f..2a54451 100644 --- a/Source/cmFileCommand.h +++ b/Source/cmFileCommand.h @@ -69,19 +69,23 @@ public: " FILE(WRITE filename \"message to write\"... )\n" " FILE(APPEND filename \"message to write\"... )\n" " FILE(READ filename variable)\n" + " FILE(GLOB variable [globbing expressions]...)\n" "WRITE will write a message into a file called 'filename'. It " "overwrites the file if it already exists, and creates the file " "if it does not exists.\n\n" "APPEND will write a message into a file same as WRITE, except " "it will append it to the end of the file\n\n" - "READ will read the content of a file and store it into a " - "variable.\n\n"; } + "READ will read the content of a file and store it into the " + "variable.\n\n" + "GLOB will generate a list of all files that match the expressions " + "and store it into the variable.\n\n"; } cmTypeMacro(cmFileCommand, cmCommand); protected: bool HandleWriteCommand(std::vector const& args, bool append); bool HandleReadCommand(std::vector const& args); + bool HandleGlobCommand(std::vector const& args); }; diff --git a/Source/cmGlob.cxx b/Source/cmGlob.cxx new file mode 100644 index 0000000..6430c48 --- /dev/null +++ b/Source/cmGlob.cxx @@ -0,0 +1,240 @@ +/*========================================================================= + + Program: CMake - Cross-Platform Makefile Generator + Module: $RCSfile$ + Language: C++ + Date: $Date$ + Version: $Revision$ + + Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved. + See Copyright.txt or http://www.cmake.org/HTML/Copyright.html 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 "cmGlob.h" + +#include +#include +#include + +#include + +class cmGlobInternal +{ +public: + std::vector Files; + std::vector Expressions; +}; + +cmGlob::cmGlob() +{ + m_Internals = new cmGlobInternal; +} + +cmGlob::~cmGlob() +{ + delete m_Internals; +} + +void cmGlob::Escape(int ch, char* buffer) +{ + if (! ( + 'a' <= ch && ch <= 'z' || + 'A' <= ch && ch <= 'Z' || + '0' <= ch && ch <= '9') ) + { + sprintf(buffer, "\\%c", ch); + } + else + { + sprintf(buffer, "%c", ch); + } +} + +std::vector& cmGlob::GetFiles() +{ + return m_Internals->Files; +} + +std::string cmGlob::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] == '!' ) + { + 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 = '^' + 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 cmGlob::ProcessDirectory(std::string::size_type start, + const std::string& dir, bool dir_only) +{ + cmsys::Directory d; + if ( !d.Load(dir.c_str()) ) + { + //std::cout << "Cannot open directory: " << dir.c_str() << std::endl; + return; + } + unsigned long cc; + std::string fullname; + bool last = ( start == m_Internals->Expressions.size()-1 ); + //std::cout << "Last: " << last << " Dironly: " << dir_only << std::endl; + for ( cc = 0; cc < d.GetNumberOfFiles(); cc ++ ) + { + if ( strcmp(d.GetFile(cc), ".") == 0 || + strcmp(d.GetFile(cc), "..") == 0 ) + { + continue; + } + if ( start == 0 ) + { + fullname = dir + d.GetFile(cc); + } + else + { + fullname = dir + "/" + d.GetFile(cc); + } + + if ( (!dir_only || !last) && !cmsys::SystemTools::FileIsDirectory(fullname.c_str()) ) + { + //std::cout << " Ignore: " << fullname.c_str() << std::endl; + continue; + } + if ( m_Internals->Expressions[start].find(d.GetFile(cc)) ) + { + //std::cout << " Matches: " << fullname.c_str() << std::endl; + if ( last ) + { + //std::cout << "--- find file: " << fullname.c_str() << "---" << std::endl; + m_Internals->Files.push_back(fullname); + } + else + { + this->ProcessDirectory(start+1, fullname, dir_only); + } + } + else + { + //std::cout << " Not Matches: " << fullname.c_str() << std::endl; + } + } +} + +bool cmGlob::FindFiles(const std::string& inexpr) +{ + std::string cexpr; + std::string::size_type cc; + std::string expr = inexpr; + + m_Internals->Expressions.empty(); + m_Internals->Files.empty(); + + if ( !cmsys::SystemTools::FileIsFullPath(expr.c_str()) ) + { + expr = cmsys::SystemTools::GetCurrentWorkingDirectory(); + expr += "/" + inexpr; + } + std::cout << "Expr: " << expr << std::endl; + 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()); + } + + this->ProcessDirectory(0, "/", true); + return true; +} + +void cmGlob::AddExpression(const char* expr) +{ + m_Internals->Expressions.push_back( + cmsys::RegularExpression( + this->ConvertExpression(expr).c_str())); +} + diff --git a/Source/cmGlob.h b/Source/cmGlob.h new file mode 100644 index 0000000..1cfa4f8 --- /dev/null +++ b/Source/cmGlob.h @@ -0,0 +1,61 @@ +/*========================================================================= + + Program: CMake - Cross-Platform Makefile Generator + Module: $RCSfile$ + Language: C++ + Date: $Date$ + Version: $Revision$ + + Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved. + See Copyright.txt or http://www.cmake.org/HTML/Copyright.html 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 cmGlob_h +#define cmGlob_h + +#include "cmStandardIncludes.h" + +class cmGlobInternal; + +/** \class cmGlob + * \brief Helper class for performing globbing searches. + * + * Finds all files that match a given globbing expression. + */ +class cmGlob +{ +public: + cmGlob(); + ~cmGlob(); + + //! Find all files that match the pattern. + bool FindFiles(const std::string& inexpr); + + //! Return the list of files that matched. + std::vector& GetFiles(); + +protected: + //! Process directory + void ProcessDirectory(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); + + cmGlobInternal* m_Internals; +}; + + +#endif diff --git a/bootstrap b/bootstrap index b6b1852..688ce38 100755 --- a/bootstrap +++ b/bootstrap @@ -28,6 +28,7 @@ CMAKE_SOURCES="\ cmMakeDepend \ cmMakefile \ cmDocumentation \ + cmGlob \ cmGlobalGenerator \ cmLocalGenerator \ cmSourceFile \ -- cgit v0.12