You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
121 lines
3.5 KiB
121 lines
3.5 KiB
/* Config.cpp |
|
* |
|
* Loads and stores configuration data in an INI-like format. |
|
*/ |
|
|
|
#include <algorithm> |
|
#include <fstream> |
|
#include <iostream> |
|
|
|
#include "Config.h" |
|
|
|
namespace PlipSdl { |
|
static inline std::string Trim(std::string str) { |
|
// Trim front. |
|
str.erase(str.cbegin(), std::find_if(str.cbegin(), str.cend(), [](unsigned char c) { |
|
return !std::isspace(c); |
|
})); |
|
|
|
// Trim back. |
|
str.erase(std::find_if(str.crbegin(), str.crend(), [](unsigned char c) { |
|
return !std::isspace(c); |
|
}).base(), str.cend()); |
|
|
|
return str; |
|
} |
|
|
|
static inline std::string ToLower(std::string str) { |
|
std::transform(str.cbegin(), str.cend(), str.begin(), [](unsigned char c) { |
|
return std::tolower(c); |
|
}); |
|
|
|
return str; |
|
} |
|
|
|
const std::string &Config::GetValue(const std::string &key) { |
|
return GetValue(global, key); |
|
} |
|
|
|
const std::string &Config::GetValue(const std::string §ion, const std::string &key) { |
|
auto secLower = ToLower(section); |
|
auto keyLower = ToLower(key); |
|
|
|
auto itSection = m_section.find(secLower); |
|
if(itSection == m_section.end()) return empty; |
|
|
|
auto itKey = itSection->second.find(keyLower); |
|
if(itKey == itSection->second.end()) return empty; |
|
|
|
return itKey->second; |
|
} |
|
|
|
bool Config::LoadFile(const std::string &filename) { |
|
std::string section = global; |
|
|
|
std::ifstream file; |
|
file.open(filename); |
|
|
|
if(!file.is_open()) return false; |
|
|
|
std::string line; |
|
int lineNum = 0; |
|
while(std::getline(file, line)) { |
|
line = Trim(line); |
|
++lineNum; |
|
|
|
if(line.empty()) continue; |
|
|
|
// Comment. |
|
if(line.front() == '#') continue; |
|
|
|
if(line.front() == '[' && line.back() == ']') { |
|
// Section |
|
line.erase(line.begin()); |
|
line.erase(line.end() - 1); |
|
section = Trim(line); |
|
continue; |
|
} |
|
|
|
// Everything else. :) |
|
auto equals = line.find('=', 0); |
|
if(equals == std::string::npos) { |
|
std::cerr << filename << ": no value specified on line " << lineNum << std::endl; |
|
continue; |
|
} |
|
|
|
auto key = Trim(line.substr(0, equals)); |
|
auto value = Trim(line.substr(equals + 1, std::string::npos)); |
|
SetValue(section, key, value); |
|
} |
|
|
|
file.close(); |
|
return true; |
|
} |
|
|
|
void Config::SetValue(const std::string &key, const std::string &value) { |
|
SetValue(global, key, value); |
|
} |
|
|
|
void Config::SetValue(const std::string §ion, const std::string &key, const std::string &value) { |
|
auto secLower = ToLower(section); |
|
auto keyLower = ToLower(key); |
|
|
|
auto itSection = m_section.find(secLower); |
|
if(itSection == m_section.end()) { |
|
// O.o |
|
auto newSection = std::pair<std::string, std::unordered_map<std::string, std::string>> |
|
(secLower, std::unordered_map<std::string, std::string>()); |
|
newSection.second.insert(std::pair<std::string, std::string>(keyLower, value)); |
|
m_section.insert(newSection); |
|
return; |
|
} |
|
|
|
auto itKey = itSection->second.find(keyLower); |
|
if(itKey == itSection->second.end()) { |
|
itSection->second.insert(std::pair<std::string, std::string>(keyLower, value)); |
|
return; |
|
} |
|
|
|
itKey->second = value; |
|
} |
|
}
|
|
|