39 std::string keyValueSeparator = " = "; |
39 std::string keyValueSeparator = " = "; |
40 std::string commentSeparatorForSections = " ; "; |
40 std::string commentSeparatorForSections = " ; "; |
41 std::string commentSeparatorForEntries = " ; "; |
41 std::string commentSeparatorForEntries = " ; "; |
42 std::string commentSeparatorStandalone = "; "; |
42 std::string commentSeparatorStandalone = "; "; |
43 |
43 |
|
44 relpipe::common::type::StringX hierarchySeparator = L"/"; |
|
45 bool allowSections = true; |
|
46 |
44 bool hasContent = false; |
47 bool hasContent = false; |
|
48 |
|
49 std::vector<relpipe::common::type::StringX> currentSection; |
|
50 |
|
51 relpipe::common::type::StringX getCurrentSectionFullName() { |
|
52 std::wstringstream result; |
|
53 |
|
54 // TODO: configurable hierarchy delimiter |
|
55 // TODO: escape delimiter characters that are part of the section names |
|
56 for (int i = 0; i < currentSection.size(); i++) { |
|
57 if (i > 0)result << hierarchySeparator; |
|
58 result << currentSection[i]; |
|
59 } |
|
60 |
|
61 return result.str(); |
|
62 } |
45 |
63 |
46 /** |
64 /** |
47 * TODO: use a common method |
65 * TODO: use a common method |
48 */ |
66 */ |
49 bool parseBoolean(const relpipe::common::type::StringX& value) { |
67 bool parseBoolean(const relpipe::common::type::StringX& value) { |
174 if (uri == option::Dialect) setDialect(value); |
192 if (uri == option::Dialect) setDialect(value); |
175 else if (uri == option::CommentSeparatorForSections) commentSeparatorForSections = convertor.to_bytes(value); |
193 else if (uri == option::CommentSeparatorForSections) commentSeparatorForSections = convertor.to_bytes(value); |
176 else if (uri == option::CommentSeparatorForEntries) commentSeparatorForEntries = convertor.to_bytes(value); |
194 else if (uri == option::CommentSeparatorForEntries) commentSeparatorForEntries = convertor.to_bytes(value); |
177 else if (uri == option::CommentSeparatorStandalone) commentSeparatorStandalone = convertor.to_bytes(value); |
195 else if (uri == option::CommentSeparatorStandalone) commentSeparatorStandalone = convertor.to_bytes(value); |
178 else if (uri == option::KeyValueSeparator) keyValueSeparator = convertor.to_bytes(value); |
196 else if (uri == option::KeyValueSeparator) keyValueSeparator = convertor.to_bytes(value); |
179 else if (uri == option::AllowSections); // TODO: allow sections |
197 else if (uri == option::HierarchySeparator) hierarchySeparator = value; |
|
198 else if (uri == option::AllowSections) allowSections = parseBoolean(value); |
180 else if (uri == option::QuotesTypeForSections) quotingForSections.type = parseQuotingType(value); |
199 else if (uri == option::QuotesTypeForSections) quotingForSections.type = parseQuotingType(value); |
181 else if (uri == option::QuotesTypeForKeys) quotingForKeys.type = parseQuotingType(value); |
200 else if (uri == option::QuotesTypeForKeys) quotingForKeys.type = parseQuotingType(value); |
182 else if (uri == option::QuotesTypeForValues) quotingForValues.type = parseQuotingType(value); |
201 else if (uri == option::QuotesTypeForValues) quotingForValues.type = parseQuotingType(value); |
183 else if (uri == option::QuotesPatternForSections) quotingForSections.pattern = value; |
202 else if (uri == option::QuotesPatternForSections) quotingForSections.pattern = value; |
184 else if (uri == option::QuotesPatternForKeys) quotingForKeys.pattern = value; |
203 else if (uri == option::QuotesPatternForKeys) quotingForKeys.pattern = value; |
198 |
217 |
199 void startDocument() { |
218 void startDocument() { |
200 } |
219 } |
201 |
220 |
202 void endDocument() { |
221 void endDocument() { |
|
222 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."); |
203 output.flush(); |
223 output.flush(); |
204 } |
224 } |
205 |
225 |
206 void startSection(const SectionStartEvent& event) { |
226 void startSection(const SectionStartEvent& event) { |
207 if (hasContent) output << std::endl; |
227 currentSection.push_back(event.name); |
208 output << "[" << escape(event.name, EscapingProcessor::TextType::SectionName) << "]"; |
228 |
209 if (event.tag.size()) output << "[" << escape(event.tag, EscapingProcessor::TextType::SectionTag) << "]"; |
229 if (allowSections) { |
210 if (event.comment.size()) output << commentSeparatorForSections << escape(event.comment, EscapingProcessor::TextType::SectionComment); |
230 if (hasContent) output << std::endl; |
211 output << std::endl; |
231 output << "[" << escape(getCurrentSectionFullName(), EscapingProcessor::TextType::SectionName) << "]"; |
|
232 if (event.tag.size()) output << "[" << escape(event.tag, EscapingProcessor::TextType::SectionTag) << "]"; |
|
233 if (event.comment.size()) output << commentSeparatorForSections << escape(event.comment, EscapingProcessor::TextType::SectionComment); |
|
234 output << std::endl; |
|
235 } |
|
236 |
212 hasContent = true; |
237 hasContent = true; |
213 } |
238 } |
214 |
239 |
215 void endSection() { |
240 void endSection() { |
|
241 currentSection.pop_back(); |
216 output.flush(); |
242 output.flush(); |
217 } |
243 } |
218 |
244 |
219 void entry(const EntryEvent& event) { |
245 void entry(const EntryEvent& event) { |
|
246 // TODO: escape/quote parts separately + configurable quoting of parts or whole + the same for sub keys |
|
247 if (!allowSections && currentSection.size()) output << escape(getCurrentSectionFullName(), EscapingProcessor::TextType::EntryKey) << convertor.to_bytes(hierarchySeparator); |
220 output << escape(event.key, EscapingProcessor::TextType::EntryKey); |
248 output << escape(event.key, EscapingProcessor::TextType::EntryKey); |
221 if (event.subKey.size()) output << "[" << escape(event.subKey, EscapingProcessor::TextType::EntrySubKey) << "]"; |
249 if (event.subKey.size()) output << "[" << escape(event.subKey, EscapingProcessor::TextType::EntrySubKey) << "]"; |
222 output << keyValueSeparator << escape(event.value, EscapingProcessor::TextType::EntryValue); |
250 output << keyValueSeparator << escape(event.value, EscapingProcessor::TextType::EntryValue); |
223 if (event.comment.size()) output << commentSeparatorForEntries << escape(event.comment, EscapingProcessor::TextType::EntryComment); |
251 if (event.comment.size()) output << commentSeparatorForEntries << escape(event.comment, EscapingProcessor::TextType::EntryComment); |
224 output << std::endl; |
252 output << std::endl; |