| LLOOP Index | GSP Language | GSP Library | Framework Classes | Component Classes |
This is the verbatim text of the file "IniFile.cpp" part of the LLOOP package. The copyright remains with Michel MEHL. All rights reserved.
#include "IniFile.h"
#include "ini__ini_headers.h" // All includes - generated
#include "ini__Parser.h" // All includes - generated
using namespace universal;
using namespace std;
using namespace ini;
/**
* Constructor.
*
* Reads the data from the passed ini file. If the creation is requested,
* the file is created and any previous file is overwritten.
*
* bCreate is optional and tells whether to force the file creation,
* overwriting any previous file. By default, the file is not created.
*/
IniFile::IniFile(const universal::String& c_sFilename, bool bCreate)
: m_pSIniFile(NULL), m_sFilename(c_sFilename)
{
if (bCreate)
{
ofstream ofs(c_sFilename);
}
m_pParser = new ini::Parser(c_sFilename);
m_pParser->run();
if (!m_pParser->fail())
{
m_pSIniFile = &m_pParser->root();
}
}
/**
* Destructor.
*
* Destroys the parser and the ini file data object.
*/
IniFile::~IniFile()
{
ini::SIniFile::factory().destroy(m_pSIniFile);
delete m_pParser;
m_pParser = NULL;
}
/**
* Returns the ini file name.
*/
universal::String IniFile::filename() const { return m_sFilename; }
/**
* Returns the parsed object containing the data of the ini file.
*/
SIniFile* IniFile::data() const { return m_pSIniFile; }
/**
* Tells whether the ini file could be read or created successfully or not.
*/
bool IniFile::fail() const { return m_pParser->fail(); }
/**
* Allows to get an error message if fail() returns true.
*/
void IniFile::getError(std::ostream& os) const
{
ini::Parser& parser = *m_pParser;
if (parser.fail())
{
if (parser.syntaxerror())
parser.outputFailureContext(os, 4);
parser.outputFailureMessage(os);
os << endl;
}
}
/**
* Save the ini file data into the passed file name. If the file name is
* empty, the data are written to the initial input file and its content
* is then overwritten.
*/
bool IniFile::save(const String& c_sFilename) const
{
if (fail())
return false;
ini::Parser& parser = *m_pParser;
universal::String s;
if (c_sFilename.empty())
s = filename();
else
s = c_sFilename;
ofstream os(s.str());
if (os.is_open())
return parser.root().expand(os);
else
return false;
}
/**
* Returns a reference to the data value for the matching
* section and data names. This reference can be used to either
* read the value or to set it.
* If the data does not exist, an empty value is returned.
* Changing this latter has no effect.
*/
universal::String& IniFile::get(const universal::String& sectionName,
const universal::String& dataName) const
{
static universal::String sEmpty;
sEmpty = "";
ini::SectionList& section = getSection(sectionName);
if (section.parsed())
{
ini::DataList* pData = section.getDataList();
while (pData && !pData->equals(dataName))
pData = pData->getDataList();
if (pData)
return *pData->getBlockToken();
}
return sEmpty;
}
/**
* Returns a reference to the section object for the matching
* name. If the section does not exist and invalid object
* is returned.
* An invalid section object is an object which wasn't
* build during the parsing and therefore calling .parsed()
* on it returns false.
*/
ini::SectionList& IniFile::getSection(const universal::String& sectionName) const
{
static ini::SectionList invalidSection;
if (!fail())
{
ini::SIniFile& ini = *m_pSIniFile;
ini::SectionList* pSection = ini.getSectionList();
while (pSection && !pSection->equals(sectionName))
pSection = pSection->getSectionList();
if (pSection)
return (*pSection);
else
return invalidSection;
}
else
{
return invalidSection;
}
}
/**
* Returns a reference to the name of the uIndex'th section.
*/
universal::String& IniFile::get(unsigned long uIndex) const
{
static universal::String sEmpty;
if (!fail())
{
ini::SIniFile& ini = *m_pSIniFile;
ini::SectionList* pSection = ini.getSectionList();
unsigned long uCurrent = 0;
while (pSection && (uCurrent != uIndex))
{
pSection = pSection->getSectionList();
uCurrent++;
}
if (pSection)
return (*pSection).BlockTokenRef();
else
return sEmpty;
}
return sEmpty;
}
/**
* Inserts a data into a section. If the section does not exist, it is
* created.
*/
bool IniFile::insert(const universal::String& sectionName,
const universal::String& dataName,
const universal::String& dataValue)
{
using namespace gsp;
/* The ini file must have been parsed successfully before
*/
if (fail())
return false;
ini::SIniFile& ini = *m_pSIniFile;
/* Try to get the value of the data. If the returned string object
* doesn't narrow to a DataList object, it means
* the matching datalist doesn't exist and can be created.
* Otherwise it means there is already such data defined and
* a negative answer is returned.
*/
universal::String& value = get(sectionName, dataName);
if (dynamic_cast<BlockToken*>(&value) != NULL)
return false;
ini::SectionList& srchSection = getSection(sectionName);
if (!srchSection.parsed())
{
/* If the section has to be created, we must append it to the
* actual list of sections.
*/
ini::SectionList& section = *new SectionList();
// Search for the last section
ini::SectionList* pSection = ini.getSectionList();
ini::SectionList* pPrevSection = pSection;
while (pSection)
{
pPrevSection = pSection;
pSection = pSection->getSectionList();
}
/* Trick: To complete the objects tree obtained through the initial
* parsing, we make the new section parse a string from which it
* should initialize and set up. The obtained parsed object is then
* simply appended to the other sections.
* Note: We add a new line at the beginning of the section to make
* it more visibly distinct from the previous section.
*/
strstream sSection;
if (pPrevSection) sSection << "\n";
sSection << "[" << sectionName << "]\n" << dataName << " = " << dataValue << "\n";
// It is advised to put the end-of-string char but it is not mandatory!
// sSection << ends;
if (!section.parse(sSection, pPrevSection ? dynamic_cast<Symbol*>(pPrevSection) : dynamic_cast<Symbol*>(&ini)))
{
return false;
}
/* Append the new section to the list of the existing sections
* If it is the first section we set it for the main ini object
*/
if (pPrevSection)
pPrevSection->setSectionList(§ion);
else
ini.setSectionList(§ion);
}
else
{
/* Create and append the data to the list of data of the
* existing section.
*/
ini::SectionList& section = srchSection;
// Look for the last data
ini::DataList* pData = section.getDataList();
ini::DataList* pPrevData = pData;
while (pData)
{
pPrevData = pData;
pData = pData->getDataList();
}
/* Trick: To complete the objects tree obtained through the initial
* parsing, we make the new data parse a string from which it
* should initialize and set up. The obtained parsed object is then
* simply appended to the other data.
*/
ini::DataList& data = *new DataList();
strstream sData;
sData << dataName << " = " << dataValue << "\n";
// It is advised to put the end-of-string char but it's not mandatory!
// sData << ends;
if (!data.parse(sData, pPrevData ? (Symbol*)pPrevData : (Symbol*)§ion))
{
return false;
}
// If it is the first section we set it for the main ini object
if (pPrevData)
pPrevData->setDataList(&data);
else
section.setDataList(&data);
}
return true;
}
This file is part of the LLOOP Reversible Object-Oriented Parser Generator. Copyright (c) 2005-2006 Michel MEHL, France. All rights reserved. LLOOP is distributed by the company ERSA SaRL.
| Copyright (c) 2005-2006 Michel MEHL, Haguenau, France |
| LLOOP version 1.1 |