3 #include "../conversion/stringconversion.h"
12 static void addChar(
char c, std::string &to, std::size_t &padding)
40 void IniFile::parse(std::istream &inputStream)
42 inputStream.exceptions(ios_base::failbit | ios_base::badbit);
45 enum State { Init, Comment, SectionName, Key,
Value } state = Init;
46 char currentCharacter;
49 std::size_t whitespace = 0;
50 string sectionName, key, value;
51 sectionName.reserve(16);
56 const auto finishKeyValue = [&state, §ionName, &key, &value, &whitespace,
this] {
57 if (key.empty() && value.empty() && state !=
Value) {
60 if (m_data.empty() || m_data.back().first != sectionName) {
61 m_data.emplace_back(make_pair(sectionName, decltype(m_data)::value_type::second_type()));
63 m_data.back().second.insert(make_pair(key, value));
71 while (inputStream.get(currentCharacter)) {
75 switch (currentCharacter) {
90 addChar(currentCharacter, key, whitespace);
95 switch (currentCharacter) {
109 addChar(currentCharacter, key, whitespace);
113 switch (currentCharacter) {
121 switch (currentCharacter) {
126 sectionName += currentCharacter;
130 switch (currentCharacter) {
140 addChar(currentCharacter, value, whitespace);
145 }
catch (
const std::ios_base::failure &) {
146 if (!inputStream.eof()) {
159 void IniFile::make(ostream &outputStream)
161 outputStream.exceptions(ios_base::failbit | ios_base::badbit);
162 for (
const auto §ion : m_data) {
163 outputStream <<
'[' << section.first <<
']' <<
'\n';
164 for (
const auto &field : section.second) {
165 outputStream << field.first <<
'=' << field.second <<
'\n';
167 outputStream <<
'\n';
216 inputStream.exceptions(ios_base::failbit | ios_base::badbit);
219 enum State { Init, CommentBlock, InlineComment, SectionInlineComment, SectionName, SectionEnd, Key,
Value } state = Init;
220 char currentCharacter;
223 std::string commentBlock, inlineComment, sectionName, key, value;
224 std::size_t keyPadding = 0, valuePadding = 0;
225 commentBlock.reserve(256);
226 inlineComment.reserve(256);
227 sectionName.reserve(16);
232 const auto finishKeyValue = [&,
this] {
233 if (key.empty() && value.empty() && state !=
Value) {
236 if (sections.empty()) {
237 sections.emplace_back(
Section{ .
flags = IniFileSectionFlags::Implicit });
239 sections.back().fields.emplace_back(
Field{ .
key = key,
241 .precedingCommentBlock = commentBlock,
242 .followingInlineComment = inlineComment,
243 .paddedKeyLength = key.size() + keyPadding,
244 .flags = (!value.empty() || state ==
Value ? IniFileFieldFlags::HasValue : IniFileFieldFlags::None) });
247 commentBlock.clear();
248 inlineComment.clear();
249 keyPadding = valuePadding = 0;
254 while (inputStream.get(currentCharacter)) {
258 switch (currentCharacter) {
260 commentBlock += currentCharacter;
263 commentBlock += currentCharacter;
264 state = CommentBlock;
267 keyPadding = valuePadding = 0;
275 addChar(currentCharacter, key, keyPadding);
280 switch (currentCharacter) {
286 state = InlineComment;
287 inlineComment += currentCharacter;
294 addChar(currentCharacter, key, keyPadding);
298 switch (currentCharacter) {
303 commentBlock += currentCharacter;
307 case SectionInlineComment:
308 switch (currentCharacter) {
314 case SectionInlineComment:
315 sections.back().followingInlineComment = inlineComment;
316 inlineComment.clear();
323 inlineComment += currentCharacter;
327 switch (currentCharacter) {
330 sections.emplace_back(
Section{ .
name = sectionName });
331 sections.back().precedingCommentBlock = commentBlock;
333 commentBlock.clear();
336 sectionName += currentCharacter;
340 switch (currentCharacter) {
345 state = SectionInlineComment;
346 inlineComment += currentCharacter;
349 keyPadding = valuePadding = 0;
356 addChar(currentCharacter, key, keyPadding);
360 switch (currentCharacter) {
366 state = InlineComment;
367 inlineComment += currentCharacter;
370 addChar(currentCharacter, value, valuePadding);
375 }
catch (
const std::ios_base::failure &) {
376 if (!inputStream.eof()) {
387 sections.emplace_back(
Section{ .
name = sectionName, .precedingCommentBlock = commentBlock, .flags = IniFileSectionFlags::Implicit });
390 case SectionInlineComment:
391 sections.emplace_back(
Section{ .
name = sectionName, .precedingCommentBlock = commentBlock, .followingInlineComment = inlineComment });
411 outputStream.exceptions(ios_base::failbit | ios_base::badbit);
412 for (
const auto §ion : sections) {
413 if (!section.precedingCommentBlock.empty()) {
414 outputStream << section.precedingCommentBlock;
416 if (!(section.flags & IniFileSectionFlags::Implicit)) {
417 outputStream <<
'[' << section.name <<
']';
418 if (!section.followingInlineComment.empty()) {
419 outputStream <<
' ' << section.followingInlineComment;
421 outputStream <<
'\n';
423 for (
const auto &field : section.fields) {
424 if (!field.precedingCommentBlock.empty()) {
425 outputStream << field.precedingCommentBlock;
427 outputStream << field.key;
428 for (
auto charsWritten = field.key.size(); charsWritten < field.paddedKeyLength; ++charsWritten) {
431 if (field.flags & IniFileFieldFlags::HasValue) {
432 outputStream <<
'=' <<
' ' << field.value;
434 if (!field.followingInlineComment.empty()) {
435 if (field.flags & IniFileFieldFlags::HasValue) {
438 outputStream << field.followingInlineComment;
440 outputStream <<
'\n';