OpenASIP  2.0
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"
41 IGNORE_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 
58 using std::tm;
59 using std::mktime;
60 using std::ifstream;
61 using std::string;
62 using std::cout;
63 using std::endl;
64 using std::vector;
65 
66 /**
67  * Constructor.
68  *
69  * @param doChecking If true, checks the semantics of the configuration file
70  * while reading it.
71  */
72 ConfigurationFile::ConfigurationFile(bool doChecking) : check_(doChecking) {
73 }
74 
75 /**
76  * Destructor.
77  */
80 }
81 
82 /**
83  * Parses the configuration file and stores the results to internal structure.
84  *
85  * @param inputStream Input file stream.
86  */
87 void
88 ConfigurationFile::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  */
98 bool
99 ConfigurationFile::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  */
113 std::string
114 ConfigurationFile::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  */
125 int
126 ConfigurationFile::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  */
145 int
146 ConfigurationFile::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  */
166 float
167 ConfigurationFile::floatValue(const std::string& key, int index) {
168  string value = valueOfKey(key, index);
169  try {
170  return Conversion::toFloat(value);
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  */
186 string
187 ConfigurationFile::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  */
201 bool
202 ConfigurationFile::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  */
227 unsigned int
228 ConfigurationFile::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  */
291 void
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  */
309 bool
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  */
323 void
324 ConfigurationFile::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  */
387 bool
388 ConfigurationFile::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  */
405 bool
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;
462  case VT_UNIX_TIMESTAMP:
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  */
482 bool
483 ConfigurationFile::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  */
504 string
505 ConfigurationFile::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 }
ConfigurationFile::ConfigurationValueType
ConfigurationValueType
Definition: ConfigurationFile.hh:73
ConfigurationFile::Key::caseSensitive_
bool caseSensitive_
True if name is case sensitive.
Definition: ConfigurationFile.hh:130
ConfigurationFile::ConfigurationFile
ConfigurationFile(bool doChecking=false)
Definition: ConfigurationFile.cc:72
ConfigurationFile::booleanValue
bool booleanValue(const std::string &key, int index=0)
Definition: ConfigurationFile.cc:202
ConfigurationFile::itemCount
int itemCount(const std::string &key)
Definition: ConfigurationFile.cc:126
ConfigurationFile::handleError
virtual bool handleError(int lineNumber, ConfigurationFileError error, const std::string &line)
Definition: ConfigurationFile.cc:310
MapTools::deleteAllKeys
static void deleteAllKeys(MapType &aMap)
POP_CLANG_DIAGS
#define POP_CLANG_DIAGS
Definition: CompilerWarnings.hh:96
NumberFormatException
Definition: Exception.hh:421
ConfigurationFile::parse
void parse(std::istream &inputStream)
Definition: ConfigurationFile.cc:324
ConfigurationFile::floatValue
float floatValue(const std::string &key, int index=0)
Definition: ConfigurationFile.cc:167
OutOfRange
Definition: Exception.hh:320
MapTools.hh
IGNORE_CLANG_WARNING
#define IGNORE_CLANG_WARNING(X)
Definition: CompilerWarnings.hh:85
ConfigurationFile::VT_UNIX_TIMESTAMP
@ VT_UNIX_TIMESTAMP
Time as seconds since starting of 1970.
Definition: ConfigurationFile.hh:79
ConfigurationFile::VT_INTEGER
@ VT_INTEGER
Integer value.
Definition: ConfigurationFile.hh:74
ConfigurationFile::values_
ValueContainer values_
Contains all the values of configuration file.
Definition: ConfigurationFile.hh:136
ConfigurationFile::check_
bool check_
True if semantics of the configuration file is checked.
Definition: ConfigurationFile.hh:134
ConfigurationFile::FE_UNKNOWN_KEY
@ FE_UNKNOWN_KEY
Unknown key error.
Definition: ConfigurationFile.hh:88
ConfigurationFile::isComment
bool isComment(const std::string &line)
Definition: ConfigurationFile.cc:388
ConfigurationFile::VT_FLOAT
@ VT_FLOAT
Float value.
Definition: ConfigurationFile.hh:75
ConfigurationFile::value
std::string value(const std::string &key, int index=0)
Definition: ConfigurationFile.cc:114
ConfigurationFile::Key::name_
std::string name_
Name of the key.
Definition: ConfigurationFile.hh:128
TCEString.hh
StringTools::stringToUpper
static std::string stringToUpper(const std::string &source)
Definition: StringTools.cc:143
StringTools.hh
ConfigurationFile::legalTime
bool legalTime(const std::string &line)
Definition: ConfigurationFile.cc:483
InvalidData
Definition: Exception.hh:149
ConfigurationFile::VT_BOOLEAN
@ VT_BOOLEAN
Boolean value.
Definition: ConfigurationFile.hh:77
Conversion.hh
ConfigurationFile::~ConfigurationFile
virtual ~ConfigurationFile()
Definition: ConfigurationFile.cc:78
__func__
#define __func__
Definition: Application.hh:67
ConfigurationFile::FE_SYNTAX
@ FE_SYNTAX
Syntax error.
Definition: ConfigurationFile.hh:86
ConfigurationFile::ConfigurationFileError
ConfigurationFileError
Definition: ConfigurationFile.hh:85
ConfigurationFile.hh
ConfigurationFile::keys_
KeyContainer keys_
Contains all the legal keys of the configuration file.
Definition: ConfigurationFile.hh:138
ConfigurationFile::checkSemantics
bool checkSemantics(const std::string &key, const std::string &value, int lineNumber, const std::string &line)
Definition: ConfigurationFile.cc:406
ConfigurationFile::FE_ILLEGAL_TYPE
@ FE_ILLEGAL_TYPE
Illegal type error.
Definition: ConfigurationFile.hh:87
StringTools::trim
static std::string trim(const std::string &source)
Definition: StringTools.cc:55
ConfigurationFile::load
void load(std::istream &inputStream)
Definition: ConfigurationFile.cc:88
TCEString
Definition: TCEString.hh:53
ConfigurationFile::intValue
int intValue(const std::string &key, int index=0)
Definition: ConfigurationFile.cc:146
StringTools::chopString
static std::vector< TCEString > chopString(const std::string &source, const std::string &delimiters)
Definition: StringTools.cc:181
KeyNotFound
Definition: Exception.hh:285
ConfigurationFile::timeStampValue
unsigned int timeStampValue(const std::string &key)
Definition: ConfigurationFile.cc:228
Conversion::toInt
static int toInt(const T &source)
ConfigurationFile::hasKey
bool hasKey(const std::string &key)
Definition: ConfigurationFile.cc:99
ConfigurationFile::addSupportedKey
void addSupportedKey(const std::string &key, ConfigurationValueType type, bool caseSensitive=false)
Definition: ConfigurationFile.cc:292
ConfigurationFile::stringValue
std::string stringValue(const std::string &key, int index=0)
Definition: ConfigurationFile.cc:187
ConfigurationFile::FE_MISSING_VALUE
@ FE_MISSING_VALUE
Missing value error.
Definition: ConfigurationFile.hh:89
StringTools::stringToLower
static std::string stringToLower(const std::string &source)
Definition: StringTools.cc:160
CompilerWarnings.hh
ConfigurationFile::valueOfKey
std::string valueOfKey(const std::string &key, int index)
Definition: ConfigurationFile.cc:505
Conversion::toFloat
static float toFloat(const T &source)
ConfigurationFile::VT_READABLE_TIME
@ VT_READABLE_TIME
Time in readable format.
Definition: ConfigurationFile.hh:78
ConfigurationFile::Key
Definition: ConfigurationFile.hh:122