diff --git a/src/file_utils.cpp b/src/file_utils.cpp new file mode 100644 index 00000000..ce60e0ad --- /dev/null +++ b/src/file_utils.cpp @@ -0,0 +1,99 @@ +#include "file_utils.h" +#include "string_utils.h" +#include +#include +#include +#include +#include +#include +#include +#include + +std::string read_line(const std::string& filename) +{ + std::string line; + std::ifstream file(filename); + std::getline(file, line); + return line; +} + +bool find_folder(const char* root, const char* prefix, std::string& dest) +{ + struct dirent* dp; + DIR* dirp = opendir(root); + if (!dirp) { + std::cerr << "Error opening directory '" << root << "': "; + perror(""); + return false; + } + + while ((dp = readdir(dirp))) { + if ((dp->d_type == DT_LNK || dp->d_type == DT_DIR) && starts_with(dp->d_name, prefix)) { + dest = dp->d_name; + closedir(dirp); + return true; + } + } + + closedir(dirp); + return false; +} + +bool find_folder(const std::string& root, const std::string& prefix, std::string& dest) +{ + return find_folder(root.c_str(), prefix.c_str(), dest); +} + +std::vector ls(const char* root, const char* prefix, LS_FLAGS flags) +{ + std::vector list; + struct dirent* dp; + + DIR* dirp = opendir(root); + if (!dirp) { + std::cerr << "Error opening directory '" << root << "': "; + perror(""); + return list; + } + + while ((dp = readdir(dirp))) { + if (dp->d_type == DT_LNK) { + struct stat s; + std::string path(root); + if (path.back() != '/') + path += "/"; + path += dp->d_name; + + if (stat(path.c_str(), &s)) + continue; + + if (((flags & LS_DIRS) && S_ISDIR(s.st_mode)) + || ((flags & LS_FILES) && !S_ISDIR(s.st_mode))) { + list.push_back(dp->d_name); + } + } else if (((flags & LS_DIRS) && dp->d_type == DT_DIR) + || ((flags & LS_FILES) && dp->d_type == DT_REG) + ) { + if ((prefix && !starts_with(dp->d_name, prefix)) + || !strcmp(dp->d_name, ".") + || !strcmp(dp->d_name, "..")) + continue; + list.push_back(dp->d_name); + } + } + + closedir(dirp); + return list; +} + +bool file_exists(const std::string& path) +{ + struct stat s; + return !stat(path.c_str(), &s) && !S_ISDIR(s.st_mode); +} + +bool dir_exists(const std::string& path) +{ + struct stat s; + return !stat(path.c_str(), &s) && S_ISDIR(s.st_mode); +} diff --git a/src/file_utils.h b/src/file_utils.h new file mode 100644 index 00000000..9692837a --- /dev/null +++ b/src/file_utils.h @@ -0,0 +1,17 @@ +#pragma once +#include +#include + +enum LS_FLAGS +{ + LS_ALL = 0x00, + LS_DIRS = 0x01, + LS_FILES = 0x02, +}; + +std::string read_line(const std::string& filename); +bool find_folder(const char* root, const char* prefix, std::string& dest); +bool find_folder(const std::string& root, const std::string& prefix, std::string& dest); +std::vector ls(const char* root, const char* prefix = nullptr, LS_FLAGS flags = LS_DIRS); +bool file_exists(const std::string& path); +bool dir_exists(const std::string& path); diff --git a/src/meson.build b/src/meson.build index 2b6b4787..6125c8bb 100644 --- a/src/meson.build +++ b/src/meson.build @@ -38,6 +38,7 @@ vklayer_files = files( 'cpu.cpp', 'loaders/loader_nvml.cpp', 'nvml.cpp', + 'file_utils.cpp', ) vklayer_mesa_overlay = shared_library( diff --git a/src/string_utils.h b/src/string_utils.h new file mode 100644 index 00000000..780ec38b --- /dev/null +++ b/src/string_utils.h @@ -0,0 +1,76 @@ +#pragma once +#include +#include +#include +#include +#include +#include +#include + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-function" + +// https://stackoverflow.com/questions/216823/whats-the-best-way-to-trim-stdstring#217605 +// trim from start (in place) +static inline void ltrim(std::string &s) { + s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](int ch) { + return !std::isspace(ch); + })); +} + +// trim from end (in place) +static inline void rtrim(std::string &s) { + s.erase(std::find_if(s.rbegin(), s.rend(), [](int ch) { + return !std::isspace(ch); + }).base(), s.end()); +} + +// trim from both ends (in place) +static inline void trim(std::string &s) { + ltrim(s); + rtrim(s); +} + +// trim from start (copying) +static inline std::string ltrim_copy(std::string s) { + ltrim(s); + return s; +} + +// trim from end (copying) +static inline std::string rtrim_copy(std::string s) { + rtrim(s); + return s; +} + +// trim from both ends (copying) +static inline std::string trim_copy(std::string s) { + trim(s); + return s; +} + +static bool starts_with(const std::string& s, const char *t) { + return s.rfind(t, 0) == 0; +} + +template +static std::string itox(T i) { + std::stringstream ss; + ss << "0x" + << std::setfill ('0') << std::setw(sizeof(T) * 2) + << std::hex << i; + return ss.str(); +} + +static bool try_stoi(int& val, const std::string& str, std::size_t* pos = 0, int base = 10) +{ + try { + val = std::stoi(str, pos, base); + return true; + } catch (std::invalid_argument& e) { + std::cerr << __func__ << ": invalid argument: '" << str << "'" << std::endl; + } + return false; +} + +#pragma GCC diagnostic pop