Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/console/src/core/ConfigFileManager.cc @ 1435

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

after some changes in MultiTypeMath and co., the new config and tconfig commands work very well. they substitute set and tset respectively.

File size: 20.7 KB
RevLine 
[1006]1/*
2 *   ORXONOX - the hottest 3D action shooter ever to exist
[1056]3 *                    > www.orxonox.net <
[1006]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"
[1026]30#include "ConfigValueContainer.h"
[1006]31#include "ConsoleCommand.h"
32#include "Identifier.h"
33#include "util/Convert.h"
34#include "util/String.h"
35
36#define CONFIG_FILE_MAX_LINELENGHT 1024
37
38namespace orxonox
39{
[1434]40    SetConsoleCommandShortcutExtern(config).setArgumentCompleter(0, autocompletion::configvalueclasses()).setArgumentCompleter(1, autocompletion::configvalues()).setArgumentCompleter(2, autocompletion::configvalue());
[1435]41    SetConsoleCommandShortcutExtern(tconfig).setArgumentCompleter(0, autocompletion::configvalueclasses()).setArgumentCompleter(1, autocompletion::configvalues()).setArgumentCompleter(2, autocompletion::configvalue());
[1341]42    SetConsoleCommandShortcutExtern(reloadConfig);
43    SetConsoleCommandShortcutExtern(cleanConfig);
44    SetConsoleCommandShortcutExtern(loadSettings);
45    SetConsoleCommandShortcutExtern(loadKeybindings);
[1006]46
[1434]47    bool config(const std::string& classname, const std::string& varname, const std::string& value)
48    {
49        std::map<std::string, Identifier*>::const_iterator identifier = Identifier::getLowercaseIdentifierMap().find(getLowercase(classname));
50        if (identifier != Identifier::getLowercaseIdentifierMapEnd())
51        {
52            std::map<std::string, ConfigValueContainer*>::const_iterator variable = (*identifier).second->getLowercaseConfigValueMap().find(getLowercase(varname));
53            if (variable != (*identifier).second->getLowercaseConfigValueMapEnd())
[1435]54                return (*variable).second->set(value);
[1434]55        }
56        return false;
57    }
58
59    bool tconfig(const std::string& classname, const std::string& varname, const std::string& value)
60    {
61        std::map<std::string, Identifier*>::const_iterator identifier = Identifier::getLowercaseIdentifierMap().find(getLowercase(classname));
62        if (identifier != Identifier::getLowercaseIdentifierMapEnd())
63        {
64            std::map<std::string, ConfigValueContainer*>::const_iterator variable = (*identifier).second->getLowercaseConfigValueMap().find(getLowercase(varname));
65            if (variable != (*identifier).second->getLowercaseConfigValueMapEnd())
66                return (*variable).second->tset(value);
67        }
68        return false;
69    }
70
[1006]71    void reloadConfig()
72    {
[1020]73        ConfigFileManager::getSingleton()->load();
[1006]74    }
75
76    void cleanConfig()
77    {
[1030]78        ConfigFileManager::getSingleton()->clean(false);
[1006]79    }
80
81    void loadSettings(const std::string& filename)
82    {
[1027]83        ConfigFileManager::getSingleton()->setFile(CFT_Settings, filename, false);
[1006]84    }
85
86    void loadKeybindings(const std::string& filename)
87    {
[1020]88        ConfigFileManager::getSingleton()->setFile(CFT_Keybindings, filename);
[1006]89    }
90
91
92    //////////////////////////
93    // ConfigFileEntryValue //
94    //////////////////////////
[1049]95
96    void ConfigFileEntryValue::setValue(const std::string& value)
97    {
98        if (!this->bString_)
99            this->value_ = value;
100        else
[1050]101            this->value_ = "\"" + addSlashes(stripEnclosingQuotes(value)) + "\"";
[1049]102    }
103
104    std::string ConfigFileEntryValue::getValue() const
105    {
106        if (!this->bString_)
107            return this->value_;
108        else
109            return removeSlashes(stripEnclosingQuotes(this->value_));
110    }
111
[1006]112    std::string ConfigFileEntryValue::getFileEntry() const
113    {
114        if (this->additionalComment_ == "" || this->additionalComment_.size() == 0)
115            return (this->name_ + "=" + this->value_);
116        else
117            return (this->name_ + "=" + this->value_ + " " + this->additionalComment_);
118    }
119
120
121    ///////////////////////////////
[1030]122    // ConfigFileEntryVectorValue //
[1006]123    ///////////////////////////////
[1030]124    std::string ConfigFileEntryVectorValue::getFileEntry() const
[1006]125    {
126        if (this->additionalComment_ == "" || this->additionalComment_.size() == 0)
[1030]127            return (this->name_ + "[" + getConvertedValue<unsigned int, std::string>(this->index_, "0") + "]" + "=" + this->value_);
[1006]128        else
[1030]129            return (this->name_ + "[" + getConvertedValue<unsigned int, std::string>(this->index_, "0") + "]=" + this->value_ + " " + this->additionalComment_);
[1006]130    }
131
132
133    ///////////////////////
134    // ConfigFileSection //
135    ///////////////////////
136    ConfigFileSection::~ConfigFileSection()
137    {
138        for (std::list<ConfigFileEntry*>::iterator it = this->entries_.begin(); it != this->entries_.end(); )
139            delete (*(it++));
140    }
141
[1030]142    void ConfigFileSection::deleteVectorEntries(const std::string& name, unsigned int startindex)
143    {
144        for (std::list<ConfigFileEntry*>::iterator it = this->entries_.begin(); it != this->entries_.end(); )
145        {
146            if (((*it)->getName() == name) && ((*it)->getIndex() >= startindex))
147            {
148                delete (*it);
149                this->entries_.erase(it++);
150            }
151            else
152            {
153                ++it;
154            }
155        }
156    }
157
158    unsigned int ConfigFileSection::getVectorSize(const std::string& name)
159    {
160        unsigned int size = 0;
161        for (std::list<ConfigFileEntry*>::const_iterator it = this->entries_.begin(); it != this->entries_.end(); ++it)
162            if ((*it)->getName() == name)
163                if ((*it)->getIndex() > size)
164                    size = (*it)->getIndex();
165        return (size + 1);
166    }
167
[1006]168    std::string ConfigFileSection::getFileEntry() const
169    {
170        if (this->additionalComment_ == "" || this->additionalComment_.size() == 0)
[1025]171            return ("[" + this->name_ + "]");
[1006]172        else
[1025]173            return ("[" + this->name_ + "] " + this->additionalComment_);
[1006]174    }
175
[1049]176    std::list<ConfigFileEntry*>::iterator ConfigFileSection::getEntryIterator(const std::string& name, const std::string& fallback, bool bString)
[1006]177    {
178        for (std::list<ConfigFileEntry*>::iterator it = this->entries_.begin(); it != this->entries_.end(); ++it)
[1049]179        {
[1020]180            if ((*it)->getName() == name)
[1049]181            {
182                (*it)->setString(bString);
[1020]183                return it;
[1049]184            }
185        }
[1020]186
187        this->bUpdated_ = true;
188
[1049]189        return this->entries_.insert(this->entries_.end(), (ConfigFileEntry*)(new ConfigFileEntryValue(name, fallback, bString)));
[1020]190    }
191
[1049]192    std::list<ConfigFileEntry*>::iterator ConfigFileSection::getEntryIterator(const std::string& name, unsigned int index, const std::string& fallback, bool bString)
[1020]193    {
194        for (std::list<ConfigFileEntry*>::iterator it = this->entries_.begin(); it != this->entries_.end(); ++it)
[1049]195        {
[1006]196            if (((*it)->getName() == name) && ((*it)->getIndex() == index))
[1049]197            {
198                (*it)->setString(bString);
[1006]199                return it;
[1049]200            }
201        }
[1006]202
203        this->bUpdated_ = true;
204
205        if (index == 0)
[1049]206            return this->entries_.insert(this->entries_.end(), (ConfigFileEntry*)(new ConfigFileEntryVectorValue(name, index, fallback, bString)));
[1006]207        else
[1049]208            return this->entries_.insert(++this->getEntryIterator(name, index - 1, "", bString), (ConfigFileEntry*)(new ConfigFileEntryVectorValue(name, index, fallback, bString)));
[1006]209    }
210
211
212    ////////////////
213    // ConfigFile //
214    ////////////////
215    ConfigFile::~ConfigFile()
216    {
217        for (std::list<ConfigFileSection*>::iterator it = this->sections_.begin(); it != this->sections_.end(); )
218            delete (*(it++));
219    }
220
[1027]221    void ConfigFile::load(bool bCreateIfNotExisting)
[1006]222    {
[1027]223        if (bCreateIfNotExisting)
224        {
225            // This creates the default config file if it's not existing
226            std::ofstream createFile;
227            createFile.open(this->filename_.c_str(), std::fstream::app);
228            createFile.close();
229        }
[1006]230
231        // Open the file
232        std::ifstream file;
233        file.open(this->filename_.c_str(), std::fstream::in);
234
235        if (!file.is_open())
236        {
237            COUT(1) << "An error occurred in ConfigFileManager.cc:" << std::endl;
238            COUT(1) << "Error: Couldn't open config-file \"" << this->filename_ << "\"." << std::endl;
239            return;
240        }
241
242        char linearray[CONFIG_FILE_MAX_LINELENGHT];
243
244        ConfigFileSection* newsection = 0;
245
246        while (file.good() && !file.eof())
247        {
248            file.getline(linearray, CONFIG_FILE_MAX_LINELENGHT);
249
250            std::string line = std::string(linearray);
251
252            std::string temp = getStripped(line);
253            if (!isEmpty(temp) && !isComment(temp))
254            {
[1030]255                unsigned int   pos1 = temp.find('[');
256                if (pos1 == 0) pos1 = line.find('['); else pos1 = std::string::npos;
257                unsigned int   pos2 = line.find(']');
[1006]258
259                if (pos1 != std::string::npos && pos2 != std::string::npos && pos2 > pos1 + 1)
260                {
261                    // New section
[1030]262                    std::string comment = line.substr(pos2 + 1);
[1006]263                    if (isComment(comment))
[1025]264                        newsection = new ConfigFileSection(line.substr(pos1 + 1, pos2 - pos1 - 1), comment);
[1006]265                    else
[1025]266                        newsection = new ConfigFileSection(line.substr(pos1 + 1, pos2 - pos1 - 1));
[1006]267                    this->sections_.insert(this->sections_.end(), newsection);
268                    continue;
269                }
270            }
271
272            if (newsection != 0)
273            {
274                if (isComment(line))
275                {
276                    // New comment
[1020]277                    newsection->getEntries().insert(newsection->getEntries().end(), new ConfigFileEntryComment(removeTrailingWhitespaces(line)));
[1006]278                    continue;
279                }
280                else
281                {
282                    unsigned int pos1 = line.find('=');
283
284                    if (pos1 != std::string::npos && pos1 > 0)
285                    {
286                        // New entry
287                        unsigned int pos2 = line.find('[');
288                        unsigned int pos3 = line.find(']');
[1049]289                        unsigned int commentposition = getNextCommentPosition(line, pos1 + 1);
290                        while (isBetweenQuotes(line, commentposition))
[1006]291                        {
[1049]292                            commentposition = getNextCommentPosition(line, commentposition + 1);
[1006]293                        }
[1049]294                        std::string value = "", comment = "";
295                        if (commentposition == std::string::npos)
296                        {
297                            value = removeTrailingWhitespaces(line.substr(pos1 + 1));
298                        }
[1006]299                        else
300                        {
[1049]301                            value = removeTrailingWhitespaces(line.substr(pos1 + 1, commentposition - pos1 - 1));
302                            comment = removeTrailingWhitespaces(line.substr(commentposition));
[1006]303                        }
304
305                        if (pos2 != std::string::npos && pos3 != std::string::npos && pos3 > pos2 + 1)
306                        {
307                            // There might be an array index
308                            unsigned int index = 0;
309                            if (ConvertValue(&index, line.substr(pos2 + 1, pos3 - pos2 - 1)))
310                            {
311                                // New array
[1049]312                                std::list<ConfigFileEntry*>::iterator it = newsection->getEntryIterator(getStripped(line.substr(0, pos2)), index, value, false);
[1030]313                                (*it)->setValue(value);
314                                (*it)->setComment(comment);
[1006]315                                continue;
316                            }
317                        }
318
319                        // New value
[1049]320                        newsection->getEntries().insert(newsection->getEntries().end(), new ConfigFileEntryValue(getStripped(line.substr(0, pos1)), value, false, comment));
[1006]321                        continue;
322                    }
323                }
324            }
325        }
326
327        file.close();
328
[1020]329        COUT(3) << "Loaded config file \"" << this->filename_ << "\"." << std::endl;
330
[1006]331        // Save the file in case something changed (like stripped whitespaces)
332        this->save();
333    }
334
335    void ConfigFile::save() const
336    {
337        std::ofstream file;
338        file.open(this->filename_.c_str(), std::fstream::out);
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();
[1020]362
363        COUT(4) << "Saved config file \"" << this->filename_ << "\"." << std::endl;
[1006]364    }
365
[1030]366    void ConfigFile::clean(bool bCleanComments)
[1006]367    {
[1027]368        for (std::list<ConfigFileSection*>::iterator it1 = this->sections_.begin(); it1 != this->sections_.end(); )
369        {
370            std::map<std::string, Identifier*>::const_iterator it2 = Identifier::getIdentifierMap().find((*it1)->getName());
371            if (it2 != Identifier::getIdentifierMapEnd() && (*it2).second->hasConfigValues())
372            {
373                // The section exists, delete comment
[1030]374                if (bCleanComments)
375                    (*it1)->setComment("");
[1027]376                for (std::list<ConfigFileEntry*>::iterator it3 = (*it1)->entries_.begin(); it3 != (*it1)->entries_.end(); )
377                {
378                    std::map<std::string, ConfigValueContainer*>::const_iterator it4 = (*it2).second->getConfigValueMap().find((*it3)->getName());
379                    if (it4 != (*it2).second->getConfigValueMapEnd())
380                    {
381                        // The config-value exists, delete comment
[1030]382                        if (bCleanComments)
383                            (*it3)->setComment("");
[1027]384                        ++it3;
385                    }
386                    else
387                    {
388                        // The config-value doesn't exist
389                        delete (*it3);
390                        (*it1)->entries_.erase(it3++);
391                    }
392                }
393                ++it1;
394            }
395            else
396            {
397                // The section doesn't exist
398                delete (*it1);
399                this->sections_.erase(it1++);
400            }
401        }
402
403        // Save the file
404        this->save();
[1006]405    }
406
407    ConfigFileSection* ConfigFile::getSection(const std::string& section)
408    {
409        for (std::list<ConfigFileSection*>::iterator it = this->sections_.begin(); it != this->sections_.end(); ++it)
410            if ((*it)->getName() == section)
411                return (*it);
412
413        this->bUpdated_ = true;
414
[1030]415        return (*this->sections_.insert(this->sections_.end(), new ConfigFileSection(section)));
[1006]416    }
417
418    void ConfigFile::saveIfUpdated()
419    {
420        bool sectionsUpdated = false;
421
422        for (std::list<ConfigFileSection*>::iterator it = this->sections_.begin(); it != this->sections_.end(); ++it)
423        {
424            if ((*it)->bUpdated_)
425            {
426                sectionsUpdated = true;
427                (*it)->bUpdated_ = false;
428            }
429        }
430
431        if (this->bUpdated_ || sectionsUpdated)
432        {
433            this->bUpdated_ = false;
434            this->save();
435        }
436    }
437
438
439    ///////////////////////
440    // ConfigFileManager //
441    ///////////////////////
442    ConfigFileManager::ConfigFileManager()
443    {
444        this->setFile(CFT_Settings, DEFAULT_CONFIG_FILE);
445    }
446
447    ConfigFileManager::~ConfigFileManager()
448    {
449        for(std::map<ConfigFileType, ConfigFile*>::const_iterator it = this->configFiles_.begin(); it != this->configFiles_.end(); )
450            delete (*(it++)).second;
451    }
452
[1020]453    ConfigFileManager* ConfigFileManager::getSingleton()
[1006]454    {
455        static ConfigFileManager instance;
456        return (&instance);
457    }
458
[1027]459    void ConfigFileManager::setFile(ConfigFileType type, const std::string& filename, bool bCreateIfNotExisting)
[1006]460    {
461        std::map<ConfigFileType, ConfigFile*>::const_iterator it = this->configFiles_.find(type);
462        if (it != this->configFiles_.end())
463            if ((*it).second != 0)
464                delete (*it).second;
465
466        this->configFiles_[type] = new ConfigFile(this->getFilePath(filename));
[1027]467        this->load(type, bCreateIfNotExisting);
[1006]468    }
469
[1027]470    void ConfigFileManager::load(bool bCreateIfNotExisting)
[1006]471    {
472        for(std::map<ConfigFileType, ConfigFile*>::const_iterator it = this->configFiles_.begin(); it != this->configFiles_.end(); ++it)
[1027]473            (*it).second->load(bCreateIfNotExisting);
[1006]474
475        this->updateConfigValues();
476    }
477
478    void ConfigFileManager::save()
479    {
480        for(std::map<ConfigFileType, ConfigFile*>::const_iterator it = this->configFiles_.begin(); it != this->configFiles_.end(); ++it)
481            (*it).second->save();
482    }
483
[1030]484    void ConfigFileManager::clean(bool bCleanComments)
[1006]485    {
486        for(std::map<ConfigFileType, ConfigFile*>::const_iterator it = this->configFiles_.begin(); it != this->configFiles_.end(); ++it)
[1030]487            this->clean((*it).first, bCleanComments);
[1006]488    }
489
[1027]490    void ConfigFileManager::load(ConfigFileType type, bool bCreateIfNotExisting)
[1006]491    {
[1027]492        this->getFile(type)->load(bCreateIfNotExisting);
[1006]493        this->updateConfigValues(type);
494    }
495
496    void ConfigFileManager::save(ConfigFileType type)
497    {
498        this->getFile(type)->save();
499    }
500
[1030]501    void ConfigFileManager::clean(ConfigFileType type, bool bCleanComments)
[1006]502    {
[1030]503        this->getFile(type)->clean(bCleanComments);
[1006]504    }
505
506    void ConfigFileManager::updateConfigValues() const
507    {
508        for(std::map<ConfigFileType, ConfigFile*>::const_iterator it = this->configFiles_.begin(); it != this->configFiles_.end(); ++it)
509            this->updateConfigValues((*it).first);
510    }
511
512    void ConfigFileManager::updateConfigValues(ConfigFileType type) const
513    {
514        if (type == CFT_Settings)
515        {
516            for (std::map<std::string, Identifier*>::const_iterator it = Identifier::getIdentifierMapBegin(); it != Identifier::getIdentifierMapEnd(); ++it)
[1026]517            {
[1006]518                if ((*it).second->hasConfigValues() /* && (*it).second != ClassManager<KeyBinder>::getIdentifier()*/)
[1026]519                {
520                    for (std::map<std::string, ConfigValueContainer*>::const_iterator it2 = (*it).second->getConfigValueMapBegin(); it2 != (*it).second->getConfigValueMapEnd(); ++it2)
521                        (*it2).second->update();
522
[1006]523                    (*it).second->updateConfigValues();
[1026]524                }
525            }
[1006]526        }
527        else if (type == CFT_Keybindings)
528        {
529            // todo
530        }
531    }
532
533    ConfigFile* ConfigFileManager::getFile(ConfigFileType type)
534    {
535        std::map<ConfigFileType, ConfigFile*>::iterator it = this->configFiles_.find(type);
536        if (it != this->configFiles_.end())
537            return (*it).second;
538
539        if (type == CFT_Settings)
540            return this->configFiles_[type] = new ConfigFile(DEFAULT_CONFIG_FILE);
541        else
542            return this->configFiles_[type] = new ConfigFile("");
543    }
544
545    std::string ConfigFileManager::getFilePath(const std::string& name) const
546    {
547        return name;
548    }
549}
Note: See TracBrowser for help on using the repository browser.