diff -r ae8775e0bc7a -r 372b161669e4 src/INIWriter.h --- a/src/INIWriter.h Sat Dec 12 00:01:57 2020 +0100 +++ b/src/INIWriter.h Sat Dec 12 14:42:36 2020 +0100 @@ -18,6 +18,7 @@ #include #include +#include #include #include @@ -51,10 +52,43 @@ else throw relpipe::reader::RelpipeReaderException(L"Unable to parse boolean value: " + value + L" (expecting true or false)"); } + EscapingProcessor::QuotingType parseQuotingType(const relpipe::common::type::StringX& value) { + if (value == quoting::None) return EscapingProcessor::QuotingType::None; + else if (value == quoting::Apostrophes) return EscapingProcessor::QuotingType::Apostrophes; + else if (value == quoting::Quotes) return EscapingProcessor::QuotingType::Quotes; + else throw relpipe::reader::RelpipeReaderException(L"Unsupported quoting type:" + value); + } + + class QuotingRule { + public: + EscapingProcessor::QuotingType type = EscapingProcessor::QuotingType::None; + relpipe::common::type::StringX pattern; + + EscapingProcessor::QuotingType findEffectiveQuotingType(const relpipe::common::type::StringX& value) { + if (type == EscapingProcessor::QuotingType::None) return type; + else if (pattern.empty()) return type; + else return std::regex_match(value, std::wregex(pattern)) ? type : EscapingProcessor::QuotingType::None; + } + }; + + QuotingRule quotingForSections; + QuotingRule quotingForKeys; + QuotingRule quotingForValues; + std::string escape(const relpipe::common::type::StringX& value, EscapingProcessor::TextType type) { relpipe::common::type::StringX result = value; - EscapingProcessor::QuotingType quotingType = EscapingProcessor::QuotingType::None; + + EscapingProcessor::QuotingType quotingType; + if (type == EscapingProcessor::TextType::SectionName || type == EscapingProcessor::TextType::SectionTag) quotingType = quotingForSections.findEffectiveQuotingType(value); + else if (type == EscapingProcessor::TextType::EntryKey || type == EscapingProcessor::TextType::EntrySubKey) quotingType = quotingForKeys.findEffectiveQuotingType(value); + else if (type == EscapingProcessor::TextType::EntryValue) quotingType = quotingForValues.findEffectiveQuotingType(value); + else quotingType = EscapingProcessor::QuotingType::None; + for (ConfiguredEscapingProcessor p : escapingProcessors) if (p.enbaled) result = p.processor->escape(result, type, quotingType); + + if (quotingType == EscapingProcessor::QuotingType::Quotes) result = L"\"" + result + L"\""; + else if (quotingType == EscapingProcessor::QuotingType::Apostrophes) result = L"'" + result + L"'"; + return convertor.to_bytes(result); } @@ -137,14 +171,18 @@ }; void setOption(relpipe::common::type::StringX uri, relpipe::common::type::StringX value) { - // TODO: setOption(): escaping, quotes, allow-sections if (uri == option::Dialect) setDialect(value); else if (uri == option::CommentSeparatorForSections) commentSeparatorForSections = convertor.to_bytes(value); else if (uri == option::CommentSeparatorForEntries) commentSeparatorForEntries = convertor.to_bytes(value); else if (uri == option::CommentSeparatorStandalone) commentSeparatorStandalone = convertor.to_bytes(value); else if (uri == option::KeyValueSeparator) keyValueSeparator = convertor.to_bytes(value); - else if (uri == option::AllowSections); - else if (uri == option::Quotes); + else if (uri == option::AllowSections); // TODO: allow sections + else if (uri == option::QuotesTypeForSections) quotingForSections.type = parseQuotingType(value); + else if (uri == option::QuotesTypeForKeys) quotingForKeys.type = parseQuotingType(value); + else if (uri == option::QuotesTypeForValues) quotingForValues.type = parseQuotingType(value); + else if (uri == option::QuotesPatternForSections) quotingForSections.pattern = value; + else if (uri == option::QuotesPatternForKeys) quotingForKeys.pattern = value; + else if (uri == option::QuotesPatternForValues) quotingForValues.pattern = value; else if (setEscaping(uri, value)); else throw relpipe::reader::RelpipeReaderException(L"Unsupported writer option: " + uri); }