Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk: iniparser cleans itself up

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