OpenASIP 2.2
Loading...
Searching...
No Matches
ConfigurationFile.cc
Go to the documentation of this file.
1/*
2 Copyright (c) 2002-2009 Tampere University.
3
4 This file is part of TTA-Based Codesign Environment (TCE).
5
6 Permission is hereby granted, free of charge, to any person obtaining a
7 copy of this software and associated documentation files (the "Software"),
8 to deal in the Software without restriction, including without limitation
9 the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 and/or sell copies of the Software, and to permit persons to whom the
11 Software is furnished to do so, subject to the following conditions:
12
13 The above copyright notice and this permission notice shall be included in
14 all copies or substantial portions of the Software.
15
16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 DEALINGS IN THE SOFTWARE.
23 */
24/**
25 * @file ConfigurationFile.cc
26 *
27 * Definition of ConfigurationFile class.
28 *
29 * @author Jussi Nykänen 2004 (nykanen-no.spam-cs.tut.fi)
30 * @author Pekka Jääskeläinen 2007 (pjaaskel-no.spam-cs.tut.fi)
31 * @note rating: red
32 */
33
34#ifdef _GLIBCXX_DEBUG
35// boost::match produces errors when this is defined, try with Boost 1.34 or
36// higher if it has been fixed
37#undef _GLIBCXX_DEBUG
38#endif
39
40#include "CompilerWarnings.hh"
41IGNORE_CLANG_WARNING("-Wkeyword-macro")
42#include <boost/regex.hpp>
44
45#include <ctime>
46#include <fstream>
47
48#include <string>
49#include <iostream>
50#include <vector>
51
52#include "ConfigurationFile.hh"
53#include "Conversion.hh"
54#include "StringTools.hh"
55#include "MapTools.hh"
56#include "TCEString.hh"
57
58using std::tm;
59using std::mktime;
60using std::ifstream;
61using std::string;
62using std::cout;
63using std::endl;
64using std::vector;
65
66/**
67 * Constructor.
68 *
69 * @param doChecking If true, checks the semantics of the configuration file
70 * while reading it.
71 */
72ConfigurationFile::ConfigurationFile(bool doChecking) : check_(doChecking) {
73}
74
75/**
76 * Destructor.
77 */
81
82/**
83 * Parses the configuration file and stores the results to internal structure.
84 *
85 * @param inputStream Input file stream.
86 */
87void
88ConfigurationFile::load(std::istream& inputStream) {
89 parse(inputStream);
90}
91
92/**
93 * Returns true if there is a given key with a value in configuration.
94 *
95 * @param key The key.
96 * @return True if there is a given key in a configuration.
97 */
98bool
99ConfigurationFile::hasKey(const std::string& key) {
100 ValueContainer::iterator iter = values_.find(key);
101 return iter != values_.end();
102}
103
104/**
105 * Returns the value of the given key.
106 *
107 * @param key The key.
108 * @param index The index of the value.
109 * @return The value of the given key.
110 * @exception KeyNotFound If key is not found.
111 * @exception OutOfRange If index is out of range.
112 */
113std::string
114ConfigurationFile::value(const std::string& key, int index) {
115 return valueOfKey(key, index);
116}
117
118/**
119 * Returns the number of values a given key has.
120 *
121 * @param key The key.
122 * @return The number of values key has.
123 * @exception KeyNotFound If key is not found.
124 */
125int
126ConfigurationFile::itemCount(const std::string& key) {
127 ValueContainer::iterator iter = values_.find(key);
128 if (iter == values_.end()) {
129 string msg = "Key " + key + " not found";
130 throw KeyNotFound(__FILE__, __LINE__, __func__, msg);
131 }
132 return (*iter).second.size();
133}
134
135/**
136 * Returns the int value of the given key.
137 *
138 * @param key The key.
139 * @param index The index of the value.
140 * @return The int value of the key.
141 * @exception KeyNotFound If key is not found.
142 * @exception OutOfRange If index is out of range.
143 * @exception InvalidData If data is wrong type.
144 */
145int
146ConfigurationFile::intValue(const std::string& key, int index) {
147 string value = valueOfKey(key, index);
148 try {
149 return Conversion::toInt(value);
150 } catch (const NumberFormatException& n) {
151 string msg = "Wrong type of value: " + value;
152 throw InvalidData(__FILE__, __LINE__, __func__, msg);
153 }
154}
155
156/**
157 * Returns the float value of the given key.
158 *
159 * @param key The key.
160 * @param index The index of the value.
161 * @return The float value of the given key.
162 * @exception KeyNotFound If key is not found.
163 * @exception OutOfRange If index is out of range.
164 * @exception InvalidData If data is wrong type.
165 */
166float
167ConfigurationFile::floatValue(const std::string& key, int index) {
168 string value = valueOfKey(key, index);
169 try {
171 } catch (const NumberFormatException& n) {
172 string msg = "Wrong type of value: " + value;
173 throw InvalidData(__FILE__, __LINE__, __func__, msg);
174 }
175}
176
177/**
178 * Returns string value of the given key.
179 *
180 * @param key The key.
181 * @param index The index of the value.
182 * @return The string value of the given key.
183 * @exception KeyNotFound If key is not found.
184 * @exception OutOfRange If index is out of range.
185 */
186string
187ConfigurationFile::stringValue(const std::string& key, int index) {
188 return valueOfKey(key, index);
189}
190
191/**
192 * Returns the boolean value of the given key.
193 *
194 * @param key The key.
195 * @param index The index of the value.
196 * @return The boolean value of the key.
197 * @exception KeyNotFound If key is not found.
198 * @exception OutOfRange If index is out of range.
199 * @exception InvalidData If value type is wrong.
200 */
201bool
202ConfigurationFile::booleanValue(const std::string& key, int index) {
203 string value = valueOfKey(key, index);
205 if (value == "true" || value == "yes" || value == "on" ||
206 value == "enabled" || value == "1") {
207
208 return true;
209 } else if (value == "false" || value == "no" || value == "off" ||
210 value == "disabled" || value == "0") {
211
212 return false;
213 } else {
214 string msg = "Wrong type of value: " + value;
215 throw InvalidData(__FILE__, __LINE__, __func__, msg);
216 return false;
217 }
218}
219
220/**
221 * Returns the time stamp value of the given key.
222 *
223 * @param key The key.
224 * @return The time stamp value.
225 * @exception KeyNotFound If key is not found.
226 */
227unsigned int
228ConfigurationFile::timeStampValue(const std::string& key) {
229 ValueContainer::iterator iter = values_.find(key);
230 if (iter == values_.end()) {
231 string msg = "Key " + key + " not found";
232 throw KeyNotFound(__FILE__, __LINE__, __func__, msg);
233 }
234
235 string value = "";
236 for (size_t i = 0; i < (*iter).second.size(); i++) {
237 value += (*iter).second[i] + " ";
238 }
239
241
242 if (!legalTime(value)) {
243 return 0;
244 }
245
246 size_t pos = value.find("-");
247 string year = value.substr(0, pos);
248 value.replace(0, pos + 1, "");
249
250 pos = value.find("-");
251 string month = value.substr(0, pos);
252 value.replace(0, pos + 1, "");
253
254 pos = value.find(" ");
255 string day = value.substr(0, pos);
256 value.replace(0, pos + 1, "");
257
258 pos = value.find(":");
259 string hours = value.substr(0, pos);
260 value.replace(0, pos + 1, "");
261
262 string minutes = value;
263
264 time_t rawtime;
265 tm* timeinfo;
266
267 time(&rawtime);
268 timeinfo = localtime (&rawtime);
269
270 int temp = Conversion::toInt(year);
271 timeinfo->tm_year = temp - 1900;
272 temp = Conversion::toInt(month);
273 timeinfo->tm_mon = temp - 1;
274 temp = Conversion::toInt(day);
275 timeinfo->tm_mday = temp;
276 temp = Conversion::toInt(hours);
277 timeinfo->tm_hour = temp;
278 temp = Conversion::toInt(minutes);
279 timeinfo->tm_min = temp;
280
281 return mktime(timeinfo);
282}
283
284/**
285 * Add supported key type.
286 *
287 * @param key Key to be added.
288 * @param type Type of the value.
289 * @param caseSensitive True if key is case sensitive.
290 */
291void
293 const std::string& key,
295 bool caseSensitive) {
296
297 Key* k = new Key();
298 k->name_ = key;
299 k->caseSensitive_ = caseSensitive;
300
301 keys_[k] = type;
302}
303
304/**
305 * Default implementation, all errors are handled.
306 *
307 * @return True.
308 */
309bool
311 int,
313 const std::string&) {
314
315 return true;
316}
317
318/**
319 * Parses the configuration file.
320 *
321 * @param inputStream Stream where file is read from.
322 */
323void
324ConfigurationFile::parse(std::istream& inputStream) {
325
326 string line = "";
327 int lineNumber = 1;
328 while (getline(inputStream, line)) {
329 line = StringTools::trim(line);
330
331 if (isComment(line) || line == "") {
332 lineNumber++;
333 continue;
334 } else {
335 const char* regExp = "[ ]*(.+)[ ]*=[ ]*(.+)[ ]*";
336 boost::regex expression(regExp);
337 boost::smatch what;
338 if (!boost::regex_match(line, what, expression)) {
339 if (!handleError(lineNumber, FE_SYNTAX, line)) {
340 return;
341 } else {
342 lineNumber++;
343 continue;
344 }
345 }
346
347 TCEString key = std::string(what[1]);
348 TCEString value = std::string(what[2]);
349 key = StringTools::trim(key);
351
352 vector<TCEString> values = StringTools::chopString(value, " ");
353
354 if (value == "") {
355 if (!handleError(lineNumber, FE_MISSING_VALUE, line)) {
356 return;
357 } else {
358 lineNumber++;
359 continue;
360 }
361 }
362
363 if (check_) {
364 if (!checkSemantics(key, value, lineNumber, line)) {
365 return;
366 }
367 }
368 ValueContainer::iterator iter = values_.find(key);
369 if (iter == values_.end()) {
370 values_[key] = values;
371 } else {
372 for (size_t i = 0; i < values.size(); i++) {
373 (*iter).second.push_back(values[i]);
374 }
375 }
376 }
377 lineNumber++;
378 }
379}
380
381/**
382 * Returns true if line is a comment.
383 *
384 * @param line Line to be checked.
385 * @return True if line is a comment.
386 */
387bool
388ConfigurationFile::isComment(const std::string& line) {
389 if (line.substr(0, 1) == "#") {
390 return true;
391 } else {
392 return false;
393 }
394}
395
396/**
397 * Check the semantics of key value pair.
398 *
399 * @param key The key.
400 * @param value The value.
401 * @param lineNumber The line number.
402 * @param line The line.
403 * @return True if semantics are ok, otherwise false.
404 */
405bool
407 const std::string& key,
408 const std::string& value,
409 int lineNumber,
410 const std::string& line) {
411
412 KeyContainer::iterator iter = keys_.begin();
413 while (iter != keys_.end()) {
414 Key* current = (*iter).first;
415 if (current->caseSensitive_) {
416 if (current->name_ == key) {
417 break;
418 }
419 } else {
420 if (StringTools::stringToUpper(current->name_) ==
422 break;
423 }
424 }
425 iter++;
426 }
427
428 if (iter == keys_.end()) {
429 return handleError(lineNumber, FE_UNKNOWN_KEY, line);
430 }
431
432 ConfigurationValueType type = (*iter).second;
433 switch (type) {
434 case VT_INTEGER:
435 try {
437 } catch (const NumberFormatException& n) {
438 return handleError(lineNumber, FE_ILLEGAL_TYPE, line);
439 }
440 break;
441 case VT_FLOAT:
442 try {
444 } catch (const NumberFormatException& n) {
445 return handleError(lineNumber, FE_ILLEGAL_TYPE, line);
446 }
447 break;
448 case VT_BOOLEAN:
449 if (value != "true" && value != "yes" && value != "on" &&
450 value != "enable" && value != "1" && value != "false" &&
451 value != "no" && value != "off" && value != "disable" &&
452 value != "0") {
453
454 return handleError(lineNumber, FE_ILLEGAL_TYPE, line);
455 }
456 break;
457 case VT_READABLE_TIME:
458 if (!legalTime(value)) {
459 return handleError(lineNumber, FE_ILLEGAL_TYPE, line);
460 }
461 break;
463 try {
465 } catch (const NumberFormatException& n) {
466 return handleError(lineNumber, FE_ILLEGAL_TYPE, line);
467 }
468 break;
469 default:
470 break;
471 }
472
473 return true;
474}
475
476/**
477 * Returns true if string is a legal time representation.
478 *
479 * @param line Line to be checked.
480 * @return True if string is legal time, false otherwise.
481 */
482bool
483ConfigurationFile::legalTime(const std::string& line) {
484
485 const char* regExp = "([0-9]{4})-([0-9]{1,2})-([0-9]{1,2}) ([0-9]{1,2}):([0-9]{2})";
486 boost::regex expression(regExp);
487 boost::smatch what;
488 if (!boost::regex_match(line, what, expression)) {
489 return false;
490 } else {
491 return true;
492 }
493}
494
495/**
496 * Returns the value of the given key and a given index.
497 *
498 * @param key The key.
499 * @param index Index of the value.
500 * @return The value of the key.
501 * @exception KeyNotFound If key is not found.
502 * @exception OutOfRange If index is out of range.
503 */
504string
505ConfigurationFile::valueOfKey(const std::string& key, int index) {
506 ValueContainer::iterator iter = values_.find(key);
507 if (iter == values_.end()) {
508 string msg = "Key " + key + " not found";
509 throw KeyNotFound(__FILE__, __LINE__, __func__, msg);
510 }
511
512 if (index < 0 || index > static_cast<int>((*iter).second.size()) - 1) {
513 string msg = "Index out of range.";
514 throw OutOfRange(__FILE__, __LINE__, __func__, msg);
515 }
516 return (*iter).second[index];
517}
#define __func__
#define POP_CLANG_DIAGS
#define IGNORE_CLANG_WARNING(X)
virtual bool handleError(int lineNumber, ConfigurationFileError error, const std::string &line)
void addSupportedKey(const std::string &key, ConfigurationValueType type, bool caseSensitive=false)
bool checkSemantics(const std::string &key, const std::string &value, int lineNumber, const std::string &line)
void load(std::istream &inputStream)
bool isComment(const std::string &line)
KeyContainer keys_
Contains all the legal keys of the configuration file.
unsigned int timeStampValue(const std::string &key)
int itemCount(const std::string &key)
bool legalTime(const std::string &line)
int intValue(const std::string &key, int index=0)
bool check_
True if semantics of the configuration file is checked.
std::string valueOfKey(const std::string &key, int index)
ConfigurationFile(bool doChecking=false)
ValueContainer values_
Contains all the values of configuration file.
bool hasKey(const std::string &key)
bool booleanValue(const std::string &key, int index=0)
std::string stringValue(const std::string &key, int index=0)
@ FE_UNKNOWN_KEY
Unknown key error.
@ FE_SYNTAX
Syntax error.
@ FE_MISSING_VALUE
Missing value error.
@ FE_ILLEGAL_TYPE
Illegal type error.
void parse(std::istream &inputStream)
@ VT_UNIX_TIMESTAMP
Time as seconds since starting of 1970.
@ VT_READABLE_TIME
Time in readable format.
@ VT_BOOLEAN
Boolean value.
@ VT_INTEGER
Integer value.
float floatValue(const std::string &key, int index=0)
std::string value(const std::string &key, int index=0)
static float toFloat(const T &source)
static int toInt(const T &source)
static void deleteAllKeys(MapType &aMap)
static std::string stringToUpper(const std::string &source)
static std::string stringToLower(const std::string &source)
static std::string trim(const std::string &source)
static std::vector< TCEString > chopString(const std::string &source, const std::string &delimiters)
std::string name_
Name of the key.
bool caseSensitive_
True if name is case sensitive.