From 05c418ebe2da24a8df4ef2c1d1d7864eb2d806e3 Mon Sep 17 00:00:00 2001 From: hrydgard Date: Fri, 4 Jun 2010 19:56:34 +0000 Subject: [PATCH] Refactor the original and much more compatible IniFile implementation to work more like Billiard's, with a public Section interface, but keep the old interface as well. git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@5603 8ced0084-cf51-0410-be5f-012b33b47a6e --- Source/Core/Common/Src/IniFile.cpp | 450 +++++++++++++------------- Source/Core/Common/Src/IniFile.h | 128 ++++++-- Source/Core/Common/Src/StringUtil.cpp | 20 +- Source/Core/Common/Src/StringUtil.h | 2 + 4 files changed, 342 insertions(+), 258 deletions(-) diff --git a/Source/Core/Common/Src/IniFile.cpp b/Source/Core/Common/Src/IniFile.cpp index 04f08168a9..84f5a099d1 100644 --- a/Source/Core/Common/Src/IniFile.cpp +++ b/Source/Core/Common/Src/IniFile.cpp @@ -28,79 +28,9 @@ #include "StringUtil.h" #include "IniFile.h" -IniFile::IniFile() -{} +namespace { -IniFile::~IniFile() -{} - -Section::Section() - : lines(), name(""), comment("") {} - - -Section::Section(const std::string& _name) - : lines(), name(_name), comment("") {} - - -Section::Section(const Section& other) -{ - name = other.name; - comment = other.comment; - lines = other.lines; -} - -const Section* IniFile::GetSection(const char* sectionName) const -{ - for (std::vector
::const_iterator iter = sections.begin(); iter != sections.end(); ++iter) - if (!strcasecmp(iter->name.c_str(), sectionName)) - return (&(*iter)); - return 0; -} - -Section* IniFile::GetSection(const char* sectionName) -{ - for (std::vector
::iterator iter = sections.begin(); iter != sections.end(); ++iter) - if (!strcasecmp(iter->name.c_str(), sectionName)) - return (&(*iter)); - return 0; -} - -Section* IniFile::GetOrCreateSection(const char* sectionName) -{ - Section* section = GetSection(sectionName); - - if (!section) - { - sections.push_back(Section(sectionName)); - section = §ions[sections.size() - 1]; - } - - return(section); -} - - -bool IniFile::DeleteSection(const char* sectionName) -{ - Section* s = GetSection(sectionName); - - if (!s) - { - return false; - } - - for (std::vector
::iterator iter = sections.begin(); iter != sections.end(); ++iter) - { - if (&(*iter) == s) - { - sections.erase(iter); - return true; - } - } - - return false; -} - -void IniFile::ParseLine(const std::string& line, std::string* keyOut, std::string* valueOut, std::string* commentOut) const +static void ParseLine(const std::string& line, std::string* keyOut, std::string* valueOut, std::string* commentOut) { // int FirstEquals = (int)line.find("=", 0); @@ -128,67 +58,243 @@ void IniFile::ParseLine(const std::string& line, std::string* keyOut, std::strin } } -std::string* IniFile::GetLine(Section* section, const char* key, std::string* valueOut, std::string* commentOut) +} + +IniFile::Section::Section() + : lines(), name(""), comment("") {} + + +IniFile::Section::Section(const std::string& _name) + : lines(), name(_name), comment("") {} + + +IniFile::Section::Section(const Section& other) { - for (std::vector::iterator iter = section->lines.begin(); iter != section->lines.end(); ++iter) + name = other.name; + comment = other.comment; + lines = other.lines; +} + +std::string* IniFile::Section::GetLine(const char* key, std::string* valueOut, std::string* commentOut) +{ + for (std::vector::iterator iter = lines.begin(); iter != lines.end(); ++iter) { std::string& line = *iter; std::string lineKey; ParseLine(line, &lineKey, valueOut, commentOut); - if (!strcasecmp(lineKey.c_str(), key)) - { return &line; - } } - return 0; } -bool IniFile::Exists(const char* const sectionName, const char* key) const +void IniFile::Section::Set(const char* key, const char* newValue) { + std::string value, comment; + std::string* line = GetLine(key, &value, &comment); + if (line) + { + // Change the value - keep the key and comment + *line = StripSpaces(key) + " = " + newValue + comment; + } + else + { + // The key did not already exist in this section - let's add it. + lines.push_back(std::string(key) + " = " + newValue); + } +} - const Section* const section = GetSection(sectionName); - if (!section) +bool IniFile::Section::Get(const char* key, std::string* value, const char* defaultValue) +{ + std::string* line = GetLine(key, value, 0); + if (!line) + { + if (defaultValue) + { + *value = defaultValue; + } return false; + } + return true; +} - for (std::vector::const_iterator iter = section->lines.begin(); iter != section->lines.end(); ++iter) +void IniFile::Section::Set(const char* key, const std::vector& newValues) +{ + std::string temp; + // Join the strings with , + std::vector::const_iterator it; + for (it = newValues.begin(); it != newValues.end(); ++it) + { + temp = (*it) + ","; + } + // remove last , + temp.resize(temp.length() - 1); + Set(key, temp.c_str()); +} + +bool IniFile::Section::Get(const char* key, std::vector& values) +{ + std::string temp; + bool retval = Get(key, &temp, 0); + if (!retval || temp.empty()) + { + return false; + } + // ignore starting , if any + size_t subStart = temp.find_first_not_of(","); + size_t subEnd; + + // split by , + while (subStart != std::string::npos) { + + // Find next , + subEnd = temp.find_first_of(",", subStart); + if (subStart != subEnd) + // take from first char until next , + values.push_back(StripSpaces(temp.substr(subStart, subEnd - subStart))); + + // Find the next non , char + subStart = temp.find_first_not_of(",", subEnd); + } + + return true; +} + +bool IniFile::Section::Get(const char* key, int* value, int defaultValue) +{ + std::string temp; + bool retval = Get(key, &temp, 0); + if (retval && TryParseInt(temp.c_str(), value)) + return true; + *value = defaultValue; + return false; +} + +bool IniFile::Section::Get(const char* key, u32* value, u32 defaultValue) +{ + std::string temp; + bool retval = Get(key, &temp, 0); + if (retval && TryParseUInt(temp.c_str(), value)) + return true; + *value = defaultValue; + return false; +} + +bool IniFile::Section::Get(const char* key, bool* value, bool defaultValue) +{ + std::string temp; + bool retval = Get(key, &temp, 0); + if (retval && TryParseBool(temp.c_str(), value)) + return true; + *value = defaultValue; + return false; +} + +bool IniFile::Section::Get(const char* key, float* value, float defaultValue) +{ + std::string temp; + bool retval = Get(key, &temp, 0); + if (retval && TryParseFloat(temp.c_str(), value)) + return true; + *value = defaultValue; + return false; +} + +bool IniFile::Section::Get(const char* key, double* value, double defaultValue) +{ + std::string temp; + bool retval = Get(key, &temp, 0); + if (retval && TryParseDouble(temp.c_str(), value)) + return true; + *value = defaultValue; + return false; +} + +bool IniFile::Section::Exists(const char *key) const +{ + for (std::vector::const_iterator iter = lines.begin(); iter != lines.end(); ++iter) { std::string lineKey; ParseLine(*iter, &lineKey, NULL, NULL); - if (!strcasecmp(lineKey.c_str(), key)) + return true; + } + return false; +} + + +// IniFile + +IniFile::IniFile() {} +IniFile::~IniFile() {} + +const IniFile::Section* IniFile::GetSection(const char* sectionName) const +{ + for (std::vector
::const_iterator iter = sections.begin(); iter != sections.end(); ++iter) + if (!strcasecmp(iter->name.c_str(), sectionName)) + return (&(*iter)); + return 0; +} + +IniFile::Section* IniFile::GetSection(const char* sectionName) +{ + for (std::vector
::iterator iter = sections.begin(); iter != sections.end(); ++iter) + if (!strcasecmp(iter->name.c_str(), sectionName)) + return (&(*iter)); + return 0; +} + +IniFile::Section* IniFile::GetOrCreateSection(const char* sectionName) +{ + Section* section = GetSection(sectionName); + if (!section) + { + sections.push_back(Section(sectionName)); + section = §ions[sections.size() - 1]; + } + return section; +} + +bool IniFile::DeleteSection(const char* sectionName) +{ + Section* s = GetSection(sectionName); + if (!s) + return false; + for (std::vector
::iterator iter = sections.begin(); iter != sections.end(); ++iter) + { + if (&(*iter) == s) { + sections.erase(iter); return true; } } - return false; } +bool IniFile::Exists(const char* sectionName, const char* key) const +{ + const Section* section = GetSection(sectionName); + if (!section) + return false; + return section->Exists(key); +} + void IniFile::SetLines(const char* sectionName, const std::vector &lines) { Section* section = GetOrCreateSection(sectionName); section->lines.clear(); - for (std::vector::const_iterator iter = lines.begin(); iter != lines.end(); ++iter) { section->lines.push_back(*iter); } } - bool IniFile::DeleteKey(const char* sectionName, const char* key) { Section* section = GetSection(sectionName); - if (!section) - { return false; - } - - std::string* line = GetLine(section, key, 0, 0); - + std::string* line = section->GetLine(key, 0, 0); for (std::vector::iterator liter = section->lines.begin(); liter != section->lines.end(); ++liter) { if (line == &(*liter)) @@ -197,7 +303,6 @@ bool IniFile::DeleteKey(const char* sectionName, const char* key) return true; } } - return false; //shouldn't happen } @@ -205,21 +310,15 @@ bool IniFile::DeleteKey(const char* sectionName, const char* key) bool IniFile::GetKeys(const char* sectionName, std::vector& keys) const { const Section* section = GetSection(sectionName); - if (!section) - { return false; - } - keys.clear(); - for (std::vector::const_iterator liter = section->lines.begin(); liter != section->lines.end(); ++liter) { std::string key; ParseLine(*liter, &key, 0, 0); keys.push_back(key); } - return true; } @@ -347,163 +446,62 @@ bool IniFile::Save(const char* filename) return true; } -void IniFile::Set(const char* sectionName, const char* key, const char* newValue) -{ - Section* section = GetOrCreateSection(sectionName); - std::string value, comment; - std::string* line = GetLine(section, key, &value, &comment); - - if (line) - { - // Change the value - keep the key and comment - *line = StripSpaces(key) + " = " + newValue + comment; - } - else - { - // The key did not already exist in this section - let's add it. - section->lines.push_back(std::string(key) + " = " + newValue); - } -} - -void IniFile::Set(const char* sectionName, const char* key, const std::vector& newValues) -{ - std::string temp; - - // Join the strings with , - std::vector::const_iterator it; - for (it = newValues.begin(); it != newValues.end(); ++it) { - - temp = (*it) + ","; - } - - // remove last , - temp.resize(temp.length() - 1); - - Set(sectionName, key, temp.c_str()); -} - -void IniFile::Set(const char* sectionName, const char* key, u32 newValue) -{ - Set(sectionName, key, StringFromFormat("0x%08x", newValue).c_str()); -} - - -void IniFile::Set(const char* sectionName, const char* key, int newValue) -{ - Set(sectionName, key, StringFromInt(newValue).c_str()); -} - - -void IniFile::Set(const char* sectionName, const char* key, bool newValue) -{ - Set(sectionName, key, StringFromBool(newValue).c_str()); -} bool IniFile::Get(const char* sectionName, const char* key, std::string* value, const char* defaultValue) { Section* section = GetSection(sectionName); - - if (!section) - { - if (defaultValue) - { + if (!section) { + if (defaultValue) { *value = defaultValue; } return false; } - - std::string* line = GetLine(section, key, value, 0); - - if (!line) - { - if (defaultValue) - { - *value = defaultValue; - } - return false; - } - - return true; + return section->Get(key, value, defaultValue); } - -bool IniFile::Get(const char* sectionName, const char* key, std::vector& values) +bool IniFile::Get(const char *sectionName, const char* key, std::vector& values) { - - std::string temp; - bool retval = Get(sectionName, key, &temp, 0); - - if (! retval || temp.empty()) { + Section *section = GetSection(sectionName); + if (!section) return false; - } - - - // ignore starting , if any - size_t subStart = temp.find_first_not_of(","); - size_t subEnd; - - // split by , - while (subStart != std::string::npos) { - - // Find next , - subEnd = temp.find_first_of(",", subStart); - if (subStart != subEnd) - // take from first char until next , - values.push_back(StripSpaces(temp.substr(subStart, subEnd - subStart))); - - // Find the next non , char - subStart = temp.find_first_not_of(",", subEnd); - } - - return true; + return section->Get(key, values); } bool IniFile::Get(const char* sectionName, const char* key, int* value, int defaultValue) { - std::string temp; - bool retval = Get(sectionName, key, &temp, 0); - - if (retval && TryParseInt(temp.c_str(), value)) - { - return true; + Section *section = GetSection(sectionName); + if (!section) { + *value = defaultValue; + return false; + } else { + return section->Get(key, value, defaultValue); } - - *value = defaultValue; - return false; } - bool IniFile::Get(const char* sectionName, const char* key, u32* value, u32 defaultValue) { - std::string temp; - bool retval = Get(sectionName, key, &temp, 0); - - if (retval && TryParseUInt(temp.c_str(), value)) - { - return true; + Section *section = GetSection(sectionName); + if (!section) { + *value = defaultValue; + return false; + } else { + return section->Get(key, value, defaultValue); } - - *value = defaultValue; - return false; } - bool IniFile::Get(const char* sectionName, const char* key, bool* value, bool defaultValue) { - std::string temp; - bool retval = Get(sectionName, key, &temp, 0); - - if (retval && TryParseBool(temp.c_str(), value)) - { - return true; + Section *section = GetSection(sectionName); + if (!section) { + *value = defaultValue; + return false; + } else { + return section->Get(key, value, defaultValue); } - - *value = defaultValue; - return false; } -// TODO: Keep this code below? +// Unit test. TODO: Move to the real unit test framework. /* int main() { diff --git a/Source/Core/Common/Src/IniFile.h b/Source/Core/Common/Src/IniFile.h index 599939731b..e287427c09 100644 --- a/Source/Core/Common/Src/IniFile.h +++ b/Source/Core/Common/Src/IniFile.h @@ -23,44 +23,110 @@ #include "StringUtil.h" -class Section -{ -public: - Section(); - Section(const std::string& _name); - Section(const Section& other); - std::vectorlines; - std::string name; - std::string comment; - - bool operator<(const Section& other) const - { - return(name < other.name); - } -}; - class IniFile { public: + class Section + { + public: + Section(); + Section(const std::string& _name); + Section(const Section& other); + + std::vector lines; + std::string name; + std::string comment; + + bool Exists(const char *key) const; + + std::string* GetLine(const char* key, std::string* valueOut, std::string* commentOut); + void Set(const char* key, const char* newValue); + void Set(const std::string &key, const std::string &value) { + Set(key.c_str(), value.c_str()); + } + bool Get(const char* key, std::string* value, const char* defaultValue); + + void Set(const char* key, u32 newValue) { + Set(key, StringFromFormat("0x%08x", newValue).c_str()); + } + void Set(const char* key, float newValue) { + Set(key, StringFromFormat("%f", newValue).c_str()); + } + void Set(const char* key, double newValue) { + Set(key, StringFromFormat("%f", newValue).c_str()); + } + void Set(const char* key, int newValue) { + Set(key, StringFromInt(newValue).c_str()); + } + void Set(const char* key, bool newValue) { + Set(key, StringFromBool(newValue).c_str()); + } + void Set(const char* key, const std::vector& newValues); + + bool Get(const char* key, int* value, int defaultValue = 0); + bool Get(const char* key, u32* value, u32 defaultValue = 0); + bool Get(const char* key, bool* value, bool defaultValue = false); + bool Get(const char* key, float* value, float defaultValue = false); + bool Get(const char* key, double* value, double defaultValue = false); + bool Get(const char* key, std::vector& values); + + // Direct getters, Billiard-style. + std::string Get(const char *key, const char *default_value) { + std::string value; Get(key, &value, default_value); return value; + } + int Get(const char *key, int defaultValue) { + int value; Get(key, &value, defaultValue); return value; + } + int Get(const char *key, u32 defaultValue) { + u32 value; Get(key, &value, defaultValue); return value; + } + int Get(const char *key, bool defaultValue) { + bool value; Get(key, &value, defaultValue); return value; + } + float Get(const char *key, float defaultValue) { + float value; Get(key, &value, defaultValue); return value; + } + double Get(const char *key, double defaultValue) { + double value; Get(key, &value, defaultValue); return value; + } + + bool operator < (const Section& other) const { + return name < other.name; + } + }; + IniFile(); ~IniFile(); bool Load(const char* filename); + bool Load(const std::string &filename) { return Load(filename.c_str()); } bool Save(const char* filename); + bool Save(const std::string &filename) { return Save(filename.c_str()); } - void Set(const char* sectionName, const char* key, const char* newValue); - void Set(const char* sectionName, const char* key, int newValue); - void Set(const char* sectionName, const char* key, u32 newValue); - void Set(const char* sectionName, const char* key, bool newValue); - void Set(const char* sectionName, const char* key, const std::string& newValue) {Set(sectionName, key, newValue.c_str());} - void Set(const char* sectionName, const char* key, const std::vector& newValues); - - void SetLines(const char* sectionName, const std::vector &lines); - - // Returns true if exists key in section + // Returns true if key exists in section bool Exists(const char* sectionName, const char* key) const; - // getter should be const + // TODO: Get rid of these, in favor of the Section ones. + void Set(const char* sectionName, const char* key, const char* newValue) { + GetOrCreateSection(sectionName)->Set(key, newValue); + } + void Set(const char* sectionName, const char* key, const std::string& newValue) { + GetOrCreateSection(sectionName)->Set(key, newValue.c_str()); + } + void Set(const char* sectionName, const char* key, int newValue) { + GetOrCreateSection(sectionName)->Set(key, newValue); + } + void Set(const char* sectionName, const char* key, u32 newValue) { + GetOrCreateSection(sectionName)->Set(key, newValue); + } + void Set(const char* sectionName, const char* key, bool newValue) { + GetOrCreateSection(sectionName)->Set(key, newValue); + } + void Set(const char* sectionName, const char* key, const std::vector& newValues) { + GetOrCreateSection(sectionName)->Set(key, newValues); + } + + // TODO: Get rid of these, in favor of the Section ones. bool Get(const char* sectionName, const char* key, std::string* value, const char* defaultValue = ""); bool Get(const char* sectionName, const char* key, int* value, int defaultValue = 0); bool Get(const char* sectionName, const char* key, u32* value, u32 defaultValue = 0); @@ -68,6 +134,8 @@ public: bool Get(const char* sectionName, const char* key, std::vector& values); bool GetKeys(const char* sectionName, std::vector& keys) const; + + void SetLines(const char* sectionName, const std::vector &lines); bool GetLines(const char* sectionName, std::vector& lines) const; bool DeleteKey(const char* sectionName, const char* key); @@ -75,15 +143,13 @@ public: void SortSections(); - void ParseLine(const std::string& line, std::string* keyOut, std::string* valueOut, std::string* commentOut) const; - std::string* GetLine(Section* section, const char* key, std::string* valueOut, std::string* commentOut); + Section* GetOrCreateSection(const char* section); private: - std::vector
sections; + std::vector
sections; const Section* GetSection(const char* section) const; Section* GetSection(const char* section); - Section* GetOrCreateSection(const char* section); std::string* GetLine(const char* section, const char* key); void CreateSection(const char* section); }; diff --git a/Source/Core/Common/Src/StringUtil.cpp b/Source/Core/Common/Src/StringUtil.cpp index b0d3d2e0e3..5165363094 100644 --- a/Source/Core/Common/Src/StringUtil.cpp +++ b/Source/Core/Common/Src/StringUtil.cpp @@ -244,7 +244,6 @@ bool TryParseInt(const char* str, int* outVal) return true; } - bool TryParseBool(const char* str, bool* output) { if ((str[0] == '1') || !strcasecmp(str, "true")) @@ -260,6 +259,25 @@ bool TryParseBool(const char* str, bool* output) return false; } +bool TryParseFloat(const char* str, float *output) +{ + double d_val; + if (sscanf(str, "%f", &d_val) == 1) + { + *output = (float)d_val; + return true; + } + else + { + return false; + } +} + +bool TryParseDouble(const char* str, double *output) +{ + return sscanf(str, "%f", output) == 1; +} + std::string StringFromInt(int value) { char temp[16]; diff --git a/Source/Core/Common/Src/StringUtil.h b/Source/Core/Common/Src/StringUtil.h index a7b12cdc56..9868c30df6 100644 --- a/Source/Core/Common/Src/StringUtil.h +++ b/Source/Core/Common/Src/StringUtil.h @@ -69,6 +69,8 @@ bool TryParseUInt(const std::wstring& str, u32* output); bool TryParseInt(const char* str, int* outVal); bool TryParseBool(const char* str, bool* output); bool TryParseUInt(const std::string& str, u32* output); +bool TryParseFloat(const char* str, float *output); +bool TryParseDouble(const char* str, double *output); // TODO: kill this