Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/merge/src/core/ConfigFileManager.cc @ 1294

Last change on this file since 1294 was 1056, checked in by landauf, 17 years ago

don't panic, no codechanges!
added a link to www.orxonox.net

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