-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement fr_find{first,next} with std::filesystem
- Loading branch information
1 parent
69cfc7f
commit 402baf3
Showing
11 changed files
with
382 additions
and
176 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
#include "find_file.h" | ||
|
||
#include "path_match.h" | ||
|
||
DIR_SEARCH DTA; // Allocate DTA and define structure | ||
|
||
namespace fs = std::filesystem; | ||
|
||
static MatchFn s_path_matcher; | ||
enum class dir_pos | ||
{ | ||
NONE = 0, | ||
DOT = 1, | ||
DOT_DOT = 2, | ||
FILES = 3 | ||
}; | ||
static dir_pos s_dir_pos{dir_pos::NONE}; | ||
static fs::directory_iterator s_dir_it; | ||
|
||
/* fill_dta | ||
* | ||
* Use data in s_find_data to fill in DTA.filename, DTA.attribute and DTA.path | ||
*/ | ||
static void fill_dta() | ||
{ | ||
DTA.path = s_dir_it->path().string(); | ||
DTA.filename = s_dir_it->path().filename().string(); | ||
DTA.attribute = is_directory(*s_dir_it) ? SUBDIR : 0; | ||
} | ||
|
||
static bool next_match() | ||
{ | ||
if (s_dir_pos == dir_pos::NONE) | ||
{ | ||
DTA.path = (s_dir_it->path() / ".").string(); | ||
DTA.filename = "."; | ||
DTA.attribute = SUBDIR; | ||
s_dir_pos = dir_pos::DOT; | ||
return true; | ||
} | ||
if (s_dir_pos == dir_pos::DOT) | ||
{ | ||
DTA.path = (s_dir_it->path() / "..").string(); | ||
DTA.filename = ".."; | ||
DTA.attribute = SUBDIR; | ||
s_dir_pos = dir_pos::DOT_DOT; | ||
return true; | ||
} | ||
s_dir_pos = dir_pos::FILES; | ||
|
||
while (s_dir_it != fs::directory_iterator() && !s_path_matcher(*s_dir_it)) | ||
{ | ||
++s_dir_it; | ||
} | ||
if (s_dir_it == fs::directory_iterator()) | ||
{ | ||
s_dir_pos = dir_pos::NONE; | ||
return false; | ||
} | ||
|
||
fill_dta(); | ||
return true; | ||
} | ||
|
||
/* fr_findfirst | ||
* | ||
* Fill in DTA.filename, DTA.path and DTA.attribute for the first file | ||
* matching the wildcard specification in path. Return zero if a file | ||
* is found, or non-zero if a file was not found or an error occurred. | ||
*/ | ||
int fr_findfirst(char const *path) // Find 1st file (or subdir) meeting path/filespec | ||
{ | ||
const fs::path search{path}; | ||
const fs::path search_dir{is_directory(search) ? search : search.parent_path()}; | ||
std::error_code err; | ||
s_dir_it = fs::directory_iterator(search_dir, err); | ||
if (err) | ||
{ | ||
return 1; | ||
} | ||
|
||
s_path_matcher = match_fn(path); | ||
if (is_directory(search) || | ||
(search.filename() == "*" && (search.extension().string().empty() || search.extension() == ".*"))) | ||
{ | ||
s_dir_pos = dir_pos::NONE; | ||
} | ||
else | ||
{ | ||
s_dir_pos = dir_pos::FILES; | ||
} | ||
return next_match() ? 0 : 1; | ||
} | ||
|
||
/* fr_findnext | ||
* | ||
* Find the next file matching the wildcard search begun by fr_findfirst. | ||
* Fill in DTA.filename, DTA.path, and DTA.attribute | ||
*/ | ||
int fr_findnext() | ||
{ | ||
if (s_dir_pos == dir_pos::FILES) | ||
{ | ||
++s_dir_it; | ||
} | ||
return next_match() ? 0 : -1; | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
#include <path_match.h> | ||
|
||
#include <regex> | ||
|
||
namespace fs = std::filesystem; | ||
|
||
static bool match_wild_string(const std::string &pattern, const std::string &text) | ||
{ | ||
if (text.length() != pattern.length()) | ||
{ | ||
return false; | ||
} | ||
for (std::size_t i = 0; i < text.length(); ++i) | ||
{ | ||
if (pattern[i] != '?' && pattern[i] != text[i]) | ||
{ | ||
return false; | ||
} | ||
} | ||
return true; | ||
} | ||
|
||
static std::regex wild_regex(const std::string &wildcard) | ||
{ | ||
std::string pat; | ||
for (const char c : wildcard) | ||
{ | ||
if (c == '.') | ||
{ | ||
pat += "\\."; | ||
} | ||
else if (c == '?') | ||
{ | ||
pat += '.'; | ||
} | ||
else if (c == '*') | ||
{ | ||
pat += ".*"; | ||
} | ||
else | ||
{ | ||
pat += c; | ||
} | ||
} | ||
return std::regex(pat); | ||
}; | ||
|
||
MatchFn match_fn(const fs::path &pattern) | ||
{ | ||
MatchFn always = [](const fs::path &) { return true; }; | ||
|
||
MatchFn match_stem; | ||
const std::string pat_stem{pattern.stem().string()}; | ||
// match any filename | ||
if (pat_stem == "*") | ||
{ | ||
match_stem = always; | ||
} | ||
// match wildcard filename | ||
else if (pat_stem.find('?') != std::string::npos) | ||
{ | ||
if (pat_stem.find('*') == std::string::npos) | ||
{ | ||
match_stem = [=](const fs::path &path) { return match_wild_string(pat_stem, path.stem().string()); }; | ||
} | ||
else | ||
{ | ||
const std::regex pat_regex = wild_regex(pat_stem); | ||
match_stem = [=](const fs::path &path) { return std::regex_match(path.stem().string(), pat_regex); }; | ||
} | ||
} | ||
// match regex filename | ||
else if (pat_stem.find('*') != std::string::npos) | ||
{ | ||
const std::regex pat_regex = wild_regex(pat_stem); | ||
match_stem = [=](const fs::path &path) { return std::regex_match(path.stem().string(), pat_regex); }; | ||
} | ||
// match exact filename | ||
else | ||
{ | ||
match_stem = [=](const fs::path &path) { return pat_stem == path.stem().string(); }; | ||
} | ||
|
||
MatchFn match_ext; | ||
const std::string pat_ext{pattern.extension().string()}; | ||
// match any extension | ||
if (pat_ext == ".*" || pat_ext.empty()) | ||
{ | ||
match_ext = always; | ||
} | ||
// match extension with ? wildcards | ||
else if (pat_ext.find('?') != std::string::npos) | ||
{ | ||
if (pat_ext.find('*') == std::string::npos) | ||
{ | ||
match_ext = [=](const fs::path &path) { return match_wild_string(pat_ext, path.extension().string()); }; | ||
} | ||
else | ||
{ | ||
const std::regex pat_regex = wild_regex(pat_ext); | ||
match_ext = [=](const fs::path &path) { return std::regex_match(path.extension().string(), pat_regex); }; | ||
} | ||
} | ||
else if (pat_ext.find('*') != std::string::npos) | ||
{ | ||
const std::regex pat_regex = wild_regex(pat_ext); | ||
match_ext = [=](const fs::path &path) { return std::regex_match(path.extension().string(), pat_regex); }; | ||
} | ||
else | ||
// match specific extension | ||
{ | ||
match_ext = [=](const fs::path &path) { return pat_ext == path.extension(); }; | ||
} | ||
|
||
return [=](const fs::path &path) { return match_stem(path) && match_ext(path); }; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
#pragma once | ||
|
||
#include <filesystem> | ||
#include <functional> | ||
|
||
using MatchFn = std::function<bool(const std::filesystem::path &)>; | ||
|
||
MatchFn match_fn(const std::filesystem::path &pattern); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.