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 &current = 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 &current = m_sections.back();
180 size_t epos; 116 size_t epos;
181 std::string key, value; 117 std::string key, value;
182 Section &current = 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 &section)
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 }