Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/trunk/src/lib/util/ini_parser.cc @ 5132

Last change on this file since 5132 was 5115, checked in by bensch, 19 years ago

orxonox/trunk: reimplemented the list functions, as i did before in revision 5110.
This time, i looked out for the bugs, and i think i found one

@patrick: i know, that you do not want to code at the moment… :/ → see mail

File size: 12.7 KB
Line 
1/*
2   orxonox - the future of 3D-vertical-scrollers
3
4   Copyright (C) 2004 orx
5
6   This program is free software; you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation; either version 2, or (at your option)
9   any later version.
10
11   ### File Specific:
12   main-programmer: Benjamin Grauer
13   co-programmer: Christian Meyer
14
15   2005-08-14: complete reimplementation:
16               now the File is parsed at the initialisation,
17               and informations is gathered there.
18*/
19
20
21#include "ini_parser.h"
22
23#include "list.h"
24#include <stdlib.h>
25#include <string.h>
26#include "debug.h"
27
28using namespace std;
29
30/**
31 *  constructs an IniParser using a file
32 * @param fileName: the path and name of the file to parse
33*/
34IniParser::IniParser (const char* fileName)
35{
36  this->currentEntry = NULL;
37  this->currentSection = NULL;
38  this->sections = NULL;
39  this->fileName = NULL;
40  if (fileName != NULL)
41    this->readFile(fileName);
42}
43
44/**
45 *  removes the IniParser from memory
46*/
47IniParser::~IniParser ()
48{
49  deleteSections();
50}
51
52/**
53 * removes all the sections. This is like delete, but even cooler :)
54 */
55void IniParser::deleteSections()
56{
57  if (this->sections)
58  {
59    tIterator<IniSection>* sectionIt = this->sections->getIterator();
60    IniSection* sectionEnum = sectionIt->firstElement();
61    while (sectionEnum)
62    {
63      tIterator<IniEntry>* entryIt = sectionEnum->entries->getIterator();
64      IniEntry* entryEnum = entryIt->firstElement();
65      while (entryEnum)
66      {
67        delete []entryEnum->name;
68        delete []entryEnum->value;
69        delete entryEnum;
70        entryEnum = entryIt->nextElement();
71      }
72      delete entryIt;
73
74      delete []sectionEnum->name;
75      delete sectionEnum->entries;
76      delete sectionEnum;
77      sectionEnum = sectionIt->nextElement();
78    }
79    delete sectionIt;
80  }
81  delete this->sections;
82  this->currentEntry = NULL;
83  this->currentSection = NULL;
84  this->sections = NULL;
85  this->setFileName(NULL);
86}
87
88/**
89 * opens another file to parse
90 * @param fileName: path and name of the new file to parse
91 * @return true on success false otherwise;
92*/
93bool IniParser::readFile(const char* fileName)
94{
95  FILE*    stream;           //!< The stream we use to read the file.
96  if (sections != NULL)
97    deleteSections();
98  if( fileName == NULL)
99    return false;
100  this->setFileName(fileName);
101
102  if( (stream = fopen (fileName, "r")) == NULL)
103  {
104    PRINTF(1)("IniParser could not open %s\n", fileName);
105    return false;
106  }
107  else
108  {
109    this->currentEntry = NULL;
110    this->currentSection = NULL;
111    this->sections = new tList<IniSection>;
112
113    /////////////////////////////
114    // READING IN THE INI-FILE //
115    /////////////////////////////
116    char lineBuffer[PARSELINELENGHT];
117    char buffer[PARSELINELENGHT];
118    const char* lineBegin;
119    char* ptr;
120
121    while( !feof( stream))
122    {
123      // get next line
124      fgets (lineBuffer, PARSELINELENGHT, stream);
125      lineBegin = lineBuffer;
126      // remove newline char, and \0-terminate
127      if( (ptr = strchr( lineBuffer, '\n')) != NULL)
128        *ptr = 0;
129      // cut up to the beginning of the line.
130      while((*lineBegin == ' ' || *lineBegin == '\t') && lineBegin < lineBuffer + strlen(lineBuffer))
131        ++lineBegin;
132      if (strlen(lineBegin) <= 1 || *lineBegin == '#' || *lineBegin == ';')
133        continue;//printf("empty Line\n");
134      // check for section identifyer
135      else if( sscanf (lineBegin, "[%s", buffer) == 1)
136      {
137        if( (ptr = strchr( buffer, ']')) != NULL)
138        {
139          *ptr = 0;
140          this->addSection(buffer);
141        }
142      }
143      // check for Entry identifier (Entry = Value)
144      else if( (ptr = strchr( lineBegin, '=')) != NULL)
145      {
146        if (currentSection == NULL)
147        {
148          PRINTF(2)("Not in a Section yet for %s\n", lineBegin);
149          continue;
150        }
151        if( ptr == lineBegin)
152          continue;
153        char* valueBegin = ptr+1;
154        while ((*valueBegin == ' ' || *valueBegin == '\t') && valueBegin <= lineBegin + strlen(lineBegin))
155          ++valueBegin;
156        char* valueEnd = valueBegin + strlen(valueBegin)-1;
157        while ((*valueEnd == ' ' || *valueEnd == '\t') && valueEnd >= valueBegin)
158          --valueEnd;
159        valueEnd[1] = '\0';
160        char* nameEnd = ptr-1;
161        while ((*nameEnd == ' ' || *nameEnd == '\t' ) && nameEnd >= lineBegin)
162          --nameEnd;
163        nameEnd[1] = '\0';
164
165        this->addVar(lineBegin, valueBegin);
166      }
167    }
168  }
169  fclose(stream);
170  return true;
171}
172
173/**
174 * opens a file and writes to it
175 * @param fileName: path and name of the new file to write to
176 * @return true on success false otherwise
177 */
178bool IniParser::writeFile(const char* fileName)
179{
180  FILE*    stream;           //!< The stream we use to read the file.
181  if( fileName == NULL)
182    return false;
183
184  if( (stream = fopen (fileName, "w")) == NULL)
185  {
186    PRINTF(1)("IniParser could not open %s\n", fileName);
187    return false;
188  }
189  else
190  {
191    if (this->sections)
192    {
193      tIterator<IniSection>* sectionIt = this->sections->getIterator();
194      IniSection* sectionEnum = sectionIt->firstElement();
195      while (sectionEnum)
196      {
197        fprintf(stream, "\n [%s]\n", sectionEnum->name);
198
199        tIterator<IniEntry>* entryIt = sectionEnum->entries->getIterator();
200        IniEntry* entryEnum = entryIt->firstElement();
201        while (entryEnum)
202        {
203          fprintf(stream, "   %s = %s\n", entryEnum->name, entryEnum->value);
204
205          entryEnum = entryIt->nextElement();
206        }
207        delete entryIt;
208
209        sectionEnum = sectionIt->nextElement();
210      }
211      delete sectionIt;
212    }
213    else
214      PRINTF(1)("%s no sections defined yet\n", fileName);
215  }
216  fclose(stream);
217}
218
219/**
220 * adds a section to the list of Sections,
221 * if no Section list is availiable, it will create it
222 * @param sectionName the Name of the section to add
223 * @return true on success... there is only success or segfault :)
224 */
225bool IniParser::addSection(const char* sectionName)
226{
227  if (this->sections == NULL)
228    this->sections = new tList<IniSection>;
229
230  IniSection* newSection = new IniSection;
231  newSection->name = new char[strlen(sectionName)+1];
232  strcpy(newSection->name, sectionName);
233  newSection->entries = new tList<IniEntry>;
234  this->currentSection = newSection;
235  this->sections->add(newSection);
236  PRINTF(5)("Added Section %s\n", sectionName);
237  return true;
238}
239
240/**
241 *  set the parsing cursor to the specified section
242 * @param sectionName: the name of the section to set the cursor to
243 * @return true on success or false if the section could not be found
244*/
245bool IniParser::getSection( const char* sectionName)
246{
247  tIterator<IniSection>* sectionIt = this->sections->getIterator();
248  IniSection* sectionEnum = sectionIt->firstElement();
249  while (sectionEnum)
250  {
251    if (!strcmp(sectionEnum->name, sectionName))
252    {
253      this->currentSection = sectionEnum;
254      this->currentEntry = NULL;
255      delete sectionIt;
256      return true;
257    }
258
259    sectionEnum = sectionIt->nextElement();
260  }
261  delete sectionIt;
262  return false;
263}
264
265/**
266 * moves to the first section
267 */
268void IniParser::getFirstSection()
269{
270  if (this->sections)
271    this->currentSection = this->sections->firstElement();
272  else
273    this->currentSection = NULL;
274  this->currentEntry = NULL;
275}
276
277/**
278 * searches the next section
279 * @returns the name of the section if found, NULL otherwise
280 */
281const char* IniParser::nextSection()
282{
283  if (this->currentSection == NULL)
284    return NULL;
285  else
286  {
287    if (this->sections)
288    {
289      if (this->currentSection == this->sections->lastElement())
290        this->currentSection = NULL;
291      else
292        this->currentSection = this->sections->nextElement(this->currentSection);
293    }
294  }
295
296  if (this->currentSection != NULL)
297    return this->currentSection->name;
298  else
299    return NULL;
300}
301
302/**
303 * moves to the first Variable of the current Section
304 */
305void IniParser::getFirstVar()
306{
307  if (this->currentSection)
308    this->currentEntry = this->currentSection->entries->firstElement();
309  else
310    this->currentEntry = NULL;
311}
312
313/**
314 *  gets the next VarName=VarValue pair from the parsing stream
315 * @return true on success, false otherwise (in the latter case name and value will be NULL)
316 */
317bool IniParser::nextVar()
318{
319  if (this->currentSection == NULL
320      || this->currentEntry == NULL
321      || this->currentEntry == this->currentSection->entries->lastElement())
322  {
323    this->currentEntry = NULL;
324    return false;
325  }
326  this->currentEntry = this->currentSection->entries->nextElement(this->currentEntry);
327
328  if (this->currentEntry == NULL)
329    return false;
330  else
331    return true;
332}
333
334/**
335 * adds a new Entry to either the currentSection or the section called by sectionName
336 * @param entryName the Name of the Entry to add
337 * @param value the value to assign to this entry
338 * @param sectionName if NULL then this entry will be set to the currentSection
339 * otherwise to the section refered to by sectionName.
340 * If both are NULL no entry will be added
341 * @return true if everything is ok false on error
342 */
343bool IniParser::addVar(const char* entryName, const char* value, const char* sectionName)
344{
345  IniSection* addSection = NULL;
346  if (sectionName != NULL)
347  {
348    tIterator<IniSection>* sectionIt = this->sections->getIterator();
349    IniSection* sectionEnum = sectionIt->firstElement();
350    while (sectionEnum)
351    {
352      if (!strcmp(sectionEnum->name, sectionName))
353      {
354        addSection = sectionEnum;
355        break;
356      }
357      sectionEnum = sectionIt->nextElement();
358    }
359    delete sectionIt;
360  }
361  else
362    addSection = this->currentSection;
363
364  if (addSection == NULL)
365  {
366    PRINTF(2)("section not found for value %s\n", entryName);
367    return false;
368  }
369  else
370  {
371    IniEntry* newEntry = new IniEntry;
372    newEntry->name = new char[strlen (entryName)+1];
373    strcpy(newEntry->name, entryName);
374    newEntry->value = new char[strlen(value)+1];
375    strcpy(newEntry->value, value);
376    this->currentSection->entries->add(newEntry);
377    PRINTF(5)("Added Entry %s with Value '%s' to Section %s\n", newEntry->name, newEntry->name, addSection->name);
378    return true;
379  }
380}
381
382/**
383 *  directly acesses an entry in a section
384 * @param entryName: the name of the entry to find
385 * @param sectionName: the section where the entry is to be found
386 * @param defaultValue: what should be returned in case the entry cannot be found
387 * @return a pointer to a buffer conatining the value of the specified entry. This buffer will contain the data specified in defvalue in case the entry wasn't found
388 *
389 *  The returned pointer points to an internal buffer, so do not free it on your own. Do not give a NULL pointer to defvalue, this will certainly
390 * lead to unwanted behaviour.
391*/
392const char* IniParser::getVar(const char* entryName, const char* sectionName, const char* defaultValue) const
393{
394  if (this->sections)
395  {
396    tIterator<IniSection>* sectionIt = this->sections->getIterator();
397    IniSection* sectionEnum = sectionIt->firstElement();
398    while (sectionEnum)
399    {
400      if (!strcmp(sectionEnum->name, sectionName))
401      {
402        tIterator<IniEntry>* entryIt = sectionEnum->entries->getIterator();
403        IniEntry* entryEnum = entryIt->firstElement();
404        while (entryEnum)
405        {
406          if (!strcmp(entryEnum->name, entryName))
407          {
408            delete entryIt;
409            delete sectionIt;
410            return entryEnum->value;
411          }
412          entryEnum = entryIt->nextElement();
413        }
414         delete entryIt;
415         PRINTF(2)("Entry %s in section %s not found.\n", entryName, sectionName);
416         break;
417      }
418      sectionEnum = sectionIt->nextElement();
419    }
420    delete sectionIt;
421    PRINTF(2)("Section %s that should be containing %s not found.\n", sectionName, entryName);
422  }
423  else
424    PRINTF(1)("%s not opened\n", fileName);
425
426  return defaultValue;
427
428}
429
430
431void IniParser::setFileName(const char* fileName)
432{
433  if (this->fileName)
434    delete []this->fileName;
435  if (fileName)
436  {
437    this->fileName = new char[strlen(fileName)+1];
438    strcpy(this->fileName, fileName);
439  }
440  else
441    this->fileName = NULL;
442}
443
444
445/**
446 * output the whole tree in a nice and easy way.
447 */
448void IniParser::debug() const
449{
450  PRINTF(0)("Iniparser %s - debug\n", this->fileName);
451  if (this->sections)
452  {
453    tIterator<IniSection>* sectionIt = this->sections->getIterator();
454    IniSection* sectionEnum = sectionIt->firstElement();
455    while (sectionEnum)
456    {
457      PRINTF(0)(" [%s]\n", sectionEnum->name);
458
459      tIterator<IniEntry>* entryIt = sectionEnum->entries->getIterator();
460      IniEntry* entryEnum = entryIt->firstElement();
461      while (entryEnum)
462      {
463        PRINTF(0)("   :%s: -> '%s'\n", entryEnum->name, entryEnum->value);
464
465        entryEnum = entryIt->nextElement();
466      }
467      delete entryIt;
468
469      sectionEnum = sectionIt->nextElement();
470    }
471    delete sectionIt;
472  }
473  else
474    PRINTF(1)("%s not opened\n", fileName);
475}
Note: See TracBrowser for help on using the repository browser.