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