Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/forks/sandbox/src/libraries/core/ConfigFileManager.cc @ 8844

Last change on this file since 8844 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
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
31#include <boost/filesystem.hpp>
32
33#include "util/Convert.h"
34#include "util/Math.h"
35#include "util/StringUtils.h"
36#include "ConfigValueContainer.h"
37#include "PathConfig.h"
38
39namespace orxonox
40{
41    bool config(const std::string& classname, const std::string& varname, const std::string& value)
42    {
43        std::map<std::string, Identifier*>::const_iterator identifier = Identifier::getLowercaseStringIdentifierMap().find(getLowercase(classname));
44        if (identifier != Identifier::getLowercaseStringIdentifierMapEnd())
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    {
55        std::map<std::string, Identifier*>::const_iterator identifier = Identifier::getLowercaseStringIdentifierMap().find(getLowercase(classname));
56        if (identifier != Identifier::getLowercaseStringIdentifierMapEnd())
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    {
67        ConfigFileManager::getInstance().load();
68    }
69
70    void cleanConfig()
71    {
72        ConfigFileManager::getInstance().clean(false);
73    }
74
75    void loadSettings(const std::string& filename)
76    {
77        ConfigFileManager::getInstance().setFilename(ConfigFileType::Settings, filename);
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
109    ////////////////////////////////
110    // ConfigFileEntryVectorValue //
111    ////////////////////////////////
112    std::string ConfigFileEntryVectorValue::getFileEntry() const
113    {
114        if (this->additionalComment_ == "" || this->additionalComment_.size() == 0)
115            return (this->name_ + "[" + multi_cast<std::string>(this->index_) + "]" + "=" + this->value_);
116        else
117            return (this->name_ + "[" + multi_cast<std::string>(this->index_) + "]=" + this->value_ + " " + this->additionalComment_);
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();
153        if (size == 0)
154            return 0;
155        else
156            return (size + 1);
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
180        return this->entries_.insert(this->entries_.end(), static_cast<ConfigFileEntry*>(new ConfigFileEntryValue(name, fallback, bString)));
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)
197            return this->entries_.insert(this->entries_.end(), static_cast<ConfigFileEntry*>(new ConfigFileEntryVectorValue(name, index, fallback, bString)));
198        else
199            return this->entries_.insert(++this->getEntryIterator(name, index - 1, "", bString), static_cast<ConfigFileEntry*>(new ConfigFileEntryVectorValue(name, index, fallback, bString)));
200    }
201
202
203    ////////////////
204    // ConfigFile //
205    ////////////////
206    ConfigFile::~ConfigFile()
207    {
208        this->clear();
209    }
210
211    void ConfigFile::load(bool bCreateIfNotExisting)
212    {
213        // Be sure we start from new in the memory
214        this->clear();
215
216        // Get default file if necessary and available
217        boost::filesystem::path filepath(PathConfig::getConfigPath() / this->filename_);
218        if (!boost::filesystem::exists(filepath))
219        {
220            // Try to get default one from the data folder
221            boost::filesystem::path defaultFilepath(PathConfig::getDataPath() / "defaultConfig" / this->filename_);
222            if (boost::filesystem::exists(defaultFilepath))
223            {
224                COUT(3) << "Copied " << this->filename_ << " from the defaultConfig folder." << std::endl;
225                boost::filesystem::copy_file(defaultFilepath, filepath);
226            }
227        }
228
229        // Open the file
230        std::ifstream file;
231        file.open(filepath.string().c_str(), std::fstream::in);
232        if (file.is_open())
233        {
234            ConfigFileSection* newsection = 0;
235
236            while (file.good() && !file.eof())
237            {
238                std::string line;
239                std::getline(file, line);
240
241                std::string temp = getStripped(line);
242                if (!isEmpty(temp) && !isComment(temp))
243                {
244                    size_t   pos1 = temp.find('[');
245                    if (pos1 == 0) pos1 = line.find('['); else pos1 = std::string::npos;
246                    size_t   pos2 = line.find(']');
247
248                    if (pos1 != std::string::npos && pos2 != std::string::npos && pos2 > pos1 + 1)
249                    {
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);
254                        else
255                            newsection = new ConfigFileSection(line.substr(pos1 + 1, pos2 - pos1 - 1));
256                        this->sections_.insert(this->sections_.end(), newsection);
257                        continue;
258                    }
259                }
260
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)
274                        {
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))
280                            {
281                                commentposition = getNextCommentPosition(line, commentposition + 1);
282                            }
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;
298                                if (convertValue(&index, line.substr(pos2 + 1, pos3 - pos2 - 1)))
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;
311                        }
312                    }
313                }
314            }
315
316            file.close();
317
318            COUT(3) << "Loaded config file \"" << this->filename_ << "\"." << std::endl;
319
320            // Save the file in case something changed (like stripped whitespaces)
321            this->save();
322
323            // Update all ConfigValueContainers
324            this->updateConfigValues();
325        } // end file.is_open()
326    }
327
328    void ConfigFile::save() const
329    {
330        std::ofstream file;
331        file.open((PathConfig::getConfigPathString() + filename_).c_str(), std::fstream::out);
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
359    void ConfigFile::saveAs(const std::string& filename)
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        {
371            std::map<std::string, Identifier*>::const_iterator it2 = Identifier::getStringIdentifierMap().find((*it1)->getName());
372            if (it2 != Identifier::getStringIdentifierMapEnd() && (*it2).second->hasConfigValues())
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
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
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
446    void ConfigFile::updateConfigValues()
447    {
448        if (this->type_ == ConfigFileType::Settings)
449        {
450            for (std::map<std::string, Identifier*>::const_iterator it = Identifier::getStringIdentifierMapBegin(); it != Identifier::getStringIdentifierMapEnd(); ++it)
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();
456
457                    it->second->updateConfigValues();
458                }
459            }
460        }
461    }
462
463
464    ///////////////////////
465    // ConfigFileManager //
466    ///////////////////////
467
468    ConfigFileManager* ConfigFileManager::singletonPtr_s = 0;
469
470    std::string ConfigFileManager::DEFAULT_CONFIG_FILE = "default.ini";
471
472    ConfigFileManager::ConfigFileManager()
473         : mininmalFreeType_(ConfigFileType::numberOfReservedTypes)
474    {
475    }
476
477    ConfigFileManager::~ConfigFileManager()
478    {
479        for(std::map<ConfigFileType, ConfigFile*>::const_iterator it = this->configFiles_.begin(); it != this->configFiles_.end(); )
480            delete (it++)->second;
481    }
482
483    void ConfigFileManager::setFilename(ConfigFileType type, const std::string& filename)
484    {
485        std::map<ConfigFileType, ConfigFile*>::const_iterator it = this->configFiles_.find(type);
486        if (it != this->configFiles_.end())
487        {
488            assert(it->second);
489            delete it->second;
490        }
491        this->configFiles_[type] = new ConfigFile(filename, type);
492        this->load(type);
493    }
494
495    void ConfigFileManager::load()
496    {
497        for(std::map<ConfigFileType, ConfigFile*>::const_iterator it = this->configFiles_.begin(); it != this->configFiles_.end(); ++it)
498            it->second->load();
499    }
500
501    void ConfigFileManager::save()
502    {
503        for(std::map<ConfigFileType, ConfigFile*>::const_iterator it = this->configFiles_.begin(); it != this->configFiles_.end(); ++it)
504            it->second->save();
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)
510            this->clean(it->first, bCleanComments);
511    }
512
513    void ConfigFileManager::load(ConfigFileType type)
514    {
515        this->getFile(type)->load();
516    }
517
518    void ConfigFileManager::save(ConfigFileType type)
519    {
520        this->getFile(type)->save();
521    }
522
523    void ConfigFileManager::saveAs(ConfigFileType type, const std::string& saveFilename)
524    {
525        this->getFile(type)->saveAs(saveFilename);
526    }
527
528    void ConfigFileManager::clean(ConfigFileType type, bool bCleanComments)
529    {
530        this->getFile(type)->clean(bCleanComments);
531    }
532
533    void ConfigFileManager::updateConfigValues()
534    {
535        for(std::map<ConfigFileType, ConfigFile*>::const_iterator it = this->configFiles_.begin(); it != this->configFiles_.end(); ++it)
536            it->second->updateConfigValues();
537    }
538
539    void ConfigFileManager::updateConfigValues(ConfigFileType type)
540    {
541        this->getFile(type)->updateConfigValues();
542    }
543
544    const std::string& ConfigFileManager::getFilename(ConfigFileType type)
545    {
546        std::map<ConfigFileType, ConfigFile*>::const_iterator it = this->configFiles_.find(type);
547        if (it != this->configFiles_.end())
548            return it->second->getFilename();
549        else
550            return BLANKSTRING;
551    }
552
553    ConfigFile* ConfigFileManager::getFile(ConfigFileType type)
554    {
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        {
560            COUT(1) << "ConfigFileManager: Can't find a config file for type with ID " << static_cast<int>(type) << std::endl;
561            COUT(1) << "Using " << DEFAULT_CONFIG_FILE << " file." << std::endl;
562            this->setFilename(type, DEFAULT_CONFIG_FILE);
563            return getFile(type);
564        }
565    }
566}
Note: See TracBrowser for help on using the repository browser.