Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/core2/src/orxonox/core/ConfigFileManager.cc @ 1030

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

extracted all config-value related macros from CoreIncludes.h and moved them to ConfigValueIncludes.h.

ConfigValueContainer can now handle std::vector<x> where 'x' is is any type supported by MultiTypeMath (all primitives, pointer, string, vector2, vector3, quaternion, colourvalue, radian, degree).

the vectors size is currently limited to 256 elements. this is just a practical limit, it can be raised if it's necessary. the reason for the limit is: you can add new elements to a vector by simply typing 'set classname varname index value' into the console or adding a new entry in the config-file. if 'index' is bigger than the vectors size, all elements up to 'index' are inserted. if the user accidentally enters a big number, he could end up with >4*109 elements in his config-file, resulting in 10-100gb on the hdd and a completely filled memory. and that's not exactly what i want ;)

File size: 18.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#include "ConfigFileManager.h"
29#include "ConfigValueContainer.h"
30#include "ConsoleCommand.h"
31#include "Identifier.h"
32#include "util/Convert.h"
33#include "util/String.h"
34
35#define CONFIG_FILE_MAX_LINELENGHT 1024
36
37namespace orxonox
38{
39    ConsoleCommandShortcutExtern(reloadConfig, AccessLevel::None);
40    ConsoleCommandShortcutExtern(cleanConfig, AccessLevel::None);
41    ConsoleCommandShortcutExtern(loadSettings, AccessLevel::None);
42    ConsoleCommandShortcutExtern(loadKeybindings, AccessLevel::None);
43
44    void reloadConfig()
45    {
46        ConfigFileManager::getSingleton()->load();
47    }
48
49    void cleanConfig()
50    {
51        ConfigFileManager::getSingleton()->clean(false);
52    }
53
54    void loadSettings(const std::string& filename)
55    {
56        ConfigFileManager::getSingleton()->setFile(CFT_Settings, filename, false);
57    }
58
59    void loadKeybindings(const std::string& filename)
60    {
61        ConfigFileManager::getSingleton()->setFile(CFT_Keybindings, filename);
62    }
63
64
65    //////////////////////////
66    // ConfigFileEntryValue //
67    //////////////////////////
68    std::string ConfigFileEntryValue::getFileEntry() const
69    {
70        if (this->additionalComment_ == "" || this->additionalComment_.size() == 0)
71            return (this->name_ + "=" + this->value_);
72        else
73            return (this->name_ + "=" + this->value_ + " " + this->additionalComment_);
74    }
75
76
77    ///////////////////////////////
78    // ConfigFileEntryVectorValue //
79    ///////////////////////////////
80    std::string ConfigFileEntryVectorValue::getFileEntry() const
81    {
82        if (this->additionalComment_ == "" || this->additionalComment_.size() == 0)
83            return (this->name_ + "[" + getConvertedValue<unsigned int, std::string>(this->index_, "0") + "]" + "=" + this->value_);
84        else
85            return (this->name_ + "[" + getConvertedValue<unsigned int, std::string>(this->index_, "0") + "]=" + this->value_ + " " + this->additionalComment_);
86    }
87
88
89    ///////////////////////
90    // ConfigFileSection //
91    ///////////////////////
92    ConfigFileSection::~ConfigFileSection()
93    {
94        for (std::list<ConfigFileEntry*>::iterator it = this->entries_.begin(); it != this->entries_.end(); )
95            delete (*(it++));
96    }
97
98    void ConfigFileSection::deleteVectorEntries(const std::string& name, unsigned int startindex)
99    {
100        for (std::list<ConfigFileEntry*>::iterator it = this->entries_.begin(); it != this->entries_.end(); )
101        {
102            if (((*it)->getName() == name) && ((*it)->getIndex() >= startindex))
103            {
104                delete (*it);
105                this->entries_.erase(it++);
106            }
107            else
108            {
109                ++it;
110            }
111        }
112    }
113
114    unsigned int ConfigFileSection::getVectorSize(const std::string& name)
115    {
116        unsigned int size = 0;
117        for (std::list<ConfigFileEntry*>::const_iterator it = this->entries_.begin(); it != this->entries_.end(); ++it)
118            if ((*it)->getName() == name)
119                if ((*it)->getIndex() > size)
120                    size = (*it)->getIndex();
121        return (size + 1);
122    }
123
124    std::string ConfigFileSection::getFileEntry() const
125    {
126        if (this->additionalComment_ == "" || this->additionalComment_.size() == 0)
127            return ("[" + this->name_ + "]");
128        else
129            return ("[" + this->name_ + "] " + this->additionalComment_);
130    }
131
132    std::list<ConfigFileEntry*>::iterator ConfigFileSection::getEntryIterator(const std::string& name, const std::string& fallback)
133    {
134        for (std::list<ConfigFileEntry*>::iterator it = this->entries_.begin(); it != this->entries_.end(); ++it)
135            if ((*it)->getName() == name)
136                return it;
137
138        this->bUpdated_ = true;
139
140        return this->entries_.insert(this->entries_.end(), (ConfigFileEntry*)(new ConfigFileEntryValue(name, fallback)));
141    }
142
143    std::list<ConfigFileEntry*>::iterator ConfigFileSection::getEntryIterator(const std::string& name, unsigned int index, const std::string& fallback)
144    {
145        for (std::list<ConfigFileEntry*>::iterator it = this->entries_.begin(); it != this->entries_.end(); ++it)
146            if (((*it)->getName() == name) && ((*it)->getIndex() == index))
147                return it;
148
149        this->bUpdated_ = true;
150
151        if (index == 0)
152            return this->entries_.insert(this->entries_.end(), (ConfigFileEntry*)(new ConfigFileEntryVectorValue(name, index, fallback)));
153        else
154            return this->entries_.insert(++this->getEntryIterator(name, index - 1), (ConfigFileEntry*)(new ConfigFileEntryVectorValue(name, index, fallback)));
155    }
156
157
158    ////////////////
159    // ConfigFile //
160    ////////////////
161    ConfigFile::~ConfigFile()
162    {
163        for (std::list<ConfigFileSection*>::iterator it = this->sections_.begin(); it != this->sections_.end(); )
164            delete (*(it++));
165    }
166
167    void ConfigFile::load(bool bCreateIfNotExisting)
168    {
169        if (bCreateIfNotExisting)
170        {
171            // This creates the default config file if it's not existing
172            std::ofstream createFile;
173            createFile.open(this->filename_.c_str(), std::fstream::app);
174            createFile.close();
175        }
176
177        // Open the file
178        std::ifstream file;
179        file.open(this->filename_.c_str(), std::fstream::in);
180
181        if (!file.is_open())
182        {
183            COUT(1) << "An error occurred in ConfigFileManager.cc:" << std::endl;
184            COUT(1) << "Error: Couldn't open config-file \"" << this->filename_ << "\"." << std::endl;
185            return;
186        }
187
188        char linearray[CONFIG_FILE_MAX_LINELENGHT];
189
190        ConfigFileSection* newsection = 0;
191
192        while (file.good() && !file.eof())
193        {
194            file.getline(linearray, CONFIG_FILE_MAX_LINELENGHT);
195
196            std::string line = std::string(linearray);
197
198            std::string temp = getStripped(line);
199            if (!isEmpty(temp) && !isComment(temp))
200            {
201                unsigned int   pos1 = temp.find('[');
202                if (pos1 == 0) pos1 = line.find('['); else pos1 = std::string::npos;
203                unsigned int   pos2 = line.find(']');
204
205                if (pos1 != std::string::npos && pos2 != std::string::npos && pos2 > pos1 + 1)
206                {
207                    // New section
208                    std::string comment = line.substr(pos2 + 1);
209                    if (isComment(comment))
210                        newsection = new ConfigFileSection(line.substr(pos1 + 1, pos2 - pos1 - 1), comment);
211                    else
212                        newsection = new ConfigFileSection(line.substr(pos1 + 1, pos2 - pos1 - 1));
213                    this->sections_.insert(this->sections_.end(), newsection);
214                    continue;
215                }
216            }
217
218            if (newsection != 0)
219            {
220                if (isComment(line))
221                {
222                    // New comment
223                    newsection->getEntries().insert(newsection->getEntries().end(), new ConfigFileEntryComment(removeTrailingWhitespaces(line)));
224                    continue;
225                }
226                else
227                {
228                    unsigned int pos1 = line.find('=');
229
230                    if (pos1 != std::string::npos && pos1 > 0)
231                    {
232                        // New entry
233                        unsigned int pos2 = line.find('[');
234                        unsigned int pos3 = line.find(']');
235
236                        std::string value = removeTrailingWhitespaces(line.substr(pos1 + 1));
237                        std::string comment = "";
238
239                        std::string betweenQuotes = getStringBetweenQuotes(value);
240                        if (value.size() > 0 && value[0] == '"' && betweenQuotes != "" && betweenQuotes.size() > 0)
241                        {
242                            value = betweenQuotes;
243                            if (line.size() > pos1 + 1 + betweenQuotes.size() + 2)
244                                comment = removeTrailingWhitespaces(getComment(line.substr(pos1 + 1 + betweenQuotes.size() + 2)));
245                        }
246                        else
247                        {
248                            unsigned int pos4 = getCommentPosition(line);
249                            value = removeTrailingWhitespaces(line.substr(pos1 + 1, pos4 - pos1 - 1));
250                            if (pos4 != std::string::npos)
251                                comment = removeTrailingWhitespaces(line.substr(pos4));
252                        }
253
254                        if (pos2 != std::string::npos && pos3 != std::string::npos && pos3 > pos2 + 1)
255                        {
256                            // There might be an array index
257                            unsigned int index = 0;
258                            if (ConvertValue(&index, line.substr(pos2 + 1, pos3 - pos2 - 1)))
259                            {
260                                // New array
261                                std::list<ConfigFileEntry*>::iterator it = newsection->getEntryIterator(getStripped(line.substr(0, pos2)), index, value);
262                                (*it)->setValue(value);
263                                (*it)->setComment(comment);
264                                continue;
265                            }
266                        }
267
268                        // New value
269                        newsection->getEntries().insert(newsection->getEntries().end(), new ConfigFileEntryValue(getStripped(line.substr(0, pos1)), value, comment));
270                        continue;
271                    }
272                }
273            }
274        }
275
276        file.close();
277
278        COUT(3) << "Loaded config file \"" << this->filename_ << "\"." << std::endl;
279
280        // Save the file in case something changed (like stripped whitespaces)
281        this->save();
282    }
283
284    void ConfigFile::save() const
285    {
286        std::ofstream file;
287        file.open(this->filename_.c_str(), std::fstream::out);
288        file.setf(std::ios::fixed, std::ios::floatfield);
289        file.precision(6);
290
291        if (!file.is_open())
292        {
293            COUT(1) << "An error occurred in ConfigFileManager.cc:" << std::endl;
294            COUT(1) << "Error: Couldn't open config-file \"" << this->filename_ << "\"." << std::endl;
295            return;
296        }
297
298        for (std::list<ConfigFileSection*>::const_iterator it = this->sections_.begin(); it != this->sections_.end(); ++it)
299        {
300            file << (*it)->getFileEntry() << std::endl;
301
302            for (std::list<ConfigFileEntry*>::const_iterator it_entries = (*it)->getEntriesBegin(); it_entries != (*it)->getEntriesEnd(); ++it_entries)
303            {
304                file << (*it_entries)->getFileEntry() << std::endl;
305            }
306
307            file << std::endl;
308        }
309
310        file.close();
311
312        COUT(4) << "Saved config file \"" << this->filename_ << "\"." << std::endl;
313    }
314
315    void ConfigFile::clean(bool bCleanComments)
316    {
317        for (std::list<ConfigFileSection*>::iterator it1 = this->sections_.begin(); it1 != this->sections_.end(); )
318        {
319            std::map<std::string, Identifier*>::const_iterator it2 = Identifier::getIdentifierMap().find((*it1)->getName());
320            if (it2 != Identifier::getIdentifierMapEnd() && (*it2).second->hasConfigValues())
321            {
322                // The section exists, delete comment
323                if (bCleanComments)
324                    (*it1)->setComment("");
325                for (std::list<ConfigFileEntry*>::iterator it3 = (*it1)->entries_.begin(); it3 != (*it1)->entries_.end(); )
326                {
327                    std::map<std::string, ConfigValueContainer*>::const_iterator it4 = (*it2).second->getConfigValueMap().find((*it3)->getName());
328                    if (it4 != (*it2).second->getConfigValueMapEnd())
329                    {
330                        // The config-value exists, delete comment
331                        if (bCleanComments)
332                            (*it3)->setComment("");
333                        ++it3;
334                    }
335                    else
336                    {
337                        // The config-value doesn't exist
338                        delete (*it3);
339                        (*it1)->entries_.erase(it3++);
340                    }
341                }
342                ++it1;
343            }
344            else
345            {
346                // The section doesn't exist
347                delete (*it1);
348                this->sections_.erase(it1++);
349            }
350        }
351
352        // Save the file
353        this->save();
354    }
355
356    ConfigFileSection* ConfigFile::getSection(const std::string& section)
357    {
358        for (std::list<ConfigFileSection*>::iterator it = this->sections_.begin(); it != this->sections_.end(); ++it)
359            if ((*it)->getName() == section)
360                return (*it);
361
362        this->bUpdated_ = true;
363
364        return (*this->sections_.insert(this->sections_.end(), new ConfigFileSection(section)));
365    }
366
367    void ConfigFile::saveIfUpdated()
368    {
369        bool sectionsUpdated = false;
370
371        for (std::list<ConfigFileSection*>::iterator it = this->sections_.begin(); it != this->sections_.end(); ++it)
372        {
373            if ((*it)->bUpdated_)
374            {
375                sectionsUpdated = true;
376                (*it)->bUpdated_ = false;
377            }
378        }
379
380        if (this->bUpdated_ || sectionsUpdated)
381        {
382            this->bUpdated_ = false;
383            this->save();
384        }
385    }
386
387
388    ///////////////////////
389    // ConfigFileManager //
390    ///////////////////////
391    ConfigFileManager::ConfigFileManager()
392    {
393        this->setFile(CFT_Settings, DEFAULT_CONFIG_FILE);
394    }
395
396    ConfigFileManager::~ConfigFileManager()
397    {
398        for(std::map<ConfigFileType, ConfigFile*>::const_iterator it = this->configFiles_.begin(); it != this->configFiles_.end(); )
399            delete (*(it++)).second;
400    }
401
402    ConfigFileManager* ConfigFileManager::getSingleton()
403    {
404        static ConfigFileManager instance;
405        return (&instance);
406    }
407
408    void ConfigFileManager::setFile(ConfigFileType type, const std::string& filename, bool bCreateIfNotExisting)
409    {
410        std::map<ConfigFileType, ConfigFile*>::const_iterator it = this->configFiles_.find(type);
411        if (it != this->configFiles_.end())
412            if ((*it).second != 0)
413                delete (*it).second;
414
415        this->configFiles_[type] = new ConfigFile(this->getFilePath(filename));
416        this->load(type, bCreateIfNotExisting);
417    }
418
419    void ConfigFileManager::load(bool bCreateIfNotExisting)
420    {
421        for(std::map<ConfigFileType, ConfigFile*>::const_iterator it = this->configFiles_.begin(); it != this->configFiles_.end(); ++it)
422            (*it).second->load(bCreateIfNotExisting);
423
424        this->updateConfigValues();
425    }
426
427    void ConfigFileManager::save()
428    {
429        for(std::map<ConfigFileType, ConfigFile*>::const_iterator it = this->configFiles_.begin(); it != this->configFiles_.end(); ++it)
430            (*it).second->save();
431    }
432
433    void ConfigFileManager::clean(bool bCleanComments)
434    {
435        for(std::map<ConfigFileType, ConfigFile*>::const_iterator it = this->configFiles_.begin(); it != this->configFiles_.end(); ++it)
436            this->clean((*it).first, bCleanComments);
437    }
438
439    void ConfigFileManager::load(ConfigFileType type, bool bCreateIfNotExisting)
440    {
441        this->getFile(type)->load(bCreateIfNotExisting);
442        this->updateConfigValues(type);
443    }
444
445    void ConfigFileManager::save(ConfigFileType type)
446    {
447        this->getFile(type)->save();
448    }
449
450    void ConfigFileManager::clean(ConfigFileType type, bool bCleanComments)
451    {
452        this->getFile(type)->clean(bCleanComments);
453    }
454
455    void ConfigFileManager::updateConfigValues() const
456    {
457        for(std::map<ConfigFileType, ConfigFile*>::const_iterator it = this->configFiles_.begin(); it != this->configFiles_.end(); ++it)
458            this->updateConfigValues((*it).first);
459    }
460
461    void ConfigFileManager::updateConfigValues(ConfigFileType type) const
462    {
463        if (type == CFT_Settings)
464        {
465            for (std::map<std::string, Identifier*>::const_iterator it = Identifier::getIdentifierMapBegin(); it != Identifier::getIdentifierMapEnd(); ++it)
466            {
467                if ((*it).second->hasConfigValues() /* && (*it).second != ClassManager<KeyBinder>::getIdentifier()*/)
468                {
469                    for (std::map<std::string, ConfigValueContainer*>::const_iterator it2 = (*it).second->getConfigValueMapBegin(); it2 != (*it).second->getConfigValueMapEnd(); ++it2)
470                        (*it2).second->update();
471
472                    (*it).second->updateConfigValues();
473                }
474            }
475        }
476        else if (type == CFT_Keybindings)
477        {
478            // todo
479        }
480    }
481
482    ConfigFile* ConfigFileManager::getFile(ConfigFileType type)
483    {
484        std::map<ConfigFileType, ConfigFile*>::iterator it = this->configFiles_.find(type);
485        if (it != this->configFiles_.end())
486            return (*it).second;
487
488        if (type == CFT_Settings)
489            return this->configFiles_[type] = new ConfigFile(DEFAULT_CONFIG_FILE);
490        else
491            return this->configFiles_[type] = new ConfigFile("");
492    }
493
494    std::string ConfigFileManager::getFilePath(const std::string& name) const
495    {
496        return name;
497    }
498}
Note: See TracBrowser for help on using the repository browser.