Mercurial > code
comparison C++/Parser.cpp @ 203:1ffe6d4937b7
Update parser for more convenience and types security #224
author | David Demelier <markand@malikania.fr> |
---|---|
date | Thu, 23 Jan 2014 14:56:50 +0100 |
parents | 600754c27c88 |
children | 9f22ce5f1b39 706f861c4c6d |
comparison
equal
deleted
inserted
replaced
202:99d0887395cc | 203:1ffe6d4937b7 |
---|---|
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
17 */ | 17 */ |
18 | 18 |
19 #include <cstring> | |
20 #include <cerrno> | |
19 #include <iostream> | 21 #include <iostream> |
20 #include <fstream> | 22 #include <fstream> |
21 | 23 |
22 #include "Parser.h" | 24 #include "Parser.h" |
23 | |
24 /* -------------------------------------------------------- | |
25 * Option public members | |
26 * -------------------------------------------------------- */ | |
27 | |
28 bool operator==(const Option &o1, const Option &o2) | |
29 { | |
30 return o1.m_key == o2.m_key && | |
31 o1.m_value == o2.m_value; | |
32 } | |
33 | 25 |
34 /* -------------------------------------------------------- | 26 /* -------------------------------------------------------- |
35 * Section public members | 27 * Section public members |
36 * -------------------------------------------------------- */ | 28 * -------------------------------------------------------- */ |
37 | 29 |
38 Section::Section() | 30 Section::Section() |
39 : m_allowed(true) | 31 : m_allowed(true) |
40 { | 32 { |
41 } | 33 } |
42 | 34 |
35 Section::Section(const std::string &name) | |
36 : m_name(name) | |
37 , m_allowed(true) | |
38 { | |
39 | |
40 } | |
41 | |
43 const std::string &Section::getName() const | 42 const std::string &Section::getName() const |
44 { | 43 { |
45 return m_name; | 44 return m_name; |
46 } | 45 } |
47 | 46 |
48 const std::string Section::findOption(const std::string &name) const | |
49 { | |
50 std::string ret; | |
51 | |
52 for (const Option &o : m_options) | |
53 if (o.m_key == name) { | |
54 ret = o.m_value; | |
55 break; | |
56 } | |
57 | |
58 return ret; | |
59 } | |
60 | |
61 template <> | |
62 bool Section::getValue(const std::string &name) const | |
63 { | |
64 bool result = false; | |
65 | |
66 if (hasOption(name)) { | |
67 std::string value = findOption(name); | |
68 | |
69 if (value == "yes" || value == "true"|| value == "1") | |
70 result = true; | |
71 else if (value == "no" || value == "false" || value == "0") | |
72 result = false; | |
73 } | |
74 | |
75 return result; | |
76 } | |
77 | |
78 template <> | |
79 int Section::getValue(const std::string &name) const | |
80 { | |
81 int result = -1; | |
82 | |
83 if (hasOption(name)) | |
84 result = atoi(findOption(name).c_str()); | |
85 | |
86 return result; | |
87 } | |
88 | |
89 template <> | |
90 std::string Section::getValue(const std::string &name) const | |
91 { | |
92 std::string result; | |
93 | |
94 if (hasOption(name)) | |
95 result = findOption(name); | |
96 | |
97 return result; | |
98 } | |
99 | |
100 const std::vector<Option> &Section::getOptions() const | |
101 { | |
102 return m_options; | |
103 } | |
104 | |
105 bool Section::hasOption(const std::string &name) const | 47 bool Section::hasOption(const std::string &name) const |
106 { | 48 { |
107 for (const Option &o : m_options) | 49 return m_options.count(name) >= 1; |
108 if (o.m_key == name) | 50 } |
109 return true; | 51 |
110 | 52 Section::Map::iterator Section::begin() |
111 return false; | 53 { |
112 } | 54 return m_options.begin(); |
113 | 55 } |
114 bool operator==(const Section &s1, const Section &s2) | 56 |
115 { | 57 Section::Map::const_iterator Section::cbegin() const |
116 if (s1.m_name != s2.m_name) | 58 { |
117 return false; | 59 return m_options.cbegin(); |
118 | 60 } |
119 return s1.m_options == s2.m_options; | 61 |
62 Section::Map::iterator Section::end() | |
63 { | |
64 return m_options.end(); | |
65 } | |
66 | |
67 Section::Map::const_iterator Section::cend() const | |
68 { | |
69 return m_options.end(); | |
120 } | 70 } |
121 | 71 |
122 /* -------------------------------------------------------- | 72 /* -------------------------------------------------------- |
123 * Parser private members | 73 * Parser private members |
124 * -------------------------------------------------------- */ | 74 * -------------------------------------------------------- */ |
125 | 75 |
126 void Parser::addSection(const std::string &name) | |
127 { | |
128 Section section; | |
129 | |
130 section.m_name = name; | |
131 section.m_allowed = true; | |
132 | |
133 m_sections.push_back(section); | |
134 } | |
135 | |
136 void Parser::addOption(const std::string &key, const std::string &value) | 76 void Parser::addOption(const std::string &key, const std::string &value) |
137 { | 77 { |
138 Option option; | 78 m_sections.back().m_options.insert(std::make_pair(key, value)); |
139 Section ¤t = m_sections.back(); | |
140 | |
141 option.m_key = key; | |
142 option.m_value = value; | |
143 | |
144 current.m_options.push_back(option); | |
145 } | 79 } |
146 | 80 |
147 void Parser::readSection(int lineno, const std::string &line) | 81 void Parser::readSection(int lineno, const std::string &line) |
148 { | 82 { |
149 size_t end; | 83 size_t end; |
150 | 84 |
151 if ((end = line.find_first_of(']')) != std::string::npos) { | 85 if ((end = line.find_first_of(']')) != std::string::npos) { |
152 if (end > 1) { | 86 if (end > 1) { |
153 std::string name = line.substr(1, end - 1); | 87 auto name = line.substr(1, end - 1); |
154 | 88 |
155 /* | 89 /* |
156 * Check if we can add a section, if redefinition is | 90 * Check if we can add a section, if redefinition is |
157 * disabled, we must disable the previous section so the | 91 * disabled, we must disable the previous section so the |
158 * further read options should not be enabled until | 92 * further read options should not be enabled until |
160 */ | 94 */ |
161 if (hasSection(name) && (m_tuning & DisableRedefinition)) { | 95 if (hasSection(name) && (m_tuning & DisableRedefinition)) { |
162 if (!(m_tuning & DisableVerbosity)) | 96 if (!(m_tuning & DisableVerbosity)) |
163 log(lineno, name, "redefinition not allowed"); | 97 log(lineno, name, "redefinition not allowed"); |
164 m_sections.back().m_allowed = false; | 98 m_sections.back().m_allowed = false; |
165 } else | 99 } else { |
166 addSection(name); | 100 m_sections.push_back(Section(name)); |
101 } | |
167 } else if (!(m_tuning & DisableVerbosity)) { | 102 } else if (!(m_tuning & DisableVerbosity)) { |
168 /* | 103 /* |
169 * Do not add options at this step because it will | 104 * Do not add options at this step because it will |
170 * corrupt the previous one. | 105 * corrupt the previous one. |
171 */ | 106 */ |
175 } | 110 } |
176 } | 111 } |
177 | 112 |
178 void Parser::readOption(int lineno, const std::string &line) | 113 void Parser::readOption(int lineno, const std::string &line) |
179 { | 114 { |
115 auto ¤t = m_sections.back(); | |
180 size_t epos; | 116 size_t epos; |
181 std::string key, value; | 117 std::string key, value; |
182 Section ¤t = m_sections.back(); | |
183 | 118 |
184 // Error on last section? | 119 // Error on last section? |
185 if (!current.m_allowed) { | 120 if (!current.m_allowed) { |
186 /* | 121 /* |
187 * If it is the root section, this has been probably set by | 122 * If it is the root section, this has been probably set by |
265 * Parser public methods | 200 * Parser public methods |
266 * -------------------------------------------------------- */ | 201 * -------------------------------------------------------- */ |
267 | 202 |
268 const char Parser::DEFAULT_COMMENT_CHAR = '#'; | 203 const char Parser::DEFAULT_COMMENT_CHAR = '#'; |
269 | 204 |
205 void Parser::open() | |
206 { | |
207 std::ifstream file; | |
208 std::string line; | |
209 int lineno = 1; | |
210 | |
211 file.open(m_path.c_str()); | |
212 if (!file.is_open()) | |
213 throw std::runtime_error(m_path + std::string(std::strerror(errno))); | |
214 | |
215 while (std::getline(file, line)) | |
216 readLine(lineno++, line); | |
217 | |
218 file.close(); | |
219 } | |
220 | |
270 Parser::Parser() | 221 Parser::Parser() |
271 { | 222 { |
272 } | 223 } |
273 | 224 |
274 Parser::Parser(const std::string &path, int tuning, char commentToken) | 225 Parser::Parser(const std::string &path, int tuning, char commentToken) |
275 : m_path(path) | 226 : m_path(path) |
276 , m_tuning(tuning) | 227 , m_tuning(tuning) |
277 , m_commentChar(commentToken) | 228 , m_commentChar(commentToken) |
278 { | 229 { |
279 Section root; | 230 Section s(""); |
280 | 231 |
281 // Add a default root section | 232 s.m_allowed = (tuning & DisableRootSection) ? false : true; |
282 root.m_name = ""; | 233 |
283 root.m_allowed = (tuning & DisableRootSection) ? false : true; | 234 m_sections.push_back(s); |
284 | 235 open(); |
285 m_sections.push_back(root); | |
286 } | 236 } |
287 | 237 |
288 Parser::~Parser() | 238 Parser::~Parser() |
289 { | 239 { |
290 } | 240 } |
291 | 241 |
292 bool Parser::open() | 242 Parser::List::iterator Parser::begin() |
293 { | 243 { |
294 std::ifstream file; | 244 return m_sections.begin(); |
295 std::string line; | 245 } |
296 int lineno = 1; | 246 |
297 | 247 Parser::List::const_iterator Parser::cbegin() const |
298 file.open(m_path.c_str()); | 248 { |
299 if (!file.is_open()) { | 249 return m_sections.cbegin(); |
300 m_error = "could not open file " + m_path; // XXX: add a real error | 250 } |
301 return false; | 251 |
302 } | 252 Parser::List::iterator Parser::end() |
303 | 253 { |
304 // Avoid use of C getline | 254 return m_sections.end(); |
305 while (std::getline(file, line)) | 255 } |
306 readLine(lineno++, line); | 256 |
307 | 257 Parser::List::const_iterator Parser::cend() const |
308 file.close(); | 258 { |
309 | 259 return m_sections.end(); |
310 return true; | |
311 } | |
312 | |
313 const std::string &Parser::getError() const | |
314 { | |
315 return m_error; | |
316 } | |
317 | |
318 const std::vector<Section> &Parser::getSections() const | |
319 { | |
320 return m_sections; | |
321 } | 260 } |
322 | 261 |
323 void Parser::findSections(const std::string &name, FindFunc func) const | 262 void Parser::findSections(const std::string &name, FindFunc func) const |
324 { | 263 { |
325 for (const Section &s : m_sections) | 264 for (const auto &s : m_sections) |
326 if (s.m_name == name) | 265 if (s.m_name == name) |
327 func(s); | 266 func(s); |
328 } | 267 } |
329 | 268 |
330 bool Parser::hasSection(const std::string &name) const | 269 bool Parser::hasSection(const std::string &name) const |
331 { | 270 { |
332 for (const Section &s : m_sections) | 271 for (const auto &s : m_sections) |
333 if (s.m_name == name) | 272 if (s.m_name == name) |
334 return true; | 273 return true; |
335 | 274 |
336 return false; | 275 return false; |
337 } | 276 } |
338 | 277 |
339 const Section &Parser::getSection(const std::string &name) const | 278 const Section &Parser::getSection(const std::string &name) const |
340 { | 279 { |
341 for (const Section &s : m_sections) | 280 for (const auto &s : m_sections) |
342 if (s.m_name == name) | 281 if (s.m_name == name) |
343 return s; | 282 return s; |
344 | 283 |
345 throw NotFoundException(name); | 284 throw std::out_of_range(name + " not found"); |
346 } | 285 } |
347 | 286 |
348 void Parser::log(int number, const std::string &, const std::string &message) | 287 void Parser::log(int number, const std::string &, const std::string &message) |
349 { | 288 { |
350 std::cout << "line " << number << ": " << message << std::endl; | 289 std::cout << "line " << number << ": " << message << std::endl; |
351 } | 290 } |
352 | |
353 void Parser::dump() | |
354 { | |
355 for (auto s : m_sections) { | |
356 dumpSection(s); | |
357 | |
358 for (auto o : s.m_options) | |
359 dumpOption(o); | |
360 } | |
361 } | |
362 | |
363 void Parser::dumpSection(const Section §ion) | |
364 { | |
365 std::cout << "Section " << section.m_name << std::endl; | |
366 } | |
367 | |
368 void Parser::dumpOption(const Option &option) | |
369 { | |
370 std::cout << " Option " << option.m_key << " = " << option.m_value << std::endl; | |
371 } |