]> git.saurik.com Git - wxWidgets.git/blobdiff - src/common/fileconf.cpp
fixed compilation problems under Windows
[wxWidgets.git] / src / common / fileconf.cpp
index 9f1aea52c0c85aa861a5f36352f0f8e4ad679bb5..f25cb997dc44770f7e6c9ec0937d90860f8346f0 100644 (file)
@@ -2,7 +2,7 @@
 // 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
-// Modified by: 
+// Modified by:
 // 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
@@ -40,8 +40,8 @@
 #include  <wx/fileconf.h>
 
 // _WINDOWS_ is defined when windows.h is included,
 #include  <wx/fileconf.h>
 
 // _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  <windows.h>
 #endif  //windows.h
 
   #include  <windows.h>
 #endif  //windows.h
 
 // 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); }
+
+// 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);
 
 // filter strings
 static wxString FilterIn(const wxString& str);
@@ -131,7 +137,7 @@ wxString wxFileConfig::GetLocalFileName(const char *szFile)
 
 void wxFileConfig::Init()
 {
 
 void wxFileConfig::Init()
 {
-  m_pCurrentGroup = 
+  m_pCurrentGroup =
   m_pRootGroup    = new ConfigGroup(NULL, "", this);
 
   m_linesHead =
   m_pRootGroup    = new ConfigGroup(NULL, "", this);
 
   m_linesHead =
@@ -181,6 +187,13 @@ wxFileConfig::~wxFileConfig()
 {
   Flush();
   delete m_pRootGroup;
 {
   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;
 {
   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 )
@@ -214,8 +227,8 @@ void wxFileConfig::Parse(wxTextFile& file, bool bLocal)
       }
 
       if ( *pEnd != ']' ) {
       }
 
       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
       }
 
         continue; // skip this line
       }
 
@@ -238,12 +251,12 @@ void wxFileConfig::Parse(wxTextFile& file, bool 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);
@@ -259,7 +272,7 @@ void wxFileConfig::Parse(wxTextFile& file, bool bLocal)
       wxString strKey(pStart, pEnd);
 
       // skip whitespace
       wxString strKey(pStart, pEnd);
 
       // skip whitespace
-      while ( isspace(*pEnd) ) 
+      while ( isspace(*pEnd) )
         pEnd++;
 
       if ( *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() ) {
           //  (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 )
@@ -297,7 +310,7 @@ void wxFileConfig::Parse(wxTextFile& file, bool bLocal)
         }
 
         // skip whitespace
         }
 
         // skip whitespace
-        while ( isspace(*pEnd) ) 
+        while ( isspace(*pEnd) )
           pEnd++;
 
         wxString strValue;
           pEnd++;
 
         wxString strValue;
@@ -325,8 +338,10 @@ void wxFileConfig::SetPath(const wxString& strPath)
 {
   wxArrayString aParts;
 
 {
   wxArrayString aParts;
 
-  if ( strPath.IsEmpty() )
+  if ( strPath.IsEmpty() ) {
+    SetRootPath();
     return;
     return;
+  }
 
   if ( strPath[0] == APPCONF_PATH_SEPARATOR ) {
     // absolute path
 
   if ( strPath[0] == APPCONF_PATH_SEPARATOR ) {
     // absolute path
@@ -392,6 +407,26 @@ bool wxFileConfig::GetNextEntry (wxString& str, long& lIndex)
     return FALSE;
 }
 
     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
 // ----------------------------------------------------------------------------
 // ----------------------------------------------------------------------------
 // read/write values
 // ----------------------------------------------------------------------------
@@ -540,6 +575,7 @@ wxFileConfig::LineList *wxFileConfig::LineListAppend(const wxString& str)
   else {
     // adjust pointers
     m_linesTail->SetNext(pLine);
   else {
     // adjust pointers
     m_linesTail->SetNext(pLine);
+    pLine->SetPrev(m_linesTail);
   }
 
   m_linesTail = pLine;
   }
 
   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
 }
 
 // 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;
-  
+  LineList *pNewLine = new LineList(str);
   if ( pLine == NULL ) {
   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 {
     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;
@@ -584,7 +643,9 @@ bool wxFileConfig::LineListIsEmpty()
 wxFileConfig::ConfigGroup::ConfigGroup(wxFileConfig::ConfigGroup *pParent,
                                        const wxString& strName,
                                        wxFileConfig *pConfig)
 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;
 {
   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 '/'
     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);
     }
@@ -688,13 +749,32 @@ wxString wxFileConfig::ConfigGroup::GetFullName() const
 // find an item
 // ----------------------------------------------------------------------------
 
 // find an item
 // ----------------------------------------------------------------------------
 
+// use binary search because the array is sorted
 wxFileConfig::ConfigEntry *
 wxFileConfig::ConfigGroup::FindEntry(const char *szName) const
 {
 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;
   }
 
   return NULL;
@@ -703,10 +783,28 @@ wxFileConfig::ConfigGroup::FindEntry(const char *szName) const
 wxFileConfig::ConfigGroup *
 wxFileConfig::ConfigGroup::FindSubgroup(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;
   }
 
   return NULL;
@@ -755,7 +853,21 @@ bool wxFileConfig::ConfigGroup::DeleteSubgroup(const char *szName)
   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;
 }
@@ -771,13 +883,20 @@ bool wxFileConfig::ConfigGroup::DeleteEntry(const char *szName)
   if ( n == nCount )
     return FALSE;
 
   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;
 }
 
 // ----------------------------------------------------------------------------
   m_aEntries.Remove(n);
   return TRUE;
 }
 
 // ----------------------------------------------------------------------------
-// 
+//
 // ----------------------------------------------------------------------------
 void wxFileConfig::ConfigGroup::SetDirty()
 {
 // ----------------------------------------------------------------------------
 void wxFileConfig::ConfigGroup::SetDirty()
 {
@@ -793,7 +912,7 @@ 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)
@@ -829,7 +948,7 @@ void wxFileConfig::ConfigEntry::SetLine(LineList *pLine)
 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;
   }
@@ -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
 
       // 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);
     }
@@ -872,10 +991,39 @@ void wxFileConfig::ConfigEntry::SetDirty()
 // global functions
 // ============================================================================
 
 // 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;
 // undo FilterOut
 wxString FilterIn(const wxString& str)
 {
   wxString strResult;
+  strResult.Alloc(str.Len());
 
   bool bQuoted = !str.IsEmpty() && str[0] == '"';
 
 
   bool bQuoted = !str.IsEmpty() && str[0] == '"';
 
@@ -915,6 +1063,7 @@ wxString FilterIn(const wxString& str)
 wxString FilterOut(const wxString& str)
 {
   wxString strResult;
 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] == '"';
 
   // quoting is necessary to preserve spaces in the beginning of the string
   bool bQuote = isspace(str[0]) || str[0] == '"';