diff -r 29d673a54ecf -r b497140b0b63 src/lib/INIReader.cpp --- a/src/lib/INIReader.cpp Thu Nov 26 18:52:49 2020 +0100 +++ b/src/lib/INIReader.cpp Fri Nov 27 16:29:12 2020 +0100 @@ -33,8 +33,6 @@ std::vector handlers; /** - * This might be configurable. - * * By default, we ignore all leading whitespace on continuing lines. * If there should be some spaces or tabs, they should be placed on the previous line before the „\“. * If a line break is desired, it should be written as \n (escaped) or the value should be quoted in " or '. @@ -42,11 +40,9 @@ * Related specifications: * - https://docs.oracle.com/javase/8/docs/api/index.html?java/util/Properties.html */ - bool consumeLeadingSpacesOnContinuingLines = true; + bool trimLeadingSpacesOnContinuingLines = true; /** - * This might be configurable. - * * KDE uses some weird INI dialect that allows [section][x] syntax where „x“ is kind of „tag“ that signalizes some properties of given section. * Line „[section_1][$i]“ means that the „section_1“ is „locked“. * We may emit this information somehow later, but for now, it is just ignored. @@ -59,8 +55,6 @@ bool allowSectionTags = true; /** - * This might be configurable. - * * If whole key is „aaa[bbb]“ then „aaa“ is considered to be the key and „bbb“ the sub-key. * No \[ escaping is currently supported, so the key might not contain the bracket character. * @@ -71,8 +65,6 @@ bool allowSubKeys = true; /** - * This might be configurable. - * * Classic INI uses „key=value“ syntax. * But some other formats/dialects might use key:value. * @@ -83,8 +75,6 @@ std::string keyValueSeparators = "="; /** - * This might be configurable. - * * Classic INI uses „; comment“ syntax. * But many existing files contain „# comment“ lines. * @@ -93,8 +83,6 @@ std::string commentSeparators = ";#"; /** - * This might be configurable. - * * INI often support both "quotes" and 'apostrophes' styles. * But some dialects may support only one of them or not support quoting at all. * @@ -146,7 +134,7 @@ } void processContinuingLine(std::stringstream& result) { - if (consumeLeadingSpacesOnContinuingLines) readSpacesAndTabs(); + if (trimLeadingSpacesOnContinuingLines) readSpacesAndTabs(); else result.put('\n'); } @@ -237,11 +225,49 @@ return std::regex_replace(s, std::regex("^\\s+|\\s+$"), ""); } + /** + * TODO: use a common method + */ + bool parseBoolean(const std::string& value) { + if (value == "true") return true; + else if (value == "false") return false; + else throw std::invalid_argument(std::string("Unable to parse boolean value: ") + value + " (expecting true or false)"); + } + + void setDialect(const std::string& name) { + if (name == "default-ini") { + // already set + } else if (name == "java-properties") { + trimLeadingSpacesOnContinuingLines = true; + allowSectionTags = false; + allowSubKeys = false; + commentSeparators = "#"; + keyValueSeparators = "=:"; + quotes = ""; + // TODO: allowSections = false; + // TODO: enable unicode unescaping + } else { + throw std::invalid_argument(std::string("Unsupported INI dialect: ") + name); + } + } + public: INIReaderImpl(std::istream& input) : input(input) { } + void setOption(const std::string& uri, const std::string& value) override { + if (uri == "trim-continuing-lines") trimLeadingSpacesOnContinuingLines = parseBoolean(value); // TODO: continuing lines modes (enum), not just boolean + // TODO: else if (uri == "allow-sections") allowSections = parseBoolean(value); + else if (uri == "allow-section-tags") allowSectionTags = parseBoolean(value); + else if (uri == "allow-sub-keys") allowSubKeys = parseBoolean(value); + else if (uri == "comment-separators") commentSeparators = value; + else if (uri == "key-value-separators") keyValueSeparators = value; + else if (uri == "quotes") quotes = value; + else if (uri == "dialect") setDialect(value); + else throw std::invalid_argument(std::string("Invalid parser option: „") + uri + "“ with value: „" + value + "“"); + } + void addHandler(INIContentHandler* handler) override { handlers.push_back(handler); }