Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 451 was 451, checked in by landauf, 17 years ago

used a union to save some memory

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