#include "fiko/ayar/ayar_sistemi.hpp" #include #include namespace fiko::ayar { namespace { // "12.5" / "0.1,0.2,0.3" gibi alanları güvenli çöz (locale'den bağımsız nokta beklenir). bool sayiCoz(std::string_view s, f64& sonuc) { if (s.empty()) return false; const std::string tmp(s); char* uc = nullptr; const f64 v = std::strtod(tmp.c_str(), &uc); if (uc == tmp.c_str()) return false; sonuc = v; return true; } std::string_view kirp(std::string_view s) { while (!s.empty() && (s.front() == ' ' || s.front() == '\t')) s.remove_prefix(1); while (!s.empty() && (s.back() == ' ' || s.back() == '\t' || s.back() == '\r')) s.remove_suffix(1); return s; } } // namespace void AyarSistemi::ayarKaydet(AyarTanim t) { if (t.kimlik.empty() || !t.al || !t.ata) return; // bağsız tanım kabul edilmez if (AyarTanim* var = bulM(t.kimlik)) { *var = std::move(t); return; } tanimlar_.push_back(std::move(t)); } const AyarTanim* AyarSistemi::bul(std::string_view kimlik) const { for (const AyarTanim& t : tanimlar_) if (t.kimlik == kimlik) return &t; return nullptr; } AyarTanim* AyarSistemi::bulM(std::string_view kimlik) { for (AyarTanim& t : tanimlar_) if (t.kimlik == kimlik) return &t; return nullptr; } std::vector AyarSistemi::kategoriler() const { std::vector k; for (const AyarTanim& t : tanimlar_) { bool var = false; for (const std::string& x : k) if (x == t.kategori) { var = true; break; } if (!var) k.push_back(t.kategori); } return k; } void AyarSistemi::gez(std::string_view kategori, const std::function& cb) const { for (const AyarTanim& t : tanimlar_) if (kategori.empty() || t.kategori == kategori) cb(t); } bool AyarSistemi::degerAta(std::string_view kimlik, const AyarDeger& d) { const AyarTanim* t = bul(kimlik); if (!t) return false; t->ata(d); if (degisti) degisti(*t, t->al()); return true; } void AyarSistemi::bildir(std::string_view kimlik) { const AyarTanim* t = bul(kimlik); if (t && degisti) degisti(*t, t->al()); } bool AyarSistemi::sifirla(std::string_view kimlik) { const AyarTanim* t = bul(kimlik); if (!t) return false; t->ata(t->varsayilan); if (degisti) degisti(*t, t->al()); return true; } int AyarSistemi::kategoriSifirla(std::string_view kategori) { int adet = 0; for (const AyarTanim& t : tanimlar_) { if (t.kategori != kategori) continue; t.ata(t.varsayilan); if (degisti) degisti(t, t.al()); ++adet; } return adet; } bool AyarSistemi::degistiMi(const AyarTanim& t) const { return degerMetni(t, t.al()) != degerMetni(t, t.varsayilan); } std::string AyarSistemi::degerMetni(const AyarTanim& t, const AyarDeger& d) { char buf[96]; switch (t.tip) { case AyarTip::Bool: return d.b ? "1" : "0"; case AyarTip::Int: std::snprintf(buf, sizeof(buf), "%lld", static_cast(d.i)); return buf; case AyarTip::F32: case AyarTip::F64: std::snprintf(buf, sizeof(buf), "%.6g", d.f); return buf; case AyarTip::Renk: std::snprintf(buf, sizeof(buf), "%.4g,%.4g,%.4g", (f64)d.renk.x, (f64)d.renk.y, (f64)d.renk.z); return buf; case AyarTip::Metin: case AyarTip::Secenek: { std::string s = d.metin; for (char& c : s) if (c == '\n' || c == '\r') c = ' '; // satır formatı bozulmasın return s; } } return {}; } bool AyarSistemi::degerCoz(const AyarTanim& t, std::string_view metin, AyarDeger& sonuc) { metin = kirp(metin); switch (t.tip) { case AyarTip::Bool: if (metin == "1" || metin == "true") { sonuc.b = true; return true; } if (metin == "0" || metin == "false") { sonuc.b = false; return true; } return false; case AyarTip::Int: { f64 v; if (!sayiCoz(metin, v)) return false; sonuc.i = static_cast(v); return true; } case AyarTip::F32: case AyarTip::F64: { f64 v; if (!sayiCoz(metin, v)) return false; sonuc.f = v; return true; } case AyarTip::Renk: { f64 rgb[3]; std::string_view kalan = metin; for (int i = 0; i < 3; ++i) { const size_t vir = kalan.find(','); const std::string_view parca = (i < 2) ? kalan.substr(0, vir) : kalan; // son parça virgülsüz if (i < 2 && vir == std::string_view::npos) return false; if (!sayiCoz(kirp(parca), rgb[i])) return false; if (i < 2) kalan.remove_prefix(vir + 1); } sonuc.renk = {(f32)rgb[0], (f32)rgb[1], (f32)rgb[2]}; return true; } case AyarTip::Metin: sonuc.metin = std::string(metin); return true; case AyarTip::Secenek: for (const std::string& s : t.secenekler) if (s == metin) { sonuc.metin = s; return true; } return false; // bilinmeyen seçenek uygulanmaz (bozuk dosya güvenliği) } return false; } std::string AyarSistemi::serilestir() const { std::string s; for (const AyarTanim& t : tanimlar_) { if (!degistiMi(t)) continue; // yalnız-fark felsefesi (spec §3.3) s += t.kimlik; s += '='; s += degerMetni(t, t.al()); s += '\n'; } return s; } int AyarSistemi::yukle(std::string_view metin) { int adet = 0; while (!metin.empty()) { const size_t sn = metin.find('\n'); std::string_view satir = (sn == std::string_view::npos) ? metin : metin.substr(0, sn); metin.remove_prefix(sn == std::string_view::npos ? metin.size() : sn + 1); satir = kirp(satir); const size_t es = satir.find('='); if (es == std::string_view::npos || es == 0) continue; const AyarTanim* t = bul(kirp(satir.substr(0, es))); if (!t) continue; AyarDeger d = t->varsayilan; if (!degerCoz(*t, satir.substr(es + 1), d)) continue; t->ata(d); // sessiz uygulama — degisti köprüsü çağrılmaz ++adet; } return adet; } AyarSistemi& sistem() { static AyarSistemi s; return s; } } // namespace fiko::ayar