Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/core/ConfigFileManager.cc @ 5706

Last change on this file since 5706 was 5695, checked in by rgrieder, 15 years ago

Merged resource2 branch back to trunk.

IMPORTANT NOTE:
Upon this merge you need to specifically call your data directory "data_extern" when checking it out (when you don't provide a name, it will be just called 'trunk').
The new CMake variable is EXTERNAL_DATA_DIRECTORY. DATA_DIRECTORY now points to the one the source part of the repository.
UPDATE YOUR DATA DIRECTORY AS WELL!!!

  • Property svn:eol-style set to native
File size: 21.1 KB
RevLine 
[1505]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"
[2103]30
[2710]31#include <boost/filesystem.hpp>
32
[1505]33#include "util/Convert.h"
[3196]34#include "util/Math.h"
[3280]35#include "util/StringUtils.h"
[2103]36#include "ConsoleCommand.h"
37#include "ConfigValueContainer.h"
[2710]38#include "Core.h"
[1505]39
40namespace orxonox
41{
[1747]42    SetConsoleCommandShortcutExtern(config).argumentCompleter(0, autocompletion::configvalueclasses()).argumentCompleter(1, autocompletion::configvalues()).argumentCompleter(2, autocompletion::configvalue());
43    SetConsoleCommandShortcutExtern(tconfig).argumentCompleter(0, autocompletion::configvalueclasses()).argumentCompleter(1, autocompletion::configvalues()).argumentCompleter(2, autocompletion::configvalue());
[1505]44    SetConsoleCommandShortcutExtern(reloadConfig);
45    SetConsoleCommandShortcutExtern(cleanConfig);
[1747]46    SetConsoleCommandShortcutExtern(loadSettings).argumentCompleter(0, autocompletion::files());
[1505]47
48    bool config(const std::string& classname, const std::string& varname, const std::string& value)
49    {
50        std::map<std::string, Identifier*>::const_iterator identifier = Identifier::getLowercaseIdentifierMap().find(getLowercase(classname));
51        if (identifier != Identifier::getLowercaseIdentifierMapEnd())
52        {
53            std::map<std::string, ConfigValueContainer*>::const_iterator variable = (*identifier).second->getLowercaseConfigValueMap().find(getLowercase(varname));
54            if (variable != (*identifier).second->getLowercaseConfigValueMapEnd())
55                return (*variable).second->set(value);
56        }
57        return false;
58    }
59
60    bool tconfig(const std::string& classname, const std::string& varname, const std::string& value)
61    {
62        std::map<std::string, Identifier*>::const_iterator identifier = Identifier::getLowercaseIdentifierMap().find(getLowercase(classname));
63        if (identifier != Identifier::getLowercaseIdentifierMapEnd())
64        {
65            std::map<std::string, ConfigValueContainer*>::const_iterator variable = (*identifier).second->getLowercaseConfigValueMap().find(getLowercase(varname));
66            if (variable != (*identifier).second->getLowercaseConfigValueMapEnd())
67                return (*variable).second->tset(value);
68        }
69        return false;
70    }
71
72    void reloadConfig()
73    {
[1795]74        ConfigFileManager::getInstance().load();
[1505]75    }
76
77    void cleanConfig()
78    {
[1795]79        ConfigFileManager::getInstance().clean(false);
[1505]80    }
81
82    void loadSettings(const std::string& filename)
83    {
[2103]84        ConfigFileManager::getInstance().setFilename(ConfigFileType::Settings, filename);
[1505]85    }
86
87    //////////////////////////
88    // ConfigFileEntryValue //
89    //////////////////////////
90
91    void ConfigFileEntryValue::setValue(const std::string& value)
92    {
93        if (!this->bString_)
94            this->value_ = value;
95        else
96            this->value_ = "\"" + addSlashes(stripEnclosingQuotes(value)) + "\"";
97    }
98
99    std::string ConfigFileEntryValue::getValue() const
100    {
101        if (!this->bString_)
102            return this->value_;
103        else
104            return removeSlashes(stripEnclosingQuotes(this->value_));
105    }
106
107    std::string ConfigFileEntryValue::getFileEntry() const
108    {
109        if (this->additionalComment_ == "" || this->additionalComment_.size() == 0)
110            return (this->name_ + "=" + this->value_);
111        else
112            return (this->name_ + "=" + this->value_ + " " + this->additionalComment_);
113    }
114
115
[2103]116    ////////////////////////////////
[1505]117    // ConfigFileEntryVectorValue //
[2103]118    ////////////////////////////////
[1505]119    std::string ConfigFileEntryVectorValue::getFileEntry() const
120    {
121        if (this->additionalComment_ == "" || this->additionalComment_.size() == 0)
[3280]122            return (this->name_ + "[" + multi_cast<std::string>(this->index_) + "]" + "=" + this->value_);
[1505]123        else
[3280]124            return (this->name_ + "[" + multi_cast<std::string>(this->index_) + "]=" + this->value_ + " " + this->additionalComment_);
[1505]125    }
126
127
128    ///////////////////////
129    // ConfigFileSection //
130    ///////////////////////
131    ConfigFileSection::~ConfigFileSection()
132    {
133        for (std::list<ConfigFileEntry*>::iterator it = this->entries_.begin(); it != this->entries_.end(); )
134            delete (*(it++));
135    }
136
137    void ConfigFileSection::deleteVectorEntries(const std::string& name, unsigned int startindex)
138    {
139        for (std::list<ConfigFileEntry*>::iterator it = this->entries_.begin(); it != this->entries_.end(); )
140        {
141            if (((*it)->getName() == name) && ((*it)->getIndex() >= startindex))
142            {
143                delete (*it);
144                this->entries_.erase(it++);
145            }
146            else
147            {
148                ++it;
149            }
150        }
151    }
152
153    unsigned int ConfigFileSection::getVectorSize(const std::string& name)
154    {
155        unsigned int size = 0;
156        for (std::list<ConfigFileEntry*>::const_iterator it = this->entries_.begin(); it != this->entries_.end(); ++it)
157            if ((*it)->getName() == name)
158                if ((*it)->getIndex() > size)
159                    size = (*it)->getIndex();
[2662]160        if (size == 0)
161            return 0;
162        else
163            return (size + 1);
[1505]164    }
165
166    std::string ConfigFileSection::getFileEntry() const
167    {
168        if (this->additionalComment_ == "" || this->additionalComment_.size() == 0)
169            return ("[" + this->name_ + "]");
170        else
171            return ("[" + this->name_ + "] " + this->additionalComment_);
172    }
173
174    std::list<ConfigFileEntry*>::iterator ConfigFileSection::getEntryIterator(const std::string& name, const std::string& fallback, bool bString)
175    {
176        for (std::list<ConfigFileEntry*>::iterator it = this->entries_.begin(); it != this->entries_.end(); ++it)
177        {
178            if ((*it)->getName() == name)
179            {
180                (*it)->setString(bString);
181                return it;
182            }
183        }
184
185        this->bUpdated_ = true;
186
[2896]187        return this->entries_.insert(this->entries_.end(), static_cast<ConfigFileEntry*>(new ConfigFileEntryValue(name, fallback, bString)));
[1505]188    }
189
190    std::list<ConfigFileEntry*>::iterator ConfigFileSection::getEntryIterator(const std::string& name, unsigned int index, const std::string& fallback, bool bString)
191    {
192        for (std::list<ConfigFileEntry*>::iterator it = this->entries_.begin(); it != this->entries_.end(); ++it)
193        {
194            if (((*it)->getName() == name) && ((*it)->getIndex() == index))
195            {
196                (*it)->setString(bString);
197                return it;
198            }
199        }
200
201        this->bUpdated_ = true;
202
203        if (index == 0)
[2896]204            return this->entries_.insert(this->entries_.end(), static_cast<ConfigFileEntry*>(new ConfigFileEntryVectorValue(name, index, fallback, bString)));
[1505]205        else
[2896]206            return this->entries_.insert(++this->getEntryIterator(name, index - 1, "", bString), static_cast<ConfigFileEntry*>(new ConfigFileEntryVectorValue(name, index, fallback, bString)));
[1505]207    }
208
209
210    ////////////////
211    // ConfigFile //
212    ////////////////
213    ConfigFile::~ConfigFile()
214    {
[2103]215        this->clear();
[1505]216    }
217
218    void ConfigFile::load(bool bCreateIfNotExisting)
219    {
[2710]220        // Be sure we start from new in the memory
[2103]221        this->clear();
[1505]222
[2710]223        // Get default file if necessary and available
224        boost::filesystem::path filepath(Core::getConfigPath() / this->filename_);
225        if (!boost::filesystem::exists(filepath))
226        {
[5695]227            // Try to get default one from the data folder
228            boost::filesystem::path defaultFilepath(Core::getDataPath() / "defaultConfig" / this->filename_);
[2710]229            if (boost::filesystem::exists(defaultFilepath))
230            {
[2725]231                COUT(3) << "Copied " << this->filename_ << " from the defaultConfig folder." << std::endl;
[2710]232                boost::filesystem::copy_file(defaultFilepath, filepath);
233            }
234        }
[2103]235
[1505]236        // Open the file
237        std::ifstream file;
[2759]238        file.open(filepath.string().c_str(), std::fstream::in);
[2710]239        if (file.is_open())
[1505]240        {
[2710]241            ConfigFileSection* newsection = 0;
[1505]242
[2710]243            while (file.good() && !file.eof())
[1505]244            {
[3198]245                std::string line;
246                std::getline(file, line);
[1505]247
[2710]248                std::string temp = getStripped(line);
249                if (!isEmpty(temp) && !isComment(temp))
[1505]250                {
[2710]251                    size_t   pos1 = temp.find('[');
252                    if (pos1 == 0) pos1 = line.find('['); else pos1 = std::string::npos;
253                    size_t   pos2 = line.find(']');
[1505]254
[2710]255                    if (pos1 != std::string::npos && pos2 != std::string::npos && pos2 > pos1 + 1)
[1505]256                    {
[2710]257                        // New section
258                        std::string comment = line.substr(pos2 + 1);
259                        if (isComment(comment))
260                            newsection = new ConfigFileSection(line.substr(pos1 + 1, pos2 - pos1 - 1), comment);
[1505]261                        else
[2710]262                            newsection = new ConfigFileSection(line.substr(pos1 + 1, pos2 - pos1 - 1));
263                        this->sections_.insert(this->sections_.end(), newsection);
264                        continue;
265                    }
266                }
[1505]267
[2710]268                if (newsection != 0)
269                {
270                    if (isComment(line))
271                    {
272                        // New comment
273                        newsection->getEntries().insert(newsection->getEntries().end(), new ConfigFileEntryComment(removeTrailingWhitespaces(line)));
274                        continue;
275                    }
276                    else
277                    {
278                        size_t pos1 = line.find('=');
279
280                        if (pos1 != std::string::npos && pos1 > 0)
[1505]281                        {
[2710]282                            // New entry
283                            size_t pos2 = line.find('[');
284                            size_t pos3 = line.find(']');
285                            size_t commentposition = getNextCommentPosition(line, pos1 + 1);
286                            while (isBetweenQuotes(line, commentposition))
[1505]287                            {
[2710]288                                commentposition = getNextCommentPosition(line, commentposition + 1);
[1505]289                            }
[2710]290                            std::string value = "", comment = "";
291                            if (commentposition == std::string::npos)
292                            {
293                                value = removeTrailingWhitespaces(line.substr(pos1 + 1));
294                            }
295                            else
296                            {
297                                value = removeTrailingWhitespaces(line.substr(pos1 + 1, commentposition - pos1 - 1));
298                                comment = removeTrailingWhitespaces(line.substr(commentposition));
299                            }
300
301                            if (pos2 != std::string::npos && pos3 != std::string::npos && pos3 > pos2 + 1)
302                            {
303                                // There might be an array index
304                                unsigned int index = 0;
[3196]305                                if (convertValue(&index, line.substr(pos2 + 1, pos3 - pos2 - 1)))
[2710]306                                {
307                                    // New array
308                                    std::list<ConfigFileEntry*>::iterator it = newsection->getEntryIterator(getStripped(line.substr(0, pos2)), index, value, false);
309                                    (*it)->setValue(value);
310                                    (*it)->setComment(comment);
311                                    continue;
312                                }
313                            }
314
315                            // New value
316                            newsection->getEntries().insert(newsection->getEntries().end(), new ConfigFileEntryValue(getStripped(line.substr(0, pos1)), value, false, comment));
317                            continue;
[1505]318                        }
319                    }
320                }
321            }
322
[2710]323            file.close();
[1505]324
[2710]325            COUT(3) << "Loaded config file \"" << this->filename_ << "\"." << std::endl;
[1505]326
[2710]327            // Save the file in case something changed (like stripped whitespaces)
328            this->save();
[2103]329
[2710]330            // Update all ConfigValueContainers
331            this->updateConfigValues();
332        } // end file.is_open()
[1505]333    }
334
335    void ConfigFile::save() const
336    {
337        std::ofstream file;
[5695]338        file.open((Core::getConfigPathString() + filename_).c_str(), std::fstream::out);
[1505]339        file.setf(std::ios::fixed, std::ios::floatfield);
340        file.precision(6);
341
342        if (!file.is_open())
343        {
344            COUT(1) << "An error occurred in ConfigFileManager.cc:" << std::endl;
345            COUT(1) << "Error: Couldn't open config-file \"" << this->filename_ << "\"." << std::endl;
346            return;
347        }
348
349        for (std::list<ConfigFileSection*>::const_iterator it = this->sections_.begin(); it != this->sections_.end(); ++it)
350        {
351            file << (*it)->getFileEntry() << std::endl;
352
353            for (std::list<ConfigFileEntry*>::const_iterator it_entries = (*it)->getEntriesBegin(); it_entries != (*it)->getEntriesEnd(); ++it_entries)
354            {
355                file << (*it_entries)->getFileEntry() << std::endl;
356            }
357
358            file << std::endl;
359        }
360
361        file.close();
362
363        COUT(4) << "Saved config file \"" << this->filename_ << "\"." << std::endl;
364    }
365
[2103]366    void ConfigFile::saveAs(const std::string& filename)
[1505]367    {
368        std::string temp = this->filename_;
369        this->filename_ = filename;
370        this->save();
371        this->filename_ = temp;
372    }
373
374    void ConfigFile::clean(bool bCleanComments)
375    {
376        for (std::list<ConfigFileSection*>::iterator it1 = this->sections_.begin(); it1 != this->sections_.end(); )
377        {
378            std::map<std::string, Identifier*>::const_iterator it2 = Identifier::getIdentifierMap().find((*it1)->getName());
379            if (it2 != Identifier::getIdentifierMapEnd() && (*it2).second->hasConfigValues())
380            {
381                // The section exists, delete comment
382                if (bCleanComments)
383                    (*it1)->setComment("");
384                for (std::list<ConfigFileEntry*>::iterator it3 = (*it1)->entries_.begin(); it3 != (*it1)->entries_.end(); )
385                {
386                    std::map<std::string, ConfigValueContainer*>::const_iterator it4 = (*it2).second->getConfigValueMap().find((*it3)->getName());
387                    if (it4 != (*it2).second->getConfigValueMapEnd())
388                    {
389                        // The config-value exists, delete comment
390                        if (bCleanComments)
391                            (*it3)->setComment("");
392                        ++it3;
393                    }
394                    else
395                    {
396                        // The config-value doesn't exist
397                        delete (*it3);
398                        (*it1)->entries_.erase(it3++);
399                    }
400                }
401                ++it1;
402            }
403            else
404            {
405                // The section doesn't exist
406                delete (*it1);
407                this->sections_.erase(it1++);
408            }
409        }
410
411        // Save the file
412        this->save();
413    }
414
[2103]415    void ConfigFile::clear()
416    {
417        for (std::list<ConfigFileSection*>::iterator it = this->sections_.begin(); it != this->sections_.end(); )
418            delete (*(it++));
419        this->sections_.clear();
420    }
421
[1505]422    ConfigFileSection* ConfigFile::getSection(const std::string& section)
423    {
424        for (std::list<ConfigFileSection*>::iterator it = this->sections_.begin(); it != this->sections_.end(); ++it)
425            if ((*it)->getName() == section)
426                return (*it);
427
428        this->bUpdated_ = true;
429
430        return (*this->sections_.insert(this->sections_.end(), new ConfigFileSection(section)));
431    }
432
433    void ConfigFile::saveIfUpdated()
434    {
435        bool sectionsUpdated = false;
436
437        for (std::list<ConfigFileSection*>::iterator it = this->sections_.begin(); it != this->sections_.end(); ++it)
438        {
439            if ((*it)->bUpdated_)
440            {
441                sectionsUpdated = true;
442                (*it)->bUpdated_ = false;
443            }
444        }
445
446        if (this->bUpdated_ || sectionsUpdated)
447        {
448            this->bUpdated_ = false;
449            this->save();
450        }
451    }
452
[2103]453    void ConfigFile::updateConfigValues()
454    {
455        if (this->type_ == ConfigFileType::Settings)
456        {
457            for (std::map<std::string, Identifier*>::const_iterator it = Identifier::getIdentifierMapBegin(); it != Identifier::getIdentifierMapEnd(); ++it)
458            {
459                if (it->second->hasConfigValues())
460                {
461                    for (std::map<std::string, ConfigValueContainer*>::const_iterator it2 = (*it).second->getConfigValueMapBegin(); it2 != (*it).second->getConfigValueMapEnd(); ++it2)
462                        it2->second->update();
[1505]463
[2103]464                    it->second->updateConfigValues();
465                }
466            }
467        }
468    }
469
470
[1505]471    ///////////////////////
472    // ConfigFileManager //
473    ///////////////////////
[2103]474
[5695]475    ConfigFileManager* ConfigFileManager::singletonPtr_s = 0;
476
477    std::string ConfigFileManager::DEFAULT_CONFIG_FILE = "default.ini";
478
[1505]479    ConfigFileManager::ConfigFileManager()
[2103]480         : mininmalFreeType_(ConfigFileType::numberOfReservedTypes)
[1505]481    {
482    }
483
484    ConfigFileManager::~ConfigFileManager()
485    {
486        for(std::map<ConfigFileType, ConfigFile*>::const_iterator it = this->configFiles_.begin(); it != this->configFiles_.end(); )
[2103]487            delete (it++)->second;
[1505]488    }
489
[2103]490    void ConfigFileManager::setFilename(ConfigFileType type, const std::string& filename)
[1505]491    {
492        std::map<ConfigFileType, ConfigFile*>::const_iterator it = this->configFiles_.find(type);
493        if (it != this->configFiles_.end())
[2103]494        {
495            assert(it->second);
496            delete it->second;
497        }
498        this->configFiles_[type] = new ConfigFile(filename, type);
499        this->load(type);
[1505]500    }
501
[2103]502    void ConfigFileManager::load()
[1505]503    {
504        for(std::map<ConfigFileType, ConfigFile*>::const_iterator it = this->configFiles_.begin(); it != this->configFiles_.end(); ++it)
[2103]505            it->second->load();
[1505]506    }
507
508    void ConfigFileManager::save()
509    {
510        for(std::map<ConfigFileType, ConfigFile*>::const_iterator it = this->configFiles_.begin(); it != this->configFiles_.end(); ++it)
[2103]511            it->second->save();
[1505]512    }
513
514    void ConfigFileManager::clean(bool bCleanComments)
515    {
516        for(std::map<ConfigFileType, ConfigFile*>::const_iterator it = this->configFiles_.begin(); it != this->configFiles_.end(); ++it)
[2103]517            this->clean(it->first, bCleanComments);
[1505]518    }
519
[2103]520    void ConfigFileManager::load(ConfigFileType type)
[1505]521    {
[2103]522        this->getFile(type)->load();
[1505]523    }
524
525    void ConfigFileManager::save(ConfigFileType type)
526    {
527        this->getFile(type)->save();
528    }
529
[2103]530    void ConfigFileManager::saveAs(ConfigFileType type, const std::string& saveFilename)
[1505]531    {
[2103]532        this->getFile(type)->saveAs(saveFilename);
[1505]533    }
534
535    void ConfigFileManager::clean(ConfigFileType type, bool bCleanComments)
536    {
537        this->getFile(type)->clean(bCleanComments);
538    }
539
[2103]540    void ConfigFileManager::updateConfigValues()
[1505]541    {
542        for(std::map<ConfigFileType, ConfigFile*>::const_iterator it = this->configFiles_.begin(); it != this->configFiles_.end(); ++it)
[2103]543            it->second->updateConfigValues();
[1505]544    }
545
[2103]546    void ConfigFileManager::updateConfigValues(ConfigFileType type)
[1505]547    {
[2103]548        this->getFile(type)->updateConfigValues();
[1505]549    }
550
[2103]551    const std::string& ConfigFileManager::getFilename(ConfigFileType type)
[1505]552    {
[2103]553        std::map<ConfigFileType, ConfigFile*>::const_iterator it = this->configFiles_.find(type);
[1505]554        if (it != this->configFiles_.end())
[2103]555            return it->second->getFilename();
[1505]556        else
[2103]557            return BLANKSTRING;
[1505]558    }
559
[2103]560    ConfigFile* ConfigFileManager::getFile(ConfigFileType type)
[1505]561    {
[2103]562        std::map<ConfigFileType, ConfigFile*>::const_iterator it = this->configFiles_.find(type);
563        if (it != this->configFiles_.end())
564            return it->second;
565        else
566        {
[3301]567            COUT(1) << "ConfigFileManager: Can't find a config file for type with ID " << static_cast<int>(type) << std::endl;
[2103]568            COUT(1) << "Using " << DEFAULT_CONFIG_FILE << " file." << std::endl;
569            this->setFilename(type, DEFAULT_CONFIG_FILE);
570            return getFile(type);
571        }
[1505]572    }
573}
Note: See TracBrowser for help on using the repository browser.