Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/orxonox/core/ConfigFileManager.cc @ 1052

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

merged core2 back to trunk
there might be some errors, wasn't able to test it yet due to some strange g++ and linker behaviour.

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