Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk: ini-parser in own subdir now (also moved tiXml-lib to lib/parser

File size: 12.9 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
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
120  if (this->fileName != NULL)
121    this->deleteSections();
122  if( fileName == NULL)
123    return false;
124
125  if( (stream = fopen (fileName, "r")) == NULL)
126  {
127    PRINTF(1)("IniParser could not open %s\n", fileName);
128    return false;
129  }
130  else
131  {
132    this->setFileName(fileName);
133
134    /////////////////////////////
135    // READING IN THE INI-FILE //
136    /////////////////////////////
137    char lineBuffer[PARSELINELENGHT];
138    char buffer[PARSELINELENGHT];
139    const char* lineBegin;
140    char* ptr;
141
142    while( fgets (lineBuffer, PARSELINELENGHT, stream))
143    {
144      lineBegin = lineBuffer;
145      // remove newline char, and \0-terminate
146      if( (ptr = strchr( lineBuffer, '\n')) != NULL)
147        *ptr = 0;
148      // cut up to the beginning of the line.
149      while((*lineBegin == ' ' || *lineBegin == '\t') && lineBegin < lineBuffer + strlen(lineBuffer))
150        ++lineBegin;
151      if (strlen(lineBegin) <= 1 || *lineBegin == '#' || *lineBegin == ';')
152        continue;//printf("empty Line\n");
153      // check for section identifyer
154      else if( sscanf (lineBegin, "[%s", buffer) == 1)
155      {
156        if( (ptr = strchr( buffer, ']')) != NULL)
157        {
158          *ptr = 0;
159          this->addSection(buffer);
160        }
161      }
162      // check for Entry identifier (Entry = Value)
163      else if( (ptr = strchr( lineBegin, '=')) != NULL)
164      {
165        if (currentSection == NULL)
166        {
167          PRINTF(2)("Not in a Section yet for %s\n", lineBegin);
168          continue;
169        }
170        if( ptr == lineBegin)
171          continue;
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      }
186    }
187  }
188  this->currentSection = this->sections.begin();
189  if (!this->sections.empty())
190    this->currentEntry = (*this->currentSection).entries.begin();
191
192  fclose(stream);
193  return true;
194}
195
196
197/**
198 * @brief opens a file and writes to it
199 * @param fileName: path and name of the new file to write to
200 * @return true on success false otherwise
201 */
202bool IniParser::writeFile(const char* fileName) const
203{
204  FILE*    stream;           //!< The stream we use to read the file.
205  if( fileName == NULL)
206    return false;
207
208  if( (stream = fopen (fileName, "w")) == NULL)
209  {
210    PRINTF(1)("IniParser could not open %s\n", fileName);
211    return false;
212  }
213  else
214  {
215    std::list<IniSection>::const_iterator section;
216    for (section = this->sections.begin(); section != this->sections.end(); section++)
217      {
218        fprintf(stream, "\n [%s]\n", (*section).name);
219
220        std::list<IniEntry>::const_iterator entry;
221        for (entry = (*section).entries.begin(); entry != (*section).entries.end(); entry++)
222          fprintf(stream, "   %s = %s\n", (*entry).name, (*entry).value);
223      }
224  }
225  fclose(stream);
226}
227
228
229/**
230 * @brief adds a section to the list of Sections,
231 * if no Section list is availiable, it will create it
232 * @param sectionName the Name of the section to add
233 * @return true on success... there is only success or segfault :)
234 */
235bool IniParser::addSection(const char* sectionName)
236{
237  this->sections.push_back(IniSection());
238
239  this->sections.back().name = new char[strlen(sectionName)+1];
240  strcpy(this->sections.back().name, sectionName);
241
242  this->currentSection = --this->sections.end();
243  if (!this->sections.empty())
244      this->currentEntry = (*this->currentSection).entries.begin();
245  PRINTF(5)("Added Section %s\n", sectionName);
246  return true;
247}
248
249
250/**
251 * @brief Set the parsing cursor to the specified section
252 * @param sectionName: the name of the section to set the cursor to
253 * @return true on success or false if the section could not be found
254 */
255bool IniParser::getSection(const char* sectionName)
256{
257  std::list<IniSection>::iterator section;
258  for (section = this->sections.begin(); section != this->sections.end(); section++)
259    if (!strcmp((*section).name, sectionName))
260      {
261        this->currentSection = section;
262        this->currentEntry = (*this->currentSection).entries.begin();
263        return true;
264      }
265  return false;
266}
267
268
269/**
270 * @brief moves to the first section
271 */
272void IniParser::firstSection()
273{
274  this->currentSection = this->sections.begin();
275  if (!this->sections.empty())
276    this->currentEntry = (*this->currentSection).entries.begin();
277}
278
279
280/**
281 * @brief searches the next section
282 * @returns the name of the section if found, NULL otherwise
283 */
284const char* IniParser::nextSection()
285{
286  if (this->currentSection == this->sections.end())
287    return NULL;
288
289  this->currentSection++;
290
291  if (this->currentSection != this->sections.end())
292    {
293      this->currentEntry = (*this->currentSection).entries.begin();
294      return this->currentSection->name;
295    }
296  else
297    return NULL;
298}
299
300
301/**
302 * @brief moves to the first Variable of the current Section
303 */
304void IniParser::firstVar()
305{
306  if (!this->sections.empty() &&
307      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  if (section == this->sections.end())
354    return false;
355
356  if (section == this->sections.end())
357  {
358    PRINTF(2)("section '%s' not found for value '%s'\n", sectionName, entryName);
359    return false;
360  }
361  else
362  {
363    (*section).entries.push_back(IniEntry());
364    (*section).entries.back().name = new char[strlen(entryName)+1];
365    strcpy((*section).entries.back().name, entryName);
366    (*section).entries.back().value = new char[strlen(value)+1];
367    strcpy((*section).entries.back().value, value);
368    PRINTF(5)("Added Entry %s with Value '%s' to Section %s\n",
369              (*section).entries.back().name,
370              (*section).entries.back().value,
371              (*section).name);
372    return true;
373  }
374}
375
376
377/**
378 * @brief directly acesses an entry in a section
379 * @param entryName: the name of the entry to find
380 * @param sectionName: the section where the entry is to be found
381 * @param defaultValue: what should be returned in case the entry cannot be found
382 * @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
383 *
384 *  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
385 * lead to unwanted behaviour.
386*/
387const char* IniParser::getVar(const char* entryName, const char* sectionName, const char* defaultValue) const
388{
389  if (fileName != NULL)
390  {
391    std::list<IniSection>::const_iterator section;
392    if (sectionName != NULL)
393      {
394        for (section = this->sections.begin(); section != this->sections.end(); section++)
395          {
396            if (!strcmp((*section).name, sectionName))
397              {
398                break;
399              }
400          }
401      }
402    else
403      section = this->currentSection;
404
405   if (section == this->sections.end())
406     {
407       PRINTF(2)("Section %s that should be containing %s not found.\n", sectionName, entryName);
408       return (defaultValue);
409     }
410
411    std::list<IniEntry>::const_iterator entry;
412    for (entry = (*section).entries.begin(); entry != (*section).entries.end(); entry++)
413      if (!strcmp((*entry).name, entryName))
414        return (*entry).value;
415    PRINTF(2)("Entry '%s' in section '%s' not found.\n", entryName, sectionName);
416
417  }
418  else
419    PRINTF(2)("%s not opened\n", fileName);
420
421  return defaultValue;
422
423}
424
425
426/**
427 * @returns the name of the Current selected Section
428 */
429const char* IniParser::getCurrentSection() const
430{
431  if (!this->sections.empty() &&
432      this->currentSection != this->sections.end())
433    return this->currentSection->name;
434  else
435    return NULL;
436 }
437
438
439/**
440 * @returns the current entries Name, or NULL if we havn't selected a Entry
441 */
442const char* IniParser::getCurrentName() const
443{
444 if (!this->sections.empty() &&
445     this->currentSection != this->sections.end() &&
446     this->currentEntry != (*this->currentSection).entries.end())
447   return (*this->currentEntry).name;
448 else
449   return NULL;
450}
451
452/**
453 * @returns the current entries Value, or NULL if we havn't selected a Entry
454 */
455const char* IniParser::getCurrentValue() const
456{
457  if (!this->sections.empty() &&
458      this->currentSection != this->sections.end() &&
459      this->currentEntry != (*this->currentSection).entries.end())
460    return (*this->currentEntry).value;
461  else
462    return NULL;
463}
464
465
466/**
467 * @brief output the whole tree in a nice and easy way.
468 */
469void IniParser::debug() const
470{
471  PRINTF(0)("Iniparser %s - debug\n", this->fileName);
472  if (this->fileName != NULL)
473  {
474    std::list<IniSection>::const_iterator section;
475    for (section = this->sections.begin(); section != this->sections.end(); section++)
476    {
477      PRINTF(0)(" [%s]\n", (*section).name);
478
479      std::list<IniEntry>::const_iterator entry;
480      for (entry = (*section).entries.begin(); entry != (*section).entries.end(); entry++)
481        PRINTF(0)("   '%s' -> '%s'\n", (*entry).name, (*entry).value);
482    }
483  }
484  else
485    PRINTF(1)("no opened ini-file.\n");
486}
487
488
Note: See TracBrowser for help on using the repository browser.