]> git.saurik.com Git - wxWidgets.git/blobdiff - src/common/fileconf.cpp
rename old wxAppConsole to wxAppConsoleBase and wxAppConsoleUnix to wxAppConsole...
[wxWidgets.git] / src / common / fileconf.cpp
index 5e84cf2c415d4d1a310e47690fc9ffec73ff919e..0c3912dbdb76b96775c7191a3ff64d257974552d 100644 (file)
 // headers
 // ----------------------------------------------------------------------------
 
 // headers
 // ----------------------------------------------------------------------------
 
+// For compilers that support precompilation, includes "wx.h".
 #include  "wx/wxprec.h"
 
 #ifdef    __BORLANDC__
 #include  "wx/wxprec.h"
 
 #ifdef    __BORLANDC__
-  #pragma hdrstop
+    #pragma hdrstop
 #endif  //__BORLANDC__
 
 #if wxUSE_CONFIG && wxUSE_FILECONFIG
 
 #ifndef   WX_PRECOMP
 #endif  //__BORLANDC__
 
 #if wxUSE_CONFIG && wxUSE_FILECONFIG
 
 #ifndef   WX_PRECOMP
-  #include  "wx/string.h"
-  #include  "wx/intl.h"
+    #include  "wx/dynarray.h"
+    #include  "wx/string.h"
+    #include  "wx/intl.h"
+    #include  "wx/log.h"
+    #include  "wx/app.h"
+    #include  "wx/utils.h"    // for wxGetHomeDir
+    #if wxUSE_STREAMS
+        #include  "wx/stream.h"
+    #endif // wxUSE_STREAMS
 #endif  //WX_PRECOMP
 
 #endif  //WX_PRECOMP
 
-#include  "wx/app.h"
-#include  "wx/dynarray.h"
 #include  "wx/file.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"
 #include  "wx/filefn.h"
 
 #include  "wx/textfile.h"
 #include  "wx/memtext.h"
 #include  "wx/config.h"
 #include  "wx/fileconf.h"
 #include  "wx/filefn.h"
 
-#if wxUSE_STREAMS
-    #include  "wx/stream.h"
-#endif // wxUSE_STREAMS
-
-#include  "wx/utils.h"    // for wxGetHomeDir
+#include  "wx/stdpaths.h"
 
 #if defined(__WXMAC__)
 
 #if defined(__WXMAC__)
-  #include  "wx/mac/private.h"  // includes mac headers
-  #include  "wx/filename.h"     // for MacSetTypeAndCreator
+    #include  "wx/mac/private.h"  // includes mac headers
 #endif
 
 #if defined(__WXMSW__)
 #endif
 
 #if defined(__WXMSW__)
-  #include "wx/msw/private.h"
+    #include "wx/msw/private.h"
 #endif  //windows.h
 #if defined(__WXPM__)
 #endif  //windows.h
 #if defined(__WXPM__)
-  #define INCL_DOS
-  #include <os2.h>
+    #define INCL_DOS
+    #include <os2.h>
 #endif
 
 #include  <stdlib.h>
 #endif
 
 #include  <stdlib.h>
@@ -69,7 +69,7 @@
 // ----------------------------------------------------------------------------
 
 #ifndef MAX_PATH
 // ----------------------------------------------------------------------------
 
 #ifndef MAX_PATH
-  #define MAX_PATH 512
+    #define MAX_PATH 512
 #endif
 
 #define FILECONF_TRACE_MASK _T("fileconf")
 #endif
 
 #define FILECONF_TRACE_MASK _T("fileconf")
@@ -261,123 +261,77 @@ public:
 // ----------------------------------------------------------------------------
 // static functions
 // ----------------------------------------------------------------------------
 // ----------------------------------------------------------------------------
 // static functions
 // ----------------------------------------------------------------------------
-wxString wxFileConfig::GetGlobalDir()
-{
-  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(__OS2__)
-    ULONG aulSysInfo[QSV_MAX] = {0};
-    UINT drive;
-    APIRET rc;
-
-    rc = DosQuerySysInfo( 1L, QSV_MAX, (PVOID)aulSysInfo, sizeof(ULONG)*QSV_MAX);
-    if (rc == 0)
+// this function modifies in place the given wxFileName object if it doesn't
+// already have an extension
+//
+// note that it's slightly misnamed under Mac as there it doesn't add an
+// extension but modifies the file name instead, so you shouldn't suppose that
+// fn.HasExt() is true after it returns
+static void AddConfFileExtIfNeeded(wxFileName& fn)
+{
+    if ( !fn.HasExt() )
     {
     {
-        drive = aulSysInfo[QSV_BOOT_DRIVE - 1];
-        strDir.Printf(wxT("%c:\\OS2\\"), 'A'+drive-1);
+#if defined( __WXMAC__ )
+        fn.SetName(fn.GetName() + wxT(" Preferences"));
+#elif defined( __UNIX__ )
+        fn.SetExt(wxT(".conf"));
+#else   // Windows
+        fn.SetExt(wxT(".ini"));
+#endif  // UNIX/Win
     }
     }
-#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?)
-    strDir = wxT(".\\");
-#elif defined(__WXWINCE__)
-    strDir = wxT("\\Windows\\");
-#else // Windows
-
-    wxChar szWinDir[MAX_PATH];
-    ::GetWindowsDirectory(szWinDir, MAX_PATH);
-
-    strDir = szWinDir;
-    strDir << wxT('\\');
-#endif // Unix/Windows
-
-    return strDir;
 }
 
 }
 
-wxString wxFileConfig::GetLocalDir()
+wxString wxFileConfig::GetGlobalDir()
 {
 {
-    wxString strDir;
-
-#if defined(__WXMAC__) || defined(__DOS__)
-    // no local dir concept on Mac OS 9 or MS-DOS
-    strDir << GetGlobalDir() ;
-#else
-    wxGetHomeDir(&strDir);
-
-    #ifdef  __UNIX__
-        if (
-            (strDir.Last() != wxT('/'))
-        #ifdef __VMS
-            && (strDir.Last() != wxT(']'))
-        #endif
-            )
-            strDir << wxT('/');
-    #else
-        if (strDir.Last() != wxT('\\'))
-            strDir << wxT('\\');
-    #endif
-#endif
-
-    return strDir;
+    return wxStandardPaths::Get().GetConfigDir();
 }
 
 }
 
-wxString wxFileConfig::GetGlobalFileName(const wxChar *szFile)
+wxString wxFileConfig::GetLocalDir(int style)
 {
 {
-    wxString str = GetGlobalDir();
-    str << szFile;
+    wxUnusedVar(style);
 
 
-    if ( wxStrchr(szFile, wxT('.')) == NULL )
-#if defined( __WXMAC__ )
-        str << wxT(" Preferences") ;
-#elif defined( __UNIX__ )
-        str << wxT(".conf");
-#else   // Windows
-        str << wxT(".ini");
-#endif  // UNIX/Win
+    wxStandardPathsBase& stdp = wxStandardPaths::Get();
 
 
-    return str;
+    // it so happens that user data directory is a subdirectory of user config
+    // directory on all supported platforms, which explains why we use it here
+    return style & wxCONFIG_USE_SUBDIR ? stdp.GetUserDataDir()
+                                       : stdp.GetUserConfigDir();
 }
 
 }
 
-wxString wxFileConfig::GetLocalFileName(const wxChar *szFile)
+wxFileName wxFileConfig::GetGlobalFile(const wxString& 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
+    wxFileName fn(GetGlobalDir(), szFile);
 
 
-#if defined( __UNIX__ ) && !defined( __VMS ) && !defined( __WXMAC__ )
-    str << wxT('.');
-#endif
+    AddConfFileExtIfNeeded(fn);
 
 
-    str << szFile;
+    return fn;
+}
 
 
-#if defined(__WINDOWS__) || defined(__DOS__)
-    if ( wxStrchr(szFile, wxT('.')) == NULL )
-        str << wxT(".ini");
-#endif
+wxFileName wxFileConfig::GetLocalFile(const wxString& szFile, int style)
+{
+    wxFileName fn(GetLocalDir(style), szFile);
 
 
-#ifdef __WXMAC__
-    str << wxT(" Preferences") ;
-#endif
+#ifdef __UNIX__
+    if ( !(style & wxCONFIG_USE_SUBDIR) )
+    {
+        // dot-files under Unix start with, well, a dot (but OTOH they usually
+        // don't have any specific extension)
+        fn.SetName(wxT('.') + fn.GetName());
+    }
+    else // we do append ".conf" extension to config files in subdirectories
+#endif // __UNIX__
+    {
+        AddConfFileExtIfNeeded(fn);
+    }
 
 
-    return str;
+    return fn;
 }
 
 // ----------------------------------------------------------------------------
 // ctor
 // ----------------------------------------------------------------------------
 }
 
 // ----------------------------------------------------------------------------
 // ctor
 // ----------------------------------------------------------------------------
+IMPLEMENT_ABSTRACT_CLASS(wxFileConfig, wxConfigBase)
 
 void wxFileConfig::Init()
 {
 
 void wxFileConfig::Init()
 {
@@ -390,33 +344,33 @@ void wxFileConfig::Init()
     // It's not an error if (one of the) file(s) doesn't exist.
 
     // parse the global file
     // It's not an error if (one of the) file(s) doesn't exist.
 
     // parse the global file
-    if ( !m_strGlobalFile.empty() && wxFile::Exists(m_strGlobalFile) )
+    if ( m_fnGlobalFile.IsOk() && m_fnGlobalFile.FileExists() )
     {
     {
-        wxTextFile fileGlobal(m_strGlobalFile);
+        wxTextFile fileGlobal(m_fnGlobalFile.GetFullPath());
 
 
-        if ( fileGlobal.Open(m_conv/*ignored in ANSI build*/) )
+        if ( fileGlobal.Open(*m_conv/*ignored in ANSI build*/) )
         {
             Parse(fileGlobal, false /* global */);
             SetRootPath();
         }
         else
         {
         {
             Parse(fileGlobal, false /* global */);
             SetRootPath();
         }
         else
         {
-            wxLogWarning(_("can't open global configuration file '%s'."), m_strGlobalFile.c_str());
+            wxLogWarning(_("can't open global configuration file '%s'."), m_fnGlobalFile.GetFullPath().c_str());
         }
     }
 
     // parse the local file
         }
     }
 
     // parse the local file
-    if ( !m_strLocalFile.empty() && wxFile::Exists(m_strLocalFile) )
+    if ( m_fnLocalFile.IsOk() && m_fnLocalFile.FileExists() )
     {
     {
-        wxTextFile fileLocal(m_strLocalFile);
-        if ( fileLocal.Open(m_conv/*ignored in ANSI build*/) )
+        wxTextFile fileLocal(m_fnLocalFile.GetFullPath());
+        if ( fileLocal.Open(*m_conv/*ignored in ANSI build*/) )
         {
             Parse(fileLocal, true /* local */);
             SetRootPath();
         }
         else
         {
         {
             Parse(fileLocal, true /* local */);
             SetRootPath();
         }
         else
         {
-            wxLogWarning(_("can't open user configuration file '%s'."),  m_strLocalFile.c_str() );
+            wxLogWarning(_("can't open user configuration file '%s'."),  m_fnLocalFile.GetFullPath().c_str() );
         }
     }
 
         }
     }
 
@@ -431,41 +385,34 @@ wxFileConfig::wxFileConfig(const wxString& appName, const wxString& vendorName,
             : wxConfigBase(::GetAppName(appName), vendorName,
                            strLocal, strGlobal,
                            style),
             : wxConfigBase(::GetAppName(appName), vendorName,
                            strLocal, strGlobal,
                            style),
-              m_strLocalFile(strLocal), m_strGlobalFile(strGlobal),
-              m_conv(conv)
+              m_fnLocalFile(strLocal),
+              m_fnGlobalFile(strGlobal),
+              m_conv(conv.Clone())
 {
     // Make up names for files if empty
 {
     // Make up names for files if empty
-    if ( m_strLocalFile.empty() && (style & wxCONFIG_USE_LOCAL_FILE) )
-        m_strLocalFile = GetLocalFileName(GetAppName());
+    if ( !m_fnLocalFile.IsOk() && (style & wxCONFIG_USE_LOCAL_FILE) )
+        m_fnLocalFile = GetLocalFile(GetAppName(), style);
 
 
-    if ( m_strGlobalFile.empty() && (style & wxCONFIG_USE_GLOBAL_FILE) )
-        m_strGlobalFile = GetGlobalFileName(GetAppName());
+    if ( !m_fnGlobalFile.IsOk() && (style & wxCONFIG_USE_GLOBAL_FILE) )
+        m_fnGlobalFile = GetGlobalFile(GetAppName());
 
     // Check if styles are not supplied, but filenames are, in which case
     // add the correct styles.
 
     // Check if styles are not supplied, but filenames are, in which case
     // add the correct styles.
-    if ( !m_strLocalFile.empty() )
+    if ( m_fnLocalFile.IsOk() )
         SetStyle(GetStyle() | wxCONFIG_USE_LOCAL_FILE);
 
         SetStyle(GetStyle() | wxCONFIG_USE_LOCAL_FILE);
 
-    if ( !m_strGlobalFile.empty() )
+    if ( m_fnGlobalFile.IsOk() )
         SetStyle(GetStyle() | wxCONFIG_USE_GLOBAL_FILE);
 
     // if the path is not absolute, prepend the standard directory to it
         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
+    // unless explicitly asked not to
     if ( !(style & wxCONFIG_USE_RELATIVE_PATH) )
     {
     if ( !(style & wxCONFIG_USE_RELATIVE_PATH) )
     {
-        if ( !m_strLocalFile.empty() && !wxIsAbsolutePath(m_strLocalFile) )
-        {
-            const wxString strLocalOrig = m_strLocalFile;
-            m_strLocalFile = GetLocalDir();
-            m_strLocalFile << strLocalOrig;
-        }
+        if ( m_fnLocalFile.IsOk() )
+            m_fnLocalFile.MakeAbsolute(GetLocalDir(style));
 
 
-        if ( !m_strGlobalFile.empty() && !wxIsAbsolutePath(m_strGlobalFile) )
-        {
-            const wxString strGlobalOrig = m_strGlobalFile;
-            m_strGlobalFile = GetGlobalDir();
-            m_strGlobalFile << strGlobalOrig;
-        }
+        if ( m_fnGlobalFile.IsOk() )
+            m_fnGlobalFile.MakeAbsolute(GetGlobalDir());
     }
 
     SetUmask(-1);
     }
 
     SetUmask(-1);
@@ -476,7 +423,7 @@ wxFileConfig::wxFileConfig(const wxString& appName, const wxString& vendorName,
 #if wxUSE_STREAMS
 
 wxFileConfig::wxFileConfig(wxInputStream &inStream, const wxMBConv& conv)
 #if wxUSE_STREAMS
 
 wxFileConfig::wxFileConfig(wxInputStream &inStream, const wxMBConv& conv)
-            : m_conv(conv)
+            : m_conv(conv.Clone())
 {
     // always local_file when this constructor is called (?)
     SetStyle(GetStyle() | wxCONFIG_USE_LOCAL_FILE);
 {
     // always local_file when this constructor is called (?)
     SetStyle(GetStyle() | wxCONFIG_USE_LOCAL_FILE);
@@ -487,16 +434,16 @@ wxFileConfig::wxFileConfig(wxInputStream &inStream, const wxMBConv& conv)
     m_linesHead =
     m_linesTail = NULL;
 
     m_linesHead =
     m_linesTail = NULL;
 
-    // translate everything to the current (platform-dependent) line
-    // termination character
-    wxString strTrans;
+    // read the entire stream contents in memory
+    wxString str;
     {
     {
-        wxString strTmp;
+        static const size_t chunkLen = 1024;
 
 
-        char buf[1024];
+        wxMemoryBuffer buf(chunkLen);
         do
         {
         do
         {
-            inStream.Read(buf, WXSIZEOF(buf)-1);  // leave room for the NULL
+            inStream.Read(buf.GetAppendBuf(chunkLen), chunkLen);
+            buf.UngetAppendBuf(inStream.LastRead());
 
             const wxStreamError err = inStream.GetLastError();
 
 
             const wxStreamError err = inStream.GetLastError();
 
@@ -505,19 +452,27 @@ wxFileConfig::wxFileConfig(wxInputStream &inStream, const wxMBConv& conv)
                 wxLogError(_("Error reading config options."));
                 break;
             }
                 wxLogError(_("Error reading config options."));
                 break;
             }
-
-            // FIXME: this is broken because if we have part of multibyte
-            //        character in the buffer (and another part hasn't been
-            //        read yet) we're going to lose data because of conversion
-            //        errors
-            buf[inStream.LastRead()] = '\0';
-            strTmp += conv.cMB2WX(buf);
         }
         while ( !inStream.Eof() );
 
         }
         while ( !inStream.Eof() );
 
-        strTrans = wxTextBuffer::Translate(strTmp);
+#if wxUSE_UNICODE
+        size_t len;
+        str = conv.cMB2WC((char *)buf.GetData(), buf.GetDataLen(), &len);
+        if ( !len && buf.GetDataLen() )
+        {
+            wxLogError(_("Failed to read config options."));
+        }
+#else // !wxUSE_UNICODE
+        // no need for conversion
+        str.assign((char *)buf.GetData(), buf.GetDataLen());
+#endif // wxUSE_UNICODE/!wxUSE_UNICODE
     }
 
     }
 
+
+    // translate everything to the current (platform-dependent) line
+    // termination character
+    str = wxTextBuffer::Translate(str);
+
     wxMemoryText memText;
 
     // Now we can add the text to the memory text. To do this we extract line
     wxMemoryText memText;
 
     // Now we can add the text to the memory text. To do this we extract line
@@ -529,21 +484,21 @@ wxFileConfig::wxFileConfig(wxInputStream &inStream, const wxMBConv& conv)
     const wxChar *pEOL = wxTextBuffer::GetEOL(wxTextBuffer::typeDefault);
     const size_t EOLLen = wxStrlen(pEOL);
 
     const wxChar *pEOL = wxTextBuffer::GetEOL(wxTextBuffer::typeDefault);
     const size_t EOLLen = wxStrlen(pEOL);
 
-    int posLineStart = strTrans.Find(pEOL);
+    int posLineStart = str.Find(pEOL);
     while ( posLineStart != -1 )
     {
     while ( posLineStart != -1 )
     {
-        wxString line(strTrans.Left(posLineStart));
+        wxString line(str.Left(posLineStart));
 
         memText.AddLine(line);
 
 
         memText.AddLine(line);
 
-        strTrans = strTrans.Mid(posLineStart + EOLLen);
+        str = str.Mid(posLineStart + EOLLen);
 
 
-        posLineStart = strTrans.Find(pEOL);
+        posLineStart = str.Find(pEOL);
     }
 
     // also add whatever we have left in the translated string.
     }
 
     // also add whatever we have left in the translated string.
-    if ( !strTrans.empty() )
-        memText.AddLine(strTrans);
+    if ( !str.empty() )
+        memText.AddLine(str);
 
     // Finally we can parse it all.
     Parse(memText, true /* local */);
 
     // Finally we can parse it all.
     Parse(memText, true /* local */);
@@ -571,6 +526,8 @@ wxFileConfig::~wxFileConfig()
     Flush();
 
     CleanUp();
     Flush();
 
     CleanUp();
+
+    delete m_conv;
 }
 
 // ----------------------------------------------------------------------------
 }
 
 // ----------------------------------------------------------------------------
@@ -771,7 +728,7 @@ wxFileConfig::DoSetPath(const wxString& strPath, bool createMissingComponents)
     // change current group
     size_t n;
     m_pCurrentGroup = m_pRootGroup;
     // change current group
     size_t n;
     m_pCurrentGroup = m_pRootGroup;
-    for ( n = 0; n < aParts.Count(); n++ ) {
+    for ( n = 0; n < aParts.GetCount(); n++ ) {
         wxFileConfigGroup *pNextGroup = m_pCurrentGroup->FindSubgroup(aParts[n]);
         if ( pNextGroup == NULL )
         {
         wxFileConfigGroup *pNextGroup = m_pCurrentGroup->FindSubgroup(aParts[n]);
         if ( pNextGroup == NULL )
         {
@@ -786,7 +743,7 @@ wxFileConfig::DoSetPath(const wxString& strPath, bool createMissingComponents)
 
     // recombine path parts in one variable
     m_strPath.Empty();
 
     // recombine path parts in one variable
     m_strPath.Empty();
-    for ( n = 0; n < aParts.Count(); n++ ) {
+    for ( n = 0; n < aParts.GetCount(); n++ ) {
         m_strPath << wxCONFIG_PATH_SEPARATOR << aParts[n];
     }
 
         m_strPath << wxCONFIG_PATH_SEPARATOR << aParts[n];
     }
 
@@ -810,7 +767,7 @@ bool wxFileConfig::GetFirstGroup(wxString& str, long& lIndex) const
 
 bool wxFileConfig::GetNextGroup (wxString& str, long& lIndex) const
 {
 
 bool wxFileConfig::GetNextGroup (wxString& str, long& lIndex) const
 {
-    if ( size_t(lIndex) < m_pCurrentGroup->Groups().Count() ) {
+    if ( size_t(lIndex) < m_pCurrentGroup->Groups().GetCount() ) {
         str = m_pCurrentGroup->Groups()[(size_t)lIndex++]->Name();
         return true;
     }
         str = m_pCurrentGroup->Groups()[(size_t)lIndex++]->Name();
         return true;
     }
@@ -826,7 +783,7 @@ bool wxFileConfig::GetFirstEntry(wxString& str, long& lIndex) const
 
 bool wxFileConfig::GetNextEntry (wxString& str, long& lIndex) const
 {
 
 bool wxFileConfig::GetNextEntry (wxString& str, long& lIndex) const
 {
-    if ( size_t(lIndex) < m_pCurrentGroup->Entries().Count() ) {
+    if ( size_t(lIndex) < m_pCurrentGroup->Entries().GetCount() ) {
         str = m_pCurrentGroup->Entries()[(size_t)lIndex++]->Name();
         return true;
     }
         str = m_pCurrentGroup->Entries()[(size_t)lIndex++]->Name();
         return true;
     }
@@ -836,10 +793,10 @@ bool wxFileConfig::GetNextEntry (wxString& str, long& lIndex) const
 
 size_t wxFileConfig::GetNumberOfEntries(bool bRecursive) const
 {
 
 size_t wxFileConfig::GetNumberOfEntries(bool bRecursive) const
 {
-    size_t n = m_pCurrentGroup->Entries().Count();
+    size_t n = m_pCurrentGroup->Entries().GetCount();
     if ( bRecursive ) {
         wxFileConfigGroup *pOldCurrentGroup = m_pCurrentGroup;
     if ( bRecursive ) {
         wxFileConfigGroup *pOldCurrentGroup = m_pCurrentGroup;
-        size_t nSubgroups = m_pCurrentGroup->Groups().Count();
+        size_t nSubgroups = m_pCurrentGroup->Groups().GetCount();
         for ( size_t nGroup = 0; nGroup < nSubgroups; nGroup++ ) {
             CONST_CAST m_pCurrentGroup = m_pCurrentGroup->Groups()[nGroup];
             n += GetNumberOfEntries(true);
         for ( size_t nGroup = 0; nGroup < nSubgroups; nGroup++ ) {
             CONST_CAST m_pCurrentGroup = m_pCurrentGroup->Groups()[nGroup];
             n += GetNumberOfEntries(true);
@@ -852,10 +809,10 @@ size_t wxFileConfig::GetNumberOfEntries(bool bRecursive) const
 
 size_t wxFileConfig::GetNumberOfGroups(bool bRecursive) const
 {
 
 size_t wxFileConfig::GetNumberOfGroups(bool bRecursive) const
 {
-    size_t n = m_pCurrentGroup->Groups().Count();
+    size_t n = m_pCurrentGroup->Groups().GetCount();
     if ( bRecursive ) {
         wxFileConfigGroup *pOldCurrentGroup = m_pCurrentGroup;
     if ( bRecursive ) {
         wxFileConfigGroup *pOldCurrentGroup = m_pCurrentGroup;
-        size_t nSubgroups = m_pCurrentGroup->Groups().Count();
+        size_t nSubgroups = m_pCurrentGroup->Groups().GetCount();
         for ( size_t nGroup = 0; nGroup < nSubgroups; nGroup++ ) {
             CONST_CAST m_pCurrentGroup = m_pCurrentGroup->Groups()[nGroup];
             n += GetNumberOfGroups(true);
         for ( size_t nGroup = 0; nGroup < nSubgroups; nGroup++ ) {
             CONST_CAST m_pCurrentGroup = m_pCurrentGroup->Groups()[nGroup];
             n += GetNumberOfGroups(true);
@@ -888,12 +845,44 @@ bool wxFileConfig::HasGroup(const wxString& strName) const
     return rc;
 }
 
     return rc;
 }
 
-bool wxFileConfig::HasEntry(const wxString& strName) const
+bool wxFileConfig::HasEntry(const wxString& entry) const
 {
 {
-    wxConfigPathChanger path(this, strName);
+    // path is the part before the last "/"
+    wxString path = entry.BeforeLast(wxCONFIG_PATH_SEPARATOR);
 
 
-    wxFileConfigEntry *pEntry = m_pCurrentGroup->FindEntry(path.Name());
-    return pEntry != NULL;
+    // except in the special case of "/keyname" when there is nothing before "/"
+    if ( path.empty() && *entry.c_str() == wxCONFIG_PATH_SEPARATOR )
+    {
+        path = wxCONFIG_PATH_SEPARATOR;
+    }
+
+    // change to the path of the entry if necessary and remember the old path
+    // to restore it later
+    wxString pathOld;
+    wxFileConfig * const self = wx_const_cast(wxFileConfig *, this);
+    if ( !path.empty() )
+    {
+        pathOld = GetPath();
+        if ( pathOld.empty() )
+            pathOld = wxCONFIG_PATH_SEPARATOR;
+
+        if ( !self->DoSetPath(path, false /* don't create if doesn't exist */) )
+        {
+            return false;
+        }
+    }
+
+    // check if the entry exists in this group
+    const bool exists = m_pCurrentGroup->FindEntry(
+                            entry.AfterLast(wxCONFIG_PATH_SEPARATOR)) != NULL;
+
+    // restore the old path if we changed it above
+    if ( !pathOld.empty() )
+    {
+        self->SetPath(pathOld);
+    }
+
+    return exists;
 }
 
 // ----------------------------------------------------------------------------
 }
 
 // ----------------------------------------------------------------------------
@@ -993,13 +982,13 @@ bool wxFileConfig::DoWriteLong(const wxString& key, long lValue)
 
 bool wxFileConfig::Flush(bool /* bCurrentOnly */)
 {
 
 bool wxFileConfig::Flush(bool /* bCurrentOnly */)
 {
-  if ( !IsDirty() || !m_strLocalFile )
+  if ( !IsDirty() || !m_fnLocalFile.GetFullPath() )
     return true;
 
   // set the umask if needed
   wxCHANGE_UMASK(m_umask);
 
     return true;
 
   // set the umask if needed
   wxCHANGE_UMASK(m_umask);
 
-  wxTempFile file(m_strLocalFile);
+  wxTempFile file(m_fnLocalFile.GetFullPath());
 
   if ( !file.IsOpened() )
   {
 
   if ( !file.IsOpened() )
   {
@@ -1008,15 +997,17 @@ bool wxFileConfig::Flush(bool /* bCurrentOnly */)
   }
 
   // write all strings to file
   }
 
   // write all strings to file
+  wxString filetext;
+  filetext.reserve(4096);
   for ( wxFileConfigLineList *p = m_linesHead; p != NULL; p = p->Next() )
   {
   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;
-    }
+    filetext << p->Text() << wxTextFile::GetEOL();
+  }
+
+  if ( !file.Write(filetext, *m_conv) )
+  {
+    wxLogError(_("can't write user configuration file."));
+    return false;
   }
 
   if ( !file.Commit() )
   }
 
   if ( !file.Commit() )
@@ -1029,7 +1020,7 @@ bool wxFileConfig::Flush(bool /* bCurrentOnly */)
   ResetDirty();
 
 #if defined(__WXMAC__)
   ResetDirty();
 
 #if defined(__WXMAC__)
-  wxFileName(m_strLocalFile).MacSetTypeAndCreator('TEXT', 'ttxt');
+  m_fnLocalFile.MacSetTypeAndCreator('TEXT', 'ttxt');
 #endif // __WXMAC__
 
   return true;
 #endif // __WXMAC__
 
   return true;
@@ -1139,11 +1130,13 @@ bool wxFileConfig::DeleteEntry(const wxString& key, bool bGroupIfEmptyAlso)
 
 bool wxFileConfig::DeleteGroup(const wxString& key)
 {
 
 bool wxFileConfig::DeleteGroup(const wxString& key)
 {
-  wxConfigPathChanger path(this, key);
+  wxConfigPathChanger path(this, RemoveTrailingSeparator(key));
 
   if ( !m_pCurrentGroup->DeleteSubgroupByName(path.Name()) )
       return false;
 
 
   if ( !m_pCurrentGroup->DeleteSubgroupByName(path.Name()) )
       return false;
 
+  path.UpdateIfDeleted();
+
   SetDirty();
 
   return true;
   SetDirty();
 
   return true;
@@ -1153,12 +1146,12 @@ bool wxFileConfig::DeleteAll()
 {
   CleanUp();
 
 {
   CleanUp();
 
-  if ( !m_strLocalFile.empty() )
+  if ( m_fnLocalFile.IsOk() )
   {
   {
-      if ( wxFile::Exists(m_strLocalFile) && wxRemove(m_strLocalFile) == -1 )
+      if ( m_fnLocalFile.FileExists() && wxRemove(m_fnLocalFile.GetFullPath()) == -1 )
       {
           wxLogSysError(_("can't delete user configuration file '%s'"),
       {
           wxLogSysError(_("can't delete user configuration file '%s'"),
-                        m_strLocalFile.c_str());
+                        m_fnLocalFile.GetFullPath().c_str());
           return false;
       }
   }
           return false;
       }
   }
@@ -1181,10 +1174,12 @@ wxFileConfigLineList *wxFileConfig::LineListAppend(const wxString& str)
                 str.c_str() );
     wxLogTrace( FILECONF_TRACE_MASK,
                 _T("        head: %s"),
                 str.c_str() );
     wxLogTrace( FILECONF_TRACE_MASK,
                 _T("        head: %s"),
-                ((m_linesHead) ? m_linesHead->Text().c_str() : wxEmptyString) );
+                ((m_linesHead) ? (const wxChar*)m_linesHead->Text().c_str()
+                               : wxEmptyString) );
     wxLogTrace( FILECONF_TRACE_MASK,
                 _T("        tail: %s"),
     wxLogTrace( FILECONF_TRACE_MASK,
                 _T("        tail: %s"),
-                ((m_linesTail) ? m_linesTail->Text().c_str() : wxEmptyString) );
+                ((m_linesTail) ? (const wxChar*)m_linesTail->Text().c_str()
+                               : wxEmptyString) );
 
     wxFileConfigLineList *pLine = new wxFileConfigLineList(str);
 
 
     wxFileConfigLineList *pLine = new wxFileConfigLineList(str);
 
@@ -1204,10 +1199,12 @@ wxFileConfigLineList *wxFileConfig::LineListAppend(const wxString& str)
 
     wxLogTrace( FILECONF_TRACE_MASK,
                 _T("        head: %s"),
 
     wxLogTrace( FILECONF_TRACE_MASK,
                 _T("        head: %s"),
-                ((m_linesHead) ? m_linesHead->Text().c_str() : wxEmptyString) );
+                ((m_linesHead) ? (const wxChar*)m_linesHead->Text().c_str()
+                               : wxEmptyString) );
     wxLogTrace( FILECONF_TRACE_MASK,
                 _T("        tail: %s"),
     wxLogTrace( FILECONF_TRACE_MASK,
                 _T("        tail: %s"),
-                ((m_linesTail) ? m_linesTail->Text().c_str() : wxEmptyString) );
+                ((m_linesTail) ? (const wxChar*)m_linesTail->Text().c_str()
+                               : wxEmptyString) );
 
     return m_linesTail;
 }
 
     return m_linesTail;
 }
@@ -1219,13 +1216,16 @@ wxFileConfigLineList *wxFileConfig::LineListInsert(const wxString& str,
     wxLogTrace( FILECONF_TRACE_MASK,
                 _T("    ** Inserting Line '%s' after '%s'"),
                 str.c_str(),
     wxLogTrace( FILECONF_TRACE_MASK,
                 _T("    ** Inserting Line '%s' after '%s'"),
                 str.c_str(),
-                ((pLine) ? pLine->Text().c_str() : wxEmptyString) );
+                ((pLine) ? (const wxChar*)pLine->Text().c_str()
+                         : wxEmptyString) );
     wxLogTrace( FILECONF_TRACE_MASK,
                 _T("        head: %s"),
     wxLogTrace( FILECONF_TRACE_MASK,
                 _T("        head: %s"),
-                ((m_linesHead) ? m_linesHead->Text().c_str() : wxEmptyString) );
+                ((m_linesHead) ? (const wxChar*)m_linesHead->Text().c_str()
+                               : wxEmptyString) );
     wxLogTrace( FILECONF_TRACE_MASK,
                 _T("        tail: %s"),
     wxLogTrace( FILECONF_TRACE_MASK,
                 _T("        tail: %s"),
-                ((m_linesTail) ? m_linesTail->Text().c_str() : wxEmptyString) );
+                ((m_linesTail) ? (const wxChar*)m_linesTail->Text().c_str()
+                               : wxEmptyString) );
 
     if ( pLine == m_linesTail )
         return LineListAppend(str);
 
     if ( pLine == m_linesTail )
         return LineListAppend(str);
@@ -1250,10 +1250,12 @@ wxFileConfigLineList *wxFileConfig::LineListInsert(const wxString& str,
 
     wxLogTrace( FILECONF_TRACE_MASK,
                 _T("        head: %s"),
 
     wxLogTrace( FILECONF_TRACE_MASK,
                 _T("        head: %s"),
-                ((m_linesHead) ? m_linesHead->Text().c_str() : wxEmptyString) );
+                ((m_linesHead) ? (const wxChar*)m_linesHead->Text().c_str()
+                               : wxEmptyString) );
     wxLogTrace( FILECONF_TRACE_MASK,
                 _T("        tail: %s"),
     wxLogTrace( FILECONF_TRACE_MASK,
                 _T("        tail: %s"),
-                ((m_linesTail) ? m_linesTail->Text().c_str() : wxEmptyString) );
+                ((m_linesTail) ? (const wxChar*)m_linesTail->Text().c_str()
+                               : wxEmptyString) );
 
     return pNewLine;
 }
 
     return pNewLine;
 }
@@ -1265,10 +1267,12 @@ void wxFileConfig::LineListRemove(wxFileConfigLineList *pLine)
                 pLine->Text().c_str() );
     wxLogTrace( FILECONF_TRACE_MASK,
                 _T("        head: %s"),
                 pLine->Text().c_str() );
     wxLogTrace( FILECONF_TRACE_MASK,
                 _T("        head: %s"),
-                ((m_linesHead) ? m_linesHead->Text().c_str() : wxEmptyString) );
+                ((m_linesHead) ? (const wxChar*)m_linesHead->Text().c_str()
+                               : wxEmptyString) );
     wxLogTrace( FILECONF_TRACE_MASK,
                 _T("        tail: %s"),
     wxLogTrace( FILECONF_TRACE_MASK,
                 _T("        tail: %s"),
-                ((m_linesTail) ? m_linesTail->Text().c_str() : wxEmptyString) );
+                ((m_linesTail) ? (const wxChar*)m_linesTail->Text().c_str()
+                               : wxEmptyString) );
 
     wxFileConfigLineList    *pPrev = pLine->Prev(),
                             *pNext = pLine->Next();
 
     wxFileConfigLineList    *pPrev = pLine->Prev(),
                             *pNext = pLine->Next();
@@ -1292,10 +1296,12 @@ void wxFileConfig::LineListRemove(wxFileConfigLineList *pLine)
 
     wxLogTrace( FILECONF_TRACE_MASK,
                 _T("        head: %s"),
 
     wxLogTrace( FILECONF_TRACE_MASK,
                 _T("        head: %s"),
-                ((m_linesHead) ? m_linesHead->Text().c_str() : wxEmptyString) );
+                ((m_linesHead) ? (const wxChar*)m_linesHead->Text().c_str()
+                               : wxEmptyString) );
     wxLogTrace( FILECONF_TRACE_MASK,
                 _T("        tail: %s"),
     wxLogTrace( FILECONF_TRACE_MASK,
                 _T("        tail: %s"),
-                ((m_linesTail) ? m_linesTail->Text().c_str() : wxEmptyString) );
+                ((m_linesTail) ? (const wxChar*)m_linesTail->Text().c_str()
+                               : wxEmptyString) );
 
     delete pLine;
 }
 
     delete pLine;
 }
@@ -1333,12 +1339,12 @@ wxFileConfigGroup::wxFileConfigGroup(wxFileConfigGroup *pParent,
 wxFileConfigGroup::~wxFileConfigGroup()
 {
   // entries
 wxFileConfigGroup::~wxFileConfigGroup()
 {
   // entries
-  size_t n, nCount = m_aEntries.Count();
+  size_t n, nCount = m_aEntries.GetCount();
   for ( n = 0; n < nCount; n++ )
     delete m_aEntries[n];
 
   // subgroups
   for ( n = 0; n < nCount; n++ )
     delete m_aEntries[n];
 
   // subgroups
-  nCount = m_aSubgroups.Count();
+  nCount = m_aSubgroups.GetCount();
   for ( n = 0; n < nCount; n++ )
     delete m_aSubgroups[n];
 }
   for ( n = 0; n < nCount; n++ )
     delete m_aSubgroups[n];
 }
@@ -1501,7 +1507,7 @@ void wxFileConfigGroup::UpdateGroupAndSubgroupsLines()
 
 
     // also update all subgroups as they have this groups name in their lines
 
 
     // also update all subgroups as they have this groups name in their lines
-    const size_t nCount = m_aSubgroups.Count();
+    const size_t nCount = m_aSubgroups.GetCount();
     for ( size_t n = 0; n < nCount; n++ )
     {
         m_aSubgroups[n]->UpdateGroupAndSubgroupsLines();
     for ( size_t n = 0; n < nCount; n++ )
     {
         m_aSubgroups[n]->UpdateGroupAndSubgroupsLines();
@@ -1512,8 +1518,17 @@ void wxFileConfigGroup::Rename(const wxString& newName)
 {
     wxCHECK_RET( m_pParent, _T("the root group can't be renamed") );
 
 {
     wxCHECK_RET( m_pParent, _T("the root group can't be renamed") );
 
+    if ( newName == m_strName )
+        return;
+
+    // we need to remove the group from the parent and it back under the new
+    // name to keep the parents array of subgroups alphabetically sorted
+    m_pParent->m_aSubgroups.Remove(this);
+
     m_strName = newName;
 
     m_strName = newName;
 
+    m_pParent->m_aSubgroups.Add(this);
+
     // update the group lines recursively
     UpdateGroupAndSubgroupsLines();
 }
     // update the group lines recursively
     UpdateGroupAndSubgroupsLines();
 }
@@ -1537,7 +1552,7 @@ wxFileConfigGroup::FindEntry(const wxChar *szName) const
 {
   size_t i,
        lo = 0,
 {
   size_t i,
        lo = 0,
-       hi = m_aEntries.Count();
+       hi = m_aEntries.GetCount();
   int res;
   wxFileConfigEntry *pEntry;
 
   int res;
   wxFileConfigEntry *pEntry;
 
@@ -1567,7 +1582,7 @@ wxFileConfigGroup::FindSubgroup(const wxChar *szName) const
 {
   size_t i,
        lo = 0,
 {
   size_t i,
        lo = 0,
-       hi = m_aSubgroups.Count();
+       hi = m_aSubgroups.GetCount();
   int res;
   wxFileConfigGroup *pGroup;
 
   int res;
   wxFileConfigGroup *pGroup;
 
@@ -1649,15 +1664,16 @@ bool wxFileConfigGroup::DeleteSubgroup(wxFileConfigGroup *pGroup)
 
     wxLogTrace( FILECONF_TRACE_MASK,
                 _T("  (m_pLine) = prev: %p, this %p, next %p"),
 
     wxLogTrace( FILECONF_TRACE_MASK,
                 _T("  (m_pLine) = prev: %p, this %p, next %p"),
-                ((m_pLine) ? m_pLine->Prev() : 0),
-                m_pLine,
-                ((m_pLine) ? m_pLine->Next() : 0) );
+                m_pLine ? wx_static_cast(void*, m_pLine->Prev()) : 0,
+                wx_static_cast(void*, m_pLine),
+                m_pLine ? wx_static_cast(void*, m_pLine->Next()) : 0 );
     wxLogTrace( FILECONF_TRACE_MASK,
                 _T("  text: '%s'"),
     wxLogTrace( FILECONF_TRACE_MASK,
                 _T("  text: '%s'"),
-                ((m_pLine) ? m_pLine->Text().c_str() : wxEmptyString) );
+                m_pLine ? (const wxChar*)m_pLine->Text().c_str()
+                        : wxEmptyString );
 
     // delete all entries...
 
     // delete all entries...
-    size_t nCount = pGroup->m_aEntries.Count();
+    size_t nCount = pGroup->m_aEntries.GetCount();
 
     wxLogTrace(FILECONF_TRACE_MASK,
                _T("Removing %lu entries"), (unsigned long)nCount );
 
     wxLogTrace(FILECONF_TRACE_MASK,
                _T("Removing %lu entries"), (unsigned long)nCount );
@@ -1676,7 +1692,7 @@ bool wxFileConfigGroup::DeleteSubgroup(wxFileConfigGroup *pGroup)
     }
 
     // ...and subgroups of this subgroup
     }
 
     // ...and subgroups of this subgroup
-    nCount = pGroup->m_aSubgroups.Count();
+    nCount = pGroup->m_aSubgroups.GetCount();
 
     wxLogTrace( FILECONF_TRACE_MASK,
                 _T("Removing %lu subgroups"), (unsigned long)nCount );
 
     wxLogTrace( FILECONF_TRACE_MASK,
                 _T("Removing %lu subgroups"), (unsigned long)nCount );
@@ -1697,7 +1713,8 @@ bool wxFileConfigGroup::DeleteSubgroup(wxFileConfigGroup *pGroup)
         wxLogTrace( FILECONF_TRACE_MASK,
                     _T("  Removing from group '%s' : '%s'"),
                     Name().c_str(),
         wxLogTrace( FILECONF_TRACE_MASK,
                     _T("  Removing from group '%s' : '%s'"),
                     Name().c_str(),
-                    ((m_pLine) ? m_pLine->Text().c_str() : wxEmptyString) );
+                    ((m_pLine) ? (const wxChar*)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
 
         // notice that we may do this test inside the previous "if"
         // because the last entry's line is surely !NULL
@@ -1709,11 +1726,11 @@ bool wxFileConfigGroup::DeleteSubgroup(wxFileConfigGroup *pGroup)
             // our last entry is being deleted, so find the last one which
             // stays by going back until we find a subgroup or reach the
             // group line
             // our last entry is being deleted, so find the last one which
             // stays by going back until we find a subgroup or reach the
             // group line
-            const size_t nSubgroups = m_aSubgroups.Count();
+            const size_t nSubgroups = m_aSubgroups.GetCount();
 
             m_pLastGroup = NULL;
             for ( wxFileConfigLineList *pl = pLine->Prev();
 
             m_pLastGroup = NULL;
             for ( wxFileConfigLineList *pl = pLine->Prev();
-                  pl && pl != m_pLine && !m_pLastGroup;
+                  pl && !m_pLastGroup;
                   pl = pl->Prev() )
             {
                 // does this line belong to our subgroup?
                   pl = pl->Prev() )
             {
                 // does this line belong to our subgroup?
@@ -1727,6 +1744,9 @@ bool wxFileConfigGroup::DeleteSubgroup(wxFileConfigGroup *pGroup)
                         break;
                     }
                 }
                         break;
                     }
                 }
+
+                if ( pl == m_pLine )
+                    break;
             }
         }
 
             }
         }
 
@@ -1764,7 +1784,7 @@ bool wxFileConfigGroup::DeleteEntry(const wxChar *szName)
 
       // go back until we find another entry or reach the group's line
       wxFileConfigEntry *pNewLast = NULL;
 
       // go back until we find another entry or reach the group's line
       wxFileConfigEntry *pNewLast = NULL;
-      size_t n, nEntries = m_aEntries.Count();
+      size_t n, nEntries = m_aEntries.GetCount();
       wxFileConfigLineList *pl;
       for ( pl = pLine->Prev(); pl != m_pLine; pl = pl->Prev() ) {
         // is it our subgroup?
       wxFileConfigLineList *pl;
       for ( pl = pLine->Prev(); pl != m_pLine; pl = pl->Prev() ) {
         // is it our subgroup?
@@ -1899,20 +1919,20 @@ void wxFileConfigEntry::SetValue(const wxString& strValue, bool bUser)
 
 int CompareEntries(wxFileConfigEntry *p1, wxFileConfigEntry *p2)
 {
 
 int CompareEntries(wxFileConfigEntry *p1, wxFileConfigEntry *p2)
 {
-  #if wxCONFIG_CASE_SENSITIVE
+#if wxCONFIG_CASE_SENSITIVE
     return wxStrcmp(p1->Name(), p2->Name());
     return wxStrcmp(p1->Name(), p2->Name());
-  #else
+#else
     return wxStricmp(p1->Name(), p2->Name());
     return wxStricmp(p1->Name(), p2->Name());
-  #endif
+#endif
 }
 
 int CompareGroups(wxFileConfigGroup *p1, wxFileConfigGroup *p2)
 {
 }
 
 int CompareGroups(wxFileConfigGroup *p1, wxFileConfigGroup *p2)
 {
-  #if wxCONFIG_CASE_SENSITIVE
+#if wxCONFIG_CASE_SENSITIVE
     return wxStrcmp(p1->Name(), p2->Name());
     return wxStrcmp(p1->Name(), p2->Name());
-  #else
+#else
     return wxStricmp(p1->Name(), p2->Name());
     return wxStricmp(p1->Name(), p2->Name());
-  #endif
+#endif
 }
 
 // ----------------------------------------------------------------------------
 }
 
 // ----------------------------------------------------------------------------
@@ -1929,7 +1949,7 @@ static wxString FilterInValue(const wxString& str)
 
   for ( size_t n = bQuoted ? 1 : 0; n < str.Len(); n++ ) {
     if ( str[n] == wxT('\\') ) {
 
   for ( size_t n = bQuoted ? 1 : 0; n < str.Len(); n++ ) {
     if ( str[n] == wxT('\\') ) {
-      switch ( str[++n] ) {
+      switch ( str[++n].GetValue() ) {
         case wxT('n'):
           strResult += wxT('\n');
           break;
         case wxT('n'):
           strResult += wxT('\n');
           break;
@@ -1982,7 +2002,7 @@ static wxString FilterOutValue(const wxString& str)
 
   wxChar c;
   for ( size_t n = 0; n < str.Len(); n++ ) {
 
   wxChar c;
   for ( size_t n = 0; n < str.Len(); n++ ) {
-    switch ( str[n] ) {
+    switch ( str[n].GetValue() ) {
       case wxT('\n'):
         c = wxT('n');
         break;
       case wxT('\n'):
         c = wxT('n');
         break;