2017-02-16 08:58:40 -07:00
|
|
|
// Copyright 2017 Dolphin Emulator Project
|
|
|
|
// Licensed under GPLv2+
|
|
|
|
// Refer to the license.txt file included.
|
|
|
|
|
|
|
|
#include <cstddef>
|
|
|
|
#include <map>
|
|
|
|
#include <memory>
|
|
|
|
|
|
|
|
#include "Common/Assert.h"
|
|
|
|
#include "Common/Config/Config.h"
|
|
|
|
#include "Common/Config/Layer.h"
|
|
|
|
#include "Common/Config/Section.h"
|
|
|
|
#include "Common/StringUtil.h"
|
|
|
|
|
|
|
|
namespace Config
|
|
|
|
{
|
|
|
|
const std::string& Section::NULL_STRING = "";
|
|
|
|
|
|
|
|
Section::Section(LayerType layer, System system, const std::string& name)
|
|
|
|
: m_layer(layer), m_system(system), m_name(name)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Section::Exists(const std::string& key) const
|
|
|
|
{
|
|
|
|
return m_values.find(key) != m_values.end();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Section::Delete(const std::string& key)
|
|
|
|
{
|
|
|
|
auto it = m_values.find(key);
|
|
|
|
if (it == m_values.end())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
m_values.erase(it);
|
|
|
|
|
|
|
|
m_deleted_keys.push_back(key);
|
|
|
|
m_dirty = true;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Section::Set(const std::string& key, const std::string& value)
|
|
|
|
{
|
|
|
|
auto it = m_values.find(key);
|
|
|
|
if (it != m_values.end() && it->second != value)
|
|
|
|
{
|
|
|
|
it->second = value;
|
|
|
|
m_dirty = true;
|
|
|
|
}
|
|
|
|
else if (it == m_values.end())
|
|
|
|
{
|
|
|
|
m_values[key] = value;
|
|
|
|
m_dirty = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-08-02 17:45:03 -06:00
|
|
|
void Section::Set(const std::string& key, u16 newValue)
|
|
|
|
{
|
|
|
|
Section::Set(key, StringFromFormat("0x%04x", newValue));
|
|
|
|
}
|
|
|
|
|
2017-02-16 08:58:40 -07:00
|
|
|
void Section::Set(const std::string& key, u32 newValue)
|
|
|
|
{
|
|
|
|
Section::Set(key, StringFromFormat("0x%08x", newValue));
|
|
|
|
}
|
|
|
|
|
|
|
|
void Section::Set(const std::string& key, float newValue)
|
|
|
|
{
|
|
|
|
Section::Set(key, StringFromFormat("%#.9g", newValue));
|
|
|
|
}
|
|
|
|
|
|
|
|
void Section::Set(const std::string& key, double newValue)
|
|
|
|
{
|
|
|
|
Section::Set(key, StringFromFormat("%#.17g", newValue));
|
|
|
|
}
|
|
|
|
|
|
|
|
void Section::Set(const std::string& key, int newValue)
|
|
|
|
{
|
2017-07-05 05:49:33 -06:00
|
|
|
Section::Set(key, std::to_string(newValue));
|
2017-02-16 08:58:40 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void Section::Set(const std::string& key, bool newValue)
|
|
|
|
{
|
|
|
|
Section::Set(key, StringFromBool(newValue));
|
|
|
|
}
|
|
|
|
|
|
|
|
void Section::Set(const std::string& key, const std::string& newValue,
|
|
|
|
const std::string& defaultValue)
|
|
|
|
{
|
|
|
|
if (newValue != defaultValue)
|
|
|
|
Set(key, newValue);
|
|
|
|
else
|
|
|
|
Delete(key);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Section::SetLines(const std::vector<std::string>& lines)
|
|
|
|
{
|
|
|
|
m_lines = lines;
|
|
|
|
m_dirty = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Section::Get(const std::string& key, std::string* value,
|
|
|
|
const std::string& default_value) const
|
|
|
|
{
|
|
|
|
const auto& it = m_values.find(key);
|
|
|
|
if (it != m_values.end())
|
|
|
|
{
|
|
|
|
*value = it->second;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else if (&default_value != &NULL_STRING)
|
|
|
|
{
|
|
|
|
*value = default_value;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Section::Get(const std::string& key, int* value, int defaultValue) const
|
|
|
|
{
|
|
|
|
std::string temp;
|
|
|
|
bool retval = Get(key, &temp);
|
|
|
|
|
|
|
|
if (retval && TryParse(temp, value))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
*value = defaultValue;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2017-08-02 17:45:03 -06:00
|
|
|
bool Section::Get(const std::string& key, u16* value, u16 defaultValue) const
|
|
|
|
{
|
|
|
|
std::string temp;
|
|
|
|
bool retval = Get(key, &temp);
|
|
|
|
|
|
|
|
if (retval && TryParse(temp, value))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
*value = defaultValue;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2017-02-16 08:58:40 -07:00
|
|
|
bool Section::Get(const std::string& key, u32* value, u32 defaultValue) const
|
|
|
|
{
|
|
|
|
std::string temp;
|
|
|
|
bool retval = Get(key, &temp);
|
|
|
|
|
|
|
|
if (retval && TryParse(temp, value))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
*value = defaultValue;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Section::Get(const std::string& key, bool* value, bool defaultValue) const
|
|
|
|
{
|
|
|
|
std::string temp;
|
|
|
|
bool retval = Get(key, &temp);
|
|
|
|
|
|
|
|
if (retval && TryParse(temp, value))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
*value = defaultValue;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Section::Get(const std::string& key, float* value, float defaultValue) const
|
|
|
|
{
|
|
|
|
std::string temp;
|
|
|
|
bool retval = Get(key, &temp);
|
|
|
|
|
|
|
|
if (retval && TryParse(temp, value))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
*value = defaultValue;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Section::Get(const std::string& key, double* value, double defaultValue) const
|
|
|
|
{
|
|
|
|
std::string temp;
|
|
|
|
bool retval = Get(key, &temp);
|
|
|
|
|
|
|
|
if (retval && TryParse(temp, value))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
*value = defaultValue;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Return a list of all lines in a section
|
|
|
|
bool Section::GetLines(std::vector<std::string>* lines, const bool remove_comments) const
|
|
|
|
{
|
|
|
|
lines->clear();
|
|
|
|
|
|
|
|
for (std::string line : m_lines)
|
|
|
|
{
|
|
|
|
line = StripSpaces(line);
|
|
|
|
|
|
|
|
if (remove_comments)
|
|
|
|
{
|
|
|
|
size_t commentPos = line.find('#');
|
|
|
|
if (commentPos == 0)
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (commentPos != std::string::npos)
|
|
|
|
{
|
|
|
|
line = StripSpaces(line.substr(0, commentPos));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
lines->push_back(line);
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Section::HasLines() const
|
|
|
|
{
|
|
|
|
return !m_lines.empty();
|
|
|
|
}
|
|
|
|
|
|
|
|
const std::string& Section::GetName() const
|
|
|
|
{
|
|
|
|
return m_name;
|
|
|
|
}
|
|
|
|
|
|
|
|
const SectionValueMap& Section::GetValues() const
|
|
|
|
{
|
|
|
|
return m_values;
|
|
|
|
}
|
|
|
|
|
|
|
|
const std::vector<std::string>& Section::GetDeletedKeys() const
|
|
|
|
{
|
|
|
|
return m_deleted_keys;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Section::IsDirty() const
|
|
|
|
{
|
|
|
|
return m_dirty;
|
|
|
|
}
|
|
|
|
void Section::ClearDirty()
|
|
|
|
{
|
|
|
|
m_dirty = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
RecursiveSection::RecursiveSection(LayerType layer, System system, const std::string& name)
|
|
|
|
: Section(layer, system, name)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
bool RecursiveSection::Exists(const std::string& key) const
|
|
|
|
{
|
|
|
|
auto layers_it = Config::GetLayers()->find(LayerType::Meta);
|
|
|
|
do
|
|
|
|
{
|
|
|
|
const Section* layer_section = layers_it->second->GetSection(m_system, m_name);
|
|
|
|
if (layer_section && layer_section->Exists(key))
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
} while (--layers_it != Config::GetLayers()->end());
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool RecursiveSection::Get(const std::string& key, std::string* value,
|
|
|
|
const std::string& default_value) const
|
|
|
|
{
|
2017-05-18 06:53:52 -06:00
|
|
|
for (auto layer_id : SEARCH_ORDER)
|
2017-02-16 08:58:40 -07:00
|
|
|
{
|
|
|
|
auto layers_it = Config::GetLayers()->find(layer_id);
|
|
|
|
if (layers_it == Config::GetLayers()->end())
|
|
|
|
continue;
|
|
|
|
|
|
|
|
const Section* layer_section = layers_it->second->GetSection(m_system, m_name);
|
|
|
|
if (layer_section && layer_section->Exists(key))
|
|
|
|
{
|
|
|
|
return layer_section->Get(key, value, default_value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return Section::Get(key, value, default_value);
|
|
|
|
}
|
|
|
|
|
|
|
|
void RecursiveSection::Set(const std::string& key, const std::string& value)
|
|
|
|
{
|
|
|
|
// The RecursiveSection can't set since it is used to recursively get values from the layer
|
|
|
|
// map.
|
|
|
|
// It is only a part of the meta layer, and the meta layer isn't allowed to set any values.
|
|
|
|
_assert_msg_(COMMON, false, "Don't try to set values here!");
|
|
|
|
}
|
|
|
|
}
|