I'm trying to make configuration file for my application, for which I'm using yaml-cpp
library to generate a configuration and modify when user changes changes some setting or something in the application. I have a separate class set up for this, the constructor generates the yaml
file which looks like this,
Serializer::Serializer(const std::string& filepath)
{
std::ifstream ifin(filepath);
if (!ifin)
{
emitter << YAML::Comment("Hello");
emitter << YAML::BeginDoc;
emitter << "This is the configuration file for the Sample Browser,"
<< YAML::Newline;
emitter << "feel free to edit this file as needed";
emitter << YAML::EndDoc;
emitter << YAML::BeginMap;
emitter << YAML::Newline << YAML::Key << "Window";
emitter << YAML::BeginMap;
emitter << YAML::Key << "SizeW" << YAML::Value << "1280";
emitter << YAML::Key << "SizeH" << YAML::Value << "720";
emitter << YAML::EndMap << YAML::Newline;
emitter << YAML::Newline << YAML::Key << "Media";
emitter << YAML::BeginMap;
emitter << YAML::Key << "Autoplay" << YAML::Value << "false";
emitter << YAML::Key << "Loop" << YAML::Value << "false";
emitter << YAML::Key << "Muted" << YAML::Value << "false";
emitter << YAML::EndMap << YAML::Newline;
emitter << YAML::Newline << YAML::Key << "Display";
emitter << YAML::BeginMap;
emitter << YAML::Key << "Font";
emitter << YAML::BeginMap;
emitter << YAML::Key << "Family" << YAML::Value << "Sans";
emitter << YAML::Key << "Size" << YAML::Value << "10";
emitter << YAML::EndMap;
emitter << YAML::EndMap << YAML::Newline;
emitter << YAML::Newline << YAML::Key << "Import_dir";
emitter << YAML::BeginMap;
emitter << YAML::Key << "AutoImport" << YAML::Value << "false";
emitter << YAML::Key << "Directory" << YAML::Value << "/home/apoorv";
emitter << YAML::EndMap << YAML::Newline;
emitter << YAML::EndMap;
std::ofstream ofout(filepath);
ofout << emitter.c_str();
}
else
{
wxLogDebug("Config file already exists! Skipping..");
}
}
and the output of this file looks like,
# Hello
---
This is the configuration file for the Sample Browser,
feel free to edit this file as needed
...
Window:
SizeW: 1280
SizeH: 720
Media:
Autoplay: false
Loop: false
Muted: false
Display:
Font:
Family: "Sans"
Size: "10"
Import_dir:
AutoImport: false
Directory: "/home/apoorv/"
I want that when user changes say font, the related key value also changes with the selected option. I tried making a function that should do this like,
void Serializer::SerializeDisplaySettings(const std::string& filepath, wxFont& font)
{
YAML::Emitter out;
std::string fontFace = font.GetFaceName().ToStdString();
int fontSize = font.GetPointSize();
std::ifstream ifin(filepath);
try
{
YAML::Node config = YAML::LoadAllFromFile(filepath)[1];
auto display = config["Display"];
if (auto fontSetting = display["Font"])
{
wxLogDebug("Changing font settings");
wxLogDebug("Font face: %s", fontFace);
wxLogDebug("Font size: %d", fontSize);
out << YAML::Key << fontSetting["Family"] << YAML::Value << fontFace;
out << YAML::Key << fontSetting["Size"] << YAML::Value << fontSize;
std::ofstream ofout(filepath);
ofout << out.c_str();
}
else
{
wxLogDebug("Error! Cannot fetch values.");
}
}
catch(const YAML::ParserException& ex)
{
std::cout << ex.what() << std::endl;
}
}
but this deletes the whole and fills just font name and size. How do I modify those values without changing/deleting whole file?
You override the file, of course it only contains the items you gave to the emitter out
. If you want to modify the loaded file, you should update the values in config
and write all of it back out:
fontSetting["Family"] = fontFace;
fontSetting["Size"] = fontSize;
out << config;
std::ofstream ofout(filepath);
ofout << out.c_str();
To get the other content as well, do this when loading:
auto docs = YAML::LoadAllFromFile(filepath);
out << YAML::Comment("Hello") << YAML::BeginDoc << docs[0] << YAML::EndDoc;
YAMl::Node config = docs[1];