Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: sandbox/src/libraries/core/ConfigFileManager.cc @ 7324

Last change on this file since 7324 was 6038, checked in by rgrieder, 15 years ago

Synchronised sandbox with current code trunk. There should be a few bug fixes.

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