configurable quoting v_0
authorFrantišek Kučera <franta-hg@frantovo.cz>
Sat, 12 Dec 2020 14:42:36 +0100
branchv_0
changeset 4 372b161669e4
parent 3 ae8775e0bc7a
child 5 bee7acb57330
configurable quoting
bash-completion.sh
src/BasicEscapingProcessor.h
src/INIWriter.h
src/JavaPropertiesDialect.h
src/uri.h
--- a/bash-completion.sh	Sat Dec 12 00:01:57 2020 +0100
+++ b/bash-completion.sh	Sat Dec 12 14:42:36 2020 +0100
@@ -40,6 +40,12 @@
 		"java-manifest-mf"
 	);
 
+	QUOTING_TYPES=(
+		"none"
+		"apostrophes"
+		"quotes"
+	)
+
 	WRITER_OPTIONS=(
 		"dialect"
 		"comment-separator-for-sections"
@@ -49,6 +55,12 @@
 		"escape-backspace"
 		"escape-basic"
 		"escape-java-properties"
+		"quotes-type-for-sections"
+		"quotes-type-for-keys"
+		"quotes-type-for-values"
+		"quotes-pattern-for-sections"
+		"quotes-pattern-for-keys"
+		"quotes-pattern-for-values"
 	);
 
 
@@ -63,6 +75,9 @@
 	elif [[ "$w2" == "--writer-option" && "$w1" == "escape-backspace"                         ]];    then COMPREPLY=($(compgen -W "${BOOLEAN_VALUES[*]}" -- "$w0"))
 	elif [[ "$w2" == "--writer-option" && "$w1" == "escape-basic"                             ]];    then COMPREPLY=($(compgen -W "${BOOLEAN_VALUES[*]}" -- "$w0"))
 	elif [[ "$w2" == "--writer-option" && "$w1" == "escape-java-properties"                   ]];    then COMPREPLY=($(compgen -W "${BOOLEAN_VALUES[*]}" -- "$w0"))
+	elif [[ "$w2" == "--writer-option" && "$w1" == "quotes-type-for-sections"                 ]];    then COMPREPLY=($(compgen -W "${QUOTING_TYPES[*]}" -- "$w0"))
+	elif [[ "$w2" == "--writer-option" && "$w1" == "quotes-type-for-keys"                     ]];    then COMPREPLY=($(compgen -W "${QUOTING_TYPES[*]}" -- "$w0"))
+	elif [[ "$w2" == "--writer-option" && "$w1" == "quotes-type-for-values"                   ]];    then COMPREPLY=($(compgen -W "${QUOTING_TYPES[*]}" -- "$w0"))
 	elif [[ "$w2" == "--writer-option"                                       && "x$w0" == "x" ]];    then COMPREPLY=("''")
 
 	else
--- a/src/BasicEscapingProcessor.h	Sat Dec 12 00:01:57 2020 +0100
+++ b/src/BasicEscapingProcessor.h	Sat Dec 12 14:42:36 2020 +0100
@@ -41,6 +41,7 @@
 			else if (ch == L'\t') result.put(ESC).put(L't');
 			else if (ch == L'"' && quotingType != QuotingType::Apostrophes) result.put(ESC).put(ch);
 			else if (ch == L'\'' && quotingType != QuotingType::Quotes) result.put(ESC).put(ch);
+			else if (ch == L'=' && quotingType == QuotingType::None) result.put(ESC).put(ch);
 			else result.put(ch);
 		}
 
--- 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 <string>
 #include <sstream>
+#include <regex>
 
 #include <relpipe/common/type/typedefs.h>
 #include <relpipe/reader/RelpipeReaderException.h>
@@ -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);
 	}
--- a/src/JavaPropertiesDialect.h	Sat Dec 12 00:01:57 2020 +0100
+++ b/src/JavaPropertiesDialect.h	Sat Dec 12 14:42:36 2020 +0100
@@ -30,7 +30,9 @@
 
 	void apply(INIWriter& writer) override {
 		writer.setOption(option::AllowSections, L"false");
-		writer.setOption(option::Quotes, L"");
+		writer.setOption(option::QuotesTypeForSections, quoting::None);
+		writer.setOption(option::QuotesTypeForKeys, quoting::None);
+		writer.setOption(option::QuotesTypeForValues, quoting::None);
 		writer.setOption(option::KeyValueSeparator, L"=");
 		writer.setOption(option::CommentSeparatorForSections, L"");
 		writer.setOption(option::CommentSeparatorForEntries, L"");
--- a/src/uri.h	Sat Dec 12 00:01:57 2020 +0100
+++ b/src/uri.h	Sat Dec 12 14:42:36 2020 +0100
@@ -31,7 +31,12 @@
 static const wchar_t* CommentSeparatorForEntries = L"comment-separator-for-entries";
 static const wchar_t* CommentSeparatorStandalone = L"comment-separator-standalone";
 static const wchar_t* KeyValueSeparator = L"key-value-separator";
-static const wchar_t* Quotes = L"quotes";
+static const wchar_t* QuotesTypeForSections = L"quotes-type-for-sections";
+static const wchar_t* QuotesTypeForKeys = L"quotes-type-for-keys";
+static const wchar_t* QuotesTypeForValues = L"quotes-type-for-values";
+static const wchar_t* QuotesPatternForSections = L"quotes-pattern-for-sections";
+static const wchar_t* QuotesPatternForKeys = L"quotes-pattern-for-keys";
+static const wchar_t* QuotesPatternForValues = L"quotes-pattern-for-values";
 static const wchar_t* Dialect = L"dialect";
 }
 
@@ -42,6 +47,13 @@
 static const wchar_t* Backspace = L"escape-backspace";
 }
 
+/** not options but a values of the quotes-type-for-* options */
+namespace quoting {
+static const wchar_t* None = L"none";
+static const wchar_t* Apostrophes = L"apostrophes";
+static const wchar_t* Quotes = L"quotes";
+}
+
 /** not options but a values of the dialect option */
 namespace dialect {
 static const wchar_t* JavaProperties = L"java-properties";