Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/core2/src/orxonox/core/ConfigValueContainer.cc @ 967

Last change on this file since 967 was 957, checked in by landauf, 16 years ago
  • added set and tset functions to the ConfigValueContainer to (temporary) set a config-value to a new value
  • ConfigValueContainer uses now the functions of MultiTypeMath to convert and assign values
  • added some errorhandling to the CommandExecutor in case there are not enough parameters when executing the command
  • added updateConfigValues function to Identifier
  • added addTime and removeTime functions to the Timer
  • some changes in Executor to allow adding description and default-values when using the ConsoleCommand macro
File size: 15.4 KB
RevLine 
[513]1/*
2 *   ORXONOX - the hottest 3D action shooter ever to exist
3 *
4 *
5 *   License notice:
6 *
7 *   This program is free software; you can redistribute it and/or
8 *   modify it under the terms of the GNU General Public License
9 *   as published by the Free Software Foundation; either version 2
10 *   of the License, or (at your option) any later version.
11 *
12 *   This program is distributed in the hope that it will be useful,
13 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
14 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 *   GNU General Public License for more details.
16 *
17 *   You should have received a copy of the GNU General Public License
18 *   along with this program; if not, write to the Free Software
19 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
20 *
21 *   Author:
[670]22 *      Fabian 'x3n' Landau
[513]23 *   Co-authors:
24 *      ...
25 *
26 */
27
[871]28/**
29    @file ConfigValueContainer.cc
30    @brief Implementation of the ConfigValueContainer class.
31*/
32
[497]33#include <fstream>
[682]34
[871]35#include "ConfigValueContainer.h"
36#include "Language.h"
[957]37#include "Iterator.h"
38#include "BaseObject.h"
[497]39
40#define CONFIGFILEPATH "orxonox.ini"
41
42namespace orxonox
43{
44    /**
[667]45        @brief Constructor: Converts the default-value to a string, checks the config-file for a changed value, sets the intern value variable.
46        @param value This is only needed to determine the right type.
[497]47        @param classname The name of the class the variable belongs to
48        @param varname The name of the variable
49        @param defvalue The default-value
50    */
[957]51    ConfigValueContainer::ConfigValueContainer(Identifier* identifier, const std::string& varname, MultiTypeMath defvalue)
[497]52    {
[705]53        this->bAddedDescription_ = false;
[957]54        this->identifier_ = identifier;
[667]55        this->varname_ = varname;
[497]56
[957]57        this->defvalueString_ = defvalue.toString();                                // Convert the default-value to a string
58        this->searchLineInConfigFile();                                             // Search the entry in the config-file
[497]59
[957]60        std::string valueString = this->parseValueStringFromConfigFile(!(defvalue.isA(MT_string) || defvalue.isA(MT_constchar)));     // Parses the value string from the config-file-entry
61        if (!this->parse(valueString, defvalue))                                    // Try to convert the string to a value
62            this->resetLineInConfigFile();                                            // The conversion failed
[497]63    }
64
65    /**
[957]66        @brief Assigns a new value to the config-value of all objects and writes the change into the config-file.
67        @param input The new value
68        @return True if the new value was successfully assigned
[497]69    */
[957]70    bool ConfigValueContainer::set(const std::string& input)
[667]71    {
[957]72        bool success = this->tset(input);
73        this->setLineInConfigFile(input);
[871]74        return success;
[667]75    }
76
77    /**
[957]78        @brief Assigns a new value to the config-value of all objects, but doesn't change the config-file (t stands for temporary).
79        @param input The new value
80        @return True if the new value was successfully assigned
[667]81    */
[957]82    bool ConfigValueContainer::tset(const std::string& input)
[667]83    {
[957]84        bool success = this->parse(input);
85        this->identifier_->updateConfigValues();
[871]86        return success;
[667]87    }
88
89    /**
[957]90        @brief Sets the value of the variable back to the default value and resets the config-file entry.
[667]91    */
[957]92    bool ConfigValueContainer::reset()
[497]93    {
[957]94        return this->set(this->defvalueString_);
[497]95    }
96
97    /**
[957]98        @brief Parses a given std::string into a value of the type of the associated variable and assigns it.
[871]99        @param input The string to convert
[703]100        @return True if the string was successfully parsed
101    */
[957]102    bool ConfigValueContainer::parse(const std::string& input)
[703]103    {
[957]104        MultiTypeMath temp = this->value_;
105        if (temp.fromString(input))
[703]106        {
[957]107            this->value_ = temp;
[703]108            return true;
109        }
110        return false;
111    }
112
113    /**
[957]114        @brief Parses a given std::string into a value of the type of the associated variable and assigns it.
[703]115        @param input The string to convert
[957]116        @param defvalue The default value to assign if the parsing fails
[703]117        @return True if the string was successfully parsed
118    */
[957]119    bool ConfigValueContainer::parse(const std::string& input, const MultiTypeMath& defvalue)
[703]120    {
[957]121        MultiTypeMath temp = defvalue;
122        if (temp.fromString(input))
[703]123        {
[957]124            this->value_ = temp;
[703]125            return true;
126        }
[957]127        else
[703]128        {
[957]129            this->value_ = defvalue;
130            return false;
[703]131        }
132    }
133
134    /**
[957]135        @brief Sets the corresponding entry in the config-file to a given value.
[703]136    */
[957]137    void ConfigValueContainer::setLineInConfigFile(const std::string& input)
[703]138    {
[957]139        (*this->configFileLine_) = this->varname_ + "=" + input;
140        ConfigValueContainer::writeConfigFile(CONFIGFILEPATH);
[703]141    }
142
143    /**
144        @brief Sets the corresponding entry in the config-file back to the default value.
[497]145    */
[957]146    void ConfigValueContainer::resetLineInConfigFile()
[497]147    {
[957]148        this->setLineInConfigFile(this->defvalueString_);
[667]149    }
[497]150
[703]151    /**
[497]152        @brief Searches the corresponding entry in the config-file and creates it, if there is no entry.
153    */
[957]154    void ConfigValueContainer::searchLineInConfigFile()
[497]155    {
156        // Read the file if needed
[698]157        if (!ConfigValueContainer::finishedReadingConfigFile())
[497]158            ConfigValueContainer::readConfigFile(CONFIGFILEPATH);
159
160        // The string of the section we're searching
[715]161        std::string section = "";
[497]162        section.append("[");
[957]163        section.append(this->identifier_->getName());
[497]164        section.append("]");
165
166        // Iterate through all config-file-lines
167        bool success = false;
[715]168        std::list<std::string>::iterator it1;
[698]169        for(it1 = ConfigValueContainer::getConfigFileLines().begin(); it1 != ConfigValueContainer::getConfigFileLines().end(); ++it1)
[497]170        {
171            // Don't try to parse comments
[957]172            if (isComment(*it1))
[497]173                continue;
174
175            if ((*it1).find(section) < (*it1).length())
176            {
177                // We found the right section
178                bool bLineIsEmpty = false;
[715]179                std::list<std::string>::iterator positionToPutNewLineAt;
[497]180
181                // Iterate through all lines in the section
[715]182                std::list<std::string>::iterator it2;
[698]183                for(it2 = ++it1; it2 != ConfigValueContainer::getConfigFileLines().end(); ++it2)
[497]184                {
185                    // Don't try to parse comments
[957]186                    if (isComment(*it2))
[497]187                        continue;
188
189                    // This if-else block is used to write a new line right after the last line of the
190                    // section but in front of the following empty lines before the next section.
191                    // (So this helps to keep a nice formatting with empty-lines between sections in the config-file)
[957]192                    if (isEmpty(*it2))
[497]193                    {
194                        if (!bLineIsEmpty)
195                        {
196                            bLineIsEmpty = true;
197                            positionToPutNewLineAt = it2;
198                        }
199                    }
200                    else
201                    {
202                        if (!bLineIsEmpty)
203                            positionToPutNewLineAt = it2;
204
205                        bLineIsEmpty = false;
206                    }
207
208                    // Look out for the beginning of the next section
209                    unsigned int open = (*it2).find("[");
210                    unsigned int close = (*it2).find("]");
211                    if ((open < (*it2).length()) && (close < (*it2).length()) && (open < close))
212                    {
213                        // The next section startet, so our line isn't yet in the file - now we add it and safe the file
[698]214                        this->configFileLine_ = this->getConfigFileLines().insert(positionToPutNewLineAt, this->varname_ + "=" + this->defvalueString_);
[497]215                        ConfigValueContainer::writeConfigFile(CONFIGFILEPATH);
216                        success = true;
217                        break;
218                    }
219
220                    // Look out for the variable-name
221                    if ((*it2).find(this->varname_) < (*it2).length())
222                    {
223                        // We found the right line - safe it and return
224                        this->configFileLine_ = it2;
225                        success = true;
226                        break;
227                    }
228                }
229
230                // Check if we succeeded
231                if (!success)
232                {
233                    // Looks like we found the right section, but the file ended without containing our variable - so we add it and safe the file
[698]234                    this->configFileLine_ = this->getConfigFileLines().insert(positionToPutNewLineAt, this->varname_ + "=" + this->defvalueString_);
[497]235                    ConfigValueContainer::writeConfigFile(CONFIGFILEPATH);
236                    success = true;
237                }
238                break;
239            }
240        }
241
242        // Check if we succeeded
243        if (!success)
244        {
245            // We obviously didn't found the right section, so we'll create it
[957]246            this->getConfigFileLines().push_back("[" + this->identifier_->getName() + "]");                   // Create the section
[698]247            this->getConfigFileLines().push_back(this->varname_ + "=" + this->defvalueString_);   // Create the line
248            this->configFileLine_ = --this->getConfigFileLines().end();                           // Set the pointer to the last element
[497]249            success = true;
[957]250            this->getConfigFileLines().push_back("");                                             // Add an empty line - this is needed for the algorithm in the searchLineInConfigFile-function
251            ConfigValueContainer::writeConfigFile(CONFIGFILEPATH);                                // Save the changed config-file
[497]252        }
253    }
254
255    /**
256        @brief Returns the part in the corresponding config-file-entry of the container that defines the value.
257        @param bStripped True = strip the value-string
258        @return The value-string
259    */
[957]260    std::string ConfigValueContainer::parseValueStringFromConfigFile(bool bStripped)
[497]261    {
[715]262        std::string output;
[497]263        if (bStripped)
[957]264            output = getStripped(*this->configFileLine_);
[497]265        else
266            output = *this->configFileLine_;
267
268        return output.substr(output.find("=") + 1);
269    }
270
271    /**
[871]272        @brief Rreturns a list, containing all entrys in the config-file.
273        @return The list
[698]274    */
[715]275    std::list<std::string>& ConfigValueContainer::getConfigFileLines()
[698]276    {
277        // This is done to avoid problems while executing this code before main()
[715]278        static std::list<std::string> configFileLinesStaticReference = std::list<std::string>();
[698]279        return configFileLinesStaticReference;
280    }
281
282    /**
283        @brief Returns true if the ConfigFile is read and stored into the ConfigFile-lines-list.
284        @param finished This is used to change the state
285        @return True if the ConfigFile is read and stored into the ConfigFile-lines-list
286    */
287    bool ConfigValueContainer::finishedReadingConfigFile(bool finished)
288    {
289        // This is done to avoid problems while executing this code before main()
290        static bool finishedReadingConfigFileStaticVariable = false;
291
292        if (finished)
293            finishedReadingConfigFileStaticVariable = true;
294
295        return finishedReadingConfigFileStaticVariable;
296    }
297
298    /**
[497]299        @brief Reads the config-file and stores the lines in a list.
300        @param filename The name of the config-file
301    */
[715]302    void ConfigValueContainer::readConfigFile(const std::string& filename)
[497]303    {
304        // This creates the file if it's not existing
305        std::ofstream createFile;
306        createFile.open(filename.c_str(), std::fstream::app);
307        createFile.close();
308
309        // Open the file
310        std::ifstream file;
311        file.open(filename.c_str(), std::fstream::in);
312
[704]313        if (!file.is_open())
314        {
[871]315            COUT(1) << "An error occurred in ConfigValueContainer.cc:" << std::endl;
[704]316            COUT(1) << "Error: Couldn't open config-file " << filename << " to read the config values!" << std::endl;
317            return;
318        }
319
[497]320        char line[1024];
321
322        // Iterate through the file and add the lines into the list
323        while (file.good() && !file.eof())
324        {
325            file.getline(line, 1024);
[698]326            ConfigValueContainer::getConfigFileLines().push_back(line);
[497]327        }
328
329        // The last line is useless
[698]330        ConfigValueContainer::getConfigFileLines().pop_back();
[497]331
332        // Add an empty line to the end of the file if needed
[957]333        // this is needed for the algorithm in the searchLineInConfigFile-function
[698]334        if ((ConfigValueContainer::getConfigFileLines().size() > 0) && !isEmpty(*ConfigValueContainer::getConfigFileLines().rbegin()))
335            ConfigValueContainer::getConfigFileLines().push_back("");
[497]336
337        file.close();
[704]338
339        ConfigValueContainer::finishedReadingConfigFile(true);
[497]340    }
341
342    /**
[705]343        @brief Writes the content of the list, containing all lines of the config-file, into the config-file.
344        @param filename The name of the config-file
345    */
[715]346    void ConfigValueContainer::writeConfigFile(const std::string& filename)
[497]347    {
348        // Make sure we stored the config-file in the list
[698]349        if (!ConfigValueContainer::finishedReadingConfigFile())
[497]350            ConfigValueContainer::readConfigFile(filename);
351
352        // Open the file
353        std::ofstream file;
354        file.open(filename.c_str(), std::fstream::out);
[949]355        file.setf(std::ios::fixed, std::ios::floatfield);
356        file.precision(6);
[497]357
[704]358        if (!file.is_open())
359        {
[871]360            COUT(1) << "An error occurred in ConfigValueContainer.cc:" << std::endl;
[704]361            COUT(1) << "Error: Couldn't open config-file " << filename << " to write the config values!" << std::endl;
362            return;
363        }
364
[497]365        // Iterate through the list an write the lines into the file
[715]366        std::list<std::string>::iterator it;
[704]367        for (it = ConfigValueContainer::getConfigFileLines().begin(); it != ConfigValueContainer::getConfigFileLines().end(); ++it)
[497]368        {
369            file << (*it) << std::endl;
370        }
371
372        file.close();
373    }
[705]374
375    /**
376        @brief Adds a description to the config-value.
377        @param description The description
378    */
[715]379    void ConfigValueContainer::description(const std::string& description)
[705]380    {
381        if (!this->bAddedDescription_)
382        {
[957]383            this->description_ = std::string("ConfigValueDescription::" + this->identifier_->getName() + "::" + this->varname_);
[871]384            AddLanguageEntry(this->description_, description);
[705]385            this->bAddedDescription_ = true;
386        }
387    }
[871]388
389    /**
390        @brief Returns the description of the config-value.
391        @return The description
392    */
393    const std::string& ConfigValueContainer::getDescription() const
394    {
395        return GetLocalisation(this->description_);
396    }
[497]397}
Note: See TracBrowser for help on using the repository browser.