forked from dolphin-emu/dolphin
		
	Updated version of #47. Android should support to_string now that we use a modern version of libc++ when building.
		
			
				
	
	
		
			280 lines
		
	
	
		
			5.8 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			280 lines
		
	
	
		
			5.8 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
// 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;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
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, std::to_string(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
 | 
						|
{
 | 
						|
  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!");
 | 
						|
}
 | 
						|
}
 |