103 lines
3.5 KiB
C++
103 lines
3.5 KiB
C++
#include "AppConfig.h"
|
|
|
|
#include <fstream>
|
|
#include <sstream>
|
|
#include <iostream>
|
|
#include <filesystem>
|
|
#include <unistd.h>
|
|
#include <vector>
|
|
|
|
namespace fs = std::filesystem;
|
|
|
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
|
|
static std::string trim(const std::string& s) {
|
|
const auto start = s.find_first_not_of(" \t\r\n");
|
|
if (start == std::string::npos) return {};
|
|
const auto end = s.find_last_not_of(" \t\r\n");
|
|
return s.substr(start, end - start + 1);
|
|
}
|
|
|
|
static std::string exeDir() {
|
|
char buf[4096] = {};
|
|
ssize_t n = readlink("/proc/self/exe", buf, sizeof(buf) - 1);
|
|
if (n > 0)
|
|
return fs::path(std::string(buf, n)).parent_path().string();
|
|
return {};
|
|
}
|
|
|
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
|
|
bool AppConfig::load() {
|
|
// Search order: next to exe, then cwd
|
|
std::vector<std::string> candidates;
|
|
std::string exe = exeDir();
|
|
if (!exe.empty())
|
|
candidates.push_back(exe + "/assets/config.ini");
|
|
candidates.push_back("assets/config.ini");
|
|
|
|
std::ifstream file;
|
|
std::string usedPath;
|
|
for (auto& p : candidates) {
|
|
file.open(p);
|
|
if (file.is_open()) { usedPath = p; break; }
|
|
}
|
|
|
|
if (!file.is_open()) {
|
|
std::cerr << "[config] No config.ini found — using defaults.\n";
|
|
return false;
|
|
}
|
|
|
|
std::cout << "[config] Loading: " << usedPath << "\n";
|
|
|
|
std::string section;
|
|
std::string line;
|
|
while (std::getline(file, line)) {
|
|
line = trim(line);
|
|
if (line.empty() || line[0] == '#') continue;
|
|
|
|
if (line.front() == '[' && line.back() == ']') {
|
|
section = line.substr(1, line.size() - 2);
|
|
continue;
|
|
}
|
|
|
|
auto eq = line.find('=');
|
|
if (eq == std::string::npos) continue;
|
|
|
|
std::string key = trim(line.substr(0, eq));
|
|
std::string val = trim(line.substr(eq + 1));
|
|
|
|
// Strip inline comments
|
|
auto hash = val.find('#');
|
|
if (hash != std::string::npos)
|
|
val = trim(val.substr(0, hash));
|
|
|
|
std::string fullKey = section.empty() ? key : section + "." + key;
|
|
m_values[fullKey] = val;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
|
|
std::string AppConfig::getString(const std::string& key,
|
|
const std::string& defaultVal) const {
|
|
auto it = m_values.find(key);
|
|
return it != m_values.end() && !it->second.empty()
|
|
? it->second : defaultVal;
|
|
}
|
|
|
|
float AppConfig::getFloat(const std::string& key, float defaultVal) const {
|
|
auto it = m_values.find(key);
|
|
if (it == m_values.end() || it->second.empty()) return defaultVal;
|
|
try { return std::stof(it->second); }
|
|
catch (...) { return defaultVal; }
|
|
}
|
|
|
|
int AppConfig::getInt(const std::string& key, int defaultVal) const {
|
|
auto it = m_values.find(key);
|
|
if (it == m_values.end() || it->second.empty()) return defaultVal;
|
|
try { return std::stoi(it->second); }
|
|
catch (...) { return defaultVal; }
|
|
} |