Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/branches/spaceshipcontrol/src/lib/util/ini_parser.cc @ 5875

Last change on this file since 5875 was 5319, checked in by bensch, 19 years ago

orxonox/trunk: some minor file-handling

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( fgets (lineBuffer, PARSELINELENGHT, stream))
122    {
123      lineBegin = lineBuffer;
124      // remove newline char, and \0-terminate
125      if( (ptr = strchr( lineBuffer, '\n')) != NULL)
126        *ptr = 0;
127      // cut up to the beginning of the line.
128      while((*lineBegin == ' ' || *lineBegin == '\t') && lineBegin < lineBuffer + strlen(lineBuffer))
129        ++lineBegin;
130      if (strlen(lineBegin) <= 1 || *lineBegin == '#' || *lineBegin == ';')
131        continue;//printf("empty Line\n");
132      // check for section identifyer
133      else if( sscanf (lineBegin, "[%s", buffer) == 1)
134      {
135        if( (ptr = strchr( buffer, ']')) != NULL)
136        {
137          *ptr = 0;
138          this->addSection(buffer);
139        }
140      }
141      // check for Entry identifier (Entry = Value)
142      else if( (ptr = strchr( lineBegin, '=')) != NULL)
143      {
144        if (currentSection == NULL)
145        {
146          PRINTF(2)("Not in a Section yet for %s\n", lineBegin);
147          continue;
148        }
149        if( ptr == lineBegin)
150          continue;
151        char* valueBegin = ptr+1;
152        while ((*valueBegin == ' ' || *valueBegin == '\t') && valueBegin <= lineBegin + strlen(lineBegin))
153          ++valueBegin;
154        char* valueEnd = valueBegin + strlen(valueBegin)-1;
155        while ((*valueEnd == ' ' || *valueEnd == '\t') && valueEnd >= valueBegin)
156          --valueEnd;
157        valueEnd[1] = '\0';
158        char* nameEnd = ptr-1;
159        while ((*nameEnd == ' ' || *nameEnd == '\t' ) && nameEnd >= lineBegin)
160          --nameEnd;
161        nameEnd[1] = '\0';
162
163        this->addVar(lineBegin, valueBegin);
164      }
165    }
166  }
167  fclose(stream);
168  return true;
169}
170
171/**
172 * opens a file and writes to it
173 * @param fileName: path and name of the new file to write to
174 * @return true on success false otherwise
175 */
176bool IniParser::writeFile(const char* fileName)
177{
178  FILE*    stream;           //!< The stream we use to read the file.
179  if( fileName == NULL)
180    return false;
181
182  if( (stream = fopen (fileName, "w")) == NULL)
183  {
184    PRINTF(1)("IniParser could not open %s\n", fileName);
185    return false;
186  }
187  else
188  {
189    if (this->sections)
190    {
191      tIterator<IniSection>* sectionIt = this->sections->getIterator();
192      IniSection* sectionEnum = sectionIt->firstElement();
193      while (sectionEnum)
194      {
195        fprintf(stream, "\n [%s]\n", sectionEnum->name);
196
197        tIterator<IniEntry>* entryIt = sectionEnum->entries->getIterator();
198        IniEntry* entryEnum = entryIt->firstElement();
199        while (entryEnum)
200        {
201          fprintf(stream, "   %s = %s\n", entryEnum->name, entryEnum->value);
202
203          entryEnum = entryIt->nextElement();
204        }
205        delete entryIt;
206
207        sectionEnum = sectionIt->nextElement();
208      }
209      delete sectionIt;
210    }
211    else
212      PRINTF(1)("%s no sections defined yet\n", fileName);
213  }
214  fclose(stream);
215}
216
217/**
218 * adds a section to the list of Sections,
219 * if no Section list is availiable, it will create it
220 * @param sectionName the Name of the section to add
221 * @return true on success... there is only success or segfault :)
222 */
223bool IniParser::addSection(const char* sectionName)
224{
225  if (this->sections == NULL)
226    this->sections = new tList<IniSection>;
227
228  IniSection* newSection = new IniSection;
229  newSection->name = new char[strlen(sectionName)+1];
230  strcpy(newSection->name, sectionName);
231  newSection->entries = new tList<IniEntry>;
232  this->currentSection = newSection;
233  this->sections->add(newSection);
234  PRINTF(5)("Added Section %s\n", sectionName);
235  return true;
236}
237
238/**
239 *  set the parsing cursor to the specified section
240 * @param sectionName: the name of the section to set the cursor to
241 * @return true on success or false if the section could not be found
242*/
243bool IniParser::getSection( const char* sectionName)
244{
245  tIterator<IniSection>* sectionIt = this->sections->getIterator();
246  IniSection* sectionEnum = sectionIt->firstElement();
247  while (sectionEnum)
248  {
249    if (!strcmp(sectionEnum->name, sectionName))
250    {
251      this->currentSection = sectionEnum;
252      this->currentEntry = NULL;
253      delete sectionIt;
254      return true;
255    }
256
257    sectionEnum = sectionIt->nextElement();
258  }
259  delete sectionIt;
260  return false;
261}
262
263/**
264 * moves to the first section
265 */
266void IniParser::getFirstSection()
267{
268  if (this->sections)
269    this->currentSection = this->sections->firstElement();
270  else
271    this->currentSection = NULL;
272  this->currentEntry = NULL;
273}
274
275/**
276 * searches the next section
277 * @returns the name of the section if found, NULL otherwise
278 */
279const char* IniParser::nextSection()
280{
281  if (this->currentSection == NULL)
282    return NULL;
283  else
284  {
285    if (this->sections)
286    {
287      if (this->currentSection == this->sections->lastElement())
288        this->currentSection = NULL;
289      else
290        this->currentSection = this->sections->nextElement(this->currentSection);
291    }
292  }
293
294  if (this->currentSection != NULL)
295    return this->currentSection->name;
296  else
297    return NULL;
298}
299
300/**
301 * moves to the first Variable of the current Section
302 */
303void IniParser::getFirstVar()
304{
305  if (this->currentSection)
306    this->currentEntry = this->currentSection->entries->firstElement();
307  else
308    this->currentEntry = NULL;
309}
310
311/**
312 *  gets the next VarName=VarValue pair from the parsing stream
313 * @return true on success, false otherwise (in the latter case name and value will be NULL)
314 */
315bool IniParser::nextVar()
316{
317  if (this->currentSection == NULL
318      || this->currentEntry == NULL
319      || this->currentEntry == this->currentSection->entries->lastElement())
320  {
321    this->currentEntry = NULL;
322    return false;
323  }
324  this->currentEntry = this->currentSection->entries->nextElement(this->currentEntry);
325
326  if (this->currentEntry == NULL)
327    return false;
328  else
329    return true;
330}
331
332/**
333 * adds a new Entry to either the currentSection or the section called by sectionName
334 * @param entryName the Name of the Entry to add
335 * @param value the value to assign to this entry
336 * @param sectionName if NULL then this entry will be set to the currentSection
337 * otherwise to the section refered to by sectionName.
338 * If both are NULL no entry will be added
339 * @return true if everything is ok false on error
340 */
341bool IniParser::addVar(const char* entryName, const char* value, const char* sectionName)
342{
343  IniSection* addSection = NULL;
344  if (sectionName != NULL)
345  {
346    tIterator<IniSection>* sectionIt = this->sections->getIterator();
347    IniSection* sectionEnum = sectionIt->firstElement();
348    while (sectionEnum)
349    {
350      if (!strcmp(sectionEnum->name, sectionName))
351      {
352        addSection = sectionEnum;
353        break;
354      }
355      sectionEnum = sectionIt->nextElement();
356    }
357    delete sectionIt;
358  }
359  else
360    addSection = this->currentSection;
361
362  if (addSection == NULL)
363  {
364    PRINTF(2)("section not found for value %s\n", entryName);
365    return false;
366  }
367  else
368  {
369    IniEntry* newEntry = new IniEntry;
370    newEntry->name = new char[strlen (entryName)+1];
371    strcpy(newEntry->name, entryName);
372    newEntry->value = new char[strlen(value)+1];
373    strcpy(newEntry->value, value);
374    this->currentSection->entries->add(newEntry);
375    PRINTF(5)("Added Entry %s with Value '%s' to Section %s\n", newEntry->name, newEntry->name, addSection->name);
376    return true;
377  }
378}
379
380/**
381 *  directly acesses an entry in a section
382 * @param entryName: the name of the entry to find
383 * @param sectionName: the section where the entry is to be found
384 * @param defaultValue: what should be returned in case the entry cannot be found
385 * @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
386 *
387 *  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
388 * lead to unwanted behaviour.
389*/
390const char* IniParser::getVar(const char* entryName, const char* sectionName, const char* defaultValue) const
391{
392  if (this->sections)
393  {
394    tIterator<IniSection>* sectionIt = this->sections->getIterator();
395    IniSection* sectionEnum = sectionIt->firstElement();
396    while (sectionEnum)
397    {
398      if (!strcmp(sectionEnum->name, sectionName))
399      {
400        tIterator<IniEntry>* entryIt = sectionEnum->entries->getIterator();
401        IniEntry* entryEnum = entryIt->firstElement();
402        while (entryEnum)
403        {
404          if (!strcmp(entryEnum->name, entryName))
405          {
406            delete entryIt;
407            delete sectionIt;
408            return entryEnum->value;
409          }
410          entryEnum = entryIt->nextElement();
411        }
412         delete entryIt;
413         PRINTF(2)("Entry %s in section %s not found.\n", entryName, sectionName);
414         break;
415      }
416      sectionEnum = sectionIt->nextElement();
417    }
418    delete sectionIt;
419    PRINTF(2)("Section %s that should be containing %s not found.\n", sectionName, entryName);
420  }
421  else
422    PRINTF(1)("%s not opened\n", fileName);
423
424  return defaultValue;
425
426}
427
428
429void IniParser::setFileName(const char* fileName)
430{
431  if (this->fileName)
432    delete []this->fileName;
433  if (fileName)
434  {
435    this->fileName = new char[strlen(fileName)+1];
436    strcpy(this->fileName, fileName);
437  }
438  else
439    this->fileName = NULL;
440}
441
442
443/**
444 * output the whole tree in a nice and easy way.
445 */
446void IniParser::debug() const
447{
448  PRINTF(0)("Iniparser %s - debug\n", this->fileName);
449  if (this->sections)
450  {
451    tIterator<IniSection>* sectionIt = this->sections->getIterator();
452    IniSection* sectionEnum = sectionIt->firstElement();
453    while (sectionEnum)
454    {
455      PRINTF(0)(" [%s]\n", sectionEnum->name);
456
457      tIterator<IniEntry>* entryIt = sectionEnum->entries->getIterator();
458      IniEntry* entryEnum = entryIt->firstElement();
459      while (entryEnum)
460      {
461        PRINTF(0)("   :%s: -> '%s'\n", entryEnum->name, entryEnum->value);
462
463        entryEnum = entryIt->nextElement();
464      }
465      delete entryIt;
466
467      sectionEnum = sectionIt->nextElement();
468    }
469    delete sectionIt;
470  }
471  else
472    PRINTF(1)("%s not opened\n", fileName);
473}
Note: See TracBrowser for help on using the repository browser.