Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 456 was 456, checked in by nicolasc, 16 years ago

removed some uneeded code - as requested

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
425        // The string of the section we're searching
426        std::string section = "";
427        section.append("[");
428        section.append(this->classname_);
429        section.append("]");
430
431        // Iterate through all config-file-lines
432        bool success = false;
433        std::list<std::string>::iterator it1;
434        for(it1 = ConfigValueContainer::configFileLines_s->begin(); it1 != ConfigValueContainer::configFileLines_s->end(); ++it1)
435        {
436            // Don't try to parse comments
437            if (this->isComment(*it1))
438                continue;
439
440            if ((*it1).find(section) < (*it1).length())
441            {
442                // We found the right section
443                bool bLineIsEmpty = false;
444                std::list<std::string>::iterator positionToPutNewLineAt;
445
446                // Iterate through all lines in the section
447                std::list<std::string>::iterator it2;
448                for(it2 = ++it1; it2 != ConfigValueContainer::configFileLines_s->end(); ++it2)
449                {
450                    // Don't try to parse comments
451                    if (this->isComment(*it2))
452                        continue;
453
454                    // This if-else block is used to write a new line right after the last line of the
455                    // section but in front of the following empty lines before the next section.
456                    // (So this helps to keep a nice formatting with empty-lines between sections in the config-file)
457                    if (this->isEmpty(*it2))
458                    {
459                        if (!bLineIsEmpty)
460                        {
461                            bLineIsEmpty = true;
462                            positionToPutNewLineAt = it2;
463                        }
464                    }
465                    else
466                    {
467                        if (!bLineIsEmpty)
468                            positionToPutNewLineAt = it2;
469
470                        bLineIsEmpty = false;
471                    }
472
473                    // Look out for the beginning of the next section
474                    unsigned int open = (*it2).find("[");
475                    unsigned int close = (*it2).find("]");
476                    if ((open < (*it2).length()) && (close < (*it2).length()) && (open < close))
477                    {
478                        // The next section startet, so our line isn't yet in the file - now we add it and safe the file
479                        this->configFileLine_ = this->configFileLines_s->insert(positionToPutNewLineAt, this->varname_ + "=" + this->defvalue_);
480                        ConfigValueContainer::writeConfigFile(CONFIGFILEPATH);
481                        success = true;
482                        break;
483                    }
484
485                    // Look out for the variable-name
486                    if ((*it2).find(this->varname_) < (*it2).length())
487                    {
488                        // We found the right line - safe it and return
489                        this->configFileLine_ = it2;
490                        success = true;
491                        break;
492                    }
493                }
494
495                // Check if we succeeded
496                if (!success)
497                {
498                    // Looks like we found the right section, but the file ended without containing our variable - so we add it and safe the file
499                    this->configFileLine_ = this->configFileLines_s->insert(positionToPutNewLineAt, this->varname_ + "=" + this->defvalue_);
500                    ConfigValueContainer::writeConfigFile(CONFIGFILEPATH);
501                    success = true;
502                }
503                break;
504            }
505        }
506
507        // Check if we succeeded
508        if (!success)
509        {
510            // We obviously didn't found the right section, so we'll create it
511            this->configFileLines_s->push_back("[" + this->classname_ + "]");           // Create the section
512            this->configFileLines_s->push_back(this->varname_ + "=" + this->defvalue_); // Create the line
513            this->configFileLine_ = --this->configFileLines_s->end();                   // Set the pointer to the last element
514            success = true;
515            this->configFileLines_s->push_back("");                                     // Add an empty line - this is needed for the algorithm in the searchConfigFileLine-function
516            ConfigValueContainer::writeConfigFile(CONFIGFILEPATH);                      // Save the changed config-file
517        }
518    }
519
520    /**
521        @brief Determines if a line in the config-file is a comment.
522        @param line The line to check
523        @return True = it's a comment
524    */
525    bool ConfigValueContainer::isComment(const std::string& line)
526    {
527        // Strip the line, whitespaces are disturbing
528        std::string teststring = getStrippedLine(line);
529
530        // There are four possible comment-symbols:
531        //  1) #comment in script-language style
532        //  2) %comment in matlab style
533        //  3) ;comment in unreal tournament config-file style
534        //  4) //comment in code style
535        if (teststring[0] == '#' || teststring[0] == '%' || teststring[0] == ';' || (teststring[0] == '/' && teststring[0] == '/'))
536            return true;
537
538        return false;
539    }
540
541    /**
542        @brief Determines if a line in the config-file is empty (contains only whitespaces).
543        @param line The line to check
544        @return True = it's empty
545    */
546    bool ConfigValueContainer::isEmpty(const std::string& line)
547    {
548        return getStrippedLine(line) == "";
549    }
550
551    /**
552        @brief Removes all whitespaces from a line.
553        @param line The line to strip
554        @return The stripped line
555    */
556    std::string ConfigValueContainer::getStrippedLine(const std::string& line)
557    {
558        std::string output = line;
559        unsigned int pos;
560        while ((pos = output.find(" ")) < output.length())
561            output.erase(pos, 1);
562        while ((pos = output.find("\t")) < output.length())
563            output.erase(pos, 1);
564
565        return output;
566    }
567
568    /**
569        @brief Returns the part in the corresponding config-file-entry of the container that defines the value.
570        @param bStripped True = strip the value-string
571        @return The value-string
572    */
573    std::string ConfigValueContainer::getValueString(bool bStripped)
574    {
575        std::string output;
576        if (bStripped)
577            output = this->getStrippedLine(*this->configFileLine_);
578        else
579            output = *this->configFileLine_;
580
581        return output.substr(output.find("=") + 1);
582    }
583
584    /**
585        @brief Reads the config-file and stores the lines in a list.
586        @param filename The name of the config-file
587    */
588    void ConfigValueContainer::readConfigFile(const std::string& filename)
589    {
590        ConfigValueContainer::readConfigFile_s = true;
591
592        // Create the list if needed
593        if (!ConfigValueContainer::configFileLines_s)
594            ConfigValueContainer::configFileLines_s = new std::list<std::string>;
595
596        // This creates the file if it's not existing
597        std::ofstream createFile;
598        createFile.open(filename.c_str(), std::fstream::app);
599        createFile.close();
600
601        // Open the file
602        std::ifstream file;
603        file.open(filename.c_str(), std::fstream::in);
604
605        char line[1024];
606
607        // Iterate through the file and add the lines into the list
608        while (file.good() && !file.eof())
609        {
610            file.getline(line, 1024);
611            ConfigValueContainer::configFileLines_s->push_back(line);
612//            std::cout << "### ->" << line << "<- : empty: " << isEmpty(line) << " comment: " << isComment(line) << std::endl;
613        }
614
615        // The last line is useless
616        ConfigValueContainer::configFileLines_s->pop_back();
617
618        // Add an empty line to the end of the file if needed
619        // this is needed for the algorithm in the searchConfigFileLine-function
620        if ((ConfigValueContainer::configFileLines_s->size() > 0) && !isEmpty(*ConfigValueContainer::configFileLines_s->rbegin()))
621        {
622//            std::cout << "### newline added" << std::endl;
623            ConfigValueContainer::configFileLines_s->push_back("");
624        }
625
626        file.close();
627    }
628
629    /**
630        @param Writes the content of the list, containing all lines of the config-file, into the config-file.
631        @param filename The name of the config-file
632    */
633    void ConfigValueContainer::writeConfigFile(const std::string& filename)
634    {
635        // Make sure we stored the config-file in the list
636        if (!ConfigValueContainer::readConfigFile_s)
637            ConfigValueContainer::readConfigFile(filename);
638
639        // Open the file
640        std::ofstream file;
641        file.open(filename.c_str(), std::fstream::out);
642
643        // Iterate through the list an write the lines into the file
644        std::list<std::string>::iterator it;
645        for(it = ConfigValueContainer::configFileLines_s->begin(); it != ConfigValueContainer::configFileLines_s->end(); ++it)
646        {
647            file << (*it) << std::endl;
648        }
649
650        file.close();
651    }
652}
Note: See TracBrowser for help on using the repository browser.