Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk: cleanup in ini-parser

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