/* * Copyright 2016 - 2022 Gary Talent (gary@drinkingtea.net). All rights reserved. */ #pragma once #include #include #include #include #include #include #include #include #include #include #include namespace nostalgia::studio { constexpr auto ConfigDir = [] { switch (ox::defines::OS) { case ox::OS::Darwin: return "{}/Library/Preferences/{}"; case ox::OS::DragonFlyBSD: case ox::OS::FreeBSD: case ox::OS::Linux: case ox::OS::NetBSD: case ox::OS::OpenBSD: return "{}/.config/{}"; case ox::OS::Windows: return "{}/AppData/Local/{}"; case ox::OS::BareMetal: return ""; } }(); template ox::Result readConfig(core::Context *ctx, const char *name) noexcept { oxAssert(ox_strcmp(name, ""), "Config type has no TypeName"); const auto homeDir = std::getenv(ox::defines::OS == ox::OS::Windows ? "USERPROFILE" : "HOME"); const auto configPath = ox::sfmt(ConfigDir, homeDir, ctx->appName).toStdString(); const auto path = ox::sfmt("{}/{}.json", configPath, name).toStdString(); std::ifstream file(path, std::ios::binary | std::ios::ate); if (!file.good()) { oxErrf("Could not find config file: {}\n", path); return OxError(1, "Could not find config file"); } try { const auto size = file.tellg(); file.seekg(0, std::ios::beg); ox::Buffer buff(static_cast(size)); file.read(buff.data(), size); return ox::readOC(buff); } catch (const std::ios_base::failure &e) { oxErrf("Could not read config file: {}\n", e.what()); return OxError(2, "Could not read config file"); } } template ox::Result readConfig(core::Context *ctx) noexcept { constexpr auto TypeName = ox::requireModelTypeName(); return readConfig(ctx, TypeName); } template ox::Error writeConfig(core::Context *ctx, const auto &name, T *data) noexcept { oxAssert(ox_strcmp(name, ""), "Config type has no TypeName"); const auto homeDir = std::getenv(ox::defines::OS == ox::OS::Windows ? "USERPROFILE" : "HOME"); const auto configPath = ox::sfmt(ConfigDir, homeDir, ctx->appName).toStdString(); const auto path = ox::sfmt("{}.json", name).toStdString(); ox::PassThroughFS fs(configPath.c_str()); if (auto err = fs.mkdir(configPath.c_str(), true)) { oxErrf("Could not create config directory: {}\n", toStr(err)); return err; } oxRequireM(buff, ox::writeOC(data)); buff.back().value = '\n'; if (auto err = fs.write(path.c_str(), buff.data(), buff.size())) { oxErrf("Could not read config file: {}\n", toStr(err)); return OxError(2, "Could not read config file"); } return OxError(0); } template ox::Error writeConfig(core::Context *ctx, T *data) noexcept { constexpr auto TypeName = ox::requireModelTypeName(); return writeConfig(ctx, TypeName, data); } template void openConfig(core::Context *ctx, const auto &name, Func f) noexcept { oxAssert(name != "", "Config type has no TypeName"); const auto c = readConfig(ctx, name); f(&c.value); } template void openConfig(core::Context *ctx, Func f) noexcept { constexpr auto TypeName = ox::requireModelTypeName(); openConfig(ctx, TypeName, f); } template void editConfig(core::Context *ctx, const auto &name, Func f) noexcept { oxAssert(ox_strcmp(name, ""), "Config type has no TypeName"); auto c = readConfig(ctx, name); f(&c.value); oxLogError(writeConfig(ctx, name, &c.value)); } template void editConfig(core::Context *ctx, Func f) noexcept { constexpr auto TypeName = ox::requireModelTypeName(); editConfig(ctx, TypeName, f); } }