Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/trunk/src/lib/parser/ini_parser/ini_parser.cc @ 5947

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

orxonox/trunk: minor cleanup

File size: 17.5 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
[5944]26#if HAVE_CONFIG_H
27#include <config.h>
[5938]28#endif
29
[5933]30#ifdef DEBUG
[5944]31 #include "../../../defs/debug.h"
[5933]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;
[5945]45  this->comment = NULL;
[5933]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();
[5944]70
[5934]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/**
[5944]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.
[5945]119  int      lineCount = 0;    //< The Count of lines.
[5934]120
[5945]121
[5934]122  if (this->fileName != NULL)
123    this->deleteSections();
[5015]124  if( fileName == NULL)
125    return false;
[5014]126
[5015]127  if( (stream = fopen (fileName, "r")) == NULL)
[5014]128  {
[5015]129    PRINTF(1)("IniParser could not open %s\n", fileName);
[5014]130    return false;
131  }
132  else
133  {
[5934]134    this->setFileName(fileName);
[5014]135
136    /////////////////////////////
137    // READING IN THE INI-FILE //
138    /////////////////////////////
139    char lineBuffer[PARSELINELENGHT];
140    char buffer[PARSELINELENGHT];
[5021]141    const char* lineBegin;
[5014]142    char* ptr;
143
[5319]144    while( fgets (lineBuffer, PARSELINELENGHT, stream))
[2551]145    {
[5021]146      lineBegin = lineBuffer;
[5014]147      // remove newline char, and \0-terminate
148      if( (ptr = strchr( lineBuffer, '\n')) != NULL)
149        *ptr = 0;
[5021]150      // cut up to the beginning of the line.
151      while((*lineBegin == ' ' || *lineBegin == '\t') && lineBegin < lineBuffer + strlen(lineBuffer))
152        ++lineBegin;
[5946]153
154      // check if we have a FileComment
155      if ( (*lineBegin == '#' || *lineBegin == ';'))
156      {
157        char* newCommenLine = new char[strlen(lineBegin)+1];
158        strcpy(newCommenLine, lineBegin);
159        this->commentList.push_back(newCommenLine);
160        continue;
161      }
162      if (lineCount == 0 && !this->commentList.empty())
163      {
164        this->setFileComment();
165        lineCount++;
166      }
167
[2551]168      // check for section identifyer
[5021]169      else if( sscanf (lineBegin, "[%s", buffer) == 1)
[5014]170      {
171        if( (ptr = strchr( buffer, ']')) != NULL)
[4597]172        {
[5014]173          *ptr = 0;
[5020]174          this->addSection(buffer);
[5946]175          this->setSectionComment();
[4597]176        }
[5014]177      }
[5018]178      // check for Entry identifier (Entry = Value)
[5021]179      else if( (ptr = strchr( lineBegin, '=')) != NULL)
[5014]180      {
181        if (currentSection == NULL)
182        {
[5021]183          PRINTF(2)("Not in a Section yet for %s\n", lineBegin);
[5946]184          lineCount++;
[5014]185          continue;
186        }
[5946]187        if( ptr == lineBegin) {
188          lineCount++;
[5014]189          continue;
[5946]190        }
[5014]191        char* valueBegin = ptr+1;
[5021]192        while ((*valueBegin == ' ' || *valueBegin == '\t') && valueBegin <= lineBegin + strlen(lineBegin))
[5014]193          ++valueBegin;
[5022]194        char* valueEnd = valueBegin + strlen(valueBegin)-1;
195        while ((*valueEnd == ' ' || *valueEnd == '\t') && valueEnd >= valueBegin)
196          --valueEnd;
197        valueEnd[1] = '\0';
[5018]198        char* nameEnd = ptr-1;
[5021]199        while ((*nameEnd == ' ' || *nameEnd == '\t' ) && nameEnd >= lineBegin)
[5014]200          --nameEnd;
201        nameEnd[1] = '\0';
[5018]202
[5021]203        this->addVar(lineBegin, valueBegin);
[5946]204        this->setEntryComment();
[5945]205
206        lineCount++;
[5014]207      }
[2551]208    }
[5014]209  }
[5934]210  this->currentSection = this->sections.begin();
211  if (!this->sections.empty())
212    this->currentEntry = (*this->currentSection).entries.begin();
213
[5014]214  fclose(stream);
215  return true;
[2064]216}
217
[5933]218
[2141]219/**
[5934]220 * @brief opens a file and writes to it
[5020]221 * @param fileName: path and name of the new file to write to
222 * @return true on success false otherwise
223 */
[5936]224bool IniParser::writeFile(const char* fileName) const
[5020]225{
226  FILE*    stream;           //!< The stream we use to read the file.
[5945]227  if( fileName == NULL && (fileName = this->fileName) == NULL )
[5020]228    return false;
229
230  if( (stream = fopen (fileName, "w")) == NULL)
231  {
232    PRINTF(1)("IniParser could not open %s\n", fileName);
233    return false;
234  }
235  else
236  {
[5936]237    std::list<IniSection>::const_iterator section;
[5934]238    for (section = this->sections.begin(); section != this->sections.end(); section++)
[5020]239      {
[5933]240        fprintf(stream, "\n [%s]\n", (*section).name);
[5944]241
[5936]242        std::list<IniEntry>::const_iterator entry;
[5933]243        for (entry = (*section).entries.begin(); entry != (*section).entries.end(); entry++)
244          fprintf(stream, "   %s = %s\n", (*entry).name, (*entry).value);
[5020]245      }
246  }
247  fclose(stream);
248}
249
[5945]250void IniParser::setFileComment(const char* fileComment)
251{
[5946]252  if (this->comment != NULL)
253    delete this->comment;
[5933]254
[5946]255  if (fileComment != NULL)
256  {
257    this->comment = new char[strlen(fileComment)+1];
258    strcpy(this->comment, fileComment);
259  }
260  else
261    this->comment = NULL;
[5945]262}
263
264
[5021]265/**
[5934]266 * @brief adds a section to the list of Sections,
[5021]267 * if no Section list is availiable, it will create it
268 * @param sectionName the Name of the section to add
269 * @return true on success... there is only success or segfault :)
270 */
[5020]271bool IniParser::addSection(const char* sectionName)
272{
[5933]273  this->sections.push_back(IniSection());
[5946]274  this->sections.back().comment = NULL;
[5933]275  this->sections.back().name = new char[strlen(sectionName)+1];
276  strcpy(this->sections.back().name, sectionName);
277
278  this->currentSection = --this->sections.end();
[5934]279  if (!this->sections.empty())
[5936]280      this->currentEntry = (*this->currentSection).entries.begin();
[5031]281  PRINTF(5)("Added Section %s\n", sectionName);
[5021]282  return true;
[5020]283}
284
[5933]285
[5020]286/**
[5934]287 * @brief Set the parsing cursor to the specified section
[5014]288 * @param sectionName: the name of the section to set the cursor to
289 * @return true on success or false if the section could not be found
[5936]290 */
291bool IniParser::getSection(const char* sectionName)
[2064]292{
[5933]293  std::list<IniSection>::iterator section;
294  for (section = this->sections.begin(); section != this->sections.end(); section++)
295    if (!strcmp((*section).name, sectionName))
[5934]296      {
297        this->currentSection = section;
298        this->currentEntry = (*this->currentSection).entries.begin();
299        return true;
300      }
[5014]301  return false;
302}
[4597]303
[5947]304/**
305 *
306 */
[5945]307void IniParser::setSectionComment(const char* comment, const char* sectionName)
308{
309
[5947]310
[5945]311}
312
[5947]313/**
314 *
315 */
[5945]316const char* IniParser::getSectionComment(const char* sectionName) const
317{
318
319}
320
321
[5014]322/**
[5934]323 * @brief moves to the first section
[5015]324 */
[5936]325void IniParser::firstSection()
[5015]326{
[5933]327  this->currentSection = this->sections.begin();
[5934]328  if (!this->sections.empty())
329    this->currentEntry = (*this->currentSection).entries.begin();
[5015]330}
331
[5933]332
[5015]333/**
[5934]334 * @brief searches the next section
[5014]335 * @returns the name of the section if found, NULL otherwise
336 */
337const char* IniParser::nextSection()
338{
[5933]339  if (this->currentSection == this->sections.end())
[5014]340    return NULL;
[5015]341
[5936]342  this->currentSection++;
343
[5934]344  if (this->currentSection != this->sections.end())
345    {
346      this->currentEntry = (*this->currentSection).entries.begin();
347      return this->currentSection->name;
348    }
[5014]349  else
350    return NULL;
[2064]351}
352
[5933]353
[2141]354/**
[5934]355 * @brief adds a new Entry to either the currentSection or the section called by sectionName
[5020]356 * @param entryName the Name of the Entry to add
357 * @param value the value to assign to this entry
358 * @param sectionName if NULL then this entry will be set to the currentSection
359 * otherwise to the section refered to by sectionName.
360 * If both are NULL no entry will be added
361 * @return true if everything is ok false on error
362 */
363bool IniParser::addVar(const char* entryName, const char* value, const char* sectionName)
364{
[5934]365  std::list<IniSection>::iterator section;
[5944]366
[5020]367  if (sectionName != NULL)
368  {
[5933]369    for (section = this->sections.begin(); section != this->sections.end(); section++)
370      if (!strcmp((*section).name, sectionName))
[5020]371        break;
372  }
373  else
[5933]374    section = this->currentSection;
[5945]375
[5936]376  if (section == this->sections.end())
377    return false;
[5020]378
[5933]379  if (section == this->sections.end())
[5020]380  {
[5934]381    PRINTF(2)("section '%s' not found for value '%s'\n", sectionName, entryName);
[5020]382    return false;
383  }
384  else
385  {
[5933]386    (*section).entries.push_back(IniEntry());
[5946]387    (*section).entries.back().comment = NULL;
[5938]388    (*section).entries.back().name = new char[strlen(entryName)+1];
[5933]389    strcpy((*section).entries.back().name, entryName);
390    (*section).entries.back().value = new char[strlen(value)+1];
391    strcpy((*section).entries.back().value, value);
[5936]392    PRINTF(5)("Added Entry %s with Value '%s' to Section %s\n",
[5945]393              (*section).entries.back().name,
394              (*section).entries.back().value,
395              (*section).name);
[5946]396    this->currentEntry = --(*section).entries.end();
[5020]397    return true;
398  }
399}
400
[5933]401
[5020]402/**
[5934]403 * @brief directly acesses an entry in a section
[5014]404 * @param entryName: the name of the entry to find
405 * @param sectionName: the section where the entry is to be found
406 * @param defaultValue: what should be returned in case the entry cannot be found
[4836]407 * @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]408 *
409 *  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
410 * lead to unwanted behaviour.
[2141]411*/
[5014]412const char* IniParser::getVar(const char* entryName, const char* sectionName, const char* defaultValue) const
[2065]413{
[5945]414  if (this->fileName != NULL)
[5014]415  {
[5945]416    std::list<IniSection>::const_iterator section = this->getSectionIT(sectionName);
[5944]417
[5945]418  if (section == this->sections.end())
419    {
420      PRINTF(2)("Section %s that should be containing %s not found.\n", sectionName, entryName);
421      return (defaultValue);
422    }
[5934]423
424    std::list<IniEntry>::const_iterator entry;
425    for (entry = (*section).entries.begin(); entry != (*section).entries.end(); entry++)
426      if (!strcmp((*entry).name, entryName))
[5945]427        return (*entry).value;
[5934]428    PRINTF(2)("Entry '%s' in section '%s' not found.\n", entryName, sectionName);
[5944]429
[5014]430  }
431  else
[5934]432    PRINTF(2)("%s not opened\n", fileName);
[5014]433
434  return defaultValue;
435
[2065]436}
[5014]437
[5947]438/**
439 * Set the Comment of a specified Entry.
440 */
[5945]441const char* IniParser::setEntryComment(const char* comment, const char* entryName, const char* sectionName)
442{
443
444
445}
446
[5947]447/**
448 *
449 */
[5945]450const char* IniParser::getEntryComment(const char* entryName, const char* sectionName) const
451{
452
453
454}
455
456
[5017]457/**
[5945]458 * @brief moves to the first Variable of the current Section
459 */
460void IniParser::firstVar()
461{
462  if (!this->sections.empty() &&
463       this->currentSection != this->sections.end())
464    this->currentEntry = (*this->currentSection).entries.begin();
465}
466
467
468/**
469 * @brief gets the next VarName = VarValue pair from the parsing stream
470 * @return true on success, false otherwise (in the latter case name and value will be NULL)
471 */
472bool IniParser::nextVar()
473{
474  if ( this->sections.empty()
475       || this->currentSection == this->sections.end()
476       || this->currentEntry == (*this->currentSection).entries.end())
477    return false;
478
479  this->currentEntry++;
480
481  if (this->currentEntry == (*this->currentSection).entries.end())
482    return false;
483  else
484    return true;
485}
486
487
488
489/**
[5944]490 * @returns the name of the Current selected Section
[5935]491 */
[5944]492const char* IniParser::getCurrentSection() const
[5935]493{
[5936]494  if (!this->sections.empty() &&
[5944]495      this->currentSection != this->sections.end())
[5936]496    return this->currentSection->name;
497  else
498    return NULL;
[5935]499 }
500
501
[5944]502/**
503 * @returns the current entries Name, or NULL if we havn't selected a Entry
[5935]504 */
505const char* IniParser::getCurrentName() const
506{
507 if (!this->sections.empty() &&
[5936]508     this->currentSection != this->sections.end() &&
[5935]509     this->currentEntry != (*this->currentSection).entries.end())
510   return (*this->currentEntry).name;
511 else
512   return NULL;
513}
514
515/**
[5944]516 * @returns the current entries Value, or NULL if we havn't selected a Entry
[5935]517 */
[5944]518const char* IniParser::getCurrentValue() const
[5935]519{
[5936]520  if (!this->sections.empty() &&
521      this->currentSection != this->sections.end() &&
522      this->currentEntry != (*this->currentSection).entries.end())
[5935]523    return (*this->currentEntry).value;
524  else
[5944]525    return NULL;
[5935]526}
527
528
[5947]529/**
530 *
531 */
[5945]532std::list<IniParser::IniSection>::const_iterator IniParser::getSectionIT(const char* sectionName) const
533{
534  std::list<IniSection>::const_iterator section;
535  if (sectionName != NULL)
536  {
537    for (section = this->sections.begin(); section != this->sections.end(); section++)
538    {
539      if (!strcmp((*section).name, sectionName))
540      {
541        break;
542      }
543    }
544  }
545  else
546    section = this->currentSection;
547
548  return section;
549}
550
[5947]551/**
552 *
553 */
[5945]554std::list<IniParser::IniEntry>::const_iterator IniParser::getEntryIT(const char* entryName, const char* sectionName) const
555{
556  if (entryName == NULL)
557    return this->currentEntry;
558
559}
560
561
562
[5947]563/**
564 * takes lines together to form one FileComment, ereasing the commentList
565 */
[5946]566void IniParser::setFileComment()
567{
568  if (this->comment != NULL)
569    delete[] this->comment;
570
571  if (this->commentList.empty()) {
572    this->comment = NULL;
573    return;
574  }
575
576  unsigned int stringLength = 1;
577  std::list<char*>::iterator comment;
578  for (comment = this->commentList.begin(); comment != this->commentList.end(); comment++)
579    stringLength += strlen((*comment)) +1;
580
581  this->comment = new char[stringLength];
582  this->comment[0] = '\0';
583  while (!this->commentList.empty())
584  {
585    if (*this->comment != '\0')
586      strcat(this->comment, "\n");
587    strcat(this->comment, this->commentList.front());
588    delete[] this->commentList.front();
589    this->commentList.pop_front();
590  }
591}
592
[5947]593/**
594 * takes lines together to form one SectionComment, ereasing the commentList
595 */
[5946]596void IniParser::setSectionComment()
597{
598  if ((*this->currentSection).comment != NULL)
599    delete[] (*this->currentSection).comment;
600
601  if (this->commentList.empty()) {
602    (*this->currentSection).comment = NULL;
603    return;
604  }
605
606  unsigned int stringLength = 1;
607  std::list<char*>::iterator comment;
608  for (comment = this->commentList.begin(); comment != this->commentList.end(); comment++)
609    stringLength += strlen((*comment)) +1;
610
611  (*this->currentSection).comment = new char[stringLength];
612  (*this->currentSection).comment[0] = '\0';
613  while (!this->commentList.empty())
614  {
615    if (*(*this->currentSection).comment != '\0')
616      strcat((*this->currentSection).comment, "\n");
617    strcat((*this->currentSection).comment, this->commentList.front());
618    delete[] this->commentList.front();
619    this->commentList.pop_front();
620  }
621}
622
[5947]623/**
624 * takes lines together to form one EntryComment, ereasing the commentList
625 */
[5946]626void IniParser::setEntryComment()
627{
628  if ((*this->currentEntry).comment != NULL)
629    delete[] (*this->currentEntry).comment;
630
631  if (this->commentList.empty()) {
632    (*this->currentEntry).comment = NULL;
633    return;
634  }
635
636  unsigned int stringLength = 1;
637  std::list<char*>::iterator comment;
638  for (comment = this->commentList.begin(); comment != this->commentList.end(); comment++)
639    stringLength += strlen((*comment)) +1;
640
641  (*this->currentEntry).comment = new char[stringLength];
642  (*this->currentEntry).comment[0] = '\0';
643  while (!this->commentList.empty())
644  {
645    if (*(*this->currentEntry).comment != '\0')
646      strcat((*this->currentEntry).comment, "\n");
647    strcat((*this->currentEntry).comment, this->commentList.front());
648    delete[] this->commentList.front();
649    this->commentList.pop_front();
650  }
651
652}
653
654
[5935]655/**
[5934]656 * @brief output the whole tree in a nice and easy way.
[5017]657 */
[5014]658void IniParser::debug() const
659{
[5031]660  PRINTF(0)("Iniparser %s - debug\n", this->fileName);
[5946]661  if (this->comment != NULL)
662    PRINTF(0)("FileComment:\n %s\n\n", this->comment);
663
[5933]664  if (this->fileName != NULL)
[5014]665  {
[5933]666    std::list<IniSection>::const_iterator section;
667    for (section = this->sections.begin(); section != this->sections.end(); section++)
[5014]668    {
[5946]669      if ((*section).comment != NULL)
670        PRINTF(0)(" %s\n", (*section).comment);
[5933]671      PRINTF(0)(" [%s]\n", (*section).name);
[5014]672
[5933]673      std::list<IniEntry>::const_iterator entry;
674      for (entry = (*section).entries.begin(); entry != (*section).entries.end(); entry++)
[5946]675      {
676        if ((*entry).comment != NULL)
677          PRINTF(0)(" %s\n", (*entry).comment);
[5933]678        PRINTF(0)("   '%s' -> '%s'\n", (*entry).name, (*entry).value);
[5946]679      }
[5014]680    }
681  }
682  else
[5933]683    PRINTF(1)("no opened ini-file.\n");
[5014]684}
[5938]685
Note: See TracBrowser for help on using the repository browser.