// Modified by:
// Created: 07.04.98 (adapted from appconf.cpp)
// RCS-ID: $Id$
-// Copyright: (c) 1997 Karsten Ballüder & Vadim Zeitlin
+// Copyright: (c) 1997 Karsten Ballueder & Vadim Zeitlin
// Ballueder@usa.net <zeitlin@dptmaths.ens-cachan.fr>
// Licence: wxWindows licence
///////////////////////////////////////////////////////////////////////////////
#include "wx/fileconf.h"
#include "wx/filefn.h"
-#include "wx/stdpaths.h"
+#include "wx/base64.h"
-#if defined(__WXMAC__)
- #include "wx/mac/private.h" // includes mac headers
-#endif
+#include "wx/stdpaths.h"
-#if defined(__WXMSW__)
+#if defined(__WINDOWS__)
#include "wx/msw/private.h"
#endif //windows.h
#if defined(__WXPM__)
#include <stdlib.h>
#include <ctype.h>
-// ----------------------------------------------------------------------------
-// macros
-// ----------------------------------------------------------------------------
-#define CONST_CAST ((wxFileConfig *)this)->
-
// ----------------------------------------------------------------------------
// constants
// ----------------------------------------------------------------------------
#define MAX_PATH 512
#endif
-#define FILECONF_TRACE_MASK _T("fileconf")
+#define FILECONF_TRACE_MASK wxT("fileconf")
// ----------------------------------------------------------------------------
// global functions declarations
wxFileConfigLineList *m_pNext, // next node
*m_pPrev; // previous one
- DECLARE_NO_COPY_CLASS(wxFileConfigLineList)
+ wxDECLARE_NO_COPY_CLASS(wxFileConfigLineList);
};
// ----------------------------------------------------------------------------
wxString m_strName, // entry name
m_strValue; // value
- bool m_bImmutable:1, // can be overriden locally?
+ bool m_bImmutable:1, // can be overridden locally?
m_bHasValue:1; // set after first call to SetValue()
int m_nLine; // used if m_pLine == NULL only
void SetValue(const wxString& strValue, bool bUser = true);
void SetLine(wxFileConfigLineList *pLine);
- DECLARE_NO_COPY_CLASS(wxFileConfigEntry)
+ wxDECLARE_NO_COPY_CLASS(wxFileConfigEntry);
};
// ----------------------------------------------------------------------------
bool IsEmpty() const { return Entries().IsEmpty() && Groups().IsEmpty(); }
// find entry/subgroup (NULL if not found)
- wxFileConfigGroup *FindSubgroup(const wxChar *szName) const;
- wxFileConfigEntry *FindEntry (const wxChar *szName) const;
+ wxFileConfigGroup *FindSubgroup(const wxString& name) const;
+ wxFileConfigEntry *FindEntry (const wxString& name) const;
// delete entry/subgroup, return false if doesn't exist
- bool DeleteSubgroupByName(const wxChar *szName);
- bool DeleteEntry(const wxChar *szName);
+ bool DeleteSubgroupByName(const wxString& name);
+ bool DeleteEntry(const wxString& name);
// create new entry/subgroup returning pointer to newly created element
wxFileConfigGroup *AddSubgroup(const wxString& strName);
// get the last line belonging to an entry/subgroup of this group
wxFileConfigLineList *GetGroupLine(); // line which contains [group]
+ // may be NULL for "/" only
wxFileConfigLineList *GetLastEntryLine(); // after which our subgroups start
wxFileConfigLineList *GetLastGroupLine(); // after which the next group starts
void SetLastGroup(wxFileConfigGroup *pGroup)
{ m_pLastGroup = pGroup; }
- DECLARE_NO_COPY_CLASS(wxFileConfigGroup)
+ wxDECLARE_NO_COPY_CLASS(wxFileConfigGroup);
};
// ============================================================================
#if defined( __WXMAC__ )
fn.SetName(fn.GetName() + wxT(" Preferences"));
#elif defined( __UNIX__ )
- fn.SetExt(wxT(".conf"));
+ fn.SetExt(wxT("conf"));
#else // Windows
- fn.SetExt(wxT(".ini"));
+ fn.SetExt(wxT("ini"));
#endif // UNIX/Win
}
}
{
wxFileName fn(GetLocalDir(style), szFile);
-#ifdef __UNIX__
+#if defined( __UNIX__ ) && !defined( __WXMAC__ )
if ( !(style & wxCONFIG_USE_SUBDIR) )
{
// dot-files under Unix start with, well, a dot (but OTOH they usually
fn.SetName(wxT('.') + fn.GetName());
}
else // we do append ".conf" extension to config files in subdirectories
-#endif // __UNIX__
+#endif // defined( __UNIX__ ) && !defined( __WXMAC__ )
{
AddConfFileExtIfNeeded(fn);
}
}
else
{
- wxLogWarning(_("can't open user configuration file '%s'."), m_fnLocalFile.GetFullPath().c_str() );
+ const wxString path = m_fnLocalFile.GetFullPath();
+ wxLogWarning(_("can't open user configuration file '%s'."),
+ path.c_str());
+
+ if ( m_fnLocalFile.FileExists() )
+ {
+ wxLogWarning(_("Changes won't be saved to avoid overwriting the existing file \"%s\""),
+ path.c_str());
+ m_fnLocalFile.Clear();
+ }
}
}
m_linesTail = NULL;
// read the entire stream contents in memory
- wxString str;
- {
- static const size_t chunkLen = 1024;
+ wxWxCharBuffer cbuf;
+ static const size_t chunkLen = 1024;
- wxMemoryBuffer buf(chunkLen);
- do
- {
- inStream.Read(buf.GetAppendBuf(chunkLen), chunkLen);
- buf.UngetAppendBuf(inStream.LastRead());
+ wxMemoryBuffer buf(chunkLen);
+ do
+ {
+ inStream.Read(buf.GetAppendBuf(chunkLen), chunkLen);
+ buf.UngetAppendBuf(inStream.LastRead());
- const wxStreamError err = inStream.GetLastError();
+ const wxStreamError err = inStream.GetLastError();
- if ( err != wxSTREAM_NO_ERROR && err != wxSTREAM_EOF )
- {
- wxLogError(_("Error reading config options."));
- break;
- }
+ if ( err != wxSTREAM_NO_ERROR && err != wxSTREAM_EOF )
+ {
+ wxLogError(_("Error reading config options."));
+ break;
}
- while ( !inStream.Eof() );
+ }
+ while ( !inStream.Eof() );
#if wxUSE_UNICODE
- size_t len;
- str = conv.cMB2WC((char *)buf.GetData(), buf.GetDataLen(), &len);
- if ( !len && buf.GetDataLen() )
- {
- wxLogError(_("Failed to read config options."));
- }
+ size_t len;
+ cbuf = conv.cMB2WC((char *)buf.GetData(), buf.GetDataLen() + 1, &len);
+ if ( !len && buf.GetDataLen() )
+ {
+ wxLogError(_("Failed to read config options."));
+ }
#else // !wxUSE_UNICODE
- // no need for conversion
- str.assign((char *)buf.GetData(), buf.GetDataLen());
+ // no need for conversion
+ cbuf = wxCharBuffer::CreateNonOwned((char *)buf.GetData(), buf.GetDataLen());
#endif // wxUSE_UNICODE/!wxUSE_UNICODE
- }
-
- // translate everything to the current (platform-dependent) line
- // termination character
- str = wxTextBuffer::Translate(str);
-
- wxMemoryText memText;
-
- // Now we can add the text to the memory text. To do this we extract line
- // by line from the translated string, until we've reached the end.
- //
- // VZ: all this is horribly inefficient, we should do the translation on
- // the fly in one pass saving both memory and time (TODO)
-
- const wxChar *pEOL = wxTextBuffer::GetEOL(wxTextBuffer::typeDefault);
- const size_t EOLLen = wxStrlen(pEOL);
-
- int posLineStart = str.Find(pEOL);
- while ( posLineStart != -1 )
+ // parse the input contents if there is anything to parse
+ if ( cbuf )
{
- wxString line(str.Left(posLineStart));
+ // now break it into lines
+ wxMemoryText memText;
+ for ( const wxChar *s = cbuf; ; ++s )
+ {
+ const wxChar *e = s;
+ while ( *e != '\0' && *e != '\n' && *e != '\r' )
+ ++e;
- memText.AddLine(line);
+ // notice that we throw away the original EOL kind here, maybe we
+ // should preserve it?
+ if ( e != s )
+ memText.AddLine(wxString(s, e));
- str = str.Mid(posLineStart + EOLLen);
+ if ( *e == '\0' )
+ break;
- posLineStart = str.Find(pEOL);
- }
+ // skip the second EOL byte if it's a DOS one
+ if ( *e == '\r' && e[1] == '\n' )
+ ++e;
- // also add whatever we have left in the translated string.
- if ( !str.empty() )
- memText.AddLine(str);
+ s = e;
+ }
- // Finally we can parse it all.
- Parse(memText, true /* local */);
+ // Finally we can parse it all.
+ Parse(memText, true /* local */);
+ }
SetRootPath();
ResetDirty();
void wxFileConfig::Parse(const wxTextBuffer& buffer, bool bLocal)
{
- const wxChar *pStart;
- const wxChar *pEnd;
- wxString strLine;
size_t nLineCount = buffer.GetLineCount();
for ( size_t n = 0; n < nLineCount; n++ )
{
- strLine = buffer[n];
+ wxString strLine = buffer[n];
+ // FIXME-UTF8: rewrite using iterators, without this buffer
+ wxWxCharBuffer buf(strLine.c_str());
+ const wxChar *pStart;
+ const wxChar *pEnd;
// add the line to linked list
if ( bLocal )
- {
LineListAppend(strLine);
- // let the root group have its start line as well
- if ( !n )
- {
- m_pCurrentGroup->SetLine(m_linesTail);
- }
- }
-
// skip leading spaces
- for ( pStart = strLine; wxIsspace(*pStart); pStart++ )
+ for ( pStart = buf; wxIsspace(*pStart); pStart++ )
;
// skip blank/comment lines
// which is exactly what we want.
else if ( !bLocal || pEntry->IsLocal() ) {
wxLogWarning(_("file '%s', line %d: key '%s' was first found at line %d."),
- buffer.GetName(), n + 1, strKey.c_str(), pEntry->Line());
+ buffer.GetName(), (int)n + 1, strKey.c_str(), pEntry->Line());
}
}
// change current group
size_t n;
m_pCurrentGroup = m_pRootGroup;
- for ( n = 0; n < aParts.Count(); n++ ) {
+ for ( n = 0; n < aParts.GetCount(); n++ ) {
wxFileConfigGroup *pNextGroup = m_pCurrentGroup->FindSubgroup(aParts[n]);
if ( pNextGroup == NULL )
{
// recombine path parts in one variable
m_strPath.Empty();
- for ( n = 0; n < aParts.Count(); n++ ) {
+ for ( n = 0; n < aParts.GetCount(); n++ ) {
m_strPath << wxCONFIG_PATH_SEPARATOR << aParts[n];
}
DoSetPath(strPath, true /* create missing path components */);
}
+const wxString& wxFileConfig::GetPath() const
+{
+ return m_strPath;
+}
+
// ----------------------------------------------------------------------------
// enumeration
// ----------------------------------------------------------------------------
bool wxFileConfig::GetNextGroup (wxString& str, long& lIndex) const
{
- if ( size_t(lIndex) < m_pCurrentGroup->Groups().Count() ) {
+ if ( size_t(lIndex) < m_pCurrentGroup->Groups().GetCount() ) {
str = m_pCurrentGroup->Groups()[(size_t)lIndex++]->Name();
return true;
}
bool wxFileConfig::GetNextEntry (wxString& str, long& lIndex) const
{
- if ( size_t(lIndex) < m_pCurrentGroup->Entries().Count() ) {
+ if ( size_t(lIndex) < m_pCurrentGroup->Entries().GetCount() ) {
str = m_pCurrentGroup->Entries()[(size_t)lIndex++]->Name();
return true;
}
size_t wxFileConfig::GetNumberOfEntries(bool bRecursive) const
{
- size_t n = m_pCurrentGroup->Entries().Count();
+ size_t n = m_pCurrentGroup->Entries().GetCount();
if ( bRecursive ) {
+ wxFileConfig * const self = const_cast<wxFileConfig *>(this);
+
wxFileConfigGroup *pOldCurrentGroup = m_pCurrentGroup;
- size_t nSubgroups = m_pCurrentGroup->Groups().Count();
+ size_t nSubgroups = m_pCurrentGroup->Groups().GetCount();
for ( size_t nGroup = 0; nGroup < nSubgroups; nGroup++ ) {
- CONST_CAST m_pCurrentGroup = m_pCurrentGroup->Groups()[nGroup];
+ self->m_pCurrentGroup = m_pCurrentGroup->Groups()[nGroup];
n += GetNumberOfEntries(true);
- CONST_CAST m_pCurrentGroup = pOldCurrentGroup;
+ self->m_pCurrentGroup = pOldCurrentGroup;
}
}
size_t wxFileConfig::GetNumberOfGroups(bool bRecursive) const
{
- size_t n = m_pCurrentGroup->Groups().Count();
+ size_t n = m_pCurrentGroup->Groups().GetCount();
if ( bRecursive ) {
+ wxFileConfig * const self = const_cast<wxFileConfig *>(this);
+
wxFileConfigGroup *pOldCurrentGroup = m_pCurrentGroup;
- size_t nSubgroups = m_pCurrentGroup->Groups().Count();
+ size_t nSubgroups = m_pCurrentGroup->Groups().GetCount();
for ( size_t nGroup = 0; nGroup < nSubgroups; nGroup++ ) {
- CONST_CAST m_pCurrentGroup = m_pCurrentGroup->Groups()[nGroup];
+ self->m_pCurrentGroup = m_pCurrentGroup->Groups()[nGroup];
n += GetNumberOfGroups(true);
- CONST_CAST m_pCurrentGroup = pOldCurrentGroup;
+ self->m_pCurrentGroup = pOldCurrentGroup;
}
}
const wxString pathOld = GetPath();
- wxFileConfig *self = wx_const_cast(wxFileConfig *, this);
+ wxFileConfig *self = const_cast<wxFileConfig *>(this);
const bool
rc = self->DoSetPath(strName, false /* don't create missing components */);
// change to the path of the entry if necessary and remember the old path
// to restore it later
wxString pathOld;
- wxFileConfig * const self = wx_const_cast(wxFileConfig *, this);
+ wxFileConfig * const self = const_cast<wxFileConfig *>(this);
if ( !path.empty() )
{
pathOld = GetPath();
return str.ToLong(pl);
}
+#if wxUSE_BASE64
+
+bool wxFileConfig::DoReadBinary(const wxString& key, wxMemoryBuffer* buf) const
+{
+ wxCHECK_MSG( buf, false, wxT("NULL buffer") );
+
+ wxString str;
+ if ( !Read(key, &str) )
+ return false;
+
+ *buf = wxBase64Decode(str);
+ return true;
+}
+
+#endif // wxUSE_BASE64
+
bool wxFileConfig::DoWriteString(const wxString& key, const wxString& szValue)
{
wxConfigPathChanger path(this, key);
wxString strName = path.Name();
wxLogTrace( FILECONF_TRACE_MASK,
- _T(" Writing String '%s' = '%s' to Group '%s'"),
+ wxT(" Writing String '%s' = '%s' to Group '%s'"),
strName.c_str(),
szValue.c_str(),
GetPath().c_str() );
// ... except if it's empty in which case it's a way to force it's creation
wxLogTrace( FILECONF_TRACE_MASK,
- _T(" Creating group %s"),
+ wxT(" Creating group %s"),
m_pCurrentGroup->Name().c_str() );
SetDirty();
- // this will add a line for this group if it didn't have it before
-
+ // this will add a line for this group if it didn't have it before (or
+ // do nothing for the root but it's ok as it always exists anyhow)
(void)m_pCurrentGroup->GetGroupLine();
}
else
if ( pEntry == 0 )
{
wxLogTrace( FILECONF_TRACE_MASK,
- _T(" Adding Entry %s"),
+ wxT(" Adding Entry %s"),
strName.c_str() );
pEntry = m_pCurrentGroup->AddEntry(strName);
}
wxLogTrace( FILECONF_TRACE_MASK,
- _T(" Setting value %s"),
+ wxT(" Setting value %s"),
szValue.c_str() );
pEntry->SetValue(szValue);
bool wxFileConfig::DoWriteLong(const wxString& key, long lValue)
{
- return Write(key, wxString::Format(_T("%ld"), lValue));
+ return Write(key, wxString::Format(wxT("%ld"), lValue));
+}
+
+#if wxUSE_BASE64
+
+bool wxFileConfig::DoWriteBinary(const wxString& key, const wxMemoryBuffer& buf)
+{
+ return Write(key, wxBase64Encode(buf));
}
+#endif // wxUSE_BASE64
+
bool wxFileConfig::Flush(bool /* bCurrentOnly */)
{
if ( !IsDirty() || !m_fnLocalFile.GetFullPath() )
ResetDirty();
-#if defined(__WXMAC__)
+#if defined( __WXOSX_MAC__ ) && wxOSX_USE_CARBON
m_fnLocalFile.MacSetTypeAndCreator('TEXT', 'ttxt');
#endif // __WXMAC__
bool wxFileConfig::RenameEntry(const wxString& oldName,
const wxString& newName)
{
- wxASSERT_MSG( !wxStrchr(oldName, wxCONFIG_PATH_SEPARATOR),
- _T("RenameEntry(): paths are not supported") );
+ wxASSERT_MSG( oldName.find(wxCONFIG_PATH_SEPARATOR) == wxString::npos,
+ wxT("RenameEntry(): paths are not supported") );
// check that the entry exists
wxFileConfigEntry *oldEntry = m_pCurrentGroup->FindEntry(oldName);
if ( m_fnLocalFile.IsOk() )
{
- if ( m_fnLocalFile.FileExists() && wxRemove(m_fnLocalFile.GetFullPath()) == -1 )
+ if ( m_fnLocalFile.FileExists() &&
+ !wxRemoveFile(m_fnLocalFile.GetFullPath()) )
{
wxLogSysError(_("can't delete user configuration file '%s'"),
m_fnLocalFile.GetFullPath().c_str());
wxFileConfigLineList *wxFileConfig::LineListAppend(const wxString& str)
{
wxLogTrace( FILECONF_TRACE_MASK,
- _T(" ** Adding Line '%s'"),
+ wxT(" ** Adding Line '%s'"),
str.c_str() );
wxLogTrace( FILECONF_TRACE_MASK,
- _T(" head: %s"),
+ wxT(" head: %s"),
((m_linesHead) ? (const wxChar*)m_linesHead->Text().c_str()
: wxEmptyString) );
wxLogTrace( FILECONF_TRACE_MASK,
- _T(" tail: %s"),
+ wxT(" tail: %s"),
((m_linesTail) ? (const wxChar*)m_linesTail->Text().c_str()
: wxEmptyString) );
m_linesTail = pLine;
wxLogTrace( FILECONF_TRACE_MASK,
- _T(" head: %s"),
+ wxT(" head: %s"),
((m_linesHead) ? (const wxChar*)m_linesHead->Text().c_str()
: wxEmptyString) );
wxLogTrace( FILECONF_TRACE_MASK,
- _T(" tail: %s"),
+ wxT(" tail: %s"),
((m_linesTail) ? (const wxChar*)m_linesTail->Text().c_str()
: wxEmptyString) );
wxFileConfigLineList *pLine)
{
wxLogTrace( FILECONF_TRACE_MASK,
- _T(" ** Inserting Line '%s' after '%s'"),
+ wxT(" ** Inserting Line '%s' after '%s'"),
str.c_str(),
((pLine) ? (const wxChar*)pLine->Text().c_str()
: wxEmptyString) );
wxLogTrace( FILECONF_TRACE_MASK,
- _T(" head: %s"),
+ wxT(" head: %s"),
((m_linesHead) ? (const wxChar*)m_linesHead->Text().c_str()
: wxEmptyString) );
wxLogTrace( FILECONF_TRACE_MASK,
- _T(" tail: %s"),
+ wxT(" tail: %s"),
((m_linesTail) ? (const wxChar*)m_linesTail->Text().c_str()
: wxEmptyString) );
}
wxLogTrace( FILECONF_TRACE_MASK,
- _T(" head: %s"),
+ wxT(" head: %s"),
((m_linesHead) ? (const wxChar*)m_linesHead->Text().c_str()
: wxEmptyString) );
wxLogTrace( FILECONF_TRACE_MASK,
- _T(" tail: %s"),
+ wxT(" tail: %s"),
((m_linesTail) ? (const wxChar*)m_linesTail->Text().c_str()
: wxEmptyString) );
void wxFileConfig::LineListRemove(wxFileConfigLineList *pLine)
{
wxLogTrace( FILECONF_TRACE_MASK,
- _T(" ** Removing Line '%s'"),
+ wxT(" ** Removing Line '%s'"),
pLine->Text().c_str() );
wxLogTrace( FILECONF_TRACE_MASK,
- _T(" head: %s"),
+ wxT(" head: %s"),
((m_linesHead) ? (const wxChar*)m_linesHead->Text().c_str()
: wxEmptyString) );
wxLogTrace( FILECONF_TRACE_MASK,
- _T(" tail: %s"),
+ wxT(" tail: %s"),
((m_linesTail) ? (const wxChar*)m_linesTail->Text().c_str()
: wxEmptyString) );
else
pNext->SetPrev(pPrev);
- if ( m_pRootGroup->GetGroupLine() == pLine )
- m_pRootGroup->SetLine(m_linesHead);
-
wxLogTrace( FILECONF_TRACE_MASK,
- _T(" head: %s"),
+ wxT(" head: %s"),
((m_linesHead) ? (const wxChar*)m_linesHead->Text().c_str()
: wxEmptyString) );
wxLogTrace( FILECONF_TRACE_MASK,
- _T(" tail: %s"),
+ wxT(" tail: %s"),
((m_linesTail) ? (const wxChar*)m_linesTail->Text().c_str()
: wxEmptyString) );
wxFileConfigGroup::~wxFileConfigGroup()
{
// entries
- size_t n, nCount = m_aEntries.Count();
+ size_t n, nCount = m_aEntries.GetCount();
for ( n = 0; n < nCount; n++ )
delete m_aEntries[n];
// subgroups
- nCount = m_aSubgroups.Count();
+ nCount = m_aSubgroups.GetCount();
for ( n = 0; n < nCount; n++ )
delete m_aSubgroups[n];
}
// for a normal (i.e. not root) group this method shouldn't be called twice
// unless we are resetting the line
wxASSERT_MSG( !m_pParent || !m_pLine || !pLine,
- _T("changing line for a non-root group?") );
+ wxT("changing line for a non-root group?") );
m_pLine = pLine;
}
wxFileConfigLineList *wxFileConfigGroup::GetGroupLine()
{
wxLogTrace( FILECONF_TRACE_MASK,
- _T(" GetGroupLine() for Group '%s'"),
+ wxT(" GetGroupLine() for Group '%s'"),
Name().c_str() );
if ( !m_pLine )
{
wxLogTrace( FILECONF_TRACE_MASK,
- _T(" Getting Line item pointer") );
+ wxT(" Getting Line item pointer") );
wxFileConfigGroup *pParent = Parent();
if ( pParent )
{
wxLogTrace( FILECONF_TRACE_MASK,
- _T(" checking parent '%s'"),
+ wxT(" checking parent '%s'"),
pParent->Name().c_str() );
wxString strFullName;
{
wxFileConfigLineList *pLine = m_pLastGroup->GetLastGroupLine();
- wxASSERT_MSG( pLine, _T("last group must have !NULL associated line") );
+ wxASSERT_MSG( pLine, wxT("last group must have !NULL associated line") );
return pLine;
}
wxFileConfigLineList *wxFileConfigGroup::GetLastEntryLine()
{
wxLogTrace( FILECONF_TRACE_MASK,
- _T(" GetLastEntryLine() for Group '%s'"),
+ wxT(" GetLastEntryLine() for Group '%s'"),
Name().c_str() );
if ( m_pLastEntry )
{
wxFileConfigLineList *pLine = m_pLastEntry->GetLine();
- wxASSERT_MSG( pLine, _T("last entry must have !NULL associated line") );
+ wxASSERT_MSG( pLine, wxT("last entry must have !NULL associated line") );
return pLine;
}
// the only situation in which a group without its own line can have
// an entry is when the first entry is added to the initially empty
// root pseudo-group
- wxASSERT_MSG( !m_pParent, _T("unexpected for non root group") );
+ wxASSERT_MSG( !m_pParent, wxT("unexpected for non root group") );
// let the group know that it does have a line in the file now
m_pLine = pEntry->GetLine();
{
// update the line of this group
wxFileConfigLineList *line = GetGroupLine();
- wxCHECK_RET( line, _T("a non root group must have a corresponding line!") );
+ wxCHECK_RET( line, wxT("a non root group must have a corresponding line!") );
// +1: skip the leading '/'
- line->SetText(wxString::Format(_T("[%s]"), GetFullName().c_str() + 1));
+ line->SetText(wxString::Format(wxT("[%s]"), GetFullName().c_str() + 1));
// also update all subgroups as they have this groups name in their lines
- const size_t nCount = m_aSubgroups.Count();
+ const size_t nCount = m_aSubgroups.GetCount();
for ( size_t n = 0; n < nCount; n++ )
{
m_aSubgroups[n]->UpdateGroupAndSubgroupsLines();
void wxFileConfigGroup::Rename(const wxString& newName)
{
- wxCHECK_RET( m_pParent, _T("the root group can't be renamed") );
+ wxCHECK_RET( m_pParent, wxT("the root group can't be renamed") );
if ( newName == m_strName )
return;
// use binary search because the array is sorted
wxFileConfigEntry *
-wxFileConfigGroup::FindEntry(const wxChar *szName) const
+wxFileConfigGroup::FindEntry(const wxString& name) const
{
size_t i,
lo = 0,
- hi = m_aEntries.Count();
+ hi = m_aEntries.GetCount();
int res;
wxFileConfigEntry *pEntry;
pEntry = m_aEntries[i];
#if wxCONFIG_CASE_SENSITIVE
- res = wxStrcmp(pEntry->Name(), szName);
+ res = pEntry->Name().compare(name);
#else
- res = wxStricmp(pEntry->Name(), szName);
+ res = pEntry->Name().CmpNoCase(name);
#endif
if ( res > 0 )
}
wxFileConfigGroup *
-wxFileConfigGroup::FindSubgroup(const wxChar *szName) const
+wxFileConfigGroup::FindSubgroup(const wxString& name) const
{
size_t i,
lo = 0,
- hi = m_aSubgroups.Count();
+ hi = m_aSubgroups.GetCount();
int res;
wxFileConfigGroup *pGroup;
pGroup = m_aSubgroups[i];
#if wxCONFIG_CASE_SENSITIVE
- res = wxStrcmp(pGroup->Name(), szName);
+ res = pGroup->Name().compare(name);
#else
- res = wxStricmp(pGroup->Name(), szName);
+ res = pGroup->Name().CmpNoCase(name);
#endif
if ( res > 0 )
delete several of them.
*/
-bool wxFileConfigGroup::DeleteSubgroupByName(const wxChar *szName)
+bool wxFileConfigGroup::DeleteSubgroupByName(const wxString& name)
{
- wxFileConfigGroup * const pGroup = FindSubgroup(szName);
+ wxFileConfigGroup * const pGroup = FindSubgroup(name);
return pGroup ? DeleteSubgroup(pGroup) : false;
}
// other data structures.
bool wxFileConfigGroup::DeleteSubgroup(wxFileConfigGroup *pGroup)
{
- wxCHECK_MSG( pGroup, false, _T("deleting non existing group?") );
+ wxCHECK_MSG( pGroup, false, wxT("deleting non existing group?") );
wxLogTrace( FILECONF_TRACE_MASK,
- _T("Deleting group '%s' from '%s'"),
+ wxT("Deleting group '%s' from '%s'"),
pGroup->Name().c_str(),
Name().c_str() );
wxLogTrace( FILECONF_TRACE_MASK,
- _T(" (m_pLine) = prev: %p, this %p, next %p"),
- m_pLine ? wx_static_cast(void*, m_pLine->Prev()) : 0,
- wx_static_cast(void*, m_pLine),
- m_pLine ? wx_static_cast(void*, m_pLine->Next()) : 0 );
+ wxT(" (m_pLine) = prev: %p, this %p, next %p"),
+ m_pLine ? static_cast<void*>(m_pLine->Prev()) : 0,
+ static_cast<void*>(m_pLine),
+ m_pLine ? static_cast<void*>(m_pLine->Next()) : 0 );
wxLogTrace( FILECONF_TRACE_MASK,
- _T(" text: '%s'"),
+ wxT(" text: '%s'"),
m_pLine ? (const wxChar*)m_pLine->Text().c_str()
: wxEmptyString );
// delete all entries...
- size_t nCount = pGroup->m_aEntries.Count();
+ size_t nCount = pGroup->m_aEntries.GetCount();
wxLogTrace(FILECONF_TRACE_MASK,
- _T("Removing %lu entries"), (unsigned long)nCount );
+ wxT("Removing %lu entries"), (unsigned long)nCount );
for ( size_t nEntry = 0; nEntry < nCount; nEntry++ )
{
if ( pLine )
{
wxLogTrace( FILECONF_TRACE_MASK,
- _T(" '%s'"),
+ wxT(" '%s'"),
pLine->Text().c_str() );
m_pConfig->LineListRemove(pLine);
}
}
// ...and subgroups of this subgroup
- nCount = pGroup->m_aSubgroups.Count();
+ nCount = pGroup->m_aSubgroups.GetCount();
wxLogTrace( FILECONF_TRACE_MASK,
- _T("Removing %lu subgroups"), (unsigned long)nCount );
+ wxT("Removing %lu subgroups"), (unsigned long)nCount );
for ( size_t nGroup = 0; nGroup < nCount; nGroup++ )
{
if ( pLine )
{
wxLogTrace( FILECONF_TRACE_MASK,
- _T(" Removing line for group '%s' : '%s'"),
+ wxT(" Removing line for group '%s' : '%s'"),
pGroup->Name().c_str(),
pLine->Text().c_str() );
wxLogTrace( FILECONF_TRACE_MASK,
- _T(" Removing from group '%s' : '%s'"),
+ wxT(" Removing from group '%s' : '%s'"),
Name().c_str(),
((m_pLine) ? (const wxChar*)m_pLine->Text().c_str()
: wxEmptyString) );
if ( pGroup == m_pLastGroup )
{
wxLogTrace( FILECONF_TRACE_MASK,
- _T(" Removing last group") );
+ wxT(" Removing last group") );
// our last entry is being deleted, so find the last one which
// stays by going back until we find a subgroup or reach the
// group line
- const size_t nSubgroups = m_aSubgroups.Count();
+ const size_t nSubgroups = m_aSubgroups.GetCount();
m_pLastGroup = NULL;
for ( wxFileConfigLineList *pl = pLine->Prev();
- pl && pl != m_pLine && !m_pLastGroup;
+ pl && !m_pLastGroup;
pl = pl->Prev() )
{
// does this line belong to our subgroup?
break;
}
}
+
+ if ( pl == m_pLine )
+ break;
}
}
else
{
wxLogTrace( FILECONF_TRACE_MASK,
- _T(" No line entry for Group '%s'?"),
+ wxT(" No line entry for Group '%s'?"),
pGroup->Name().c_str() );
}
return true;
}
-bool wxFileConfigGroup::DeleteEntry(const wxChar *szName)
+bool wxFileConfigGroup::DeleteEntry(const wxString& name)
{
- wxFileConfigEntry *pEntry = FindEntry(szName);
+ wxFileConfigEntry *pEntry = FindEntry(name);
if ( !pEntry )
{
// entry doesn't exist, nothing to do
// our last entry is being deleted - find the last one which stays
wxASSERT( m_pLine != NULL ); // if we have an entry with !NULL pLine...
- // go back until we find another entry or reach the group's line
+ // find the previous entry (if any)
wxFileConfigEntry *pNewLast = NULL;
- size_t n, nEntries = m_aEntries.Count();
- wxFileConfigLineList *pl;
- for ( pl = pLine->Prev(); pl != m_pLine; pl = pl->Prev() ) {
- // is it our subgroup?
- for ( n = 0; (pNewLast == NULL) && (n < nEntries); n++ ) {
- if ( m_aEntries[n]->GetLine() == m_pLine )
- pNewLast = m_aEntries[n];
- }
-
- if ( pNewLast != NULL ) // found?
+ const wxFileConfigLineList * const
+ pNewLastLine = m_pLastEntry->GetLine()->Prev();
+ const size_t nEntries = m_aEntries.GetCount();
+ for ( size_t n = 0; n < nEntries; n++ ) {
+ if ( m_aEntries[n]->GetLine() == pNewLastLine ) {
+ pNewLast = m_aEntries[n];
break;
+ }
}
- if ( pl == m_pLine ) {
- wxASSERT( !pNewLast ); // how comes it has the same line as we?
+ // pNewLast can be NULL here -- it's ok and can happen if we have no
+ // entries left
+ m_pLastEntry = pNewLast;
- // we've reached the group line without finding any subgroups
- m_pLastEntry = NULL;
- }
- else
- m_pLastEntry = pNewLast;
+ // For the root group only, we could be removing the first group line
+ // here, so update m_pLine to avoid keeping a dangling pointer.
+ if ( pLine == m_pLine )
+ SetLine(NULL);
}
m_pConfig->LineListRemove(pLine);
int CompareEntries(wxFileConfigEntry *p1, wxFileConfigEntry *p2)
{
#if wxCONFIG_CASE_SENSITIVE
- return wxStrcmp(p1->Name(), p2->Name());
+ return p1->Name().compare(p2->Name());
#else
- return wxStricmp(p1->Name(), p2->Name());
+ return p1->Name().CmpNoCase(p2->Name());
#endif
}
int CompareGroups(wxFileConfigGroup *p1, wxFileConfigGroup *p2)
{
#if wxCONFIG_CASE_SENSITIVE
- return wxStrcmp(p1->Name(), p2->Name());
+ return p1->Name().compare(p2->Name());
#else
- return wxStricmp(p1->Name(), p2->Name());
+ return p1->Name().CmpNoCase(p2->Name());
#endif
}
// undo FilterOutValue
static wxString FilterInValue(const wxString& str)
{
- wxString strResult;
- strResult.Alloc(str.Len());
+ wxString strResult;
+ if ( str.empty() )
+ return strResult;
- bool bQuoted = !str.empty() && str[0] == '"';
+ strResult.reserve(str.length());
- for ( size_t n = bQuoted ? 1 : 0; n < str.Len(); n++ ) {
- if ( str[n] == wxT('\\') ) {
- switch ( str[++n].GetValue() ) {
- case wxT('n'):
- strResult += wxT('\n');
- break;
+ wxString::const_iterator i = str.begin();
+ const bool bQuoted = *i == '"';
+ if ( bQuoted )
+ ++i;
- case wxT('r'):
- strResult += wxT('\r');
- break;
+ for ( const wxString::const_iterator end = str.end(); i != end; ++i )
+ {
+ if ( *i == wxT('\\') )
+ {
+ if ( ++i == end )
+ {
+ wxLogWarning(_("trailing backslash ignored in '%s'"), str.c_str());
+ break;
+ }
- case wxT('t'):
- strResult += wxT('\t');
- break;
+ switch ( (*i).GetValue() )
+ {
+ case wxT('n'):
+ strResult += wxT('\n');
+ break;
- case wxT('\\'):
- strResult += wxT('\\');
- break;
+ case wxT('r'):
+ strResult += wxT('\r');
+ break;
- case wxT('"'):
- strResult += wxT('"');
- break;
- }
- }
- else {
- if ( str[n] != wxT('"') || !bQuoted )
- strResult += str[n];
- else if ( n != str.Len() - 1 ) {
- wxLogWarning(_("unexpected \" at position %d in '%s'."),
- n, str.c_str());
- }
- //else: it's the last quote of a quoted string, ok
+ case wxT('t'):
+ strResult += wxT('\t');
+ break;
+
+ case wxT('\\'):
+ strResult += wxT('\\');
+ break;
+
+ case wxT('"'):
+ strResult += wxT('"');
+ break;
+ }
+ }
+ else // not a backslash
+ {
+ if ( *i != wxT('"') || !bQuoted )
+ {
+ strResult += *i;
+ }
+ else if ( i != end - 1 )
+ {
+ wxLogWarning(_("unexpected \" at position %d in '%s'."),
+ i - str.begin(), str.c_str());
+ }
+ //else: it's the last quote of a quoted string, ok
+ }
}
- }
- return strResult;
+ return strResult;
}
// quote the string before writing it to file
for ( const wxChar *pc = str.c_str(); *pc != '\0'; pc++ ) {
if ( *pc == wxT('\\') ) {
// we need to test it here or we'd skip past the NUL in the loop line
- if ( *++pc == _T('\0') )
+ if ( *++pc == wxT('\0') )
break;
}
#if !wxUSE_UNICODE
((unsigned char)c < 127) &&
#endif // ANSI
- !wxIsalnum(c) && !wxStrchr(wxT("@_/-!.*%"), c) )
+ !wxIsalnum(c) && !wxStrchr(wxT("@_/-!.*%()"), c) )
{
strResult += wxT('\\');
}