Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/libraries/core/ConfigFileManager.cc @ 6445

Last change on this file since 6445 was 6425, checked in by rgrieder, 15 years ago

Replaced "=" with " = " in our ini files for the config value.
Also made some changes to have const std::string& forwarding with getValue().

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