Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk: merged the std-branche back, it runs on windows and Linux

svn merge https://svn.orxonox.net/orxonox/branches/std . -r7202:HEAD

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