diff --git a/g2o/apps/g2o_cli/dl_wrapper.cpp b/g2o/apps/g2o_cli/dl_wrapper.cpp index e3ef87b86..9fd55168a 100644 --- a/g2o/apps/g2o_cli/dl_wrapper.cpp +++ b/g2o/apps/g2o_cli/dl_wrapper.cpp @@ -28,8 +28,8 @@ #include -#include #include +#include #include "g2o/stuff/filesys_tools.h" #include "g2o/stuff/logger.h" @@ -38,19 +38,6 @@ #include #endif -#ifdef __APPLE__ -#define SO_EXT "dylib" -#define SO_EXT_LEN 5 -#elif defined(WINDOWS) || defined(CYGWIN) -#define SO_EXT "dll" -#define SO_EXT_LEN 3 -#else // Linux -#define SO_EXT "so" -#define SO_EXT_LEN 2 -#endif - -using namespace std; - namespace g2o { DlWrapper::DlWrapper() {} @@ -62,18 +49,12 @@ DlWrapper::~DlWrapper() { int DlWrapper::openLibraries(const std::string& directory, const std::string& pattern) { G2O_TRACE("Loading libraries from {} pattern {}", directory, pattern); - // cerr << "# loading libraries from " << directory << "\t pattern: " << - // pattern << endl; - string searchPattern = directory + "/" + pattern; - if (pattern == "") searchPattern = directory + "/*"; - vector matchingFiles = getFilesByPattern(searchPattern.c_str()); + std::vector matchingFiles = + getFilesByPattern(directory, std::regex(pattern)); int numLibs = 0; - for (size_t i = 0; i < matchingFiles.size(); ++i) { - const string& filename = matchingFiles[i]; - if (find(_filenames.begin(), _filenames.end(), filename) != - _filenames.end()) - continue; + for (const std::string& filename : matchingFiles) { + if (_filenames.count(filename) != 0) continue; // open the lib G2O_TRACE("Loading {}", filename); @@ -117,7 +98,7 @@ bool DlWrapper::openLibrary(const std::string& filename) { // cerr << "loaded " << filename << endl; - _filenames.push_back(filename); + _filenames.insert(filename); _handles.push_back(handle); return true; } diff --git a/g2o/apps/g2o_cli/dl_wrapper.h b/g2o/apps/g2o_cli/dl_wrapper.h index 96ea60014..79502f6e7 100644 --- a/g2o/apps/g2o_cli/dl_wrapper.h +++ b/g2o/apps/g2o_cli/dl_wrapper.h @@ -34,6 +34,7 @@ // clang-format on #include +#include #include #include "g2o_cli_api.h" @@ -77,7 +78,7 @@ class G2O_CLI_API DlWrapper { #elif defined(WINDOWS) std::vector _handles; #endif - std::vector _filenames; + std::unordered_set _filenames; }; } // namespace g2o diff --git a/g2o/apps/g2o_cli/g2o_common.cpp b/g2o/apps/g2o_cli/g2o_common.cpp index 35d2f58a0..da5b24353 100644 --- a/g2o/apps/g2o_cli/g2o_common.cpp +++ b/g2o/apps/g2o_cli/g2o_common.cpp @@ -71,8 +71,10 @@ HMODULE getMyInstance() { } #endif -static constexpr std::string_view TYPES_PATTERN = "*_types_*." SO_EXT; -static constexpr std::string_view SOLVERS_PATTERN = "*_solver_*." SO_EXT; +static constexpr std::string_view TYPES_PATTERN = + "^.*g2o_types_.*\\." SO_EXT "$"; +static constexpr std::string_view SOLVERS_PATTERN = + "^.*g2o_solver_.*\\." SO_EXT "$"; namespace g2o { diff --git a/g2o/stuff/filesys_tools.cpp b/g2o/stuff/filesys_tools.cpp index 84390b728..d99f16e9a 100644 --- a/g2o/stuff/filesys_tools.cpp +++ b/g2o/stuff/filesys_tools.cpp @@ -24,134 +24,75 @@ // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -/*************************************************************************** - * filesysTools.cpp - * - * Fr 02 Mär 2007 23:14:08 CET - * Copyright 2007 Rainer Kümmerle - * Email rk@raikue.net - ****************************************************************************/ #include "filesys_tools.h" -// clang-format off -#ifdef WINDOWS -#include -#endif -// clang-format on - -#include -#include - -#include -#include -#include - -#if (defined(UNIX) || defined(CYGWIN)) && !defined(ANDROID) -#include -#endif - -#ifdef __APPLE__ -// #include -// #include -#endif - -using namespace ::std; +#include +#include +#include namespace g2o { -std::string getFileExtension(const std::string& filename) { - std::string::size_type lastDot = filename.find_last_of('.'); - if (lastDot != std::string::npos) - return filename.substr(lastDot + 1); - else - return ""; +std::string getFileExtension(std::string_view filename) { + const std::filesystem::path path(filename); + const std::string result = path.extension().string(); + if (!result.empty() && result.front() == '.') return result.substr(1); + return result; } -std::string getPureFilename(const std::string& filename) { - std::string::size_type lastDot = filename.find_last_of('.'); - if (lastDot != std::string::npos) - return filename.substr(0, lastDot); - else - return filename; +std::string getPureFilename(std::string_view filename) { + const std::filesystem::path path(filename); + if (path.has_parent_path()) { + return (path.parent_path() / path.stem()).string(); + } + return path.stem().string(); } -std::string getBasename(const std::string& filename) { -#ifdef WINDOWS - std::string::size_type lastSlash = filename.find_last_of('\\'); -#else - std::string::size_type lastSlash = filename.find_last_of('/'); -#endif - if (lastSlash != std::string::npos) - return filename.substr(lastSlash + 1); - else - return filename; +std::string getBasename(std::string_view filename) { + const std::filesystem::path path(filename); + return path.filename().string(); } -std::string getDirname(const std::string& filename) { -#ifdef WINDOWS - std::string::size_type lastSlash = filename.find_last_of('\\'); -#else - std::string::size_type lastSlash = filename.find_last_of('/'); -#endif - if (lastSlash != std::string::npos) - return filename.substr(0, lastSlash); - else - return ""; +std::string getDirname(std::string_view filename) { + const std::filesystem::path path(filename); + return path.parent_path().string(); } -std::string changeFileExtension(const std::string& filename, - const std::string& newExt, bool stripDot) { - std::string::size_type lastDot = filename.find_last_of('.'); - if (lastDot != std::string::npos) { - if (stripDot) - return filename.substr(0, lastDot) + newExt; - else - return filename.substr(0, lastDot + 1) + newExt; - } else - return filename; +std::string changeFileExtension(std::string_view filename, + std::string_view newExt) { + std::filesystem::path path(filename); + if (!path.has_extension()) { + return path.string(); + } + path.replace_extension(std::filesystem::path(newExt)); + return path.string(); } -bool fileExists(const char* filename) { - struct stat statInfo; - return (stat(filename, &statInfo) == 0); +bool fileExists(std::string_view filename) { + const std::filesystem::path path(filename); + return std::filesystem::exists(path); } -std::vector getFilesByPattern(const char* pattern) { - std::vector result; - -#ifdef WINDOWS - - HANDLE hFind; - WIN32_FIND_DATA FData; - if ((hFind = FindFirstFile(pattern, &FData)) != INVALID_HANDLE_VALUE) { - do { - result.push_back(FData.cFileName); - } while (FindNextFile(hFind, &FData)); - FindClose(hFind); - } - -#elif (defined(UNIX) || defined(CYGWIN)) && !defined(ANDROID) - - wordexp_t p; - wordexp(pattern, &p, 0); +std::vector getFilesByPattern(std::string_view directory, + const std::regex& pattern) { + auto match = [&pattern](const std::filesystem::path& entry) { + return std::regex_search(entry.filename().string(), pattern); + }; - // For some reason, wordexp sometimes fails on an APPLE machine to - // return anything; therefore, run it several times until we do find - // something - or give up -#ifdef __APPLE__ - for (int k = 0; (k < 100) && (p.we_wordc == 0); k++) { - // chrono::milliseconds duration(20); - // this_thread::sleep_for(duration); - wordexp(pattern, &p, WRDE_APPEND); + std::vector result; + for (const auto& dir_entry : + std::filesystem::directory_iterator(std::filesystem::path(directory))) { + if (dir_entry.is_regular_file() && match(dir_entry)) { + result.emplace_back(dir_entry.path().string()); + continue; + } + if (dir_entry.is_symlink() && + std::filesystem::is_regular_file( + std::filesystem::read_symlink(dir_entry)) && + match(dir_entry)) { + result.emplace_back(dir_entry.path().string()); + continue; + } } -#endif - - result.reserve(p.we_wordc); - for (size_t i = 0; i < p.we_wordc; ++i) result.push_back(p.we_wordv[i]); - - wordfree(&p); - -#endif return result; } diff --git a/g2o/stuff/filesys_tools.h b/g2o/stuff/filesys_tools.h index 6e642a044..a2726a491 100644 --- a/g2o/stuff/filesys_tools.h +++ b/g2o/stuff/filesys_tools.h @@ -24,14 +24,6 @@ // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -/*************************************************************************** - * filesysTools.h - * - * Fr 02 Mär 2007 23:14:21 CET - * Copyright 2007 Rainer Kümmerle - * Email rk@raikue.net - ****************************************************************************/ - #ifndef G2O_FILESYS_TOOLS_H #define G2O_FILESYS_TOOLS_H @@ -44,7 +36,9 @@ * \brief utility functions for handling files, directory on Linux/Unix */ +#include #include +#include #include namespace g2o { @@ -53,43 +47,43 @@ namespace g2o { * get filename extension (the part after the last .), e.g. * the extension of file.txt is txt */ -G2O_STUFF_API std::string getFileExtension(const std::string& filename); +G2O_STUFF_API std::string getFileExtension(std::string_view filename); /** * get the filename without the extension. * file.txt -> file */ -G2O_STUFF_API std::string getPureFilename(const std::string& filename); +G2O_STUFF_API std::string getPureFilename(std::string_view filename); /** * change the fileextension of a given filename. * Only if filename contains an extension, otherwise filename is returned. */ -G2O_STUFF_API std::string changeFileExtension(const std::string& filename, - const std::string& newExt, - bool stripDot = false); +G2O_STUFF_API std::string changeFileExtension(std::string_view filename, + std::string_view newExt); /** * return the basename of the given filename * /etc/fstab -> fstab */ -G2O_STUFF_API std::string getBasename(const std::string& filename); +G2O_STUFF_API std::string getBasename(std::string_view filename); /** * return the directory of a given filename * /etc/fstab -> /etc */ -G2O_STUFF_API std::string getDirname(const std::string& filename); +G2O_STUFF_API std::string getDirname(std::string_view filename); /** * check if file exists (note a directory is also a file) */ -G2O_STUFF_API bool fileExists(const char* filename); +G2O_STUFF_API bool fileExists(std::string_view filename); /** - * return all files that match a given pattern, e.g., ~/blaa*.txt, /tmp/a* + * return all files that match a given regexp in the directory. */ -G2O_STUFF_API std::vector getFilesByPattern(const char* pattern); +G2O_STUFF_API std::vector getFilesByPattern( + std::string_view directory, const std::regex& pattern); } // namespace g2o // @} diff --git a/unit_test/stuff/filesys_tools_tests.cpp b/unit_test/stuff/filesys_tools_tests.cpp index c04c42096..0d6dbc559 100644 --- a/unit_test/stuff/filesys_tools_tests.cpp +++ b/unit_test/stuff/filesys_tools_tests.cpp @@ -24,78 +24,75 @@ // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#include +#include +#include #include "g2o/config.h" #include "g2o/stuff/filesys_tools.h" #include "gmock/gmock.h" -namespace { -#ifdef WINDOWS -static const std::string pathSep = "\\"; -#else -static const std::string pathSep = "/"; -#endif -} // namespace - TEST(Stuff, GetFileExtension) { - ASSERT_EQ("txt", g2o::getFileExtension("test.txt")); - ASSERT_EQ("txt", g2o::getFileExtension("/home/g2o/test.txt")); - ASSERT_EQ("", g2o::getFileExtension("/home/g2o/test")); - ASSERT_EQ("", g2o::getFileExtension("")); + EXPECT_EQ("txt", g2o::getFileExtension("test.txt")); + EXPECT_EQ("txt", g2o::getFileExtension("/home/g2o/test.txt")); + EXPECT_EQ("", g2o::getFileExtension("/home/g2o/test")); + EXPECT_EQ("", g2o::getFileExtension("")); } TEST(Stuff, GetPureFilename) { - ASSERT_EQ("test", g2o::getPureFilename("test.txt")); - ASSERT_EQ("test", g2o::getPureFilename("test")); - ASSERT_EQ("/home/g2o/test", g2o::getPureFilename("/home/g2o/test.txt")); - ASSERT_EQ("", g2o::getPureFilename("")); + EXPECT_EQ("test", g2o::getPureFilename("test.txt")); + EXPECT_EQ("test", g2o::getPureFilename("test")); + EXPECT_EQ("/home/g2o/test", g2o::getPureFilename("/home/g2o/test.txt")); + EXPECT_EQ("", g2o::getPureFilename("")); } TEST(Stuff, ChangeFileExtension) { - ASSERT_EQ("test.dat", g2o::changeFileExtension("test.txt", "dat", false)); - ASSERT_EQ("test.dat", g2o::changeFileExtension("test.txt", ".dat", true)); - ASSERT_EQ("test", g2o::changeFileExtension("test", "dat", false)); - ASSERT_EQ("test", g2o::changeFileExtension("test", ".dat", true)); + EXPECT_EQ("test.dat", g2o::changeFileExtension("test.txt", "dat")); + EXPECT_EQ("test.dat", g2o::changeFileExtension("test.txt", ".dat")); + EXPECT_EQ("test", g2o::changeFileExtension("test", "dat")); + EXPECT_EQ("test", g2o::changeFileExtension("test", ".dat")); } TEST(Stuff, GetBasename) { - ASSERT_EQ("test.txt", g2o::getBasename("test.txt")); - ASSERT_EQ("test", g2o::getBasename("test")); + EXPECT_EQ("test.txt", g2o::getBasename("test.txt")); + EXPECT_EQ("test", g2o::getBasename("test")); #ifdef WINDOWS - ASSERT_EQ("test.txt", g2o::getBasename("C:\\users\\g2o\\test.txt")); + EXPECT_EQ("test.txt", g2o::getBasename("C:\\users\\g2o\\test.txt")); #else - ASSERT_EQ("test.txt", g2o::getBasename("/home/g2o/test.txt")); + EXPECT_EQ("test.txt", g2o::getBasename("/home/g2o/test.txt")); #endif - ASSERT_EQ("", g2o::getBasename("")); + EXPECT_EQ("", g2o::getBasename("")); } TEST(Stuff, GetDirname) { - ASSERT_EQ("", g2o::getDirname("test.txt")); - ASSERT_EQ("", g2o::getDirname("test")); + EXPECT_EQ("", g2o::getDirname("test.txt")); + EXPECT_EQ("", g2o::getDirname("test")); #ifdef WINDOWS - ASSERT_EQ("C:\\users\\g2o", g2o::getDirname("C:\\users\\g2o\\test.txt")); + EXPECT_EQ("C:\\users\\g2o", g2o::getDirname("C:\\users\\g2o\\test.txt")); #else - ASSERT_EQ("/home/g2o", g2o::getDirname("/home/g2o/test.txt")); + EXPECT_EQ("/home/g2o", g2o::getDirname("/home/g2o/test.txt")); #endif - ASSERT_EQ("", g2o::getDirname("")); + EXPECT_EQ("", g2o::getDirname("")); } TEST(Stuff, FileExists) { - ASSERT_FALSE(g2o::fileExists("test12345.txt")); - ASSERT_FALSE(g2o::fileExists("test12345")); + namespace fs = std::filesystem; + + EXPECT_FALSE(g2o::fileExists("test12345.txt")); + EXPECT_FALSE(g2o::fileExists("test12345")); - ASSERT_TRUE(g2o::fileExists(G2O_SRC_DIR)); - ASSERT_TRUE(g2o::fileExists( - (std::string(G2O_SRC_DIR) + pathSep + "CMakeLists.txt").c_str())); + EXPECT_TRUE(g2o::fileExists(G2O_SRC_DIR)); + EXPECT_TRUE(g2o::fileExists( + (fs::path(G2O_SRC_DIR) / fs::path("CMakeLists.txt")).string())); } TEST(Stuff, GetFilesByPattern) { using namespace testing; - std::string pattern = - std::string(G2O_SRC_DIR) + pathSep + "doc" + pathSep + "license*.txt"; - std::vector licenseFiles = - g2o::getFilesByPattern(pattern.c_str()); - ASSERT_THAT(licenseFiles, SizeIs(3)); - ASSERT_THAT(licenseFiles, Each(ContainsRegex("license.*\\.txt$"))); + namespace fs = std::filesystem; + const std::string directory = + (fs::path(G2O_SRC_DIR) / fs::path("doc")).string(); + const std::regex pattern("^license.*\\.txt$"); + const std::vector licenseFiles = + g2o::getFilesByPattern(directory, pattern); + EXPECT_THAT(licenseFiles, SizeIs(3)); + EXPECT_THAT(licenseFiles, Each(ContainsRegex("license.*\\.txt$"))); }