summaryrefslogtreecommitdiff
path: root/src/xdg.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/xdg.cc')
-rw-r--r--src/xdg.cc116
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