Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/core2/src/orxonox/core/ConfigValueContainer.cc @ 898

Last change on this file since 898 was 871, checked in by landauf, 16 years ago

merged core branch to trunk

File size: 39.0 KB
Line 
1/*
2 *   ORXONOX - the hottest 3D action shooter ever to exist
3 *
4 *
5 *   License notice:
6 *
7 *   This program is free software; you can redistribute it and/or
8 *   modify it under the terms of the GNU General Public License
9 *   as published by the Free Software Foundation; either version 2
10 *   of the License, or (at your option) any later version.
11 *
12 *   This program is distributed in the hope that it will be useful,
13 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
14 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 *   GNU General Public License for more details.
16 *
17 *   You should have received a copy of the GNU General Public License
18 *   along with this program; if not, write to the Free Software
19 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
20 *
21 *   Author:
22 *      Fabian 'x3n' Landau
23 *   Co-authors:
24 *      ...
25 *
26 */
27
28/**
29    @file ConfigValueContainer.cc
30    @brief Implementation of the ConfigValueContainer class.
31*/
32
33#include <fstream>
34
35#include "ConfigValueContainer.h"
36#include "util/Tokenizer.h"
37#include "util/Convert.h"
38#include "Language.h"
39
40#define CONFIGFILEPATH "orxonox.ini"
41
42namespace orxonox
43{
44    /**
45        @brief Constructor: Converts the default-value to a string, checks the config-file for a changed value, sets the intern value variable.
46        @param value This is only needed to determine the right type.
47        @param classname The name of the class the variable belongs to
48        @param varname The name of the variable
49        @param defvalue The default-value
50    */
51    ConfigValueContainer::ConfigValueContainer(const std::string& classname, const std::string& varname, MultiTypeMath defvalue)
52    {
53        this->bAddedDescription_ = false;
54        this->classname_ = classname;
55        this->varname_ = varname;
56
57        this->valueToString(&this->defvalueString_, defvalue);                      // Try to convert the default-value to a string
58        this->searchConfigFileLine();                                               // Search the entry in the config-file
59
60        std::string valueString = this->parseValueString(!(defvalue.isA(MT_string) || defvalue.isA(MT_constchar)));     // Parses the value string from the config-file-entry
61        if (!this->parseString(valueString, defvalue))                              // Try to convert the string to a value
62            this->resetConfigFileEntry();                                           // The conversion failed
63    }
64
65    /**
66        @brief Converts a value to a string.
67        @param output The string to write to
68        @param input The value to convert
69        @return True if the converson was successful
70    */
71    bool ConfigValueContainer::valueToString(std::string* output, MultiTypeMath& input)
72    {
73        if (input.getType() == MT_int)
74            return ConvertValue(output, input.getInt(), std::string("0"));
75        else if (input.getType() == MT_uint)
76            return ConvertValue(output, input.getUnsignedInt(), std::string("0"));
77        else if (input.getType() == MT_char)
78            return ConvertValue(output, (int)input.getChar(), std::string("0"));
79        else if (input.getType() == MT_uchar)
80            return ConvertValue(output, (unsigned int)input.getUnsignedChar(), std::string("0"));
81        else if (input.getType() == MT_short)
82            return ConvertValue(output, input.getShort(), std::string("0"));
83        else if (input.getType() == MT_ushort)
84            return ConvertValue(output, input.getUnsignedShort(), std::string("0"));
85        else if (input.getType() == MT_long)
86            return ConvertValue(output, input.getLong(), std::string("0"));
87        else if (input.getType() == MT_ulong)
88            return ConvertValue(output, input.getUnsignedLong(), std::string("0"));
89        else if (input.getType() == MT_float)
90            return ConvertValue(output, input.getFloat(), std::string("0.000000"));
91        else if (input.getType() == MT_double)
92            return ConvertValue(output, input.getDouble(), std::string("0.000000"));
93        else if (input.getType() == MT_longdouble)
94            return ConvertValue(output, input.getChar(), std::string("0.000000"));
95        else if (input.getType() == MT_bool)
96        {
97            if (input.getBool())
98                (*output) = "true";
99            else
100                (*output) = "false";
101
102            return true;
103        }
104        else if (input.getType() == MT_constchar)
105        {
106            (*output) = "\"" + input.getString() + "\"";
107            return true;
108        }
109        else if (input.getType() == MT_string)
110        {
111            (*output) = "\"" + input.getString() + "\"";
112            return true;
113        }
114        else if (input.getType() == MT_vector2)
115        {
116            std::ostringstream ostream;
117            if (ostream << "(" << input.getVector2().x << "," << input.getVector2().y << ")")
118            {
119                (*output) = ostream.str();
120                return true;
121            }
122            else
123            {
124                (*output) = "(0,0)";
125                return false;
126            }
127        }
128        else if (input.getType() == MT_vector3)
129        {
130            std::ostringstream ostream;
131            if (ostream << "(" << input.getVector3().x << "," << input.getVector3().y << "," << input.getVector3().z << ")")
132            {
133                (*output) = ostream.str();
134                return true;
135            }
136            else
137            {
138                (*output) = "(0,0,0)";
139                return false;
140            }
141        }
142        else if (input.getType() == MT_colourvalue)
143        {
144            std::ostringstream ostream;
145            if (ostream << "(" << input.getColourValue().r << "," << input.getColourValue().g << "," << input.getColourValue().b << "," << input.getColourValue().a << ")")
146            {
147                (*output) = ostream.str();
148                return true;
149            }
150            else
151            {
152                (*output) = "(0,0,0,0)";
153                return false;
154            }
155        }
156        else if (input.getType() == MT_quaternion)
157        {
158            std::ostringstream ostream;
159            if (ostream << "(" << input.getQuaternion().w << "," << input.getQuaternion().x << "," << input.getQuaternion().y << "," << input.getQuaternion().z << ")")
160            {
161                (*output) = ostream.str();
162                return true;
163            }
164            else
165            {
166                (*output) = "(0,0,0,0)";
167                return false;
168            }
169        }
170        else if (input.getType() == MT_radian)
171            return ConvertValue(output, input.getRadian(), std::string("0.000000"));
172        else if (input.getType() == MT_degree)
173            return ConvertValue(output, input.getDegree(), std::string("0.000000"));
174
175        return false;
176    }
177
178    /**
179        @brief Parses a given std::string into a value of the type of the associated variable and assigns it.
180        @param input The string to convert
181        @return True if the string was successfully parsed
182    */
183    bool ConfigValueContainer::parseString(const std::string& input, MultiTypeMath& defvalue)
184    {
185        if (defvalue.getType() == MT_int)
186            return this->parseString(input, defvalue.getInt());
187        else if (defvalue.getType() == MT_uint)
188            return this->parseString(input, defvalue.getUnsignedInt());
189        else if (defvalue.getType() == MT_char)
190            return this->parseString(input, defvalue.getChar());
191        else if (defvalue.getType() == MT_uchar)
192            return this->parseString(input, defvalue.getUnsignedChar());
193        else if (defvalue.getType() == MT_short)
194            return this->parseString(input, defvalue.getShort());
195        else if (defvalue.getType() == MT_ushort)
196            return this->parseString(input, defvalue.getUnsignedShort());
197        else if (defvalue.getType() == MT_long)
198            return this->parseString(input, defvalue.getLong());
199        else if (defvalue.getType() == MT_ulong)
200            return this->parseString(input, defvalue.getUnsignedLong());
201        else if (defvalue.getType() == MT_float)
202            return this->parseString(input, defvalue.getFloat());
203        else if (defvalue.getType() == MT_double)
204            return this->parseString(input, defvalue.getDouble());
205        else if (defvalue.getType() == MT_longdouble)
206            return this->parseString(input, defvalue.getLongDouble());
207        else if (defvalue.getType() == MT_bool)
208            return this->parseString(input, defvalue.getBool());
209        else if (defvalue.getType() == MT_constchar)
210            return this->parseString(input, defvalue.getString());
211        else if (defvalue.getType() == MT_string)
212            return this->parseString(input, defvalue.getString());
213        else if (defvalue.getType() == MT_vector2)
214            return this->parseString(input, defvalue.getVector2());
215        else if (defvalue.getType() == MT_vector3)
216            return this->parseString(input, defvalue.getVector3());
217        else if (defvalue.getType() == MT_colourvalue)
218            return this->parseString(input, defvalue.getColourValue());
219        else if (defvalue.getType() == MT_quaternion)
220            return this->parseString(input, defvalue.getQuaternion());
221        else if (defvalue.getType() == MT_radian)
222            return this->parseString(input, defvalue.getRadian());
223        else if (defvalue.getType() == MT_degree)
224            return this->parseString(input, defvalue.getDegree());
225
226        return false;
227    }
228
229    /**
230        @brief Parses a given std::string into a value of the type int and assigns it to the right variable. If the conversion failed, the default-value gets assigned.
231        @param input The string to convert
232        @param defvalue The default-value
233        @return True if the string was successfully parsed
234    */
235    bool ConfigValueContainer::parseString(const std::string& input, int defvalue)
236    {
237        int temp;
238        bool success = ConvertValue(&temp, input, defvalue);
239        this->value_.setValue(temp);
240        return success;
241    }
242
243    /**
244        @brief Parses a given std::string into a value of the type unsigned int and assigns it to the right variable. If the conversion failed, the default-value gets assigned.
245        @param input The string to convert
246        @param defvalue The default-value
247        @return True if the string was successfully parsed
248    */
249    bool ConfigValueContainer::parseString(const std::string& input, unsigned int defvalue)
250    {
251        unsigned int temp;
252        bool success = ConvertValue(&temp, input, defvalue);
253        this->value_.setValue(temp);
254        return success;
255    }
256
257    /**
258        @brief Parses a given std::string into a value of the type char and assigns it to the right variable. If the conversion failed, the default-value gets assigned.
259        @param input The string to convert
260        @param defvalue The default-value
261        @return True if the string was successfully parsed
262    */
263    bool ConfigValueContainer::parseString(const std::string& input, char defvalue)
264    {
265        // I used value_int_ instead of value_char_ to avoid number <-> char confusion in the config-file
266        int temp;
267        bool success = ConvertValue(&temp, input, (int)defvalue);
268        this->value_.setValue((char)temp);
269        return success;
270    }
271
272    /**
273        @brief Parses a given std::string into a value of the type unsigned char and assigns it to the right variable. If the conversion failed, the default-value gets assigned.
274        @param input The string to convert
275        @param defvalue The default-value
276        @return True if the string was successfully parsed
277    */
278    bool ConfigValueContainer::parseString(const std::string& input, unsigned char defvalue)
279    {
280        // I used value_uint_ instead of value_uchar_ to avoid number <-> char confusion in the config-file
281        unsigned int temp;
282        bool success = ConvertValue(&temp, input, (unsigned int)defvalue);
283        this->value_.setValue((unsigned char)temp);
284        return success;
285    }
286
287    /**
288        @brief Parses a given std::string into a value of the type short and assigns it to the right variable. If the conversion failed, the default-value gets assigned.
289        @param input The string to convert
290        @param defvalue The default-value
291        @return True if the string was successfully parsed
292    */
293    bool ConfigValueContainer::parseString(const std::string& input, short defvalue)
294    {
295        short temp;
296        bool success = ConvertValue(&temp, input, defvalue);
297        this->value_.setValue(temp);
298        return success;
299    }
300
301    /**
302        @brief Parses a given std::string into a value of the type unsigned short and assigns it to the right variable. If the conversion failed, the default-value gets assigned.
303        @param input The string to convert
304        @param defvalue The default-value
305        @return True if the string was successfully parsed
306    */
307    bool ConfigValueContainer::parseString(const std::string& input, unsigned short defvalue)
308    {
309        unsigned short temp;
310        bool success = ConvertValue(&temp, input, defvalue);
311        this->value_.setValue(temp);
312        return success;
313    }
314
315    /**
316        @brief Parses a given std::string into a value of the type long and assigns it to the right variable. If the conversion failed, the default-value gets assigned.
317        @param input The string to convert
318        @param defvalue The default-value
319        @return True if the string was successfully parsed
320    */
321    bool ConfigValueContainer::parseString(const std::string& input, long defvalue)
322    {
323        long temp;
324        bool success = ConvertValue(&temp, input, defvalue);
325        this->value_.setValue(temp);
326        return success;
327    }
328
329    /**
330        @brief Parses a given std::string into a value of the type unsigned long and assigns it to the right variable. If the conversion failed, the default-value gets assigned.
331        @param input The string to convert
332        @param defvalue The default-value
333        @return True if the string was successfully parsed
334    */
335    bool ConfigValueContainer::parseString(const std::string& input, unsigned long defvalue)
336    {
337        unsigned long temp;
338        bool success = ConvertValue(&temp, input, defvalue);
339        this->value_.setValue(temp);
340        return success;
341    }
342
343    /**
344        @brief Parses a given std::string into a value of the type float and assigns it to the right variable. If the conversion failed, the default-value gets assigned.
345        @param input The string to convert
346        @param defvalue The default-value
347        @return True if the string was successfully parsed
348    */
349    bool ConfigValueContainer::parseString(const std::string& input, float defvalue)
350    {
351        float temp;
352        bool success = ConvertValue(&temp, input, defvalue);
353        this->value_.setValue(temp);
354        return success;
355    }
356
357    /**
358        @brief Parses a given std::string into a value of the type double and assigns it to the right variable. If the conversion failed, the default-value gets assigned.
359        @param input The string to convert
360        @param defvalue The default-value
361        @return True if the string was successfully parsed
362    */
363    bool ConfigValueContainer::parseString(const std::string& input, double defvalue)
364    {
365        double temp;
366        bool success = ConvertValue(&temp, input, defvalue);
367        this->value_.setValue(temp);
368        return success;
369    }
370
371    /**
372        @brief Parses a given std::string into a value of the type long double and assigns it to the right variable. If the conversion failed, the default-value gets assigned.
373        @param input The string to convert
374        @param defvalue The default-value
375        @return True if the string was successfully parsed
376    */
377    bool ConfigValueContainer::parseString(const std::string& input, long double defvalue)
378    {
379        long double temp;
380        bool success = ConvertValue(&temp, input, defvalue);
381        this->value_.setValue(temp);
382        return success;
383    }
384
385    /**
386        @brief Parses a given std::string into a value of the type bool and assigns it to the right variable. If the conversion failed, the default-value gets assigned.
387        @param input The string to convert
388        @param defvalue The default-value
389        @return True if the string was successfully parsed
390    */
391    bool ConfigValueContainer::parseString(const std::string& input, bool defvalue)
392    {
393        // Try to parse the value-string - is it a word?
394        if (input.find("true") < input.size()
395         || input.find("True") < input.size()
396         || input.find("yes") < input.size()
397         || input.find("Yes") < input.size())
398            this->value_.setValue(true);
399        else if (input.find("false") < input.size()
400              || input.find("False") < input.size()
401              || input.find("no") < input.size()
402              || input.find("No") < input.size())
403            this->value_.setValue(false);
404        else
405        {
406            // Its not a known word - is it a number?
407            bool temp;
408            bool success = ConvertValue(&temp, input, defvalue);
409            this->value_.setValue(temp);
410            return success;
411        }
412
413        return true;
414    }
415
416    /**
417        @brief Parses a given std::string into a value of the type std::string and assigns it to the right variable. If the conversion failed, the default-value gets assigned.
418        @param input The string to convert
419        @param defvalue The default-value
420        @return True if the string was successfully parsed
421    */
422    bool ConfigValueContainer::parseString(const std::string& input, const std::string& defvalue)
423    {
424        // Strip the quotes
425        unsigned int pos1 = input.find("\"") + 1;
426        unsigned int pos2 = input.find("\"", pos1);
427
428        // Check if the entry was correctly quoted
429        if (pos1 < input.length() && pos2 < input.length() && !(input.find("\"", pos2 + 1) < input.length()))
430        {
431            // It was - get the string between the quotes
432            this->value_.setValue(input.substr(pos1, pos2 - pos1));
433            return true;
434        }
435
436        // It wasn't - use the default-value and restore the entry in the config-file.
437        this->value_.setValue(defvalue);
438        return false;
439    }
440
441    /**
442        @brief Parses a given std::string into a value of the type const char* and assigns it to the right variable. If the conversion failed, the default-value gets assigned.
443        @param input The string to convert
444        @param defvalue The default-value
445        @return True if the string was successfully parsed
446    */
447    bool ConfigValueContainer::parseString(const std::string& input, const char* defvalue)
448    {
449        // Strip the quotes
450        unsigned int pos1 = input.find("\"") + 1;
451        unsigned int pos2 = input.find("\"", pos1);
452
453        // Check if the entry was correctly quoted
454        if (pos1 < input.length() && pos2 < input.length() && !(input.find("\"", pos2 + 1) < input.length()))
455        {
456            // It was - get the string between the quotes
457            this->value_.setValue(input.substr(pos1, pos2 - pos1));
458            return true;
459        }
460
461        // It wasn't - use the default-value and restore the entry in the config-file.
462        this->value_.setValue(defvalue);
463        return false;
464    }
465
466    /**
467        @brief Parses a given std::string into a value of the type _Vector2 and assigns it to the right variable. If the conversion failed, the default-value gets assigned.
468        @param input The string to convert
469        @param defvalue The default-value
470        @return True if the string was successfully parsed
471    */
472    bool ConfigValueContainer::parseString(const std::string& input, const Vector2& defvalue)
473    {
474        // Strip the value-string
475        unsigned int pos1 = input.find("(") + 1;
476        unsigned int pos2 = input.find(")", pos1);
477
478        // Try to convert the stripped value-string to Vector2
479        if (pos1 < input.length() && pos2 < input.length() && pos1 < pos2)
480        {
481            std::vector<std::string> tokens = tokenize(input.substr(pos1, pos2 - pos1), ",");
482            if (!ConvertValue(&this->value_.getVector2().x, tokens[0]))
483            {
484                this->value_.setValue(defvalue);
485                return false;
486            }
487            if (!ConvertValue(&this->value_.getVector2().y, tokens[1]))
488            {
489                this->value_.setValue(defvalue);
490                return false;
491            }
492
493            return true;
494        }
495
496        this->value_.setValue(defvalue);
497        return false;
498    }
499
500    /**
501        @brief Parses a given std::string into a value of the type Vector3 and assigns it to the right variable. If the conversion failed, the default-value gets assigned.
502        @param input The string to convert
503        @param defvalue The default-value
504        @return True if the string was successfully parsed
505    */
506    bool ConfigValueContainer::parseString(const std::string& input, const Vector3& defvalue)
507    {
508        // Strip the value-string
509        unsigned int pos1 = input.find("(") + 1;
510        unsigned int pos2 = input.find(")", pos1);
511
512        // Try to convert the stripped value-string to Vector3
513        if (pos1 < input.length() && pos2 < input.length() && pos1 < pos2)
514        {
515            std::vector<std::string> tokens = tokenize(input.substr(pos1, pos2 - pos1), ",");
516            if (!ConvertValue(&this->value_.getVector3().x, tokens[0]))
517            {
518                this->value_.setValue(defvalue);
519                return false;
520            }
521            if (!ConvertValue(&this->value_.getVector3().y, tokens[1]))
522            {
523                this->value_.setValue(defvalue);
524                return false;
525            }
526            if (!ConvertValue(&this->value_.getVector3().z, tokens[2]))
527            {
528                this->value_.setValue(defvalue);
529                return false;
530            }
531
532            return true;
533        }
534
535        this->value_.setValue(defvalue);
536        return false;
537    }
538
539    /**
540        @brief Parses a given std::string into a value of the type ColourValue and assigns it to the right variable. If the conversion failed, the default-value gets assigned.
541        @param input The string to convert
542        @param defvalue The default-value
543        @return True if the string was successfully parsed
544    */
545    bool ConfigValueContainer::parseString(const std::string& input, const ColourValue& defvalue)
546    {
547        // Strip the value-string
548        unsigned int pos1 = input.find("(") + 1;
549        unsigned int pos2 = input.find(")", pos1);
550
551        // Try to convert the stripped value-string to Vector3
552        if (pos1 < input.length() && pos2 < input.length() && pos1 < pos2)
553        {
554            std::vector<std::string> tokens = tokenize(input.substr(pos1, pos2 - pos1), ",");
555            if (!ConvertValue(&this->value_.getColourValue().r, tokens[0]))
556            {
557                this->value_.setValue(defvalue);
558                return false;
559            }
560            if (!ConvertValue(&this->value_.getColourValue().g, tokens[1]))
561            {
562                this->value_.setValue(defvalue);
563                return false;
564            }
565            if (!ConvertValue(&this->value_.getColourValue().b, tokens[2]))
566            {
567                this->value_.setValue(defvalue);
568                return false;
569            }
570            if (!ConvertValue(&this->value_.getColourValue().a, tokens[3]))
571            {
572                this->value_.setValue(defvalue);
573                return false;
574            }
575
576            return true;
577        }
578
579        this->value_.setValue(defvalue);
580        return false;
581    }
582
583    /**
584        @brief Parses a given std::string into a value of the type Quaternion and assigns it to the right variable. If the conversion failed, the default-value gets assigned.
585        @param input The string to convert
586        @param defvalue The default-value
587        @return True if the string was successfully parsed
588    */
589    bool ConfigValueContainer::parseString(const std::string& input, const Quaternion& defvalue)
590    {
591        // Strip the value-string
592        unsigned int pos1 = input.find("(") + 1;
593        unsigned int pos2 = input.find(")", pos1);
594
595        // Try to convert the stripped value-string to Vector3
596        if (pos1 < input.length() && pos2 < input.length() && pos1 < pos2)
597        {
598            std::vector<std::string> tokens = tokenize(input.substr(pos1, pos2 - pos1), ",");
599            if (!ConvertValue(&this->value_.getQuaternion().w, tokens[0]))
600            {
601                this->value_.setValue(defvalue);
602                return false;
603            }
604            if (!ConvertValue(&this->value_.getQuaternion().x, tokens[1]))
605            {
606                this->value_.setValue(defvalue);
607                return false;
608            }
609            if (!ConvertValue(&this->value_.getQuaternion().y, tokens[2]))
610            {
611                this->value_.setValue(defvalue);
612                return false;
613            }
614            if (!ConvertValue(&this->value_.getQuaternion().z, tokens[3]))
615            {
616                this->value_.setValue(defvalue);
617                return false;
618            }
619
620            return true;
621        }
622
623        this->value_.setValue(defvalue);
624        return false;
625    }
626
627    /**
628        @brief Parses a given std::string into a value of the type long double and assigns it to the right variable. If the conversion failed, the default-value gets assigned.
629        @param input The string to convert
630        @param defvalue The default-value
631        @return True if the string was successfully parsed
632    */
633    bool ConfigValueContainer::parseString(const std::string& input, const Radian& defvalue)
634    {
635        return ConvertValue(&this->value_.getRadian(), input, defvalue);
636    }
637
638    /**
639        @brief Parses a given std::string into a value of the type long double and assigns it to the right variable. If the conversion failed, the default-value gets assigned.
640        @param input The string to convert
641        @param defvalue The default-value
642        @return True if the string was successfully parsed
643    */
644    bool ConfigValueContainer::parseString(const std::string& input, const Degree& defvalue)
645    {
646        return ConvertValue(&this->value_.getDegree(), input, defvalue);
647    }
648
649    /**
650        @brief Sets the corresponding entry in the config-file back to the default value.
651    */
652    void ConfigValueContainer::resetConfigFileEntry()
653    {
654        (*this->configFileLine_) = this->varname_ + "=" + this->defvalueString_;
655        ConfigValueContainer::writeConfigFile(CONFIGFILEPATH);
656    }
657
658    /**
659        @brief Sets the value of the variable back to the default value and resets the config-file entry.
660    */
661    void ConfigValueContainer::resetConfigValue()
662    {
663        this->parseString(this->defvalueString_, this->value_);
664        this->resetConfigFileEntry();
665    }
666
667    /**
668        @brief Searches the corresponding entry in the config-file and creates it, if there is no entry.
669    */
670    void ConfigValueContainer::searchConfigFileLine()
671    {
672        // Read the file if needed
673        if (!ConfigValueContainer::finishedReadingConfigFile())
674            ConfigValueContainer::readConfigFile(CONFIGFILEPATH);
675
676        // The string of the section we're searching
677        std::string section = "";
678        section.append("[");
679        section.append(this->classname_);
680        section.append("]");
681
682        // Iterate through all config-file-lines
683        bool success = false;
684        std::list<std::string>::iterator it1;
685        for(it1 = ConfigValueContainer::getConfigFileLines().begin(); it1 != ConfigValueContainer::getConfigFileLines().end(); ++it1)
686        {
687            // Don't try to parse comments
688            if (this->isComment(*it1))
689                continue;
690
691            if ((*it1).find(section) < (*it1).length())
692            {
693                // We found the right section
694                bool bLineIsEmpty = false;
695                std::list<std::string>::iterator positionToPutNewLineAt;
696
697                // Iterate through all lines in the section
698                std::list<std::string>::iterator it2;
699                for(it2 = ++it1; it2 != ConfigValueContainer::getConfigFileLines().end(); ++it2)
700                {
701                    // Don't try to parse comments
702                    if (this->isComment(*it2))
703                        continue;
704
705                    // This if-else block is used to write a new line right after the last line of the
706                    // section but in front of the following empty lines before the next section.
707                    // (So this helps to keep a nice formatting with empty-lines between sections in the config-file)
708                    if (this->isEmpty(*it2))
709                    {
710                        if (!bLineIsEmpty)
711                        {
712                            bLineIsEmpty = true;
713                            positionToPutNewLineAt = it2;
714                        }
715                    }
716                    else
717                    {
718                        if (!bLineIsEmpty)
719                            positionToPutNewLineAt = it2;
720
721                        bLineIsEmpty = false;
722                    }
723
724                    // Look out for the beginning of the next section
725                    unsigned int open = (*it2).find("[");
726                    unsigned int close = (*it2).find("]");
727                    if ((open < (*it2).length()) && (close < (*it2).length()) && (open < close))
728                    {
729                        // The next section startet, so our line isn't yet in the file - now we add it and safe the file
730                        this->configFileLine_ = this->getConfigFileLines().insert(positionToPutNewLineAt, this->varname_ + "=" + this->defvalueString_);
731                        ConfigValueContainer::writeConfigFile(CONFIGFILEPATH);
732                        success = true;
733                        break;
734                    }
735
736                    // Look out for the variable-name
737                    if ((*it2).find(this->varname_) < (*it2).length())
738                    {
739                        // We found the right line - safe it and return
740                        this->configFileLine_ = it2;
741                        success = true;
742                        break;
743                    }
744                }
745
746                // Check if we succeeded
747                if (!success)
748                {
749                    // Looks like we found the right section, but the file ended without containing our variable - so we add it and safe the file
750                    this->configFileLine_ = this->getConfigFileLines().insert(positionToPutNewLineAt, this->varname_ + "=" + this->defvalueString_);
751                    ConfigValueContainer::writeConfigFile(CONFIGFILEPATH);
752                    success = true;
753                }
754                break;
755            }
756        }
757
758        // Check if we succeeded
759        if (!success)
760        {
761            // We obviously didn't found the right section, so we'll create it
762            this->getConfigFileLines().push_back("[" + this->classname_ + "]");                   // Create the section
763            this->getConfigFileLines().push_back(this->varname_ + "=" + this->defvalueString_);   // Create the line
764            this->configFileLine_ = --this->getConfigFileLines().end();                           // Set the pointer to the last element
765            success = true;
766            this->getConfigFileLines().push_back("");                                             // Add an empty line - this is needed for the algorithm in the searchConfigFileLine-function
767            ConfigValueContainer::writeConfigFile(CONFIGFILEPATH);                              // Save the changed config-file
768        }
769    }
770
771    /**
772        @brief Determines if a line in the config-file is a comment.
773        @param line The line to check
774        @return True = it's a comment
775    */
776    bool ConfigValueContainer::isComment(const std::string& line)
777    {
778        // Strip the line, whitespaces are disturbing
779        std::string teststring = getStrippedLine(line);
780
781        // There are four possible comment-symbols:
782        //  1) #comment in script-language style
783        //  2) %comment in matlab style
784        //  3) ;comment in unreal tournament config-file style
785        //  4) //comment in code style
786        if (teststring[0] == '#' || teststring[0] == '%' || teststring[0] == ';' || (teststring[0] == '/' && teststring[0] == '/'))
787            return true;
788
789        return false;
790    }
791
792    /**
793        @brief Determines if a line in the config-file is empty (contains only whitespaces).
794        @param line The line to check
795        @return True = it's empty
796    */
797    bool ConfigValueContainer::isEmpty(const std::string& line)
798    {
799        return getStrippedLine(line) == "";
800    }
801
802    /**
803        @brief Removes all whitespaces from a line.
804        @param line The line to strip
805        @return The stripped line
806    */
807    std::string ConfigValueContainer::getStrippedLine(const std::string& line)
808    {
809        std::string output = line;
810        unsigned int pos;
811        while ((pos = output.find(" ")) < output.length())
812            output.erase(pos, 1);
813        while ((pos = output.find("\t")) < output.length())
814            output.erase(pos, 1);
815
816        return output;
817    }
818
819    /**
820        @brief Returns the part in the corresponding config-file-entry of the container that defines the value.
821        @param bStripped True = strip the value-string
822        @return The value-string
823    */
824    std::string ConfigValueContainer::parseValueString(bool bStripped)
825    {
826        std::string output;
827        if (bStripped)
828            output = this->getStrippedLine(*this->configFileLine_);
829        else
830            output = *this->configFileLine_;
831
832        return output.substr(output.find("=") + 1);
833    }
834
835    /**
836        @brief Rreturns a list, containing all entrys in the config-file.
837        @return The list
838    */
839    std::list<std::string>& ConfigValueContainer::getConfigFileLines()
840    {
841        // This is done to avoid problems while executing this code before main()
842        static std::list<std::string> configFileLinesStaticReference = std::list<std::string>();
843        return configFileLinesStaticReference;
844    }
845
846    /**
847        @brief Returns true if the ConfigFile is read and stored into the ConfigFile-lines-list.
848        @param finished This is used to change the state
849        @return True if the ConfigFile is read and stored into the ConfigFile-lines-list
850    */
851    bool ConfigValueContainer::finishedReadingConfigFile(bool finished)
852    {
853        // This is done to avoid problems while executing this code before main()
854        static bool finishedReadingConfigFileStaticVariable = false;
855
856        if (finished)
857            finishedReadingConfigFileStaticVariable = true;
858
859        return finishedReadingConfigFileStaticVariable;
860    }
861
862    /**
863        @brief Reads the config-file and stores the lines in a list.
864        @param filename The name of the config-file
865    */
866    void ConfigValueContainer::readConfigFile(const std::string& filename)
867    {
868        // This creates the file if it's not existing
869        std::ofstream createFile;
870        createFile.open(filename.c_str(), std::fstream::app);
871        createFile.close();
872
873        // Open the file
874        std::ifstream file;
875        file.open(filename.c_str(), std::fstream::in);
876
877        if (!file.is_open())
878        {
879            COUT(1) << "An error occurred in ConfigValueContainer.cc:" << std::endl;
880            COUT(1) << "Error: Couldn't open config-file " << filename << " to read the config values!" << std::endl;
881            return;
882        }
883
884        char line[1024];
885
886        // Iterate through the file and add the lines into the list
887        while (file.good() && !file.eof())
888        {
889            file.getline(line, 1024);
890            ConfigValueContainer::getConfigFileLines().push_back(line);
891//            std::cout << "### ->" << line << "<- : empty: " << isEmpty(line) << " comment: " << isComment(line) << std::endl;
892        }
893
894        // The last line is useless
895        ConfigValueContainer::getConfigFileLines().pop_back();
896
897        // Add an empty line to the end of the file if needed
898        // this is needed for the algorithm in the searchConfigFileLine-function
899        if ((ConfigValueContainer::getConfigFileLines().size() > 0) && !isEmpty(*ConfigValueContainer::getConfigFileLines().rbegin()))
900        {
901//            std::cout << "### newline added" << std::endl;
902            ConfigValueContainer::getConfigFileLines().push_back("");
903        }
904
905        file.close();
906
907        ConfigValueContainer::finishedReadingConfigFile(true);
908    }
909
910    /**
911        @brief Writes the content of the list, containing all lines of the config-file, into the config-file.
912        @param filename The name of the config-file
913    */
914    void ConfigValueContainer::writeConfigFile(const std::string& filename)
915    {
916        // Make sure we stored the config-file in the list
917        if (!ConfigValueContainer::finishedReadingConfigFile())
918            ConfigValueContainer::readConfigFile(filename);
919
920        // Open the file
921        std::ofstream file;
922        file.open(filename.c_str(), std::fstream::out);
923
924        if (!file.is_open())
925        {
926            COUT(1) << "An error occurred in ConfigValueContainer.cc:" << std::endl;
927            COUT(1) << "Error: Couldn't open config-file " << filename << " to write the config values!" << std::endl;
928            return;
929        }
930
931        // Iterate through the list an write the lines into the file
932        std::list<std::string>::iterator it;
933        for (it = ConfigValueContainer::getConfigFileLines().begin(); it != ConfigValueContainer::getConfigFileLines().end(); ++it)
934        {
935            file << (*it) << std::endl;
936        }
937
938        file.close();
939    }
940
941    /**
942        @brief Adds a description to the config-value.
943        @param description The description
944    */
945    void ConfigValueContainer::description(const std::string& description)
946    {
947        if (!this->bAddedDescription_)
948        {
949            this->description_ = std::string("ConfigValueDescription::" + this->classname_ + "::" + this->varname_);
950            AddLanguageEntry(this->description_, description);
951            this->bAddedDescription_ = true;
952        }
953    }
954
955    /**
956        @brief Returns the description of the config-value.
957        @return The description
958    */
959    const std::string& ConfigValueContainer::getDescription() const
960    {
961        return GetLocalisation(this->description_);
962    }
963}
Note: See TracBrowser for help on using the repository browser.