Changed LICENSE. Now referenced to web site and file on project root directory
[anna.git] / source / core / util / Configuration.cpp
1 // ANNA - Anna is Not Nothingness Anymore                                                         //
2 //                                                                                                //
3 // (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo                         //
4 //                                                                                                //
5 // See project site at http://redmine.teslayout.com/projects/anna-suite                           //
6 // See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
7
8
9 #include <stdio.h>
10 #include <ctype.h>
11
12 #include <algorithm>
13
14 #include <anna/core/functions.hpp>
15 #include <anna/core/util/Configuration.hpp>
16 #include <anna/core/RuntimeException.hpp>
17 #include <anna/core/tracing/Logger.hpp>
18 #include <anna/core/tracing/TraceMethod.hpp>
19
20 using namespace std;
21 using namespace anna;
22
23 const char* Configuration::defaultSection = "@global@";
24
25 void Configuration::load(const char* configFile)
26 throw(RuntimeException) {
27   LOGMETHOD(TraceMethod tm("Configuration", "load", ANNA_FILE_LOCATION));
28   char buffer [2048];
29   FILE* file;
30   char* aux;
31   string currentSection(defaultSection);
32   int nline(1);
33   removeAll();
34
35   if((file = fopen(configFile, "r")) == NULL)
36     throw RuntimeException(configFile, errno, ANNA_FILE_LOCATION);
37
38   LOGDEBUG(Logger::write(Logger::Debug, "Configuration file", configFile, ANNA_FILE_LOCATION));
39
40   try {
41     while(fgets(buffer, sizeof(buffer) - 1, file) != NULL) {
42       if((aux = strchr(buffer, '#')) != NULL)
43         * aux = 0;
44
45       if(anna_strlen(aux = strip(buffer)) <= 0)
46         continue;
47
48       if(processSection(nline, aux, currentSection) == true)
49         continue;
50
51       processVariable(nline, aux, currentSection);
52       nline ++;
53     }
54   } catch(RuntimeException& ex) {
55     fclose(file);
56     throw;
57   }
58
59   fclose(file);
60 }
61
62 bool Configuration::exists(const char* sectionName, const char* variableName) const
63 throw() {
64   const VariableEx* var = find(string(sectionName), variableName);
65   return (var == NULL) ? false : !var->isNull();
66 }
67
68 void Configuration::setDefaultValue(const char* sectionName, const char* variableName, const char* defaultValue)
69 throw(RuntimeException) {
70   string section(sectionName);
71   VariableEx* var = find(section, variableName);
72
73   if(var == NULL)
74     var = createVariable(section, variableName);
75
76   var->setDefaultValue(defaultValue);
77   LOGINFORMATION(
78     string msg(sectionName);
79     msg += "::";
80     msg += variableName;
81     msg += " (default)";
82     msg += " | Default value: ";
83     msg += defaultValue;
84     Logger::write(Logger::Information, msg, ANNA_FILE_LOCATION);
85   )
86 }
87
88 const char* Configuration::getValue(const char* sectionName, const char* variableName, const bool strict) const
89 throw(RuntimeException) {
90   const VariableEx* variable = find(string(sectionName), variableName);
91   const char* result(NULL);
92
93   if(variable == NULL) {
94     string msg("Variable ");
95     msg += sectionName;
96     msg += "::";
97     msg += variableName;
98     msg += " is not defined";
99     throw RuntimeException(msg, ANNA_FILE_LOCATION);
100   }
101
102   if(variable->isNull() == false)
103     result = variable->getStringValue();
104   else
105     result = (strict == false) ? variable->getDefaultValue() : NULL;
106
107   return result;
108 }
109
110 int Configuration::getIntegerValue(const char* sectionName, const char* variableName, const bool strict) const
111 throw(RuntimeException) {
112   return atoi(getValue(sectionName, variableName, strict));
113 }
114
115 char* Configuration::strip(char* buffer) {
116   char* result;
117   result = buffer + (anna_strlen(buffer) - 1);
118
119   while(result >= buffer && isspace(*result))
120     result --;
121
122   result[1] = 0;
123
124   for(result = buffer; *result  && isspace(*result); result ++);
125
126   return result;
127 }
128
129 bool Configuration::processSection(const int nline, char* buffer, string& currentSection) {
130   bool result(false);
131   char* end;
132   char* section;
133
134   if(*buffer == '[') {
135     if((end = strchr(buffer, ']')) != NULL) {
136       *end = 0; // JASC, antes NULL
137
138       if(anna_strlen(section = strip(++ buffer)) > 0)
139         currentSection = section;
140       else {
141         string msg("Invalid section name at line: ");
142         msg += functions::asString(nline);
143         throw RuntimeException(msg, ANNA_FILE_LOCATION);
144       }
145
146       result = true;
147     }
148   }
149
150   return result;
151 }
152
153 void Configuration::processVariable(const int nline, char* buffer, const string& currentSection)
154 throw(RuntimeException) {
155   char* variableName;
156   char* value;
157   char* aux;
158   VariableEx* variable;
159
160   if((aux = anna_strchr(buffer , '=')) == NULL)
161     return;
162
163   *aux = 0;
164
165   if(anna_strlen(variableName = strip(buffer)) <= 0) {
166     string msg("Invalid section name at line: ");
167     msg += functions::asString(nline);
168     throw RuntimeException(msg, ANNA_FILE_LOCATION);
169   }
170
171   if(anna_strlen(value = strip(aux + 1)) <= 0)
172     return;
173
174   if((variable = find(currentSection, variableName)) != NULL) {
175     if(variable->isNull() == false) {
176       string msg("Duplicated variable | Section: ");
177       msg += currentSection;
178       msg += " | Variable: ";
179       msg += variableName;
180       msg += " | Line: ";
181       msg += functions::asString(nline);
182       throw RuntimeException(msg, ANNA_FILE_LOCATION);
183     }
184   } else
185     variable = createVariable(currentSection, variableName);
186
187   variable->setValue(value);
188
189   if(Logger::isActive(Logger::Information)) {
190     string msg(currentSection);
191     msg += "::";
192     msg += variableName;
193     msg += " | Value: ";
194     msg += value;
195     Logger::write(Logger::Information, variable->asString(), ANNA_FILE_LOCATION);
196   }
197 }
198
199 Configuration::VariableEx* Configuration::createVariable(const string& section, const char* variableName)
200 throw() {
201   map <string, VariableEx::Vector*>::iterator isection(a_sections.find(section));
202   VariableEx* result;
203   VariableEx::Vector* variables;
204   result = new VariableEx(variableName);
205
206   if(isection == a_sections.end()) {
207     variables = new VariableEx::Vector;
208     a_sections [section] = variables;
209   } else
210     variables = isection->second;
211
212   variables->push_back(result);
213   return result;
214 }
215
216 Configuration::VariableEx* Configuration::find(const string& section, const char* variableName)
217 throw() {
218   VariableEx* result(NULL);
219   map <string, VariableEx::Vector*>::iterator isection(a_sections.find(section));
220
221   if(isection == a_sections.end())
222     return NULL;
223
224   VariableEx::Vector* varVector(isection->second);
225
226   for(VariableEx::Vector::iterator vv = varVector->begin(), maxvv = varVector->end(); vv != maxvv; vv ++) {
227     if(!strcmp((*vv)->getName(), variableName)) {
228       result = *vv;
229       break;
230     }
231   }
232
233   return result;
234 }
235
236 void Configuration::removeAll()
237 throw() {
238   map <string, VariableEx::Vector*>::iterator ii(a_sections.begin());
239   map <string, VariableEx::Vector*>::iterator end(a_sections.end());
240   VariableEx::Vector::iterator vv, maxvv;
241   VariableEx* variable;
242
243   for(; ii != end; ii ++) {
244     for(vv = ii->second->begin(), maxvv = ii->second->end(); vv != maxvv; vv ++) {
245       variable = *vv;
246       delete variable;
247     }
248
249     delete ii->second;
250   }
251
252   a_sections.clear();
253 }
254