Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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