113 void processContinuingLine(std::stringstream& result) { |
125 void processContinuingLine(std::stringstream& result) { |
114 if (consumeLeadingSpacesOnContinuingLines) readSpacesAndTabs(); |
126 if (consumeLeadingSpacesOnContinuingLines) readSpacesAndTabs(); |
115 else result.put('\n'); |
127 else result.put('\n'); |
116 } |
128 } |
117 |
129 |
118 std::string readUntil(char until, bool* found = nullptr) { |
130 std::string readUntil(const char until, bool* found = nullptr) { |
|
131 return readUntil(std::string(1, until), found); |
|
132 } |
|
133 |
|
134 std::string readUntil(const std::string& until, bool* found = nullptr) { |
119 std::stringstream result; |
135 std::stringstream result; |
120 |
136 |
121 for (char ch = peek(); input.good() && ch != until; ch = peek()) { |
137 for (char ch = peek(); input.good() && !oneOf(ch, until); ch = peek()) { |
122 if (ch == '\\') { |
138 if (ch == '\\') { |
123 get(); |
139 get(); |
124 ch = get(); |
140 ch = get(); |
125 if (ch == until && ch == '\n') processContinuingLine(result); |
141 if (oneOf(ch, until) && ch == '\n') processContinuingLine(result); |
126 else if (ch == until) result.put(ch); |
142 else if (oneOf(ch, until)) result.put(ch); |
127 else if (ch == std::istream::traits_type::eof()) break; |
143 else if (ch == std::istream::traits_type::eof()) break; |
128 else result.put('\\').put(ch); |
144 else result.put('\\').put(ch); |
129 // TODO: two-stage and modular unescaping: here unescape only \+LF or more genereally: unescape only the until character and rest leave untouched |
145 // unescaping is done in two phases: |
130 // second escaping stage move to separate class/wrapper (similar to hierarchical wrappers) |
146 // here we unescape just the \n (LF) |
|
147 // other escape sequences are leaved untouched and will be processed in later phases, see see UnescapingINIHandler |
131 } else { |
148 } else { |
132 ch = get(); |
149 ch = get(); |
133 result.put(ch); |
150 result.put(ch); |
134 } |
151 } |
135 } |
152 } |
136 |
153 |
137 if (peek() == until) { |
154 if (oneOf(peek(), until)) { |
138 get(); |
155 get(); |
139 if (found) *found = true; |
156 if (found) *found = true; |
140 } else { |
157 } else { |
141 if (found) *found = false; |
158 if (found) *found = false; |
142 } |
159 } |
143 |
160 |
144 return result.str(); |
161 return result.str(); |
145 } |
162 } |
146 |
163 |
147 std::string readToken(char until, char* quote = nullptr, bool* found = nullptr) { |
164 std::string readToken(const char until, char* quote = nullptr, bool* found = nullptr) { |
|
165 return readToken(std::string(1, until), quote, found); |
|
166 } |
|
167 |
|
168 std::string readToken(const std::string& until, char* quote = nullptr, bool* found = nullptr) { |
148 std::string result; |
169 std::string result; |
149 |
170 |
150 char ch = peek(); |
171 char ch = peek(); |
151 if (isQuote(ch)) { |
172 if (isQuote(ch)) { |
152 if (quote) *quote = ch; |
173 if (quote) *quote = ch; |
153 result = readUntil(get(), found); |
174 result = readUntil(std::string(1, get()), found); |
154 } else { |
175 } else { |
155 if (quote) *quote = 0; |
176 if (quote) *quote = 0; |
156 result = readUntil(until, found); |
177 result = readUntil(until, found); |
157 } |
178 } |
158 |
179 |
159 return result; |
180 return result; |
160 } |
181 } |
161 |
182 |
162 std::string readTokenAndEatTerminator(char until, char* quote = nullptr, bool* found = nullptr) { |
183 std::string readTokenAndEatTerminator(char until, char* quote = nullptr, bool* found = nullptr) { |
|
184 return readTokenAndEatTerminator(std::string(1, until), quote, found); |
|
185 } |
|
186 |
|
187 std::string readTokenAndEatTerminator(const std::string& until, char* quote = nullptr, bool* found = nullptr) { |
163 std::string result = readToken(until, quote, found); |
188 std::string result = readToken(until, quote, found); |
164 if (*quote) { |
189 if (*quote) { |
165 readAllWhitespace(); |
190 readAllWhitespace(); |
166 if (get() != until) throw std::logic_error(std::string("missing „") + std::string(1, until) + "“ after quoted section name"); |
191 if (!oneOf(get(), until)) throw std::logic_error(std::string("missing „") + until + "“ after quoted section name"); |
167 } |
192 } |
168 return result; |
193 return result; |
169 } |
194 } |
170 |
195 |
171 bool isComment(char ch) { |
196 bool isComment(char ch) { |
172 return ch == '#' || ch == ';'; |
197 return ch == '#' || ch == ';'; |
173 } |
198 } |
174 |
199 |
175 bool isQuote(char ch) { |
200 bool isQuote(char ch) { |
176 return ch == '"' || ch == '\''; |
201 return ch == '"' || ch == '\''; |
|
202 } |
|
203 |
|
204 /** |
|
205 * @param ch character to be evaluated |
|
206 * @param options list of options (characters) |
|
207 * @return whether ch is one of options |
|
208 */ |
|
209 bool oneOf(char ch, const std::string& options) { |
|
210 return options.find(ch) != std::string::npos; |
177 } |
211 } |
178 |
212 |
179 std::string trim(std::string s) { |
213 std::string trim(std::string s) { |
180 return std::regex_replace(s, std::regex("^\\s+|\\s+$"), ""); |
214 return std::regex_replace(s, std::regex("^\\s+|\\s+$"), ""); |
181 } |
215 } |
253 } else { |
287 } else { |
254 INIContentHandler::EntryEvent event; |
288 INIContentHandler::EntryEvent event; |
255 event.lineNumber = lineNumber; |
289 event.lineNumber = lineNumber; |
256 event.eventNumber = ++eventNumber; |
290 event.eventNumber = ++eventNumber; |
257 |
291 |
258 std::string fullKey = readToken('=', "e, &found); |
292 std::string fullKey = readToken(keyValueSeparators, "e, &found); |
259 if (!found) throw std::logic_error(std::string("missing = after key: '") + fullKey + "'"); |
293 if (!found) throw std::logic_error(std::string("missing = after key: '") + fullKey + "'"); |
260 if (!quote) fullKey = trim(fullKey); |
294 if (!quote) fullKey = trim(fullKey); |
261 readSpacesAndTabs(); |
295 readSpacesAndTabs(); |
262 |
296 |
263 if (quote) { |
297 if (quote) { |
264 ch = get(); |
298 ch = get(); |
265 if (ch == '=') readSpacesAndTabs(); |
299 if (oneOf(ch, keyValueSeparators)) readSpacesAndTabs(); |
266 else throw std::logic_error(std::string("missing = after quoted key: '") + fullKey + "'"); |
300 else throw std::logic_error(std::string("missing = after quoted key: '") + fullKey + "'"); |
267 } |
301 } |
268 |
302 |
269 std::string value = readToken('\n', "e, &found); |
303 std::string value = readToken('\n', "e, &found); |
270 if (!quote) value = trim(value); |
304 if (!quote) value = trim(value); |