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
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 char* fileName)
43{
44  this->fileName = NULL;
45  this->comment = NULL;
46
47  if (fileName != NULL)
48    this->readFile(fileName);
49}
50
51
52/**
53 * @brief removes the IniParser from memory
54 */
55IniParser::~IniParser ()
56{
57  this->deleteSections();
58}
59
60
61/**
62 * @brief removes all the sections. This is like delete, but even cooler :)
63 */
64void IniParser::deleteSections()
65{
66  // in all sections
67  while(!this->sections.empty())
68  {
69     IniSection section = this->sections.front();
70
71    // in all entries of the sections
72    while(!section.entries.empty())
73    {
74      // delete all strings of entries.
75      IniEntry entry = section.entries.front();
76      delete []entry.name;
77      delete []entry.value;
78      section.entries.pop_front();
79    }
80    // delete all Sections
81    delete []section.name;
82    this->sections.pop_front();
83  }
84  this->currentSection = this->sections.end();
85  this->setFileName(NULL);
86}
87
88
89/**
90 * @brief sets the Name of the input-file
91 * @param fileName The new FileName to set to the IniParser
92 * If fileName is NULL the new Name will be set to NULL too.
93 */
94void IniParser::setFileName(const char* fileName)
95{
96  if (this->fileName)
97    delete []this->fileName;
98  if (fileName != NULL)
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/**
109 * @brief opens a file to parse
110 * @param fileName: path and name of the new file to parse
111 * @return true on success false otherwise;
112 *
113 * If there was already an opened file, the file will be closed,
114 * and the new one will be opened.
115 */
116bool IniParser::readFile(const char* fileName)
117{
118  FILE*    stream;           //< The stream we use to read the file.
119  int      lineCount = 0;    //< The Count of lines.
120
121
122  if (this->fileName != NULL)
123    this->deleteSections();
124  if( fileName == NULL)
125    return false;
126
127  if( (stream = fopen (fileName, "r")) == NULL)
128  {
129    PRINTF(1)("IniParser could not open %s\n", fileName);
130    return false;
131  }
132  else
133  {
134    this->setFileName(fileName);
135
136    /////////////////////////////
137    // READING IN THE INI-FILE //
138    /////////////////////////////
139    char lineBuffer[PARSELINELENGHT];
140    char buffer[PARSELINELENGHT];
141    const char* lineBegin;
142    char* ptr;
143
144    while( fgets (lineBuffer, PARSELINELENGHT, stream))
145    {
146      lineBegin = lineBuffer;
147      // remove newline char, and \0-terminate
148      if( (ptr = strchr( lineBuffer, '\n')) != NULL)
149        *ptr = 0;
150      // cut up to the beginning of the line.
151      while((*lineBegin == ' ' || *lineBegin == '\t') && lineBegin < lineBuffer + strlen(lineBuffer))
152        ++lineBegin;
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
168      // check for section identifyer
169      else if( sscanf (lineBegin, "[%s", buffer) == 1)
170      {
171        if( (ptr = strchr( buffer, ']')) != NULL)
172        {
173          *ptr = 0;
174          this->addSection(buffer);
175          this->setSectionComment();
176        }
177      }
178      // check for Entry identifier (Entry = Value)
179      else if( (ptr = strchr( lineBegin, '=')) != NULL)
180      {
181        if (currentSection == NULL)
182        {
183          PRINTF(2)("Not in a Section yet for %s\n", lineBegin);
184          lineCount++;
185          continue;
186        }
187        if( ptr == lineBegin) {
188          lineCount++;
189          continue;
190        }
191        char* valueBegin = ptr+1;
192        while ((*valueBegin == ' ' || *valueBegin == '\t') && valueBegin <= lineBegin + strlen(lineBegin))
193          ++valueBegin;
194        char* valueEnd = valueBegin + strlen(valueBegin)-1;
195        while ((*valueEnd == ' ' || *valueEnd == '\t') && valueEnd >= valueBegin)
196          --valueEnd;
197        valueEnd[1] = '\0';
198        char* nameEnd = ptr-1;
199        while ((*nameEnd == ' ' || *nameEnd == '\t' ) && nameEnd >= lineBegin)
200          --nameEnd;
201        nameEnd[1] = '\0';
202
203        this->addVar(lineBegin, valueBegin);
204        this->setEntryComment();
205
206        lineCount++;
207      }
208    }
209  }
210  this->currentSection = this->sections.begin();
211  if (!this->sections.empty())
212    this->currentEntry = (*this->currentSection).entries.begin();
213
214  fclose(stream);
215  return true;
216}
217
218
219/**
220 * @brief opens a file and writes to it
221 * @param fileName: path and name of the new file to write to
222 * @return true on success false otherwise
223 */
224bool IniParser::writeFile(const char* fileName) const
225{
226  FILE*    stream;           //!< The stream we use to read the file.
227  if( fileName == NULL && (fileName = this->fileName) == NULL )
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  {
237    std::list<IniSection>::const_iterator section;
238    for (section = this->sections.begin(); section != this->sections.end(); section++)
239      {
240        fprintf(stream, "\n [%s]\n", (*section).name);
241
242        std::list<IniEntry>::const_iterator entry;
243        for (entry = (*section).entries.begin(); entry != (*section).entries.end(); entry++)
244          fprintf(stream, "   %s = %s\n", (*entry).name, (*entry).value);
245      }
246  }
247  fclose(stream);
248}
249
250void IniParser::setFileComment(const char* fileComment)
251{
252  if (this->comment != NULL)
253    delete this->comment;
254
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;
262}
263
264
265/**
266 * @brief adds a section to the list of Sections,
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 */
271bool IniParser::addSection(const char* sectionName)
272{
273  this->sections.push_back(IniSection());
274  this->sections.back().comment = NULL;
275  this->sections.back().name = new char[strlen(sectionName)+1];
276  strcpy(this->sections.back().name, sectionName);
277
278  this->currentSection = --this->sections.end();
279  if (!this->sections.empty())
280      this->currentEntry = (*this->currentSection).entries.begin();
281  PRINTF(5)("Added Section %s\n", sectionName);
282  return true;
283}
284
285
286/**
287 * @brief Set the parsing cursor to the specified section
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
290 */
291bool IniParser::getSection(const char* sectionName)
292{
293  std::list<IniSection>::iterator section;
294  for (section = this->sections.begin(); section != this->sections.end(); section++)
295    if (!strcmp((*section).name, sectionName))
296      {
297        this->currentSection = section;
298        this->currentEntry = (*this->currentSection).entries.begin();
299        return true;
300      }
301  return false;
302}
303
304/**
305 *
306 */
307void IniParser::setSectionComment(const char* comment, const char* sectionName)
308{
309
310
311}
312
313/**
314 *
315 */
316const char* IniParser::getSectionComment(const char* sectionName) const
317{
318
319}
320
321
322/**
323 * @brief moves to the first section
324 */
325void IniParser::firstSection()
326{
327  this->currentSection = this->sections.begin();
328  if (!this->sections.empty())
329    this->currentEntry = (*this->currentSection).entries.begin();
330}
331
332
333/**
334 * @brief searches the next section
335 * @returns the name of the section if found, NULL otherwise
336 */
337const char* IniParser::nextSection()
338{
339  if (this->currentSection == this->sections.end())
340    return NULL;
341
342  this->currentSection++;
343
344  if (this->currentSection != this->sections.end())
345    {
346      this->currentEntry = (*this->currentSection).entries.begin();
347      return this->currentSection->name;
348    }
349  else
350    return NULL;
351}
352
353
354/**
355 * @brief adds a new Entry to either the currentSection or the section called by sectionName
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{
365  std::list<IniSection>::iterator section;
366
367  if (sectionName != NULL)
368  {
369    for (section = this->sections.begin(); section != this->sections.end(); section++)
370      if (!strcmp((*section).name, sectionName))
371        break;
372  }
373  else
374    section = this->currentSection;
375
376  if (section == this->sections.end())
377    return false;
378
379  if (section == this->sections.end())
380  {
381    PRINTF(2)("section '%s' not found for value '%s'\n", sectionName, entryName);
382    return false;
383  }
384  else
385  {
386    (*section).entries.push_back(IniEntry());
387    (*section).entries.back().comment = NULL;
388    (*section).entries.back().name = new char[strlen(entryName)+1];
389    strcpy((*section).entries.back().name, entryName);
390    (*section).entries.back().value = new char[strlen(value)+1];
391    strcpy((*section).entries.back().value, value);
392    PRINTF(5)("Added Entry %s with Value '%s' to Section %s\n",
393              (*section).entries.back().name,
394              (*section).entries.back().value,
395              (*section).name);
396    this->currentEntry = --(*section).entries.end();
397    return true;
398  }
399}
400
401
402/**
403 * @brief directly acesses an entry in a section
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
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
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.
411*/
412const char* IniParser::getVar(const char* entryName, const char* sectionName, const char* defaultValue) const
413{
414  if (this->fileName != NULL)
415  {
416    std::list<IniSection>::const_iterator section = this->getSectionIT(sectionName);
417
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    }
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))
427        return (*entry).value;
428    PRINTF(2)("Entry '%s' in section '%s' not found.\n", entryName, sectionName);
429
430  }
431  else
432    PRINTF(2)("%s not opened\n", fileName);
433
434  return defaultValue;
435
436}
437
438/**
439 * Set the Comment of a specified Entry.
440 */
441const char* IniParser::setEntryComment(const char* comment, const char* entryName, const char* sectionName)
442{
443
444
445}
446
447/**
448 *
449 */
450const char* IniParser::getEntryComment(const char* entryName, const char* sectionName) const
451{
452
453
454}
455
456
457/**
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/**
490 * @returns the name of the Current selected Section
491 */
492const char* IniParser::getCurrentSection() const
493{
494  if (!this->sections.empty() &&
495      this->currentSection != this->sections.end())
496    return this->currentSection->name;
497  else
498    return NULL;
499 }
500
501
502/**
503 * @returns the current entries Name, or NULL if we havn't selected a Entry
504 */
505const char* IniParser::getCurrentName() const
506{
507 if (!this->sections.empty() &&
508     this->currentSection != this->sections.end() &&
509     this->currentEntry != (*this->currentSection).entries.end())
510   return (*this->currentEntry).name;
511 else
512   return NULL;
513}
514
515/**
516 * @returns the current entries Value, or NULL if we havn't selected a Entry
517 */
518const char* IniParser::getCurrentValue() const
519{
520  if (!this->sections.empty() &&
521      this->currentSection != this->sections.end() &&
522      this->currentEntry != (*this->currentSection).entries.end())
523    return (*this->currentEntry).value;
524  else
525    return NULL;
526}
527
528
529/**
530 *
531 */
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
551/**
552 *
553 */
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
563/**
564 * takes lines together to form one FileComment, ereasing the commentList
565 */
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
593/**
594 * takes lines together to form one SectionComment, ereasing the commentList
595 */
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
623/**
624 * takes lines together to form one EntryComment, ereasing the commentList
625 */
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
655/**
656 * @brief output the whole tree in a nice and easy way.
657 */
658void IniParser::debug() const
659{
660  PRINTF(0)("Iniparser %s - debug\n", this->fileName);
661  if (this->comment != NULL)
662    PRINTF(0)("FileComment:\n %s\n\n", this->comment);
663
664  if (this->fileName != NULL)
665  {
666    std::list<IniSection>::const_iterator section;
667    for (section = this->sections.begin(); section != this->sections.end(); section++)
668    {
669      if ((*section).comment != NULL)
670        PRINTF(0)(" %s\n", (*section).comment);
671      PRINTF(0)(" [%s]\n", (*section).name);
672
673      std::list<IniEntry>::const_iterator entry;
674      for (entry = (*section).entries.begin(); entry != (*section).entries.end(); entry++)
675      {
676        if ((*entry).comment != NULL)
677          PRINTF(0)(" %s\n", (*entry).comment);
678        PRINTF(0)("   '%s' -> '%s'\n", (*entry).name, (*entry).value);
679      }
680    }
681  }
682  else
683    PRINTF(1)("no opened ini-file.\n");
684}
685
Note: See TracBrowser for help on using the repository browser.