X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/cfe780fb99dc42d454625b1ea88ae687c54acbf1..e99c30481090eb4ceaec74c0c1b5fac89b235e7f:/src/common/fileconf.cpp?ds=sidebyside diff --git a/src/common/fileconf.cpp b/src/common/fileconf.cpp index 9f1aea52c0..f25cb997dc 100644 --- a/src/common/fileconf.cpp +++ b/src/common/fileconf.cpp @@ -2,7 +2,7 @@ // Name: fileconf.cpp // Purpose: implementation of wxFileConfig derivation of wxConfig // Author: Vadim Zeitlin -// Modified by: +// Modified by: // Created: 07.04.98 (adapted from appconf.cpp) // RCS-ID: $Id$ // Copyright: (c) 1997 Karsten Ballüder & Vadim Zeitlin @@ -40,8 +40,8 @@ #include // _WINDOWS_ is defined when windows.h is included, -// __WINDOWS__ is defined for MS Windows compilation -#if defined(__WINDOWS__) && !defined(_WINDOWS_) +// __WXMSW__ is defined for MS Windows compilation +#if defined(__WXMSW__) && !defined(_WINDOWS_) #include #endif //windows.h @@ -55,7 +55,13 @@ // 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); } + +// compare functions for sorting the arrays +static int CompareEntries(wxFileConfig::ConfigEntry *p1, + wxFileConfig::ConfigEntry *p2); +static int CompareGroups(wxFileConfig::ConfigGroup *p1, + wxFileConfig::ConfigGroup *p2); // filter strings static wxString FilterIn(const wxString& str); @@ -131,7 +137,7 @@ wxString wxFileConfig::GetLocalFileName(const char *szFile) void wxFileConfig::Init() { - m_pCurrentGroup = + m_pCurrentGroup = m_pRootGroup = new ConfigGroup(NULL, "", this); m_linesHead = @@ -181,6 +187,13 @@ wxFileConfig::~wxFileConfig() { Flush(); delete m_pRootGroup; + + LineList *pCur = m_linesHead; + while ( pCur != NULL ) { + LineList *pNext = pCur->Next(); + delete pCur; + pCur = pNext; + } } // ---------------------------------------------------------------------------- @@ -191,7 +204,7 @@ void wxFileConfig::Parse(wxTextFile& file, bool bLocal) { const char *pStart; const char *pEnd; - + for ( uint n = 0; n < file.GetLineCount(); n++ ) { // add the line to linked list if ( bLocal ) @@ -214,8 +227,8 @@ void wxFileConfig::Parse(wxTextFile& file, bool bLocal) } if ( *pEnd != ']' ) { - wxLogError("file '%s': unexpected character at line %d (missing ']'?)", - file.GetName(), n + 1); + wxLogError("file '%s': unexpected character %c at line %d.", + file.GetName(), *pEnd, n + 1); continue; // skip this line } @@ -238,12 +251,12 @@ void wxFileConfig::Parse(wxTextFile& file, bool bLocal) case ';': bCont = FALSE; 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); @@ -259,7 +272,7 @@ void wxFileConfig::Parse(wxTextFile& file, bool bLocal) wxString strKey(pStart, pEnd); // skip whitespace - while ( isspace(*pEnd) ) + while ( isspace(*pEnd) ) pEnd++; if ( *pEnd++ != '=' ) { @@ -288,7 +301,7 @@ void wxFileConfig::Parse(wxTextFile& file, bool bLocal) // (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 ) @@ -297,7 +310,7 @@ void wxFileConfig::Parse(wxTextFile& file, bool bLocal) } // skip whitespace - while ( isspace(*pEnd) ) + while ( isspace(*pEnd) ) pEnd++; wxString strValue; @@ -325,8 +338,10 @@ void wxFileConfig::SetPath(const wxString& strPath) { wxArrayString aParts; - if ( strPath.IsEmpty() ) + if ( strPath.IsEmpty() ) { + SetRootPath(); return; + } if ( strPath[0] == APPCONF_PATH_SEPARATOR ) { // absolute path @@ -392,6 +407,26 @@ bool wxFileConfig::GetNextEntry (wxString& str, long& lIndex) return FALSE; } +// ---------------------------------------------------------------------------- +// 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 // ---------------------------------------------------------------------------- @@ -540,6 +575,7 @@ wxFileConfig::LineList *wxFileConfig::LineListAppend(const wxString& str) else { // adjust pointers m_linesTail->SetNext(pLine); + pLine->SetPrev(m_linesTail); } m_linesTail = pLine; @@ -547,26 +583,49 @@ wxFileConfig::LineList *wxFileConfig::LineListAppend(const wxString& str) } // 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 *pNewLine; - + LineList *pNewLine = new LineList(str); if ( pLine == NULL ) { - pNewLine = new LineList(str, m_linesHead); + // prepend to the list + pNewLine->SetNext(m_linesHead); + m_linesHead->SetPrev(pNewLine); 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; } +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; @@ -584,7 +643,9 @@ bool wxFileConfig::LineListIsEmpty() wxFileConfig::ConfigGroup::ConfigGroup(wxFileConfig::ConfigGroup *pParent, const wxString& strName, wxFileConfig *pConfig) - : m_strName(strName) + : m_aEntries(CompareEntries), + m_aSubgroups(CompareGroups), + m_strName(strName) { m_pConfig = pConfig; m_pParent = pParent; @@ -627,7 +688,7 @@ wxFileConfig::LineList *wxFileConfig::ConfigGroup::GetGroupLine() 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); } @@ -688,13 +749,32 @@ wxString wxFileConfig::ConfigGroup::GetFullName() const // find an item // ---------------------------------------------------------------------------- +// use binary search because the array is sorted wxFileConfig::ConfigEntry * wxFileConfig::ConfigGroup::FindEntry(const char *szName) const { - uint nCount = m_aEntries.Count(); - for ( uint n = 0; n < nCount; n++ ) { - if ( m_aEntries[n]->Name().IsSameAs(szName, APPCONF_CASE_SENSITIVE) ) - return m_aEntries[n]; + uint i, + lo = 0, + hi = m_aEntries.Count(); + int res; + wxFileConfig::ConfigEntry *pEntry; + + while ( lo < hi ) { + i = (lo + hi)/2; + pEntry = m_aEntries[i]; + + #if APPCONF_CASE_SENSITIVE + res = strcmp(pEntry->Name(), szName); + #else + res = Stricmp(pEntry->Name(), szName); + #endif + + if ( res < 0 ) + hi = i; + else if ( res > 0 ) + lo = i + 1; + else + return pEntry; } return NULL; @@ -703,10 +783,28 @@ wxFileConfig::ConfigGroup::FindEntry(const char *szName) const wxFileConfig::ConfigGroup * wxFileConfig::ConfigGroup::FindSubgroup(const char *szName) const { - uint nCount = m_aSubgroups.Count(); - for ( uint n = 0; n < nCount; n++ ) { - if ( m_aSubgroups[n]->Name().IsSameAs(szName, APPCONF_CASE_SENSITIVE) ) - return m_aSubgroups[n]; + uint i, + lo = 0, + hi = m_aSubgroups.Count(); + int res; + wxFileConfig::ConfigGroup *pGroup; + + while ( lo < hi ) { + i = (lo + hi)/2; + pGroup = m_aSubgroups[i]; + + #if APPCONF_CASE_SENSITIVE + res = strcmp(pGroup->Name(), szName); + #else + res = Stricmp(pGroup->Name(), szName); + #endif + + if ( res < 0 ) + hi = i; + else if ( res > 0 ) + lo = i + 1; + else + return pGroup; } return NULL; @@ -755,7 +853,21 @@ bool wxFileConfig::ConfigGroup::DeleteSubgroup(const char *szName) 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; } @@ -771,13 +883,20 @@ bool wxFileConfig::ConfigGroup::DeleteEntry(const char *szName) if ( n == nCount ) return FALSE; - delete m_aEntries[n]; + 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; } // ---------------------------------------------------------------------------- -// +// // ---------------------------------------------------------------------------- void wxFileConfig::ConfigGroup::SetDirty() { @@ -793,7 +912,7 @@ void wxFileConfig::ConfigGroup::SetDirty() // ---------------------------------------------------------------------------- // ctor // ---------------------------------------------------------------------------- -wxFileConfig::ConfigEntry::ConfigEntry(wxFileConfig::ConfigGroup *pParent, +wxFileConfig::ConfigEntry::ConfigEntry(wxFileConfig::ConfigGroup *pParent, const wxString& strName, int nLine) : m_strName(strName) @@ -829,7 +948,7 @@ void wxFileConfig::ConfigEntry::SetLine(LineList *pLine) 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; } @@ -853,7 +972,7 @@ void wxFileConfig::ConfigEntry::SetValue(const wxString& strValue, bool bUser) // 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); } @@ -872,10 +991,39 @@ void wxFileConfig::ConfigEntry::SetDirty() // global functions // ============================================================================ +// ---------------------------------------------------------------------------- +// compare functions for array sorting +// ---------------------------------------------------------------------------- + +int CompareEntries(wxFileConfig::ConfigEntry *p1, + wxFileConfig::ConfigEntry *p2) +{ + #if APPCONF_CASE_SENSITIVE + return strcmp(p1->Name(), p2->Name()); + #else + return Stricmp(p1->Name(), p2->Name()); + #endif +} + +int CompareGroups(wxFileConfig::ConfigGroup *p1, + wxFileConfig::ConfigGroup *p2) +{ + #if APPCONF_CASE_SENSITIVE + return strcmp(p1->Name(), p2->Name()); + #else + return Stricmp(p1->Name(), p2->Name()); + #endif +} + +// ---------------------------------------------------------------------------- +// filter functions +// ---------------------------------------------------------------------------- + // undo FilterOut wxString FilterIn(const wxString& str) { wxString strResult; + strResult.Alloc(str.Len()); bool bQuoted = !str.IsEmpty() && str[0] == '"'; @@ -915,6 +1063,7 @@ wxString FilterIn(const wxString& str) wxString FilterOut(const wxString& str) { wxString strResult; + strResult.Alloc(str.Len()); // quoting is necessary to preserve spaces in the beginning of the string bool bQuote = isspace(str[0]) || str[0] == '"';