#include "fgc/Paths.h" #include #include #include namespace fs = std::filesystem; namespace fgc::paths { namespace { std::string envOr(const char* name, const std::string& fallback) { const char* v = std::getenv(name); return (v && *v) ? std::string(v) : fallback; } } // namespace std::string expandUser(const std::string& path) { if (path.empty()) return path; std::string out; out.reserve(path.size()); // Leading ~ -> $HOME size_t i = 0; if (path[0] == '~' && (path.size() == 1 || path[1] == '/')) { out += envOr("HOME", ""); i = 1; } // $VAR and ${VAR} expansion for (; i < path.size(); ++i) { if (path[i] == '$') { size_t start = i + 1; bool braced = (start < path.size() && path[start] == '{'); if (braced) ++start; size_t end = start; while (end < path.size() && (std::isalnum(static_cast(path[end])) || path[end] == '_')) { ++end; } std::string name = path.substr(start, end - start); if (!name.empty()) { out += envOr(name.c_str(), ""); i = braced && end < path.size() && path[end] == '}' ? end : end - 1; continue; } } out += path[i]; } return out; } std::string executableDir() { std::error_code ec; fs::path self = fs::read_symlink("/proc/self/exe", ec); if (ec) return {}; return self.parent_path().string(); } std::vector configSearchPaths(const std::string& cliArg) { std::vector paths; if (!cliArg.empty()) paths.push_back(expandUser(cliArg)); if (const char* env = std::getenv("FGC_CONFIG"); env && *env) paths.push_back(expandUser(env)); paths.push_back("config.ini"); // current working directory if (std::string dir = executableDir(); !dir.empty()) paths.push_back((fs::path(dir) / "config.ini").string()); std::string xdg = envOr("XDG_CONFIG_HOME", expandUser("~/.config")); if (!xdg.empty()) paths.push_back((fs::path(xdg) / "fire_gimbal_control" / "config.ini").string()); return paths; } std::optional resolveConfigPath(const std::string& cliArg) { std::error_code ec; for (const auto& p : configSearchPaths(cliArg)) { if (fs::is_regular_file(p, ec)) return p; } return std::nullopt; } std::string defaultOutputDir() { std::string base = envOr("XDG_DATA_HOME", expandUser("~/.local/share")); return (fs::path(base) / "fire_gimbal_control" / "images").string(); } } // namespace fgc::paths