Resync
[CMakeLuaTailorHgBridge.git] / CMakeLua / Source / kwsys / Glob.cxx
blobe558908ddcb3ee723a7416622f66786a239ee51b
1 /*=========================================================================
3 Program: KWSys - Kitware System Library
4 Module: $RCSfile: Glob.cxx,v $
6 Copyright (c) Kitware, Inc., Insight Consortium. All rights reserved.
7 See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
9 This software is distributed WITHOUT ANY WARRANTY; without even
10 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
11 PURPOSE. See the above copyright notices for more information.
13 =========================================================================*/
14 #include "kwsysPrivate.h"
15 #include KWSYS_HEADER(Glob.hxx)
17 #include KWSYS_HEADER(Configure.hxx)
19 #include KWSYS_HEADER(RegularExpression.hxx)
20 #include KWSYS_HEADER(SystemTools.hxx)
21 #include KWSYS_HEADER(Directory.hxx)
22 #include KWSYS_HEADER(stl/string)
23 #include KWSYS_HEADER(stl/vector)
25 // Work-around CMake dependency scanning limitation. This must
26 // duplicate the above list of headers.
27 #if 0
28 # include "Glob.hxx.in"
29 # include "Directory.hxx.in"
30 # include "Configure.hxx.in"
31 # include "RegularExpression.hxx.in"
32 # include "SystemTools.hxx.in"
33 # include "kwsys_stl.hxx.in"
34 # include "kwsys_stl_string.hxx.in"
35 #endif
37 #include <ctype.h>
38 #include <stdio.h>
39 #include <string.h>
40 namespace KWSYS_NAMESPACE
42 #if defined(_WIN32) || defined(__APPLE__) || defined(__CYGWIN__)
43 // On Windows and apple, no difference between lower and upper case
44 # define KWSYS_GLOB_CASE_INDEPENDENT
45 #endif
47 #if defined(_WIN32) || defined(__CYGWIN__)
48 // Handle network paths
49 # define KWSYS_GLOB_SUPPORT_NETWORK_PATHS
50 #endif
52 //----------------------------------------------------------------------------
53 class GlobInternals
55 public:
56 kwsys_stl::vector<kwsys_stl::string> Files;
57 kwsys_stl::vector<kwsys::RegularExpression> Expressions;
60 //----------------------------------------------------------------------------
61 Glob::Glob()
63 this->Internals = new GlobInternals;
64 this->Recurse = false;
65 this->Relative = "";
68 //----------------------------------------------------------------------------
69 Glob::~Glob()
71 delete this->Internals;
74 //----------------------------------------------------------------------------
75 kwsys_stl::vector<kwsys_stl::string>& Glob::GetFiles()
77 return this->Internals->Files;
80 //----------------------------------------------------------------------------
81 kwsys_stl::string Glob::PatternToRegex(const kwsys_stl::string& pattern,
82 bool require_whole_string)
84 // Incrementally build the regular expression from the pattern.
85 kwsys_stl::string regex = require_whole_string? "^" : "";
86 kwsys_stl::string::const_iterator pattern_first = pattern.begin();
87 kwsys_stl::string::const_iterator pattern_last = pattern.end();
88 for(kwsys_stl::string::const_iterator i = pattern_first;
89 i != pattern_last; ++i)
91 int c = *i;
92 if(c == '*')
94 // A '*' (not between brackets) matches any string.
95 // We modify this to not match slashes since the orignal glob
96 // pattern documentation was meant for matching file name
97 // components separated by slashes.
98 regex += "[^/]*";
100 else if(c == '?')
102 // A '?' (not between brackets) matches any single character.
103 // We modify this to not match slashes since the orignal glob
104 // pattern documentation was meant for matching file name
105 // components separated by slashes.
106 regex += "[^/]";
108 else if(c == '[')
110 // Parse out the bracket expression. It begins just after the
111 // opening character.
112 kwsys_stl::string::const_iterator bracket_first = i+1;
113 kwsys_stl::string::const_iterator bracket_last = bracket_first;
115 // The first character may be complementation '!' or '^'.
116 if(bracket_last != pattern_last &&
117 (*bracket_last == '!' || *bracket_last == '^'))
119 ++bracket_last;
122 // If the next character is a ']' it is included in the brackets
123 // because the bracket string may not be empty.
124 if(bracket_last != pattern_last && *bracket_last == ']')
126 ++bracket_last;
129 // Search for the closing ']'.
130 while(bracket_last != pattern_last && *bracket_last != ']')
132 ++bracket_last;
135 // Check whether we have a complete bracket string.
136 if(bracket_last == pattern_last)
138 // The bracket string did not end, so it was opened simply by
139 // a '[' that is supposed to be matched literally.
140 regex += "\\[";
142 else
144 // Convert the bracket string to its regex equivalent.
145 kwsys_stl::string::const_iterator k = bracket_first;
147 // Open the regex block.
148 regex += "[";
150 // A regex range complement uses '^' instead of '!'.
151 if(k != bracket_last && *k == '!')
153 regex += "^";
154 ++k;
157 // Convert the remaining characters.
158 for(; k != bracket_last; ++k)
160 // Backslashes must be escaped.
161 if(*k == '\\')
163 regex += "\\";
166 // Store this character.
167 regex += *k;
170 // Close the regex block.
171 regex += "]";
173 // Jump to the end of the bracket string.
174 i = bracket_last;
177 else
179 // A single character matches itself.
180 int ch = c;
181 if(!(('a' <= ch && ch <= 'z') ||
182 ('A' <= ch && ch <= 'Z') ||
183 ('0' <= ch && ch <= '9')))
185 // Escape the non-alphanumeric character.
186 regex += "\\";
188 #if defined(KWSYS_GLOB_CASE_INDEPENDENT)
189 else
191 // On case-insensitive systems file names are converted to lower
192 // case before matching.
193 ch = tolower(ch);
195 #endif
197 // Store the character.
198 regex.append(1, static_cast<char>(ch));
202 if(require_whole_string)
204 regex += "$";
206 return regex;
209 //----------------------------------------------------------------------------
210 void Glob::RecurseDirectory(kwsys_stl::string::size_type start,
211 const kwsys_stl::string& dir, bool dir_only)
213 kwsys::Directory d;
214 if ( !d.Load(dir.c_str()) )
216 return;
218 unsigned long cc;
219 kwsys_stl::string fullname;
220 kwsys_stl::string realname;
221 kwsys_stl::string fname;
222 for ( cc = 0; cc < d.GetNumberOfFiles(); cc ++ )
224 fname = d.GetFile(cc);
225 if ( strcmp(fname.c_str(), ".") == 0 ||
226 strcmp(fname.c_str(), "..") == 0 )
228 continue;
231 if ( start == 0 )
233 realname = dir + fname;
235 else
237 realname = dir + "/" + fname;
240 #if defined( KWSYS_GLOB_CASE_INDEPENDENT )
241 // On Windows and apple, no difference between lower and upper case
242 fname = kwsys::SystemTools::LowerCase(fname);
243 #endif
245 if ( start == 0 )
247 fullname = dir + fname;
249 else
251 fullname = dir + "/" + fname;
254 if ( !dir_only || !kwsys::SystemTools::FileIsDirectory(realname.c_str()) )
256 if ( (this->Internals->Expressions.size() > 0) &&
257 this->Internals->Expressions[
258 this->Internals->Expressions.size()-1].find(fname.c_str()) )
260 this->AddFile(this->Internals->Files, realname.c_str());
263 if ( kwsys::SystemTools::FileIsDirectory(realname.c_str()) )
265 this->RecurseDirectory(start+1, realname, dir_only);
270 //----------------------------------------------------------------------------
271 void Glob::ProcessDirectory(kwsys_stl::string::size_type start,
272 const kwsys_stl::string& dir, bool dir_only)
274 //kwsys_ios::cout << "ProcessDirectory: " << dir << kwsys_ios::endl;
275 bool last = ( start == this->Internals->Expressions.size()-1 );
276 if ( last && this->Recurse )
278 this->RecurseDirectory(start, dir, dir_only);
279 return;
282 if ( start >= this->Internals->Expressions.size() )
284 return;
287 kwsys::Directory d;
288 if ( !d.Load(dir.c_str()) )
290 return;
292 unsigned long cc;
293 kwsys_stl::string fullname;
294 kwsys_stl::string realname;
295 kwsys_stl::string fname;
296 for ( cc = 0; cc < d.GetNumberOfFiles(); cc ++ )
298 fname = d.GetFile(cc);
299 if ( strcmp(fname.c_str(), ".") == 0 ||
300 strcmp(fname.c_str(), "..") == 0 )
302 continue;
305 if ( start == 0 )
307 realname = dir + fname;
309 else
311 realname = dir + "/" + fname;
314 #if defined(KWSYS_GLOB_CASE_INDEPENDENT)
315 // On case-insensitive file systems convert to lower case for matching.
316 fname = kwsys::SystemTools::LowerCase(fname);
317 #endif
319 if ( start == 0 )
321 fullname = dir + fname;
323 else
325 fullname = dir + "/" + fname;
328 //kwsys_ios::cout << "Look at file: " << fname << kwsys_ios::endl;
329 //kwsys_ios::cout << "Match: "
330 // << this->Internals->TextExpressions[start].c_str() << kwsys_ios::endl;
331 //kwsys_ios::cout << "Full name: " << fullname << kwsys_ios::endl;
333 if ( (!dir_only || !last) &&
334 !kwsys::SystemTools::FileIsDirectory(realname.c_str()) )
336 continue;
339 if ( this->Internals->Expressions[start].find(fname.c_str()) )
341 if ( last )
343 this->AddFile(this->Internals->Files, realname.c_str());
345 else
347 this->ProcessDirectory(start+1, realname + "/", dir_only);
353 //----------------------------------------------------------------------------
354 bool Glob::FindFiles(const kwsys_stl::string& inexpr)
356 kwsys_stl::string cexpr;
357 kwsys_stl::string::size_type cc;
358 kwsys_stl::string expr = inexpr;
360 this->Internals->Expressions.clear();
361 this->Internals->Files.clear();
363 if ( !kwsys::SystemTools::FileIsFullPath(expr.c_str()) )
365 expr = kwsys::SystemTools::GetCurrentWorkingDirectory();
366 expr += "/" + inexpr;
368 kwsys_stl::string fexpr = expr;
370 int skip = 0;
371 int last_slash = 0;
372 for ( cc = 0; cc < expr.size(); cc ++ )
374 if ( cc > 0 && expr[cc] == '/' && expr[cc-1] != '\\' )
376 last_slash = static_cast<int>(cc);
378 if ( cc > 0 &&
379 (expr[cc] == '[' || expr[cc] == '?' || expr[cc] == '*') &&
380 expr[cc-1] != '\\' )
382 break;
385 if ( last_slash > 0 )
387 //kwsys_ios::cout << "I can skip: " << fexpr.substr(0, last_slash)
388 //<< kwsys_ios::endl;
389 skip = last_slash;
391 if ( skip == 0 )
393 #if defined( KWSYS_GLOB_SUPPORT_NETWORK_PATHS )
394 // Handle network paths
395 if ( expr[0] == '/' && expr[1] == '/' )
397 int cnt = 0;
398 for ( cc = 2; cc < expr.size(); cc ++ )
400 if ( expr[cc] == '/' )
402 cnt ++;
403 if ( cnt == 2 )
405 break;
409 skip = int(cc + 1);
411 else
412 #endif
413 // Handle drive letters on Windows
414 if ( expr[1] == ':' && expr[0] != '/' )
416 skip = 2;
420 if ( skip > 0 )
422 expr = expr.substr(skip);
425 cexpr = "";
426 for ( cc = 0; cc < expr.size(); cc ++ )
428 int ch = expr[cc];
429 if ( ch == '/' )
431 if ( cexpr.size() > 0 )
433 this->AddExpression(cexpr.c_str());
435 cexpr = "";
437 else
439 cexpr.append(1, static_cast<char>(ch));
442 if ( cexpr.size() > 0 )
444 this->AddExpression(cexpr.c_str());
447 // Handle network paths
448 if ( skip > 0 )
450 this->ProcessDirectory(0, fexpr.substr(0, skip) + "/",
451 true);
453 else
455 this->ProcessDirectory(0, "/", true);
457 return true;
460 //----------------------------------------------------------------------------
461 void Glob::AddExpression(const char* expr)
463 this->Internals->Expressions.push_back(
464 kwsys::RegularExpression(
465 this->PatternToRegex(expr).c_str()));
468 //----------------------------------------------------------------------------
469 void Glob::SetRelative(const char* dir)
471 if ( !dir )
473 this->Relative = "";
474 return;
476 this->Relative = dir;
479 //----------------------------------------------------------------------------
480 const char* Glob::GetRelative()
482 if ( this->Relative.empty() )
484 return 0;
486 return this->Relative.c_str();
489 //----------------------------------------------------------------------------
490 void Glob::AddFile(kwsys_stl::vector<kwsys_stl::string>& files, const char* file)
492 if ( !this->Relative.empty() )
494 files.push_back(kwsys::SystemTools::RelativePath(this->Relative.c_str(), file));
496 else
498 files.push_back(file);
502 } // namespace KWSYS_NAMESPACE