// Copyright 2017 Dolphin Emulator Project // Licensed under GPLv2+ // Refer to the license.txt file included. #include #include #include #include #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& 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* 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& 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 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!"); } }