Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/FICN/src/orxonox/core/ConfigValueContainer.cc @ 497

Last change on this file since 497 was 497, checked in by landauf, 16 years ago

added the new files from objecthierarchy

File size: 27.1 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_.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_.value_int_))
35        {
36            // The conversion failed - use the default value and restore the entry in the config-file
37            this->value_.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_.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_.value_double_))
65        {
66            // The conversion failed - use the default value and restore the entry in the config-file
67            this->value_.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_.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_.value_bool_ = true;
94        else if (valueString.find("false") < valueString.size() || valueString.find("no") < valueString.size())
95            this->value_.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_.value_bool_))
101            {
102                // The conversion failed - use the default value and restore the entry in the config-file
103                this->value_.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        // Convert the string to a "config-file-string" with quotes
119        this->defvalue_ = "\"" + std::string(defvalue) + "\"";
120
121        // Set the default-values, then get the value-string
122        this->setDefaultValues(classname, varname);
123        std::string valueString = this->getValueString(false);
124
125        // Strip the quotes
126        unsigned int pos1 = valueString.find("\"") + 1;
127        unsigned int pos2 = valueString.find("\"", pos1);
128
129        // Check if the entry was correctly quoted
130        if (pos1 < valueString.length() && pos2 < valueString.length() && !(valueString.find("\"", pos2 + 1) < valueString.length()))
131        {
132            // It was - get the string between the quotes
133            valueString = valueString.substr(pos1, pos2 - pos1);
134            this->value_string_ = valueString;
135        }
136        else
137        {
138            // It wasn't - use the default-value and restore the entry in the config-file.
139            this->value_string_ = defvalue;
140            (*this->configFileLine_) = this->varname_ + "=" + this->defvalue_;
141            ConfigValueContainer::writeConfigFile(CONFIGFILEPATH);
142        }
143    }
144
145    /**
146        @brief Constructor: Converts the default-value to a string, checks the config-file for a changed value, sets this->value_vector2_.
147        @param classname The name of the class the variable belongs to
148        @param varname The name of the variable
149        @param defvalue The default-value
150    */
151    ConfigValueContainer::ConfigValueContainer(const std::string& classname, const std::string& varname, Ogre::Vector2 defvalue)
152    {
153        // Try to convert the default-value from Vector2 to string
154        std::ostringstream ostream;
155        if (ostream << "(" << defvalue.x << "," << defvalue.y << ")")
156            this->defvalue_ = ostream.str();
157        else
158            this->defvalue_ = "(0,0)";
159
160        // Set the default values, then get the value-string
161        this->setDefaultValues(classname, varname);
162        std::string valueString = this->getValueString();
163
164        // Strip the value-string
165        bool bEntryIsCorrupt = false;
166        valueString = this->getStrippedLine(valueString);
167        unsigned int pos1, pos2, pos3;
168        pos1 = valueString.find("(");
169        if (pos1 == 0)
170            valueString.erase(pos1, 1);
171        else
172            bEntryIsCorrupt = true;
173
174        pos2 = valueString.find(")");
175        if (pos2 == valueString.length() - 1)
176            valueString.erase(pos2, 1);
177        else
178            bEntryIsCorrupt = true;
179
180        int count = 0;
181        while ((pos3 = valueString.find(",")) < valueString.length())
182        {
183            count++;
184            valueString.replace(pos3, 1, " ");
185            if (pos3 < pos1)
186                bEntryIsCorrupt = true;
187        }
188
189        if (count != 1)
190            bEntryIsCorrupt = true;
191
192        // Try to convert the stripped value-string to Vector2
193        if (!bEntryIsCorrupt)
194        {
195            std::istringstream istream(valueString);
196            if (!(istream >> this->value_vector2_.x))
197            {
198                // The conversion failed - use the default value and restore the entry in the config-file
199                this->value_vector2_.x = defvalue.x;
200                (*this->configFileLine_) = this->varname_ + "=" + this->defvalue_;
201                ConfigValueContainer::writeConfigFile(CONFIGFILEPATH);
202            }
203            if (!(istream >> this->value_vector2_.y))
204            {
205                // The conversion failed - use the default value and restore the entry in the config-file
206                this->value_vector2_.y = defvalue.y;
207                (*this->configFileLine_) = this->varname_ + "=" + this->defvalue_;
208                ConfigValueContainer::writeConfigFile(CONFIGFILEPATH);
209            }
210        }
211        else
212        {
213            // The conversion failed - use the default value and restore the entry in the config-file
214            this->value_vector2_ = defvalue;
215            (*this->configFileLine_) = this->varname_ + "=" + this->defvalue_;
216            ConfigValueContainer::writeConfigFile(CONFIGFILEPATH);
217        }
218    }
219
220    /**
221        @brief Constructor: Converts the default-value to a string, checks the config-file for a changed value, sets this->value_vector3_.
222        @param classname The name of the class the variable belongs to
223        @param varname The name of the variable
224        @param defvalue The default-value
225    */
226    ConfigValueContainer::ConfigValueContainer(const std::string& classname, const std::string& varname, Ogre::Vector3 defvalue)
227    {
228        // Try to convert the default-value from Vector3 to string
229        std::ostringstream ostream;
230        if (ostream << "(" << defvalue.x << "," << defvalue.y << "," << defvalue.z << ")")
231            this->defvalue_ = ostream.str();
232        else
233            this->defvalue_ = "(0,0,0)";
234
235        // Set the default values, then get the value-string
236        this->setDefaultValues(classname, varname);
237        std::string valueString = this->getValueString();
238
239        // Strip the value-string
240        bool bEntryIsCorrupt = false;
241        valueString = this->getStrippedLine(valueString);
242        unsigned int pos1, pos2, pos3;
243        pos1 = valueString.find("(");
244        if (pos1 == 0)
245            valueString.erase(pos1, 1);
246        else
247            bEntryIsCorrupt = true;
248
249        pos2 = valueString.find(")");
250        if (pos2 == valueString.length() - 1)
251            valueString.erase(pos2, 1);
252        else
253            bEntryIsCorrupt = true;
254
255        int count = 0;
256        while ((pos3 = valueString.find(",")) < valueString.length())
257        {
258            count++;
259            valueString.replace(pos3, 1, " ");
260            if (pos3 < pos1)
261                bEntryIsCorrupt = true;
262        }
263
264        if (count != 2)
265            bEntryIsCorrupt = true;
266
267        // Try to convert the stripped value-string to Vector3
268        if (!bEntryIsCorrupt)
269        {
270            std::istringstream istream(valueString);
271            if (!(istream >> this->value_vector3_.x))
272            {
273                // The conversion failed - use the default value and restore the entry in the config-file
274                this->value_vector3_.x = defvalue.x;
275                (*this->configFileLine_) = this->varname_ + "=" + this->defvalue_;
276                ConfigValueContainer::writeConfigFile(CONFIGFILEPATH);
277            }
278            if (!(istream >> this->value_vector3_.y))
279            {
280                // The conversion failed - use the default value and restore the entry in the config-file
281                this->value_vector3_.y = defvalue.y;
282                (*this->configFileLine_) = this->varname_ + "=" + this->defvalue_;
283                ConfigValueContainer::writeConfigFile(CONFIGFILEPATH);
284            }
285            if (!(istream >> this->value_vector3_.z))
286            {
287                // The conversion failed - use the default value and restore the entry in the config-file
288                this->value_vector3_.z = defvalue.z;
289                (*this->configFileLine_) = this->varname_ + "=" + this->defvalue_;
290                ConfigValueContainer::writeConfigFile(CONFIGFILEPATH);
291            }
292        }
293        else
294        {
295            // The conversion failed - use the default value and restore the entry in the config-file
296            this->value_vector3_ = defvalue;
297            (*this->configFileLine_) = this->varname_ + "=" + this->defvalue_;
298            ConfigValueContainer::writeConfigFile(CONFIGFILEPATH);
299        }
300    }
301
302    /**
303        @brief Constructor: Converts the default-value to a string, checks the config-file for a changed value, sets this->value_colourvalue_.
304        @param classname The name of the class the variable belongs to
305        @param varname The name of the variable
306        @param defvalue The default-value
307    */
308    ConfigValueContainer::ConfigValueContainer(const std::string& classname, const std::string& varname, Ogre::ColourValue defvalue)
309    {
310        // Try to convert the default-value from ColourValue to string
311        std::ostringstream ostream;
312        if (ostream << "(" << defvalue.r << "," << defvalue.g << "," << defvalue.b << "," << defvalue.a << ")")
313            this->defvalue_ = ostream.str();
314        else
315            this->defvalue_ = "(0,0,0,0)";
316
317        // Set the default values, then get the value-string
318        this->setDefaultValues(classname, varname);
319        std::string valueString = this->getValueString();
320
321        // Strip the value-string
322        bool bEntryIsCorrupt = false;
323        valueString = this->getStrippedLine(valueString);
324        unsigned int pos1, pos2, pos3;
325        pos1 = valueString.find("(");
326        if (pos1 == 0)
327            valueString.erase(pos1, 1);
328        else
329            bEntryIsCorrupt = true;
330
331        pos2 = valueString.find(")");
332        if (pos2 == valueString.length() - 1)
333            valueString.erase(pos2, 1);
334        else
335            bEntryIsCorrupt = true;
336
337        int count = 0;
338        while ((pos3 = valueString.find(",")) < valueString.length())
339        {
340            count++;
341            valueString.replace(pos3, 1, " ");
342            if (pos3 < pos1)
343                bEntryIsCorrupt = true;
344        }
345
346        if (count != 3)
347            bEntryIsCorrupt = true;
348
349        // Try to convert the stripped value-string to Vector3
350        if (!bEntryIsCorrupt)
351        {
352            std::istringstream istream(valueString);
353            if (!(istream >> this->value_colourvalue_.r))
354            {
355                // The conversion failed - use the default value and restore the entry in the config-file
356                this->value_colourvalue_.r = defvalue.r;
357                (*this->configFileLine_) = this->varname_ + "=" + this->defvalue_;
358                ConfigValueContainer::writeConfigFile(CONFIGFILEPATH);
359            }
360            if (!(istream >> this->value_colourvalue_.g))
361            {
362                // The conversion failed - use the default value and restore the entry in the config-file
363                this->value_colourvalue_.g = defvalue.g;
364                (*this->configFileLine_) = this->varname_ + "=" + this->defvalue_;
365                ConfigValueContainer::writeConfigFile(CONFIGFILEPATH);
366            }
367            if (!(istream >> this->value_colourvalue_.b))
368            {
369                // The conversion failed - use the default value and restore the entry in the config-file
370                this->value_colourvalue_.b = defvalue.b;
371                (*this->configFileLine_) = this->varname_ + "=" + this->defvalue_;
372                ConfigValueContainer::writeConfigFile(CONFIGFILEPATH);
373            }
374            if (!(istream >> this->value_colourvalue_.a))
375            {
376                // The conversion failed - use the default value and restore the entry in the config-file
377                this->value_colourvalue_.a = defvalue.a;
378                (*this->configFileLine_) = this->varname_ + "=" + this->defvalue_;
379                ConfigValueContainer::writeConfigFile(CONFIGFILEPATH);
380            }
381        }
382        else
383        {
384            // The conversion failed - use the default value and restore the entry in the config-file
385            this->value_colourvalue_ = defvalue;
386            (*this->configFileLine_) = this->varname_ + "=" + this->defvalue_;
387            ConfigValueContainer::writeConfigFile(CONFIGFILEPATH);
388        }
389    }
390
391    /**
392        @brief Sets the default values of the container and searches the coresponding entry in the config-file.
393        @param classname The name of the class the variable belongs to
394        @param varname The name of the variable
395    */
396    void ConfigValueContainer::setDefaultValues(const std::string& classname, const std::string& varname)
397    {
398        // Set the class and variable names
399        this->classname_ = classname;
400        this->varname_ = varname;
401
402        // Search the entry in the config-file
403        this->searchConfigFileLine();
404
405        // Set the values of all types to zero
406        this->value_.value_int_ = 0;
407        this->value_.value_double_ = 0.000000;
408        this->value_.value_bool_ = false;
409        this->value_string_ = "";
410        this->value_vector2_ = Ogre::Vector2(0, 0);
411        this->value_vector3_ = Ogre::Vector3(0, 0, 0);
412        this->value_colourvalue_ = Ogre::ColourValue(0, 0, 0, 0);
413    }
414
415    /**
416        @brief Searches the corresponding entry in the config-file and creates it, if there is no entry.
417    */
418    void ConfigValueContainer::searchConfigFileLine()
419    {
420        // Read the file if needed
421        if (!ConfigValueContainer::readConfigFile_s)
422            ConfigValueContainer::readConfigFile(CONFIGFILEPATH);
423
424        // The string of the section we're searching
425        std::string section = "";
426        section.append("[");
427        section.append(this->classname_);
428        section.append("]");
429
430        // Iterate through all config-file-lines
431        bool success = false;
432        std::list<std::string>::iterator it1;
433        for(it1 = ConfigValueContainer::configFileLines_s->begin(); it1 != ConfigValueContainer::configFileLines_s->end(); ++it1)
434        {
435            // Don't try to parse comments
436            if (this->isComment(*it1))
437                continue;
438
439            if ((*it1).find(section) < (*it1).length())
440            {
441                // We found the right section
442                bool bLineIsEmpty = false;
443                std::list<std::string>::iterator positionToPutNewLineAt;
444
445                // Iterate through all lines in the section
446                std::list<std::string>::iterator it2;
447                for(it2 = ++it1; it2 != ConfigValueContainer::configFileLines_s->end(); ++it2)
448                {
449                    // Don't try to parse comments
450                    if (this->isComment(*it2))
451                        continue;
452
453                    // This if-else block is used to write a new line right after the last line of the
454                    // section but in front of the following empty lines before the next section.
455                    // (So this helps to keep a nice formatting with empty-lines between sections in the config-file)
456                    if (this->isEmpty(*it2))
457                    {
458                        if (!bLineIsEmpty)
459                        {
460                            bLineIsEmpty = true;
461                            positionToPutNewLineAt = it2;
462                        }
463                    }
464                    else
465                    {
466                        if (!bLineIsEmpty)
467                            positionToPutNewLineAt = it2;
468
469                        bLineIsEmpty = false;
470                    }
471
472                    // Look out for the beginning of the next section
473                    unsigned int open = (*it2).find("[");
474                    unsigned int close = (*it2).find("]");
475                    if ((open < (*it2).length()) && (close < (*it2).length()) && (open < close))
476                    {
477                        // The next section startet, so our line isn't yet in the file - now we add it and safe the file
478                        this->configFileLine_ = this->configFileLines_s->insert(positionToPutNewLineAt, this->varname_ + "=" + this->defvalue_);
479                        ConfigValueContainer::writeConfigFile(CONFIGFILEPATH);
480                        success = true;
481                        break;
482                    }
483
484                    // Look out for the variable-name
485                    if ((*it2).find(this->varname_) < (*it2).length())
486                    {
487                        // We found the right line - safe it and return
488                        this->configFileLine_ = it2;
489                        success = true;
490                        break;
491                    }
492                }
493
494                // Check if we succeeded
495                if (!success)
496                {
497                    // Looks like we found the right section, but the file ended without containing our variable - so we add it and safe the file
498                    this->configFileLine_ = this->configFileLines_s->insert(positionToPutNewLineAt, this->varname_ + "=" + this->defvalue_);
499                    ConfigValueContainer::writeConfigFile(CONFIGFILEPATH);
500                    success = true;
501                }
502                break;
503            }
504        }
505
506        // Check if we succeeded
507        if (!success)
508        {
509            // We obviously didn't found the right section, so we'll create it
510            this->configFileLines_s->push_back("[" + this->classname_ + "]");           // Create the section
511            this->configFileLines_s->push_back(this->varname_ + "=" + this->defvalue_); // Create the line
512            this->configFileLine_ = --this->configFileLines_s->end();                   // Set the pointer to the last element
513            success = true;
514            this->configFileLines_s->push_back("");                                     // Add an empty line - this is needed for the algorithm in the searchConfigFileLine-function
515            ConfigValueContainer::writeConfigFile(CONFIGFILEPATH);                      // Save the changed config-file
516        }
517    }
518
519    /**
520        @brief Determines if a line in the config-file is a comment.
521        @param line The line to check
522        @return True = it's a comment
523    */
524    bool ConfigValueContainer::isComment(const std::string& line)
525    {
526        // Strip the line, whitespaces are disturbing
527        std::string teststring = getStrippedLine(line);
528
529        // There are four possible comment-symbols:
530        //  1) #comment in script-language style
531        //  2) %comment in matlab style
532        //  3) ;comment in unreal tournament config-file style
533        //  4) //comment in code style
534        if (teststring[0] == '#' || teststring[0] == '%' || teststring[0] == ';' || (teststring[0] == '/' && teststring[0] == '/'))
535            return true;
536
537        return false;
538    }
539
540    /**
541        @brief Determines if a line in the config-file is empty (contains only whitespaces).
542        @param line The line to check
543        @return True = it's empty
544    */
545    bool ConfigValueContainer::isEmpty(const std::string& line)
546    {
547        return getStrippedLine(line) == "";
548    }
549
550    /**
551        @brief Removes all whitespaces from a line.
552        @param line The line to strip
553        @return The stripped line
554    */
555    std::string ConfigValueContainer::getStrippedLine(const std::string& line)
556    {
557        std::string output = line;
558        unsigned int pos;
559        while ((pos = output.find(" ")) < output.length())
560            output.erase(pos, 1);
561        while ((pos = output.find("\t")) < output.length())
562            output.erase(pos, 1);
563
564        return output;
565    }
566
567    /**
568        @brief Returns the part in the corresponding config-file-entry of the container that defines the value.
569        @param bStripped True = strip the value-string
570        @return The value-string
571    */
572    std::string ConfigValueContainer::getValueString(bool bStripped)
573    {
574        std::string output;
575        if (bStripped)
576            output = this->getStrippedLine(*this->configFileLine_);
577        else
578            output = *this->configFileLine_;
579
580        return output.substr(output.find("=") + 1);
581    }
582
583    /**
584        @brief Reads the config-file and stores the lines in a list.
585        @param filename The name of the config-file
586    */
587    void ConfigValueContainer::readConfigFile(const std::string& filename)
588    {
589        ConfigValueContainer::readConfigFile_s = true;
590
591        // Create the list if needed
592        if (!ConfigValueContainer::configFileLines_s)
593            ConfigValueContainer::configFileLines_s = new std::list<std::string>;
594
595        // This creates the file if it's not existing
596        std::ofstream createFile;
597        createFile.open(filename.c_str(), std::fstream::app);
598        createFile.close();
599
600        // Open the file
601        std::ifstream file;
602        file.open(filename.c_str(), std::fstream::in);
603
604        char line[1024];
605
606        // Iterate through the file and add the lines into the list
607        while (file.good() && !file.eof())
608        {
609            file.getline(line, 1024);
610            ConfigValueContainer::configFileLines_s->push_back(line);
611//            std::cout << "### ->" << line << "<- : empty: " << isEmpty(line) << " comment: " << isComment(line) << std::endl;
612        }
613
614        // The last line is useless
615        ConfigValueContainer::configFileLines_s->pop_back();
616
617        // Add an empty line to the end of the file if needed
618        // this is needed for the algorithm in the searchConfigFileLine-function
619        if ((ConfigValueContainer::configFileLines_s->size() > 0) && !isEmpty(*ConfigValueContainer::configFileLines_s->rbegin()))
620        {
621//            std::cout << "### newline added" << std::endl;
622            ConfigValueContainer::configFileLines_s->push_back("");
623        }
624
625        file.close();
626    }
627
628    /**
629        @param Writes the content of the list, containing all lines of the config-file, into the config-file.
630        @param filename The name of the config-file
631    */
632    void ConfigValueContainer::writeConfigFile(const std::string& filename)
633    {
634        // Make sure we stored the config-file in the list
635        if (!ConfigValueContainer::readConfigFile_s)
636            ConfigValueContainer::readConfigFile(filename);
637
638        // Open the file
639        std::ofstream file;
640        file.open(filename.c_str(), std::fstream::out);
641
642        // Iterate through the list an write the lines into the file
643        std::list<std::string>::iterator it;
644        for(it = ConfigValueContainer::configFileLines_s->begin(); it != ConfigValueContainer::configFileLines_s->end(); ++it)
645        {
646            file << (*it) << std::endl;
647        }
648
649        file.close();
650    }
651}
Note: See TracBrowser for help on using the repository browser.