42 } |
43 } |
43 |
44 |
44 }; |
45 }; |
45 |
46 |
46 std::vector<ConfiguredUnescapingProcessor> unescapingProcessors; |
47 std::vector<ConfiguredUnescapingProcessor> unescapingProcessors; |
|
48 |
|
49 class ConfiguredDialect { |
|
50 public: |
|
51 std::shared_ptr<Dialect> dialect; |
|
52 const std::string uri; |
|
53 |
|
54 ConfiguredDialect(std::shared_ptr<Dialect> dialect, const std::string uri) : dialect(dialect), uri(uri) { |
|
55 } |
|
56 |
|
57 }; |
|
58 |
|
59 std::vector<ConfiguredDialect> dialects; |
47 |
60 |
48 /** |
61 /** |
49 * By default, we ignore all leading whitespace on continuing lines. |
62 * By default, we ignore all leading whitespace on continuing lines. |
50 * If there should be some spaces or tabs, they should be placed on the previous line before the „\“. |
63 * If there should be some spaces or tabs, they should be placed on the previous line before the „\“. |
51 * If a line break is desired, it should be written as \n (escaped) or the value should be quoted in " or '. |
64 * If a line break is desired, it should be written as \n (escaped) or the value should be quoted in " or '. |
268 if (value == "true") return true; |
281 if (value == "true") return true; |
269 else if (value == "false") return false; |
282 else if (value == "false") return false; |
270 else throw std::invalid_argument(std::string("Unable to parse boolean value: ") + value + " (expecting true or false)"); |
283 else throw std::invalid_argument(std::string("Unable to parse boolean value: ") + value + " (expecting true or false)"); |
271 } |
284 } |
272 |
285 |
273 void setDialect(const std::string& name) { |
286 void setDialect(const std::string& uri) { |
274 if (name == "default-ini") { |
287 for (ConfiguredDialect& d : dialects) { |
275 // already set |
288 if (d.uri == uri) { |
276 } else if (name == "java-properties") { |
289 d.dialect->apply(*this); |
277 trimLeadingSpacesOnContinuingLines = true; |
290 return; |
278 allowSections = false; |
291 } |
279 allowSectionTags = false; |
292 } |
280 allowSubKeys = false; |
293 throw std::invalid_argument(std::string("Unsupported INI dialect: ") + uri); |
281 commentSeparators = "#"; |
|
282 keyValueSeparators = "=:"; |
|
283 quotes = ""; |
|
284 // TODO: enable unicode unescaping |
|
285 } else { |
|
286 throw std::invalid_argument(std::string("Unsupported INI dialect: ") + name); |
|
287 } |
|
288 } |
294 } |
289 |
295 |
290 bool setUnescaping(const std::string& uri, const std::string& value) { |
296 bool setUnescaping(const std::string& uri, const std::string& value) { |
291 for (ConfiguredUnescapingProcessor& p : unescapingProcessors) { |
297 for (ConfiguredUnescapingProcessor& p : unescapingProcessors) { |
292 if (p.uri == uri) { |
298 if (p.uri == uri) { |
301 |
307 |
302 INIReaderImpl(std::istream& input) : input(input) { |
308 INIReaderImpl(std::istream& input) : input(input) { |
303 } |
309 } |
304 |
310 |
305 void setOption(const std::string& uri, const std::string& value) override { |
311 void setOption(const std::string& uri, const std::string& value) override { |
306 if (uri == "trim-continuing-lines") trimLeadingSpacesOnContinuingLines = parseBoolean(value); // TODO: continuing lines modes (enum), not just boolean |
312 if (uri == option::TrimContinuingLines) trimLeadingSpacesOnContinuingLines = parseBoolean(value); // TODO: continuing lines modes (enum), not just boolean |
307 else if (uri == "allow-sections") allowSections = parseBoolean(value); |
313 else if (uri == option::AllowSections) allowSections = parseBoolean(value); |
308 else if (uri == "allow-section-tags") allowSectionTags = parseBoolean(value); |
314 else if (uri == option::AllowSectionTags) allowSectionTags = parseBoolean(value); |
309 else if (uri == "allow-sub-keys") allowSubKeys = parseBoolean(value); |
315 else if (uri == option::AllowSubKeys) allowSubKeys = parseBoolean(value); |
310 else if (uri == "comment-separators") commentSeparators = value; |
316 else if (uri == option::CommentSeparators) commentSeparators = value; |
311 else if (uri == "key-value-separators") keyValueSeparators = value; |
317 else if (uri == option::KeyValueSeparators) keyValueSeparators = value; |
312 else if (uri == "quotes") quotes = value; |
318 else if (uri == option::Quotes) quotes = value; |
313 else if (uri == "dialect") setDialect(value); |
319 else if (uri == option::Dialect) setDialect(value); |
314 else if (setUnescaping(uri, value)); |
320 else if (setUnescaping(uri, value)); |
315 else throw std::invalid_argument(std::string("Invalid parser option: „") + uri + "“ with value: „" + value + "“"); |
321 else throw std::invalid_argument(std::string("Invalid parser option: „") + uri + "“ with value: „" + value + "“"); |
316 } |
322 } |
317 |
323 |
318 void addHandler(INIContentHandler* handler) override { |
324 void addHandler(INIContentHandler* handler) override { |
319 handlers.push_back(handler); |
325 handlers.push_back(handler); |
320 } |
326 } |
321 |
327 |
322 void addUnescapingProcessor(std::shared_ptr<UnescapingProcessor> processor, const std::string uri, bool enabledByDefault) override { |
328 void addUnescapingProcessor(std::shared_ptr<UnescapingProcessor> processor, const std::string uri, bool enabledByDefault) override { |
323 unescapingProcessors.push_back({processor, uri, enabledByDefault}); |
329 unescapingProcessors.push_back({processor, uri, enabledByDefault}); |
|
330 } |
|
331 |
|
332 void addDialect(std::shared_ptr<Dialect> dialect, const std::string uri, bool enabledByDefault) override { |
|
333 dialects.push_back({dialect, uri}); |
|
334 if (enabledByDefault) dialect->apply(*this); |
324 } |
335 } |
325 |
336 |
326 void process() override { |
337 void process() override { |
327 for (INIContentHandler* handler : handlers) handler->startDocument(); |
338 for (INIContentHandler* handler : handlers) handler->startDocument(); |
328 |
339 |