Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/branches/std/src/lib/parser/ini_parser/ini_parser.cc @ 7204

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

small bug… more to come :/

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