LLOOP Index | GSP Language | GSP Library | Framework Classes | Component Classes

IniFile.cpp

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(&section);	
      else
	ini.setSectionList(&section);
    }
  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*)&section))
	{
	  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