Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 8360 was 7401, checked in by landauf, 14 years ago

merged doc branch back to trunk

  • Property svn:eol-style set to native
File size: 29.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
[7401]29/**
30    @file
31    @brief Implementation of ConfigFileManager and its helper classes.
32*/
33
[1505]34#include "ConfigFileManager.h"
[2103]35
[2710]36#include <boost/filesystem.hpp>
37
[1505]38#include "util/Convert.h"
[3196]39#include "util/Math.h"
[7163]40#include "util/StringUtils.h"
[2103]41#include "ConfigValueContainer.h"
[5929]42#include "PathConfig.h"
[7284]43#include "command/ConsoleCommand.h"
[1505]44
45namespace orxonox
46{
47    //////////////////////////
48    // ConfigFileEntryValue //
49    //////////////////////////
[7401]50    /**
51        @brief Updates the string that will be stored in the file after one of it's components (name, value, comment) has changed.
52    */
[6425]53    void ConfigFileEntryValue::update()
[1505]54    {
[6425]55        // Make sure we remove the quotes when bString changes
56        if (this->bString_)
57            this->value_ = stripEnclosingQuotes(this->value_);
58        // Assemble the entry line
59        this->fileEntry_ = this->getKeyString() + " = ";
[6536]60        if (this->bString_ && !this->value_.empty())
[6425]61            this->fileEntry_ += '"' + addSlashes(this->value_) + '"';
[1505]62        else
[6425]63            this->fileEntry_ += this->value_;
64        if (!this->additionalComment_.empty())
65            this->fileEntry_ += ' ' + this->additionalComment_;
[1505]66    }
67
68
[2103]69    ////////////////////////////////
[1505]70    // ConfigFileEntryVectorValue //
[2103]71    ////////////////////////////////
[7401]72    /**
73        @brief Updates the string that will be stored in the file after one of it's components (name, value, index, comment) has changed.
74    */
[6425]75    void ConfigFileEntryVectorValue::update()
[1505]76    {
[6425]77        this->keyString_ = this->name_ + '[' + multi_cast<std::string>(this->index_) + ']';
78        ConfigFileEntryValue::update();
[1505]79    }
80
81
82    ///////////////////////
83    // ConfigFileSection //
84    ///////////////////////
[7401]85    /**
86        @brief Destructor: Deletes all entries.
87    */
[1505]88    ConfigFileSection::~ConfigFileSection()
89    {
90        for (std::list<ConfigFileEntry*>::iterator it = this->entries_.begin(); it != this->entries_.end(); )
91            delete (*(it++));
92    }
93
[7401]94    /**
95        @brief Deletes all elements of a config vector if their index is greater or equal to @a startindex.
96
97        @param name         The name of the vector
98        @param startindex   The index of the first element that will be deleted
99    */
[1505]100    void ConfigFileSection::deleteVectorEntries(const std::string& name, unsigned int startindex)
101    {
102        for (std::list<ConfigFileEntry*>::iterator it = this->entries_.begin(); it != this->entries_.end(); )
103        {
104            if (((*it)->getName() == name) && ((*it)->getIndex() >= startindex))
105            {
106                delete (*it);
107                this->entries_.erase(it++);
108            }
109            else
110            {
111                ++it;
112            }
113        }
114    }
115
[7401]116    /**
117        @brief Returns the size of a config vector.
118        @param name     The name of the vector
119    */
[6536]120    unsigned int ConfigFileSection::getVectorSize(const std::string& name) const
[1505]121    {
122        unsigned int size = 0;
123        for (std::list<ConfigFileEntry*>::const_iterator it = this->entries_.begin(); it != this->entries_.end(); ++it)
124            if ((*it)->getName() == name)
125                if ((*it)->getIndex() > size)
126                    size = (*it)->getIndex();
[2662]127        if (size == 0)
128            return 0;
129        else
130            return (size + 1);
[1505]131    }
132
[7401]133    /**
134        @brief Returns the title and comment of the section as it will be stored in the file.
135    */
[1505]136    std::string ConfigFileSection::getFileEntry() const
137    {
[6417]138        if (this->additionalComment_.empty())
139            return ('[' + this->name_ + ']');
[1505]140        else
[6417]141            return ('[' + this->name_ + "] " + this->additionalComment_);
[1505]142    }
143
[7401]144    /**
145        @brief Returns the entry with given name (or NULL if it doesn't exist).
146
147        @param name     The name of the entry
148    */
[6536]149    ConfigFileEntry* ConfigFileSection::getEntry(const std::string& name) const
[1505]150    {
[6536]151        for (std::list<ConfigFileEntry*>::const_iterator it = this->entries_.begin(); it != this->entries_.end(); ++it)
152        {
153            if ((*it)->getName() == name)
154                return *it;
155        }
156        return NULL;
157    }
158
[7401]159    /**
160        @brief Returns the entry of a vector element with given name and index (or NULL if it doesn't exist).
161
162        @param name     The name of the vector
163        @param index    The index of the element in the vector
164    */
[6536]165    ConfigFileEntry* ConfigFileSection::getEntry(const std::string& name, unsigned int index) const
166    {
167        for (std::list<ConfigFileEntry*>::const_iterator it = this->entries_.begin(); it != this->entries_.end(); ++it)
168        {
169            if (((*it)->getName() == name) && ((*it)->getIndex() == index))
170                return *it;
171        }
172        return NULL;
173    }
174
[7401]175    /**
176        @brief Returns the iterator to the entry with given name. If the entry doesn't exist, it is created using the fallback value.
177
178        @param name     The name of the entry
179        @param fallback The value that will be used if the entry doesn't exist
180        @param bString  If true, the value is treated as string which means some special treatment of special characters.
181    */
[6536]182    std::list<ConfigFileEntry*>::iterator ConfigFileSection::getOrCreateEntryIterator(const std::string& name, const std::string& fallback, bool bString)
183    {
[1505]184        for (std::list<ConfigFileEntry*>::iterator it = this->entries_.begin(); it != this->entries_.end(); ++it)
185        {
186            if ((*it)->getName() == name)
187            {
188                (*it)->setString(bString);
189                return it;
190            }
191        }
192
193        this->bUpdated_ = true;
194
[6536]195        return this->entries_.insert(this->entries_.end(), new ConfigFileEntryValue(name, fallback, bString));
[1505]196    }
197
[7401]198    /**
199        @brief Returns the iterator to the entry of a vector element with given name and index. If the entry doesn't exist, it is created using the fallback value.
200
201        @param name     The name of the vector
202        @param index    The index of the element in the vector
203        @param fallback The value that will be used if the entry doesn't exist
204        @param bString  If true, the value is treated as string which means some special treatment of special characters.
205    */
[6536]206    std::list<ConfigFileEntry*>::iterator ConfigFileSection::getOrCreateEntryIterator(const std::string& name, unsigned int index, const std::string& fallback, bool bString)
[1505]207    {
208        for (std::list<ConfigFileEntry*>::iterator it = this->entries_.begin(); it != this->entries_.end(); ++it)
209        {
210            if (((*it)->getName() == name) && ((*it)->getIndex() == index))
211            {
212                (*it)->setString(bString);
213                return it;
214            }
215        }
216
217        this->bUpdated_ = true;
218
219        if (index == 0)
[6536]220            return this->entries_.insert(this->entries_.end(), new ConfigFileEntryVectorValue(name, index, fallback, bString));
[1505]221        else
[6536]222            return this->entries_.insert(++this->getOrCreateEntryIterator(name, index - 1, "", bString), new ConfigFileEntryVectorValue(name, index, fallback, bString));
[1505]223    }
224
225
226    ////////////////
227    // ConfigFile //
228    ////////////////
[6536]229
230    const char* ConfigFile::DEFAULT_CONFIG_FOLDER = "defaultConfig";
231
[7401]232    /**
233        @brief Constructor: Initializes the config file.
234        @param filename The file-name of this config file
235        @param bCopyFallbackFile If true, the default config file is copied into the config-directory before loading the file
236    */
[6536]237    ConfigFile::ConfigFile(const std::string& filename, bool bCopyFallbackFile)
238        : filename_(filename)
239        , bCopyFallbackFile_(bCopyFallbackFile)
240        , bUpdated_(false)
241    {
242    }
243
[7401]244    /**
245        @brief Destructor: Deletes all sections and entries.
246    */
[1505]247    ConfigFile::~ConfigFile()
248    {
[2103]249        this->clear();
[1505]250    }
251
[7401]252    /**
253        @brief Loads the config file from the hard-disk and reads the sections and their values.
254    */
[6536]255    void ConfigFile::load()
[1505]256    {
[2710]257        // Be sure we start from new in the memory
[2103]258        this->clear();
[1505]259
[6536]260        boost::filesystem::path filepath(this->filename_);
261        if (!filepath.is_complete())
[2710]262        {
[6536]263            filepath = PathConfig::getConfigPath() / filepath;
264            if (this->bCopyFallbackFile_)
[2710]265            {
[6536]266                // Look for default file in the data folder
267                if (!boost::filesystem::exists(filepath))
268                {
269                    boost::filesystem::path defaultFilepath(PathConfig::getDataPath() / DEFAULT_CONFIG_FOLDER / this->filename_);
270                    if (boost::filesystem::exists(defaultFilepath))
271                    {
272                        // Try to copy default file from the data folder
273                        try
274                        {
275                            boost::filesystem::copy_file(defaultFilepath, filepath);
276                            COUT(3) << "Copied " << this->filename_ << " from the default config folder." << std::endl;
277                        }
278                        catch (const boost::filesystem::filesystem_error& ex)
279                        { COUT(1) << "Error in ConfigFile: " << ex.what() << std::endl; }
280                    }
281                }
[2710]282            }
283        }
[2103]284
[1505]285        // Open the file
286        std::ifstream file;
[2759]287        file.open(filepath.string().c_str(), std::fstream::in);
[2710]288        if (file.is_open())
[1505]289        {
[2710]290            ConfigFileSection* newsection = 0;
[1505]291
[2710]292            while (file.good() && !file.eof())
[1505]293            {
[3198]294                std::string line;
295                std::getline(file, line);
[1505]296
[6417]297                const std::string& temp = getStripped(line);
[2710]298                if (!isEmpty(temp) && !isComment(temp))
[1505]299                {
[2710]300                    size_t   pos1 = temp.find('[');
301                    if (pos1 == 0) pos1 = line.find('['); else pos1 = std::string::npos;
302                    size_t   pos2 = line.find(']');
[1505]303
[2710]304                    if (pos1 != std::string::npos && pos2 != std::string::npos && pos2 > pos1 + 1)
[1505]305                    {
[2710]306                        // New section
[6417]307                        const std::string& comment = line.substr(pos2 + 1);
[2710]308                        if (isComment(comment))
309                            newsection = new ConfigFileSection(line.substr(pos1 + 1, pos2 - pos1 - 1), comment);
[1505]310                        else
[2710]311                            newsection = new ConfigFileSection(line.substr(pos1 + 1, pos2 - pos1 - 1));
312                        this->sections_.insert(this->sections_.end(), newsection);
313                        continue;
314                    }
315                }
[1505]316
[2710]317                if (newsection != 0)
318                {
319                    if (isComment(line))
320                    {
321                        // New comment
322                        newsection->getEntries().insert(newsection->getEntries().end(), new ConfigFileEntryComment(removeTrailingWhitespaces(line)));
323                        continue;
324                    }
325                    else
326                    {
327                        size_t pos1 = line.find('=');
328
329                        if (pos1 != std::string::npos && pos1 > 0)
[1505]330                        {
[2710]331                            // New entry
332                            size_t pos2 = line.find('[');
333                            size_t pos3 = line.find(']');
334                            size_t commentposition = getNextCommentPosition(line, pos1 + 1);
335                            while (isBetweenQuotes(line, commentposition))
[1505]336                            {
[2710]337                                commentposition = getNextCommentPosition(line, commentposition + 1);
[1505]338                            }
[6417]339                            std::string value, comment;
[2710]340                            if (commentposition == std::string::npos)
341                            {
[7284]342                                value = line.substr(pos1 + 1);
[2710]343                            }
344                            else
345                            {
[7284]346                                value = line.substr(pos1 + 1, commentposition - pos1 - 1);
[2710]347                                comment = removeTrailingWhitespaces(line.substr(commentposition));
348                            }
349
[7284]350                            value = removeTrailingWhitespaces(value);
351                            value = removeSlashes(value);
352
[2710]353                            if (pos2 != std::string::npos && pos3 != std::string::npos && pos3 > pos2 + 1)
354                            {
355                                // There might be an array index
356                                unsigned int index = 0;
[3196]357                                if (convertValue(&index, line.substr(pos2 + 1, pos3 - pos2 - 1)))
[2710]358                                {
359                                    // New array
[6536]360                                    std::list<ConfigFileEntry*>::iterator it = newsection->getOrCreateEntryIterator(getStripped(line.substr(0, pos2)), index, value, false);
[2710]361                                    (*it)->setValue(value);
362                                    (*it)->setComment(comment);
363                                    continue;
364                                }
365                            }
366
367                            // New value
368                            newsection->getEntries().insert(newsection->getEntries().end(), new ConfigFileEntryValue(getStripped(line.substr(0, pos1)), value, false, comment));
369                            continue;
[1505]370                        }
371                    }
372                }
373            }
374
[2710]375            file.close();
[1505]376
[2710]377            COUT(3) << "Loaded config file \"" << this->filename_ << "\"." << std::endl;
[1505]378
[6536]379            // DO NOT save the file --> we can open supposedly read only config files
[2710]380        } // end file.is_open()
[1505]381    }
382
[7401]383    /**
384        @brief Writes the sections and values to the hard-disk.
385    */
[1505]386    void ConfigFile::save() const
387    {
[6536]388        this->saveAs(this->filename_);
389    }
390
[7401]391    /**
392        @brief Writes the sections and values to a given file on the hard-disk.
393    */
[6536]394    void ConfigFile::saveAs(const std::string& filename) const
395    {
396        boost::filesystem::path filepath(filename);
397        if (!filepath.is_complete())
398            filepath = PathConfig::getConfigPath() / filename;
[1505]399        std::ofstream file;
[6536]400        file.open(filepath.string().c_str(), std::fstream::out);
[1505]401        file.setf(std::ios::fixed, std::ios::floatfield);
402        file.precision(6);
403
404        if (!file.is_open())
405        {
[6536]406            COUT(1) << "Error: Couldn't open config-file \"" << filename << "\"." << std::endl;
[1505]407            return;
408        }
409
410        for (std::list<ConfigFileSection*>::const_iterator it = this->sections_.begin(); it != this->sections_.end(); ++it)
411        {
412            file << (*it)->getFileEntry() << std::endl;
413
414            for (std::list<ConfigFileEntry*>::const_iterator it_entries = (*it)->getEntriesBegin(); it_entries != (*it)->getEntriesEnd(); ++it_entries)
415                file << (*it_entries)->getFileEntry() << std::endl;
416
417            file << std::endl;
418        }
419
420        file.close();
421
[6536]422        COUT(4) << "Saved config file \"" << filename << "\"." << std::endl;
[1505]423    }
424
[7401]425    /**
426        @brief Deletes all sections (which again delete all their values) and clears the list of sections.
427    */
[6536]428    void ConfigFile::clear()
[1505]429    {
[6536]430        for (std::list<ConfigFileSection*>::iterator it = this->sections_.begin(); it != this->sections_.end(); )
431            delete (*(it++));
432        this->sections_.clear();
[1505]433    }
434
[7401]435    /**
436        @brief Deletes all elements of a config vector if their index is greater or equal to @a startindex.
[6536]437
[7401]438        @param section      The name of the section
439        @param name         The name of the vector
440        @param startindex   The index of the first element that will be deleted
441    */
[6536]442    void ConfigFile::deleteVectorEntries(const std::string& section, const std::string& name, unsigned int startindex)
443    {
444        if (ConfigFileSection* sectionPtr = this->getSection(section))
[1505]445        {
[6536]446            sectionPtr->deleteVectorEntries(name, startindex);
447            this->save();
[1505]448        }
449    }
450
[7401]451    /**
452        @brief Returns a pointer to the section with given name (or NULL if the section doesn't exist).
453    */
[6536]454    ConfigFileSection* ConfigFile::getSection(const std::string& section) const
[2103]455    {
[6536]456        for (std::list<ConfigFileSection*>::const_iterator it = this->sections_.begin(); it != this->sections_.end(); ++it)
457            if ((*it)->getName() == section)
458                return (*it);
459        return NULL;
[2103]460    }
461
[7401]462    /**
463        @brief Returns a pointer to the section with given name. If it doesn't exist, the section is created.
464    */
[6536]465    ConfigFileSection* ConfigFile::getOrCreateSection(const std::string& section)
[1505]466    {
467        for (std::list<ConfigFileSection*>::iterator it = this->sections_.begin(); it != this->sections_.end(); ++it)
468            if ((*it)->getName() == section)
469                return (*it);
470
471        this->bUpdated_ = true;
472
473        return (*this->sections_.insert(this->sections_.end(), new ConfigFileSection(section)));
474    }
475
[7401]476    /**
477        @brief Saves the config file if it was updated (or if any of its sections were updated).
478    */
[1505]479    void ConfigFile::saveIfUpdated()
480    {
481        bool sectionsUpdated = false;
482
483        for (std::list<ConfigFileSection*>::iterator it = this->sections_.begin(); it != this->sections_.end(); ++it)
484        {
485            if ((*it)->bUpdated_)
486            {
487                sectionsUpdated = true;
488                (*it)->bUpdated_ = false;
489            }
490        }
491
492        if (this->bUpdated_ || sectionsUpdated)
493        {
494            this->bUpdated_ = false;
495            this->save();
496        }
497    }
498
499
[6536]500    ////////////////////////
501    // SettingsConfigFile //
502    ////////////////////////
[2103]503
[7284]504    static const std::string __CC_load_name = "reloadSettings";
505    static const std::string __CC_setFilename_name = "setSettingsFile";
506    static const std::string __CC_config_name = "config";
507    static const std::string __CC_tconfig_name = "tconfig";
508    static const std::string __CC_getConfig_name = "getConfig";
509
510    SetConsoleCommand(__CC_load_name,            &ConfigFile::load);
511    SetConsoleCommand(__CC_setFilename_name,     &SettingsConfigFile::setFilename);
512    SetConsoleCommand(__CC_config_name,          &SettingsConfigFile::config).argumentCompleter(0, autocompletion::settingssections()).argumentCompleter(1, autocompletion::settingsentries()).argumentCompleter(2, autocompletion::settingsvalue());
513    SetConsoleCommand(__CC_tconfig_name,         &SettingsConfigFile::tconfig).argumentCompleter(0, autocompletion::settingssections()).argumentCompleter(1, autocompletion::settingsentries()).argumentCompleter(2, autocompletion::settingsvalue());
514    SetConsoleCommand(__CC_getConfig_name,       &SettingsConfigFile::getConfig).argumentCompleter(0, autocompletion::settingssections()).argumentCompleter(1, autocompletion::settingsentries());
515
[6536]516    SettingsConfigFile* SettingsConfigFile::singletonPtr_s = 0;
[2103]517
[7401]518    /**
519        @brief Constructor: Activates the console commands.
520    */
[6536]521    SettingsConfigFile::SettingsConfigFile(const std::string& filename)
522        : ConfigFile(filename)
523    {
[7284]524        ModifyConsoleCommand(__CC_load_name).setObject(this);
525        ModifyConsoleCommand(__CC_setFilename_name).setObject(this);
526        ModifyConsoleCommand(__CC_config_name).setObject(this);
527        ModifyConsoleCommand(__CC_tconfig_name).setObject(this);
528        ModifyConsoleCommand(__CC_getConfig_name).setObject(this);
[6536]529    }
[2103]530
[7401]531    /**
532        @brief Destructor: Deactivates the console commands.
533    */
[6536]534    SettingsConfigFile::~SettingsConfigFile()
[1505]535    {
[7284]536        ModifyConsoleCommand(__CC_load_name).setObject(0);
537        ModifyConsoleCommand(__CC_setFilename_name).setObject(0);
538        ModifyConsoleCommand(__CC_config_name).setObject(0);
539        ModifyConsoleCommand(__CC_tconfig_name).setObject(0);
540        ModifyConsoleCommand(__CC_getConfig_name).setObject(0);
[1505]541    }
542
[7401]543    /**
544        @brief Loads the config file and updates the @ref ConfigValueContainer "config value containers".
545    */
[6536]546    void SettingsConfigFile::load()
[1505]547    {
[6536]548        ConfigFile::load();
549        this->updateConfigValues();
[1505]550    }
551
[7401]552    /**
553        @brief Changes the file-name.
554    */
[6536]555    void SettingsConfigFile::setFilename(const std::string& filename)
[1505]556    {
[6536]557        ConfigFileManager::getInstance().setFilename(ConfigFileType::Settings, filename);
[1505]558    }
559
[7401]560    /**
561        @brief Registers a new @ref ConfigValueContainer "config value container".
562    */
[6536]563    void SettingsConfigFile::addConfigValueContainer(ConfigValueContainer* container)
[1505]564    {
[6536]565        if (container == NULL)
566            return;
567        std::pair<std::string, ConfigValueContainer*> second(getLowercase(container->getName()), container);
568        this->containers_.insert(std::make_pair(getLowercase(container->getSectionName()), second));
569        this->sectionNames_.insert(container->getSectionName());
[1505]570    }
571
[7401]572    /**
573        @brief Unregisters a @ref ConfigValueContainer "config value container".
574    */
[6536]575    void SettingsConfigFile::removeConfigValueContainer(ConfigValueContainer* container)
[1505]576    {
[6536]577        if (container == NULL)
578            return;
579        const std::string& sectionLC = getLowercase(container->getSectionName());
580        ContainerMap::iterator upper = this->containers_.upper_bound(sectionLC);
581        for (ContainerMap::iterator it = this->containers_.lower_bound(sectionLC); it != upper; ++it)
582        {
583            if (it->second.second == container)
584            {
585                // Remove entry from section name set this was the last container for that section
586                if (upper == this->containers_.lower_bound(sectionLC))
587                    this->sectionNames_.erase(container->getSectionName());
588                this->containers_.erase(it);
589                break;
590            }
591        }
[1505]592    }
593
[7401]594    /**
595        @brief Updates all @ref ConfigValueContainer "config value containers".
596    */
[6536]597    void SettingsConfigFile::updateConfigValues()
[1505]598    {
[7401]599        // todo: can this be done more efficiently? looks like some identifiers will be updated multiple times.
600
[6536]601        for (ContainerMap::const_iterator it = this->containers_.begin(); it != this->containers_.end(); ++it)
602        {
603            it->second.second->update();
604            it->second.second->getIdentifier()->updateConfigValues();
605        }
[1505]606    }
607
[7401]608    /**
609        @brief Removes entries and sections from the file that don't exist anymore (i.e. if there's no corresponding @ref ConfigValueContainer "config value container").
610        @param bCleanComments If true, comments are also removed from the file
611    */
[6536]612    void SettingsConfigFile::clean(bool bCleanComments)
[1505]613    {
[6536]614        for (std::list<ConfigFileSection*>::iterator itSection = this->sections_.begin(); itSection != this->sections_.end(); )
615        {
616            const std::string& sectionLC = getLowercase((*itSection)->getName());
617            ContainerMap::const_iterator lower = this->containers_.lower_bound(sectionLC);
618            ContainerMap::const_iterator upper = this->containers_.upper_bound(sectionLC);
619            if (lower != upper)
620            {
621                // The section exists, delete comment
622                if (bCleanComments)
623                    (*itSection)->setComment("");
624                for (std::list<ConfigFileEntry*>::iterator itEntry = (*itSection)->entries_.begin(); itEntry != (*itSection)->entries_.end(); )
625                {
626                    const std::string& entryLC = getLowercase((*itEntry)->getName());
627                    bool bFound = false;
628                    for (ContainerMap::const_iterator itContainer = lower; itContainer != upper; ++itContainer)
629                    {
630                        if (itContainer->second.first == entryLC)
631                        {
632                            // The config-value exists, delete comment
633                            if (bCleanComments)
634                                (*itEntry)->setComment("");
635                            ++itEntry;
636                            bFound = true;
637                            break;
638                        }
639                    }
640                    if (!bFound)
641                    {
642                        // The config-value doesn't exist
643                        delete (*itEntry);
644                        (*itSection)->entries_.erase(itEntry++);
645                    }
646                }
647                ++itSection;
648            }
649            else
650            {
651                // The section doesn't exist
652                delete (*itSection);
653                this->sections_.erase(itSection++);
654            }
655        }
656
657        // Save the file
658        this->save();
[1505]659    }
660
[7401]661    /**
662        @brief Console-command: Changes the value of an entry and stores it the file.
663
664        @param section  The section of the config value
665        @param entry    The name of the config value
666        @param value    The new value
667    */
[7284]668    void SettingsConfigFile::config(const std::string& section, const std::string& entry, const std::string& value)
[1505]669    {
[7284]670        if (!this->configImpl(section, entry, value, &ConfigValueContainer::set))
671            COUT(1) << "Error: Config value \"" << entry << "\" in section \"" << section << "\" doesn't exist." << std::endl;
[1505]672    }
673
[7401]674    /**
675        @brief Console-command: Changes the value of an entry, but doesn't store it in the file (it's only a temporary change).
676
677        @param section  The section of the config value
678        @param entry    The name of the config value
679        @param value    The new value
680    */
[7284]681    void SettingsConfigFile::tconfig(const std::string& section, const std::string& entry, const std::string& value)
[1505]682    {
[7284]683        if (!this->configImpl(section, entry, value, &ConfigValueContainer::tset))
684            COUT(1) << "Error: Config value \"" << entry << "\" in section \"" << section << "\" doesn't exist." << std::endl;
[1505]685    }
686
[7401]687    /**
688        @brief Changes the value of an entry, depending on @a function, either by using "set" or "tset"
689
690        @param section  The section of the config value
691        @param entry    The name of the config value
692        @param value    The new value
693        @param function The function ("set" or "tset") that will be used to change the value.
694    */
[6536]695    bool SettingsConfigFile::configImpl(const std::string& section, const std::string& entry, const std::string& value, bool (ConfigValueContainer::*function)(const MultiType&))
[1505]696    {
[6536]697        const std::string& sectionLC = getLowercase(section);
698        const std::string& entryLC = getLowercase(entry);
699        ContainerMap::iterator upper = this->containers_.upper_bound(sectionLC);
700        for (ContainerMap::iterator it = this->containers_.lower_bound(sectionLC); it != upper; ++it)
701        {
702            // Note: Config value vectors cannot be supported
703            if (it->second.first == entryLC && !it->second.second->isVector())
704            {
705                return (it->second.second->*function)(value);
706            }
707        }
708        return false;
[1505]709    }
710
[7401]711    /**
712        @brief Console-command: Returns the value of a given entry.
713
714        @param section  The section of the config value
715        @param entry    The name of the config value
716    */
[6536]717    std::string SettingsConfigFile::getConfig(const std::string& section, const std::string& entry)
[1505]718    {
[6536]719        const std::string& sectionLC = getLowercase(section);
720        const std::string& entryLC = getLowercase(entry);
721        ContainerMap::iterator upper = this->containers_.upper_bound(sectionLC);
722        for (ContainerMap::iterator it = this->containers_.lower_bound(sectionLC); it != upper; ++it)
723        {
724            // Note: Config value vectors cannot be supported
725            if (it->second.first == entryLC && ! it->second.second->isVector())
726            {
727                std::string value;
728                it->second.second->getValue<std::string, OrxonoxClass>(&value, NULL);
729                return value;
730            }
731        }
732        return "";
[1505]733    }
734
[6536]735
736    ///////////////////////
737    // ConfigFileManager //
738    ///////////////////////
739
740    ConfigFileManager* ConfigFileManager::singletonPtr_s = 0;
741
[7401]742    /// Constructor: Initializes the array of config files with NULL.
[6536]743    ConfigFileManager::ConfigFileManager()
[1505]744    {
[6536]745        this->configFiles_.assign(NULL);
[1505]746    }
747
[7401]748    /// Destructor: Deletes the config files.
[6536]749    ConfigFileManager::~ConfigFileManager()
[1505]750    {
[6536]751        for (boost::array<ConfigFile*, 3>::const_iterator it = this->configFiles_.begin(); it != this->configFiles_.end(); ++it)
752            if (*it)
753                delete (*it);
[1505]754    }
755
[7401]756    /// Defines the file-name for the config file of a given type (settings, calibration, etc.).
[6536]757    void ConfigFileManager::setFilename(ConfigFileType::Value type, const std::string& filename)
[1505]758    {
[6536]759        if (this->getConfigFile(type))
760            delete this->configFiles_[type];
761        // Create and load config file
762        switch (type)
[2103]763        {
[6536]764        case ConfigFileType::Settings:
765            this->configFiles_[type] = new SettingsConfigFile(filename);
766            break;
767        case ConfigFileType::JoyStickCalibration:
768        case ConfigFileType::CommandHistory:
769            this->configFiles_[type] = new ConfigFile(filename);
770            break;
[2103]771        }
[6536]772        this->configFiles_[type]->load();
[1505]773    }
774}
Note: See TracBrowser for help on using the repository browser.