C++ Utilities  5.3.0
Useful C++ classes and routines such as argument parser, IO and conversion utilities
inifile.cpp
Go to the documentation of this file.
1 #include "./inifile.h"
2 
3 #include <iostream>
4 
5 using namespace std;
6 
7 namespace CppUtilities {
8 
21 void IniFile::parse(std::istream &inputStream)
22 {
23  // define variable for state machine
24  enum State { Init, Comment, ScopeName, Key, Value } state = Init;
25  // current character
26  char c;
27  // number of postponed whitespaces
28  unsigned int whitespace = 0;
29  // current scope, key and value
30  string scope, key, value;
31  scope.reserve(16);
32  key.reserve(16);
33  value.reserve(256);
34  // define actions for state machine
35  // called when key/value pair is complete
36  const auto finishKeyValue = [&state, &scope, &key, &value, &whitespace, this] {
37  if (key.empty() && value.empty() && state != Value) {
38  return;
39  }
40  if (m_data.empty() || m_data.back().first != scope) {
41  m_data.emplace_back(make_pair(scope, decltype(m_data)::value_type::second_type()));
42  }
43  m_data.back().second.insert(make_pair(key, value));
44  key.clear();
45  value.clear();
46  whitespace = 0;
47  };
48  // called to add current character to current key or value
49  const auto addChar = [&whitespace, &c](string &to) {
50  if (c == ' ') {
51  ++whitespace;
52  } else {
53  if (!to.empty()) {
54  while (whitespace) {
55  to += ' ';
56  --whitespace;
57  }
58  } else {
59  whitespace = 0;
60  }
61  to += c;
62  }
63  };
64  // thorw an exception when an IO error occurs
65  inputStream.exceptions(ios_base::failbit | ios_base::badbit);
66  // parse the file char by char
67  try {
68  while (inputStream.get(c)) {
69  switch (state) {
70  case Init:
71  switch (c) {
72  case '\n':
73  break;
74  case '#':
75  state = Comment;
76  break;
77  case '=':
78  whitespace = 0;
79  state = Value;
80  break;
81  case '[':
82  scope.clear();
83  state = ScopeName;
84  break;
85  default:
86  addChar(key);
87  state = Key;
88  }
89  break;
90  case Key:
91  switch (c) {
92  case '\n':
93  finishKeyValue();
94  state = Init;
95  break;
96  case '#':
97  finishKeyValue();
98  state = Comment;
99  break;
100  case '=':
101  whitespace = 0;
102  state = Value;
103  break;
104  default:
105  addChar(key);
106  }
107  break;
108  case Comment:
109  switch (c) {
110  case '\n':
111  state = Init;
112  break;
113  default:;
114  }
115  break;
116  case ScopeName:
117  switch (c) {
118  case ']':
119  state = Init;
120  break;
121  default:
122  scope += c;
123  }
124  break;
125  case Value:
126  switch (c) {
127  case '\n':
128  finishKeyValue();
129  state = Init;
130  break;
131  case '#':
132  finishKeyValue();
133  state = Comment;
134  break;
135  default:
136  addChar(value);
137  }
138  break;
139  }
140  }
141  } catch (const std::ios_base::failure &) {
142  if (!inputStream.eof()) {
143  throw;
144  }
145  // we just reached the end of the file
146  // don't forget to save the last key/value pair
147  finishKeyValue();
148  }
149 }
150 
154 void IniFile::make(ostream &outputStream)
155 {
156  // thorw an exception when an IO error occurs
157  outputStream.exceptions(ios_base::failbit | ios_base::badbit);
158  for (const auto &scope : m_data) {
159  outputStream << '[' << scope.first << ']' << '\n';
160  for (const auto &field : scope.second) {
161  outputStream << field.first << '=' << field.second << '\n';
162  }
163  outputStream << '\n';
164  }
165 }
166 
167 } // namespace CppUtilities
inifile.h
CppUtilities
Contains all utilities provides by the c++utilities library.
Definition: argumentparser.h:17
CppUtilities::IniFile::ScopeName
std::string ScopeName
Definition: inifile.h:15
CppUtilities::Value
@ Value
Definition: argumentparser.cpp:39