]> git.saurik.com Git - wxWidgets.git/blobdiff - src/common/fileconf.cpp
test for timegm() added
[wxWidgets.git] / src / common / fileconf.cpp
index ae3f3087dc6521bcf839eb4a696ff5fa73fa77f1..54bc21641a83d76157a032d94ba8e223c1e00699 100644 (file)
 #pragma implementation "fileconf.h"
 #endif
 
 #pragma implementation "fileconf.h"
 #endif
 
-// ============================================================================
-// declarations
-// ============================================================================
-
 // ----------------------------------------------------------------------------
 // headers
 // ----------------------------------------------------------------------------
 // ----------------------------------------------------------------------------
 // headers
 // ----------------------------------------------------------------------------
+
 #include  "wx/wxprec.h"
 
 #ifdef    __BORLANDC__
   #pragma hdrstop
 #endif  //__BORLANDC__
 
 #include  "wx/wxprec.h"
 
 #ifdef    __BORLANDC__
   #pragma hdrstop
 #endif  //__BORLANDC__
 
+#if wxUSE_CONFIG
+
 #ifndef   WX_PRECOMP
 #ifndef   WX_PRECOMP
-  #include  <wx/string.h>
-  #include  <wx/intl.h>
+  #include  "wx/string.h"
+  #include  "wx/intl.h"
 #endif  //WX_PRECOMP
 
 #endif  //WX_PRECOMP
 
-#include  <wx/dynarray.h>
-#include  <wx/file.h>
-#include  <wx/log.h>
-#include  <wx/textfile.h>
-#include  <wx/config.h>
-#include  <wx/fileconf.h>
+#include  "wx/app.h"
+#include  "wx/dynarray.h"
+#include  "wx/file.h"
+#include  "wx/log.h"
+#include  "wx/textfile.h"
+#include  "wx/config.h"
+#include  "wx/fileconf.h"
+
+#include  "wx/utils.h"    // for wxGetHomeDir
 
 // _WINDOWS_ is defined when windows.h is included,
 // __WXMSW__ is defined for MS Windows compilation
 #if       defined(__WXMSW__) && !defined(_WINDOWS_)
   #include  <windows.h>
 #endif  //windows.h
 
 // _WINDOWS_ is defined when windows.h is included,
 // __WXMSW__ is defined for MS Windows compilation
 #if       defined(__WXMSW__) && !defined(_WINDOWS_)
   #include  <windows.h>
 #endif  //windows.h
+#if defined(__WXPM__)
+  #define INCL_DOS
+  #include <os2.h>
+  #define LINKAGEMODE _Optlink
+#else
+  #define LINKAGEMODE
+#endif
 
 #include  <stdlib.h>
 #include  <ctype.h>
 
 #include  <stdlib.h>
 #include  <ctype.h>
 #define CONST_CAST ((wxFileConfig *)this)->
 
 // ----------------------------------------------------------------------------
 #define CONST_CAST ((wxFileConfig *)this)->
 
 // ----------------------------------------------------------------------------
-// global functions declarations
+// constants
 // ----------------------------------------------------------------------------
 // ----------------------------------------------------------------------------
+#ifndef MAX_PATH
+  #define MAX_PATH 512
+#endif
 
 
-// is 'c' a valid character in group name?
-// NB: wxCONFIG_IMMUTABLE_PREFIX and wxCONFIG_PATH_SEPARATOR must be valid chars,
-//     but _not_ ']' (group name delimiter)
-inline bool IsValid(char c) { return isalnum(c) || strchr("@_/-!.*%", c); }
+// ----------------------------------------------------------------------------
+// global functions declarations
+// ----------------------------------------------------------------------------
 
 // compare functions for sorting the arrays
 
 // compare functions for sorting the arrays
-static int CompareEntries(wxFileConfig::ConfigEntry *p1,
-                          wxFileConfig::ConfigEntry *p2);
-static int CompareGroups(wxFileConfig::ConfigGroup *p1,
-                         wxFileConfig::ConfigGroup *p2);
+static int LINKAGEMODE CompareEntries(ConfigEntry *p1, ConfigEntry *p2);
+static int LINKAGEMODE CompareGroups(ConfigGroup *p1, ConfigGroup *p2);
 
 // filter strings
 
 // filter strings
-static wxString FilterIn(const wxString& str);
-static wxString FilterOut(const wxString& str);
+static wxString FilterInValue(const wxString& str);
+static wxString FilterOutValue(const wxString& str);
+
+static wxString FilterInEntryName(const wxString& str);
+static wxString FilterOutEntryName(const wxString& str);
+
+// get the name to use in wxFileConfig ctor
+static wxString GetAppName(const wxString& appname);
 
 // ============================================================================
 // implementation
 
 // ============================================================================
 // implementation
@@ -83,18 +98,123 @@ wxString wxFileConfig::GetGlobalDir()
 {
   wxString strDir;
 
 {
   wxString strDir;
 
-  #ifdef __UNIX__
-    strDir = "/etc/";
+  #ifdef __VMS__ // Note if __VMS is defined __UNIX is also defined
+    strDir = wxT("sys$manager:");
+  #elif defined( __UNIX__ )
+    strDir = wxT("/etc/");
+  #elif defined(__WXPM__)
+    ULONG                           aulSysInfo[QSV_MAX] = {0};
+    UINT                            drive;
+    APIRET                          rc;
+
+    rc = DosQuerySysInfo( 1L, QSV_MAX, (PVOID)aulSysInfo, sizeof(ULONG)*QSV_MAX);
+    if (rc == 0)
+    {
+        drive = aulSysInfo[QSV_BOOT_DRIVE - 1];
+        switch(drive)
+        {
+           case 1:
+              strDir = "A:\\OS2\\";
+              break;
+           case 2:
+              strDir = "B:\\OS2\\";
+              break;
+           case 3:
+              strDir = "C:\\OS2\\";
+              break;
+           case 4:
+              strDir = "D:\\OS2\\";
+              break;
+           case 5:
+              strDir = "E:\\OS2\\";
+              break;
+           case 6:
+              strDir = "F:\\OS2\\";
+              break;
+           case 7:
+              strDir = "G:\\OS2\\";
+              break;
+           case 8:
+              strDir = "H:\\OS2\\";
+              break;
+           case 9:
+              strDir = "I:\\OS2\\";
+              break;
+           case 10:
+              strDir = "J:\\OS2\\";
+              break;
+           case 11:
+              strDir = "K:\\OS2\\";
+              break;
+           case 12:
+              strDir = "L:\\OS2\\";
+              break;
+           case 13:
+              strDir = "M:\\OS2\\";
+              break;
+           case 14:
+              strDir = "N:\\OS2\\";
+              break;
+           case 15:
+              strDir = "O:\\OS2\\";
+              break;
+           case 16:
+              strDir = "P:\\OS2\\";
+              break;
+           case 17:
+              strDir = "Q:\\OS2\\";
+              break;
+           case 18:
+              strDir = "R:\\OS2\\";
+              break;
+           case 19:
+              strDir = "S:\\OS2\\";
+              break;
+           case 20:
+              strDir = "T:\\OS2\\";
+              break;
+           case 21:
+              strDir = "U:\\OS2\\";
+              break;
+           case 22:
+              strDir = "V:\\OS2\\";
+              break;
+           case 23:
+              strDir = "W:\\OS2\\";
+              break;
+           case 24:
+              strDir = "X:\\OS2\\";
+              break;
+           case 25:
+              strDir = "Y:\\OS2\\";
+              break;
+           case 26:
+              strDir = "Z:\\OS2\\";
+              break;
+        }
+    }
+  #elif defined(__WXSTUBS__)
+    wxASSERT_MSG( FALSE, wxT("TODO") ) ;
+  #elif defined(__WXMAC__)
+  {
+               short           vRefNum  ;
+               long            dirID ;
+               
+               if ( FindFolder( (short) kOnSystemDisk, kPreferencesFolderType, kDontCreateFolder, &vRefNum, &dirID) == noErr)
+               {
+                       FSSpec file ;
+                       if ( FSMakeFSSpec( vRefNum , dirID , "\p" , &file ) == noErr )
+                       {
+                               strDir = wxMacFSSpec2UnixFilename( &file ) + "/" ;
+                       }
+               }
+  }
   #else // Windows
   #else // Windows
-    #ifndef _MAX_PATH
-      #define _MAX_PATH 512
-    #endif
-
-    char szWinDir[_MAX_PATH];
-    ::GetWindowsDirectory(szWinDir, _MAX_PATH);
+    wxChar szWinDir[MAX_PATH];
+    ::GetWindowsDirectory(szWinDir, MAX_PATH);
 
     strDir = szWinDir;
 
     strDir = szWinDir;
-    strDir << '\\';
+    strDir << wxT('\\');
   #endif // Unix/Windows
 
   return strDir;
   #endif // Unix/Windows
 
   return strDir;
@@ -104,61 +224,66 @@ wxString wxFileConfig::GetLocalDir()
 {
   wxString strDir;
 
 {
   wxString strDir;
 
-  #ifdef __UNIX__
-    const char *szHome = getenv("HOME");
-    if ( szHome == NULL ) {
-      // we're homeless...
-      wxLogWarning(_("can't find user's HOME, using current directory."));
-      strDir = ".";
-    }
-    else
-      strDir = szHome;
-  #else   // Windows
-    #ifdef  __WIN32__
-      const char *szHome = getenv("HOMEDRIVE");
-      if ( szHome != NULL )
-        strDir << szHome;
-      szHome = getenv("HOMEPATH");
-      if ( szHome != NULL )
-        strDir << szHome;
-    #else   // Win16
-      // Win16 has no idea about home, so use the current directory instead
-      strDir = ".\\";
-    #endif  // WIN16/32
-  #endif  // UNIX/Win
+#ifndef __WXMAC__
+  wxGetHomeDir(&strDir);
+
+#ifndef __VMS__
+# ifdef  __UNIX__
+  if (strDir.Last() != wxT('/')) strDir << wxT('/');
+#else
+  if (strDir.Last() != wxT('\\')) strDir << wxT('\\');
+#endif
+#endif
+#else
+       // no local dir concept on mac
+       return GetGlobalDir() ;
+#endif
 
   return strDir;
 }
 
 
   return strDir;
 }
 
-wxString wxFileConfig::GetGlobalFileName(const char *szFile)
+wxString wxFileConfig::GetGlobalFileName(const wxChar *szFile)
 {
 {
-  wxString str = GetLocalDir();
+  wxString str = GetGlobalDir();
   str << szFile;
 
   str << szFile;
 
-  if ( strchr(szFile, '.') == NULL )
+  if ( wxStrchr(szFile, wxT('.')) == NULL )
   #ifdef  __UNIX__
   #ifdef  __UNIX__
-    str << ".conf";
+    str << wxT(".conf");
+  #elif defined( __WXMAC__ )
+     str << " Preferences";
   #else   // Windows
   #else   // Windows
-    str << ".ini";
+    str << wxT(".ini");
   #endif  // UNIX/Win
 
   return str;
 }
 
   #endif  // UNIX/Win
 
   return str;
 }
 
-wxString wxFileConfig::GetLocalFileName(const char *szFile)
+wxString wxFileConfig::GetLocalFileName(const wxChar *szFile)
 {
 {
-  wxString str = GetLocalDir();
-
+#ifdef __VMS__ // On VMS I saw the problem that the home directory was appended
+   // twice for the configuration file. Does that also happen for other
+   // platforms?
+   wxString str = wxT( ' ' ); 
+#else
+   wxString str = GetLocalDir();
+#endif
+   
   #ifdef  __UNIX__
   #ifdef  __UNIX__
-    str << '.';
+    str << wxT('.');
   #endif
 
   str << szFile;
 
   #ifdef __WXMSW__
   #endif
 
   str << szFile;
 
   #ifdef __WXMSW__
-    str << ".ini";
+    if ( wxStrchr(szFile, wxT('.')) == NULL )
+      str << wxT(".ini");
   #endif
 
   #endif
 
+
+  #ifdef __WXMAC__
+     str << " Preferences";
+  #endif
   return str;
 }
 
   return str;
 }
 
@@ -202,30 +327,52 @@ void wxFileConfig::Init()
   }
 }
 
   }
 }
 
-wxFileConfig::wxFileConfig(const char *szAppName, bool bLocalOnly)
+// constructor supports creation of wxFileConfig objects of any type
+wxFileConfig::wxFileConfig(const wxString& appName, const wxString& vendorName,
+                           const wxString& strLocal, const wxString& strGlobal,
+                           long style)
+            : wxConfigBase(::GetAppName(appName), vendorName,
+                           strLocal, strGlobal,
+                           style),
+              m_strLocalFile(strLocal), m_strGlobalFile(strGlobal)
 {
 {
-  wxASSERT( !IsEmpty(szAppName) ); // invent a name for your application!
+  // Make up names for files if empty
+  if ( m_strLocalFile.IsEmpty() && (style & wxCONFIG_USE_LOCAL_FILE) )
+  {
+    m_strLocalFile = GetLocalFileName(GetAppName());
+  }
 
 
-  m_strLocalFile = GetLocalFileName(szAppName);
-  if ( !bLocalOnly )
-    m_strGlobalFile = GetGlobalFileName(szAppName);
-  //else: it's going to be empty and we won't use the global file
+  if ( m_strGlobalFile.IsEmpty() && (style & wxCONFIG_USE_GLOBAL_FILE) )
+  {
+    m_strGlobalFile = GetGlobalFileName(GetAppName());
+  }
 
 
-  Init();
-}
+  // Check if styles are not supplied, but filenames are, in which case
+  // add the correct styles.
+  if ( !m_strLocalFile.IsEmpty() )
+    SetStyle(GetStyle() | wxCONFIG_USE_LOCAL_FILE);
 
 
-wxFileConfig::wxFileConfig(const wxString& strLocal, const wxString& strGlobal)
-            : m_strLocalFile(strLocal), m_strGlobalFile(strGlobal)
-{
-  // if the path is not absolute, prepend the standard directory to it
+  if ( !m_strGlobalFile.IsEmpty() )
+    SetStyle(GetStyle() | wxCONFIG_USE_GLOBAL_FILE);
 
 
-  if ( !strLocal.IsEmpty() && !wxIsPathSeparator(strLocal[0u]) )
-    m_strLocalFile = GetLocalDir();
-  m_strLocalFile << strLocal;
+  // if the path is not absolute, prepend the standard directory to it
+  // UNLESS wxCONFIG_USE_RELATIVE_PATH style is set
+  if ( !(style & wxCONFIG_USE_RELATIVE_PATH) )
+  {
+      if ( !m_strLocalFile.IsEmpty() && !wxIsAbsolutePath(m_strLocalFile) )
+      {
+          wxString strLocal = m_strLocalFile;
+          m_strLocalFile = GetLocalDir();
+          m_strLocalFile << strLocal;
+      }
 
 
-  if ( !strGlobal.IsEmpty() && !wxIsPathSeparator(strGlobal[0u]) )
-    m_strGlobalFile = GetGlobalDir();
-  m_strGlobalFile << strGlobal;
+      if ( !m_strGlobalFile.IsEmpty() && !wxIsAbsolutePath(m_strGlobalFile) )
+      {
+          wxString strGlobal = m_strGlobalFile;
+          m_strGlobalFile = GetGlobalDir();
+          m_strGlobalFile << strGlobal;
+      }
+  }
 
   Init();
 }
 
   Init();
 }
@@ -255,12 +402,12 @@ wxFileConfig::~wxFileConfig()
 
 void wxFileConfig::Parse(wxTextFile& file, bool bLocal)
 {
 
 void wxFileConfig::Parse(wxTextFile& file, bool bLocal)
 {
-  const char *pStart;
-  const char *pEnd;
+  const wxChar *pStart;
+  const wxChar *pEnd;
   wxString strLine;
 
   wxString strLine;
 
-  uint nLineCount = file.GetLineCount();
-  for ( uint n = 0; n < nLineCount; n++ ) {
+  size_t nLineCount = file.GetLineCount();
+  for ( size_t n = 0; n < nLineCount; n++ ) {
     strLine = file[n];
 
     // add the line to linked list
     strLine = file[n];
 
     // add the line to linked list
@@ -268,22 +415,22 @@ void wxFileConfig::Parse(wxTextFile& file, bool bLocal)
       LineListAppend(strLine);
 
     // skip leading spaces
       LineListAppend(strLine);
 
     // skip leading spaces
-    for ( pStart = strLine; isspace(*pStart); pStart++ )
+    for ( pStart = strLine; wxIsspace(*pStart); pStart++ )
       ;
 
     // skip blank/comment lines
       ;
 
     // skip blank/comment lines
-    if ( *pStart == '\0'|| *pStart == ';' || *pStart == '#' )
+    if ( *pStart == wxT('\0')|| *pStart == wxT(';') || *pStart == wxT('#') )
       continue;
 
       continue;
 
-    if ( *pStart == '[' ) {          // a new group
+    if ( *pStart == wxT('[') ) {          // a new group
       pEnd = pStart;
 
       pEnd = pStart;
 
-      while ( *++pEnd != ']' ) {
-        if ( !IsValid(*pEnd) && *pEnd != ' ' )  // allow spaces in group names
-          break;
+      while ( *++pEnd != wxT(']') ) {
+        if ( *pEnd == wxT('\n') || *pEnd == wxT('\0') )
+            break;
       }
 
       }
 
-      if ( *pEnd != ']' ) {
+      if ( *pEnd != wxT(']') ) {
         wxLogError(_("file '%s': unexpected character %c at line %d."),
                    file.GetName(), *pEnd, n + 1);
         continue; // skip this line
         wxLogError(_("file '%s': unexpected character %c at line %d."),
                    file.GetName(), *pEnd, n + 1);
         continue; // skip this line
@@ -292,7 +439,8 @@ void wxFileConfig::Parse(wxTextFile& file, bool bLocal)
       // group name here is always considered as abs path
       wxString strGroup;
       pStart++;
       // group name here is always considered as abs path
       wxString strGroup;
       pStart++;
-      strGroup << wxCONFIG_PATH_SEPARATOR << wxString(pStart, pEnd - pStart);
+      strGroup << wxCONFIG_PATH_SEPARATOR
+               << FilterInEntryName(wxString(pStart, pEnd - pStart));
 
       // will create it if doesn't yet exist
       SetPath(strGroup);
 
       // will create it if doesn't yet exist
       SetPath(strGroup);
@@ -302,15 +450,15 @@ void wxFileConfig::Parse(wxTextFile& file, bool bLocal)
 
       // check that there is nothing except comments left on this line
       bool bCont = TRUE;
 
       // check that there is nothing except comments left on this line
       bool bCont = TRUE;
-      while ( *++pEnd != '\0' && bCont ) {
+      while ( *++pEnd != wxT('\0') && bCont ) {
         switch ( *pEnd ) {
         switch ( *pEnd ) {
-          case '#':
-          case ';':
+          case wxT('#'):
+          case wxT(';'):
             bCont = FALSE;
             break;
 
             bCont = FALSE;
             break;
 
-          case ' ':
-          case '\t':
+          case wxT(' '):
+          case wxT('\t'):
             // ignore whitespace ('\n' impossible here)
             break;
 
             // ignore whitespace ('\n' impossible here)
             break;
 
@@ -323,17 +471,24 @@ void wxFileConfig::Parse(wxTextFile& file, bool bLocal)
       }
     }
     else {                        // a key
       }
     }
     else {                        // a key
-      const char *pEnd = pStart;
-      while ( IsValid(*pEnd) )
+      const wxChar *pEnd = pStart;
+      while ( *pEnd != wxT('=') && !wxIsspace(*pEnd) ) {
+        if ( *pEnd == wxT('\\') ) {
+          // next character may be space or not - still take it because it's
+          // quoted
+          pEnd++;
+        }
+
         pEnd++;
         pEnd++;
+      }
 
 
-      wxString strKey(pStart, pEnd);
+      wxString strKey(FilterInEntryName(wxString(pStart, pEnd)));
 
       // skip whitespace
       while ( isspace(*pEnd) )
         pEnd++;
 
 
       // skip whitespace
       while ( isspace(*pEnd) )
         pEnd++;
 
-      if ( *pEnd++ != '=' ) {
+      if ( *pEnd++ != wxT('=') ) {
         wxLogError(_("file '%s', line %d: '=' expected."),
                    file.GetName(), n + 1);
       }
         wxLogError(_("file '%s', line %d: '=' expected."),
                    file.GetName(), n + 1);
       }
@@ -371,10 +526,10 @@ void wxFileConfig::Parse(wxTextFile& file, bool bLocal)
         }
 
         // skip whitespace
         }
 
         // skip whitespace
-        while ( isspace(*pEnd) )
+        while ( wxIsspace(*pEnd) )
           pEnd++;
 
           pEnd++;
 
-        pEntry->SetValue(FilterIn(pEnd), FALSE /* read from file */);
+        pEntry->SetValue(FilterInValue(pEnd), FALSE /* read from file */);
       }
     }
   }
       }
     }
   }
@@ -411,7 +566,7 @@ void wxFileConfig::SetPath(const wxString& strPath)
   }
 
   // change current group
   }
 
   // change current group
-  uint n;
+  size_t n;
   m_pCurrentGroup = m_pRootGroup;
   for ( n = 0; n < aParts.Count(); n++ ) {
     ConfigGroup *pNextGroup = m_pCurrentGroup->FindSubgroup(aParts[n]);
   m_pCurrentGroup = m_pRootGroup;
   for ( n = 0; n < aParts.Count(); n++ ) {
     ConfigGroup *pNextGroup = m_pCurrentGroup->FindSubgroup(aParts[n]);
@@ -431,15 +586,15 @@ void wxFileConfig::SetPath(const wxString& strPath)
 // enumeration
 // ----------------------------------------------------------------------------
 
 // enumeration
 // ----------------------------------------------------------------------------
 
-bool wxFileConfig::GetFirstGroup(wxString& str, long& lIndex)
+bool wxFileConfig::GetFirstGroup(wxString& str, long& lIndex) const
 {
   lIndex = 0;
   return GetNextGroup(str, lIndex);
 }
 
 {
   lIndex = 0;
   return GetNextGroup(str, lIndex);
 }
 
-bool wxFileConfig::GetNextGroup (wxString& str, long& lIndex)
+bool wxFileConfig::GetNextGroup (wxString& str, long& lIndex) const
 {
 {
-  if ( uint(lIndex) < m_pCurrentGroup->Groups().Count() ) {
+  if ( size_t(lIndex) < m_pCurrentGroup->Groups().Count() ) {
     str = m_pCurrentGroup->Groups()[lIndex++]->Name();
     return TRUE;
   }
     str = m_pCurrentGroup->Groups()[lIndex++]->Name();
     return TRUE;
   }
@@ -447,15 +602,15 @@ bool wxFileConfig::GetNextGroup (wxString& str, long& lIndex)
     return FALSE;
 }
 
     return FALSE;
 }
 
-bool wxFileConfig::GetFirstEntry(wxString& str, long& lIndex)
+bool wxFileConfig::GetFirstEntry(wxString& str, long& lIndex) const
 {
   lIndex = 0;
   return GetNextEntry(str, lIndex);
 }
 
 {
   lIndex = 0;
   return GetNextEntry(str, lIndex);
 }
 
-bool wxFileConfig::GetNextEntry (wxString& str, long& lIndex)
+bool wxFileConfig::GetNextEntry (wxString& str, long& lIndex) const
 {
 {
-  if ( uint(lIndex) < m_pCurrentGroup->Entries().Count() ) {
+  if ( size_t(lIndex) < m_pCurrentGroup->Entries().Count() ) {
     str = m_pCurrentGroup->Entries()[lIndex++]->Name();
     return TRUE;
   }
     str = m_pCurrentGroup->Entries()[lIndex++]->Name();
     return TRUE;
   }
@@ -463,13 +618,13 @@ bool wxFileConfig::GetNextEntry (wxString& str, long& lIndex)
     return FALSE;
 }
 
     return FALSE;
 }
 
-uint wxFileConfig::GetNumberOfEntries(bool bRecursive) const
+size_t wxFileConfig::GetNumberOfEntries(bool bRecursive) const
 {
 {
-  uint n = m_pCurrentGroup->Entries().Count();
+  size_t n = m_pCurrentGroup->Entries().Count();
   if ( bRecursive ) {
     ConfigGroup *pOldCurrentGroup = m_pCurrentGroup;
   if ( bRecursive ) {
     ConfigGroup *pOldCurrentGroup = m_pCurrentGroup;
-    uint nSubgroups = m_pCurrentGroup->Groups().Count();
-    for ( uint nGroup = 0; nGroup < nSubgroups; nGroup++ ) {
+    size_t nSubgroups = m_pCurrentGroup->Groups().Count();
+    for ( size_t nGroup = 0; nGroup < nSubgroups; nGroup++ ) {
       CONST_CAST m_pCurrentGroup = m_pCurrentGroup->Groups()[nGroup];
       n += GetNumberOfEntries(TRUE);
       CONST_CAST m_pCurrentGroup = pOldCurrentGroup;
       CONST_CAST m_pCurrentGroup = m_pCurrentGroup->Groups()[nGroup];
       n += GetNumberOfEntries(TRUE);
       CONST_CAST m_pCurrentGroup = pOldCurrentGroup;
@@ -479,13 +634,13 @@ uint wxFileConfig::GetNumberOfEntries(bool bRecursive) const
   return n;
 }
 
   return n;
 }
 
-uint wxFileConfig::GetNumberOfGroups(bool bRecursive) const
+size_t wxFileConfig::GetNumberOfGroups(bool bRecursive) const
 {
 {
-  uint n = m_pCurrentGroup->Groups().Count();
+  size_t n = m_pCurrentGroup->Groups().Count();
   if ( bRecursive ) {
     ConfigGroup *pOldCurrentGroup = m_pCurrentGroup;
   if ( bRecursive ) {
     ConfigGroup *pOldCurrentGroup = m_pCurrentGroup;
-    uint nSubgroups = m_pCurrentGroup->Groups().Count();
-    for ( uint nGroup = 0; nGroup < nSubgroups; nGroup++ ) {
+    size_t nSubgroups = m_pCurrentGroup->Groups().Count();
+    for ( size_t nGroup = 0; nGroup < nSubgroups; nGroup++ ) {
       CONST_CAST m_pCurrentGroup = m_pCurrentGroup->Groups()[nGroup];
       n += GetNumberOfGroups(TRUE);
       CONST_CAST m_pCurrentGroup = pOldCurrentGroup;
       CONST_CAST m_pCurrentGroup = m_pCurrentGroup->Groups()[nGroup];
       n += GetNumberOfGroups(TRUE);
       CONST_CAST m_pCurrentGroup = pOldCurrentGroup;
@@ -501,7 +656,7 @@ uint wxFileConfig::GetNumberOfGroups(bool bRecursive) const
 
 bool wxFileConfig::HasGroup(const wxString& strName) const
 {
 
 bool wxFileConfig::HasGroup(const wxString& strName) const
 {
-  PathChanger path(this, strName);
+  wxConfigPathChanger path(this, strName);
 
   ConfigGroup *pGroup = m_pCurrentGroup->FindSubgroup(path.Name());
   return pGroup != NULL;
 
   ConfigGroup *pGroup = m_pCurrentGroup->FindSubgroup(path.Name());
   return pGroup != NULL;
@@ -509,7 +664,7 @@ bool wxFileConfig::HasGroup(const wxString& strName) const
 
 bool wxFileConfig::HasEntry(const wxString& strName) const
 {
 
 bool wxFileConfig::HasEntry(const wxString& strName) const
 {
-  PathChanger path(this, strName);
+  wxConfigPathChanger path(this, strName);
 
   ConfigEntry *pEntry = m_pCurrentGroup->FindEntry(path.Name());
   return pEntry != NULL;
 
   ConfigEntry *pEntry = m_pCurrentGroup->FindEntry(path.Name());
   return pEntry != NULL;
@@ -519,53 +674,59 @@ bool wxFileConfig::HasEntry(const wxString& strName) const
 // read/write values
 // ----------------------------------------------------------------------------
 
 // read/write values
 // ----------------------------------------------------------------------------
 
-bool wxFileConfig::Read(wxString   *pstr,
-                        const char *szKey,
-                        const char *szDefault) const
+bool wxFileConfig::Read(const wxString& key,
+                        wxString* pStr) const
 {
 {
-  PathChanger path(this, szKey);
+  wxConfigPathChanger path(this, key);
 
   ConfigEntry *pEntry = m_pCurrentGroup->FindEntry(path.Name());
   if (pEntry == NULL) {
 
   ConfigEntry *pEntry = m_pCurrentGroup->FindEntry(path.Name());
   if (pEntry == NULL) {
-    *pstr = ExpandEnvVars(szDefault);
     return FALSE;
   }
   else {
     return FALSE;
   }
   else {
-    *pstr = ExpandEnvVars(pEntry->Value());
+    *pStr = ExpandEnvVars(pEntry->Value());
     return TRUE;
   }
 }
 
     return TRUE;
   }
 }
 
-const char *wxFileConfig::Read(const char *szKey,
-                               const char *szDefault) const
+bool wxFileConfig::Read(const wxString& key,
+                        wxString* pStr, const wxString& defVal) const
 {
 {
-  static wxString s_str;
-  Read(&s_str, szKey, szDefault);
+  wxConfigPathChanger path(this, key);
 
 
-  return s_str.c_str();
+  ConfigEntry *pEntry = m_pCurrentGroup->FindEntry(path.Name());
+  if (pEntry == NULL) {
+    if( IsRecordingDefaults() )
+      ((wxFileConfig *)this)->Write(key,defVal);
+    *pStr = ExpandEnvVars(defVal);
+    return FALSE;
+  }
+  else {
+    *pStr = ExpandEnvVars(pEntry->Value());
+    return TRUE;
+  }
 }
 
 }
 
-bool wxFileConfig::Read(long *pl, const char *szKey, long lDefault) const
+bool wxFileConfig::Read(const wxString& key, long *pl) const
 {
   wxString str;
 {
   wxString str;
-  if ( Read(&str, szKey) ) {
-    *pl = atol(str);
+  if ( Read(key, & str) ) {
+    *pl = wxAtol(str);
     return TRUE;
   }
   else {
     return TRUE;
   }
   else {
-    *pl = lDefault;
     return FALSE;
   }
 }
 
     return FALSE;
   }
 }
 
-bool wxFileConfig::Write(const char *szKey, const char *szValue)
+bool wxFileConfig::Write(const wxString& key, const wxString& szValue)
 {
 {
-  PathChanger path(this, szKey);
+  wxConfigPathChanger path(this, key);
 
   wxString strName = path.Name();
   if ( strName.IsEmpty() ) {
     // setting the value of a group is an error
 
   wxString strName = path.Name();
   if ( strName.IsEmpty() ) {
     // setting the value of a group is an error
-    wxASSERT_MSG( IsEmpty(szValue), "can't set value of a group!" );
+    wxASSERT_MSG( wxIsEmpty(szValue), wxT("can't set value of a group!") );
 
     // ... except if it's empty in which case it's a way to force it's creation
     m_pCurrentGroup->SetDirty();
 
     // ... except if it's empty in which case it's a way to force it's creation
     m_pCurrentGroup->SetDirty();
@@ -578,19 +739,11 @@ bool wxFileConfig::Write(const char *szKey, const char *szValue)
 
     // check that the name is reasonable
     if ( strName[0u] == wxCONFIG_IMMUTABLE_PREFIX ) {
 
     // check that the name is reasonable
     if ( strName[0u] == wxCONFIG_IMMUTABLE_PREFIX ) {
-      wxLogError(_("Entry name can't start with '%c'."),
+      wxLogError(_("Config entry name cannot start with '%c'."),
                  wxCONFIG_IMMUTABLE_PREFIX);
       return FALSE;
     }
 
                  wxCONFIG_IMMUTABLE_PREFIX);
       return FALSE;
     }
 
-    for ( const char *pc = strName; *pc != '\0'; pc++ ) {
-      if ( !IsValid(*pc) ) {
-        wxLogError(_("Character '%c' is invalid in a config entry name."),
-                   *pc);
-        return FALSE;
-      }
-    }
-
     ConfigEntry *pEntry = m_pCurrentGroup->FindEntry(strName);
     if ( pEntry == NULL )
       pEntry = m_pCurrentGroup->AddEntry(strName);
     ConfigEntry *pEntry = m_pCurrentGroup->FindEntry(strName);
     if ( pEntry == NULL )
       pEntry = m_pCurrentGroup->AddEntry(strName);
@@ -601,12 +754,12 @@ bool wxFileConfig::Write(const char *szKey, const char *szValue)
   return TRUE;
 }
 
   return TRUE;
 }
 
-bool wxFileConfig::Write(const char *szKey, long lValue)
+bool wxFileConfig::Write(const wxString& key, long lValue)
 {
   // ltoa() is not ANSI :-(
 {
   // ltoa() is not ANSI :-(
-  char szBuf[40];   // should be good for sizeof(long) <= 16 (128 bits)
-  sprintf(szBuf, "%ld", lValue);
-  return Write(szKey, szBuf);
+  wxString buf;
+  buf.Printf(wxT("%ld"), lValue);
+  return Write(key, buf);
 }
 
 bool wxFileConfig::Flush(bool /* bCurrentOnly */)
 }
 
 bool wxFileConfig::Flush(bool /* bCurrentOnly */)
@@ -629,16 +782,78 @@ bool wxFileConfig::Flush(bool /* bCurrentOnly */)
     }
   }
 
     }
   }
 
+#ifndef __WXMAC__
   return file.Commit();
   return file.Commit();
+#else
+  bool ret = file.Commit();
+  if ( ret )
+  {
+       FSSpec spec ;
+       
+       wxUnixFilename2FSSpec( m_strLocalFile , &spec ) ;
+       FInfo finfo ;
+       if ( FSpGetFInfo( &spec , &finfo ) == noErr )
+       {
+               finfo.fdType = 'TEXT' ;
+               finfo.fdCreator = 'ttxt' ;
+               FSpSetFInfo( &spec , &finfo ) ;
+       }
+  }
+  return ret ;
+#endif
+}
+
+// ----------------------------------------------------------------------------
+// renaming groups/entries
+// ----------------------------------------------------------------------------
+
+bool wxFileConfig::RenameEntry(const wxString& oldName,
+                               const wxString& newName)
+{
+    // check that the entry exists
+    ConfigEntry *oldEntry = m_pCurrentGroup->FindEntry(oldName);
+    if ( !oldEntry )
+        return FALSE;
+
+    // check that the new entry doesn't already exist
+    if ( m_pCurrentGroup->FindEntry(newName) )
+        return FALSE;
+
+    // delete the old entry, create the new one
+    wxString value = oldEntry->Value();
+    if ( !m_pCurrentGroup->DeleteEntry(oldName) )
+        return FALSE;
+
+    ConfigEntry *newEntry = m_pCurrentGroup->AddEntry(newName);
+    newEntry->SetValue(value);
+
+    return TRUE;
+}
+
+bool wxFileConfig::RenameGroup(const wxString& oldName,
+                               const wxString& newName)
+{
+    // check that the group exists
+    ConfigGroup *group = m_pCurrentGroup->FindSubgroup(oldName);
+    if ( !group )
+        return FALSE;
+
+    // check that the new group doesn't already exist
+    if ( m_pCurrentGroup->FindSubgroup(newName) )
+        return FALSE;
+
+    group->Rename(newName);
+
+    return TRUE;
 }
 
 // ----------------------------------------------------------------------------
 // delete groups/entries
 // ----------------------------------------------------------------------------
 
 }
 
 // ----------------------------------------------------------------------------
 // delete groups/entries
 // ----------------------------------------------------------------------------
 
-bool wxFileConfig::DeleteEntry(const char *szKey, bool bGroupIfEmptyAlso)
+bool wxFileConfig::DeleteEntry(const wxString& key, bool bGroupIfEmptyAlso)
 {
 {
-  PathChanger path(this, szKey);
+  wxConfigPathChanger path(this, key);
 
   if ( !m_pCurrentGroup->DeleteEntry(path.Name()) )
     return FALSE;
 
   if ( !m_pCurrentGroup->DeleteEntry(path.Name()) )
     return FALSE;
@@ -646,8 +861,8 @@ bool wxFileConfig::DeleteEntry(const char *szKey, bool bGroupIfEmptyAlso)
   if ( bGroupIfEmptyAlso && m_pCurrentGroup->IsEmpty() ) {
     if ( m_pCurrentGroup != m_pRootGroup ) {
       ConfigGroup *pGroup = m_pCurrentGroup;
   if ( bGroupIfEmptyAlso && m_pCurrentGroup->IsEmpty() ) {
     if ( m_pCurrentGroup != m_pRootGroup ) {
       ConfigGroup *pGroup = m_pCurrentGroup;
-      SetPath("..");  // changes m_pCurrentGroup!
-      m_pCurrentGroup->DeleteSubgroup(pGroup->Name());
+      SetPath(wxT(".."));  // changes m_pCurrentGroup!
+      m_pCurrentGroup->DeleteSubgroupByName(pGroup->Name());
     }
     //else: never delete the root group
   }
     }
     //else: never delete the root group
   }
@@ -655,28 +870,22 @@ bool wxFileConfig::DeleteEntry(const char *szKey, bool bGroupIfEmptyAlso)
   return TRUE;
 }
 
   return TRUE;
 }
 
-bool wxFileConfig::DeleteGroup(const char *szKey)
+bool wxFileConfig::DeleteGroup(const wxString& key)
 {
 {
-  PathChanger path(this, szKey);
+  wxConfigPathChanger path(this, key);
 
 
-  return m_pCurrentGroup->DeleteSubgroup(path.Name());
+  return m_pCurrentGroup->DeleteSubgroupByName(path.Name());
 }
 
 bool wxFileConfig::DeleteAll()
 {
   CleanUp();
 
 }
 
 bool wxFileConfig::DeleteAll()
 {
   CleanUp();
 
-  m_strLocalFile = m_strGlobalFile = "";
-  Init();
-
-  const char *szFile = m_strLocalFile;
-
-  if ( remove(szFile) == -1 )
-    wxLogSysError(_("can't delete user configuration file '%s'"), szFile);
+  if ( remove(m_strLocalFile.fn_str()) == -1 )
+    wxLogSysError(_("can't delete user configuration file '%s'"), m_strLocalFile.c_str());
 
 
-  szFile = m_strGlobalFile;
-  if ( remove(szFile) )
-    wxLogSysError(_("can't delete system configuration file '%s'"), szFile);
+  m_strLocalFile = m_strGlobalFile = wxT("");
+  Init();
 
   return TRUE;
 }
 
   return TRUE;
 }
@@ -686,7 +895,7 @@ bool wxFileConfig::DeleteAll()
 // ----------------------------------------------------------------------------
 
 // append a new line to the end of the list
 // ----------------------------------------------------------------------------
 
 // append a new line to the end of the list
-wxFileConfig::LineList *wxFileConfig::LineListAppend(const wxString& str)
+LineList *wxFileConfig::LineListAppend(const wxString& str)
 {
   LineList *pLine = new LineList(str);
 
 {
   LineList *pLine = new LineList(str);
 
@@ -705,7 +914,7 @@ 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,
+LineList *wxFileConfig::LineListInsert(const wxString& str,
                                                      LineList *pLine)
 {
   if ( pLine == m_linesTail )
                                                      LineList *pLine)
 {
   if ( pLine == m_linesTail )
@@ -744,7 +953,7 @@ void wxFileConfig::LineListRemove(LineList *pLine)
   // last entry?
   if ( pNext == NULL )
     m_linesTail = pPrev;
   // last entry?
   if ( pNext == NULL )
     m_linesTail = pPrev;
-  else    
+  else
     pNext->SetPrev(pPrev);
 
   delete pLine;
     pNext->SetPrev(pPrev);
 
   delete pLine;
@@ -764,7 +973,7 @@ bool wxFileConfig::LineListIsEmpty()
 // ----------------------------------------------------------------------------
 
 // ctor
 // ----------------------------------------------------------------------------
 
 // ctor
-wxFileConfig::ConfigGroup::ConfigGroup(wxFileConfig::ConfigGroup *pParent,
+ConfigGroup::ConfigGroup(ConfigGroup *pParent,
                                        const wxString& strName,
                                        wxFileConfig *pConfig)
                          : m_aEntries(CompareEntries),
                                        const wxString& strName,
                                        wxFileConfig *pConfig)
                          : m_aEntries(CompareEntries),
@@ -781,10 +990,10 @@ wxFileConfig::ConfigGroup::ConfigGroup(wxFileConfig::ConfigGroup *pParent,
 }
 
 // dtor deletes all children
 }
 
 // dtor deletes all children
-wxFileConfig::ConfigGroup::~ConfigGroup()
+ConfigGroup::~ConfigGroup()
 {
   // entries
 {
   // entries
-  uint n, nCount = m_aEntries.Count();
+  size_t n, nCount = m_aEntries.Count();
   for ( n = 0; n < nCount; n++ )
     delete m_aEntries[n];
 
   for ( n = 0; n < nCount; n++ )
     delete m_aEntries[n];
 
@@ -798,7 +1007,7 @@ wxFileConfig::ConfigGroup::~ConfigGroup()
 // line
 // ----------------------------------------------------------------------------
 
 // line
 // ----------------------------------------------------------------------------
 
-void wxFileConfig::ConfigGroup::SetLine(LineList *pLine)
+void ConfigGroup::SetLine(LineList *pLine)
 {
   wxASSERT( m_pLine == NULL ); // shouldn't be called twice
 
 {
   wxASSERT( m_pLine == NULL ); // shouldn't be called twice
 
@@ -834,12 +1043,12 @@ void wxFileConfig::ConfigGroup::SetLine(LineList *pLine)
       backwards in the config file (OTOH, it's not that important) and as we
       would still need to do it for the subgroups the code wouldn't have been
       significantly less complicated.
       backwards in the config file (OTOH, it's not that important) and as we
       would still need to do it for the subgroups the code wouldn't have been
       significantly less complicated.
- */
+*/
 
 // Return the line which contains "[our name]". If we're still not in the list,
 // add our line to it immediately after the last line of our parent group if we
 // have it or in the very beginning if we're the root group.
 
 // Return the line which contains "[our name]". If we're still not in the list,
 // add our line to it immediately after the last line of our parent group if we
 // have it or in the very beginning if we're the root group.
-wxFileConfig::LineList *wxFileConfig::ConfigGroup::GetGroupLine()
+LineList *ConfigGroup::GetGroupLine()
 {
   if ( m_pLine == NULL ) {
     ConfigGroup *pParent = Parent();
 {
   if ( m_pLine == NULL ) {
     ConfigGroup *pParent = Parent();
@@ -847,7 +1056,10 @@ wxFileConfig::LineList *wxFileConfig::ConfigGroup::GetGroupLine()
     // this group wasn't present in local config file, add it now
     if ( pParent != NULL ) {
       wxString strFullName;
     // this group wasn't present in local config file, add it now
     if ( pParent != NULL ) {
       wxString strFullName;
-      strFullName << "[" << GetFullName().c_str() + 1 << "]"; // +1: no '/'
+      strFullName << wxT("[")
+                  // +1: no '/'
+                  << FilterOutEntryName(GetFullName().c_str() + 1)
+                  << wxT("]");
       m_pLine = m_pConfig->LineListInsert(strFullName,
                                           pParent->GetLastGroupLine());
       pParent->SetLastGroup(this);  // we're surely after all the others
       m_pLine = m_pConfig->LineListInsert(strFullName,
                                           pParent->GetLastGroupLine());
       pParent->SetLastGroup(this);  // we're surely after all the others
@@ -864,12 +1076,12 @@ wxFileConfig::LineList *wxFileConfig::ConfigGroup::GetGroupLine()
 // Return the last line belonging to the subgroups of this group (after which
 // we can add a new subgroup), if we don't have any subgroups or entries our
 // last line is the group line (m_pLine) itself.
 // Return the last line belonging to the subgroups of this group (after which
 // we can add a new subgroup), if we don't have any subgroups or entries our
 // last line is the group line (m_pLine) itself.
-wxFileConfig::LineList *wxFileConfig::ConfigGroup::GetLastGroupLine()
+LineList *ConfigGroup::GetLastGroupLine()
 {
   // if we have any subgroups, our last line is the last line of the last
   // subgroup
   if ( m_pLastGroup != NULL ) {
 {
   // if we have any subgroups, our last line is the last line of the last
   // subgroup
   if ( m_pLastGroup != NULL ) {
-    wxFileConfig::LineList *pLine = m_pLastGroup->GetLastGroupLine();
+    LineList *pLine = m_pLastGroup->GetLastGroupLine();
 
     wxASSERT( pLine != NULL );  // last group must have !NULL associated line
     return pLine;
 
     wxASSERT( pLine != NULL );  // last group must have !NULL associated line
     return pLine;
@@ -882,10 +1094,10 @@ wxFileConfig::LineList *wxFileConfig::ConfigGroup::GetLastGroupLine()
 // return the last line belonging to the entries of this group (after which
 // we can add a new entry), if we don't have any entries we will add the new
 // one immediately after the group line itself.
 // return the last line belonging to the entries of this group (after which
 // we can add a new entry), if we don't have any entries we will add the new
 // one immediately after the group line itself.
-wxFileConfig::LineList *wxFileConfig::ConfigGroup::GetLastEntryLine()
+LineList *ConfigGroup::GetLastEntryLine()
 {
   if ( m_pLastEntry != NULL ) {
 {
   if ( m_pLastEntry != NULL ) {
-    wxFileConfig::LineList *pLine = m_pLastEntry->GetLine();
+    LineList *pLine = m_pLastEntry->GetLine();
 
     wxASSERT( pLine != NULL );  // last entry must have !NULL associated line
     return pLine;
 
     wxASSERT( pLine != NULL );  // last entry must have !NULL associated line
     return pLine;
@@ -899,12 +1111,24 @@ wxFileConfig::LineList *wxFileConfig::ConfigGroup::GetLastEntryLine()
 // group name
 // ----------------------------------------------------------------------------
 
 // group name
 // ----------------------------------------------------------------------------
 
-wxString wxFileConfig::ConfigGroup::GetFullName() const
+void ConfigGroup::Rename(const wxString& newName)
+{
+    m_strName = newName;
+
+    LineList *line = GetGroupLine();
+    wxString strFullName;
+    strFullName << wxT("[") << (GetFullName().c_str() + 1) << wxT("]"); // +1: no '/'
+    line->SetText(strFullName);
+
+    SetDirty();
+}
+
+wxString ConfigGroup::GetFullName() const
 {
   if ( Parent() )
     return Parent()->GetFullName() + wxCONFIG_PATH_SEPARATOR + Name();
   else
 {
   if ( Parent() )
     return Parent()->GetFullName() + wxCONFIG_PATH_SEPARATOR + Name();
   else
-    return "";
+    return wxT("");
 }
 
 // ----------------------------------------------------------------------------
 }
 
 // ----------------------------------------------------------------------------
@@ -912,23 +1136,23 @@ wxString wxFileConfig::ConfigGroup::GetFullName() const
 // ----------------------------------------------------------------------------
 
 // use binary search because the array is sorted
 // ----------------------------------------------------------------------------
 
 // use binary search because the array is sorted
-wxFileConfig::ConfigEntry *
-wxFileConfig::ConfigGroup::FindEntry(const char *szName) const
+ConfigEntry *
+ConfigGroup::FindEntry(const wxChar *szName) const
 {
 {
-  uint i,
+  size_t i,
        lo = 0,
        hi = m_aEntries.Count();
   int res;
        lo = 0,
        hi = m_aEntries.Count();
   int res;
-  wxFileConfig::ConfigEntry *pEntry;
+  ConfigEntry *pEntry;
 
   while ( lo < hi ) {
     i = (lo + hi)/2;
     pEntry = m_aEntries[i];
 
     #if wxCONFIG_CASE_SENSITIVE
 
   while ( lo < hi ) {
     i = (lo + hi)/2;
     pEntry = m_aEntries[i];
 
     #if wxCONFIG_CASE_SENSITIVE
-      res = strcmp(pEntry->Name(), szName);
+      res = wxStrcmp(pEntry->Name(), szName);
     #else
     #else
-      res = Stricmp(pEntry->Name(), szName);
+      res = wxStricmp(pEntry->Name(), szName);
     #endif
 
     if ( res > 0 )
     #endif
 
     if ( res > 0 )
@@ -942,23 +1166,23 @@ wxFileConfig::ConfigGroup::FindEntry(const char *szName) const
   return NULL;
 }
 
   return NULL;
 }
 
-wxFileConfig::ConfigGroup *
-wxFileConfig::ConfigGroup::FindSubgroup(const char *szName) const
+ConfigGroup *
+ConfigGroup::FindSubgroup(const wxChar *szName) const
 {
 {
-  uint i,
+  size_t i,
        lo = 0,
        hi = m_aSubgroups.Count();
   int res;
        lo = 0,
        hi = m_aSubgroups.Count();
   int res;
-  wxFileConfig::ConfigGroup *pGroup;
+  ConfigGroup *pGroup;
 
   while ( lo < hi ) {
     i = (lo + hi)/2;
     pGroup = m_aSubgroups[i];
 
     #if wxCONFIG_CASE_SENSITIVE
 
   while ( lo < hi ) {
     i = (lo + hi)/2;
     pGroup = m_aSubgroups[i];
 
     #if wxCONFIG_CASE_SENSITIVE
-      res = strcmp(pGroup->Name(), szName);
+      res = wxStrcmp(pGroup->Name(), szName);
     #else
     #else
-      res = Stricmp(pGroup->Name(), szName);
+      res = wxStricmp(pGroup->Name(), szName);
     #endif
 
     if ( res > 0 )
     #endif
 
     if ( res > 0 )
@@ -977,8 +1201,8 @@ wxFileConfig::ConfigGroup::FindSubgroup(const char *szName) const
 // ----------------------------------------------------------------------------
 
 // create a new entry and add it to the current group
 // ----------------------------------------------------------------------------
 
 // create a new entry and add it to the current group
-wxFileConfig::ConfigEntry *
-wxFileConfig::ConfigGroup::AddEntry(const wxString& strName, int nLine)
+ConfigEntry *
+ConfigGroup::AddEntry(const wxString& strName, int nLine)
 {
   wxASSERT( FindEntry(strName) == NULL );
 
 {
   wxASSERT( FindEntry(strName) == NULL );
 
@@ -989,8 +1213,8 @@ wxFileConfig::ConfigGroup::AddEntry(const wxString& strName, int nLine)
 }
 
 // create a new group and add it to the current group
 }
 
 // create a new group and add it to the current group
-wxFileConfig::ConfigGroup *
-wxFileConfig::ConfigGroup::AddSubgroup(const wxString& strName)
+ConfigGroup *
+ConfigGroup::AddSubgroup(const wxString& strName)
 {
   wxASSERT( FindSubgroup(strName) == NULL );
 
 {
   wxASSERT( FindSubgroup(strName) == NULL );
 
@@ -1011,19 +1235,32 @@ wxFileConfig::ConfigGroup::AddSubgroup(const wxString& strName)
   delete several of them.
  */
 
   delete several of them.
  */
 
-bool wxFileConfig::ConfigGroup::DeleteSubgroup(const char *szName)
+bool ConfigGroup::DeleteSubgroupByName(const wxChar *szName)
+{
+  return DeleteSubgroup(FindSubgroup(szName));
+}
+
+// doesn't delete the subgroup itself, but does remove references to it from
+// all other data structures (and normally the returned pointer should be
+// deleted a.s.a.p. because there is nothing much to be done with it anyhow)
+bool ConfigGroup::DeleteSubgroup(ConfigGroup *pGroup)
 {
 {
-  ConfigGroup *pGroup = FindSubgroup(szName);
   wxCHECK( pGroup != NULL, FALSE ); // deleting non existing group?
 
   // delete all entries
   wxCHECK( pGroup != NULL, FALSE ); // deleting non existing group?
 
   // delete all entries
-  uint nCount = pGroup->m_aEntries.Count();
-  for ( uint nEntry = 0; nEntry < nCount; nEntry++ ) {
+  size_t nCount = pGroup->m_aEntries.Count();
+  for ( size_t nEntry = 0; nEntry < nCount; nEntry++ ) {
     LineList *pLine = pGroup->m_aEntries[nEntry]->GetLine();
     if ( pLine != NULL )
       m_pConfig->LineListRemove(pLine);
   }
 
     LineList *pLine = pGroup->m_aEntries[nEntry]->GetLine();
     if ( pLine != NULL )
       m_pConfig->LineListRemove(pLine);
   }
 
+  // and subgroups of this sungroup
+  nCount = pGroup->m_aSubgroups.Count();
+  for ( size_t nGroup = 0; nGroup < nCount; nGroup++ ) {
+    pGroup->DeleteSubgroup(pGroup->m_aSubgroups[0]);
+  }
+
   LineList *pLine = pGroup->m_pLine;
   if ( pLine != NULL ) {
     // notice that we may do this test inside the previous "if" because the
   LineList *pLine = pGroup->m_pLine;
   if ( pLine != NULL ) {
     // notice that we may do this test inside the previous "if" because the
@@ -1034,7 +1271,7 @@ bool wxFileConfig::ConfigGroup::DeleteSubgroup(const char *szName)
 
       // go back until we find a subgroup or reach the group's line
       ConfigGroup *pNewLast = NULL;
 
       // go back until we find a subgroup or reach the group's line
       ConfigGroup *pNewLast = NULL;
-      uint n, nSubgroups = m_aSubgroups.Count();
+      size_t n, nSubgroups = m_aSubgroups.Count();
       LineList *pl;
       for ( pl = pLine->Prev(); pl != m_pLine; pl = pl->Prev() ) {
         // is it our subgroup?
       LineList *pl;
       for ( pl = pLine->Prev(); pl != m_pLine; pl = pl->Prev() ) {
         // is it our subgroup?
@@ -1070,7 +1307,7 @@ bool wxFileConfig::ConfigGroup::DeleteSubgroup(const char *szName)
   return TRUE;
 }
 
   return TRUE;
 }
 
-bool wxFileConfig::ConfigGroup::DeleteEntry(const char *szName)
+bool ConfigGroup::DeleteEntry(const wxChar *szName)
 {
   ConfigEntry *pEntry = FindEntry(szName);
   wxCHECK( pEntry != NULL, FALSE );  // deleting non existing item?
 {
   ConfigEntry *pEntry = FindEntry(szName);
   wxCHECK( pEntry != NULL, FALSE );  // deleting non existing item?
@@ -1085,7 +1322,7 @@ bool wxFileConfig::ConfigGroup::DeleteEntry(const char *szName)
 
       // go back until we find another entry or reach the group's line
       ConfigEntry *pNewLast = NULL;
 
       // go back until we find another entry or reach the group's line
       ConfigEntry *pNewLast = NULL;
-      uint n, nEntries = m_aEntries.Count();
+      size_t n, nEntries = m_aEntries.Count();
       LineList *pl;
       for ( pl = pLine->Prev(); pl != m_pLine; pl = pl->Prev() ) {
         // is it our subgroup?
       LineList *pl;
       for ( pl = pLine->Prev(); pl != m_pLine; pl = pl->Prev() ) {
         // is it our subgroup?
@@ -1123,7 +1360,7 @@ bool wxFileConfig::ConfigGroup::DeleteEntry(const char *szName)
 // ----------------------------------------------------------------------------
 //
 // ----------------------------------------------------------------------------
 // ----------------------------------------------------------------------------
 //
 // ----------------------------------------------------------------------------
-void wxFileConfig::ConfigGroup::SetDirty()
+void ConfigGroup::SetDirty()
 {
   m_bDirty = TRUE;
   if ( Parent() != NULL )             // propagate upwards
 {
   m_bDirty = TRUE;
   if ( Parent() != NULL )             // propagate upwards
@@ -1137,7 +1374,7 @@ void wxFileConfig::ConfigGroup::SetDirty()
 // ----------------------------------------------------------------------------
 // ctor
 // ----------------------------------------------------------------------------
 // ----------------------------------------------------------------------------
 // ctor
 // ----------------------------------------------------------------------------
-wxFileConfig::ConfigEntry::ConfigEntry(wxFileConfig::ConfigGroup *pParent,
+ConfigEntry::ConfigEntry(ConfigGroup *pParent,
                                        const wxString& strName,
                                        int nLine)
                          : m_strName(strName)
                                        const wxString& strName,
                                        int nLine)
                          : m_strName(strName)
@@ -1159,7 +1396,7 @@ wxFileConfig::ConfigEntry::ConfigEntry(wxFileConfig::ConfigGroup *pParent,
 // set value
 // ----------------------------------------------------------------------------
 
 // set value
 // ----------------------------------------------------------------------------
 
-void wxFileConfig::ConfigEntry::SetLine(LineList *pLine)
+void ConfigEntry::SetLine(LineList *pLine)
 {
   if ( m_pLine != NULL ) {
     wxLogWarning(_("entry '%s' appears more than once in group '%s'"),
 {
   if ( m_pLine != NULL ) {
     wxLogWarning(_("entry '%s' appears more than once in group '%s'"),
@@ -1172,7 +1409,7 @@ void wxFileConfig::ConfigEntry::SetLine(LineList *pLine)
 
 // second parameter is FALSE if we read the value from file and prevents the
 // entry from being marked as 'dirty'
 
 // second parameter is FALSE if we read the value from file and prevents the
 // entry from being marked as 'dirty'
-void wxFileConfig::ConfigEntry::SetValue(const wxString& strValue, bool bUser)
+void ConfigEntry::SetValue(const wxString& strValue, bool bUser)
 {
   if ( bUser && IsImmutable() ) {
     wxLogWarning(_("attempt to change immutable key '%s' ignored."),
 {
   if ( bUser && IsImmutable() ) {
     wxLogWarning(_("attempt to change immutable key '%s' ignored."),
@@ -1187,9 +1424,9 @@ void wxFileConfig::ConfigEntry::SetValue(const wxString& strValue, bool bUser)
   m_strValue = strValue;
 
   if ( bUser ) {
   m_strValue = strValue;
 
   if ( bUser ) {
-    wxString strVal = FilterOut(strValue);
+    wxString strVal = FilterOutValue(strValue);
     wxString strLine;
     wxString strLine;
-    strLine << m_strName << " = " << strVal;
+    strLine << FilterOutEntryName(m_strName) << wxT('=') << strVal;
 
     if ( m_pLine != NULL ) {
       // entry was read from the local config file, just modify the line
 
     if ( m_pLine != NULL ) {
       // entry was read from the local config file, just modify the line
@@ -1197,7 +1434,7 @@ void wxFileConfig::ConfigEntry::SetValue(const wxString& strValue, bool bUser)
     }
     else {
       // add a new line to the file
     }
     else {
       // add a new line to the file
-      wxASSERT( m_nLine == NOT_FOUND );   // consistency check
+      wxASSERT( m_nLine == wxNOT_FOUND );   // consistency check
 
       m_pLine = Group()->Config()->LineListInsert(strLine,
                                                   Group()->GetLastEntryLine());
 
       m_pLine = Group()->Config()->LineListInsert(strLine,
                                                   Group()->GetLastEntryLine());
@@ -1208,7 +1445,7 @@ void wxFileConfig::ConfigEntry::SetValue(const wxString& strValue, bool bUser)
   }
 }
 
   }
 }
 
-void wxFileConfig::ConfigEntry::SetDirty()
+void ConfigEntry::SetDirty()
 {
   m_bDirty = TRUE;
   Group()->SetDirty();
 {
   m_bDirty = TRUE;
   Group()->SetDirty();
@@ -1222,23 +1459,23 @@ void wxFileConfig::ConfigEntry::SetDirty()
 // compare functions for array sorting
 // ----------------------------------------------------------------------------
 
 // compare functions for array sorting
 // ----------------------------------------------------------------------------
 
-int CompareEntries(wxFileConfig::ConfigEntry *p1,
-                   wxFileConfig::ConfigEntry *p2)
+int CompareEntries(ConfigEntry *p1,
+                   ConfigEntry *p2)
 {
   #if wxCONFIG_CASE_SENSITIVE
 {
   #if wxCONFIG_CASE_SENSITIVE
-    return strcmp(p1->Name(), p2->Name());
+    return wxStrcmp(p1->Name(), p2->Name());
   #else
   #else
-    return Stricmp(p1->Name(), p2->Name());
+    return wxStricmp(p1->Name(), p2->Name());
   #endif
 }
 
   #endif
 }
 
-int CompareGroups(wxFileConfig::ConfigGroup *p1,
-                  wxFileConfig::ConfigGroup *p2)
+int CompareGroups(ConfigGroup *p1,
+                  ConfigGroup *p2)
 {
   #if wxCONFIG_CASE_SENSITIVE
 {
   #if wxCONFIG_CASE_SENSITIVE
-    return strcmp(p1->Name(), p2->Name());
+    return wxStrcmp(p1->Name(), p2->Name());
   #else
   #else
-    return Stricmp(p1->Name(), p2->Name());
+    return wxStricmp(p1->Name(), p2->Name());
   #endif
 }
 
   #endif
 }
 
@@ -1246,40 +1483,40 @@ int CompareGroups(wxFileConfig::ConfigGroup *p1,
 // filter functions
 // ----------------------------------------------------------------------------
 
 // filter functions
 // ----------------------------------------------------------------------------
 
-// undo FilterOut
-wxString FilterIn(const wxString& str)
+// undo FilterOutValue
+static wxString FilterInValue(const wxString& str)
 {
   wxString strResult;
   strResult.Alloc(str.Len());
 
   bool bQuoted = !str.IsEmpty() && str[0] == '"';
 
 {
   wxString strResult;
   strResult.Alloc(str.Len());
 
   bool bQuoted = !str.IsEmpty() && str[0] == '"';
 
-  for ( uint n = bQuoted ? 1 : 0; n < str.Len(); n++ ) {
-    if ( str[n] == '\\' ) {
+  for ( size_t n = bQuoted ? 1 : 0; n < str.Len(); n++ ) {
+    if ( str[n] == wxT('\\') ) {
       switch ( str[++n] ) {
       switch ( str[++n] ) {
-        case 'n':
-          strResult += '\n';
+        case wxT('n'):
+          strResult += wxT('\n');
           break;
 
           break;
 
-        case 'r':
-          strResult += '\r';
+        case wxT('r'):
+          strResult += wxT('\r');
           break;
 
           break;
 
-        case 't':
-          strResult += '\t';
+        case wxT('t'):
+          strResult += wxT('\t');
           break;
 
           break;
 
-        case '\\':
-          strResult += '\\';
+        case wxT('\\'):
+          strResult += wxT('\\');
           break;
 
           break;
 
-        case '"':
-          strResult += '"';
+        case wxT('"'):
+          strResult += wxT('"');
           break;
       }
     }
     else {
           break;
       }
     }
     else {
-      if ( str[n] != '"' || !bQuoted )
+      if ( str[n] != wxT('"') || !bQuoted )
         strResult += str[n];
       else if ( n != str.Len() - 1 ) {
         wxLogWarning(_("unexpected \" at position %d in '%s'."),
         strResult += str[n];
       else if ( n != str.Len() - 1 ) {
         wxLogWarning(_("unexpected \" at position %d in '%s'."),
@@ -1293,39 +1530,44 @@ wxString FilterIn(const wxString& str)
 }
 
 // quote the string before writing it to file
 }
 
 // quote the string before writing it to file
-wxString FilterOut(const wxString& str)
+static wxString FilterOutValue(const wxString& str)
 {
 {
+   if ( !str )
+      return str;
+
   wxString strResult;
   strResult.Alloc(str.Len());
 
   // quoting is necessary to preserve spaces in the beginning of the string
   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] == '"';
+  bool bQuote = wxIsspace(str[0]) || str[0] == wxT('"');
 
   if ( bQuote )
 
   if ( bQuote )
-    strResult += '"';
+    strResult += wxT('"');
 
 
-  char c;
-  for ( uint n = 0; n < str.Len(); n++ ) {
+  wxChar c;
+  for ( size_t n = 0; n < str.Len(); n++ ) {
     switch ( str[n] ) {
     switch ( str[n] ) {
-      case '\n':
-        c = 'n';
+      case wxT('\n'):
+        c = wxT('n');
         break;
 
         break;
 
-      case '\r':
-        c = 'r';
+      case wxT('\r'):
+        c = wxT('r');
         break;
 
         break;
 
-      case '\t':
-        c = 't';
+      case wxT('\t'):
+        c = wxT('t');
         break;
 
         break;
 
-      case '\\':
-        c = '\\';
+      case wxT('\\'):
+        c = wxT('\\');
         break;
 
         break;
 
-      case '"':
-        if ( bQuote )
-          c = '"';
+      case wxT('"'):
+        if ( bQuote ) {
+          c = wxT('"');
+          break;
+        }
         //else: fall through
 
       default:
         //else: fall through
 
       default:
@@ -1334,11 +1576,62 @@ wxString FilterOut(const wxString& str)
     }
 
     // we get here only for special characters
     }
 
     // we get here only for special characters
-    strResult << '\\' << c;
+    strResult << wxT('\\') << c;
   }
 
   if ( bQuote )
   }
 
   if ( bQuote )
-    strResult += '"';
+    strResult += wxT('"');
+
+  return strResult;
+}
+
+// undo FilterOutEntryName
+static wxString FilterInEntryName(const wxString& str)
+{
+  wxString strResult;
+  strResult.Alloc(str.Len());
+
+  for ( const wxChar *pc = str.c_str(); *pc != '\0'; pc++ ) {
+    if ( *pc == wxT('\\') )
+      pc++;
+
+    strResult += *pc;
+  }
+
+  return strResult;
+}
+
+// sanitize entry or group name: insert '\\' before any special characters
+static wxString FilterOutEntryName(const wxString& str)
+{
+  wxString strResult;
+  strResult.Alloc(str.Len());
+
+  for ( const wxChar *pc = str.c_str(); *pc != wxT('\0'); pc++ ) {
+    wxChar c = *pc;
+
+    // we explicitly allow some of "safe" chars and 8bit ASCII characters
+    // which will probably never have special meaning
+    // NB: note that wxCONFIG_IMMUTABLE_PREFIX and wxCONFIG_PATH_SEPARATOR
+    //     should *not* be quoted
+    if ( !wxIsalnum(c) && !wxStrchr(wxT("@_/-!.*%"), c) && ((c & 0x80) == 0) )
+      strResult += wxT('\\');
+
+    strResult += c;
+  }
 
   return strResult;
 }
 
   return strResult;
 }
+
+// we can't put ?: in the ctor initializer list because it confuses some
+// broken compilers (Borland C++)
+static wxString GetAppName(const wxString& appName)
+{
+    if ( !appName && wxTheApp )
+        return wxTheApp->GetAppName();
+    else
+        return appName;
+}
+
+#endif // wxUSE_CONFIG
+