--- a/src/lib/INIReader.cpp Thu Nov 26 17:08:49 2020 +0100
+++ b/src/lib/INIReader.cpp Thu Nov 26 18:28:27 2020 +0100
@@ -70,6 +70,18 @@
*/
bool allowSubKeys = true;
+ /**
+ * This might be configurable.
+ *
+ * Classic INI uses „key=value“ syntax.
+ * But some other formats/dialects might use key:value.
+ *
+ * Only single character separators are supported.
+ * If multiple separators should be recognized (e.g. both „=“ and „:“), this string will contain all of them,
+ * i.e. „:=“ does not mean that the „key:=value“ syntax, but „key=value“ or „key:value“.
+ */
+ std::string keyValueSeparators = "=";
+
int lineNumber = 1;
int eventNumber = 0;
@@ -115,26 +127,31 @@
else result.put('\n');
}
- std::string readUntil(char until, bool* found = nullptr) {
+ std::string readUntil(const char until, bool* found = nullptr) {
+ return readUntil(std::string(1, until), found);
+ }
+
+ std::string readUntil(const std::string& until, bool* found = nullptr) {
std::stringstream result;
- for (char ch = peek(); input.good() && ch != until; ch = peek()) {
+ for (char ch = peek(); input.good() && !oneOf(ch, until); ch = peek()) {
if (ch == '\\') {
get();
ch = get();
- if (ch == until && ch == '\n') processContinuingLine(result);
- else if (ch == until) result.put(ch);
+ if (oneOf(ch, until) && ch == '\n') processContinuingLine(result);
+ else if (oneOf(ch, until)) result.put(ch);
else if (ch == std::istream::traits_type::eof()) break;
else result.put('\\').put(ch);
- // TODO: two-stage and modular unescaping: here unescape only \+LF or more genereally: unescape only the until character and rest leave untouched
- // second escaping stage move to separate class/wrapper (similar to hierarchical wrappers)
+ // unescaping is done in two phases:
+ // here we unescape just the \n (LF)
+ // other escape sequences are leaved untouched and will be processed in later phases, see see UnescapingINIHandler
} else {
ch = get();
result.put(ch);
}
}
- if (peek() == until) {
+ if (oneOf(peek(), until)) {
get();
if (found) *found = true;
} else {
@@ -144,13 +161,17 @@
return result.str();
}
- std::string readToken(char until, char* quote = nullptr, bool* found = nullptr) {
+ std::string readToken(const char until, char* quote = nullptr, bool* found = nullptr) {
+ return readToken(std::string(1, until), quote, found);
+ }
+
+ std::string readToken(const std::string& until, char* quote = nullptr, bool* found = nullptr) {
std::string result;
char ch = peek();
if (isQuote(ch)) {
if (quote) *quote = ch;
- result = readUntil(get(), found);
+ result = readUntil(std::string(1, get()), found);
} else {
if (quote) *quote = 0;
result = readUntil(until, found);
@@ -160,10 +181,14 @@
}
std::string readTokenAndEatTerminator(char until, char* quote = nullptr, bool* found = nullptr) {
+ return readTokenAndEatTerminator(std::string(1, until), quote, found);
+ }
+
+ std::string readTokenAndEatTerminator(const std::string& until, char* quote = nullptr, bool* found = nullptr) {
std::string result = readToken(until, quote, found);
if (*quote) {
readAllWhitespace();
- if (get() != until) throw std::logic_error(std::string("missing „") + std::string(1, until) + "“ after quoted section name");
+ if (!oneOf(get(), until)) throw std::logic_error(std::string("missing „") + until + "“ after quoted section name");
}
return result;
}
@@ -176,6 +201,15 @@
return ch == '"' || ch == '\'';
}
+ /**
+ * @param ch character to be evaluated
+ * @param options list of options (characters)
+ * @return whether ch is one of options
+ */
+ bool oneOf(char ch, const std::string& options) {
+ return options.find(ch) != std::string::npos;
+ }
+
std::string trim(std::string s) {
return std::regex_replace(s, std::regex("^\\s+|\\s+$"), "");
}
@@ -255,14 +289,14 @@
event.lineNumber = lineNumber;
event.eventNumber = ++eventNumber;
- std::string fullKey = readToken('=', "e, &found);
+ std::string fullKey = readToken(keyValueSeparators, "e, &found);
if (!found) throw std::logic_error(std::string("missing = after key: '") + fullKey + "'");
if (!quote) fullKey = trim(fullKey);
readSpacesAndTabs();
if (quote) {
ch = get();
- if (ch == '=') readSpacesAndTabs();
+ if (oneOf(ch, keyValueSeparators)) readSpacesAndTabs();
else throw std::logic_error(std::string("missing = after quoted key: '") + fullKey + "'");
}