@@ -12,54 +12,52 @@ namespace fs = std::filesystem;
12
12
std::vector<std::string> DirectoryScanner::Scan (const fs::path& directory, const std::vector<std::string>& extensions,
13
13
const std::vector<std::string>& ignoreDirs) const
14
14
{
15
- // Scan a directory and return a list of all the paths to the files with the given extensions
16
- std::vector<std::string> file_paths;
17
-
18
- if (fs::exists (directory) && fs::is_directory (directory))
19
- {
20
- for (const auto & entry : fs::recursive_directory_iterator (directory))
21
- {
22
- if (fs::is_regular_file (entry.status ()))
23
- {
24
- // Check if the file has one of the extensions
25
- bool has_extension = false ;
26
- for (const auto & extension : extensions)
27
- {
28
- if (entry.path ().extension () == extension)
29
- {
30
- has_extension = true ;
31
- break ;
32
- }
33
- }
34
- if (!has_extension)
35
- continue ;
36
-
37
- try
38
- {
39
- file_paths.push_back (entry.path ().string ());
40
- }
41
- catch (const std::system_error& e)
42
- {
43
- // Sometimes throws this error:
44
- // No mapping for the Unicode character exists in the target multi-byte code page
15
+ std::vector<std::string> result;
16
+
17
+ if (!fs::exists (directory) || !fs::is_directory (directory)) {
18
+ return result;
19
+ }
20
+
21
+ // Normalize ignore directories into absolute canonical paths
22
+ std::vector<fs::path> ignorePaths;
23
+ for (const auto & dir : ignoreDirs) {
24
+ fs::path p (dir);
25
+ if (p.is_absolute ()) {
26
+ ignorePaths.push_back (fs::weakly_canonical (p));
27
+ } else {
28
+ ignorePaths.push_back (fs::weakly_canonical (directory / p));
29
+ }
30
+ }
45
31
46
- // Ignore the file and print a warning
47
- std::cerr << " Warning: System error thrown while getting a file path. Skipping file. \n " ;
48
- std::cerr << " Error message: " << e. what () << ' \n ' ;
32
+ fs::recursive_directory_iterator it (directory), end;
33
+ while (it != end) {
34
+ const fs::directory_entry& entry = *it ;
49
35
50
- continue ;
51
- }
52
- }
36
+ if (entry.is_directory ()) {
37
+ fs::path current = fs::weakly_canonical (entry.path ());
38
+
39
+ // Skip if inside any ignored directory
40
+ bool skip = std::any_of (ignorePaths.begin (), ignorePaths.end (),
41
+ [&](const fs::path& ignore) {
42
+ return isSubPath (ignore, current);
43
+ });
44
+
45
+ if (skip) {
46
+ it.disable_recursion_pending (); // skip this whole subtree
47
+ }
53
48
}
49
+ else if (entry.is_regular_file ()) {
50
+ std::string ext = entry.path ().extension ().string ();
51
+
52
+ if (std::find (extensions.begin (), extensions.end (), ext) != extensions.end ()) {
53
+ result.push_back (entry.path ().string ());
54
+ }
55
+ }
56
+
57
+ ++it;
54
58
}
55
- else
56
- {
57
- std::cerr << " Directory does not exist or is not a directory " << directory << std::endl;
58
- }
59
-
60
- // Remove files in ignored directories
61
- RemoveIgnoredFiles (file_paths, ignoreDirs);
62
- return file_paths;
59
+
60
+ return result;
63
61
}
64
62
65
63
std::vector<std::string> DirectoryScanner::FindIgnoredDirectories (const std::filesystem::path &directory, const std::vector<std::string> &ignorePatterns) const
@@ -102,19 +100,20 @@ std::vector<std::string> DirectoryScanner::FindIgnoredDirectories(const std::fil
102
100
return ignoredDirectories;
103
101
}
104
102
105
- void DirectoryScanner::RemoveIgnoredFiles ( std::vector<std::string> &filePaths , const std::vector<std::string> &ignoreDirs ) const
103
+ bool DirectoryScanner::isSubPath ( const std::filesystem::path &base , const std::filesystem::path &path ) const
106
104
{
107
- filePaths.erase (std::remove_if (filePaths.begin (), filePaths.end (),
108
- [&ignoreDirs](const std::string& filePath)
109
- {
110
- for (const auto & ignoreDir : ignoreDirs)
111
- {
112
- if (filePath.find (ignoreDir) != std::string::npos)
113
- {
114
- return true ; // Remove this file
115
- }
116
- }
117
- return false ; // Keep this file
118
- }),
119
- filePaths.end ());
105
+ auto baseAbs = fs::weakly_canonical (base);
106
+ auto pathAbs = fs::weakly_canonical (path);
107
+
108
+ auto baseIt = baseAbs.begin ();
109
+ auto pathIt = pathAbs.begin ();
110
+
111
+ for (; baseIt != baseAbs.end () && pathIt != pathAbs.end (); ++baseIt, ++pathIt) {
112
+ if (*baseIt != *pathIt) {
113
+ return false ;
114
+ }
115
+ }
116
+
117
+ // True if base was fully consumed (base == path, or base is a prefix of path)
118
+ return baseIt == baseAbs.end ();
120
119
}
0 commit comments