287 lines
6.1 KiB
C++
287 lines
6.1 KiB
C++
|
// Copyright 2017 Dolphin Emulator Project
|
||
|
// Licensed under GPLv2+
|
||
|
// Refer to the license.txt file included.
|
||
|
|
||
|
#include <array>
|
||
|
#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;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
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)
|
||
|
{
|
||
|
Section::Set(key, StringFromInt(newValue));
|
||
|
}
|
||
|
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
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
|
||
|
{
|
||
|
static constexpr std::array<LayerType, 7> search_order = {{
|
||
|
// Skip the meta layer
|
||
|
LayerType::CurrentRun, LayerType::CommandLine, LayerType::Movie, LayerType::Netplay,
|
||
|
LayerType::LocalGame, LayerType::GlobalGame, LayerType::Base,
|
||
|
}};
|
||
|
|
||
|
for (auto layer_id : search_order)
|
||
|
{
|
||
|
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!");
|
||
|
}
|
||
|
}
|