Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk: writing, loading, and comments work

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