#include "paths.hh" #include "str.hh" #include #include #include #include #include #include #include #include #include #include #include namespace paths { namespace { std::vector xdg_read_dirs( const char* userdir_env_name, std::string_view userdir_home_default, const char* dirs_env_name, std::vector const& dirs_default_value) { std::vector ret; std::unordered_set tmp; auto* env_userdir = getenv(userdir_env_name); if (env_userdir != nullptr && env_userdir[0] != '\0') { ret.emplace_back(env_userdir); } else { ret.emplace_back(home() / userdir_home_default); } tmp.insert(ret.back()); auto* env_dirs = getenv(dirs_env_name); if (env_dirs != nullptr && env_dirs[0] != '\0') { for (auto dir : str::split(env_dirs, ':')) { if (tmp.emplace(dir).second) { ret.emplace_back(dir); } } } else { std::ranges::copy_if( dirs_default_value, std::back_inserter(ret), [&tmp](auto const& dir) { return tmp.emplace(dir).second; }); } return ret; } } // namespace std::filesystem::path home() { { auto* str = getenv("HOME"); if (str != nullptr && str[0] != '\0') return str; } { auto maybe_size = sysconf(_SC_GETPW_R_SIZE_MAX); size_t size = maybe_size > 0 ? static_cast(maybe_size) : 1024; auto buffer = std::make_unique(size); struct passwd pwd; struct passwd* ret; int err; while (true) { err = getpwuid_r(geteuid(), &pwd, buffer.get(), size, &ret); if (err == 0) break; if (err != ERANGE) break; auto new_size = size * 2; if (new_size < size) break; buffer = std::make_unique(new_size); size = new_size; } if (err == 0 && ret) { if (ret->pw_dir != nullptr && ret->pw_dir[0] != '\0') { return ret->pw_dir; } } } return "/"; } std::vector config_dirs() { static const std::vector fallback{"/etc/xdg"}; return xdg_read_dirs("XDG_CONFIG_HOME", ".config", "XDG_CONFIG_DIRS", fallback); } std::vector data_dirs() { static const std::vector fallback{"/usr/local/share/", "/usr/share/"}; return xdg_read_dirs("XDG_DATA_HOME", ".local/share", "XDG_DATA_DIRS", fallback); } } // namespace paths