#include "util/platform_paths.h" #include #include "absl/strings/str_cat.h" #include "absl/strings/str_replace.h" #ifdef _WIN32 #include #include #else #include #include #endif namespace yaze { namespace util { std::filesystem::path PlatformPaths::GetHomeDirectory() { #ifdef _WIN32 // Windows: Use USERPROFILE environment variable const char* userprofile = std::getenv("USERPROFILE"); if (userprofile && *userprofile) { return std::filesystem::path(userprofile); } // Fallback to HOMEDRIVE + HOMEPATH const char* homedrive = std::getenv("HOMEDRIVE"); const char* homepath = std::getenv("HOMEPATH"); if (homedrive && homepath) { return std::filesystem::path(std::string(homedrive) + std::string(homepath)); } // Last resort: use temp directory return std::filesystem::temp_directory_path(); #else // Unix/macOS: Use HOME environment variable const char* home = std::getenv("HOME"); if (home && *home) { return std::filesystem::path(home); } // Fallback: try getpwuid struct passwd* pw = getpwuid(getuid()); if (pw && pw->pw_dir) { return std::filesystem::path(pw->pw_dir); } // Last resort: current directory return std::filesystem::current_path(); #endif } absl::StatusOr PlatformPaths::GetAppDataDirectory() { #ifdef _WIN32 wchar_t path[MAX_PATH]; if (SUCCEEDED(SHGetFolderPathW(NULL, CSIDL_APPDATA, NULL, 0, path))) { std::filesystem::path app_data = std::filesystem::path(path) / "yaze"; auto status = EnsureDirectoryExists(app_data); if (!status.ok()) { return status; } return app_data; } // Fallback if SHGetFolderPathW fails std::filesystem::path home = GetHomeDirectory(); std::filesystem::path app_data = home / "yaze_data"; auto status = EnsureDirectoryExists(app_data); if (!status.ok()) { return status; } return app_data; #elif defined(__APPLE__) std::filesystem::path home = GetHomeDirectory(); std::filesystem::path app_data = home / "Library" / "Application Support" / "yaze"; auto status = EnsureDirectoryExists(app_data); if (!status.ok()) { return status; } return app_data; #else // Linux and other Unix-like systems const char* xdg_config_home = std::getenv("XDG_CONFIG_HOME"); std::filesystem::path config_dir; if (xdg_config_home && *xdg_config_home) { config_dir = std::filesystem::path(xdg_config_home); } else { config_dir = GetHomeDirectory() / ".config"; } std::filesystem::path app_data = config_dir / "yaze"; auto status = EnsureDirectoryExists(app_data); if (!status.ok()) { return status; } return app_data; #endif } absl::StatusOr PlatformPaths::GetConfigDirectory() { // For yaze, config and data directories are the same. // This provides a semantically clearer API for config access. return GetAppDataDirectory(); } absl::StatusOr PlatformPaths::GetAppDataSubdirectory( const std::string& subdir) { auto app_data_result = GetAppDataDirectory(); if (!app_data_result.ok()) { return app_data_result.status(); } std::filesystem::path subdir_path = *app_data_result / subdir; auto status = EnsureDirectoryExists(subdir_path); if (!status.ok()) { return status; } return subdir_path; } absl::Status PlatformPaths::EnsureDirectoryExists( const std::filesystem::path& path) { if (Exists(path)) { return absl::OkStatus(); } std::error_code ec; if (!std::filesystem::create_directories(path, ec)) { if (ec) { return absl::InternalError( absl::StrCat("Failed to create directory: ", path.string(), " - Error: ", ec.message())); } } return absl::OkStatus(); } bool PlatformPaths::Exists(const std::filesystem::path& path) { std::error_code ec; bool exists = std::filesystem::exists(path, ec); return exists && !ec; } absl::StatusOr PlatformPaths::GetTempDirectory() { std::error_code ec; std::filesystem::path temp_base = std::filesystem::temp_directory_path(ec); if (ec) { return absl::InternalError( absl::StrCat("Failed to get temp directory: ", ec.message())); } std::filesystem::path yaze_temp = temp_base / "yaze"; auto status = EnsureDirectoryExists(yaze_temp); if (!status.ok()) { return status; } return yaze_temp; } std::string PlatformPaths::NormalizePathForDisplay( const std::filesystem::path& path) { // Convert to string and replace backslashes with forward slashes // Forward slashes work on all platforms for display purposes std::string path_str = path.string(); return absl::StrReplaceAll(path_str, {{"\\", "/"}}); } std::string PlatformPaths::ToNativePath(const std::filesystem::path& path) { // std::filesystem::path::string() already returns the native format return path.string(); } } // namespace util } // namespace yaze