Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

sync with notebook, nothing special here

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        if (this->identifier_)
86            this->identifier_->updateConfigValues();
87        return success;
88    }
89
90    /**
91        @brief Sets the value of the variable back to the default value and resets the config-file entry.
92    */
93    bool ConfigValueContainer::reset()
94    {
95        return this->set(this->defvalueString_);
96    }
97
98    /**
99        @brief Parses a given std::string into a value of the type of the associated variable and assigns it.
100        @param input The string to convert
101        @return True if the string was successfully parsed
102    */
103    bool ConfigValueContainer::parse(const std::string& input)
104    {
105        MultiTypeMath temp = this->value_;
106        if (temp.fromString(input))
107        {
108            this->value_ = temp;
109            return true;
110        }
111        return false;
112    }
113
114    /**
115        @brief Parses a given std::string into a value of the type of the associated variable and assigns it.
116        @param input The string to convert
117        @param defvalue The default value to assign if the parsing fails
118        @return True if the string was successfully parsed
119    */
120    bool ConfigValueContainer::parse(const std::string& input, const MultiTypeMath& defvalue)
121    {
122        MultiTypeMath temp = defvalue;
123        if (temp.fromString(input))
124        {
125            this->value_ = temp;
126            return true;
127        }
128        else
129        {
130            this->value_ = defvalue;
131            return false;
132        }
133    }
134
135    /**
136        @brief Sets the corresponding entry in the config-file to a given value.
137    */
138    void ConfigValueContainer::setLineInConfigFile(const std::string& input)
139    {
140        (*this->configFileLine_) = this->varname_ + "=" + input;
141        ConfigValueContainer::writeConfigFile(CONFIGFILEPATH);
142    }
143
144    /**
145        @brief Sets the corresponding entry in the config-file back to the default value.
146    */
147    void ConfigValueContainer::resetLineInConfigFile()
148    {
149        this->setLineInConfigFile(this->defvalueString_);
150    }
151
152    /**
153        @brief Searches the corresponding entry in the config-file and creates it, if there is no entry.
154    */
155    void ConfigValueContainer::searchLineInConfigFile()
156    {
157        // Read the file if needed
158        if (!ConfigValueContainer::finishedReadingConfigFile())
159            ConfigValueContainer::readConfigFile(CONFIGFILEPATH);
160
161        // The string of the section we're searching
162        std::string section = "";
163        section.append("[");
164        section.append(this->identifier_->getName());
165        section.append("]");
166
167        // Iterate through all config-file-lines
168        bool success = false;
169        std::list<std::string>::iterator it1;
170        for(it1 = ConfigValueContainer::getConfigFileLines().begin(); it1 != ConfigValueContainer::getConfigFileLines().end(); ++it1)
171        {
172            // Don't try to parse comments
173            if (isComment(*it1))
174                continue;
175
176            if ((*it1).find(section) < (*it1).length())
177            {
178                // We found the right section
179                bool bLineIsEmpty = false;
180                std::list<std::string>::iterator positionToPutNewLineAt;
181
182                // Iterate through all lines in the section
183                std::list<std::string>::iterator it2;
184                for(it2 = ++it1; it2 != ConfigValueContainer::getConfigFileLines().end(); ++it2)
185                {
186                    // Don't try to parse comments
187                    if (isComment(*it2))
188                        continue;
189
190                    // This if-else block is used to write a new line right after the last line of the
191                    // section but in front of the following empty lines before the next section.
192                    // (So this helps to keep a nice formatting with empty-lines between sections in the config-file)
193                    if (isEmpty(*it2))
194                    {
195                        if (!bLineIsEmpty)
196                        {
197                            bLineIsEmpty = true;
198                            positionToPutNewLineAt = it2;
199                        }
200                    }
201                    else
202                    {
203                        if (!bLineIsEmpty)
204                            positionToPutNewLineAt = it2;
205
206                        bLineIsEmpty = false;
207                    }
208
209                    // Look out for the beginning of the next section
210                    unsigned int open = (*it2).find("[");
211                    unsigned int close = (*it2).find("]");
212                    if ((open < (*it2).length()) && (close < (*it2).length()) && (open < close))
213                    {
214                        // The next section startet, so our line isn't yet in the file - now we add it and safe the file
215                        this->configFileLine_ = this->getConfigFileLines().insert(positionToPutNewLineAt, this->varname_ + "=" + this->defvalueString_);
216                        ConfigValueContainer::writeConfigFile(CONFIGFILEPATH);
217                        success = true;
218                        break;
219                    }
220
221                    // Look out for the variable-name
222                    if ((*it2).find(this->varname_) < (*it2).length())
223                    {
224                        // We found the right line - safe it and return
225                        this->configFileLine_ = it2;
226                        success = true;
227                        break;
228                    }
229                }
230
231                // Check if we succeeded
232                if (!success)
233                {
234                    // Looks like we found the right section, but the file ended without containing our variable - so we add it and safe the file
235                    this->configFileLine_ = this->getConfigFileLines().insert(positionToPutNewLineAt, this->varname_ + "=" + this->defvalueString_);
236                    ConfigValueContainer::writeConfigFile(CONFIGFILEPATH);
237                    success = true;
238                }
239                break;
240            }
241        }
242
243        // Check if we succeeded
244        if (!success)
245        {
246            // We obviously didn't found the right section, so we'll create it
247            this->getConfigFileLines().push_back("[" + this->identifier_->getName() + "]");                   // Create the section
248            this->getConfigFileLines().push_back(this->varname_ + "=" + this->defvalueString_);   // Create the line
249            this->configFileLine_ = --this->getConfigFileLines().end();                           // Set the pointer to the last element
250            success = true;
251            this->getConfigFileLines().push_back("");                                             // Add an empty line - this is needed for the algorithm in the searchLineInConfigFile-function
252            ConfigValueContainer::writeConfigFile(CONFIGFILEPATH);                                // Save the changed config-file
253        }
254    }
255
256    /**
257        @brief Returns the part in the corresponding config-file-entry of the container that defines the value.
258        @param bStripped True = strip the value-string
259        @return The value-string
260    */
261    std::string ConfigValueContainer::parseValueStringFromConfigFile(bool bStripped)
262    {
263        std::string output;
264        if (bStripped)
265            output = getStripped(*this->configFileLine_);
266        else
267            output = *this->configFileLine_;
268
269        return output.substr(output.find("=") + 1);
270    }
271
272    /**
273        @brief Rreturns a list, containing all entrys in the config-file.
274        @return The list
275    */
276    std::list<std::string>& ConfigValueContainer::getConfigFileLines()
277    {
278        // This is done to avoid problems while executing this code before main()
279        static std::list<std::string> configFileLinesStaticReference = std::list<std::string>();
280        return configFileLinesStaticReference;
281    }
282
283    /**
284        @brief Returns true if the ConfigFile is read and stored into the ConfigFile-lines-list.
285        @param finished This is used to change the state
286        @return True if the ConfigFile is read and stored into the ConfigFile-lines-list
287    */
288    bool ConfigValueContainer::finishedReadingConfigFile(bool finished)
289    {
290        // This is done to avoid problems while executing this code before main()
291        static bool finishedReadingConfigFileStaticVariable = false;
292
293        if (finished)
294            finishedReadingConfigFileStaticVariable = true;
295
296        return finishedReadingConfigFileStaticVariable;
297    }
298
299    /**
300        @brief Reads the config-file and stores the lines in a list.
301        @param filename The name of the config-file
302    */
303    void ConfigValueContainer::readConfigFile(const std::string& filename)
304    {
305        // This creates the file if it's not existing
306        std::ofstream createFile;
307        createFile.open(filename.c_str(), std::fstream::app);
308        createFile.close();
309
310        // Open the file
311        std::ifstream file;
312        file.open(filename.c_str(), std::fstream::in);
313
314        if (!file.is_open())
315        {
316            COUT(1) << "An error occurred in ConfigValueContainer.cc:" << std::endl;
317            COUT(1) << "Error: Couldn't open config-file " << filename << " to read the config values!" << std::endl;
318            return;
319        }
320
321        char line[1024];
322
323        // Iterate through the file and add the lines into the list
324        while (file.good() && !file.eof())
325        {
326            file.getline(line, 1024);
327            ConfigValueContainer::getConfigFileLines().push_back(line);
328        }
329
330        // The last line is useless
331        ConfigValueContainer::getConfigFileLines().pop_back();
332
333        // Add an empty line to the end of the file if needed
334        // this is needed for the algorithm in the searchLineInConfigFile-function
335        if ((ConfigValueContainer::getConfigFileLines().size() > 0) && !isEmpty(*ConfigValueContainer::getConfigFileLines().rbegin()))
336            ConfigValueContainer::getConfigFileLines().push_back("");
337
338        file.close();
339
340        ConfigValueContainer::finishedReadingConfigFile(true);
341    }
342
343    /**
344        @brief Writes the content of the list, containing all lines of the config-file, into the config-file.
345        @param filename The name of the config-file
346    */
347    void ConfigValueContainer::writeConfigFile(const std::string& filename)
348    {
349        // Make sure we stored the config-file in the list
350        if (!ConfigValueContainer::finishedReadingConfigFile())
351            ConfigValueContainer::readConfigFile(filename);
352
353        // Open the file
354        std::ofstream file;
355        file.open(filename.c_str(), std::fstream::out);
356        file.setf(std::ios::fixed, std::ios::floatfield);
357        file.precision(6);
358
359        if (!file.is_open())
360        {
361            COUT(1) << "An error occurred in ConfigValueContainer.cc:" << std::endl;
362            COUT(1) << "Error: Couldn't open config-file " << filename << " to write the config values!" << std::endl;
363            return;
364        }
365
366        // Iterate through the list an write the lines into the file
367        std::list<std::string>::iterator it;
368        for (it = ConfigValueContainer::getConfigFileLines().begin(); it != ConfigValueContainer::getConfigFileLines().end(); ++it)
369        {
370            file << (*it) << std::endl;
371        }
372
373        file.close();
374    }
375
376    /**
377        @brief Adds a description to the config-value.
378        @param description The description
379    */
380    void ConfigValueContainer::description(const std::string& description)
381    {
382        if (!this->bAddedDescription_)
383        {
384            this->description_ = std::string("ConfigValueDescription::" + this->identifier_->getName() + "::" + this->varname_);
385            AddLanguageEntry(this->description_, description);
386            this->bAddedDescription_ = true;
387        }
388    }
389
390    /**
391        @brief Returns the description of the config-value.
392        @return The description
393    */
394    const std::string& ConfigValueContainer::getDescription() const
395    {
396        return GetLocalisation(this->description_);
397    }
398}
Note: See TracBrowser for help on using the repository browser.