Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/trunk/src/lib/util/ini_parser.cc @ 5935

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

orxonox/trunk: ini-parser works again

File size: 12.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#ifdef DEBUG
27 #include "debug.h"
28#else
29 #define PRINTF(x) printf
30#endif
31
32using namespace std;
33
34/**
35 * @brief constructs an IniParser using a file
36 * @param fileName: the path and name of the file to parse
37 */
38IniParser::IniParser (const char* fileName)
39{
40  this->fileName = NULL;
41
42
43  if (fileName != NULL)
44    this->readFile(fileName);
45}
46
47
48/**
49 * @brief removes the IniParser from memory
50 */
51IniParser::~IniParser ()
52{
53  this->deleteSections();
54}
55
56
57/**
58 * @brief removes all the sections. This is like delete, but even cooler :)
59 */
60void IniParser::deleteSections()
61{
62  // in all sections
63  while(!this->sections.empty())
64  {
65   
66    IniSection section = this->sections.front();
67   
68    // in all entries of the sections
69    while(!section.entries.empty())
70    {
71      // delete all strings of entries.
72      IniEntry entry = section.entries.front();
73      delete []entry.name;
74      delete []entry.value;
75      section.entries.pop_front();
76    }
77    // delete all Sections
78    delete []section.name;
79    this->sections.pop_front();
80  }
81  this->setFileName(NULL);
82}
83
84
85/**
86 * @brief sets the Name of the input-file
87 * @param fileName The new FileName to set to the IniParser
88 * IF fileName is NULL the new Name will be set to NULL too.
89 */
90void IniParser::setFileName(const char* fileName)
91{
92  if (this->fileName)
93    delete []this->fileName;
94  if (fileName)
95  {
96    this->fileName = new char[strlen(fileName)+1];
97    strcpy(this->fileName, fileName);
98  }
99  else
100    this->fileName = NULL;
101}
102
103
104/**
105 * @brief opens a file to parse
106 * @param fileName: path and name of the new file to parse
107 * @return true on success false otherwise;
108 *
109 * If there was already an opened file, the file will be closed,
110 * and the new one will be opened.
111 */
112bool IniParser::readFile(const char* fileName)
113{
114  FILE*    stream;           //< The stream we use to read the file.
115
116  if (this->fileName != NULL)
117    this->deleteSections();
118  if( fileName == NULL)
119    return false;
120
121  if( (stream = fopen (fileName, "r")) == NULL)
122  {
123    PRINTF(1)("IniParser could not open %s\n", fileName);
124    return false;
125  }
126  else
127  {
128    this->setFileName(fileName);
129
130    /////////////////////////////
131    // READING IN THE INI-FILE //
132    /////////////////////////////
133    char lineBuffer[PARSELINELENGHT];
134    char buffer[PARSELINELENGHT];
135    const char* lineBegin;
136    char* ptr;
137
138    while( fgets (lineBuffer, PARSELINELENGHT, stream))
139    {
140      lineBegin = lineBuffer;
141      // remove newline char, and \0-terminate
142      if( (ptr = strchr( lineBuffer, '\n')) != NULL)
143        *ptr = 0;
144      // cut up to the beginning of the line.
145      while((*lineBegin == ' ' || *lineBegin == '\t') && lineBegin < lineBuffer + strlen(lineBuffer))
146        ++lineBegin;
147      if (strlen(lineBegin) <= 1 || *lineBegin == '#' || *lineBegin == ';')
148        continue;//printf("empty Line\n");
149      // check for section identifyer
150      else if( sscanf (lineBegin, "[%s", buffer) == 1)
151      {
152        if( (ptr = strchr( buffer, ']')) != NULL)
153        {
154          *ptr = 0;
155          this->addSection(buffer);
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          continue;
165        }
166        if( ptr == lineBegin)
167          continue;
168        char* valueBegin = ptr+1;
169        while ((*valueBegin == ' ' || *valueBegin == '\t') && valueBegin <= lineBegin + strlen(lineBegin))
170          ++valueBegin;
171        char* valueEnd = valueBegin + strlen(valueBegin)-1;
172        while ((*valueEnd == ' ' || *valueEnd == '\t') && valueEnd >= valueBegin)
173          --valueEnd;
174        valueEnd[1] = '\0';
175        char* nameEnd = ptr-1;
176        while ((*nameEnd == ' ' || *nameEnd == '\t' ) && nameEnd >= lineBegin)
177          --nameEnd;
178        nameEnd[1] = '\0';
179
180        this->addVar(lineBegin, valueBegin);
181      }
182    }
183  }
184  this->currentSection = this->sections.begin();
185  if (!this->sections.empty())
186    this->currentEntry = (*this->currentSection).entries.begin();
187
188  fclose(stream);
189  return true;
190}
191
192
193/**
194 * @brief opens a file and writes to it
195 * @param fileName: path and name of the new file to write to
196 * @return true on success false otherwise
197 */
198bool IniParser::writeFile(const char* fileName)
199{
200  FILE*    stream;           //!< The stream we use to read the file.
201  if( fileName == NULL)
202    return false;
203
204  if( (stream = fopen (fileName, "w")) == NULL)
205  {
206    PRINTF(1)("IniParser could not open %s\n", fileName);
207    return false;
208  }
209  else
210  {
211    std::list<IniSection>::iterator section;
212    for (section = this->sections.begin(); section != this->sections.end(); section++)
213      {
214        fprintf(stream, "\n [%s]\n", (*section).name);
215       
216        std::list<IniEntry>::iterator entry;
217        for (entry = (*section).entries.begin(); entry != (*section).entries.end(); entry++)
218          fprintf(stream, "   %s = %s\n", (*entry).name, (*entry).value);
219      }
220  }
221  fclose(stream);
222}
223
224
225/**
226 * @brief adds a section to the list of Sections,
227 * if no Section list is availiable, it will create it
228 * @param sectionName the Name of the section to add
229 * @return true on success... there is only success or segfault :)
230 */
231bool IniParser::addSection(const char* sectionName)
232{
233  this->sections.push_back(IniSection());
234
235  this->sections.back().name = new char[strlen(sectionName)+1];
236  strcpy(this->sections.back().name, sectionName);
237
238  this->currentSection = --this->sections.end();
239  if (!this->sections.empty())
240    this->currentEntry = (*this->currentSection).entries.begin();
241  PRINTF(5)("Added Section %s\n", sectionName);
242  return true;
243}
244
245
246/**
247 * @brief Set the parsing cursor to the specified section
248 * @param sectionName: the name of the section to set the cursor to
249 * @return true on success or false if the section could not be found
250*/
251bool IniParser::getSection( const char* sectionName)
252{
253  std::list<IniSection>::iterator section;
254  for (section = this->sections.begin(); section != this->sections.end(); section++)
255    if (!strcmp((*section).name, sectionName))
256      {
257        this->currentSection = section;
258        this->currentEntry = (*this->currentSection).entries.begin();
259        return true;
260      }
261
262  return false;
263}
264
265
266/**
267 * @brief moves to the first section
268 */
269void IniParser::getFirstSection()
270{
271  this->currentSection = this->sections.begin();
272  if (!this->sections.empty())
273    this->currentEntry = (*this->currentSection).entries.begin();
274}
275
276
277/**
278 * @brief searches the next section
279 * @returns the name of the section if found, NULL otherwise
280 */
281const char* IniParser::nextSection()
282{
283  if (this->currentSection == this->sections.end())
284    return NULL;
285  else
286  {
287    this->currentSection++;
288  }
289    if (this->currentSection == this->sections.end())
290      return NULL;
291
292  if (this->currentSection != this->sections.end())
293    {
294      this->currentEntry = (*this->currentSection).entries.begin();
295      return this->currentSection->name;
296    }
297  else
298    return NULL;
299}
300
301
302/**
303 * @brief moves to the first Variable of the current Section
304 */
305void IniParser::getFirstVar()
306{
307  if (this->currentSection != this->sections.end())
308    this->currentEntry = (*this->currentSection).entries.begin();
309}
310
311
312/**
313 * @brief gets the next VarName = VarValue pair from the parsing stream
314 * @return true on success, false otherwise (in the latter case name and value will be NULL)
315 */
316bool IniParser::nextVar()
317{
318  if ( this->sections.empty() 
319       || this->currentSection == this->sections.end()
320       || this->currentEntry == (*this->currentSection).entries.end())
321    return false;
322
323  this->currentEntry++;
324
325  if (this->currentEntry == (*this->currentSection).entries.end())
326    return false;
327  else
328    return true;
329}
330
331
332/**
333 * @brief adds a new Entry to either the currentSection or the section called by sectionName
334 * @param entryName the Name of the Entry to add
335 * @param value the value to assign to this entry
336 * @param sectionName if NULL then this entry will be set to the currentSection
337 * otherwise to the section refered to by sectionName.
338 * If both are NULL no entry will be added
339 * @return true if everything is ok false on error
340 */
341bool IniParser::addVar(const char* entryName, const char* value, const char* sectionName)
342{
343  std::list<IniSection>::iterator section;
344
345  if (sectionName != NULL)
346  {
347    for (section = this->sections.begin(); section != this->sections.end(); section++)
348      if (!strcmp((*section).name, sectionName))
349        break;
350  }
351  else
352    section = this->currentSection;
353
354  if (section == this->sections.end())
355  {
356    PRINTF(2)("section '%s' not found for value '%s'\n", sectionName, entryName);
357    return false;
358  }
359  else
360  {
361    (*section).entries.push_back(IniEntry());
362    (*section).entries.back().name = new char[strlen (entryName)+1];
363    strcpy((*section).entries.back().name, entryName);
364    (*section).entries.back().value = new char[strlen(value)+1];
365    strcpy((*section).entries.back().value, value);
366    PRINTF(5)("Added Entry %s with Value '%s' to Section %s\n", entryName, value, (*section).name);
367    return true;
368  }
369}
370
371
372/**
373 * @brief directly acesses an entry in a section
374 * @param entryName: the name of the entry to find
375 * @param sectionName: the section where the entry is to be found
376 * @param defaultValue: what should be returned in case the entry cannot be found
377 * @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
378 *
379 *  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
380 * lead to unwanted behaviour.
381*/
382const char* IniParser::getVar(const char* entryName, const char* sectionName, const char* defaultValue) const
383{
384  if (fileName != NULL)
385  {
386    std::list<IniSection>::const_iterator section;
387    if (sectionName != NULL)
388      {
389
390        for (section = this->sections.begin(); section != this->sections.end(); section++)
391          {
392            if (!strcmp((*section).name, sectionName))
393              {
394                break;
395              }
396          }
397        PRINTF(2)("Section %s that should be containing %s not found.\n", sectionName, entryName);
398      }
399    else
400      section = this->currentSection;
401
402    std::list<IniEntry>::const_iterator entry;
403    for (entry = (*section).entries.begin(); entry != (*section).entries.end(); entry++)
404      if (!strcmp((*entry).name, entryName))
405        return (*entry).value;
406    PRINTF(2)("Entry '%s' in section '%s' not found.\n", entryName, sectionName);
407   
408  }
409  else
410    PRINTF(2)("%s not opened\n", fileName);
411
412  return defaultValue;
413
414}
415
416
417/**
418 * @returns the name of the Current selected Section
419 */
420const char* IniParser::getCurrentSection() const 
421{
422 return (this->currentSection!=NULL) ? 
423   this->currentSection->name :
424   NULL;
425 }
426
427
428/**
429 * @returns the current entries Name, or NULL if we havn't selected a Entry
430 */
431const char* IniParser::getCurrentName() const
432{
433 if (!this->sections.empty() &&
434     this->currentEntry != (*this->currentSection).entries.end())
435   return (*this->currentEntry).name;
436 else
437   return NULL;
438}
439
440/**
441 * @returns the current entries Value, or NULL if we havn't selected a Entry
442 */
443const char* IniParser::getCurrentValue() const 
444{
445  if (!this->sections.empty() 
446      && this->currentEntry != (*this->currentSection).entries.end())
447    return (*this->currentEntry).value;
448  else
449    return NULL; 
450}
451
452
453/**
454 * @brief output the whole tree in a nice and easy way.
455 */
456void IniParser::debug() const
457{
458  PRINTF(0)("Iniparser %s - debug\n", this->fileName);
459  if (this->fileName != NULL)
460  {
461    std::list<IniSection>::const_iterator section;
462    for (section = this->sections.begin(); section != this->sections.end(); section++)
463    {
464      PRINTF(0)(" [%s]\n", (*section).name);
465
466      std::list<IniEntry>::const_iterator entry;
467      for (entry = (*section).entries.begin(); entry != (*section).entries.end(); entry++)
468        PRINTF(0)("   '%s' -> '%s'\n", (*entry).name, (*entry).value);
469    }
470  }
471  else
472    PRINTF(1)("no opened ini-file.\n");
473}
Note: See TracBrowser for help on using the repository browser.