1#ifndef _LOGIT_PATH_UTILS_HPP_INCLUDED
2#define _LOGIT_PATH_UTILS_HPP_INCLUDED
8#if __cplusplus >= 201703L
22#elif defined(__APPLE__)
24#include <mach-o/dyld.h>
41# if __cplusplus >= 201703L
42 namespace fs = std::filesystem;
45#if defined(__EMSCRIPTEN__)
49 inline std::vector<std::string>
get_list_files(
const std::string&) {
50 std::cerr <<
"get_list_files is not supported under Emscripten" << std::endl;
54 inline std::string
get_file_name(
const std::string& file_path) {
55 size_t pos = file_path.find_last_of(
"/\\");
56 if (pos == std::string::npos)
return file_path;
57 return file_path.substr(pos + 1);
60 inline std::string
make_relative(
const std::string& file_path,
const std::string&) {
65 std::cerr <<
"create_directories is not supported under Emscripten" << std::endl;
68 inline bool is_file(
const std::string& path) {
69 size_t dot_pos = path.find_last_of(
'.');
70 size_t slash_pos = path.find_last_of(
"/\\");
71 return (dot_pos != std::string::npos && (slash_pos == std::string::npos || dot_pos > slash_pos));
80 std::vector<wchar_t> buffer(MAX_PATH);
81 HMODULE hModule = GetModuleHandle(NULL);
84 std::size_t size =
static_cast<std::size_t
>(GetModuleFileNameW(hModule, buffer.data(),
static_cast<DWORD
>(buffer.size())));
87 while (size == buffer.size() && GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
88 buffer.resize(buffer.size() * 2);
89 size =
static_cast<std::size_t
>(GetModuleFileNameW(hModule, buffer.data(),
static_cast<DWORD
>(buffer.size())));
93 throw std::runtime_error(
"Failed to get executable path.");
96 std::wstring exe_path(buffer.begin(), buffer.begin() + size);
99 size_t pos = exe_path.find_last_of(L
"\\/");
100 if (pos != std::wstring::npos) {
101 exe_path = exe_path.substr(0, pos);
105 std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
106 return converter.to_bytes(exe_path);
107# elif defined(__APPLE__)
109 _NSGetExecutablePath(
nullptr, &size);
110 std::vector<char> path(size);
111 if (_NSGetExecutablePath(path.data(), &size) != 0) {
112 throw std::runtime_error(
"Failed to get executable path.");
114 std::string exe_path(path.data());
115 char resolved[PATH_MAX];
116 if (realpath(exe_path.c_str(), resolved) ==
nullptr) {
117 throw std::runtime_error(
"Failed to resolve executable path.");
120 size_t pos = exe_path.find_last_of(
"\\/");
121 if (pos != std::string::npos) {
122 exe_path = exe_path.substr(0, pos);
126 char result[PATH_MAX];
127 ssize_t count = readlink(
"/proc/self/exe", result, PATH_MAX);
130 throw std::runtime_error(
"Failed to get executable path.");
133 std::string exe_path(result, count);
136 size_t pos = exe_path.find_last_of(
"\\/");
137 if (pos != std::string::npos) {
138 exe_path = exe_path.substr(0, pos);
149 std::vector<std::string> list_files;
152 std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
153 std::wstring wsearch_path;
157 wchar_t buffer[MAX_PATH];
158 GetCurrentDirectoryW(MAX_PATH, buffer);
159 wsearch_path = buffer;
161 wsearch_path = converter.from_bytes(path);
165 if (!wsearch_path.empty()) {
166 wchar_t last_char = wsearch_path.back();
167 if (last_char != L
'\\' && last_char != L
'/') {
168 wsearch_path.push_back(L
'\\');
173 std::wstring pattern = wsearch_path + L
"*";
175 HANDLE hFind = FindFirstFileW(pattern.c_str(), &fd);
176 if (hFind != INVALID_HANDLE_VALUE) {
178 if (wcscmp(fd.cFileName, L
".") == 0 || wcscmp(fd.cFileName, L
"..") == 0)
181 std::wstring wfull_path = wsearch_path + fd.cFileName;
183 if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
185 std::vector<std::string> sub_files =
get_list_files(converter.to_bytes(wfull_path));
186 list_files.insert(list_files.end(), sub_files.begin(), sub_files.end());
189 list_files.push_back(converter.to_bytes(wfull_path));
191 }
while (FindNextFileW(hFind, &fd));
196 std::string search_path = path;
197 if (search_path.empty()) {
198 char buffer[PATH_MAX];
199 if (getcwd(buffer, PATH_MAX)) {
200 search_path = buffer;
204 if (search_path.back() !=
'/' && search_path.back() !=
'\\') {
205 search_path.push_back(
'/');
207 DIR* dir = opendir(search_path.c_str());
209 struct dirent* entry;
210 while ((entry = readdir(dir)) !=
nullptr) {
211 std::string file_name = entry->d_name;
212 if (file_name ==
"." || file_name ==
"..")
214 std::string full_path = search_path + file_name;
216 if (stat(full_path.c_str(), &statbuf) == 0) {
217 if (S_ISDIR(statbuf.st_mode)) {
219 list_files.insert(list_files.end(), sub_files.begin(), sub_files.end());
220 }
else if (S_ISREG(statbuf.st_mode)) {
221 list_files.push_back(full_path);
235# if __cplusplus >= 201703L
236 return fs::u8path(file_path).filename().u8string();
238 size_t pos = file_path.find_last_of(
"/\\");
239 if (pos == std::string::npos)
return file_path;
240 return file_path.substr(pos + 1);
244#if __cplusplus >= 201703L
250 inline std::string
make_relative(
const std::string& file_path,
const std::string& base_path) {
251 if (base_path.empty())
return file_path;
252 std::filesystem::path fileP = std::filesystem::u8path(file_path);
253 std::filesystem::path baseP = std::filesystem::u8path(base_path);
255 std::filesystem::path relativeP = std::filesystem::relative(fileP, baseP, ec);
260 return relativeP.u8string();
270 std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
271 std::wstring wide_path = converter.from_bytes(path);
272 std::filesystem::path dir(wide_path);
274 std::filesystem::path dir = std::filesystem::u8path(path);
276 if (!std::filesystem::exists(dir)) {
278 if (!std::filesystem::create_directories(dir, ec)) {
279 throw std::runtime_error(
"Failed to create directories for path: " + dir.u8string());
299 size_t n = path.size();
302 if (n >= 1 && (path[0] ==
'/' || path[0] ==
'\\')) {
306 }
else if (n >= 2 && std::isalpha(path[0]) && path[1] ==
':') {
308 result.
root = path.substr(0, 2);
310 if (n >= 3 && (path[2] ==
'/' || path[2] ==
'\\')) {
319 while (i < n && (path[i] ==
'/' || path[i] ==
'\\')) {
324 while (j < n && path[j] !=
'/' && path[j] !=
'\\') {
328 result.
components.push_back(path.substr(i, j - i));
340 std::string
make_relative(
const std::string& file_path,
const std::string& base_path) {
341 if (base_path.empty())
return file_path;
351 size_t common_size = 0;
352 while (common_size < file_pc.
components.size() &&
359 std::vector<std::string> relative_components;
362 for (
size_t i = common_size; i < base_pc.
components.size(); ++i) {
363 relative_components.push_back(
"..");
367 for (
size_t i = common_size; i < file_pc.
components.size(); ++i) {
368 relative_components.push_back(file_pc.
components[i]);
372 std::string relative_path;
373 if (relative_components.empty()) {
376 for (
size_t i = 0; i < relative_components.size(); ++i) {
379 relative_path +=
'\\';
381 relative_path +=
'/';
384 relative_path += relative_components[i];
388 return relative_path;
394 inline bool is_file(
const std::string& path) {
395 size_t dot_pos = path.find_last_of(
'.');
396 size_t slash_pos = path.find_last_of(
"/\\");
397 return (dot_pos != std::string::npos && (slash_pos == std::string::npos || dot_pos > slash_pos));
404 if (path.empty())
return;
407 size_t components_size = components.size();
415 std::string current_path = path_pc.
root;
416 for (
size_t i = 0; i < components_size; ++i) {
417 if (!current_path.empty() && current_path.back() !=
'/' && current_path.back() !=
'\\') {
420 current_path += components[i];
423 if (components[i] ==
".." ||
424 components[i] ==
"/" ||
425 components[i] ==
"~/")
continue;
427 int ret = _mkdir(utf8_to_ansi(current_path).c_str());
429 int ret = mkdir(current_path.c_str(), 0755);
432 if (ret != 0 && errnum != EEXIST) {
433 throw std::runtime_error(
"Failed to create directory: " + current_path);
The primary namespace for the LogIt++ library.
std::vector< std::string > get_list_files(const std::string &path)
Recursively retrieves a list of all files in a directory.
std::string make_relative(const std::string &file_path, const std::string &base_path)
Computes the relative path from base_path to file_path.
bool is_file(const std::string &path)
Checks if a path represents a file (by checking for an extension).
PathComponents split_path(const std::string &path)
Splits a path into its root and components.
void create_directories(const std::string &path)
Creates directories recursively for the given path.
std::string get_file_name(const std::string &file_path)
Extracts the file name from a full file path.
std::string get_exec_dir()
Retrieves the directory of the executable file.
Structure to hold the root and components of a path.
std::string root
The root part of the path (e.g., "/", "C:")
std::vector< std::string > components
The components of the path.