From de4e45a43326b6d15e44a687070af7d12c17a71e Mon Sep 17 00:00:00 2001 From: Connor McLaughlin Date: Fri, 24 Jan 2020 14:50:57 +1000 Subject: [PATCH] Common: Add a function to get the path to the running program --- src/common/cd_image_cue.cpp | 21 +----- src/common/file_system.cpp | 124 ++++++++++++++++++++++++++++++++++++ src/common/file_system.h | 13 ++-- 3 files changed, 133 insertions(+), 25 deletions(-) diff --git a/src/common/cd_image_cue.cpp b/src/common/cd_image_cue.cpp index 357ac793d..7912f6df9 100644 --- a/src/common/cd_image_cue.cpp +++ b/src/common/cd_image_cue.cpp @@ -32,25 +32,6 @@ CDImageCueSheet::~CDImageCueSheet() cd_delete(m_cd); } -static std::string GetPathDirectory(const char* path) -{ - const char* forwardslash_ptr = std::strrchr(path, '/'); - const char* backslash_ptr = std::strrchr(path, '\\'); - const char* slash_ptr; - if (forwardslash_ptr && backslash_ptr) - slash_ptr = std::max(forwardslash_ptr, backslash_ptr); - else if (backslash_ptr) - slash_ptr = backslash_ptr; - else if (forwardslash_ptr) - slash_ptr = forwardslash_ptr; - else - return {}; - - std::string str; - str.append(path, slash_ptr - path + 1); - return str; -} - static std::string ReplaceExtension(std::string_view path, std::string_view new_extension) { std::string_view::size_type pos = path.rfind('.'); @@ -80,7 +61,7 @@ bool CDImageCueSheet::OpenAndParse(const char* filename) } // get the directory of the filename - std::string basepath = GetPathDirectory(filename); + std::string basepath = FileSystem::GetPathDirectory(filename) + "/"; m_filename = filename; u32 disc_lba = 0; diff --git a/src/common/file_system.cpp b/src/common/file_system.cpp index 38508b0f2..5f1d51b10 100644 --- a/src/common/file_system.cpp +++ b/src/common/file_system.cpp @@ -144,6 +144,11 @@ void CanonicalizePath(String& Destination, bool OSPath /* = true */) CanonicalizePath(Destination, Destination); } +void CanonicalizePath(std::string& path, bool OSPath /*= true*/) +{ + CanonicalizePath(path.data(), static_cast(path.size() + 1), path.c_str(), OSPath); +} + static inline bool FileSystemCharacterIsSane(char c, bool StripSlashes) { if (!(c >= 'a' && c <= 'z') && !(c >= 'A' && c <= 'Z') && !(c >= '0' && c <= '9') && c != ' ' && c != ' ' && @@ -217,6 +222,34 @@ void SanitizeFileName(String& Destination, bool StripSlashes /* = true */) return SanitizeFileName(Destination, Destination, StripSlashes); } +std::string GetPathDirectory(const char* path) +{ +#ifdef WIN32 + const char* forwardslash_ptr = std::strrchr(path, '/'); + const char* backslash_ptr = std::strrchr(path, '\\'); + const char* slash_ptr; + if (forwardslash_ptr && backslash_ptr) + slash_ptr = std::max(forwardslash_ptr, backslash_ptr); + else if (backslash_ptr) + slash_ptr = backslash_ptr; + else if (forwardslash_ptr) + slash_ptr = forwardslash_ptr; + else + return {}; +#else + const char* slash_ptr = std::strrchr(path, '/'); + if (!slash_ptr) + return {}; +#endif + + if (slash_ptr == path) + return {}; + + std::string str; + str.append(path, slash_ptr - path); + return str; +} + void BuildPathRelativeToFile(char* Destination, u32 cbDestination, const char* CurrentFileName, const char* NewFileName, bool OSPath /* = true */, bool Canonicalize /* = true */) { @@ -957,6 +990,31 @@ bool FileSystem::DeleteDirectory(const char* Path, bool Recursive) return true; } +std::string GetProgramPath() +{ + const HANDLE hProcess = GetCurrentProcess(); + + std::string buffer; + buffer.resize(MAX_PATH); + + for (;;) + { + DWORD nChars = static_cast(buffer.size()); + if (!QueryFullProcessImageNameA(GetCurrentProcess(), 0, buffer.data(), &nChars) && + GetLastError() == ERROR_INSUFFICIENT_BUFFER) + { + buffer.resize(buffer.size() * 2); + continue; + } + + buffer.resize(nChars); + break; + } + + CanonicalizePath(buffer); + return buffer; +} + #else std::unique_ptr CreateChangeNotifier(const char* path, bool recursiveWatch) @@ -1270,6 +1328,72 @@ bool DeleteDirectory(const char* Path, bool Recursive) return false; } +std::string GetProgramPath() +{ +#if defined(__linux__) + static const char* exeFileName = "/proc/self/exe"; + + int curSize = PATH_MAX; + char* buffer = static_cast(std::realloc(nullptr, curSize)); + for (;;) + { + int len = readlink(exeFileName, buffer, curSize); + if (len < 0) + { + std::free(buffer); + return {}; + } + else if (len < curSize) + { + buffer[len] = '\0'; + std::string ret(buffer, len); + std::free(buffer); + return ret; + } + + curSize *= 2; + buffer = static_cast(std::realloc(buffer, curSize)); + } + +#elif defined(__APPLE__) + + int curSize = PATH_MAX; + char* buffer = static_cast(std::realloc(nullptr, curSize + 1)); + for (;;) + { + uint32 nChars = PATH_MAX - 1; + int res = _NSGetExecutablePath(buffer, &nChars); + if (res == 0) + { + buffer[nChars] = 0; + + char* resolvedBuffer = realpath(buffer, nullptr); + if (resolvedBuffer == nullptr) + { + std::free(buffer); + return {}; + } + + std::string ret(buffer, len); + std::free(buffer); + return ret; + } + + if (curSize >= 1048576) + { + std::free(buffer); + return {}; + } + + curSize *= 2; + buffer = static_cast(std::realloc(buffer, curSize + 1)); + } + +#else + return {}; +#endif +} + #endif } // namespace FileSystem \ No newline at end of file diff --git a/src/common/file_system.h b/src/common/file_system.h index 448887dc9..9b3697c25 100644 --- a/src/common/file_system.h +++ b/src/common/file_system.h @@ -8,7 +8,7 @@ class ByteStream; -#ifdef Y_PLATFORM_WINDOWS +#ifdef WIN32 #define FS_OSPATH_SEPERATOR_CHARACTER '\\' #else #define FS_OSPATH_SEPERATOR_CHARACTER '/' @@ -111,15 +111,12 @@ protected: // create a change notifier std::unique_ptr CreateChangeNotifier(const char* path, bool recursiveWatch); -// appends a path string to the current path string. optionally canonicalizes it. -void AppendPath(char* Path, u32 cbPath, const char* NewPath); -void AppendPath(String& Path, const char* NewPath); - // canonicalize a path string (i.e. replace .. with actual folder name, etc), if OS path is used, on windows, the // separators will be \, otherwise / void CanonicalizePath(char* Destination, u32 cbDestination, const char* Path, bool OSPath = true); void CanonicalizePath(String& Destination, const char* Path, bool OSPath = true); void CanonicalizePath(String& Destination, bool OSPath = true); +void CanonicalizePath(std::string& path, bool OSPath = true); // translates the specified path into a string compatible with the hosting OS void BuildOSPath(char* Destination, u32 cbDestination, const char* Path); @@ -137,6 +134,9 @@ void SanitizeFileName(char* Destination, u32 cbDestination, const char* FileName void SanitizeFileName(String& Destination, const char* FileName, bool StripSlashes = true); void SanitizeFileName(String& Destination, bool StripSlashes = true); +/// Returns the directory component of a filename. +std::string GetPathDirectory(const char* path); + // search for files bool FindFiles(const char* Path, const char* Pattern, u32 Flags, FindResultsArray* pResults); @@ -173,4 +173,7 @@ bool CreateDirectory(const char* Path, bool Recursive); // if the directory has files, unless the recursive flag is set, it will fail bool DeleteDirectory(const char* Path, bool Recursive); +/// Returns the path to the current executable. +std::string GetProgramPath(); + }; // namespace FileSystem