Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

bugfix

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.