fwt_software/src/core/Paths.cpp

96 lines
2.6 KiB
C++

#include "fgc/Paths.h"
#include <cstdlib>
#include <filesystem>
#include <unistd.h>
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<unsigned char>(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<std::string> configSearchPaths(const std::string& cliArg) {
std::vector<std::string> 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<std::string> 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