diff options
Diffstat (limited to 'src/xdg.cc')
| -rw-r--r-- | src/xdg.cc | 116 |
1 files changed, 116 insertions, 0 deletions
diff --git a/src/xdg.cc b/src/xdg.cc new file mode 100644 index 0000000..b61b4ba --- /dev/null +++ b/src/xdg.cc @@ -0,0 +1,116 @@ +#include "common.hh" + +#include "xdg.hh" + +#include <filesystem> +#include <pwd.h> +#include <stdlib.h> +#include <unistd.h> + +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<std::filesystem::path>* 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 |
