150 lines
4.2 KiB
C++
150 lines
4.2 KiB
C++
|
|
#include "./folders.hpp"
|
|
|
|
#include <cstdlib>
|
|
#include <ranges>
|
|
|
|
#include "../detect.hpp"
|
|
#include "../debug/assert.hpp"
|
|
|
|
#if MIJIN_TARGET_OS == MIJIN_OS_WINDOWS
|
|
# include <Shlobj.h>
|
|
#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
|
|
{
|
|
WSTR 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<fs::path> getAllConfigFolders(IncludeUser includeUser, IncludeSystem includeSystem) MIJIN_NOEXCEPT
|
|
{
|
|
std::vector<fs::path> 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());
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
return result;
|
|
}
|
|
|
|
std::vector<fs::path> getAllDataFolders(IncludeUser includeUser, IncludeSystem includeSystem) MIJIN_NOEXCEPT
|
|
{
|
|
std::vector<fs::path> 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());
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
return result;
|
|
}
|
|
} |