Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 9366 was 8858, checked in by landauf, 13 years ago

merged output branch back to trunk.

Changes:

  • you have to include util/Output.h instead of util/Debug.h
  • COUT(x) is now called orxout(level)
  • output levels are now defined by an enum instead of numbers. see util/Output.h for the definition
  • it's possible to use output contexts with orxout(level, context). see util/Output.h for some common contexts. you can define more contexts
  • you must use 'endl' at the end of an output message, '\n' does not flush the message

Output levels:

  • instead of COUT(0) use orxout()
  • instead of COUT(1) use orxout(user_error) or orxout(internal_error)
  • instead of COUT(2) use orxout(user_warning) or orxout(internal_warning)
  • instead of COUT(3) use orxout(user_status/user_info) or orxout(internal_status/internal_info)
  • instead of COUT(4) use orxout(verbose)
  • instead of COUT(5) use orxout(verbose_more)
  • instead of COUT(6) use orxout(verbose_ultra)

Guidelines:

  • user_* levels are for the user, visible in the console and the log-file
  • internal_* levels are for developers, visible in the log-file
  • verbose_* levels are for debugging, only visible if the context of the output is activated

Usage in C++:

  • orxout() << "message" << endl;
  • orxout(level) << "message" << endl;
  • orxout(level, context) << "message" << endl;

Usage in Lua:

  • orxout("message")
  • orxout(orxonox.level.levelname, "message")
  • orxout(orxonox.level.levelname, "context", "message")

Usage in Tcl (and in the in-game-console):

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