/* orxonox - the future of 3D-vertical-scrollers Copyright (C) 2004 orx This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. ### File Specific: main-programmer: Benjamin Grauer co-programmer: Christian Meyer 2005-08-14: complete reimplementation: now the File is parsed at the initialisation, and informations is gathered there. */ #include "ini_parser.h" #include "list.h" #include "stdlibincl.h" #include "debug.h" using namespace std; /** * constructs an IniParser using a file * @param filename: the path and name of the file to parse */ IniParser::IniParser (const char* fileName) { this->setClassID(CL_INI_PARSER, "IniParser"); this->setName(fileName); this->currentEntry = NULL; this->currentSection = NULL; this->sections = NULL; if (fileName != NULL) this->openFile(fileName); } /** * removes the IniParser from memory */ IniParser::~IniParser () { deleteSections(); } /** * removes all the sections. This is like delete, but even cooler :) */ void IniParser::deleteSections() { if (this->sections) { tIterator* sectionIt = this->sections->getIterator(); IniSection* sectionEnum = sectionIt->nextElement(); while (sectionEnum) { tIterator* entryIt = sectionEnum->entries->getIterator(); IniEntry* entryEnum = entryIt->nextElement(); while (entryEnum) { delete []entryEnum->name; delete []entryEnum->value; delete entryEnum; entryEnum = entryIt->nextElement(); } delete entryIt; delete []sectionEnum->name; delete sectionEnum->entries; delete sectionEnum; sectionEnum = sectionIt->nextElement(); } delete sectionIt; } delete this->sections; this->currentEntry = NULL; this->currentSection = NULL; this->sections = NULL; } /** * opens another file to parse * @param filename: path and name of the new file to parse * @return true on success false otherwise; */ bool IniParser::openFile(const char* fileName) { FILE* stream; //!< The stream we use to read the file. if (sections != NULL) deleteSections(); if( fileName == NULL) return false; if( (stream = fopen (fileName, "r")) == NULL) { PRINTF(1)("IniParser could not open %s\n", fileName); return false; } else { this->currentEntry = NULL; this->currentSection = NULL; this->sections = new tList; ///////////////////////////// // READING IN THE INI-FILE // ///////////////////////////// char lineBuffer[PARSELINELENGHT]; char buffer[PARSELINELENGHT]; char* ptr; rewind (stream); while( !feof( stream)) { // get next line fgets (lineBuffer, PARSELINELENGHT, stream); // remove newline char, and \0-terminate if( (ptr = strchr( lineBuffer, '\n')) != NULL) *ptr = 0; // check for section identifyer if( sscanf (lineBuffer, "[%s", buffer) == 1) { if( (ptr = strchr( buffer, ']')) != NULL) { *ptr = 0; IniSection* newSection = new IniSection; newSection->name = new char[strlen(buffer)+1]; strcpy(newSection->name, buffer); newSection->entries = new tList; this->sections->add(newSection); this->currentSection = newSection; } } else if( (ptr = strchr( lineBuffer, '=')) != NULL) { if (currentSection == NULL) { PRINTF(2)("Not in a Section yet for %s\n", lineBuffer); continue; } if( ptr == lineBuffer) continue; IniEntry* newEntry = new IniEntry; char* valueBegin = ptr+1; while ((*valueBegin == ' ' || *valueBegin == '\t') && valueBegin <= lineBuffer + strlen(lineBuffer)) ++valueBegin; newEntry->value = new char[strlen(valueBegin)+1]; strcpy(newEntry->value, valueBegin); char* nameEnd = ptr-1, *nameBegin = lineBuffer; while ((*nameBegin == ' ' || *nameBegin == '\t') && nameBegin < ptr) ++nameBegin; while ((*nameEnd == ' ' || *nameEnd == '\t' ) && nameEnd >= nameBegin) --nameEnd; nameEnd[1] = '\0'; newEntry->name = new char[strlen (nameBegin)]; strcpy(newEntry->name, nameBegin); this->currentSection->entries->add(newEntry); } } } fclose(stream); return true; } /** * set the parsing cursor to the specified section * @param sectionName: the name of the section to set the cursor to * @return true on success or false if the section could not be found */ bool IniParser::getSection( const char* sectionName) { tIterator* sectionIt = this->sections->getIterator(); IniSection* sectionEnum = sectionIt->nextElement(); while (sectionEnum) { if (!strcmp(sectionEnum->name, sectionName)) { this->currentSection = sectionEnum; this->currentEntry = NULL; delete sectionIt; return true; } sectionEnum = sectionIt->nextElement(); } delete sectionIt; return false; } /** * moves to the first section */ void IniParser::getFirstSection() { if (this->sections) this->currentSection = this->sections->firstElement(); else this->currentSection = NULL; this->currentEntry = NULL; } /** * searches the next section * @returns the name of the section if found, NULL otherwise */ const char* IniParser::nextSection() { if (this->currentSection == NULL) return NULL; else { if (this->sections) { if (this->currentSection == this->sections->lastElement()) this->currentSection = NULL; else this->currentSection = this->sections->nextElement(this->currentSection); } } if (this->currentSection != NULL) return this->currentSection->name; else return NULL; } /** * moves to the first Variable of the current Section */ void IniParser::getFirstVar() { if (this->currentSection) this->currentEntry = this->currentSection->entries->firstElement(); else this->currentEntry = NULL; } /** * gets the next VarName=VarValue pair from the parsing stream * @return true on success, false otherwise (in the latter case name and value will be NULL) */ bool IniParser::nextVar() { if (this->currentSection == NULL || this->currentEntry == NULL || this->currentEntry == this->currentSection->entries->lastElement()) { this->currentEntry = NULL; return false; } this->currentEntry = this->currentSection->entries->nextElement(this->currentEntry); if (this->currentEntry == NULL) return false; else return true; } /** * directly acesses an entry in a section * @param entryName: the name of the entry to find * @param sectionName: the section where the entry is to be found * @param defaultValue: what should be returned in case the entry cannot be found * @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 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 lead to unwanted behaviour. */ const char* IniParser::getVar(const char* entryName, const char* sectionName, const char* defaultValue) const { if (this->sections) { tIterator* sectionIt = this->sections->getIterator(); IniSection* sectionEnum = sectionIt->nextElement(); while (sectionEnum) { if (!strcmp(sectionEnum->name, sectionName)) { tIterator* entryIt = sectionEnum->entries->getIterator(); IniEntry* entryEnum = entryIt->nextElement(); while (entryEnum) { if (!strcmp(entryEnum->name, entryName)) { delete entryIt; delete sectionIt; return entryEnum->value; } entryEnum = entryIt->nextElement(); } delete entryIt; PRINTF(2)("Entry %s in section %s not found.\n", entryName, sectionName); break; } sectionEnum = sectionIt->nextElement(); } delete sectionIt; PRINTF(2)("Section %s that should be containing %s not found.\n", sectionName, entryName); } else PRINTF(1)("%s not opened\n", this->getName()); return defaultValue; } void IniParser::debug() const { PRINTF(0)("Iniparser %s - debug\n", this->getName()); if (this->sections) { tIterator* sectionIt = this->sections->getIterator(); IniSection* sectionEnum = sectionIt->nextElement(); while (sectionEnum) { PRINTF(0)(" [%s]\n", sectionEnum->name); tIterator* entryIt = sectionEnum->entries->getIterator(); IniEntry* entryEnum = entryIt->nextElement(); while (entryEnum) { PRINTF(0)(" :%s: -> '%s'\n", entryEnum->name, entryEnum->value); entryEnum = entryIt->nextElement(); } delete entryIt; sectionEnum = sectionIt->nextElement(); } delete sectionIt; } else PRINTF(1)("%s not opened\n", this->getName()); }