]> git.saurik.com Git - wxWidgets.git/blobdiff - src/common/fileconf.cpp
Removed streams from VC++ makefile for now; corrected typo in log.h
[wxWidgets.git] / src / common / fileconf.cpp
index 9a0f899135eb952f2c620caa39d058837a027911..bc0e8aa5ac01c942d35b79008ca3bf9e2cf6e94d 100644 (file)
@@ -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
 // Licence:     wxWindows license
 ///////////////////////////////////////////////////////////////////////////////
 
+#ifdef __GNUG__
+#pragma implementation "fileconf.h"
+#endif
+
 // ============================================================================
 // declarations
 // ============================================================================
@@ -36,8 +40,8 @@
 #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
 
@@ -51,7 +55,7 @@
 // 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);
@@ -127,7 +131,7 @@ wxString wxFileConfig::GetLocalFileName(const char *szFile)
 
 void wxFileConfig::Init()
 {
-  m_pCurrentGroup = 
+  m_pCurrentGroup =
   m_pRootGroup    = new ConfigGroup(NULL, "", this);
 
   m_linesHead =
@@ -177,6 +181,13 @@ wxFileConfig::~wxFileConfig()
 {
   Flush();
   delete m_pRootGroup;
+
+  LineList *pCur = m_linesHead;
+  while ( pCur != NULL ) {
+    LineList *pNext = pCur->Next();
+    delete pCur;
+    pCur = pNext;
+  }
 }
 
 // ----------------------------------------------------------------------------
@@ -187,7 +198,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 )
@@ -234,12 +245,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);
@@ -255,7 +266,7 @@ void wxFileConfig::Parse(wxTextFile& file, bool bLocal)
       wxString strKey(pStart, pEnd);
 
       // skip whitespace
-      while ( isspace(*pEnd) ) 
+      while ( isspace(*pEnd) )
         pEnd++;
 
       if ( *pEnd++ != '=' ) {
@@ -284,7 +295,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 )
@@ -293,7 +304,7 @@ void wxFileConfig::Parse(wxTextFile& file, bool bLocal)
         }
 
         // skip whitespace
-        while ( isspace(*pEnd) ) 
+        while ( isspace(*pEnd) )
           pEnd++;
 
         wxString strValue;
@@ -321,8 +332,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
@@ -388,6 +401,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
 // ----------------------------------------------------------------------------
@@ -536,25 +569,57 @@ wxFileConfig::LineList *wxFileConfig::LineListAppend(const wxString& str)
   else {
     // adjust pointers
     m_linesTail->SetNext(pLine);
+    pLine->SetPrev(m_linesTail);
   }
 
   m_linesTail = pLine;
   return m_linesTail;
 }
 
-// insert a new line after the given one
-wxFileConfig::LineList *wxFileConfig::LineListInsert(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,
                                                      LineList *pLine)
 {
-  if ( pLine == NULL )
+  if ( pLine == m_linesTail )
     return LineListAppend(str);
 
-  LineList *pNewLine = new LineList(str, pLine->Next());
-  pLine->SetNext(pNewLine);
+  LineList *pNewLine = new LineList(str);
+  if ( pLine == NULL ) {
+    // prepend to the list
+    pNewLine->SetNext(m_linesHead);
+    m_linesHead->SetPrev(pNewLine);
+    m_linesHead = pNewLine;
+  }
+  else {
+    // 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;
@@ -578,9 +643,8 @@ wxFileConfig::ConfigGroup::ConfigGroup(wxFileConfig::ConfigGroup *pParent,
   m_pParent = pParent;
   m_pLine   = NULL;
   m_bDirty  = FALSE;
-
-  m_nLastEntry = 
-  m_nLastGroup = NOT_FOUND;
+  m_pLastEntry = NULL;
+  m_pLastGroup = NULL;
 }
 
 // dtor deletes all children
@@ -616,13 +680,13 @@ 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);
     }
     else {
-      // we're the root group, yet we were not in the local file => there were
-      // only comments and blank lines in config file or nothing at all
-      // we return NULL, so that LineListInsert() will do Append()
+      // we return NULL, so that LineListInsert() will insert us in the
+      // very beginning
     }
   }
 
@@ -635,14 +699,12 @@ wxFileConfig::LineList *wxFileConfig::ConfigGroup::GetLastGroupLine()
 {
   // if we have any subgroups, our last line is the last line of the last
   // subgroup
-  if ( m_nLastGroup != NOT_FOUND ) {
-    return m_aSubgroups[m_nLastGroup]->GetLastGroupLine();
-  }
+  if ( m_pLastGroup != NULL )
+    return m_pLastGroup->GetLastGroupLine();
 
   // if we have any entries, our last line is the last entry
-  if ( m_nLastEntry != NOT_FOUND ) {
-    return m_aEntries[m_nLastEntry]->GetLine();
-  }
+  if ( m_pLastEntry != NULL )
+    return m_pLastEntry->GetLine();
 
   // nothing at all: last line is the first one
   return GetGroupLine();
@@ -652,10 +714,15 @@ wxFileConfig::LineList *wxFileConfig::ConfigGroup::GetLastGroupLine()
 // (after which we can add a new entry)
 wxFileConfig::LineList *wxFileConfig::ConfigGroup::GetLastEntryLine()
 {
-  if ( m_nLastEntry != NOT_FOUND )
-    return m_aEntries[m_nLastEntry]->GetLine();
-  else
-    return GetGroupLine();
+  if ( m_pLastEntry != NULL ) {
+    wxFileConfig::LineList *pLine = m_pLastEntry->GetLine();
+
+    wxASSERT( pLine != NULL );  // last entry must have !NULL associated line
+    return pLine;
+  }
+
+  // no entrues: insert after the group header
+  return GetGroupLine();
 }
 
 // ----------------------------------------------------------------------------
@@ -741,7 +808,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;
 }
@@ -757,13 +838,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()
 {
@@ -779,7 +867,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)
@@ -807,6 +895,7 @@ void wxFileConfig::ConfigEntry::SetLine(LineList *pLine)
   }
 
   m_pLine = pLine;
+  Group()->SetLastEntry(this);
 }
 
 // second parameter is FALSE if we read the value from file and prevents the
@@ -814,7 +903,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;
   }
@@ -838,7 +927,9 @@ void wxFileConfig::ConfigEntry::SetValue(const wxString& strValue, bool bUser)
       // add a new line to the file
       wxASSERT( m_nLine == NOT_FOUND );   // consistency check
 
-      Group()->Config()->LineListInsert(strLine, Group()->GetLastEntryLine());
+      m_pLine = Group()->Config()->LineListInsert(strLine,
+                                                  Group()->GetLastEntryLine());
+      Group()->SetLastEntry(this);
     }
 
     SetDirty();