added INI parser
This commit is contained in:
parent
f396b8afa1
commit
f462d71200
|
@ -29,7 +29,8 @@ SOURCES += \
|
||||||
io/ansiescapecodes.cpp \
|
io/ansiescapecodes.cpp \
|
||||||
misc/random.cpp \
|
misc/random.cpp \
|
||||||
io/bitreader.cpp \
|
io/bitreader.cpp \
|
||||||
application/commandlineutils.cpp
|
application/commandlineutils.cpp \
|
||||||
|
io/inifile.cpp
|
||||||
|
|
||||||
HEADERS += \
|
HEADERS += \
|
||||||
application/global.h \
|
application/global.h \
|
||||||
|
@ -54,7 +55,8 @@ HEADERS += \
|
||||||
misc/memory.h \
|
misc/memory.h \
|
||||||
misc/random.h \
|
misc/random.h \
|
||||||
io/bitreader.h \
|
io/bitreader.h \
|
||||||
application/commandlineutils.h
|
application/commandlineutils.h \
|
||||||
|
io/inifile.h
|
||||||
|
|
||||||
OTHER_FILES += \
|
OTHER_FILES += \
|
||||||
README.md \
|
README.md \
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
Loading…
Reference in New Issue