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
Line 
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:
22 *      Fabian 'x3n' Landau
23 *   Co-authors:
24 *      ...
25 *
26 */
27
28/**
29    @file ConfigValueContainer.cc
30    @brief Implementation of the ConfigValueContainer class.
31*/
32
33#include <fstream>
34
35#include "ConfigValueContainer.h"
36#include "Language.h"
37#include "Iterator.h"
38#include "BaseObject.h"
39
40#define CONFIGFILEPATH "orxonox.ini"
41
42namespace orxonox
43{
44    /**
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.
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    */
51    ConfigValueContainer::ConfigValueContainer(Identifier* identifier, const std::string& varname, MultiTypeMath defvalue)
52    {
53        this->bAddedDescription_ = false;
54        this->identifier_ = identifier;
55        this->varname_ = varname;
56
57        this->defvalueString_ = defvalue.toString();                                // Convert the default-value to a string
58        this->searchLineInConfigFile();                                             // Search the entry in the config-file
59
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
63    }
64
65    /**
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
69    */
70    bool ConfigValueContainer::set(const std::string& input)
71    {
72        bool success = this->tset(input);
73        this->setLineInConfigFile(input);
74        return success;
75    }
76
77    /**
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
81    */
82    bool ConfigValueContainer::tset(const std::string& input)
83    {
84        bool success = this->parse(input);
85        this->identifier_->updateConfigValues();
86        return success;
87    }
88
89    /**
90        @brief Sets the value of the variable back to the default value and resets the config-file entry.
91    */
92    bool ConfigValueContainer::reset()
93    {
94        return this->set(this->defvalueString_);
95    }
96
97    /**
98        @brief Parses a given std::string into a value of the type of the associated variable and assigns it.
99        @param input The string to convert
100        @return True if the string was successfully parsed
101    */
102    bool ConfigValueContainer::parse(const std::string& input)
103    {
104        MultiTypeMath temp = this->value_;
105        if (temp.fromString(input))
106        {
107            this->value_ = temp;
108            return true;
109        }
110        return false;
111    }
112
113    /**
114        @brief Parses a given std::string into a value of the type of the associated variable and assigns it.
115        @param input The string to convert
116        @param defvalue The default value to assign if the parsing fails
117        @return True if the string was successfully parsed
118    */
119    bool ConfigValueContainer::parse(const std::string& input, const MultiTypeMath& defvalue)
120    {
121        MultiTypeMath temp = defvalue;
122        if (temp.fromString(input))
123        {
124            this->value_ = temp;
125            return true;
126        }
127        else
128        {
129            this->value_ = defvalue;
130            return false;
131        }
132    }
133
134    /**
135        @brief Sets the corresponding entry in the config-file to a given value.
136    */
137    void ConfigValueContainer::setLineInConfigFile(const std::string& input)
138    {
139        (*this->configFileLine_) = this->varname_ + "=" + input;
140        ConfigValueContainer::writeConfigFile(CONFIGFILEPATH);
141    }
142
143    /**
144        @brief Sets the corresponding entry in the config-file back to the default value.
145    */
146    void ConfigValueContainer::resetLineInConfigFile()
147    {
148        this->setLineInConfigFile(this->defvalueString_);
149    }
150
151    /**
152        @brief Searches the corresponding entry in the config-file and creates it, if there is no entry.
153    */
154    void ConfigValueContainer::searchLineInConfigFile()
155    {
156        // Read the file if needed
157        if (!ConfigValueContainer::finishedReadingConfigFile())
158            ConfigValueContainer::readConfigFile(CONFIGFILEPATH);
159
160        // The string of the section we're searching
161        std::string section = "";
162        section.append("[");
163        section.append(this->identifier_->getName());
164        section.append("]");
165
166        // Iterate through all config-file-lines
167        bool success = false;
168        std::list<std::string>::iterator it1;
169        for(it1 = ConfigValueContainer::getConfigFileLines().begin(); it1 != ConfigValueContainer::getConfigFileLines().end(); ++it1)
170        {
171            // Don't try to parse comments
172            if (isComment(*it1))
173                continue;
174
175            if ((*it1).find(section) < (*it1).length())
176            {
177                // We found the right section
178                bool bLineIsEmpty = false;
179                std::list<std::string>::iterator positionToPutNewLineAt;
180
181                // Iterate through all lines in the section
182                std::list<std::string>::iterator it2;
183                for(it2 = ++it1; it2 != ConfigValueContainer::getConfigFileLines().end(); ++it2)
184                {
185                    // Don't try to parse comments
186                    if (isComment(*it2))
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)
192                    if (isEmpty(*it2))
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
214                        this->configFileLine_ = this->getConfigFileLines().insert(positionToPutNewLineAt, this->varname_ + "=" + this->defvalueString_);
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
234                    this->configFileLine_ = this->getConfigFileLines().insert(positionToPutNewLineAt, this->varname_ + "=" + this->defvalueString_);
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
246            this->getConfigFileLines().push_back("[" + this->identifier_->getName() + "]");                   // Create the section
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
249            success = true;
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
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    */
260    std::string ConfigValueContainer::parseValueStringFromConfigFile(bool bStripped)
261    {
262        std::string output;
263        if (bStripped)
264            output = getStripped(*this->configFileLine_);
265        else
266            output = *this->configFileLine_;
267
268        return output.substr(output.find("=") + 1);
269    }
270
271    /**
272        @brief Rreturns a list, containing all entrys in the config-file.
273        @return The list
274    */
275    std::list<std::string>& ConfigValueContainer::getConfigFileLines()
276    {
277        // This is done to avoid problems while executing this code before main()
278        static std::list<std::string> configFileLinesStaticReference = std::list<std::string>();
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    /**
299        @brief Reads the config-file and stores the lines in a list.
300        @param filename The name of the config-file
301    */
302    void ConfigValueContainer::readConfigFile(const std::string& filename)
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
313        if (!file.is_open())
314        {
315            COUT(1) << "An error occurred in ConfigValueContainer.cc:" << std::endl;
316            COUT(1) << "Error: Couldn't open config-file " << filename << " to read the config values!" << std::endl;
317            return;
318        }
319
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);
326            ConfigValueContainer::getConfigFileLines().push_back(line);
327        }
328
329        // The last line is useless
330        ConfigValueContainer::getConfigFileLines().pop_back();
331
332        // Add an empty line to the end of the file if needed
333        // this is needed for the algorithm in the searchLineInConfigFile-function
334        if ((ConfigValueContainer::getConfigFileLines().size() > 0) && !isEmpty(*ConfigValueContainer::getConfigFileLines().rbegin()))
335            ConfigValueContainer::getConfigFileLines().push_back("");
336
337        file.close();
338
339        ConfigValueContainer::finishedReadingConfigFile(true);
340    }
341
342    /**
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    */
346    void ConfigValueContainer::writeConfigFile(const std::string& filename)
347    {
348        // Make sure we stored the config-file in the list
349        if (!ConfigValueContainer::finishedReadingConfigFile())
350            ConfigValueContainer::readConfigFile(filename);
351
352        // Open the file
353        std::ofstream file;
354        file.open(filename.c_str(), std::fstream::out);
355        file.setf(std::ios::fixed, std::ios::floatfield);
356        file.precision(6);
357
358        if (!file.is_open())
359        {
360            COUT(1) << "An error occurred in ConfigValueContainer.cc:" << std::endl;
361            COUT(1) << "Error: Couldn't open config-file " << filename << " to write the config values!" << std::endl;
362            return;
363        }
364
365        // Iterate through the list an write the lines into the file
366        std::list<std::string>::iterator it;
367        for (it = ConfigValueContainer::getConfigFileLines().begin(); it != ConfigValueContainer::getConfigFileLines().end(); ++it)
368        {
369            file << (*it) << std::endl;
370        }
371
372        file.close();
373    }
374
375    /**
376        @brief Adds a description to the config-value.
377        @param description The description
378    */
379    void ConfigValueContainer::description(const std::string& description)
380    {
381        if (!this->bAddedDescription_)
382        {
383            this->description_ = std::string("ConfigValueDescription::" + this->identifier_->getName() + "::" + this->varname_);
384            AddLanguageEntry(this->description_, description);
385            this->bAddedDescription_ = true;
386        }
387    }
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    }
397}
Note: See TracBrowser for help on using the repository browser.