Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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