#include "common.hh" #include "xdg.hh" #include #include #include #include namespace xdg { namespace { bool valid(char const* path) { return path && path[0] == '/'; } bool valid(std::string const& path, size_t pos, size_t len) { return len > 0 && path[pos] == '/'; } std::filesystem::path get_home() { auto* env = getenv("HOME"); if (valid(env)) return env; auto* pwd = getpwuid(getuid()); if (pwd && valid(pwd->pw_dir)) return pwd->pw_dir; return "/"; } void get_paths(Type type, std::string* dirs, std::filesystem::path* home) { char const* env; switch (type) { case Type::CONFIG: if (dirs) { env = getenv("XDG_CONFIG_DIRS"); if (valid(env)) { dirs->assign(env); } else { dirs->assign("/etc/xdg"); } } if (home) { env = getenv("XDG_CONFIG_HOME"); if (valid(env)) { *home = env; } else { *home = get_home() / ".config"; } } break; case Type::DATA: if (dirs) { env = getenv("XDG_DATA_DIRS"); if (valid(env)) { dirs->assign(env); } else { dirs->assign("usr/local/share/:/usr/share/"); } } if (home) { env = getenv("XDG_DATA_HOME"); if (valid(env)) { *home = env; } else { *home = get_home() / ".local/share"; } } break; case Type::CACHE: if (dirs) dirs->clear(); if (home) { env = getenv("XDG_CACHE_HOME"); if (valid(env)) { *home = env; } else { *home = get_home() / ".cache"; } } break; } } } // namespace void paths_to_read(Type type, std::string_view name, std::vector& out) { std::string dirs; std::filesystem::path home; get_paths(type, &dirs, &home); out.clear(); out.push_back(home / name); size_t last = 0; while (true) { size_t next = dirs.find(':', last); if (next == std::string::npos) { if (valid(dirs, last, dirs.size() - last)) out.push_back(std::filesystem::path(dirs.substr(last)) / name); break; } if (valid(dirs, last, next - last)) out.push_back( std::filesystem::path(dirs.substr(last, next - last)) / name); last = next + 1; } } std::filesystem::path path_to_write(Type type, std::string_view name) { std::filesystem::path home; get_paths(type, nullptr, &home); return home / name; } } // namespace xdg