Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 5943 was 5943, checked in by bensch, 18 years ago

orxonox/trunk: ini_parser sync

File size: 12.9 KB
RevLine 
[4597]1/*
[2064]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:
[5014]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.
[2064]18*/
19
20
21#include "ini_parser.h"
[4381]22
[5031]23#include <stdlib.h>
24#include <string.h>
[2064]25
[5938]26#if HAVE_CONFIG_H
27#include <config.h> 
28#endif
29
[5933]30#ifdef DEBUG
31 #include "debug.h"
32#else
33 #define PRINTF(x) printf
34#endif
35
[2064]36using namespace std;
37
[2141]38/**
[5934]39 * @brief constructs an IniParser using a file
[5017]40 * @param fileName: the path and name of the file to parse
[5933]41 */
[5014]42IniParser::IniParser (const char* fileName)
[2064]43{
[5031]44  this->fileName = NULL;
[5933]45
[5934]46
[5014]47  if (fileName != NULL)
[5018]48    this->readFile(fileName);
[2064]49}
50
[5933]51
[2141]52/**
[5934]53 * @brief removes the IniParser from memory
[5933]54 */
[2064]55IniParser::~IniParser ()
56{
[5933]57  this->deleteSections();
[2064]58}
59
[5933]60
[5015]61/**
[5934]62 * @brief removes all the sections. This is like delete, but even cooler :)
[5015]63 */
[5014]64void IniParser::deleteSections()
[2064]65{
[5934]66  // in all sections
[5933]67  while(!this->sections.empty())
[5014]68  {
[5936]69     IniSection section = this->sections.front();
[5934]70   
71    // in all entries of the sections
[5933]72    while(!section.entries.empty())
[3231]73    {
[5934]74      // delete all strings of entries.
[5933]75      IniEntry entry = section.entries.front();
76      delete []entry.name;
77      delete []entry.value;
78      section.entries.pop_front();
79    }
[5934]80    // delete all Sections
[5933]81    delete []section.name;
82    this->sections.pop_front();
[5014]83  }
[5936]84  this->currentSection = this->sections.end();
[5031]85  this->setFileName(NULL);
[2064]86}
87
[5933]88
[2141]89/**
[5934]90 * @brief sets the Name of the input-file
91 * @param fileName The new FileName to set to the IniParser
[5938]92 * If fileName is NULL the new Name will be set to NULL too.
[5934]93 */
94void IniParser::setFileName(const char* fileName)
95{
96  if (this->fileName)
97    delete []this->fileName;
[5938]98  if (fileName != NULL)
[5934]99  {
100    this->fileName = new char[strlen(fileName)+1];
101    strcpy(this->fileName, fileName);
102  }
103  else
104    this->fileName = NULL;
105}
106
107
108/**
109 * @brief opens a file to parse
[5017]110 * @param fileName: path and name of the new file to parse
[5014]111 * @return true on success false otherwise;
[5934]112 *
113 * If there was already an opened file, the file will be closed,
114 * and the new one will be opened.
[5933]115 */
[5018]116bool IniParser::readFile(const char* fileName)
[2064]117{
[5934]118  FILE*    stream;           //< The stream we use to read the file.
119
120  if (this->fileName != NULL)
121    this->deleteSections();
[5015]122  if( fileName == NULL)
123    return false;
[5014]124
[5015]125  if( (stream = fopen (fileName, "r")) == NULL)
[5014]126  {
[5015]127    PRINTF(1)("IniParser could not open %s\n", fileName);
[5014]128    return false;
129  }
130  else
131  {
[5934]132    this->setFileName(fileName);
[5014]133
134    /////////////////////////////
135    // READING IN THE INI-FILE //
136    /////////////////////////////
137    char lineBuffer[PARSELINELENGHT];
138    char buffer[PARSELINELENGHT];
[5021]139    const char* lineBegin;
[5014]140    char* ptr;
141
[5319]142    while( fgets (lineBuffer, PARSELINELENGHT, stream))
[2551]143    {
[5021]144      lineBegin = lineBuffer;
[5014]145      // remove newline char, and \0-terminate
146      if( (ptr = strchr( lineBuffer, '\n')) != NULL)
147        *ptr = 0;
[5021]148      // cut up to the beginning of the line.
149      while((*lineBegin == ' ' || *lineBegin == '\t') && lineBegin < lineBuffer + strlen(lineBuffer))
150        ++lineBegin;
151      if (strlen(lineBegin) <= 1 || *lineBegin == '#' || *lineBegin == ';')
152        continue;//printf("empty Line\n");
[2551]153      // check for section identifyer
[5021]154      else if( sscanf (lineBegin, "[%s", buffer) == 1)
[5014]155      {
156        if( (ptr = strchr( buffer, ']')) != NULL)
[4597]157        {
[5014]158          *ptr = 0;
[5020]159          this->addSection(buffer);
[4597]160        }
[5014]161      }
[5018]162      // check for Entry identifier (Entry = Value)
[5021]163      else if( (ptr = strchr( lineBegin, '=')) != NULL)
[5014]164      {
165        if (currentSection == NULL)
166        {
[5021]167          PRINTF(2)("Not in a Section yet for %s\n", lineBegin);
[5014]168          continue;
169        }
[5021]170        if( ptr == lineBegin)
[5014]171          continue;
172        char* valueBegin = ptr+1;
[5021]173        while ((*valueBegin == ' ' || *valueBegin == '\t') && valueBegin <= lineBegin + strlen(lineBegin))
[5014]174          ++valueBegin;
[5022]175        char* valueEnd = valueBegin + strlen(valueBegin)-1;
176        while ((*valueEnd == ' ' || *valueEnd == '\t') && valueEnd >= valueBegin)
177          --valueEnd;
178        valueEnd[1] = '\0';
[5018]179        char* nameEnd = ptr-1;
[5021]180        while ((*nameEnd == ' ' || *nameEnd == '\t' ) && nameEnd >= lineBegin)
[5014]181          --nameEnd;
182        nameEnd[1] = '\0';
[5018]183
[5021]184        this->addVar(lineBegin, valueBegin);
[5014]185      }
[2551]186    }
[5014]187  }
[5934]188  this->currentSection = this->sections.begin();
189  if (!this->sections.empty())
190    this->currentEntry = (*this->currentSection).entries.begin();
191
[5014]192  fclose(stream);
193  return true;
[2064]194}
195
[5933]196
[2141]197/**
[5934]198 * @brief opens a file and writes to it
[5020]199 * @param fileName: path and name of the new file to write to
200 * @return true on success false otherwise
201 */
[5936]202bool IniParser::writeFile(const char* fileName) const
[5020]203{
204  FILE*    stream;           //!< The stream we use to read the file.
205  if( fileName == NULL)
206    return false;
207
208  if( (stream = fopen (fileName, "w")) == NULL)
209  {
210    PRINTF(1)("IniParser could not open %s\n", fileName);
211    return false;
212  }
213  else
214  {
[5936]215    std::list<IniSection>::const_iterator section;
[5934]216    for (section = this->sections.begin(); section != this->sections.end(); section++)
[5020]217      {
[5933]218        fprintf(stream, "\n [%s]\n", (*section).name);
[5934]219       
[5936]220        std::list<IniEntry>::const_iterator entry;
[5933]221        for (entry = (*section).entries.begin(); entry != (*section).entries.end(); entry++)
222          fprintf(stream, "   %s = %s\n", (*entry).name, (*entry).value);
[5020]223      }
224  }
225  fclose(stream);
226}
227
[5933]228
[5021]229/**
[5934]230 * @brief adds a section to the list of Sections,
[5021]231 * if no Section list is availiable, it will create it
232 * @param sectionName the Name of the section to add
233 * @return true on success... there is only success or segfault :)
234 */
[5020]235bool IniParser::addSection(const char* sectionName)
236{
[5933]237  this->sections.push_back(IniSection());
[5020]238
[5933]239  this->sections.back().name = new char[strlen(sectionName)+1];
240  strcpy(this->sections.back().name, sectionName);
241
242  this->currentSection = --this->sections.end();
[5934]243  if (!this->sections.empty())
[5936]244      this->currentEntry = (*this->currentSection).entries.begin();
[5031]245  PRINTF(5)("Added Section %s\n", sectionName);
[5021]246  return true;
[5020]247}
248
[5933]249
[5020]250/**
[5934]251 * @brief Set the parsing cursor to the specified section
[5014]252 * @param sectionName: the name of the section to set the cursor to
253 * @return true on success or false if the section could not be found
[5936]254 */
255bool IniParser::getSection(const char* sectionName)
[2064]256{
[5933]257  std::list<IniSection>::iterator section;
258  for (section = this->sections.begin(); section != this->sections.end(); section++)
259    if (!strcmp((*section).name, sectionName))
[5934]260      {
261        this->currentSection = section;
262        this->currentEntry = (*this->currentSection).entries.begin();
263        return true;
264      }
[5014]265  return false;
266}
[4597]267
[5933]268
[5014]269/**
[5934]270 * @brief moves to the first section
[5015]271 */
[5936]272void IniParser::firstSection()
[5015]273{
[5933]274  this->currentSection = this->sections.begin();
[5934]275  if (!this->sections.empty())
276    this->currentEntry = (*this->currentSection).entries.begin();
[5015]277}
278
[5933]279
[5015]280/**
[5934]281 * @brief searches the next section
[5014]282 * @returns the name of the section if found, NULL otherwise
283 */
284const char* IniParser::nextSection()
285{
[5933]286  if (this->currentSection == this->sections.end())
[5014]287    return NULL;
[5015]288
[5936]289  this->currentSection++;
290
[5934]291  if (this->currentSection != this->sections.end())
292    {
293      this->currentEntry = (*this->currentSection).entries.begin();
294      return this->currentSection->name;
295    }
[5014]296  else
297    return NULL;
[2064]298}
299
[5933]300
[2141]301/**
[5934]302 * @brief moves to the first Variable of the current Section
[5015]303 */
[5936]304void IniParser::firstVar()
[5015]305{
[5936]306  if (!this->sections.empty() &&
307      this->currentSection != this->sections.end())
[5933]308    this->currentEntry = (*this->currentSection).entries.begin();
[5015]309}
310
[5933]311
[5015]312/**
[5934]313 * @brief gets the next VarName = VarValue pair from the parsing stream
[5014]314 * @return true on success, false otherwise (in the latter case name and value will be NULL)
315 */
316bool IniParser::nextVar()
317{
[5934]318  if ( this->sections.empty() 
319       || this->currentSection == this->sections.end()
320       || this->currentEntry == (*this->currentSection).entries.end())
[5014]321    return false;
[5934]322
[5933]323  this->currentEntry++;
[5014]324
[5934]325  if (this->currentEntry == (*this->currentSection).entries.end())
[5014]326    return false;
327  else
328    return true;
329}
330
[5933]331
[5014]332/**
[5934]333 * @brief adds a new Entry to either the currentSection or the section called by sectionName
[5020]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{
[5934]343  std::list<IniSection>::iterator section;
[5936]344 
[5020]345  if (sectionName != NULL)
346  {
[5933]347    for (section = this->sections.begin(); section != this->sections.end(); section++)
348      if (!strcmp((*section).name, sectionName))
[5020]349        break;
350  }
351  else
[5933]352    section = this->currentSection;
[5936]353  if (section == this->sections.end())
354    return false;
[5020]355
[5933]356  if (section == this->sections.end())
[5020]357  {
[5934]358    PRINTF(2)("section '%s' not found for value '%s'\n", sectionName, entryName);
[5020]359    return false;
360  }
361  else
362  {
[5933]363    (*section).entries.push_back(IniEntry());
[5938]364    (*section).entries.back().name = new char[strlen(entryName)+1];
[5933]365    strcpy((*section).entries.back().name, entryName);
366    (*section).entries.back().value = new char[strlen(value)+1];
367    strcpy((*section).entries.back().value, value);
[5936]368    PRINTF(5)("Added Entry %s with Value '%s' to Section %s\n",
369              (*section).entries.back().name,
370              (*section).entries.back().value,
371              (*section).name);
[5020]372    return true;
373  }
374}
375
[5933]376
[5020]377/**
[5934]378 * @brief directly acesses an entry in a section
[5014]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
[4836]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
[5020]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.
[2141]386*/
[5014]387const char* IniParser::getVar(const char* entryName, const char* sectionName, const char* defaultValue) const
[2065]388{
[5933]389  if (fileName != NULL)
[5014]390  {
[5933]391    std::list<IniSection>::const_iterator section;
[5934]392    if (sectionName != NULL)
[5014]393      {
[5934]394        for (section = this->sections.begin(); section != this->sections.end(); section++)
395          {
396            if (!strcmp((*section).name, sectionName))
397              {
398                break;
399              }
400          }
[5014]401      }
[5934]402    else
403      section = this->currentSection;
[5936]404   
405   if (section == this->sections.end())
[5943]406     {
407       PRINTF(2)("Section %s that should be containing %s not found.\n", sectionName, entryName);
408       return (defaultValue);
409     }
[5934]410
411    std::list<IniEntry>::const_iterator entry;
412    for (entry = (*section).entries.begin(); entry != (*section).entries.end(); entry++)
413      if (!strcmp((*entry).name, entryName))
414        return (*entry).value;
415    PRINTF(2)("Entry '%s' in section '%s' not found.\n", entryName, sectionName);
416   
[5014]417  }
418  else
[5934]419    PRINTF(2)("%s not opened\n", fileName);
[5014]420
421  return defaultValue;
422
[2065]423}
[5014]424
[5935]425
[5017]426/**
[5935]427 * @returns the name of the Current selected Section
428 */
429const char* IniParser::getCurrentSection() const 
430{
[5936]431  if (!this->sections.empty() &&
432      this->currentSection != this->sections.end()) 
433    return this->currentSection->name;
434  else
435    return NULL;
[5935]436 }
437
438
439/**
440 * @returns the current entries Name, or NULL if we havn't selected a Entry
441 */
442const char* IniParser::getCurrentName() const
443{
444 if (!this->sections.empty() &&
[5936]445     this->currentSection != this->sections.end() &&
[5935]446     this->currentEntry != (*this->currentSection).entries.end())
447   return (*this->currentEntry).name;
448 else
449   return NULL;
450}
451
452/**
453 * @returns the current entries Value, or NULL if we havn't selected a Entry
454 */
455const char* IniParser::getCurrentValue() const 
456{
[5936]457  if (!this->sections.empty() &&
458      this->currentSection != this->sections.end() &&
459      this->currentEntry != (*this->currentSection).entries.end())
[5935]460    return (*this->currentEntry).value;
461  else
462    return NULL; 
463}
464
465
466/**
[5934]467 * @brief output the whole tree in a nice and easy way.
[5017]468 */
[5014]469void IniParser::debug() const
470{
[5031]471  PRINTF(0)("Iniparser %s - debug\n", this->fileName);
[5933]472  if (this->fileName != NULL)
[5014]473  {
[5933]474    std::list<IniSection>::const_iterator section;
475    for (section = this->sections.begin(); section != this->sections.end(); section++)
[5014]476    {
[5933]477      PRINTF(0)(" [%s]\n", (*section).name);
[5014]478
[5933]479      std::list<IniEntry>::const_iterator entry;
480      for (entry = (*section).entries.begin(); entry != (*section).entries.end(); entry++)
481        PRINTF(0)("   '%s' -> '%s'\n", (*entry).name, (*entry).value);
[5014]482    }
483  }
484  else
[5933]485    PRINTF(1)("no opened ini-file.\n");
[5014]486}
[5938]487
488
Note: See TracBrowser for help on using the repository browser.