cpp-utilities/io/inifile.cpp

167 lines
4.6 KiB
C++
Raw Normal View History

2015-09-06 20:19:09 +02:00
#include "./inifile.h"
2016-06-14 22:53:19 +02:00
#include "./catchiofailure.h"
2015-07-07 00:50:49 +02:00
#include <iostream>
using namespace std;
namespace IoUtilities {
/*!
* \class IniFile
* \brief The IniFile class parses and makes INI files.
*/
2015-07-07 00:50:49 +02:00
/*!
* \brief Parses all data from the specified \a inputStream.
*/
void IniFile::parse(std::istream &inputStream)
{
// define variable for state machine
2017-05-01 03:13:11 +02:00
enum State { Init, Comment, ScopeName, Key, Value } state = Init;
2015-07-07 00:50:49 +02:00
// 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
2016-01-27 02:17:06 +01:00
const auto finishKeyValue = [&state, &scope, &key, &value, &whitespace, this] {
2017-05-01 03:13:11 +02:00
if (key.empty() && value.empty() && state != Value) {
2016-01-27 02:17:06 +01:00
return;
}
2017-05-01 03:13:11 +02:00
if (m_data.empty() || m_data.back().first != scope) {
m_data.emplace_back(make_pair(scope, decltype(m_data)::value_type::second_type()));
}
m_data.back().second.insert(make_pair(key, value));
2015-07-07 00:50:49 +02:00
key.clear();
value.clear();
whitespace = 0;
};
// called to add current character to current key or value
2017-05-01 03:13:11 +02:00
const auto addChar = [&whitespace, &c](string &to) {
if (c == ' ') {
2015-07-07 00:50:49 +02:00
++whitespace;
} else {
2017-05-01 03:13:11 +02:00
if (!to.empty()) {
while (whitespace) {
2015-07-07 00:50:49 +02:00
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 {
2017-05-01 03:13:11 +02:00
while (inputStream.get(c)) {
switch (state) {
2015-07-07 00:50:49 +02:00
case Init:
2017-05-01 03:13:11 +02:00
switch (c) {
2015-07-07 00:50:49 +02:00
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:
2017-05-01 03:13:11 +02:00
switch (c) {
2015-07-07 00:50:49 +02:00
case '\n':
finishKeyValue();
state = Init;
break;
case '#':
finishKeyValue();
state = Comment;
break;
case '=':
whitespace = 0;
state = Value;
break;
default:
addChar(key);
}
break;
case Comment:
2017-05-01 03:13:11 +02:00
switch (c) {
2015-07-07 00:50:49 +02:00
case '\n':
state = Init;
break;
2017-05-01 03:13:11 +02:00
default:;
2015-07-07 00:50:49 +02:00
}
break;
case ScopeName:
2017-05-01 03:13:11 +02:00
switch (c) {
2015-07-07 00:50:49 +02:00
case ']':
state = Init;
break;
default:
scope += c;
}
break;
case Value:
2017-05-01 03:13:11 +02:00
switch (c) {
2015-07-07 00:50:49 +02:00
case '\n':
finishKeyValue();
state = Init;
break;
case '#':
finishKeyValue();
state = Comment;
break;
default:
addChar(value);
}
break;
}
}
2017-05-01 03:13:11 +02:00
} catch (...) {
2016-06-14 22:53:19 +02:00
const char *what = catchIoFailure();
2017-05-01 03:13:11 +02:00
if (inputStream.eof()) {
2015-07-07 00:50:49 +02:00
// we just reached the end of the file
// don't forget to save the last key/value pair
finishKeyValue();
} else {
2016-06-14 22:53:19 +02:00
throwIoFailure(what);
2015-07-07 00:50:49 +02:00
}
}
}
/*!
* \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);
2017-05-01 03:13:11 +02:00
for (const auto &scope : m_data) {
2015-07-07 00:50:49 +02:00
outputStream << '[' << scope.first << ']' << '\n';
2017-05-01 03:13:11 +02:00
for (const auto &field : scope.second) {
2015-07-07 00:50:49 +02:00
outputStream << field.first << '=' << field.second << '\n';
}
outputStream << '\n';
}
}
} // namespace IoUtilities