Mercurial > code
annotate C++/Parser.cpp @ 205:9f22ce5f1b39
Parser: rename getValue, add operator==
author | David Demelier <markand@malikania.fr> |
---|---|
date | Sun, 16 Feb 2014 12:39:03 +0100 |
parents | 1ffe6d4937b7 |
children | 3b0e276f0866 |
rev | line source |
---|---|
179 | 1 /* |
2 * Parser.h -- config file parser | |
3 * | |
205
9f22ce5f1b39
Parser: rename getValue, add operator==
David Demelier <markand@malikania.fr>
parents:
203
diff
changeset
|
4 * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr> |
179 | 5 * |
6 * Permission to use, copy, modify, and/or distribute this software for any | |
7 * purpose with or without fee is hereby granted, provided that the above | |
8 * copyright notice and this permission notice appear in all copies. | |
9 * | |
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
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 | |
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
17 */ | |
18 | |
203
1ffe6d4937b7
Update parser for more convenience and types security #224
David Demelier <markand@malikania.fr>
parents:
187
diff
changeset
|
19 #include <cstring> |
1ffe6d4937b7
Update parser for more convenience and types security #224
David Demelier <markand@malikania.fr>
parents:
187
diff
changeset
|
20 #include <cerrno> |
179 | 21 #include <iostream> |
22 #include <fstream> | |
23 | |
24 #include "Parser.h" | |
25 | |
26 /* -------------------------------------------------------- | |
27 * Section public members | |
28 * -------------------------------------------------------- */ | |
29 | |
30 Section::Section() | |
180 | 31 : m_allowed(true) |
179 | 32 { |
33 } | |
34 | |
203
1ffe6d4937b7
Update parser for more convenience and types security #224
David Demelier <markand@malikania.fr>
parents:
187
diff
changeset
|
35 Section::Section(const std::string &name) |
1ffe6d4937b7
Update parser for more convenience and types security #224
David Demelier <markand@malikania.fr>
parents:
187
diff
changeset
|
36 : m_name(name) |
1ffe6d4937b7
Update parser for more convenience and types security #224
David Demelier <markand@malikania.fr>
parents:
187
diff
changeset
|
37 , m_allowed(true) |
1ffe6d4937b7
Update parser for more convenience and types security #224
David Demelier <markand@malikania.fr>
parents:
187
diff
changeset
|
38 { |
1ffe6d4937b7
Update parser for more convenience and types security #224
David Demelier <markand@malikania.fr>
parents:
187
diff
changeset
|
39 |
1ffe6d4937b7
Update parser for more convenience and types security #224
David Demelier <markand@malikania.fr>
parents:
187
diff
changeset
|
40 } |
1ffe6d4937b7
Update parser for more convenience and types security #224
David Demelier <markand@malikania.fr>
parents:
187
diff
changeset
|
41 |
180 | 42 const std::string &Section::getName() const |
179 | 43 { |
180 | 44 return m_name; |
179 | 45 } |
46 | |
203
1ffe6d4937b7
Update parser for more convenience and types security #224
David Demelier <markand@malikania.fr>
parents:
187
diff
changeset
|
47 bool Section::hasOption(const std::string &name) const |
179 | 48 { |
203
1ffe6d4937b7
Update parser for more convenience and types security #224
David Demelier <markand@malikania.fr>
parents:
187
diff
changeset
|
49 return m_options.count(name) >= 1; |
179 | 50 } |
51 | |
203
1ffe6d4937b7
Update parser for more convenience and types security #224
David Demelier <markand@malikania.fr>
parents:
187
diff
changeset
|
52 Section::Map::iterator Section::begin() |
179 | 53 { |
203
1ffe6d4937b7
Update parser for more convenience and types security #224
David Demelier <markand@malikania.fr>
parents:
187
diff
changeset
|
54 return m_options.begin(); |
179 | 55 } |
56 | |
203
1ffe6d4937b7
Update parser for more convenience and types security #224
David Demelier <markand@malikania.fr>
parents:
187
diff
changeset
|
57 Section::Map::const_iterator Section::cbegin() const |
179 | 58 { |
203
1ffe6d4937b7
Update parser for more convenience and types security #224
David Demelier <markand@malikania.fr>
parents:
187
diff
changeset
|
59 return m_options.cbegin(); |
179 | 60 } |
61 | |
203
1ffe6d4937b7
Update parser for more convenience and types security #224
David Demelier <markand@malikania.fr>
parents:
187
diff
changeset
|
62 Section::Map::iterator Section::end() |
179 | 63 { |
203
1ffe6d4937b7
Update parser for more convenience and types security #224
David Demelier <markand@malikania.fr>
parents:
187
diff
changeset
|
64 return m_options.end(); |
179 | 65 } |
66 | |
203
1ffe6d4937b7
Update parser for more convenience and types security #224
David Demelier <markand@malikania.fr>
parents:
187
diff
changeset
|
67 Section::Map::const_iterator Section::cend() const |
179 | 68 { |
203
1ffe6d4937b7
Update parser for more convenience and types security #224
David Demelier <markand@malikania.fr>
parents:
187
diff
changeset
|
69 return m_options.end(); |
179 | 70 } |
71 | |
205
9f22ce5f1b39
Parser: rename getValue, add operator==
David Demelier <markand@malikania.fr>
parents:
203
diff
changeset
|
72 bool operator==(const Section &s1, const Section &s2) |
9f22ce5f1b39
Parser: rename getValue, add operator==
David Demelier <markand@malikania.fr>
parents:
203
diff
changeset
|
73 { |
9f22ce5f1b39
Parser: rename getValue, add operator==
David Demelier <markand@malikania.fr>
parents:
203
diff
changeset
|
74 return s1.m_name == s2.m_name && s1.m_options == s2.m_options; |
9f22ce5f1b39
Parser: rename getValue, add operator==
David Demelier <markand@malikania.fr>
parents:
203
diff
changeset
|
75 } |
9f22ce5f1b39
Parser: rename getValue, add operator==
David Demelier <markand@malikania.fr>
parents:
203
diff
changeset
|
76 |
179 | 77 /* -------------------------------------------------------- |
78 * Parser private members | |
79 * -------------------------------------------------------- */ | |
80 | |
81 void Parser::addOption(const std::string &key, const std::string &value) | |
82 { | |
203
1ffe6d4937b7
Update parser for more convenience and types security #224
David Demelier <markand@malikania.fr>
parents:
187
diff
changeset
|
83 m_sections.back().m_options.insert(std::make_pair(key, value)); |
179 | 84 } |
85 | |
86 void Parser::readSection(int lineno, const std::string &line) | |
87 { | |
88 size_t end; | |
89 | |
187
600754c27c88
Update parser to style and remove useless stuff
David Demelier <markand@malikania.fr>
parents:
180
diff
changeset
|
90 if ((end = line.find_first_of(']')) != std::string::npos) { |
600754c27c88
Update parser to style and remove useless stuff
David Demelier <markand@malikania.fr>
parents:
180
diff
changeset
|
91 if (end > 1) { |
203
1ffe6d4937b7
Update parser for more convenience and types security #224
David Demelier <markand@malikania.fr>
parents:
187
diff
changeset
|
92 auto name = line.substr(1, end - 1); |
179 | 93 |
94 /* | |
95 * Check if we can add a section, if redefinition is | |
96 * disabled, we must disable the previous section so the | |
97 * further read options should not be enabled until | |
98 * a correct section is found again. | |
99 */ | |
187
600754c27c88
Update parser to style and remove useless stuff
David Demelier <markand@malikania.fr>
parents:
180
diff
changeset
|
100 if (hasSection(name) && (m_tuning & DisableRedefinition)) { |
179 | 101 if (!(m_tuning & DisableVerbosity)) |
102 log(lineno, name, "redefinition not allowed"); | |
103 m_sections.back().m_allowed = false; | |
203
1ffe6d4937b7
Update parser for more convenience and types security #224
David Demelier <markand@malikania.fr>
parents:
187
diff
changeset
|
104 } else { |
1ffe6d4937b7
Update parser for more convenience and types security #224
David Demelier <markand@malikania.fr>
parents:
187
diff
changeset
|
105 m_sections.push_back(Section(name)); |
1ffe6d4937b7
Update parser for more convenience and types security #224
David Demelier <markand@malikania.fr>
parents:
187
diff
changeset
|
106 } |
187
600754c27c88
Update parser to style and remove useless stuff
David Demelier <markand@malikania.fr>
parents:
180
diff
changeset
|
107 } else if (!(m_tuning & DisableVerbosity)) { |
179 | 108 /* |
109 * Do not add options at this step because it will | |
110 * corrupt the previous one. | |
111 */ | |
112 m_sections.back().m_allowed = false; | |
113 log(lineno, "", "empty section name"); | |
114 } | |
115 } | |
116 } | |
117 | |
118 void Parser::readOption(int lineno, const std::string &line) | |
119 { | |
203
1ffe6d4937b7
Update parser for more convenience and types security #224
David Demelier <markand@malikania.fr>
parents:
187
diff
changeset
|
120 auto ¤t = m_sections.back(); |
179 | 121 size_t epos; |
122 std::string key, value; | |
123 | |
124 // Error on last section? | |
187
600754c27c88
Update parser to style and remove useless stuff
David Demelier <markand@malikania.fr>
parents:
180
diff
changeset
|
125 if (!current.m_allowed) { |
179 | 126 /* |
127 * If it is the root section, this has been probably set by | |
128 * DisableRootSection flag, otherwise an error has occured | |
129 * so no need to log. | |
130 */ | |
131 if (current.m_name == "" && !(m_tuning == DisableVerbosity)) | |
132 log(lineno, "", "option not allowed in that scope"); | |
133 | |
134 return; | |
135 } | |
136 | |
187
600754c27c88
Update parser to style and remove useless stuff
David Demelier <markand@malikania.fr>
parents:
180
diff
changeset
|
137 if ((epos = line.find_first_of('=')) == std::string::npos) { |
179 | 138 if (!(m_tuning & DisableVerbosity)) |
139 log(lineno, current.m_name, "missing `=' keyword"); | |
140 return; | |
141 } | |
142 | |
187
600754c27c88
Update parser to style and remove useless stuff
David Demelier <markand@malikania.fr>
parents:
180
diff
changeset
|
143 if (epos > 0) { |
179 | 144 size_t i, begin, last; |
145 char c; | |
146 | |
147 key = line.substr(0, epos - 1); | |
148 value = line.substr(epos + 1); | |
149 | |
150 // clean option key | |
151 for (i = 0; !isspace(key[i]) && i < key.length(); ++i) | |
152 continue; | |
153 key = key.substr(0, i); | |
154 | |
155 // clean option value | |
156 for (begin = 0; isspace(value[begin]) && begin < value.length(); ++begin) | |
157 continue; | |
158 value = value.substr(begin); | |
159 | |
160 c = value[0]; | |
161 begin = 0; | |
187
600754c27c88
Update parser to style and remove useless stuff
David Demelier <markand@malikania.fr>
parents:
180
diff
changeset
|
162 if (c == '\'' || c == '"') { |
179 | 163 for (last = begin = 1; value[last] != c && last < value.length(); ++last) |
164 continue; | |
165 if (value[last] != c && !(m_tuning & DisableVerbosity)) | |
166 if (!(m_tuning & DisableVerbosity)) | |
167 log(lineno, current.m_name, "undisclosed std::string"); | |
187
600754c27c88
Update parser to style and remove useless stuff
David Demelier <markand@malikania.fr>
parents:
180
diff
changeset
|
168 } else { |
179 | 169 for (last = begin; !isspace(value[last]) && last < value.length(); ++last) |
170 continue; | |
171 } | |
172 | |
173 if (last - begin > 0) | |
174 value = value.substr(begin, last - begin); | |
175 else | |
176 value.clear(); | |
177 | |
178 // Add the option if the key is not empty | |
179 if (key.length() > 0) | |
180 addOption(key, value); | |
181 } | |
182 } | |
183 | |
184 void Parser::readLine(int lineno, const std::string &line) | |
185 { | |
186 size_t i; | |
187 std::string buffer; | |
188 | |
189 // Skip default spaces | |
190 for (i = 0; isspace(line[i]) && i < line.length(); ++i) | |
191 continue; | |
192 | |
193 buffer = line.substr(i); | |
187
600754c27c88
Update parser to style and remove useless stuff
David Demelier <markand@malikania.fr>
parents:
180
diff
changeset
|
194 if (buffer.length() > 0) { |
600754c27c88
Update parser to style and remove useless stuff
David Demelier <markand@malikania.fr>
parents:
180
diff
changeset
|
195 if (buffer[0] != m_commentChar) { |
179 | 196 if (buffer[0] == '[') |
197 readSection(lineno, buffer); | |
198 else | |
199 readOption(lineno, buffer); | |
200 } | |
201 } | |
202 } | |
203 | |
204 /* -------------------------------------------------------- | |
205 * Parser public methods | |
206 * -------------------------------------------------------- */ | |
207 | |
208 const char Parser::DEFAULT_COMMENT_CHAR = '#'; | |
209 | |
203
1ffe6d4937b7
Update parser for more convenience and types security #224
David Demelier <markand@malikania.fr>
parents:
187
diff
changeset
|
210 void Parser::open() |
1ffe6d4937b7
Update parser for more convenience and types security #224
David Demelier <markand@malikania.fr>
parents:
187
diff
changeset
|
211 { |
1ffe6d4937b7
Update parser for more convenience and types security #224
David Demelier <markand@malikania.fr>
parents:
187
diff
changeset
|
212 std::ifstream file; |
1ffe6d4937b7
Update parser for more convenience and types security #224
David Demelier <markand@malikania.fr>
parents:
187
diff
changeset
|
213 std::string line; |
1ffe6d4937b7
Update parser for more convenience and types security #224
David Demelier <markand@malikania.fr>
parents:
187
diff
changeset
|
214 int lineno = 1; |
1ffe6d4937b7
Update parser for more convenience and types security #224
David Demelier <markand@malikania.fr>
parents:
187
diff
changeset
|
215 |
1ffe6d4937b7
Update parser for more convenience and types security #224
David Demelier <markand@malikania.fr>
parents:
187
diff
changeset
|
216 file.open(m_path.c_str()); |
1ffe6d4937b7
Update parser for more convenience and types security #224
David Demelier <markand@malikania.fr>
parents:
187
diff
changeset
|
217 if (!file.is_open()) |
205
9f22ce5f1b39
Parser: rename getValue, add operator==
David Demelier <markand@malikania.fr>
parents:
203
diff
changeset
|
218 throw std::runtime_error(m_path + ": " + std::string(std::strerror(errno))); |
203
1ffe6d4937b7
Update parser for more convenience and types security #224
David Demelier <markand@malikania.fr>
parents:
187
diff
changeset
|
219 |
1ffe6d4937b7
Update parser for more convenience and types security #224
David Demelier <markand@malikania.fr>
parents:
187
diff
changeset
|
220 while (std::getline(file, line)) |
1ffe6d4937b7
Update parser for more convenience and types security #224
David Demelier <markand@malikania.fr>
parents:
187
diff
changeset
|
221 readLine(lineno++, line); |
1ffe6d4937b7
Update parser for more convenience and types security #224
David Demelier <markand@malikania.fr>
parents:
187
diff
changeset
|
222 |
1ffe6d4937b7
Update parser for more convenience and types security #224
David Demelier <markand@malikania.fr>
parents:
187
diff
changeset
|
223 file.close(); |
1ffe6d4937b7
Update parser for more convenience and types security #224
David Demelier <markand@malikania.fr>
parents:
187
diff
changeset
|
224 } |
1ffe6d4937b7
Update parser for more convenience and types security #224
David Demelier <markand@malikania.fr>
parents:
187
diff
changeset
|
225 |
180 | 226 Parser::Parser() |
227 { | |
228 } | |
229 | |
179 | 230 Parser::Parser(const std::string &path, int tuning, char commentToken) |
180 | 231 : m_path(path) |
232 , m_tuning(tuning) | |
233 , m_commentChar(commentToken) | |
179 | 234 { |
203
1ffe6d4937b7
Update parser for more convenience and types security #224
David Demelier <markand@malikania.fr>
parents:
187
diff
changeset
|
235 Section s(""); |
179 | 236 |
203
1ffe6d4937b7
Update parser for more convenience and types security #224
David Demelier <markand@malikania.fr>
parents:
187
diff
changeset
|
237 s.m_allowed = (tuning & DisableRootSection) ? false : true; |
179 | 238 |
203
1ffe6d4937b7
Update parser for more convenience and types security #224
David Demelier <markand@malikania.fr>
parents:
187
diff
changeset
|
239 m_sections.push_back(s); |
1ffe6d4937b7
Update parser for more convenience and types security #224
David Demelier <markand@malikania.fr>
parents:
187
diff
changeset
|
240 open(); |
179 | 241 } |
242 | |
243 Parser::~Parser() | |
244 { | |
245 } | |
246 | |
203
1ffe6d4937b7
Update parser for more convenience and types security #224
David Demelier <markand@malikania.fr>
parents:
187
diff
changeset
|
247 Parser::List::iterator Parser::begin() |
179 | 248 { |
203
1ffe6d4937b7
Update parser for more convenience and types security #224
David Demelier <markand@malikania.fr>
parents:
187
diff
changeset
|
249 return m_sections.begin(); |
179 | 250 } |
251 | |
203
1ffe6d4937b7
Update parser for more convenience and types security #224
David Demelier <markand@malikania.fr>
parents:
187
diff
changeset
|
252 Parser::List::const_iterator Parser::cbegin() const |
179 | 253 { |
203
1ffe6d4937b7
Update parser for more convenience and types security #224
David Demelier <markand@malikania.fr>
parents:
187
diff
changeset
|
254 return m_sections.cbegin(); |
179 | 255 } |
256 | |
203
1ffe6d4937b7
Update parser for more convenience and types security #224
David Demelier <markand@malikania.fr>
parents:
187
diff
changeset
|
257 Parser::List::iterator Parser::end() |
179 | 258 { |
203
1ffe6d4937b7
Update parser for more convenience and types security #224
David Demelier <markand@malikania.fr>
parents:
187
diff
changeset
|
259 return m_sections.end(); |
1ffe6d4937b7
Update parser for more convenience and types security #224
David Demelier <markand@malikania.fr>
parents:
187
diff
changeset
|
260 } |
1ffe6d4937b7
Update parser for more convenience and types security #224
David Demelier <markand@malikania.fr>
parents:
187
diff
changeset
|
261 |
1ffe6d4937b7
Update parser for more convenience and types security #224
David Demelier <markand@malikania.fr>
parents:
187
diff
changeset
|
262 Parser::List::const_iterator Parser::cend() const |
1ffe6d4937b7
Update parser for more convenience and types security #224
David Demelier <markand@malikania.fr>
parents:
187
diff
changeset
|
263 { |
1ffe6d4937b7
Update parser for more convenience and types security #224
David Demelier <markand@malikania.fr>
parents:
187
diff
changeset
|
264 return m_sections.end(); |
179 | 265 } |
266 | |
180 | 267 void Parser::findSections(const std::string &name, FindFunc func) const |
179 | 268 { |
203
1ffe6d4937b7
Update parser for more convenience and types security #224
David Demelier <markand@malikania.fr>
parents:
187
diff
changeset
|
269 for (const auto &s : m_sections) |
180 | 270 if (s.m_name == name) |
271 func(s); | |
179 | 272 } |
273 | |
274 bool Parser::hasSection(const std::string &name) const | |
275 { | |
203
1ffe6d4937b7
Update parser for more convenience and types security #224
David Demelier <markand@malikania.fr>
parents:
187
diff
changeset
|
276 for (const auto &s : m_sections) |
179 | 277 if (s.m_name == name) |
278 return true; | |
279 | |
280 return false; | |
281 } | |
282 | |
180 | 283 const Section &Parser::getSection(const std::string &name) const |
179 | 284 { |
203
1ffe6d4937b7
Update parser for more convenience and types security #224
David Demelier <markand@malikania.fr>
parents:
187
diff
changeset
|
285 for (const auto &s : m_sections) |
179 | 286 if (s.m_name == name) |
180 | 287 return s; |
179 | 288 |
203
1ffe6d4937b7
Update parser for more convenience and types security #224
David Demelier <markand@malikania.fr>
parents:
187
diff
changeset
|
289 throw std::out_of_range(name + " not found"); |
179 | 290 } |
291 | |
292 void Parser::log(int number, const std::string &, const std::string &message) | |
293 { | |
294 std::cout << "line " << number << ": " << message << std::endl; | |
295 } | |
205
9f22ce5f1b39
Parser: rename getValue, add operator==
David Demelier <markand@malikania.fr>
parents:
203
diff
changeset
|
296 |
9f22ce5f1b39
Parser: rename getValue, add operator==
David Demelier <markand@malikania.fr>
parents:
203
diff
changeset
|
297 bool operator==(const Parser &p1, const Parser &p2) |
9f22ce5f1b39
Parser: rename getValue, add operator==
David Demelier <markand@malikania.fr>
parents:
203
diff
changeset
|
298 { |
9f22ce5f1b39
Parser: rename getValue, add operator==
David Demelier <markand@malikania.fr>
parents:
203
diff
changeset
|
299 return p1.m_sections == p2.m_sections && |
9f22ce5f1b39
Parser: rename getValue, add operator==
David Demelier <markand@malikania.fr>
parents:
203
diff
changeset
|
300 p1.m_path == p2.m_path && |
9f22ce5f1b39
Parser: rename getValue, add operator==
David Demelier <markand@malikania.fr>
parents:
203
diff
changeset
|
301 p1.m_tuning == p2.m_tuning && |
9f22ce5f1b39
Parser: rename getValue, add operator==
David Demelier <markand@malikania.fr>
parents:
203
diff
changeset
|
302 p1.m_commentChar == p2.m_commentChar; |
9f22ce5f1b39
Parser: rename getValue, add operator==
David Demelier <markand@malikania.fr>
parents:
203
diff
changeset
|
303 } |