added INI parser

This commit is contained in:
Martchus 2015-07-07 00:50:49 +02:00
parent f396b8afa1
commit f462d71200
3 changed files with 214 additions and 2 deletions

View File

@ -29,7 +29,8 @@ SOURCES += \
io/ansiescapecodes.cpp \
misc/random.cpp \
io/bitreader.cpp \
application/commandlineutils.cpp
application/commandlineutils.cpp \
io/inifile.cpp
HEADERS += \
application/global.h \
@ -54,7 +55,8 @@ HEADERS += \
misc/memory.h \
misc/random.h \
io/bitreader.h \
application/commandlineutils.h
application/commandlineutils.h \
io/inifile.h
OTHER_FILES += \
README.md \

155
io/inifile.cpp Normal file
View File

@ -0,0 +1,155 @@
#include "inifile.h"
#include <iostream>
using namespace std;
namespace IoUtilities {
/*!
* \brief Parses all data from the specified \a inputStream.
*/
void IniFile::parse(std::istream &inputStream)
{
// define variable for state machine
enum State {Init, Comment, ScopeName, Key, Value} state = Init;
// current character
char c;
// number of postponed whitespaces
unsigned int whitespace = 0;
// current scope, key and value
string scope, key, value;
scope.reserve(16);
key.reserve(16);
value.reserve(256);
// define actions for state machine
// called when key/value pair is complete
auto finishKeyValue = [&scope, &key, &value, &whitespace, this] {
m_data[scope].insert(make_pair(key, value));
key.clear();
value.clear();
whitespace = 0;
};
// called to add current character to current key or value
auto addChar = [&whitespace, &c] (string &to) {
if(c == ' ') {
++whitespace;
} else {
if(!to.empty()) {
while(whitespace) {
to += ' ';
--whitespace;
}
} else {
whitespace = 0;
}
to += c;
}
};
// thorw an exception when an IO error occurs
inputStream.exceptions(ios_base::failbit | ios_base::badbit);
// parse the file char by char
try {
while(inputStream.get(c)) {
switch(state) {
case Init:
switch(c) {
case '\n':
break;
case '#':
state = Comment;
break;
case '=':
whitespace = 0;
state = Value;
break;
case '[':
scope.clear();
state = ScopeName;
break;
default:
addChar(key);
state = Key;
}
break;
case Key:
switch(c) {
case '\n':
finishKeyValue();
state = Init;
break;
case '#':
finishKeyValue();
state = Comment;
break;
case '=':
whitespace = 0;
state = Value;
break;
default:
addChar(key);
}
break;
case Comment:
switch(c) {
case '\n':
state = Init;
break;
default:
;
}
break;
case ScopeName:
switch(c) {
case ']':
state = Init;
break;
default:
scope += c;
}
break;
case Value:
switch(c) {
case '\n':
finishKeyValue();
state = Init;
break;
case '#':
finishKeyValue();
state = Comment;
break;
default:
addChar(value);
}
break;
}
}
} catch (const ios_base::failure &) {
if(inputStream.eof()) {
// we just reached the end of the file
// don't forget to save the last key/value pair
finishKeyValue();
} else {
throw;
}
}
}
/*!
* \brief Write the current data to the specified \a outputStream.
*/
void IniFile::make(ostream &outputStream)
{
// thorw an exception when an IO error occurs
outputStream.exceptions(ios_base::failbit | ios_base::badbit);
for(const auto &scope : m_data) {
outputStream << '[' << scope.first << ']' << '\n';
for(const auto &field : scope.second) {
outputStream << field.first << '=' << field.second << '\n';
}
outputStream << '\n';
}
}
} // namespace IoUtilities

55
io/inifile.h Normal file
View File

@ -0,0 +1,55 @@
#ifndef IOUTILITIES_INIFILE_H
#define IOUTILITIES_INIFILE_H
#include "../application/global.h"
#include <map>
namespace IoUtilities {
class LIB_EXPORT IniFile
{
public:
IniFile();
std::map<std::string, std::multimap<std::string, std::string> > &data();
const std::map<std::string, std::multimap<std::string, std::string> > &data() const;
void parse(std::istream &inputStream);
void make(std::ostream &outputStream);
private:
std::map<std::string, std::multimap<std::string, std::string> > m_data;
};
/*!
* \brief Constructs an empty ini file.
*/
inline IniFile::IniFile()
{}
/*!
* \brief Returns the data of the file.
*
* - The keys in the returned map represent the [scope name]s.
* - The values in the returned map are maps representing "key = value"-pairs within the scope.
* - The data might be modified an saved using the make() method.
*/
inline std::map<std::string, std::multimap<std::string, std::string> > &IniFile::data()
{
return m_data;
}
/*!
* \brief Returns the data of the file.
*
* - The keys in the returned map represent the [scope name]s.
* - The values in the returned map are maps representing "key = value"-pairs within the scope.
*/
inline const std::map<std::string, std::multimap<std::string, std::string> > &IniFile::data() const
{
return m_data;
}
} // namespace IoUtilities
#endif // IOUTILITIES_INIFILE_H