implement --writer-option allow-sections false (flat key=value output) v_0
authorFrantišek Kučera <franta-hg@frantovo.cz>
Sat, 12 Dec 2020 19:52:38 +0100
branchv_0
changeset 5 bee7acb57330
parent 4 372b161669e4
child 6 a823b1aaf1f6
implement --writer-option allow-sections false (flat key=value output)
bash-completion.sh
src/INIDispatchHandler.h
src/INIWriter.h
src/JavaManifestMFDialect.h
src/JavaPropertiesDialect.h
src/uri.h
--- a/bash-completion.sh	Sat Dec 12 14:42:36 2020 +0100
+++ b/bash-completion.sh	Sat Dec 12 19:52:38 2020 +0100
@@ -61,6 +61,8 @@
 		"quotes-pattern-for-sections"
 		"quotes-pattern-for-keys"
 		"quotes-pattern-for-values"
+		"allow-sections"
+		"hierarchy-separator"
 	);
 
 
@@ -78,6 +80,8 @@
 	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" && "$w1" == "allow-sections"                           ]];    then COMPREPLY=($(compgen -W "${BOOLEAN_VALUES[*]}" -- "$w0"))
+	elif [[ "$w2" == "--writer-option" && "$w1" == "hierarchy-separator"                      ]];    then COMPREPLY=("'/'")
 	elif [[ "$w2" == "--writer-option"                                       && "x$w0" == "x" ]];    then COMPREPLY=("''")
 
 	else
--- a/src/INIDispatchHandler.h	Sat Dec 12 14:42:36 2020 +0100
+++ b/src/INIDispatchHandler.h	Sat Dec 12 19:52:38 2020 +0100
@@ -105,6 +105,7 @@
 	void endOfPipe() {
 		if (currentHandler) currentHandler->endOfPipe();
 		currentHandler.reset();
+		writer.endDocument();
 		output.flush();
 	}
 
--- a/src/INIWriter.h	Sat Dec 12 14:42:36 2020 +0100
+++ b/src/INIWriter.h	Sat Dec 12 19:52:38 2020 +0100
@@ -41,8 +41,26 @@
 	std::string commentSeparatorForEntries = " ; ";
 	std::string commentSeparatorStandalone = "; ";
 
+	relpipe::common::type::StringX hierarchySeparator = L"/";
+	bool allowSections = true;
+
 	bool hasContent = false;
 
+	std::vector<relpipe::common::type::StringX> currentSection;
+
+	relpipe::common::type::StringX getCurrentSectionFullName() {
+		std::wstringstream result;
+
+		// TODO: configurable hierarchy delimiter
+		// TODO: escape delimiter characters that are part of the section names
+		for (int i = 0; i < currentSection.size(); i++) {
+			if (i > 0)result << hierarchySeparator;
+			result << currentSection[i];
+		}
+
+		return result.str();
+	}
+
 	/**
 	 * TODO: use a common method
 	 */
@@ -176,7 +194,8 @@
 		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); // TODO: allow sections
+		else if (uri == option::HierarchySeparator) hierarchySeparator = value;
+		else if (uri == option::AllowSections) allowSections = parseBoolean(value);
 		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);
@@ -200,23 +219,32 @@
 	}
 
 	void endDocument() {
+		if (currentSection.size()) throw relpipe::reader::RelpipeReaderException(L"There are still " + std::to_wstring(currentSection.size()) + L" open sections during the endDocument() call. Need to call endSection() before.");
 		output.flush();
 	}
 
 	void startSection(const SectionStartEvent& event) {
-		if (hasContent) output << std::endl;
-		output << "[" << escape(event.name, EscapingProcessor::TextType::SectionName) << "]";
-		if (event.tag.size()) output << "[" << escape(event.tag, EscapingProcessor::TextType::SectionTag) << "]";
-		if (event.comment.size()) output << commentSeparatorForSections << escape(event.comment, EscapingProcessor::TextType::SectionComment);
-		output << std::endl;
+		currentSection.push_back(event.name);
+
+		if (allowSections) {
+			if (hasContent) output << std::endl;
+			output << "[" << escape(getCurrentSectionFullName(), EscapingProcessor::TextType::SectionName) << "]";
+			if (event.tag.size()) output << "[" << escape(event.tag, EscapingProcessor::TextType::SectionTag) << "]";
+			if (event.comment.size()) output << commentSeparatorForSections << escape(event.comment, EscapingProcessor::TextType::SectionComment);
+			output << std::endl;
+		}
+
 		hasContent = true;
 	}
 
 	void endSection() {
+		currentSection.pop_back();
 		output.flush();
 	}
 
 	void entry(const EntryEvent& event) {
+		// TODO: escape/quote parts separately + configurable quoting of parts or whole + the same for sub keys
+		if (!allowSections && currentSection.size()) output << escape(getCurrentSectionFullName(), EscapingProcessor::TextType::EntryKey) << convertor.to_bytes(hierarchySeparator);
 		output << escape(event.key, EscapingProcessor::TextType::EntryKey);
 		if (event.subKey.size()) output << "[" << escape(event.subKey, EscapingProcessor::TextType::EntrySubKey) << "]";
 		output << keyValueSeparator << escape(event.value, EscapingProcessor::TextType::EntryValue);
--- a/src/JavaManifestMFDialect.h	Sat Dec 12 14:42:36 2020 +0100
+++ b/src/JavaManifestMFDialect.h	Sat Dec 12 19:52:38 2020 +0100
@@ -31,6 +31,7 @@
 	void apply(INIWriter& writer) override {
 		writer.setOption(option::Dialect, dialect::JavaProperties);
 		writer.setOption(option::KeyValueSeparator, L": ");
+		writer.setOption(option::HierarchySeparator, L"-");
 	}
 
 };
--- a/src/JavaPropertiesDialect.h	Sat Dec 12 14:42:36 2020 +0100
+++ b/src/JavaPropertiesDialect.h	Sat Dec 12 19:52:38 2020 +0100
@@ -30,6 +30,7 @@
 
 	void apply(INIWriter& writer) override {
 		writer.setOption(option::AllowSections, L"false");
+		writer.setOption(option::HierarchySeparator, L".");
 		writer.setOption(option::QuotesTypeForSections, quoting::None);
 		writer.setOption(option::QuotesTypeForKeys, quoting::None);
 		writer.setOption(option::QuotesTypeForValues, quoting::None);
@@ -37,7 +38,7 @@
 		writer.setOption(option::CommentSeparatorForSections, L"");
 		writer.setOption(option::CommentSeparatorForEntries, L"");
 		writer.setOption(option::CommentSeparatorStandalone, L"# ");
-		// writer.setOption(escaping::Basic, L"false"); // TODO: basic vs. .properties
+		writer.setOption(escaping::Basic, L"false");
 		writer.setOption(escaping::JavaProperties, L"true");
 	}
 
--- a/src/uri.h	Sat Dec 12 14:42:36 2020 +0100
+++ b/src/uri.h	Sat Dec 12 19:52:38 2020 +0100
@@ -24,7 +24,9 @@
 
 /** general options of the INI writer */
 namespace option {
+// TODO: „allow sections“ vs. „enable sections“, see also relpipe-in-ini
 static const wchar_t* AllowSections = L"allow-sections";
+static const wchar_t* HierarchySeparator = L"hierarchy-separator";
 // static const wchar_t* AllowSectionTags = L"allow-section-tags";
 // static const wchar_t* AllowSubKeys = L"allow-sub-keys";
 static const wchar_t* CommentSeparatorForSections = L"comment-separator-for-sections";