2015-08-16 21:35:13 +00:00
|
|
|
#include "ini.h"
|
2021-05-31 17:44:55 +00:00
|
|
|
#include "types.h"
|
2015-08-18 17:36:19 +00:00
|
|
|
#include <sstream>
|
2021-10-10 15:24:17 +00:00
|
|
|
#include "stdclass.h"
|
2015-08-16 21:35:13 +00:00
|
|
|
|
2019-03-23 19:56:01 +00:00
|
|
|
namespace emucfg {
|
|
|
|
|
2015-08-18 17:36:19 +00:00
|
|
|
/* ConfigEntry */
|
|
|
|
|
2020-03-29 17:29:14 +00:00
|
|
|
const std::string& ConfigEntry::get_string() const
|
2015-08-16 21:35:13 +00:00
|
|
|
{
|
2015-08-18 17:36:19 +00:00
|
|
|
return this->value;
|
2015-08-16 21:35:13 +00:00
|
|
|
}
|
|
|
|
|
2015-08-18 17:36:19 +00:00
|
|
|
int ConfigEntry::get_int()
|
2015-08-16 21:35:13 +00:00
|
|
|
{
|
2015-08-18 17:36:19 +00:00
|
|
|
if (strstr(this->value.c_str(), "0x") != NULL)
|
|
|
|
{
|
2021-01-23 14:59:57 +00:00
|
|
|
return (int)strtoul(this->value.c_str(), NULL, 16);
|
2015-08-18 17:36:19 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return atoi(this->value.c_str());
|
|
|
|
}
|
2015-08-16 21:35:13 +00:00
|
|
|
}
|
|
|
|
|
2015-08-18 17:36:19 +00:00
|
|
|
bool ConfigEntry::get_bool()
|
2015-08-16 21:35:13 +00:00
|
|
|
{
|
2015-08-23 01:12:20 +00:00
|
|
|
if (stricmp(this->value.c_str(), "yes") == 0 ||
|
|
|
|
stricmp(this->value.c_str(), "true") == 0 ||
|
|
|
|
stricmp(this->value.c_str(), "on") == 0 ||
|
|
|
|
stricmp(this->value.c_str(), "1") == 0)
|
2015-08-18 17:36:19 +00:00
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
2015-08-16 21:35:13 +00:00
|
|
|
else
|
2015-08-18 17:36:19 +00:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2015-08-16 21:35:13 +00:00
|
|
|
}
|
|
|
|
|
2015-08-18 17:36:19 +00:00
|
|
|
/* ConfigSection */
|
|
|
|
|
2019-02-16 13:25:54 +00:00
|
|
|
bool ConfigSection::has_entry(const std::string& name)
|
2015-08-16 21:35:13 +00:00
|
|
|
{
|
2015-08-18 17:36:19 +00:00
|
|
|
return (this->entries.count(name) == 1);
|
2019-09-07 12:37:39 +00:00
|
|
|
}
|
2015-08-16 21:35:13 +00:00
|
|
|
|
2019-02-16 13:25:54 +00:00
|
|
|
ConfigEntry* ConfigSection::get_entry(const std::string& name)
|
2015-08-16 21:35:13 +00:00
|
|
|
{
|
2015-08-18 17:36:19 +00:00
|
|
|
if(this->has_entry(name))
|
2015-08-16 21:35:13 +00:00
|
|
|
{
|
2015-08-18 17:36:19 +00:00
|
|
|
return &this->entries[name];
|
2015-08-16 21:35:13 +00:00
|
|
|
}
|
2015-08-18 17:36:19 +00:00
|
|
|
return NULL;
|
2019-09-07 12:37:39 +00:00
|
|
|
}
|
2015-08-16 21:35:13 +00:00
|
|
|
|
2019-02-16 13:25:54 +00:00
|
|
|
void ConfigSection::set(const std::string& name, const std::string& value)
|
2015-08-16 21:35:13 +00:00
|
|
|
{
|
2015-08-19 02:43:54 +00:00
|
|
|
ConfigEntry new_entry = { value };
|
2015-08-18 17:36:19 +00:00
|
|
|
this->entries[name] = new_entry;
|
2019-09-07 12:37:39 +00:00
|
|
|
}
|
2015-08-16 21:35:13 +00:00
|
|
|
|
2019-02-16 13:25:54 +00:00
|
|
|
void ConfigSection::delete_entry(const std::string& name)
|
|
|
|
{
|
|
|
|
this->entries.erase(name);
|
|
|
|
}
|
|
|
|
|
2015-08-18 17:36:19 +00:00
|
|
|
/* ConfigFile */
|
2015-08-16 21:35:13 +00:00
|
|
|
|
2019-02-16 13:25:54 +00:00
|
|
|
ConfigSection* ConfigFile::add_section(const std::string& name, bool is_virtual)
|
2015-08-18 17:36:19 +00:00
|
|
|
{
|
2015-08-19 02:43:54 +00:00
|
|
|
ConfigSection new_section;
|
|
|
|
if (is_virtual)
|
|
|
|
{
|
|
|
|
this->virtual_sections.insert(std::make_pair(name, new_section));
|
|
|
|
return &this->virtual_sections[name];
|
|
|
|
}
|
|
|
|
this->sections.insert(std::make_pair(name, new_section));
|
|
|
|
return &this->sections[name];
|
2019-09-07 12:37:39 +00:00
|
|
|
}
|
2015-08-18 17:36:19 +00:00
|
|
|
|
2019-02-16 13:25:54 +00:00
|
|
|
bool ConfigFile::has_section(const std::string& name)
|
2015-08-18 17:36:19 +00:00
|
|
|
{
|
2015-08-19 02:43:54 +00:00
|
|
|
return (this->virtual_sections.count(name) == 1 || this->sections.count(name) == 1);
|
2015-08-18 17:36:19 +00:00
|
|
|
}
|
|
|
|
|
2019-02-16 13:25:54 +00:00
|
|
|
bool ConfigFile::has_entry(const std::string& section_name, const std::string& entry_name)
|
2015-08-18 17:36:19 +00:00
|
|
|
{
|
2015-08-19 02:43:54 +00:00
|
|
|
ConfigSection* section = this->get_section(section_name, true);
|
|
|
|
if ((section != NULL) && section->has_entry(entry_name))
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
section = this->get_section(section_name, false);
|
|
|
|
return ((section != NULL) && section->has_entry(entry_name));
|
|
|
|
}
|
2015-08-18 17:36:19 +00:00
|
|
|
|
2019-02-16 13:25:54 +00:00
|
|
|
ConfigSection* ConfigFile::get_section(const std::string& name, bool is_virtual)
|
2015-08-18 17:36:19 +00:00
|
|
|
{
|
2015-08-19 02:43:54 +00:00
|
|
|
if(is_virtual)
|
2015-08-16 21:35:13 +00:00
|
|
|
{
|
2015-08-19 02:43:54 +00:00
|
|
|
if (this->virtual_sections.count(name) == 1)
|
|
|
|
{
|
|
|
|
return &this->virtual_sections[name];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (this->sections.count(name) == 1)
|
|
|
|
{
|
|
|
|
return &this->sections[name];
|
|
|
|
}
|
2015-08-16 21:35:13 +00:00
|
|
|
}
|
2015-08-18 17:36:19 +00:00
|
|
|
return NULL;
|
2019-09-07 12:37:39 +00:00
|
|
|
}
|
2015-08-16 21:35:13 +00:00
|
|
|
|
2019-02-16 13:25:54 +00:00
|
|
|
ConfigEntry* ConfigFile::get_entry(const std::string& section_name, const std::string& entry_name)
|
2015-08-18 17:36:19 +00:00
|
|
|
{
|
2015-08-19 02:43:54 +00:00
|
|
|
ConfigSection* section = this->get_section(section_name, true);
|
2018-02-13 22:20:23 +00:00
|
|
|
if(section != NULL && section->has_entry(entry_name))
|
2015-08-19 02:43:54 +00:00
|
|
|
{
|
|
|
|
return section->get_entry(entry_name);
|
|
|
|
}
|
|
|
|
|
|
|
|
section = this->get_section(section_name, false);
|
|
|
|
if(section != NULL)
|
2015-08-16 21:35:13 +00:00
|
|
|
{
|
2015-08-19 02:43:54 +00:00
|
|
|
return section->get_entry(entry_name);
|
2015-08-16 21:35:13 +00:00
|
|
|
}
|
2015-08-19 02:43:54 +00:00
|
|
|
return NULL;
|
|
|
|
|
2015-08-18 17:36:19 +00:00
|
|
|
}
|
2015-08-16 21:35:13 +00:00
|
|
|
|
2020-03-29 17:29:14 +00:00
|
|
|
std::string ConfigFile::get(const std::string& section_name, const std::string& entry_name, const std::string& default_value)
|
2015-08-18 17:36:19 +00:00
|
|
|
{
|
|
|
|
ConfigEntry* entry = this->get_entry(section_name, entry_name);
|
2018-08-28 17:38:11 +00:00
|
|
|
if (entry == NULL)
|
|
|
|
{
|
|
|
|
return default_value;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return entry->get_string();
|
|
|
|
}
|
2015-08-16 21:35:13 +00:00
|
|
|
}
|
|
|
|
|
2019-02-16 13:25:54 +00:00
|
|
|
int ConfigFile::get_int(const std::string& section_name, const std::string& entry_name, int default_value)
|
2015-08-16 21:35:13 +00:00
|
|
|
{
|
2015-08-18 17:36:19 +00:00
|
|
|
ConfigEntry* entry = this->get_entry(section_name, entry_name);
|
|
|
|
if (entry == NULL)
|
2015-08-16 21:35:13 +00:00
|
|
|
{
|
2015-08-18 17:36:19 +00:00
|
|
|
return default_value;
|
2015-08-16 21:35:13 +00:00
|
|
|
}
|
2015-08-18 17:36:19 +00:00
|
|
|
else
|
2015-08-16 21:35:13 +00:00
|
|
|
{
|
2015-08-18 17:36:19 +00:00
|
|
|
return entry->get_int();
|
2015-08-16 21:35:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-16 13:25:54 +00:00
|
|
|
bool ConfigFile::get_bool(const std::string& section_name, const std::string& entry_name, bool default_value)
|
2015-08-16 21:35:13 +00:00
|
|
|
{
|
2015-08-18 17:36:19 +00:00
|
|
|
ConfigEntry* entry = this->get_entry(section_name, entry_name);
|
|
|
|
if (entry == NULL)
|
|
|
|
{
|
|
|
|
return default_value;
|
|
|
|
}
|
|
|
|
else
|
2015-08-16 21:35:13 +00:00
|
|
|
{
|
2015-08-18 17:36:19 +00:00
|
|
|
return entry->get_bool();
|
2015-08-16 21:35:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-16 13:25:54 +00:00
|
|
|
void ConfigFile::set(const std::string& section_name, const std::string& entry_name, const std::string& value, bool is_virtual)
|
2015-08-16 21:35:13 +00:00
|
|
|
{
|
2015-08-19 02:43:54 +00:00
|
|
|
ConfigSection* section = this->get_section(section_name, is_virtual);
|
2015-08-18 17:36:19 +00:00
|
|
|
if(section == NULL)
|
2015-08-16 21:35:13 +00:00
|
|
|
{
|
2015-08-19 02:43:54 +00:00
|
|
|
section = this->add_section(section_name, is_virtual);
|
2015-08-16 21:35:13 +00:00
|
|
|
}
|
2015-08-19 02:43:54 +00:00
|
|
|
section->set(entry_name, value);
|
2019-09-07 12:37:39 +00:00
|
|
|
}
|
2015-08-16 21:35:13 +00:00
|
|
|
|
2019-02-16 13:25:54 +00:00
|
|
|
void ConfigFile::set_int(const std::string& section_name, const std::string& entry_name, int value, bool is_virtual)
|
2015-08-18 17:36:19 +00:00
|
|
|
{
|
|
|
|
std::stringstream str_value;
|
|
|
|
str_value << value;
|
2015-08-19 02:43:54 +00:00
|
|
|
this->set(section_name, entry_name, str_value.str(), is_virtual);
|
2015-08-16 21:35:13 +00:00
|
|
|
}
|
|
|
|
|
2019-02-16 13:25:54 +00:00
|
|
|
void ConfigFile::set_bool(const std::string& section_name, const std::string& entry_name, bool value, bool is_virtual)
|
2015-08-16 21:35:13 +00:00
|
|
|
{
|
2020-03-29 17:29:14 +00:00
|
|
|
std::string str_value = (value ? "yes" : "no");
|
2015-08-19 02:43:54 +00:00
|
|
|
this->set(section_name, entry_name, str_value, is_virtual);
|
2015-08-16 21:35:13 +00:00
|
|
|
}
|
|
|
|
|
2015-08-18 17:36:19 +00:00
|
|
|
void ConfigFile::parse(FILE* file)
|
2015-08-16 21:35:13 +00:00
|
|
|
{
|
2021-10-10 15:24:17 +00:00
|
|
|
if (file == nullptr)
|
2015-08-18 17:36:19 +00:00
|
|
|
return;
|
2021-10-10 15:24:17 +00:00
|
|
|
|
2015-08-18 17:36:19 +00:00
|
|
|
char line[512];
|
2021-10-10 15:24:17 +00:00
|
|
|
std::string section;
|
2015-08-18 17:36:19 +00:00
|
|
|
int cline = 0;
|
2021-10-10 15:24:17 +00:00
|
|
|
while (true)
|
2015-08-16 21:35:13 +00:00
|
|
|
{
|
2021-10-10 15:24:17 +00:00
|
|
|
if (std::fgets(line, sizeof(line), file) == nullptr)
|
2015-08-16 21:35:13 +00:00
|
|
|
break;
|
|
|
|
cline++;
|
2021-10-10 15:24:17 +00:00
|
|
|
std::string s(line);
|
|
|
|
s = trim_ws(s, " \r\n");
|
|
|
|
if (s.empty())
|
2015-08-16 21:35:13 +00:00
|
|
|
continue;
|
2021-10-10 15:24:17 +00:00
|
|
|
if (s.length() >= 3 && s[0] == '[' && s[s.length() - 1] == ']')
|
2015-08-16 21:35:13 +00:00
|
|
|
{
|
2021-10-10 15:24:17 +00:00
|
|
|
section = s.substr(1, s.length() - 2);
|
|
|
|
continue;
|
2015-08-16 21:35:13 +00:00
|
|
|
}
|
2021-10-10 15:24:17 +00:00
|
|
|
auto eqpos = s.find('=');
|
|
|
|
if (eqpos == std::string::npos)
|
2015-08-16 21:35:13 +00:00
|
|
|
{
|
2021-10-10 15:24:17 +00:00
|
|
|
WARN_LOG(COMMON, "Malformed entry on config - ignoring line %d: %s", cline, s.c_str());
|
|
|
|
continue;
|
2015-08-16 21:35:13 +00:00
|
|
|
}
|
2021-10-10 15:24:17 +00:00
|
|
|
std::string property = trim_ws(s.substr(0, eqpos));
|
|
|
|
std::string value = trim_ws(s.substr(eqpos + 1));
|
|
|
|
if (value.length() >= 2 && value[0] == '"' && value[value.length() - 1] == '"')
|
|
|
|
value = value.substr(1, value.length() - 2);
|
|
|
|
set(section, property, value);
|
2015-08-16 21:35:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-08-18 17:36:19 +00:00
|
|
|
void ConfigFile::save(FILE* file)
|
2015-08-16 21:35:13 +00:00
|
|
|
{
|
2019-09-30 13:33:19 +00:00
|
|
|
for (const auto& section_it : this->sections)
|
2015-08-16 21:35:13 +00:00
|
|
|
{
|
2020-03-29 17:29:14 +00:00
|
|
|
const std::string& section_name = section_it.first;
|
2019-09-30 13:33:19 +00:00
|
|
|
const ConfigSection& section = section_it.second;
|
2015-08-19 02:43:54 +00:00
|
|
|
|
2021-10-10 15:24:17 +00:00
|
|
|
if (!section_name.empty())
|
|
|
|
std::fprintf(file, "[%s]\n", section_name.c_str());
|
2015-08-16 21:35:13 +00:00
|
|
|
|
2019-09-30 13:33:19 +00:00
|
|
|
for (const auto& entry_it : section.entries)
|
2015-08-18 17:36:19 +00:00
|
|
|
{
|
2020-03-29 17:29:14 +00:00
|
|
|
const std::string& entry_name = entry_it.first;
|
2019-09-30 13:33:19 +00:00
|
|
|
const ConfigEntry& entry = entry_it.second;
|
2021-01-19 10:11:01 +00:00
|
|
|
std::fprintf(file, "%s = %s\n", entry_name.c_str(), entry.get_string().c_str());
|
2015-08-18 17:36:19 +00:00
|
|
|
}
|
2015-08-16 21:35:13 +00:00
|
|
|
}
|
|
|
|
}
|
2019-03-23 19:56:01 +00:00
|
|
|
|
2019-02-16 13:25:54 +00:00
|
|
|
void ConfigFile::delete_section(const std::string& section_name) {
|
|
|
|
sections.erase(section_name);
|
|
|
|
virtual_sections.erase(section_name);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ConfigFile::delete_entry(const std::string& section_name, const std::string& entry_name)
|
|
|
|
{
|
|
|
|
ConfigSection *section = get_section(section_name, false);
|
|
|
|
if (section != NULL)
|
|
|
|
section->delete_entry(entry_name);
|
|
|
|
}
|
|
|
|
|
2021-03-01 09:13:40 +00:00
|
|
|
bool ConfigFile::is_virtual(const std::string& section_name, const std::string& entry_name)
|
|
|
|
{
|
|
|
|
ConfigSection *section = get_section(section_name, true);
|
|
|
|
if (section == nullptr)
|
|
|
|
return false;
|
|
|
|
return section->has_entry(entry_name);
|
|
|
|
}
|
|
|
|
|
2019-03-23 19:56:01 +00:00
|
|
|
} // namespace emucfg
|
|
|
|
|