bug (were not deleted from file) in wxFileConfig
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@183
c3d73ce0-8a6f-49c7-b76d-
6d57e0e08775
virtual bool GetFirstEntry(wxString& str, long& lIndex) = 0;
virtual bool GetNextEntry (wxString& str, long& lIndex) = 0;
virtual bool GetFirstEntry(wxString& str, long& lIndex) = 0;
virtual bool GetNextEntry (wxString& str, long& lIndex) = 0;
+ // tests of existence
+ // returns TRUE if the group by this name exists
+ virtual bool HasGroup(const wxString& strName) const = 0;
+ // same as above, but for an entry
+ virtual bool HasEntry(const wxString& strName) const = 0;
+ // returns TRUE if either a group or an entry with a given name exist
+ bool Exists(const wxString& strName) const
+ { return HasGroup(strName) || HasEntry(strName); }
+
// key access: returns TRUE if value was really read, FALSE if default used
// (and if the key is not found the default value is returned.)
// read a string from the key
// key access: returns TRUE if value was really read, FALSE if default used
// (and if the key is not found the default value is returned.)
// read a string from the key
virtual const char *Read(const char *szKey,
const char *szDefault = NULL) const;
// the same for longs
virtual const char *Read(const char *szKey,
const char *szDefault = NULL) const;
// the same for longs
- long Read(const char *szKey, long lDefault) const
+ virtual long Read(const char *szKey, long lDefault) const
{ long l; Read(&l, szKey, lDefault); return l; }
// and another version: returns true if default value is returned
virtual bool Read(long *pl, const char *szKey, long lDefault = 0) const = 0;
{ long l; Read(&l, szKey, lDefault); return l; }
// and another version: returns true if default value is returned
virtual bool Read(long *pl, const char *szKey, long lDefault = 0) const = 0;
// ----------------------------------------------------------------------------
/*
// ----------------------------------------------------------------------------
/*
- wxFileConfig derives from base Config and implements file based config class,
+ wxFileConfig derives from base Config and implements file based config class,
i.e. it uses ASCII disk files to store the information. These files are
i.e. it uses ASCII disk files to store the information. These files are
- alternatively called INI, .conf or .rc in the documentation. They are
+ alternatively called INI, .conf or .rc in the documentation. They are
organized in groups or sections, which can nest (i.e. a group contains
subgroups, which contain their own subgroups &c). Each group has some
organized in groups or sections, which can nest (i.e. a group contains
subgroups, which contain their own subgroups &c). Each group has some
- number of entries, which are "key = value" pairs. More precisely, the format
+ number of entries, which are "key = value" pairs. More precisely, the format
is:
# comments are allowed after either ';' or '#' (Win/UNIX standard)
is:
# comments are allowed after either ';' or '#' (Win/UNIX standard)
virtual bool GetFirstEntry(wxString& str, long& lIndex);
virtual bool GetNextEntry (wxString& str, long& lIndex);
virtual bool GetFirstEntry(wxString& str, long& lIndex);
virtual bool GetNextEntry (wxString& str, long& lIndex);
+ virtual bool HasGroup(const wxString& strName) const;
+ virtual bool HasEntry(const wxString& strName) const;
+
virtual bool Read(wxString *pstr, const char *szKey,
const char *szDefault = 0) const;
virtual const char *Read(const char *szKey,
const char *szDefault = 0) const;
virtual bool Read(long *pl, const char *szKey, long lDefault) const;
virtual bool Read(wxString *pstr, const char *szKey,
const char *szDefault = 0) const;
virtual const char *Read(const char *szKey,
const char *szDefault = 0) const;
virtual bool Read(long *pl, const char *szKey, long lDefault) const;
+ virtual long Read(const char *szKey, long lDefault) const
+ { return wxConfig::Read(szKey, lDefault); }
virtual bool Write(const char *szKey, const char *szValue);
virtual bool Write(const char *szKey, long lValue);
virtual bool Flush(bool bCurrentOnly = FALSE);
virtual bool Write(const char *szKey, const char *szValue);
virtual bool Write(const char *szKey, long lValue);
virtual bool Flush(bool bCurrentOnly = FALSE);
- LineList(const wxString& str, LineList *pNext = NULL) : m_strLine(str)
- { SetNext(pNext); }
-
- //
+ LineList(const wxString& str, LineList *pNext = NULL) : m_strLine(str)
+ { SetNext(pNext); SetPrev(NULL); }
+
+ //
LineList *Next() const { return m_pNext; }
LineList *Next() const { return m_pNext; }
+ LineList *Prev() const { return m_pPrev; }
void SetNext(LineList *pNext) { m_pNext = pNext; }
void SetNext(LineList *pNext) { m_pNext = pNext; }
+ void SetPrev(LineList *pPrev) { m_pPrev = pPrev; }
//
void SetText(const wxString& str) { m_strLine = str; }
//
void SetText(const wxString& str) { m_strLine = str; }
private:
wxString m_strLine; // line contents
private:
wxString m_strLine; // line contents
- LineList *m_pNext; // next node
+ LineList *m_pNext, // next node
+ *m_pPrev; // previous one
// functions to work with this list
LineList *LineListAppend(const wxString& str);
// functions to work with this list
LineList *LineListAppend(const wxString& str);
- LineList *LineListInsert(const wxString& str,
- LineList *pLine); // NULL => Append()
+ LineList *LineListInsert(const wxString& str,
+ LineList *pLine); // NULL => Prepend()
+ void LineListRemove(LineList *pLine);
bool LineListIsEmpty();
private:
bool LineListIsEmpty();
private:
// will also recursively set parent's dirty flag
void SetDirty();
void SetLine(LineList *pLine);
// will also recursively set parent's dirty flag
void SetDirty();
void SetLine(LineList *pLine);
// the new entries in this subgroup will be inserted after the last subgroup
// or, if there is none, after the last entry
void SetLastEntry(ConfigEntry *pLastEntry) { m_pLastEntry = pLastEntry; }
// the new entries in this subgroup will be inserted after the last subgroup
// or, if there is none, after the last entry
void SetLastEntry(ConfigEntry *pLastEntry) { m_pLastEntry = pLastEntry; }
// Name: fileconf.cpp
// Purpose: implementation of wxFileConfig derivation of wxConfig
// Author: Vadim Zeitlin
// Name: fileconf.cpp
// Purpose: implementation of wxFileConfig derivation of wxConfig
// Author: Vadim Zeitlin
// Created: 07.04.98 (adapted from appconf.cpp)
// RCS-ID: $Id$
// Copyright: (c) 1997 Karsten Ballüder & Vadim Zeitlin
// Created: 07.04.98 (adapted from appconf.cpp)
// RCS-ID: $Id$
// Copyright: (c) 1997 Karsten Ballüder & Vadim Zeitlin
// is 'c' a valid character in group name?
// NB: APPCONF_IMMUTABLE_PREFIX and APPCONF_PATH_SEPARATOR must be valid chars,
// but _not_ ']' (group name delimiter)
// is 'c' a valid character in group name?
// NB: APPCONF_IMMUTABLE_PREFIX and APPCONF_PATH_SEPARATOR must be valid chars,
// but _not_ ']' (group name delimiter)
-inline bool IsValid(char c) { return isalnum(c) || strchr("_/-!.*%", c); }
+inline bool IsValid(char c) { return isalnum(c) || strchr("@_/-!.*%", c); }
// filter strings
static wxString FilterIn(const wxString& str);
// filter strings
static wxString FilterIn(const wxString& str);
void wxFileConfig::Init()
{
void wxFileConfig::Init()
{
m_pRootGroup = new ConfigGroup(NULL, "", this);
m_linesHead =
m_pRootGroup = new ConfigGroup(NULL, "", this);
m_linesHead =
{
const char *pStart;
const char *pEnd;
{
const char *pStart;
const char *pEnd;
for ( uint n = 0; n < file.GetLineCount(); n++ ) {
// add the line to linked list
if ( bLocal )
for ( uint n = 0; n < file.GetLineCount(); n++ ) {
// add the line to linked list
if ( bLocal )
case ';':
bCont = FALSE;
break;
case ';':
bCont = FALSE;
break;
case ' ':
case '\t':
// ignore whitespace ('\n' impossible here)
break;
case ' ':
case '\t':
// ignore whitespace ('\n' impossible here)
break;
default:
wxLogWarning("file '%s', line %d: '%s' ignored after group header.",
file.GetName(), n + 1, pEnd);
default:
wxLogWarning("file '%s', line %d: '%s' ignored after group header.",
file.GetName(), n + 1, pEnd);
wxString strKey(pStart, pEnd);
// skip whitespace
wxString strKey(pStart, pEnd);
// skip whitespace
- while ( isspace(*pEnd) )
+ while ( isspace(*pEnd) )
pEnd++;
if ( *pEnd++ != '=' ) {
pEnd++;
if ( *pEnd++ != '=' ) {
// (c) key from global file now found in local one
// which is exactly what we want.
else if ( !bLocal || pEntry->IsLocal() ) {
// (c) key from global file now found in local one
// which is exactly what we want.
else if ( !bLocal || pEntry->IsLocal() ) {
- wxLogWarning("file '%s', line %d: key '%s' was first found at line %d.",
+ wxLogWarning("file '%s', line %d: key '%s' was first found at line %d.",
file.GetName(), n + 1, strKey.c_str(), pEntry->Line());
if ( bLocal )
file.GetName(), n + 1, strKey.c_str(), pEntry->Line());
if ( bLocal )
- while ( isspace(*pEnd) )
+ while ( isspace(*pEnd) )
pEnd++;
wxString strValue;
pEnd++;
wxString strValue;
- if ( strPath.IsEmpty() )
+ if ( strPath.IsEmpty() ) {
+ SetRootPath();
if ( strPath[0] == APPCONF_PATH_SEPARATOR ) {
// absolute path
if ( strPath[0] == APPCONF_PATH_SEPARATOR ) {
// absolute path
+// ----------------------------------------------------------------------------
+// tests for existence
+// ----------------------------------------------------------------------------
+
+bool wxFileConfig::HasGroup(const wxString& strName) const
+{
+ PathChanger path(this, strName);
+
+ ConfigGroup *pGroup = m_pCurrentGroup->FindSubgroup(path.Name());
+ return pGroup != NULL;
+}
+
+bool wxFileConfig::HasEntry(const wxString& strName) const
+{
+ PathChanger path(this, strName);
+
+ ConfigEntry *pEntry = m_pCurrentGroup->FindEntry(path.Name());
+ return pEntry != NULL;
+}
+
// ----------------------------------------------------------------------------
// read/write values
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// read/write values
// ----------------------------------------------------------------------------
else {
// adjust pointers
m_linesTail->SetNext(pLine);
else {
// adjust pointers
m_linesTail->SetNext(pLine);
+ pLine->SetPrev(m_linesTail);
}
// insert a new line after the given one or in the very beginning if !pLine
}
// insert a new line after the given one or in the very beginning if !pLine
-wxFileConfig::LineList *wxFileConfig::LineListInsert(const wxString& str,
+wxFileConfig::LineList *wxFileConfig::LineListInsert(const wxString& str,
LineList *pLine)
{
if ( pLine == m_linesTail )
return LineListAppend(str);
LineList *pLine)
{
if ( pLine == m_linesTail )
return LineListAppend(str);
+ LineList *pNewLine = new LineList(str);
- pNewLine = new LineList(str, m_linesHead);
+ // prepend to the list
+ pNewLine->SetNext(m_linesHead);
+ m_linesHead->SetPrev(pNewLine);
m_linesHead = pNewLine;
}
else {
m_linesHead = pNewLine;
}
else {
- pNewLine = new LineList(str, pLine->Next());
+ // insert before pLine
+ LineList *pNext = pLine->Next();
+ pNewLine->SetNext(pNext);
+ pNewLine->SetPrev(pLine);
+ pNext->SetPrev(pNewLine);
pLine->SetNext(pNewLine);
}
return pNewLine;
}
pLine->SetNext(pNewLine);
}
return pNewLine;
}
+void wxFileConfig::LineListRemove(LineList *pLine)
+{
+ LineList *pPrev = pLine->Prev(),
+ *pNext = pLine->Next();
+ if ( pPrev == NULL ) {
+ // deleting the first entry
+ m_linesHead = pNext;
+ }
+ else {
+ // not the first entry
+ pPrev->SetNext(pNext);
+ }
+
+ pNext->SetPrev(pPrev);
+
+ delete pLine;
+}
+
bool wxFileConfig::LineListIsEmpty()
{
return m_linesHead == NULL;
bool wxFileConfig::LineListIsEmpty()
{
return m_linesHead == NULL;
if ( Parent() != NULL ) {
wxString strFullName;
strFullName << "[" << GetFullName().c_str() + 1 << "]"; // +1: no '/'
if ( Parent() != NULL ) {
wxString strFullName;
strFullName << "[" << GetFullName().c_str() + 1 << "]"; // +1: no '/'
- m_pLine = m_pConfig->LineListInsert(strFullName,
+ m_pLine = m_pConfig->LineListInsert(strFullName,
Parent()->GetLastGroupLine());
Parent()->SetLastGroup(this);
}
Parent()->GetLastGroupLine());
Parent()->SetLastGroup(this);
}
if ( n == nCount )
return FALSE;
if ( n == nCount )
return FALSE;
- delete m_aSubgroups[n];
+ nCount = m_aEntries.Count();
+ for ( n = 0; n < nCount; n++ ) {
+ LineList *pLine = m_aEntries[n]->GetLine();
+ if ( pLine != NULL )
+ m_pConfig->LineListRemove(pLine);
+ }
+
+ ConfigGroup *pGroup = m_aSubgroups[n];
+ LineList *pLine = pGroup->m_pLine;
+ if ( pLine != NULL )
+ m_pConfig->LineListRemove(pLine);
+ delete pGroup;
+
+ SetDirty();
+
m_aSubgroups.Remove(n);
return TRUE;
}
m_aSubgroups.Remove(n);
return TRUE;
}
if ( n == nCount )
return FALSE;
if ( n == nCount )
return FALSE;
+ ConfigEntry *pEntry = m_aEntries[n];
+ LineList *pLine = pEntry->GetLine();
+ if ( pLine != NULL )
+ m_pConfig->LineListRemove(pLine);
+ delete pEntry;
+
+ SetDirty();
+
m_aEntries.Remove(n);
return TRUE;
}
// ----------------------------------------------------------------------------
m_aEntries.Remove(n);
return TRUE;
}
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
void wxFileConfig::ConfigGroup::SetDirty()
{
// ----------------------------------------------------------------------------
void wxFileConfig::ConfigGroup::SetDirty()
{
// ----------------------------------------------------------------------------
// ctor
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// ctor
// ----------------------------------------------------------------------------
-wxFileConfig::ConfigEntry::ConfigEntry(wxFileConfig::ConfigGroup *pParent,
+wxFileConfig::ConfigEntry::ConfigEntry(wxFileConfig::ConfigGroup *pParent,
const wxString& strName,
int nLine)
: m_strName(strName)
const wxString& strName,
int nLine)
: m_strName(strName)
void wxFileConfig::ConfigEntry::SetValue(const wxString& strValue, bool bUser)
{
if ( bUser && IsImmutable() ) {
void wxFileConfig::ConfigEntry::SetValue(const wxString& strValue, bool bUser)
{
if ( bUser && IsImmutable() ) {
- wxLogWarning("Attempt to change immutable key '%s' ignored.",
+ wxLogWarning("Attempt to change immutable key '%s' ignored.",
Name().c_str());
return;
}
Name().c_str());
return;
}
// add a new line to the file
wxASSERT( m_nLine == NOT_FOUND ); // consistency check
// add a new line to the file
wxASSERT( m_nLine == NOT_FOUND ); // consistency check
- m_pLine = Group()->Config()->LineListInsert(strLine,
+ m_pLine = Group()->Config()->LineListInsert(strLine,
Group()->GetLastEntryLine());
Group()->SetLastEntry(this);
}
Group()->GetLastEntryLine());
Group()->SetLastEntry(this);
}