]> git.saurik.com Git - wxWidgets.git/blobdiff - src/common/fileconf.cpp
fix bug in Borland (bcc32 really hates ?)
[wxWidgets.git] / src / common / fileconf.cpp
index d0c6ac80627c6a7c59dc2a1b5ab5039242fdec55..0ff30e5381e0ac553e99eb52a1faced9b139fd37 100644 (file)
 // RCS-ID:      $Id$
 // Copyright:   (c) 1997 Karsten Ballüder   &  Vadim Zeitlin
 //                       Ballueder@usa.net     <zeitlin@dptmaths.ens-cachan.fr>
 // RCS-ID:      $Id$
 // Copyright:   (c) 1997 Karsten Ballüder   &  Vadim Zeitlin
 //                       Ballueder@usa.net     <zeitlin@dptmaths.ens-cachan.fr>
-// Licence:     wxWindows license
+// Licence:     wxWindows licence
 ///////////////////////////////////////////////////////////////////////////////
 
 #ifdef __GNUG__
 #pragma implementation "fileconf.h"
 #endif
 
 ///////////////////////////////////////////////////////////////////////////////
 
 #ifdef __GNUG__
 #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>
-
-// _WINDOWS_ is defined when windows.h is included,
-// __WXMSW__ is defined for MS Windows compilation
-#if       defined(__WXMSW__) && !defined(_WINDOWS_)
-  #include  <windows.h>
+#include  "wx/app.h"
+#include  "wx/dynarray.h"
+#include  "wx/file.h"
+#include  "wx/log.h"
+#include  "wx/textfile.h"
+#include  "wx/memtext.h"
+#include  "wx/config.h"
+#include  "wx/fileconf.h"
+
+#if wxUSE_STREAMS
+    #include  "wx/stream.h"
+#endif // wxUSE_STREAMS
+
+#include  "wx/utils.h"    // for wxGetHomeDir
+
+#if defined(__WXMAC__)
+  #include  "wx/mac/private.h"  // includes mac headers
+#endif
+
+#if defined(__WXMSW__)
+  #include "wx/msw/private.h"
 #endif  //windows.h
 #endif  //windows.h
+#if defined(__WXPM__)
+  #define INCL_DOS
+  #include <os2.h>
+#endif
 
 #include  <stdlib.h>
 #include  <ctype.h>
 
 
 #include  <stdlib.h>
 #include  <ctype.h>
 
+// headers needed for umask()
+#ifdef __UNIX__
+    #include <sys/types.h>
+    #include <sys/stat.h>
+#endif // __UNIX__
+
 // ----------------------------------------------------------------------------
 // macros
 // ----------------------------------------------------------------------------
 #define CONST_CAST ((wxFileConfig *)this)->
 
 // ----------------------------------------------------------------------------
 // ----------------------------------------------------------------------------
 // macros
 // ----------------------------------------------------------------------------
 #define CONST_CAST ((wxFileConfig *)this)->
 
 // ----------------------------------------------------------------------------
-// global functions declarations
+// constants
 // ----------------------------------------------------------------------------
 
 // ----------------------------------------------------------------------------
 
-// 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); }
+#ifndef MAX_PATH
+  #define MAX_PATH 512
+#endif
+
+// ----------------------------------------------------------------------------
+// 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(wxFileConfigEntry *p1, wxFileConfigEntry *p2);
+static int LINKAGEMODE CompareGroups(wxFileConfigGroup *p1, wxFileConfigGroup *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);
+
+// ============================================================================
+// private classes
+// ============================================================================
+
+// ----------------------------------------------------------------------------
+// "template" array types
+// ----------------------------------------------------------------------------
+
+WX_DEFINE_SORTED_EXPORTED_ARRAY(wxFileConfigEntry *, ArrayEntries);
+WX_DEFINE_SORTED_EXPORTED_ARRAY(wxFileConfigGroup *, ArrayGroups);
+
+// ----------------------------------------------------------------------------
+// wxFileConfigLineList
+// ----------------------------------------------------------------------------
+
+// we store all lines of the local config file as a linked list in memory
+class wxFileConfigLineList
+{
+public:
+  void SetNext(wxFileConfigLineList *pNext)  { m_pNext = pNext; }
+  void SetPrev(wxFileConfigLineList *pPrev)  { m_pPrev = pPrev; }
+
+  // ctor
+  wxFileConfigLineList(const wxString& str,
+                       wxFileConfigLineList *pNext = NULL) : m_strLine(str)
+    { SetNext(pNext); SetPrev(NULL); }
+
+  // next/prev nodes in the linked list
+  wxFileConfigLineList *Next() const { return m_pNext;  }
+  wxFileConfigLineList *Prev() const { return m_pPrev;  }
+
+  // get/change lines text
+  void SetText(const wxString& str) { m_strLine = str;  }
+  const wxString& Text() const { return m_strLine; }
+
+private:
+  wxString  m_strLine;                  // line contents
+  wxFileConfigLineList *m_pNext,        // next node
+                       *m_pPrev;        // previous one
+
+    DECLARE_NO_COPY_CLASS(wxFileConfigLineList)
+};
+
+// ----------------------------------------------------------------------------
+// wxFileConfigEntry: a name/value pair
+// ----------------------------------------------------------------------------
+
+class wxFileConfigEntry
+{
+private:
+  wxFileConfigGroup *m_pParent; // group that contains us
+
+  wxString      m_strName,      // entry name
+                m_strValue;     //       value
+  bool          m_bDirty:1,     // changed since last read?
+                m_bImmutable:1, // can be overriden locally?
+                m_bHasValue:1;  // set after first call to SetValue()
+
+  int           m_nLine;        // used if m_pLine == NULL only
+
+  // pointer to our line in the linked list or NULL if it was found in global
+  // file (which we don't modify)
+  wxFileConfigLineList *m_pLine;
+
+public:
+  wxFileConfigEntry(wxFileConfigGroup *pParent,
+                    const wxString& strName, int nLine);
+
+  // simple accessors
+  const wxString& Name()        const { return m_strName;    }
+  const wxString& Value()       const { return m_strValue;   }
+  wxFileConfigGroup *Group()    const { return m_pParent;    }
+  bool            IsDirty()     const { return m_bDirty;     }
+  bool            IsImmutable() const { return m_bImmutable; }
+  bool            IsLocal()     const { return m_pLine != 0; }
+  int             Line()        const { return m_nLine;      }
+  wxFileConfigLineList *
+                  GetLine()     const { return m_pLine;      }
+
+  // modify entry attributes
+  void SetValue(const wxString& strValue, bool bUser = TRUE);
+  void SetDirty();
+  void SetLine(wxFileConfigLineList *pLine);
+
+    DECLARE_NO_COPY_CLASS(wxFileConfigEntry)
+};
+
+// ----------------------------------------------------------------------------
+// wxFileConfigGroup: container of entries and other groups
+// ----------------------------------------------------------------------------
+
+class wxFileConfigGroup
+{
+private:
+  wxFileConfig *m_pConfig;          // config object we belong to
+  wxFileConfigGroup  *m_pParent;    // parent group (NULL for root group)
+  ArrayEntries  m_aEntries;         // entries in this group
+  ArrayGroups   m_aSubgroups;       // subgroups
+  wxString      m_strName;          // group's name
+  bool          m_bDirty;           // if FALSE => all subgroups are not dirty
+  wxFileConfigLineList *m_pLine;    // pointer to our line in the linked list
+  wxFileConfigEntry *m_pLastEntry;  // last entry/subgroup of this group in the
+  wxFileConfigGroup *m_pLastGroup;  // local file (we insert new ones after it)
+
+  // DeleteSubgroupByName helper
+  bool DeleteSubgroup(wxFileConfigGroup *pGroup);
+
+public:
+  // ctor
+  wxFileConfigGroup(wxFileConfigGroup *pParent, const wxString& strName, wxFileConfig *);
+
+  // dtor deletes all entries and subgroups also
+  ~wxFileConfigGroup();
+
+  // simple accessors
+  const wxString& Name()    const { return m_strName; }
+  wxFileConfigGroup    *Parent()  const { return m_pParent; }
+  wxFileConfig   *Config()  const { return m_pConfig; }
+  bool            IsDirty() const { return m_bDirty;  }
+
+  const ArrayEntries& Entries() const { return m_aEntries;   }
+  const ArrayGroups&  Groups()  const { return m_aSubgroups; }
+  bool  IsEmpty() const { return Entries().IsEmpty() && Groups().IsEmpty(); }
+
+  // find entry/subgroup (NULL if not found)
+  wxFileConfigGroup *FindSubgroup(const wxChar *szName) const;
+  wxFileConfigEntry *FindEntry   (const wxChar *szName) const;
+
+  // delete entry/subgroup, return FALSE if doesn't exist
+  bool DeleteSubgroupByName(const wxChar *szName);
+  bool DeleteEntry(const wxChar *szName);
+
+  // create new entry/subgroup returning pointer to newly created element
+  wxFileConfigGroup *AddSubgroup(const wxString& strName);
+  wxFileConfigEntry *AddEntry   (const wxString& strName, int nLine = wxNOT_FOUND);
+
+  // will also recursively set parent's dirty flag
+  void SetDirty();
+  void SetLine(wxFileConfigLineList *pLine);
+
+  // rename: no checks are done to ensure that the name is unique!
+  void Rename(const wxString& newName);
+
+  //
+  wxString GetFullName() const;
+
+  // get the last line belonging to an entry/subgroup of this group
+  wxFileConfigLineList *GetGroupLine();     // line which contains [group]
+  wxFileConfigLineList *GetLastEntryLine(); // after which our subgroups start
+  wxFileConfigLineList *GetLastGroupLine(); // after which the next group starts
+
+  // called by entries/subgroups when they're created/deleted
+  void SetLastEntry(wxFileConfigEntry *pEntry) { m_pLastEntry = pEntry; }
+  void SetLastGroup(wxFileConfigGroup *pGroup) { m_pLastGroup = pGroup; }
+
+    DECLARE_NO_COPY_CLASS(wxFileConfigGroup)
+};
 
 // ============================================================================
 // implementation
 
 // ============================================================================
 // implementation
@@ -79,61 +263,111 @@ static wxString FilterOut(const wxString& str);
 // ----------------------------------------------------------------------------
 // static functions
 // ----------------------------------------------------------------------------
 // ----------------------------------------------------------------------------
 // static functions
 // ----------------------------------------------------------------------------
-wxString wxFileConfig::GetGlobalFileName(const char *szFile)
+wxString wxFileConfig::GetGlobalDir()
 {
 {
-  wxString str;
+  wxString strDir;
+
+#ifdef __VMS__ // Note if __VMS is defined __UNIX is also defined
+    strDir = wxT("sys$manager:");
+#elif defined(__WXMAC__)
+    strDir = wxMacFindFolder(  (short) kOnSystemDisk, kPreferencesFolderType, kDontCreateFolder ) ;
+#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];
+        strDir.Printf(wxT("%c:\\OS2\\"), 'A'+drive-1);
+    }
+#elif defined(__WXSTUBS__)
+    wxASSERT_MSG( FALSE, wxT("TODO") ) ;
+#elif defined(__DOS__)
+    // There's no such thing as global cfg dir in MS-DOS, let's return
+    // current directory (FIXME_MGL?)
+    return wxT(".\\");
+#else // Windows
+    wxChar szWinDir[MAX_PATH];
+    ::GetWindowsDirectory(szWinDir, MAX_PATH);
+
+    strDir = szWinDir;
+    strDir << wxT('\\');
+#endif // Unix/Windows
+
+    return strDir;
+}
 
 
-  bool bNoExt = strchr(szFile, '.') == NULL;
+wxString wxFileConfig::GetLocalDir()
+{
+    wxString strDir;
 
 
-  #ifdef  __UNIX__
-    str << "/etc/" << szFile;
-    if ( bNoExt )
-      str << ".conf";
-  #else   // Windows
-    #ifndef _MAX_PATH
-      #define _MAX_PATH 512
-    #endif
+#if defined(__WXMAC__) || defined(__DOS__)
+    // no local dir concept on Mac OS 9 or MS-DOS
+    return GetGlobalDir() ;
+#else
+    wxGetHomeDir(&strDir);
 
 
-    char szWinDir[_MAX_PATH];
-    ::GetWindowsDirectory(szWinDir, _MAX_PATH);
-    str << szWinDir <<  "\\" << szFile;
-    if ( bNoExt )
-      str << ".ini";
-  #endif  // UNIX/Win
+#ifdef  __UNIX__
+#ifdef __VMS
+    if (strDir.Last() != wxT(']'))
+#endif
+    if (strDir.Last() != wxT('/')) strDir << wxT('/');
+#else
+    if (strDir.Last() != wxT('\\')) strDir << wxT('\\');
+#endif
+#endif
 
 
-  return str;
+    return strDir;
 }
 
 }
 
-wxString wxFileConfig::GetLocalFileName(const char *szFile)
+wxString wxFileConfig::GetGlobalFileName(const wxChar *szFile)
 {
 {
-  wxString str;
+    wxString str = GetGlobalDir();
+    str << szFile;
+
+    if ( wxStrchr(szFile, wxT('.')) == NULL )
+#if defined( __WXMAC__ )
+        str << " Preferences";
+#elif defined( __UNIX__ )
+        str << wxT(".conf");
+#else   // Windows
+        str << wxT(".ini");
+#endif  // UNIX/Win
+
+    return str;
+}
 
 
-  #ifdef  __UNIX__
-    const char *szHome = getenv("HOME");
-    if ( szHome == NULL ) {
-      // we're homeless...
-      wxLogWarning(_("can't find user's HOME, using current directory."));
-      szHome = ".";
-    }
-    str << szHome << "/." << szFile;
-  #else   // Windows
-    #ifdef  __WIN32__
-      const char *szHome = getenv("HOMEDRIVE");
-      if ( szHome != NULL )
-        str << szHome;
-      szHome = getenv("HOMEPATH");
-      if ( szHome != NULL )
-        str << szHome;
-      str << szFile;
-      if ( strchr(szFile, '.') == NULL )
-        str << ".ini";
-    #else   // Win16
-      // Win16 has no idea about home, so use the current directory instead
-      str << ".\\" << szFile;
-    #endif  // WIN16/32
-  #endif  // UNIX/Win
-
-  return str;
+wxString wxFileConfig::GetLocalFileName(const wxChar *szFile)
+{
+#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
+
+#if defined( __UNIX__ ) && !defined( __VMS ) && !defined( __WXMAC__ )
+    str << wxT('.');
+#endif
+
+    str << szFile;
+
+#if defined(__WINDOWS__) || defined(__DOS__)
+    if ( wxStrchr(szFile, wxT('.')) == NULL )
+        str << wxT(".ini");
+#endif
+
+#ifdef __WXMAC__
+    str << " Preferences";
+#endif
+
+    return str;
 }
 
 // ----------------------------------------------------------------------------
 }
 
 // ----------------------------------------------------------------------------
@@ -142,107 +376,231 @@ wxString wxFileConfig::GetLocalFileName(const char *szFile)
 
 void wxFileConfig::Init()
 {
 
 void wxFileConfig::Init()
 {
-  m_pCurrentGroup =
-  m_pRootGroup    = new ConfigGroup(NULL, "", this);
+    m_pCurrentGroup =
+    m_pRootGroup    = new wxFileConfigGroup(NULL, wxT(""), this);
 
 
-  m_linesHead =
-  m_linesTail = NULL;
+    m_linesHead =
+    m_linesTail = NULL;
 
 
-  m_strPath.Empty();
+    // It's not an error if (one of the) file(s) doesn't exist.
+
+    // parse the global file
+    if ( !m_strGlobalFile.IsEmpty() && wxFile::Exists(m_strGlobalFile) )
+    {
+        wxTextFile fileGlobal(m_strGlobalFile);
+
+        if ( fileGlobal.Open(m_conv/*ignored in ANSI build*/) )
+        {
+            Parse(fileGlobal, FALSE /* global */);
+            SetRootPath();
+        }
+        else
+        {
+            wxLogWarning(_("can't open global configuration file '%s'."), m_strGlobalFile.c_str());
+        }
+    }
+
+    // parse the local file
+    if ( !m_strLocalFile.IsEmpty() && wxFile::Exists(m_strLocalFile) )
+    {
+        wxTextFile fileLocal(m_strLocalFile);
+        if ( fileLocal.Open(m_conv/*ignored in ANSI build*/) )
+        {
+            Parse(fileLocal, TRUE /* local */);
+            SetRootPath();
+        }
+        else
+        {
+            wxLogWarning(_("can't open user configuration file '%s'."),  m_strLocalFile.c_str() );
+        }
+    }
 }
 
 }
 
-wxFileConfig::wxFileConfig(const wxString& strLocal, const wxString& strGlobal)
-            : m_strLocalFile(strLocal), m_strGlobalFile(strGlobal)
+// 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, wxMBConv& conv)
+            : wxConfigBase(::GetAppName(appName), vendorName,
+                           strLocal, strGlobal,
+                           style),
+              m_strLocalFile(strLocal), m_strGlobalFile(strGlobal),
+              m_conv(conv)
 {
 {
-  Init();
+    // Make up names for files if empty
+    if ( m_strLocalFile.IsEmpty() && (style & wxCONFIG_USE_LOCAL_FILE) )
+        m_strLocalFile = GetLocalFileName(GetAppName());
+
+    if ( m_strGlobalFile.IsEmpty() && (style & wxCONFIG_USE_GLOBAL_FILE) )
+        m_strGlobalFile = GetGlobalFileName(GetAppName());
+
+    // 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);
+
+    if ( !m_strGlobalFile.IsEmpty() )
+        SetStyle(GetStyle() | wxCONFIG_USE_GLOBAL_FILE);
+
+    // 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;
+        }
 
 
-  // it's not an error if (one of the) file(s) doesn't exist
+        if ( !m_strGlobalFile.IsEmpty() && !wxIsAbsolutePath(m_strGlobalFile) )
+        {
+            wxString strGlobal = m_strGlobalFile;
+            m_strGlobalFile = GetGlobalDir();
+            m_strGlobalFile << strGlobal;
+        }
+    }
 
 
-  // parse the global file
-  if ( !strGlobal.IsEmpty() ) {
-    if ( wxFile::Exists(strGlobal) ) {
-      wxTextFile fileGlobal(strGlobal);
+    SetUmask(-1);
 
 
-      if ( fileGlobal.Open() ) {
-        Parse(fileGlobal, FALSE /* global */);
-        SetRootPath();
-      }
-      else
-        wxLogWarning(_("can't open global configuration file '%s'."),
-                     strGlobal.c_str());
+    Init();
+}
+
+#if wxUSE_STREAMS
+
+wxFileConfig::wxFileConfig(wxInputStream &inStream, wxMBConv& conv)
+        : m_conv(conv)
+{
+    // always local_file when this constructor is called (?)
+    SetStyle(GetStyle() | wxCONFIG_USE_LOCAL_FILE);
+
+    m_pCurrentGroup =
+    m_pRootGroup    = new wxFileConfigGroup(NULL, wxT(""), this);
+
+    m_linesHead =
+    m_linesTail = NULL;
+
+    // translate everything to the current (platform-dependent) line
+    // termination character
+    wxString strTrans;
+    {
+        wxString strTmp;
+
+        char buf[1024];
+        while ( !inStream.Read(buf, WXSIZEOF(buf)).Eof() )
+            strTmp.append(wxConvertMB2WX(buf), inStream.LastRead());
+
+        strTmp.append(wxConvertMB2WX(buf), inStream.LastRead());
+
+        strTrans = wxTextBuffer::Translate(strTmp);
     }
     }
-  }
 
 
-  // parse the local file
-  if ( wxFile::Exists(strLocal) ) {
-    wxTextFile fileLocal(strLocal);
-    if ( fileLocal.Open() ) {
-      Parse(fileLocal, TRUE /* local */);
-      SetRootPath();
+    wxMemoryText memText;
+
+    // Now we can add the text to the memory text. To do this we extract line
+    // by line from the translated string, until we've reached the end.
+    //
+    // VZ: all this is horribly inefficient, we should do the translation on
+    //     the fly in one pass saving both memory and time (TODO)
+
+    const wxChar *pEOL = wxTextBuffer::GetEOL(wxTextBuffer::typeDefault);
+    const size_t EOLLen = wxStrlen(pEOL);
+
+    int posLineStart = strTrans.Find(pEOL);
+    while ( posLineStart != -1 )
+    {
+        wxString line(strTrans.Left(posLineStart));
+
+        memText.AddLine(line);
+
+        strTrans = strTrans.Mid(posLineStart + EOLLen);
+
+        posLineStart = strTrans.Find(pEOL);
     }
     }
-    else
-      wxLogWarning(_("can't open user configuration file '%s'."),
-                   strLocal.c_str());
-  }
+
+    // also add whatever we have left in the translated string.
+    memText.AddLine(strTrans);
+
+    // Finally we can parse it all.
+    Parse(memText, TRUE /* local */);
+
+    SetRootPath();
 }
 
 }
 
-wxFileConfig::~wxFileConfig()
+#endif // wxUSE_STREAMS
+
+void wxFileConfig::CleanUp()
 {
 {
-  Flush();
   delete m_pRootGroup;
 
   delete m_pRootGroup;
 
-  LineList *pCur = m_linesHead;
+  wxFileConfigLineList *pCur = m_linesHead;
   while ( pCur != NULL ) {
   while ( pCur != NULL ) {
-    LineList *pNext = pCur->Next();
+    wxFileConfigLineList *pNext = pCur->Next();
     delete pCur;
     pCur = pNext;
   }
 }
 
     delete pCur;
     pCur = pNext;
   }
 }
 
+wxFileConfig::~wxFileConfig()
+{
+  Flush();
+
+  CleanUp();
+}
+
 // ----------------------------------------------------------------------------
 // parse a config file
 // ----------------------------------------------------------------------------
 
 // ----------------------------------------------------------------------------
 // parse a config file
 // ----------------------------------------------------------------------------
 
-void wxFileConfig::Parse(wxTextFile& file, bool bLocal)
+void wxFileConfig::Parse(wxTextBuffer& buffer, 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++ ) {
-    strLine = file[n];
+  size_t nLineCount = buffer.GetLineCount();
+
+  for ( size_t n = 0; n < nLineCount; n++ )
+  {
+    strLine = buffer[n];
 
     // add the line to linked list
     if ( bLocal )
       LineListAppend(strLine);
 
     // skip leading spaces
 
     // add the line to linked list
     if ( bLocal )
       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('\\') ) {
+            // the next char is escaped, so skip it even if it is ']'
+            pEnd++;
+        }
+
+        if ( *pEnd == wxT('\n') || *pEnd == wxT('\0') ) {
+            // we reached the end of line, break out of the loop
+            break;
+        }
       }
 
       }
 
-      if ( *pEnd != ']' ) {
+      if ( *pEnd != wxT(']') ) {
         wxLogError(_("file '%s': unexpected character %c at line %d."),
         wxLogError(_("file '%s': unexpected character %c at line %d."),
-                   file.GetName(), *pEnd, n + 1);
+                   buffer.GetName(), *pEnd, n + 1);
         continue; // skip this line
       }
 
       // group name here is always considered as abs path
       wxString strGroup;
       pStart++;
         continue; // skip this line
       }
 
       // group name here is always considered as abs path
       wxString strGroup;
       pStart++;
-      strGroup << APPCONF_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);
@@ -252,43 +610,53 @@ 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;
 
           default:
             // ignore whitespace ('\n' impossible here)
             break;
 
           default:
-            wxLogWarning(_("file '%s', line %d: '%s' "
-                           "ignored after group header."),
-                         file.GetName(), n + 1, pEnd);
+            wxLogWarning(_("file '%s', line %d: '%s' ignored after group header."),
+                         buffer.GetName(), n + 1, pEnd);
             bCont = FALSE;
         }
       }
     }
     else {                        // a key
             bCont = FALSE;
         }
       }
     }
     else {                        // a key
-      const char *pEnd = pStart;
-      while ( IsValid(*pEnd) )
+      const wxChar *pEnd = pStart;
+      while ( *pEnd && *pEnd != wxT('=') && !wxIsspace(*pEnd) ) {
+        if ( *pEnd == wxT('\\') ) {
+          // next character may be space or not - still take it because it's
+          // quoted (unless there is nothing)
+          pEnd++;
+          if ( !*pEnd ) {
+            // the error message will be given below anyhow
+            break;
+          }
+        }
+
         pEnd++;
         pEnd++;
+      }
 
 
-      wxString strKey(pStart, pEnd);
+      wxString strKey(FilterInEntryName(wxString(pStart, pEnd)));
 
       // skip whitespace
 
       // skip whitespace
-      while ( isspace(*pEnd) )
+      while ( wxIsspace(*pEnd) )
         pEnd++;
 
         pEnd++;
 
-      if ( *pEnd++ != '=' ) {
+      if ( *pEnd++ != wxT('=') ) {
         wxLogError(_("file '%s', line %d: '=' expected."),
         wxLogError(_("file '%s', line %d: '=' expected."),
-                   file.GetName(), n + 1);
+                   buffer.GetName(), n + 1);
       }
       else {
       }
       else {
-        ConfigEntry *pEntry = m_pCurrentGroup->FindEntry(strKey);
+        wxFileConfigEntry *pEntry = m_pCurrentGroup->FindEntry(strKey);
 
         if ( pEntry == NULL ) {
           // new entry
 
         if ( pEntry == NULL ) {
           // new entry
@@ -300,9 +668,8 @@ void wxFileConfig::Parse(wxTextFile& file, bool bLocal)
         else {
           if ( bLocal && pEntry->IsImmutable() ) {
             // immutable keys can't be changed by user
         else {
           if ( bLocal && pEntry->IsImmutable() ) {
             // immutable keys can't be changed by user
-            wxLogWarning(_("file '%s', line %d: value for "
-                           "immutable key '%s' ignored."),
-                         file.GetName(), n + 1, strKey.c_str());
+            wxLogWarning(_("file '%s', line %d: value for immutable key '%s' ignored."),
+                         buffer.GetName(), n + 1, strKey.c_str());
             continue;
           }
           // the condition below catches the cases (a) and (b) but not (c):
             continue;
           }
           // the condition below catches the cases (a) and (b) but not (c):
@@ -311,9 +678,8 @@ 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."),
-                         file.GetName(), n + 1, strKey.c_str(), pEntry->Line());
+            wxLogWarning(_("file '%s', line %d: key '%s' was first found at line %d."),
+                         buffer.GetName(), n + 1, strKey.c_str(), pEntry->Line());
 
             if ( bLocal )
               pEntry->SetLine(m_linesTail);
 
             if ( bLocal )
               pEntry->SetLine(m_linesTail);
@@ -321,10 +687,14 @@ 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 */);
+        wxString value = pEnd;
+        if ( !(GetStyle() & wxCONFIG_USE_NO_ESCAPE_CHARACTERS) )
+            value = FilterInValue(value);
+
+        pEntry->SetValue(value, FALSE);
       }
     }
   }
       }
     }
   }
@@ -349,22 +719,22 @@ void wxFileConfig::SetPath(const wxString& strPath)
     return;
   }
 
     return;
   }
 
-  if ( strPath[0] == APPCONF_PATH_SEPARATOR ) {
+  if ( strPath[0] == wxCONFIG_PATH_SEPARATOR ) {
     // absolute path
     wxSplitPath(aParts, strPath);
   }
   else {
     // relative path, combine with current one
     wxString strFullPath = m_strPath;
     // absolute path
     wxSplitPath(aParts, strPath);
   }
   else {
     // relative path, combine with current one
     wxString strFullPath = m_strPath;
-    strFullPath << APPCONF_PATH_SEPARATOR << strPath;
+    strFullPath << wxCONFIG_PATH_SEPARATOR << strPath;
     wxSplitPath(aParts, strFullPath);
   }
 
   // change current group
     wxSplitPath(aParts, strFullPath);
   }
 
   // change current group
-  uint n;
+  size_t n;
   m_pCurrentGroup = m_pRootGroup;
   for ( n = 0; n < aParts.Count(); n++ ) {
   m_pCurrentGroup = m_pRootGroup;
   for ( n = 0; n < aParts.Count(); n++ ) {
-    ConfigGroup *pNextGroup = m_pCurrentGroup->FindSubgroup(aParts[n]);
+    wxFileConfigGroup *pNextGroup = m_pCurrentGroup->FindSubgroup(aParts[n]);
     if ( pNextGroup == NULL )
       pNextGroup = m_pCurrentGroup->AddSubgroup(aParts[n]);
     m_pCurrentGroup = pNextGroup;
     if ( pNextGroup == NULL )
       pNextGroup = m_pCurrentGroup->AddSubgroup(aParts[n]);
     m_pCurrentGroup = pNextGroup;
@@ -373,7 +743,7 @@ void wxFileConfig::SetPath(const wxString& strPath)
   // recombine path parts in one variable
   m_strPath.Empty();
   for ( n = 0; n < aParts.Count(); n++ ) {
   // recombine path parts in one variable
   m_strPath.Empty();
   for ( n = 0; n < aParts.Count(); n++ ) {
-    m_strPath << APPCONF_PATH_SEPARATOR << aParts[n];
+    m_strPath << wxCONFIG_PATH_SEPARATOR << aParts[n];
   }
 }
 
   }
 }
 
@@ -381,45 +751,45 @@ 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() ) {
-    str = m_pCurrentGroup->Groups()[lIndex++]->Name();
+  if ( size_t(lIndex) < m_pCurrentGroup->Groups().Count() ) {
+    str = m_pCurrentGroup->Groups()[(size_t)lIndex++]->Name();
     return TRUE;
   }
   else
     return FALSE;
 }
 
     return TRUE;
   }
   else
     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() ) {
-    str = m_pCurrentGroup->Entries()[lIndex++]->Name();
+  if ( size_t(lIndex) < m_pCurrentGroup->Entries().Count() ) {
+    str = m_pCurrentGroup->Entries()[(size_t)lIndex++]->Name();
     return TRUE;
   }
   else
     return FALSE;
 }
 
     return TRUE;
   }
   else
     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 ) {
   if ( bRecursive ) {
-    ConfigGroup *pOldCurrentGroup = m_pCurrentGroup;
-    uint nSubgroups = m_pCurrentGroup->Groups().Count();
-    for ( uint nGroup = 0; nGroup < nSubgroups; nGroup++ ) {
+    wxFileConfigGroup *pOldCurrentGroup = m_pCurrentGroup;
+    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;
@@ -429,13 +799,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 ) {
   if ( bRecursive ) {
-    ConfigGroup *pOldCurrentGroup = m_pCurrentGroup;
-    uint nSubgroups = m_pCurrentGroup->Groups().Count();
-    for ( uint nGroup = 0; nGroup < nSubgroups; nGroup++ ) {
+    wxFileConfigGroup *pOldCurrentGroup = m_pCurrentGroup;
+    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;
@@ -451,17 +821,17 @@ 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());
+  wxFileConfigGroup *pGroup = m_pCurrentGroup->FindSubgroup(path.Name());
   return pGroup != NULL;
 }
 
 bool wxFileConfig::HasEntry(const wxString& strName) const
 {
   return pGroup != NULL;
 }
 
 bool wxFileConfig::HasEntry(const wxString& strName) const
 {
-  PathChanger path(this, strName);
+  wxConfigPathChanger path(this, strName);
 
 
-  ConfigEntry *pEntry = m_pCurrentGroup->FindEntry(path.Name());
+  wxFileConfigEntry *pEntry = m_pCurrentGroup->FindEntry(path.Name());
   return pEntry != NULL;
 }
 
   return pEntry != NULL;
 }
 
@@ -469,135 +839,218 @@ 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::DoReadString(const wxString& key, wxString* pStr) const
 {
 {
-  PathChanger path(this, szKey);
+  wxConfigPathChanger path(this, key);
 
 
-  ConfigEntry *pEntry = m_pCurrentGroup->FindEntry(path.Name());
+  wxFileConfigEntry *pEntry = m_pCurrentGroup->FindEntry(path.Name());
   if (pEntry == NULL) {
   if (pEntry == NULL) {
-    *pstr = ExpandEnvVars(szDefault);
     return FALSE;
   }
     return FALSE;
   }
-  else {
-    *pstr = ExpandEnvVars(pEntry->Value());
-    return TRUE;
-  }
-}
 
 
-const char *wxFileConfig::Read(const char *szKey,
-                               const char *szDefault) const
-{
-  static wxString s_str;
-  Read(&s_str, szKey, szDefault);
+  *pStr = pEntry->Value();
 
 
-  return s_str.c_str();
+  return TRUE;
 }
 
 }
 
-bool wxFileConfig::Read(long *pl, const char *szKey, long lDefault) const
+bool wxFileConfig::DoReadLong(const wxString& key, long *pl) const
 {
   wxString str;
 {
   wxString str;
-  if ( Read(&str, szKey) ) {
-    *pl = atol(str);
-    return TRUE;
-  }
-  else {
-    *pl = lDefault;
+  if ( !Read(key, & str) )
+  {
     return FALSE;
   }
     return FALSE;
   }
+  return str.ToLong(pl) ;
 }
 
 }
 
-bool wxFileConfig::Write(const char *szKey, const char *szValue)
+bool wxFileConfig::DoWriteString(const wxString& key, const wxString& szValue)
 {
 {
-  PathChanger path(this, szKey);
+    wxConfigPathChanger     path(this, key);
+    wxString                strName = path.Name();
 
 
-  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!" );
+    wxLogTrace( _T("wxFileConfig"),
+                _T("  Writing String '%s' = '%s' to Group '%s'"),
+                strName.c_str(),
+                szValue.c_str(),
+                GetPath().c_str() );
 
 
-    // ... except if it's empty in which case it's a way to force it's creation
-    m_pCurrentGroup->SetDirty();
+    if ( strName.IsEmpty() )
+    {
+            // setting the value of a group is an error
 
 
-    // this will add a line for this group if it didn't have it before
-    (void)m_pCurrentGroup->GetGroupLine();
-  }
-  else {
-    // writing an entry
+        wxASSERT_MSG( wxIsEmpty(szValue), wxT("can't set value of a group!") );
 
 
-    // check that the name is reasonable
-    if ( strName[0u] == APPCONF_IMMUTABLE_PREFIX ) {
-      wxLogError(_("Entry name can't start with '%c'."),
-                 APPCONF_IMMUTABLE_PREFIX);
-      return FALSE;
-    }
+            // ... except if it's empty in which case it's a way to force it's creation
 
 
-    for ( const char *pc = strName; *pc != '\0'; pc++ ) {
-      if ( !IsValid(*pc) ) {
-        wxLogError(_("Character '%c' is invalid in a config entry name."),
-                   *pc);
-        return FALSE;
-      }
+        wxLogTrace( _T("wxFileConfig"),
+                    _T("  Creating group %s"),
+                    m_pCurrentGroup->Name().c_str() );
+
+        m_pCurrentGroup->SetDirty();
+
+            // this will add a line for this group if it didn't have it before
+
+        (void)m_pCurrentGroup->GetGroupLine();
     }
     }
+    else
+    {
+            // writing an entry
+            // check that the name is reasonable
+
+        if ( strName[0u] == wxCONFIG_IMMUTABLE_PREFIX )
+        {
+            wxLogError( _("Config entry name cannot start with '%c'."),
+                        wxCONFIG_IMMUTABLE_PREFIX);
+            return FALSE;
+        }
 
 
-    ConfigEntry *pEntry = m_pCurrentGroup->FindEntry(strName);
-    if ( pEntry == NULL )
-      pEntry = m_pCurrentGroup->AddEntry(strName);
+        wxFileConfigEntry   *pEntry = m_pCurrentGroup->FindEntry(strName);
 
 
-    pEntry->SetValue(szValue);
-  }
+        if ( pEntry == 0 )
+        {
+            wxLogTrace( _T("wxFileConfig"),
+                        _T("  Adding Entry %s"),
+                        strName.c_str() );
+            pEntry = m_pCurrentGroup->AddEntry(strName);
+        }
 
 
-  return TRUE;
+        wxLogTrace( _T("wxFileConfig"),
+                    _T("  Setting value %s"),
+                    szValue.c_str() );
+        pEntry->SetValue(szValue);
+    }
+
+    return TRUE;
 }
 
 }
 
-bool wxFileConfig::Write(const char *szKey, long lValue)
+bool wxFileConfig::DoWriteLong(const wxString& key, long lValue)
 {
 {
-  // ltoa() is not ANSI :-(
-  char szBuf[40];   // should be good for sizeof(long) <= 16 (128 bits)
-  sprintf(szBuf, "%ld", lValue);
-  return Write(szKey, szBuf);
+  return Write(key, wxString::Format(_T("%ld"), lValue));
 }
 
 bool wxFileConfig::Flush(bool /* bCurrentOnly */)
 {
 }
 
 bool wxFileConfig::Flush(bool /* bCurrentOnly */)
 {
-  if ( LineListIsEmpty() || !m_pRootGroup->IsDirty() )
+  if ( LineListIsEmpty() || !m_pRootGroup->IsDirty() || !m_strLocalFile )
     return TRUE;
 
     return TRUE;
 
+#ifdef __UNIX__
+  // set the umask if needed
+  mode_t umaskOld = 0;
+  if ( m_umask != -1 )
+  {
+      umaskOld = umask((mode_t)m_umask);
+  }
+#endif // __UNIX__
+
   wxTempFile file(m_strLocalFile);
 
   wxTempFile file(m_strLocalFile);
 
-  if ( !file.IsOpened() ) {
+  if ( !file.IsOpened() )
+  {
     wxLogError(_("can't open user configuration file."));
     return FALSE;
   }
 
   // write all strings to file
     wxLogError(_("can't open user configuration file."));
     return FALSE;
   }
 
   // write all strings to file
-  for ( LineList *p = m_linesHead; p != NULL; p = p->Next() ) {
-    if ( !file.Write(p->Text() + wxTextFile::GetEOL()) ) {
+  for ( wxFileConfigLineList *p = m_linesHead; p != NULL; p = p->Next() )
+  {
+    wxString line = p->Text();
+    line += wxTextFile::GetEOL();
+    if ( !file.Write(line, m_conv) )
+    {
       wxLogError(_("can't write user configuration file."));
       return FALSE;
     }
   }
 
       wxLogError(_("can't write user configuration file."));
       return FALSE;
     }
   }
 
-  return file.Commit();
+  bool ret = file.Commit();
+
+#if defined(__WXMAC__)
+  if ( ret )
+  {
+       FSSpec spec ;
+
+       wxMacFilename2FSSpec( m_strLocalFile , &spec ) ;
+       FInfo finfo ;
+       if ( FSpGetFInfo( &spec , &finfo ) == noErr )
+       {
+               finfo.fdType = 'TEXT' ;
+               finfo.fdCreator = 'ttxt' ;
+               FSpSetFInfo( &spec , &finfo ) ;
+       }
+  }
+#endif // __WXMAC__
+
+#ifdef __UNIX__
+  // restore the old umask if we changed it
+  if ( m_umask != -1 )
+  {
+      (void)umask(umaskOld);
+  }
+#endif // __UNIX__
+
+  return ret;
+}
+
+// ----------------------------------------------------------------------------
+// renaming groups/entries
+// ----------------------------------------------------------------------------
+
+bool wxFileConfig::RenameEntry(const wxString& oldName,
+                               const wxString& newName)
+{
+    // check that the entry exists
+    wxFileConfigEntry *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;
+
+    wxFileConfigEntry *newEntry = m_pCurrentGroup->AddEntry(newName);
+    newEntry->SetValue(value);
+
+    return TRUE;
+}
+
+bool wxFileConfig::RenameGroup(const wxString& oldName,
+                               const wxString& newName)
+{
+    // check that the group exists
+    wxFileConfigGroup *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 ( bGroupIfEmptyAlso && m_pCurrentGroup->IsEmpty() ) {
     if ( m_pCurrentGroup != m_pRootGroup ) {
 
   if ( !m_pCurrentGroup->DeleteEntry(path.Name()) )
     return FALSE;
 
   if ( bGroupIfEmptyAlso && m_pCurrentGroup->IsEmpty() ) {
     if ( m_pCurrentGroup != m_pRootGroup ) {
-      ConfigGroup *pGroup = m_pCurrentGroup;
-      SetPath("..");  // changes m_pCurrentGroup!
-      m_pCurrentGroup->DeleteSubgroup(pGroup->Name());
+      wxFileConfigGroup *pGroup = m_pCurrentGroup;
+      SetPath(wxT(".."));  // changes m_pCurrentGroup!
+      m_pCurrentGroup->DeleteSubgroupByName(pGroup->Name());
     }
     //else: never delete the root group
   }
     }
     //else: never delete the root group
   }
@@ -605,25 +1058,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()
 {
 }
 
 bool wxFileConfig::DeleteAll()
 {
-  const char *szFile = m_strLocalFile;
-  delete m_pRootGroup;
-  Init();
+  CleanUp();
 
 
-  if ( remove(szFile) == -1 )
-    wxLogSysError(_("can't delete user configuration file '%s'"), szFile);
+  if ( wxRemove(m_strLocalFile) == -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;
 }
@@ -632,78 +1082,139 @@ bool wxFileConfig::DeleteAll()
 // linked list functions
 // ----------------------------------------------------------------------------
 
 // linked list functions
 // ----------------------------------------------------------------------------
 
-// append a new line to the end of the list
-wxFileConfig::LineList *wxFileConfig::LineListAppend(const wxString& str)
+    // append a new line to the end of the list
+
+wxFileConfigLineList *wxFileConfig::LineListAppend(const wxString& str)
 {
 {
-  LineList *pLine = new LineList(str);
+    wxLogTrace( _T("wxFileConfig"),
+                _T("    ** Adding Line '%s'"),
+                str.c_str() );
+    wxLogTrace( _T("wxFileConfig"),
+                _T("        head: %s"),
+                ((m_linesHead) ? m_linesHead->Text().c_str() : wxEmptyString) );
+    wxLogTrace( _T("wxFileConfig"),
+                _T("        tail: %s"),
+                ((m_linesTail) ? m_linesTail->Text().c_str() : wxEmptyString) );
+
+    wxFileConfigLineList *pLine = new wxFileConfigLineList(str);
+
+    if ( m_linesTail == NULL )
+    {
+        // list is empty
+        m_linesHead = pLine;
+    }
+    else
+    {
+        // adjust pointers
+        m_linesTail->SetNext(pLine);
+        pLine->SetPrev(m_linesTail);
+    }
 
 
-  if ( m_linesTail == NULL ) {
-    // list is empty
-    m_linesHead = pLine;
-  }
-  else {
-    // adjust pointers
-    m_linesTail->SetNext(pLine);
-    pLine->SetPrev(m_linesTail);
-  }
+    m_linesTail = pLine;
+
+    wxLogTrace( _T("wxFileConfig"),
+                _T("        head: %s"),
+                ((m_linesHead) ? m_linesHead->Text().c_str() : wxEmptyString) );
+    wxLogTrace( _T("wxFileConfig"),
+                _T("        tail: %s"),
+                ((m_linesTail) ? m_linesTail->Text().c_str() : wxEmptyString) );
 
 
-  m_linesTail = pLine;
-  return m_linesTail;
+    return m_linesTail;
 }
 
 }
 
-// insert a new line after the given one or in the very beginning if !pLine
-wxFileConfig::LineList *wxFileConfig::LineListInsert(const wxString& str,
-                                                     LineList *pLine)
+    // insert a new line after the given one or in the very beginning if !pLine
+
+wxFileConfigLineList *wxFileConfig::LineListInsert(const wxString& str,
+                                                   wxFileConfigLineList *pLine)
 {
 {
-  if ( pLine == m_linesTail )
-    return LineListAppend(str);
+    wxLogTrace( _T("wxFileConfig"),
+                _T("    ** Inserting Line '%s' after '%s'"),
+                str.c_str(),
+                ((pLine) ? pLine->Text().c_str() : wxEmptyString) );
+    wxLogTrace( _T("wxFileConfig"),
+                _T("        head: %s"),
+                ((m_linesHead) ? m_linesHead->Text().c_str() : wxEmptyString) );
+    wxLogTrace( _T("wxFileConfig"),
+                _T("        tail: %s"),
+                ((m_linesTail) ? m_linesTail->Text().c_str() : wxEmptyString) );
+
+    if ( pLine == m_linesTail )
+        return LineListAppend(str);
+
+    wxFileConfigLineList *pNewLine = new wxFileConfigLineList(str);
+    if ( pLine == NULL )
+    {
+        // prepend to the list
+        pNewLine->SetNext(m_linesHead);
+        m_linesHead->SetPrev(pNewLine);
+        m_linesHead = pNewLine;
+    }
+    else
+    {
+        // insert before pLine
+        wxFileConfigLineList *pNext = pLine->Next();
+        pNewLine->SetNext(pNext);
+        pNewLine->SetPrev(pLine);
+        pNext->SetPrev(pNewLine);
+        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);
-  }
+    wxLogTrace( _T("wxFileConfig"),
+                _T("        head: %s"),
+                ((m_linesHead) ? m_linesHead->Text().c_str() : wxEmptyString) );
+    wxLogTrace( _T("wxFileConfig"),
+                _T("        tail: %s"),
+                ((m_linesTail) ? m_linesTail->Text().c_str() : wxEmptyString) );
 
 
-  return pNewLine;
+    return pNewLine;
 }
 
 }
 
-void wxFileConfig::LineListRemove(LineList *pLine)
+void wxFileConfig::LineListRemove(wxFileConfigLineList *pLine)
 {
 {
-  LineList *pPrev = pLine->Prev(),
-           *pNext = pLine->Next();
+    wxLogTrace( _T("wxFileConfig"),
+                _T("    ** Removing Line '%s'"),
+                pLine->Text().c_str() );
+    wxLogTrace( _T("wxFileConfig"),
+                _T("        head: %s"),
+                ((m_linesHead) ? m_linesHead->Text().c_str() : wxEmptyString) );
+    wxLogTrace( _T("wxFileConfig"),
+                _T("        tail: %s"),
+                ((m_linesTail) ? m_linesTail->Text().c_str() : wxEmptyString) );
+
+    wxFileConfigLineList    *pPrev = pLine->Prev(),
+                            *pNext = pLine->Next();
+
+        // first entry?
+
+    if ( pPrev == NULL )
+        m_linesHead = pNext;
+    else
+        pPrev->SetNext(pNext);
 
 
-  // first entry?
-  if ( pPrev == NULL )
-    m_linesHead = pNext;
-  else
-    pPrev->SetNext(pNext);
+        // last entry?
+
+    if ( pNext == NULL )
+        m_linesTail = pPrev;
+    else
+        pNext->SetPrev(pPrev);
 
 
-  // last entry?
-  if ( pNext == NULL )
-    m_linesTail = pPrev;
-  else    
-    pNext->SetPrev(pPrev);
+    wxLogTrace( _T("wxFileConfig"),
+                _T("        head: %s"),
+                ((m_linesHead) ? m_linesHead->Text().c_str() : wxEmptyString) );
+    wxLogTrace( _T("wxFileConfig"),
+                _T("        tail: %s"),
+                ((m_linesTail) ? m_linesTail->Text().c_str() : wxEmptyString) );
 
 
-  delete pLine;
+    delete pLine;
 }
 
 bool wxFileConfig::LineListIsEmpty()
 {
 }
 
 bool wxFileConfig::LineListIsEmpty()
 {
-  return m_linesHead == NULL;
+    return m_linesHead == NULL;
 }
 
 // ============================================================================
 }
 
 // ============================================================================
-// wxFileConfig::ConfigGroup
+// wxFileConfig::wxFileConfigGroup
 // ============================================================================
 
 // ----------------------------------------------------------------------------
 // ============================================================================
 
 // ----------------------------------------------------------------------------
@@ -711,7 +1222,7 @@ bool wxFileConfig::LineListIsEmpty()
 // ----------------------------------------------------------------------------
 
 // ctor
 // ----------------------------------------------------------------------------
 
 // ctor
-wxFileConfig::ConfigGroup::ConfigGroup(wxFileConfig::ConfigGroup *pParent,
+wxFileConfigGroup::wxFileConfigGroup(wxFileConfigGroup *pParent,
                                        const wxString& strName,
                                        wxFileConfig *pConfig)
                          : m_aEntries(CompareEntries),
                                        const wxString& strName,
                                        wxFileConfig *pConfig)
                          : m_aEntries(CompareEntries),
@@ -728,10 +1239,10 @@ wxFileConfig::ConfigGroup::ConfigGroup(wxFileConfig::ConfigGroup *pParent,
 }
 
 // dtor deletes all children
 }
 
 // dtor deletes all children
-wxFileConfig::ConfigGroup::~ConfigGroup()
+wxFileConfigGroup::~wxFileConfigGroup()
 {
   // 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];
 
@@ -745,11 +1256,10 @@ wxFileConfig::ConfigGroup::~ConfigGroup()
 // line
 // ----------------------------------------------------------------------------
 
 // line
 // ----------------------------------------------------------------------------
 
-void wxFileConfig::ConfigGroup::SetLine(LineList *pLine)
+void wxFileConfigGroup::SetLine(wxFileConfigLineList *pLine)
 {
 {
-  wxASSERT( m_pLine == NULL ); // shouldn't be called twice
-
-  m_pLine = pLine;
+    wxASSERT( m_pLine == 0 ); // shouldn't be called twice
+    m_pLine = pLine;
 }
 
 /*
 }
 
 /*
@@ -781,77 +1291,116 @@ 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()
-{
-  if ( m_pLine == NULL ) {
-    ConfigGroup *pParent = Parent();
-
-    // this group wasn't present in local config file, add it now
-    if ( pParent != NULL ) {
-      wxString strFullName;
-      strFullName << "[" << GetFullName().c_str() + 1 << "]"; // +1: no '/'
-      m_pLine = m_pConfig->LineListInsert(strFullName,
-                                          pParent->GetLastGroupLine());
-      pParent->SetLastGroup(this);  // we're surely after all the others
-    }
-    else {
-      // we return NULL, so that LineListInsert() will insert us in the
-      // very beginning
+wxFileConfigLineList *wxFileConfigGroup::GetGroupLine()
+{
+    wxLogTrace( _T("wxFileConfig"),
+                _T("  GetGroupLine() for Group '%s'"),
+                Name().c_str() );
+
+    if ( m_pLine == 0 )
+    {
+        wxLogTrace( _T("wxFileConfig"),
+                    _T("    Getting Line item pointer") );
+
+        wxFileConfigGroup   *pParent = Parent();
+
+            // this group wasn't present in local config file, add it now
+
+        if ( pParent != 0 )
+        {
+            wxLogTrace( _T("wxFileConfig"),
+                        _T("    checking parent '%s'"),
+                        pParent->Name().c_str() );
+
+            wxString    strFullName;
+
+            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
+        }
+        else
+        {
+            // we return NULL, so that LineListInsert() will insert us in the
+            // very beginning
+        }
     }
     }
-  }
 
 
-  return m_pLine;
+    return m_pLine;
 }
 
 // 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()
+wxFileConfigLineList *wxFileConfigGroup::GetLastGroupLine()
 {
 {
-  // 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();
+        // if we have any subgroups, our last line is
+        // the last line of the last subgroup
 
 
-    wxASSERT( pLine != NULL );  // last group must have !NULL associated line
-    return pLine;
-  }
+    if ( m_pLastGroup != 0 )
+    {
+        wxFileConfigLineList *pLine = m_pLastGroup->GetLastGroupLine();
+
+        wxASSERT( pLine != 0 );  // last group must have !NULL associated line
+        return pLine;
+    }
+
+        // no subgroups, so the last line is the line of thelast entry (if any)
 
 
-  // no subgroups, so the last line is the line of thelast entry (if any)
-  return GetLastEntryLine();
+    return GetLastEntryLine();
 }
 
 // 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()
+wxFileConfigLineList *wxFileConfigGroup::GetLastEntryLine()
 {
 {
-  if ( m_pLastEntry != NULL ) {
-    wxFileConfig::LineList *pLine = m_pLastEntry->GetLine();
+    wxLogTrace( _T("wxFileConfig"),
+                _T("  GetLastEntryLine() for Group '%s'"),
+                Name().c_str() );
 
 
-    wxASSERT( pLine != NULL );  // last entry must have !NULL associated line
-    return pLine;
-  }
+    if ( m_pLastEntry != 0 )
+    {
+        wxFileConfigLineList    *pLine = m_pLastEntry->GetLine();
+
+        wxASSERT( pLine != 0 );  // last entry must have !NULL associated line
+        return pLine;
+    }
 
 
-  // no entries: insert after the group header
-  return GetGroupLine();
+        // no entries: insert after the group header
+
+    return GetGroupLine();
 }
 
 // ----------------------------------------------------------------------------
 // group name
 // ----------------------------------------------------------------------------
 
 }
 
 // ----------------------------------------------------------------------------
 // group name
 // ----------------------------------------------------------------------------
 
-wxString wxFileConfig::ConfigGroup::GetFullName() const
+void wxFileConfigGroup::Rename(const wxString& newName)
+{
+    m_strName = newName;
+
+    wxFileConfigLineList *line = GetGroupLine();
+    wxString strFullName;
+    strFullName << wxT("[") << (GetFullName().c_str() + 1) << wxT("]"); // +1: no '/'
+    line->SetText(strFullName);
+
+    SetDirty();
+}
+
+wxString wxFileConfigGroup::GetFullName() const
 {
   if ( Parent() )
 {
   if ( Parent() )
-    return Parent()->GetFullName() + APPCONF_PATH_SEPARATOR + Name();
+    return Parent()->GetFullName() + wxCONFIG_PATH_SEPARATOR + Name();
   else
   else
-    return "";
+    return wxT("");
 }
 
 // ----------------------------------------------------------------------------
 }
 
 // ----------------------------------------------------------------------------
@@ -859,23 +1408,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
+wxFileConfigEntry *
+wxFileConfigGroup::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;
+  wxFileConfigEntry *pEntry;
 
   while ( lo < hi ) {
     i = (lo + hi)/2;
     pEntry = m_aEntries[i];
 
 
   while ( lo < hi ) {
     i = (lo + hi)/2;
     pEntry = m_aEntries[i];
 
-    #if APPCONF_CASE_SENSITIVE
-      res = strcmp(pEntry->Name(), szName);
+    #if wxCONFIG_CASE_SENSITIVE
+      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 )
@@ -889,23 +1438,23 @@ wxFileConfig::ConfigGroup::FindEntry(const char *szName) const
   return NULL;
 }
 
   return NULL;
 }
 
-wxFileConfig::ConfigGroup *
-wxFileConfig::ConfigGroup::FindSubgroup(const char *szName) const
+wxFileConfigGroup *
+wxFileConfigGroup::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;
+  wxFileConfigGroup *pGroup;
 
   while ( lo < hi ) {
     i = (lo + hi)/2;
     pGroup = m_aSubgroups[i];
 
 
   while ( lo < hi ) {
     i = (lo + hi)/2;
     pGroup = m_aSubgroups[i];
 
-    #if APPCONF_CASE_SENSITIVE
-      res = strcmp(pGroup->Name(), szName);
+    #if wxCONFIG_CASE_SENSITIVE
+      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 )
@@ -924,27 +1473,25 @@ 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)
+wxFileConfigEntry *wxFileConfigGroup::AddEntry(const wxString& strName, int nLine)
 {
 {
-  wxASSERT( FindEntry(strName) == NULL );
+    wxASSERT( FindEntry(strName) == 0 );
 
 
-  ConfigEntry *pEntry = new ConfigEntry(this, strName, nLine);
-  m_aEntries.Add(pEntry);
+    wxFileConfigEntry   *pEntry = new wxFileConfigEntry(this, strName, nLine);
 
 
-  return pEntry;
+    m_aEntries.Add(pEntry);
+    return pEntry;
 }
 
 // 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)
+wxFileConfigGroup *wxFileConfigGroup::AddSubgroup(const wxString& strName)
 {
 {
-  wxASSERT( FindSubgroup(strName) == NULL );
+    wxASSERT( FindSubgroup(strName) == 0 );
 
 
-  ConfigGroup *pGroup = new ConfigGroup(this, strName, m_pConfig);
-  m_aSubgroups.Add(pGroup);
+    wxFileConfigGroup   *pGroup = new wxFileConfigGroup(this, strName, m_pConfig);
 
 
-  return pGroup;
+    m_aSubgroups.Add(pGroup);
+    return pGroup;
 }
 
 // ----------------------------------------------------------------------------
 }
 
 // ----------------------------------------------------------------------------
@@ -958,70 +1505,160 @@ wxFileConfig::ConfigGroup::AddSubgroup(const wxString& strName)
   delete several of them.
  */
 
   delete several of them.
  */
 
-bool wxFileConfig::ConfigGroup::DeleteSubgroup(const char *szName)
+bool wxFileConfigGroup::DeleteSubgroupByName(const wxChar *szName)
 {
 {
-  ConfigGroup *pGroup = FindSubgroup(szName);
-  wxCHECK( pGroup != NULL, FALSE ); // deleting non existing group?
-
-  // delete all entries
-  uint nCount = pGroup->m_aEntries.Count();
-  for ( uint nEntry = 0; nEntry < nCount; nEntry++ ) {
-    LineList *pLine = pGroup->m_aEntries[nEntry]->GetLine();
-    if ( pLine != NULL )
-      m_pConfig->LineListRemove(pLine);
-  }
+    wxFileConfigGroup * const pGroup = FindSubgroup(szName);
 
 
-  LineList *pLine = pGroup->m_pLine;
-  if ( pLine != NULL ) {
-    // notice that we may do this test inside the previous "if" because the
-    // last entry's line is surely !NULL
-    if ( pGroup == m_pLastGroup ) {
-      // our last entry is being deleted - find the last one which stays
-      wxASSERT( m_pLine != NULL );  // we have a subgroup with !NULL pLine...
+    return pGroup ? DeleteSubgroup(pGroup) : FALSE;
+}
 
 
-      // go back until we find a subgroup or reach the group's line
-      ConfigGroup *pNewLast = NULL;
-      uint n, nSubgroups = m_aSubgroups.Count();
-      for ( LineList *pl = pLine->Prev(); pl != m_pLine; pl = pl->Prev() ) {
-        // is it our subgroup?
-        for ( n = 0; (pNewLast == NULL) && (n < nSubgroups); n++ ) {
-          // do _not_ call GetGroupLine! we don't want to add it to the local
-          // file if it's not already there
-          if ( m_aSubgroups[n]->m_pLine == m_pLine )
-            pNewLast = m_aSubgroups[n];
+// Delete the subgroup and remove all references to it from
+// other data structures.
+bool wxFileConfigGroup::DeleteSubgroup(wxFileConfigGroup *pGroup)
+{
+    wxCHECK_MSG( pGroup, FALSE, _T("deleting non existing group?") );
+
+    wxLogTrace( _T("wxFileConfig"),
+                _T("Deleting group '%s' from '%s'"),
+                pGroup->Name().c_str(),
+                Name().c_str() );
+
+    wxLogTrace( _T("wxFileConfig"),
+                _T("  (m_pLine) = prev: %p, this %p, next %p"),
+                ((m_pLine) ? m_pLine->Prev() : 0),
+                m_pLine,
+                ((m_pLine) ? m_pLine->Next() : 0) );
+    wxLogTrace( _T("wxFileConfig"),
+                _T("  text: '%s'"),
+                ((m_pLine) ? m_pLine->Text().c_str() : wxEmptyString) );
+
+    // delete all entries
+    size_t nCount = pGroup->m_aEntries.Count();
+
+    wxLogTrace(_T("wxFileConfig"),
+               _T("Removing %lu Entries"),
+               (unsigned long)nCount );
+
+    for ( size_t nEntry = 0; nEntry < nCount; nEntry++ )
+    {
+        wxFileConfigLineList    *pLine = pGroup->m_aEntries[nEntry]->GetLine();
+
+        if ( pLine != 0 )
+        {
+            wxLogTrace( _T("wxFileConfig"),
+                        _T("    '%s'"),
+                        pLine->Text().c_str() );
+            m_pConfig->LineListRemove(pLine);
         }
         }
+    }
 
 
-        if ( pNewLast != NULL ) // found?
-          break;
-      }
+        // and subgroups of this subgroup
 
 
-      if ( pl == m_pLine ) {
-        wxASSERT( !pNewLast );  // how comes it has the same line as we?
+    nCount = pGroup->m_aSubgroups.Count();
 
 
-        // we've reached the group line without finding any subgroups
-        m_pLastGroup = NULL;
-      }
-      else
-        m_pLastGroup = pNewLast;
+    wxLogTrace( _T("wxFileConfig"),
+                _T("Removing %lu SubGroups"),
+                (unsigned long)nCount );
+
+    for ( size_t nGroup = 0; nGroup < nCount; nGroup++ )
+    {
+        pGroup->DeleteSubgroup(pGroup->m_aSubgroups[0]);
     }
 
     }
 
-    m_pConfig->LineListRemove(pLine);
-  }
+        // finally the group itself
+
+    wxFileConfigLineList    *pLine = pGroup->m_pLine;
+
+    if ( pLine != 0 )
+    {
+        wxLogTrace( _T("wxFileConfig"),
+                    _T("  Removing line entry for Group '%s' : '%s'"),
+                    pGroup->Name().c_str(),
+                    pLine->Text().c_str() );
+        wxLogTrace( _T("wxFileConfig"),
+                    _T("  Removing from Group '%s' : '%s'"),
+                    Name().c_str(),
+                    ((m_pLine) ? m_pLine->Text().c_str() : wxEmptyString) );
+
+            // notice that we may do this test inside the previous "if"
+            // because the last entry's line is surely !NULL
+
+        if ( pGroup == m_pLastGroup )
+        {
+            wxLogTrace( _T("wxFileConfig"),
+                        _T("  ------- Removing last group -------") );
+
+                // our last entry is being deleted, so find the last one which stays.
+                // go back until we find a subgroup or reach the group's line, unless
+                // we are the root group, which we'll notice shortly.
+
+            wxFileConfigGroup       *pNewLast = 0;
+            size_t                   nSubgroups = m_aSubgroups.Count();
+            wxFileConfigLineList    *pl;
+
+            for ( pl = pLine->Prev(); pl != m_pLine; pl = pl->Prev() )
+            {
+                    // is it our subgroup?
+
+                for ( size_t n = 0; (pNewLast == 0) && (n < nSubgroups); n++ )
+                {
+                    // do _not_ call GetGroupLine! we don't want to add it to the local
+                    // file if it's not already there
+
+                    if ( m_aSubgroups[n]->m_pLine == m_pLine )
+                        pNewLast = m_aSubgroups[n];
+                }
+
+                if ( pNewLast != 0 ) // found?
+                    break;
+            }
+
+            if ( pl == m_pLine || m_pParent == 0 )
+            {
+                wxLogTrace( _T("wxFileConfig"),
+                            _T("  ------- No previous group found -------") );
+
+                wxASSERT_MSG( !pNewLast || m_pLine == 0,
+                              _T("how comes it has the same line as we?") );
+
+                    // we've reached the group line without finding any subgroups,
+                    // or realised we removed the last group from the root.
+
+                m_pLastGroup = 0;
+            }
+            else
+            {
+                wxLogTrace( _T("wxFileConfig"),
+                            _T("  ------- Last Group set to '%s' -------"),
+                            pNewLast->Name().c_str() );
+
+                m_pLastGroup = pNewLast;
+            }
+        }
 
 
-  SetDirty();
+        m_pConfig->LineListRemove(pLine);
+    }
+    else
+    {
+        wxLogTrace( _T("wxFileConfig"),
+                    _T("  No line entry for Group '%s'?"),
+                    pGroup->Name().c_str() );
+    }
+
+    SetDirty();
 
 
-  m_aSubgroups.Remove(pGroup);
-  delete pGroup;
+    m_aSubgroups.Remove(pGroup);
+    delete pGroup;
 
 
-  return TRUE;
+    return TRUE;
 }
 
 }
 
-bool wxFileConfig::ConfigGroup::DeleteEntry(const char *szName)
+bool wxFileConfigGroup::DeleteEntry(const wxChar *szName)
 {
 {
-  ConfigEntry *pEntry = FindEntry(szName);
+  wxFileConfigEntry *pEntry = FindEntry(szName);
   wxCHECK( pEntry != NULL, FALSE );  // deleting non existing item?
 
   wxCHECK( pEntry != NULL, FALSE );  // deleting non existing item?
 
-  LineList *pLine = pEntry->GetLine();
+  wxFileConfigLineList *pLine = pEntry->GetLine();
   if ( pLine != NULL ) {
     // notice that we may do this test inside the previous "if" because the
     // last entry's line is surely !NULL
   if ( pLine != NULL ) {
     // notice that we may do this test inside the previous "if" because the
     // last entry's line is surely !NULL
@@ -1030,9 +1667,10 @@ bool wxFileConfig::ConfigGroup::DeleteEntry(const char *szName)
       wxASSERT( m_pLine != NULL );  // if we have an entry with !NULL pLine...
 
       // go back until we find another entry or reach the group's line
       wxASSERT( m_pLine != NULL );  // if we have an entry with !NULL pLine...
 
       // go back until we find another entry or reach the group's line
-      ConfigEntry *pNewLast = NULL;
-      uint n, nEntries = m_aEntries.Count();
-      for ( LineList *pl = pLine->Prev(); pl != m_pLine; pl = pl->Prev() ) {
+      wxFileConfigEntry *pNewLast = NULL;
+      size_t n, nEntries = m_aEntries.Count();
+      wxFileConfigLineList *pl;
+      for ( pl = pLine->Prev(); pl != m_pLine; pl = pl->Prev() ) {
         // is it our subgroup?
         for ( n = 0; (pNewLast == NULL) && (n < nEntries); n++ ) {
           if ( m_aEntries[n]->GetLine() == m_pLine )
         // is it our subgroup?
         for ( n = 0; (pNewLast == NULL) && (n < nEntries); n++ ) {
           if ( m_aEntries[n]->GetLine() == m_pLine )
@@ -1068,7 +1706,7 @@ bool wxFileConfig::ConfigGroup::DeleteEntry(const char *szName)
 // ----------------------------------------------------------------------------
 //
 // ----------------------------------------------------------------------------
 // ----------------------------------------------------------------------------
 //
 // ----------------------------------------------------------------------------
-void wxFileConfig::ConfigGroup::SetDirty()
+void wxFileConfigGroup::SetDirty()
 {
   m_bDirty = TRUE;
   if ( Parent() != NULL )             // propagate upwards
 {
   m_bDirty = TRUE;
   if ( Parent() != NULL )             // propagate upwards
@@ -1076,13 +1714,13 @@ void wxFileConfig::ConfigGroup::SetDirty()
 }
 
 // ============================================================================
 }
 
 // ============================================================================
-// wxFileConfig::ConfigEntry
+// wxFileConfig::wxFileConfigEntry
 // ============================================================================
 
 // ----------------------------------------------------------------------------
 // ctor
 // ----------------------------------------------------------------------------
 // ============================================================================
 
 // ----------------------------------------------------------------------------
 // ctor
 // ----------------------------------------------------------------------------
-wxFileConfig::ConfigEntry::ConfigEntry(wxFileConfig::ConfigGroup *pParent,
+wxFileConfigEntry::wxFileConfigEntry(wxFileConfigGroup *pParent,
                                        const wxString& strName,
                                        int nLine)
                          : m_strName(strName)
                                        const wxString& strName,
                                        int nLine)
                          : m_strName(strName)
@@ -1093,9 +1731,10 @@ wxFileConfig::ConfigEntry::ConfigEntry(wxFileConfig::ConfigGroup *pParent,
   m_nLine   = nLine;
   m_pLine   = NULL;
 
   m_nLine   = nLine;
   m_pLine   = NULL;
 
-  m_bDirty  = FALSE;
+  m_bDirty =
+  m_bHasValue = FALSE;
 
 
-  m_bImmutable = strName[0] == APPCONF_IMMUTABLE_PREFIX;
+  m_bImmutable = strName[0] == wxCONFIG_IMMUTABLE_PREFIX;
   if ( m_bImmutable )
     m_strName.erase(0, 1);  // remove first character
 }
   if ( m_bImmutable )
     m_strName.erase(0, 1);  // remove first character
 }
@@ -1104,7 +1743,7 @@ wxFileConfig::ConfigEntry::ConfigEntry(wxFileConfig::ConfigGroup *pParent,
 // set value
 // ----------------------------------------------------------------------------
 
 // set value
 // ----------------------------------------------------------------------------
 
-void wxFileConfig::ConfigEntry::SetLine(LineList *pLine)
+void wxFileConfigEntry::SetLine(wxFileConfigLineList *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'"),
@@ -1117,43 +1756,59 @@ 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 wxFileConfigEntry::SetValue(const wxString& strValue, bool bUser)
 {
 {
-  if ( bUser && IsImmutable() ) {
-    wxLogWarning(_("attempt to change immutable key '%s' ignored."),
-                 Name().c_str());
-    return;
-  }
+    if ( bUser && IsImmutable() )
+    {
+        wxLogWarning( _("attempt to change immutable key '%s' ignored."),
+                      Name().c_str());
+        return;
+    }
 
 
-  // do nothing if it's the same value
-  if ( strValue == m_strValue )
-    return;
+        // do nothing if it's the same value: but don't test for it
+        // if m_bHasValue hadn't been set yet or we'd never write
+        // empty values to the file
 
 
-  m_strValue = strValue;
+    if ( m_bHasValue && strValue == m_strValue )
+        return;
 
 
-  if ( bUser ) {
-    wxString strVal = FilterOut(strValue);
-    wxString strLine;
-    strLine << m_strName << " = " << strVal;
+    m_bHasValue = TRUE;
+    m_strValue = strValue;
 
 
-    if ( m_pLine != NULL ) {
-      // entry was read from the local config file, just modify the line
-      m_pLine->SetText(strLine);
-    }
-    else {
-      // add a new line to the file
-      wxASSERT( m_nLine == NOT_FOUND );   // consistency check
+    if ( bUser )
+    {
+        wxString    strValFiltered;
 
 
-      m_pLine = Group()->Config()->LineListInsert(strLine,
-                                                  Group()->GetLastEntryLine());
-      Group()->SetLastEntry(this);
-    }
+        if ( Group()->Config()->GetStyle() & wxCONFIG_USE_NO_ESCAPE_CHARACTERS )
+        {
+            strValFiltered = strValue;
+        }
+        else {
+            strValFiltered = FilterOutValue(strValue);
+        }
 
 
-    SetDirty();
-  }
+        wxString    strLine;
+        strLine << FilterOutEntryName(m_strName) << wxT('=') << strValFiltered;
+
+        if ( m_pLine != 0 )
+        {
+            // entry was read from the local config file, just modify the line
+            m_pLine->SetText(strLine);
+        }
+        else {
+            // add a new line to the file
+            wxASSERT( m_nLine == wxNOT_FOUND );   // consistency check
+
+            m_pLine = Group()->Config()->LineListInsert(strLine,
+                                                        Group()->GetLastEntryLine());
+            Group()->SetLastEntry(this);
+        }
+
+        SetDirty();
+    }
 }
 
 }
 
-void wxFileConfig::ConfigEntry::SetDirty()
+void wxFileConfigEntry::SetDirty()
 {
   m_bDirty = TRUE;
   Group()->SetDirty();
 {
   m_bDirty = TRUE;
   Group()->SetDirty();
@@ -1167,23 +1822,21 @@ void wxFileConfig::ConfigEntry::SetDirty()
 // compare functions for array sorting
 // ----------------------------------------------------------------------------
 
 // compare functions for array sorting
 // ----------------------------------------------------------------------------
 
-int CompareEntries(wxFileConfig::ConfigEntry *p1,
-                   wxFileConfig::ConfigEntry *p2)
+int CompareEntries(wxFileConfigEntry *p1, wxFileConfigEntry *p2)
 {
 {
-  #if APPCONF_CASE_SENSITIVE
-    return strcmp(p1->Name(), p2->Name());
+  #if wxCONFIG_CASE_SENSITIVE
+    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(wxFileConfigGroup *p1, wxFileConfigGroup *p2)
 {
 {
-  #if APPCONF_CASE_SENSITIVE
-    return strcmp(p1->Name(), p2->Name());
+  #if wxCONFIG_CASE_SENSITIVE
+    return wxStrcmp(p1->Name(), p2->Name());
   #else
   #else
-    return Stricmp(p1->Name(), p2->Name());
+    return wxStricmp(p1->Name(), p2->Name());
   #endif
 }
 
   #endif
 }
 
@@ -1191,40 +1844,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'."),
@@ -1238,39 +1891,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:
@@ -1279,11 +1937,64 @@ 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;
 }
 
   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;
+}
+
+// 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
+
+
+// vi:sts=4:sw=4:et