#include "./folders.hpp" #include #include #include "../detect.hpp" #include "../debug/assert.hpp" #if MIJIN_TARGET_OS == MIJIN_OS_WINDOWS # include #endif namespace mijin { fs::path getKnownFolder(KnownFolder folder) MIJIN_NOEXCEPT { #if MIJIN_TARGET_OS == MIJIN_OS_LINUX switch (folder) { case KnownFolder::USER_HOME: if (const char* val = std::getenv("HOME"); val != nullptr) { return val; } return "/"; case KnownFolder::TEMP: for (const char* varname : {"TMPDIR", "TEMP", "TMP"}) { if (const char* val = std::getenv(varname); val != nullptr) { return val; } } return "/tmp"; case KnownFolder::CACHE_ROOT: if (const char* val = std::getenv("XDG_CACHE_HOME"); val != nullptr) { return val; } return getKnownFolder(KnownFolder::USER_HOME) / ".cache"; case KnownFolder::USER_CONFIG_ROOT: if (const char* val = std::getenv("XDG_CONFIG_HOME"); val != nullptr) { return val; } return getKnownFolder(KnownFolder::USER_HOME) / ".config"; case KnownFolder::USER_DATA_ROOT: if (const char* val = std::getenv("XDG_DATA_HOME"); val != nullptr) { return val; } return getKnownFolder(KnownFolder::USER_HOME) / ".local/share"; } MIJIN_ERROR("Invalid value passed to getKnownFolder()."); return {}; #elif MIJIN_TARGET_OS == MIJIN_OS_WINDOWS // TODO: this is 100% untested on Windows auto getKnownFolderPath = [](REFKNOWNFOLDERID rfid) -> fs::path { WCHAR* path = nullptr; if (!SUCCEEDED(SHGetKnownFolderPath(rfid, KF_FLAG_DEFAULT, nullptr, &path))) { CoTaskMemFree(path); return {}; } fs::path result(path); CoTaskMemFree(path); return result; }; switch (folder) { case KnownFolder::USER_HOME: if (const fs::path path = getKnownFolderPath(FOLDERID_Profile); !path.empty()) { return path; } return "C:\\"; case KnownFolder::TEMP: case KnownFolder::CACHE_ROOT: for (const char* varname : {"TMPDIR", "TEMP", "TMP"}) { if (const char* val = std::getenv(varname); val != nullptr) { return val; } } return getKnownFolder(KnownFolder::USER_DATA_ROOT) / "Temp"; case KnownFolder::USER_CONFIG_ROOT: case KnownFolder::USER_DATA_ROOT: if (const fs::path path = getKnownFolderPath(FOLDERID_LocalAppData); !path.empty()) { return path; } return getKnownFolder(KnownFolder::USER_HOME) / "AppData" / "Local"; } MIJIN_ERROR("Invalid value passed to getKnownFolder()."); return {}; #else MIJIN_ERROR("Known folders not implemented for this platform."); return {}; // don't know :/ #endif } std::vector getAllConfigFolders(IncludeUser includeUser, IncludeSystem includeSystem) MIJIN_NOEXCEPT { std::vector result; if (includeUser) { result.push_back(getKnownFolder(KnownFolder::USER_CONFIG_ROOT)); } #if MIJIN_TARGET_OS == MIJIN_OS_LINUX if (includeSystem) { if (const char* val = std::getenv("XDG_CONFIG_DIRS"); val != nullptr) { for (auto part : std::ranges::split_view(std::string_view(val), ':')) { result.emplace_back(part.begin(), part.end()); } } } #else (void) includeSystem; #endif return result; } std::vector getAllDataFolders(IncludeUser includeUser, IncludeSystem includeSystem) MIJIN_NOEXCEPT { std::vector result; if (includeUser) { result.push_back(getKnownFolder(KnownFolder::USER_DATA_ROOT)); } #if MIJIN_TARGET_OS == MIJIN_OS_LINUX if (includeSystem) { if (const char* val = std::getenv("XDG_DATA_DIRS"); val != nullptr) { for (auto part : std::ranges::split_view(std::string_view(val), ':')) { result.emplace_back(part.begin(), part.end()); } } } #else (void) includeSystem; #endif return result; } }