Resync
[CMakeLuaTailorHgBridge.git] / CMakeLua / Source / kwsys / Glob.cxx
blob4c17d63549598f320678181454d8227a89ff283b
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 = "";
67 this->RecurseThroughSymlinks = true;
68 // RecurseThroughSymlinks is true by default for backwards compatibility,
69 // not because it's a good idea...
70 this->FollowedSymlinkCount = 0;
73 //----------------------------------------------------------------------------
74 Glob::~Glob()
76 delete this->Internals;
79 //----------------------------------------------------------------------------
80 kwsys_stl::vector<kwsys_stl::string>& Glob::GetFiles()
82 return this->Internals->Files;
85 //----------------------------------------------------------------------------
86 kwsys_stl::string Glob::PatternToRegex(const kwsys_stl::string& pattern,
87 bool require_whole_string)
89 // Incrementally build the regular expression from the pattern.
90 kwsys_stl::string regex = require_whole_string? "^" : "";
91 kwsys_stl::string::const_iterator pattern_first = pattern.begin();
92 kwsys_stl::string::const_iterator pattern_last = pattern.end();
93 for(kwsys_stl::string::const_iterator i = pattern_first;
94 i != pattern_last; ++i)
96 int c = *i;
97 if(c == '*')
99 // A '*' (not between brackets) matches any string.
100 // We modify this to not match slashes since the orignal glob
101 // pattern documentation was meant for matching file name
102 // components separated by slashes.
103 regex += "[^/]*";
105 else if(c == '?')
107 // A '?' (not between brackets) matches any single character.
108 // We modify this to not match slashes since the orignal glob
109 // pattern documentation was meant for matching file name
110 // components separated by slashes.
111 regex += "[^/]";
113 else if(c == '[')
115 // Parse out the bracket expression. It begins just after the
116 // opening character.
117 kwsys_stl::string::const_iterator bracket_first = i+1;
118 kwsys_stl::string::const_iterator bracket_last = bracket_first;
120 // The first character may be complementation '!' or '^'.
121 if(bracket_last != pattern_last &&
122 (*bracket_last == '!' || *bracket_last == '^'))
124 ++bracket_last;
127 // If the next character is a ']' it is included in the brackets
128 // because the bracket string may not be empty.
129 if(bracket_last != pattern_last && *bracket_last == ']')
131 ++bracket_last;
134 // Search for the closing ']'.
135 while(bracket_last != pattern_last && *bracket_last != ']')
137 ++bracket_last;
140 // Check whether we have a complete bracket string.
141 if(bracket_last == pattern_last)
143 // The bracket string did not end, so it was opened simply by
144 // a '[' that is supposed to be matched literally.
145 regex += "\\[";
147 else
149 // Convert the bracket string to its regex equivalent.
150 kwsys_stl::string::const_iterator k = bracket_first;
152 // Open the regex block.
153 regex += "[";
155 // A regex range complement uses '^' instead of '!'.
156 if(k != bracket_last && *k == '!')
158 regex += "^";
159 ++k;
162 // Convert the remaining characters.
163 for(; k != bracket_last; ++k)
165 // Backslashes must be escaped.
166 if(*k == '\\')
168 regex += "\\";
171 // Store this character.
172 regex += *k;
175 // Close the regex block.
176 regex += "]";
178 // Jump to the end of the bracket string.
179 i = bracket_last;
182 else
184 // A single character matches itself.
185 int ch = c;
186 if(!(('a' <= ch && ch <= 'z') ||
187 ('A' <= ch && ch <= 'Z') ||
188 ('0' <= ch && ch <= '9')))
190 // Escape the non-alphanumeric character.
191 regex += "\\";
193 #if defined(KWSYS_GLOB_CASE_INDEPENDENT)
194 else
196 // On case-insensitive systems file names are converted to lower
197 // case before matching.
198 ch = tolower(ch);
200 #endif
202 // Store the character.
203 regex.append(1, static_cast<char>(ch));
207 if(require_whole_string)
209 regex += "$";
211 return regex;
214 //----------------------------------------------------------------------------
215 void Glob::RecurseDirectory(kwsys_stl::string::size_type start,
216 const kwsys_stl::string& dir, bool dir_only)
218 kwsys::Directory d;
219 if ( !d.Load(dir.c_str()) )
221 return;
223 unsigned long cc;
224 kwsys_stl::string fullname;
225 kwsys_stl::string realname;
226 kwsys_stl::string fname;
227 for ( cc = 0; cc < d.GetNumberOfFiles(); cc ++ )
229 fname = d.GetFile(cc);
230 if ( strcmp(fname.c_str(), ".") == 0 ||
231 strcmp(fname.c_str(), "..") == 0 )
233 continue;
236 if ( start == 0 )
238 realname = dir + fname;
240 else
242 realname = dir + "/" + fname;
245 #if defined( KWSYS_GLOB_CASE_INDEPENDENT )
246 // On Windows and apple, no difference between lower and upper case
247 fname = kwsys::SystemTools::LowerCase(fname);
248 #endif
250 if ( start == 0 )
252 fullname = dir + fname;
254 else
256 fullname = dir + "/" + fname;
259 if ( !dir_only || !kwsys::SystemTools::FileIsDirectory(realname.c_str()) )
261 if ( (this->Internals->Expressions.size() > 0) &&
262 this->Internals->Expressions[
263 this->Internals->Expressions.size()-1].find(fname.c_str()) )
265 this->AddFile(this->Internals->Files, realname.c_str());
268 if ( kwsys::SystemTools::FileIsDirectory(realname.c_str()) )
270 bool isSymLink = kwsys::SystemTools::FileIsSymlink(realname.c_str());
271 if (!isSymLink || this->RecurseThroughSymlinks)
273 if (isSymLink)
275 ++this->FollowedSymlinkCount;
277 this->RecurseDirectory(start+1, realname, dir_only);
283 //----------------------------------------------------------------------------
284 void Glob::ProcessDirectory(kwsys_stl::string::size_type start,
285 const kwsys_stl::string& dir, bool dir_only)
287 //kwsys_ios::cout << "ProcessDirectory: " << dir << kwsys_ios::endl;
288 bool last = ( start == this->Internals->Expressions.size()-1 );
289 if ( last && this->Recurse )
291 this->RecurseDirectory(start, dir, dir_only);
292 return;
295 if ( start >= this->Internals->Expressions.size() )
297 return;
300 kwsys::Directory d;
301 if ( !d.Load(dir.c_str()) )
303 return;
305 unsigned long cc;
306 kwsys_stl::string fullname;
307 kwsys_stl::string realname;
308 kwsys_stl::string fname;
309 for ( cc = 0; cc < d.GetNumberOfFiles(); cc ++ )
311 fname = d.GetFile(cc);
312 if ( strcmp(fname.c_str(), ".") == 0 ||
313 strcmp(fname.c_str(), "..") == 0 )
315 continue;
318 if ( start == 0 )
320 realname = dir + fname;
322 else
324 realname = dir + "/" + fname;
327 #if defined(KWSYS_GLOB_CASE_INDEPENDENT)
328 // On case-insensitive file systems convert to lower case for matching.
329 fname = kwsys::SystemTools::LowerCase(fname);
330 #endif
332 if ( start == 0 )
334 fullname = dir + fname;
336 else
338 fullname = dir + "/" + fname;
341 //kwsys_ios::cout << "Look at file: " << fname << kwsys_ios::endl;
342 //kwsys_ios::cout << "Match: "
343 // << this->Internals->TextExpressions[start].c_str() << kwsys_ios::endl;
344 //kwsys_ios::cout << "Full name: " << fullname << kwsys_ios::endl;
346 if ( (!dir_only || !last) &&
347 !kwsys::SystemTools::FileIsDirectory(realname.c_str()) )
349 continue;
352 if ( this->Internals->Expressions[start].find(fname.c_str()) )
354 if ( last )
356 this->AddFile(this->Internals->Files, realname.c_str());
358 else
360 this->ProcessDirectory(start+1, realname + "/", dir_only);
366 //----------------------------------------------------------------------------
367 bool Glob::FindFiles(const kwsys_stl::string& inexpr)
369 kwsys_stl::string cexpr;
370 kwsys_stl::string::size_type cc;
371 kwsys_stl::string expr = inexpr;
373 this->Internals->Expressions.clear();
374 this->Internals->Files.clear();
376 if ( !kwsys::SystemTools::FileIsFullPath(expr.c_str()) )
378 expr = kwsys::SystemTools::GetCurrentWorkingDirectory();
379 expr += "/" + inexpr;
381 kwsys_stl::string fexpr = expr;
383 kwsys_stl::string::size_type skip = 0;
384 kwsys_stl::string::size_type last_slash = 0;
385 for ( cc = 0; cc < expr.size(); cc ++ )
387 if ( cc > 0 && expr[cc] == '/' && expr[cc-1] != '\\' )
389 last_slash = cc;
391 if ( cc > 0 &&
392 (expr[cc] == '[' || expr[cc] == '?' || expr[cc] == '*') &&
393 expr[cc-1] != '\\' )
395 break;
398 if ( last_slash > 0 )
400 //kwsys_ios::cout << "I can skip: " << fexpr.substr(0, last_slash)
401 //<< kwsys_ios::endl;
402 skip = last_slash;
404 if ( skip == 0 )
406 #if defined( KWSYS_GLOB_SUPPORT_NETWORK_PATHS )
407 // Handle network paths
408 if ( expr[0] == '/' && expr[1] == '/' )
410 int cnt = 0;
411 for ( cc = 2; cc < expr.size(); cc ++ )
413 if ( expr[cc] == '/' )
415 cnt ++;
416 if ( cnt == 2 )
418 break;
422 skip = int(cc + 1);
424 else
425 #endif
426 // Handle drive letters on Windows
427 if ( expr[1] == ':' && expr[0] != '/' )
429 skip = 2;
433 if ( skip > 0 )
435 expr = expr.substr(skip);
438 cexpr = "";
439 for ( cc = 0; cc < expr.size(); cc ++ )
441 int ch = expr[cc];
442 if ( ch == '/' )
444 if ( cexpr.size() > 0 )
446 this->AddExpression(cexpr.c_str());
448 cexpr = "";
450 else
452 cexpr.append(1, static_cast<char>(ch));
455 if ( cexpr.size() > 0 )
457 this->AddExpression(cexpr.c_str());
460 // Handle network paths
461 if ( skip > 0 )
463 this->ProcessDirectory(0, fexpr.substr(0, skip) + "/",
464 true);
466 else
468 this->ProcessDirectory(0, "/", true);
470 return true;
473 //----------------------------------------------------------------------------
474 void Glob::AddExpression(const char* expr)
476 this->Internals->Expressions.push_back(
477 kwsys::RegularExpression(
478 this->PatternToRegex(expr).c_str()));
481 //----------------------------------------------------------------------------
482 void Glob::SetRelative(const char* dir)
484 if ( !dir )
486 this->Relative = "";
487 return;
489 this->Relative = dir;
492 //----------------------------------------------------------------------------
493 const char* Glob::GetRelative()
495 if ( this->Relative.empty() )
497 return 0;
499 return this->Relative.c_str();
502 //----------------------------------------------------------------------------
503 void Glob::AddFile(kwsys_stl::vector<kwsys_stl::string>& files, const char* file)
505 if ( !this->Relative.empty() )
507 files.push_back(kwsys::SystemTools::RelativePath(this->Relative.c_str(), file));
509 else
511 files.push_back(file);
515 } // namespace KWSYS_NAMESPACE