154 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			154 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
 | 
						|
    {
 | 
						|
        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<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());
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
#else
 | 
						|
    (void) includeSystem;
 | 
						|
#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());
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
#else
 | 
						|
    (void) includeSystem;
 | 
						|
#endif
 | 
						|
    return result;
 | 
						|
}
 | 
						|
} |