From 7be524369a4226c54dffad40b85eef63ecb5f8f0 Mon Sep 17 00:00:00 2001 From: Keith Zantow Date: Sun, 16 Dec 2018 11:12:15 -0500 Subject: [PATCH] #77 enhance osx filesystem: fix `.` and `..` in directory listings & create recursive copying function --- libs/filesystem/filesystem.cpp | 175 ++++++++++++++++++++++++--------- libs/filesystem/filesystem.h | 31 +++++- 2 files changed, 155 insertions(+), 51 deletions(-) diff --git a/libs/filesystem/filesystem.cpp b/libs/filesystem/filesystem.cpp index def47ee0140..e61aa880d00 100644 --- a/libs/filesystem/filesystem.cpp +++ b/libs/filesystem/filesystem.cpp @@ -12,53 +12,67 @@ #include "filesystem.h" namespace std::experimental::filesystem { - path::path(): - path("") - {} - - path::path(std::string filePath): - p(filePath) - {} - - path::operator std::string() { - return p; - } - - void path::append(std::string s) { - p.append("/"); - p.append(s); - } - - const char* path::c_str() { - return p.c_str(); - } - - std::string path::generic_string() { - return p; - } - - path path::filename() { - auto idx = this->p.find_last_of("/"); - path p(this->p.substr(idx+1)); - return p; - } - - std::string path::extension() { - auto idx = this->p.find_last_of("."); - return p.substr(idx); - } + // path class: + path::path(): + path("") + {} - file::file(std::string filePath): - p(filePath) - {} - - file::operator class path() { - return p; - } - - path file::path() { - return p; - } + path::path(std::string filePath): + p(filePath) + {} + + path::operator std::string() { + return p; + } + + void path::append(std::string s) { + p.append("/"); + p.append(s); + } + + const char* path::c_str() { + return p.c_str(); + } + + std::string path::generic_string() const { + return p; + } + + path path::filename() { + auto idx = this->p.find_last_of("/"); + path p(this->p.substr(idx+1)); + return p; + } + + std::string path::extension() { + auto idx = this->p.find_last_of("."); + return p.substr(idx); + } + // emd path class + + // file class: + file::file(std::string filePath): + p(filePath) + {} + + file::operator class path() { + return p; + } + + path file::path() const { + return p; + } + // end file class + + // directory_entry class: + directory_entry::directory_entry(class path p): + p(p) + {} + + path directory_entry::path() const { + return p; + } + // end directory_entry bool exists(path p) { FILE *file; @@ -107,9 +121,13 @@ namespace std::experimental::filesystem { // this needs to return the full path not just the relative path while ((dirp = readdir(dp)) != NULL) { - path newp = p; - newp.append( dirp->d_name ); - file res( newp.c_str() ); + string fname(dirp->d_name); + // Skip . and .. : https://github.com/kurasu/surge/issues/77 + if (fname.compare(".") == 0 || fname.compare("..") == 0) { + continue; + } + + file res(p.generic_string() + '/' + fname); files.push_back(res); } @@ -118,6 +136,65 @@ namespace std::experimental::filesystem { return files; } + + std::vector recursive_directory_iterator(const path& src) { + std::vector entries; + for(const auto& entry : directory_iterator(src)) { + const auto& p = entry.path(); + directory_entry e(p); + entries.emplace_back(e); + if (is_directory(p)) { + std::vector subdir = recursive_directory_iterator(p); + for(const auto& subdirEntry : subdir) { + entries.emplace_back(subdirEntry); + } + } + } + return entries; + } + + path relative(const path& p, const path& root) { + return path(p.generic_string().substr(root.generic_string().length())); + } + + void copy(const path& src, const path& dst, const copy_options options) { + std::ifstream in(src.generic_string()); + std::ofstream out(dst.generic_string()); + out << in.rdbuf(); + } + + void copy_recursive(const path& src, const path& target, const std::function& predicate) noexcept + { + try + { + for (const auto& dirEntry : recursive_directory_iterator(src)) + { + const auto& p = dirEntry.path(); + if (predicate(p)) + { + // Create path in target, if not existing. + const auto relativeSrc = relative(p, src); + auto targetStr = target.generic_string() + '/' + relativeSrc.generic_string(); + path targetPath(targetStr); + if (is_directory(p)) { + create_directories(targetPath); + } else { + // Copy to the targetParentPath which we just created. + copy(p, targetPath, copy_options::overwrite_existing); + } + } + } + } + catch (std::exception& e) + { + // std::cout << e.what(); + } + } + + void copy_recursive(const path& src, const path& target) noexcept + { + copy_recursive(src, target, [](path p) { return true; }); + } } #endif diff --git a/libs/filesystem/filesystem.h b/libs/filesystem/filesystem.h index b31c411de65..41590eff8c7 100644 --- a/libs/filesystem/filesystem.h +++ b/libs/filesystem/filesystem.h @@ -8,6 +8,8 @@ #ifndef Filesystem_h #define Filesystem_h +#include + #ifdef __APPLE__ #include "TargetConditionals.h" #ifdef TARGET_OS_MAC @@ -17,6 +19,7 @@ #include #include #include +#include namespace std::experimental::filesystem { class path { @@ -33,7 +36,7 @@ namespace std::experimental::filesystem { const char* c_str(); - std::string generic_string(); + std::string generic_string() const; path filename(); @@ -48,7 +51,16 @@ namespace std::experimental::filesystem { operator path(); - path path(); + path path() const; + }; + + class directory_entry { + public: + path p; + + directory_entry(path p); + + path path() const; }; bool exists(path p); @@ -58,6 +70,21 @@ namespace std::experimental::filesystem { bool is_directory(path p); std::vector directory_iterator(path p); + + std::vector recursive_directory_iterator(const path& src); + + path relative(const path& p, const path& root); + + enum copy_options { + overwrite_existing = 1 + }; + + void copy(const path& src, const path& dst, const copy_options options); + + // Exras: + void copy_recursive(const path& src, const path& target, const std::function& predicate) noexcept; + + void copy_recursive(const path& src, const path& target) noexcept; } #endif