Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/tutorial3/src/libraries/core/ConfigFileManager.cc @ 9647

Last change on this file since 9647 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
Line 
1/*
2 *   ORXONOX - the hottest 3D action shooter ever to exist
3 *                    > www.orxonox.net <
4 *
5 *
6 *   License notice:
7 *
8 *   This program is free software; you can redistribute it and/or
9 *   modify it under the terms of the GNU General Public License
10 *   as published by the Free Software Foundation; either version 2
11 *   of the License, or (at your option) any later version.
12 *
13 *   This program is distributed in the hope that it will be useful,
14 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
15 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 *   GNU General Public License for more details.
17 *
18 *   You should have received a copy of the GNU General Public License
19 *   along with this program; if not, write to the Free Software
20 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21 *
22 *   Author:
23 *      Fabian 'x3n' Landau
24 *   Co-authors:
25 *      ...
26 *
27 */
28
29/**
30    @file
31    @brief Implementation of ConfigFileManager and its helper classes.
32*/
33
34#include "ConfigFileManager.h"
35
36#include <boost/filesystem.hpp>
37
38#include "util/Convert.h"
39#include "util/Math.h"
40#include "util/StringUtils.h"
41#include "ConfigValueContainer.h"
42#include "PathConfig.h"
43#include "command/ConsoleCommand.h"
44
45namespace orxonox
46{
47    //////////////////////////
48    // ConfigFileEntryValue //
49    //////////////////////////
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    */
53    void ConfigFileEntryValue::update()
54    {
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() + " = ";
60        if (this->bString_ && !this->value_.empty())
61            this->fileEntry_ += '"' + addSlashes(this->value_) + '"';
62        else
63            this->fileEntry_ += this->value_;
64        if (!this->additionalComment_.empty())
65            this->fileEntry_ += ' ' + this->additionalComment_;
66    }
67
68
69    ////////////////////////////////
70    // ConfigFileEntryVectorValue //
71    ////////////////////////////////
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    */
75    void ConfigFileEntryVectorValue::update()
76    {
77        this->keyString_ = this->name_ + '[' + multi_cast<std::string>(this->index_) + ']';
78        ConfigFileEntryValue::update();
79    }
80
81
82    ///////////////////////
83    // ConfigFileSection //
84    ///////////////////////
85    /**
86        @brief Destructor: Deletes all entries.
87    */
88    ConfigFileSection::~ConfigFileSection()
89    {
90        for (std::list<ConfigFileEntry*>::iterator it = this->entries_.begin(); it != this->entries_.end(); )
91            delete (*(it++));
92    }
93
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    */
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
116    /**
117        @brief Returns the size of a config vector.
118        @param name     The name of the vector
119    */
120    unsigned int ConfigFileSection::getVectorSize(const std::string& name) const
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() + 1;
127        return size;
128    }
129
130    /**
131        @brief Returns the title and comment of the section as it will be stored in the file.
132    */
133    std::string ConfigFileSection::getFileEntry() const
134    {
135        if (this->additionalComment_.empty())
136            return ('[' + this->name_ + ']');
137        else
138            return ('[' + this->name_ + "] " + this->additionalComment_);
139    }
140
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    */
146    ConfigFileEntry* ConfigFileSection::getEntry(const std::string& name) const
147    {
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
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    */
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
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    */
179    std::list<ConfigFileEntry*>::iterator ConfigFileSection::getOrCreateEntryIterator(const std::string& name, const std::string& fallback, bool bString)
180    {
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
192        return this->entries_.insert(this->entries_.end(), new ConfigFileEntryValue(name, fallback, bString));
193    }
194
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    */
203    std::list<ConfigFileEntry*>::iterator ConfigFileSection::getOrCreateEntryIterator(const std::string& name, unsigned int index, const std::string& fallback, bool bString)
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)
217            return this->entries_.insert(this->entries_.end(), new ConfigFileEntryVectorValue(name, index, fallback, bString));
218        else
219            return this->entries_.insert(++this->getOrCreateEntryIterator(name, index - 1, "", bString), new ConfigFileEntryVectorValue(name, index, fallback, bString));
220    }
221
222
223    ////////////////
224    // ConfigFile //
225    ////////////////
226
227    const char* ConfigFile::DEFAULT_CONFIG_FOLDER = "defaultConfig";
228
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    */
234    ConfigFile::ConfigFile(const std::string& filename, bool bCopyFallbackFile)
235        : filename_(filename)
236        , bCopyFallbackFile_(bCopyFallbackFile)
237        , bUpdated_(false)
238    {
239    }
240
241    /**
242        @brief Destructor: Deletes all sections and entries.
243    */
244    ConfigFile::~ConfigFile()
245    {
246        this->clear();
247    }
248
249    /**
250        @brief Loads the config file from the hard-disk and reads the sections and their values.
251    */
252    void ConfigFile::load()
253    {
254        // Be sure we start from new in the memory
255        this->clear();
256
257        boost::filesystem::path filepath(this->filename_);
258        if (!filepath.is_complete())
259        {
260            filepath = PathConfig::getConfigPath() / filepath;
261            if (this->bCopyFallbackFile_)
262            {
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);
273                            orxout(internal_info, context::config) << "Copied " << this->filename_ << " from the default config folder." << endl;
274                        }
275                        catch (const boost::filesystem::filesystem_error& ex)
276                        { orxout(user_error, context::config) << "Error in ConfigFile: " << ex.what() << endl; }
277                    }
278                }
279            }
280        }
281
282        // Open the file
283        std::ifstream file;
284        file.open(filepath.string().c_str(), std::fstream::in);
285        if (file.is_open())
286        {
287            ConfigFileSection* newsection = 0;
288
289            while (file.good() && !file.eof())
290            {
291                std::string line;
292                std::getline(file, line);
293
294                const std::string& temp = getStripped(line);
295                if (!isEmpty(temp) && !isComment(temp))
296                {
297                    size_t   pos1 = temp.find('[');
298                    if (pos1 == 0) pos1 = line.find('['); else pos1 = std::string::npos;
299                    size_t   pos2 = line.find(']');
300
301                    if (pos1 != std::string::npos && pos2 != std::string::npos && pos2 > pos1 + 1)
302                    {
303                        // New section
304                        const std::string& comment = line.substr(pos2 + 1);
305                        if (isComment(comment))
306                            newsection = new ConfigFileSection(line.substr(pos1 + 1, pos2 - pos1 - 1), comment);
307                        else
308                            newsection = new ConfigFileSection(line.substr(pos1 + 1, pos2 - pos1 - 1));
309                        this->sections_.insert(this->sections_.end(), newsection);
310                        continue;
311                    }
312                }
313
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)
327                        {
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))
333                            {
334                                commentposition = getNextCommentPosition(line, commentposition + 1);
335                            }
336                            std::string value, comment;
337                            if (commentposition == std::string::npos)
338                            {
339                                value = line.substr(pos1 + 1);
340                            }
341                            else
342                            {
343                                value = line.substr(pos1 + 1, commentposition - pos1 - 1);
344                                comment = removeTrailingWhitespaces(line.substr(commentposition));
345                            }
346
347                            value = removeTrailingWhitespaces(value);
348                            value = removeSlashes(value);
349
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;
354                                if (convertValue(&index, line.substr(pos2 + 1, pos3 - pos2 - 1)))
355                                {
356                                    // New array
357                                    std::list<ConfigFileEntry*>::iterator it = newsection->getOrCreateEntryIterator(getStripped(line.substr(0, pos2)), index, value, false);
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;
367                        }
368                    }
369                }
370            }
371
372            file.close();
373
374            orxout(internal_info, context::config) << "Loaded config file \"" << this->filename_ << "\"." << endl;
375
376            // DO NOT save the file --> we can open supposedly read only config files
377        } // end file.is_open()
378    }
379
380    /**
381        @brief Writes the sections and values to the hard-disk.
382    */
383    void ConfigFile::save() const
384    {
385        this->saveAs(this->filename_);
386    }
387
388    /**
389        @brief Writes the sections and values to a given file on the hard-disk.
390    */
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;
396        std::ofstream file;
397        file.open(filepath.string().c_str(), std::fstream::out);
398        file.setf(std::ios::fixed, std::ios::floatfield);
399        file.precision(6);
400
401        if (!file.is_open())
402        {
403            orxout(user_error, context::config) << "Couldn't open config-file \"" << filename << "\"." << endl;
404            return;
405        }
406
407        for (std::list<ConfigFileSection*>::const_iterator it = this->sections_.begin(); it != this->sections_.end(); ++it)
408        {
409            file << (*it)->getFileEntry() << endl;
410
411            for (std::list<ConfigFileEntry*>::const_iterator it_entries = (*it)->getEntriesBegin(); it_entries != (*it)->getEntriesEnd(); ++it_entries)
412                file << (*it_entries)->getFileEntry() << endl;
413
414            file << endl;
415        }
416
417        file.close();
418
419        orxout(verbose, context::config) << "Saved config file \"" << filename << "\"." << endl;
420    }
421
422    /**
423        @brief Deletes all sections (which again delete all their values) and clears the list of sections.
424    */
425    void ConfigFile::clear()
426    {
427        for (std::list<ConfigFileSection*>::iterator it = this->sections_.begin(); it != this->sections_.end(); )
428            delete (*(it++));
429        this->sections_.clear();
430    }
431
432    /**
433        @brief Deletes all elements of a config vector if their index is greater or equal to @a startindex.
434
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    */
439    void ConfigFile::deleteVectorEntries(const std::string& section, const std::string& name, unsigned int startindex)
440    {
441        if (ConfigFileSection* sectionPtr = this->getSection(section))
442        {
443            sectionPtr->deleteVectorEntries(name, startindex);
444            this->save();
445        }
446    }
447
448    /**
449        @brief Returns a pointer to the section with given name (or NULL if the section doesn't exist).
450    */
451    ConfigFileSection* ConfigFile::getSection(const std::string& section) const
452    {
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;
457    }
458
459    /**
460        @brief Returns a pointer to the section with given name. If it doesn't exist, the section is created.
461    */
462    ConfigFileSection* ConfigFile::getOrCreateSection(const std::string& section)
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
473    /**
474        @brief Saves the config file if it was updated (or if any of its sections were updated).
475    */
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
497    ////////////////////////
498    // SettingsConfigFile //
499    ////////////////////////
500
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
513    SettingsConfigFile* SettingsConfigFile::singletonPtr_s = 0;
514
515    /**
516        @brief Constructor: Activates the console commands.
517    */
518    SettingsConfigFile::SettingsConfigFile(const std::string& filename)
519        : ConfigFile(filename)
520    {
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);
526    }
527
528    /**
529        @brief Destructor: Deactivates the console commands.
530    */
531    SettingsConfigFile::~SettingsConfigFile()
532    {
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);
538    }
539
540    /**
541        @brief Loads the config file and updates the @ref ConfigValueContainer "config value containers".
542    */
543    void SettingsConfigFile::load()
544    {
545        ConfigFile::load();
546        this->updateConfigValues();
547    }
548
549    /**
550        @brief Changes the file-name.
551    */
552    void SettingsConfigFile::setFilename(const std::string& filename)
553    {
554        ConfigFileManager::getInstance().setFilename(ConfigFileType::Settings, filename);
555    }
556
557    /**
558        @brief Registers a new @ref ConfigValueContainer "config value container".
559    */
560    void SettingsConfigFile::addConfigValueContainer(ConfigValueContainer* container)
561    {
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());
567    }
568
569    /**
570        @brief Unregisters a @ref ConfigValueContainer "config value container".
571    */
572    void SettingsConfigFile::removeConfigValueContainer(ConfigValueContainer* container)
573    {
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        }
589    }
590
591    /**
592        @brief Updates all @ref ConfigValueContainer "config value containers".
593    */
594    void SettingsConfigFile::updateConfigValues()
595    {
596        // todo: can this be done more efficiently? looks like some identifiers will be updated multiple times.
597
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        }
603    }
604
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    */
609    void SettingsConfigFile::clean(bool bCleanComments)
610    {
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();
656    }
657
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    */
665    void SettingsConfigFile::config(const std::string& section, const std::string& entry, const std::string& value)
666    {
667        if (!this->configImpl(section, entry, value, &ConfigValueContainer::set))
668            orxout(user_error, context::config) << "Config value \"" << entry << "\" in section \"" << section << "\" doesn't exist." << endl;
669    }
670
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    */
678    void SettingsConfigFile::tconfig(const std::string& section, const std::string& entry, const std::string& value)
679    {
680        if (!this->configImpl(section, entry, value, &ConfigValueContainer::tset))
681            orxout(user_error, context::config) << "Config value \"" << entry << "\" in section \"" << section << "\" doesn't exist." << endl;
682    }
683
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    */
692    bool SettingsConfigFile::configImpl(const std::string& section, const std::string& entry, const std::string& value, bool (ConfigValueContainer::*function)(const MultiType&))
693    {
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;
706    }
707
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    */
714    std::string SettingsConfigFile::getConfig(const std::string& section, const std::string& entry)
715    {
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 "";
730    }
731
732
733    ///////////////////////
734    // ConfigFileManager //
735    ///////////////////////
736
737    ConfigFileManager* ConfigFileManager::singletonPtr_s = 0;
738
739    /// Constructor: Initializes the array of config files with NULL.
740    ConfigFileManager::ConfigFileManager()
741    {
742        this->configFiles_.assign(NULL);
743    }
744
745    /// Destructor: Deletes the config files.
746    ConfigFileManager::~ConfigFileManager()
747    {
748        for (boost::array<ConfigFile*, 3>::const_iterator it = this->configFiles_.begin(); it != this->configFiles_.end(); ++it)
749            if (*it)
750                delete (*it);
751    }
752
753    /// Defines the file-name for the config file of a given type (settings, calibration, etc.).
754    void ConfigFileManager::setFilename(ConfigFileType::Value type, const std::string& filename)
755    {
756        if (this->getConfigFile(type))
757            delete this->configFiles_[type];
758        // Create and load config file
759        switch (type)
760        {
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;
768        }
769        this->configFiles_[type]->load();
770    }
771}
Note: See TracBrowser for help on using the repository browser.