Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/objecthierarchy/src/orxonox/core/ConfigValueContainer.cc @ 447

Last change on this file since 447 was 447, checked in by landauf, 16 years ago
  • added comments and doxygen-tags to the ConfigValueContainer
  • changed some comments in the other files
File size: 21.4 KB
Line 
1#include <fstream>
2#include <string>
3#include "ConfigValueContainer.h"
4
5//#define CONFIGFILEPATH "O:\\oh\\bin\\orxonox.ini"
6#define CONFIGFILEPATH "orxonox.ini"
7
8namespace orxonox
9{
10    std::list<std::string>* ConfigValueContainer::configFileLines_s = 0; // Set the static member variable configFileLines_s to zero
11    bool ConfigValueContainer::readConfigFile_s = false;                 // Set the static member variable readConfigFile_s to false
12
13    /**
14        @brief Constructor: Converts the default-value to a string, checks the config-file for a changed value, sets this->value_int_.
15        @param classname The name of the class the variable belongs to
16        @param varname The name of the variable
17        @param defvalue The default-value
18    */
19    ConfigValueContainer::ConfigValueContainer(const std::string& classname, const std::string& varname, int defvalue)
20    {
21        // Try to convert the default-value from int to string
22        std::ostringstream ostream;
23        if (ostream << defvalue)
24            this->defvalue_ = ostream.str();
25        else
26            this->defvalue_ = "0";
27
28        // Set the default values, then get the value-string
29        this->setDefaultValues(classname, varname);
30        std::string valueString = this->getValueString();
31
32        // Try to convert the value-string to int
33        std::istringstream istream(valueString);
34        if (!(istream >> this->value_int_))
35        {
36            // The conversion failed - use the default value and restore the entry in the config-file
37            this->value_int_ = defvalue;
38            (*this->configFileLine_) = this->varname_ + "=" + this->defvalue_;
39            ConfigValueContainer::writeConfigFile(CONFIGFILEPATH);
40        }
41    }
42
43    /**
44        @brief Constructor: Converts the default-value to a string, checks the config-file for a changed value, sets this->value_double_.
45        @param classname The name of the class the variable belongs to
46        @param varname The name of the variable
47        @param defvalue The default-value
48    */
49    ConfigValueContainer::ConfigValueContainer(const std::string& classname, const std::string& varname, double defvalue)
50    {
51        // Try to convert the default-value from double to string
52        std::ostringstream ostream;
53        if (ostream << defvalue)
54            this->defvalue_ = ostream.str();
55        else
56            this->defvalue_ = "0.000000";
57
58        // Set the default values, then get the value-string
59        this->setDefaultValues(classname, varname);
60        std::string valueString = this->getValueString();
61
62        // Try to convert the value-string to double
63        std::istringstream istream(valueString);
64        if (!(istream >> this->value_double_))
65        {
66            // The conversion failed - use the default value and restore the entry in the config-file
67            this->value_double_ = defvalue;
68            (*this->configFileLine_) = this->varname_ + "=" + this->defvalue_;
69            ConfigValueContainer::writeConfigFile(CONFIGFILEPATH);
70        }
71    }
72
73    /**
74        @brief Constructor: Converts the default-value to a string, checks the config-file for a changed value, sets this->value_bool_.
75        @param classname The name of the class the variable belongs to
76        @param varname The name of the variable
77        @param defvalue The default-value
78    */
79    ConfigValueContainer::ConfigValueContainer(const std::string& classname, const std::string& varname, bool defvalue)
80    {
81        // Convert the default-value from bool to string
82        if (defvalue)
83            this->defvalue_ = "true";
84        else
85            this->defvalue_ = "false";
86
87        // Set the default values, then get the value-string
88        this->setDefaultValues(classname, varname);
89        std::string valueString = this->getValueString();
90
91        // Try to parse the value-string - is it a word?
92        if (valueString.find("true") < valueString.size() || valueString.find("yes") < valueString.size())
93            this->value_bool_ = true;
94        else if (valueString.find("false") < valueString.size() || valueString.find("no") < valueString.size())
95            this->value_bool_ = false;
96        else
97        {
98            // Its not a known word - is it a number?
99            std::istringstream istream(valueString);
100            if (!(istream >> this->value_bool_))
101            {
102                // The conversion failed - use the default value and restore the entry in the config-file
103                this->value_bool_ = defvalue;
104                (*this->configFileLine_) = this->varname_ + "=" + this->defvalue_;
105                ConfigValueContainer::writeConfigFile(CONFIGFILEPATH);
106            }
107        }
108    }
109
110    /**
111        @brief Constructor: Converts the default-value to a string, checks the config-file for a changed value, sets this->value_string_.
112        @param classname The name of the class the variable belongs to
113        @param varname The name of the variable
114        @param defvalue The default-value
115    */
116    ConfigValueContainer::ConfigValueContainer(const std::string& classname, const std::string& varname, const char* defvalue)
117    {
118        // Not much to do here - just set all member-variables and check the config-file
119        this->defvalue_ = defvalue;
120        this->setDefaultValues(classname, varname);
121        this->value_string_ = this->getValueString(false);
122    }
123
124    /**
125        @brief Constructor: Converts the default-value to a string, checks the config-file for a changed value, sets this->value_vector3_.
126        @param classname The name of the class the variable belongs to
127        @param varname The name of the variable
128        @param defvalue The default-value
129    */
130    ConfigValueContainer::ConfigValueContainer(const std::string& classname, const std::string& varname, Ogre::Vector3 defvalue)
131    {
132        // Try to convert the default-value from Vector3 to string
133        std::ostringstream ostream;
134        if (ostream << "(" << defvalue.x << "," << defvalue.y << "," << defvalue.z << ")")
135            this->defvalue_ = ostream.str();
136        else
137            this->defvalue_ = "(0,0,0)";
138
139        // Set the default values, then get the value-string
140        this->setDefaultValues(classname, varname);
141        std::string valueString = this->getValueString();
142
143        // Strip the value-string
144        valueString = this->getStrippedLine(valueString);
145        unsigned int pos;
146        while ((pos = valueString.find("(")) < valueString.length())
147            valueString.erase(pos, 1);
148        while ((pos = valueString.find(")")) < valueString.length())
149            valueString.erase(pos, 1);
150        while ((pos = valueString.find(",")) < valueString.length())
151            valueString.replace(pos, 1, " ");
152
153        // Try to convert the stripped value-string to Vector3
154        std::istringstream istream(valueString);
155        if (!(istream >> this->value_vector3_.x))
156        {
157            // The conversion failed - use the default value and restore the entry in the config-file
158            this->value_vector3_.x = defvalue.x;
159            (*this->configFileLine_) = this->varname_ + "=" + this->defvalue_;
160            ConfigValueContainer::writeConfigFile(CONFIGFILEPATH);
161        }
162        if (!(istream >> this->value_vector3_.y))
163        {
164            // The conversion failed - use the default value and restore the entry in the config-file
165            this->value_vector3_.y = defvalue.y;
166            (*this->configFileLine_) = this->varname_ + "=" + this->defvalue_;
167            ConfigValueContainer::writeConfigFile(CONFIGFILEPATH);
168        }
169        if (!(istream >> this->value_vector3_.z))
170        {
171            // The conversion failed - use the default value and restore the entry in the config-file
172            this->value_vector3_.z = defvalue.z;
173            (*this->configFileLine_) = this->varname_ + "=" + this->defvalue_;
174            ConfigValueContainer::writeConfigFile(CONFIGFILEPATH);
175        }
176    }
177
178    /**
179        @brief Constructor: Converts the default-value to a string, checks the config-file for a changed value, sets this->value_colourvalue_.
180        @param classname The name of the class the variable belongs to
181        @param varname The name of the variable
182        @param defvalue The default-value
183    */
184    ConfigValueContainer::ConfigValueContainer(const std::string& classname, const std::string& varname, Ogre::ColourValue defvalue)
185    {
186        // Try to convert the default-value from ColourValue to string
187        std::ostringstream ostream;
188        if (ostream << "(" << defvalue.r << "," << defvalue.g << "," << defvalue.b << "," << defvalue.a << ")")
189            this->defvalue_ = ostream.str();
190        else
191            this->defvalue_ = "(0,0,0,0)";
192
193        // Set the default values, then get the value-string
194        this->setDefaultValues(classname, varname);
195        std::string valueString = this->getValueString();
196
197        // Strip the value-string
198        valueString = this->getStrippedLine(valueString);
199        unsigned int pos;
200        while ((pos = valueString.find("(")) < valueString.length())
201            valueString.erase(pos, 1);
202        while ((pos = valueString.find(")")) < valueString.length())
203            valueString.erase(pos, 1);
204        while ((pos = valueString.find(",")) < valueString.length())
205            valueString.replace(pos, 1, " ");
206
207        // Try to convert the stripped value-string to Vector3
208        std::istringstream istream(valueString);
209        if (!(istream >> this->value_colourvalue_.r))
210        {
211            // The conversion failed - use the default value and restore the entry in the config-file
212            this->value_colourvalue_.r = defvalue.r;
213            (*this->configFileLine_) = this->varname_ + "=" + this->defvalue_;
214            ConfigValueContainer::writeConfigFile(CONFIGFILEPATH);
215        }
216        if (!(istream >> this->value_colourvalue_.g))
217        {
218            // The conversion failed - use the default value and restore the entry in the config-file
219            this->value_colourvalue_.g = defvalue.g;
220            (*this->configFileLine_) = this->varname_ + "=" + this->defvalue_;
221            ConfigValueContainer::writeConfigFile(CONFIGFILEPATH);
222        }
223        if (!(istream >> this->value_colourvalue_.b))
224        {
225            // The conversion failed - use the default value and restore the entry in the config-file
226            this->value_colourvalue_.b = defvalue.b;
227            (*this->configFileLine_) = this->varname_ + "=" + this->defvalue_;
228            ConfigValueContainer::writeConfigFile(CONFIGFILEPATH);
229        }
230        if (!(istream >> this->value_colourvalue_.a))
231        {
232            // The conversion failed - use the default value and restore the entry in the config-file
233            this->value_colourvalue_.a = defvalue.a;
234            (*this->configFileLine_) = this->varname_ + "=" + this->defvalue_;
235            ConfigValueContainer::writeConfigFile(CONFIGFILEPATH);
236        }
237    }
238
239    /**
240        @brief Sets the default values of the container and searches the coresponding entry in the config-file.
241        @param classname The name of the class the variable belongs to
242        @param varname The name of the variable
243    */
244    void ConfigValueContainer::setDefaultValues(const std::string& classname, const std::string& varname)
245    {
246        // Set the class and variable names
247        this->classname_ = classname;
248        this->varname_ = varname;
249
250        // Search the entry in the config-file
251        this->searchConfigFileLine();
252
253        // Set the values of all types to zero
254        this->value_int_ = 0;
255        this->value_double_ = 0.000000;
256        this->value_bool_ = false;
257        this->value_string_ = "";
258        this->value_vector3_ = Ogre::Vector3(0, 0, 0);
259        this->value_colourvalue_ = Ogre::ColourValue(0, 0, 0, 0);
260    }
261
262    /**
263        @brief Searches the corresponding entry in the config-file and creates it, if there is no entry.
264    */
265    void ConfigValueContainer::searchConfigFileLine()
266    {
267        // Read the file if needed
268        if (!ConfigValueContainer::readConfigFile_s)
269            ConfigValueContainer::readConfigFile(CONFIGFILEPATH);
270
271        // Just in case something goes wrong
272        this->configFileLine_ = 0;
273
274        // The string of the section we're searching
275        std::string section = "";
276        section.append("[");
277        section.append(this->classname_);
278        section.append("]");
279
280        // Iterate through all config-file-lines
281        bool success = false;
282        std::list<std::string>::iterator it1;
283        for(it1 = ConfigValueContainer::configFileLines_s->begin(); it1 != ConfigValueContainer::configFileLines_s->end(); ++it1)
284        {
285            // Don't try to parse comments
286            if (this->isComment(*it1))
287                continue;
288
289            if ((*it1).find(section) < (*it1).length())
290            {
291                // We found the right section
292                bool bLineIsEmpty = false;
293                std::list<std::string>::iterator positionToPutNewLineAt;
294
295                // Iterate through all lines in the section
296                std::list<std::string>::iterator it2;
297                for(it2 = ++it1; it2 != ConfigValueContainer::configFileLines_s->end(); ++it2)
298                {
299                    // Don't try to parse comments
300                    if (this->isComment(*it2))
301                        continue;
302
303                    // This if-else block is used to write a new line right after the last line of the
304                    // section but in front of the following empty lines before the next section.
305                    // (So this helps to keep a nice formatting with empty-lines between sections in the config-file)
306                    if (this->isEmpty(*it2))
307                    {
308                        if (!bLineIsEmpty)
309                        {
310                            bLineIsEmpty = true;
311                            positionToPutNewLineAt = it2;
312                        }
313                    }
314                    else
315                    {
316                        if (!bLineIsEmpty)
317                            positionToPutNewLineAt = it2;
318
319                        bLineIsEmpty = false;
320                    }
321
322                    // Look out for the beginning of the next section
323                    unsigned int open = (*it2).find("[");
324                    unsigned int close = (*it2).find("]");
325                    if ((open < (*it2).length()) && (close < (*it2).length()) && (open < close))
326                    {
327                        // The next section startet, so our line isn't yet in the file - now we add it and safe the file
328                        this->configFileLine_ = this->configFileLines_s->insert(positionToPutNewLineAt, this->varname_ + "=" + this->defvalue_);
329                        ConfigValueContainer::writeConfigFile(CONFIGFILEPATH);
330                        success = true;
331                        break;
332                    }
333
334                    // Look out for the variable-name
335                    if ((*it2).find(this->varname_) < (*it2).length())
336                    {
337                        // We found the right line - safe it and return
338                        this->configFileLine_ = it2;
339                        success = true;
340                        break;
341                    }
342                }
343
344                // Check if we succeeded
345                if (!success)
346                {
347                    // Looks like we found the right section, but the file ended without containing our variable - so we add it and safe the file
348                    this->configFileLine_ = this->configFileLines_s->insert(positionToPutNewLineAt, this->varname_ + "=" + this->defvalue_);
349                    ConfigValueContainer::writeConfigFile(CONFIGFILEPATH);
350                    success = true;
351                }
352                break;
353            }
354        }
355
356        // Check if we succeeded
357        if (!success)
358        {
359            // We obviously didn't found the right section, so we'll create it
360            this->configFileLines_s->push_back("[" + this->classname_ + "]");           // Create the section
361            this->configFileLines_s->push_back(this->varname_ + "=" + this->defvalue_); // Create the line
362            this->configFileLine_ = --this->configFileLines_s->end();                   // Set the pointer to the last element
363            success = true;
364            this->configFileLines_s->push_back("");                                     // Add an empty line - this is needed for the algorithm in the searchConfigFileLine-function
365            ConfigValueContainer::writeConfigFile(CONFIGFILEPATH);                      // Save the changed config-file
366        }
367    }
368
369    /**
370        @brief Determines if a line in the config-file is a comment.
371        @param line The line to check
372        @return True = it's a comment
373    */
374    bool ConfigValueContainer::isComment(const std::string& line)
375    {
376        // Strip the line, whitespaces are disturbing
377        std::string teststring = getStrippedLine(line);
378
379        // There are four possible comment-symbols:
380        //  1) #comment in script-language style
381        //  2) %comment in matlab style
382        //  3) ;comment in unreal tournament config-file style
383        //  4) //comment in code style
384        if (teststring[0] == '#' || teststring[0] == '%' || teststring[0] == ';' || (teststring[0] == '/' && teststring[0] == '/'))
385            return true;
386
387        return false;
388    }
389
390    /**
391        @brief Determines if a line in the config-file is empty (contains only whitespaces).
392        @param line The line to check
393        @return True = it's empty
394    */
395    bool ConfigValueContainer::isEmpty(const std::string& line)
396    {
397        return getStrippedLine(line) == "";
398    }
399
400    /**
401        @brief Removes all whitespaces from a line.
402        @param line The line to strip
403        @return The stripped line
404    */
405    std::string ConfigValueContainer::getStrippedLine(const std::string& line)
406    {
407        std::string output = line;
408        unsigned int pos;
409        while ((pos = output.find(" ")) < output.length())
410            output.erase(pos, 1);
411
412        return output;
413    }
414
415    /**
416        @brief Returns the part in the corresponding config-file-entry of the container that defines the value.
417        @param bStripped True = strip the value-string
418        @return The value-string
419    */
420    std::string ConfigValueContainer::getValueString(bool bStripped)
421    {
422        std::string output;
423        if (bStripped)
424            output = this->getStrippedLine(*this->configFileLine_);
425        else
426            output = *this->configFileLine_;
427
428        return output.substr(output.find("=") + 1);
429    }
430
431    /**
432        @brief Reads the config-file and stores the lines in a list.
433        @param filename The name of the config-file
434    */
435    void ConfigValueContainer::readConfigFile(const std::string& filename)
436    {
437        ConfigValueContainer::readConfigFile_s = true;
438
439        // Create the list if needed
440        if (!ConfigValueContainer::configFileLines_s)
441            ConfigValueContainer::configFileLines_s = new std::list<std::string>;
442
443        // This creates the file if it's not existing
444        std::ofstream createFile;
445        createFile.open(filename.c_str(), std::fstream::app);
446        createFile.close();
447
448        // Open the file
449        std::ifstream file;
450        file.open(filename.c_str(), std::fstream::in);
451
452        char line[1024];
453
454        // Iterate through the file and add the lines into the list
455        while (file.good() && !file.eof())
456        {
457            file.getline(line, 1024);
458            ConfigValueContainer::configFileLines_s->push_back(line);
459//            std::cout << "### ->" << line << "<- : empty: " << isEmpty(line) << " comment: " << isComment(line) << std::endl;
460        }
461
462        // The last line is useless
463        ConfigValueContainer::configFileLines_s->pop_back();
464
465        // Add an empty line to the end of the file if needed
466        // this is needed for the algorithm in the searchConfigFileLine-function
467        if ((ConfigValueContainer::configFileLines_s->size() > 0) && !isEmpty(*ConfigValueContainer::configFileLines_s->rbegin()))
468        {
469//            std::cout << "### newline added" << std::endl;
470            ConfigValueContainer::configFileLines_s->push_back("");
471        }
472
473        file.close();
474    }
475
476    /**
477        @param Writes the content of the list, containing all lines of the config-file, into the config-file.
478        @param filename The name of the config-file
479    */
480    void ConfigValueContainer::writeConfigFile(const std::string& filename)
481    {
482        // Make sure we stored the config-file in the list
483        if (!ConfigValueContainer::readConfigFile_s)
484            ConfigValueContainer::readConfigFile(filename);
485
486        // Open the file
487        std::ofstream file;
488        file.open(filename.c_str(), std::fstream::out);
489
490        // Iterate through the list an write the lines into the file
491        std::list<std::string>::iterator it;
492        for(it = ConfigValueContainer::configFileLines_s->begin(); it != ConfigValueContainer::configFileLines_s->end(); ++it)
493        {
494            file << (*it) << std::endl;
495        }
496
497        file.close();
498    }
499}
Note: See TracBrowser for help on using the repository browser.