]> git.saurik.com Git - wxWidgets.git/blobdiff - src/common/fileconf.cpp
fixed incorrect GetTextExtent for wxTELETYPE font
[wxWidgets.git] / src / common / fileconf.cpp
index c887bc6b8664edfae8eb68918f75c3deab764e95..0d5b0a4ae3132ede1a8a2547516dff0f1b1db0f6 100644 (file)
 #pragma implementation "fileconf.h"
 #endif
 
 #pragma implementation "fileconf.h"
 #endif
 
-// ============================================================================
-// declarations
-// ============================================================================
-
 // ----------------------------------------------------------------------------
 // headers
 // ----------------------------------------------------------------------------
 // ----------------------------------------------------------------------------
 // headers
 // ----------------------------------------------------------------------------
+
 #include  "wx/wxprec.h"
 
 #ifdef    __BORLANDC__
   #pragma hdrstop
 #endif  //__BORLANDC__
 
 #include  "wx/wxprec.h"
 
 #ifdef    __BORLANDC__
   #pragma hdrstop
 #endif  //__BORLANDC__
 
+#if wxUSE_CONFIG
+
 #ifndef   WX_PRECOMP
   #include  "wx/string.h"
   #include  "wx/intl.h"
 #ifndef   WX_PRECOMP
   #include  "wx/string.h"
   #include  "wx/intl.h"
 #if       defined(__WXMSW__) && !defined(_WINDOWS_)
   #include  <windows.h>
 #endif  //windows.h
 #if       defined(__WXMSW__) && !defined(_WINDOWS_)
   #include  <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
 // ----------------------------------------------------------------------------
 // ----------------------------------------------------------------------------
 // macros
 // ----------------------------------------------------------------------------
 // global functions declarations
 // ----------------------------------------------------------------------------
 
 // global functions declarations
 // ----------------------------------------------------------------------------
 
-// is 'c' a valid character in group name?
-// NB: wxCONFIG_IMMUTABLE_PREFIX and wxCONFIG_PATH_SEPARATOR must be valid chars,
-//     but _not_ ']' (group name delimiter)
-inline bool IsValid(char c) { return isalnum(c) || strchr("@_/-!.*%", c); }
-
 // compare functions for sorting the arrays
 // compare functions for sorting the arrays
-static int CompareEntries(ConfigEntry *p1,
-                          ConfigEntry *p2);
-static int CompareGroups(ConfigGroup *p1,
-                         ConfigGroup *p2);
+static int LINKAGEMODE CompareEntries(ConfigEntry *p1, ConfigEntry *p2);
+static int LINKAGEMODE CompareGroups(ConfigGroup *p1, ConfigGroup *p2);
 
 // filter strings
 
 // filter strings
-static wxString FilterIn(const wxString& str);
-static wxString FilterOut(const wxString& str);
+static wxString FilterInValue(const wxString& str);
+static wxString FilterOutValue(const wxString& str);
+
+static wxString FilterInEntryName(const wxString& str);
+static wxString FilterOutEntryName(const wxString& str);
+
+// get the name to use in wxFileConfig ctor
+static wxString GetAppName(const wxString& appname);
 
 // ============================================================================
 // implementation
 
 // ============================================================================
 // implementation
@@ -93,16 +101,123 @@ wxString wxFileConfig::GetGlobalDir()
 {
   wxString strDir;
 
 {
   wxString strDir;
 
-  #ifdef __UNIX__
-    strDir = "/etc/";
+  #ifdef __VMS__ // Note if __VMS is defined __UNIX is also defined
+    strDir = wxT("sys$manager:");
+  #elif defined( __UNIX__ )
+    strDir = wxT("/etc/");
+  #elif defined(__WXPM__)
+    ULONG                           aulSysInfo[QSV_MAX] = {0};
+    UINT                            drive;
+    APIRET                          rc;
+
+    rc = DosQuerySysInfo( 1L, QSV_MAX, (PVOID)aulSysInfo, sizeof(ULONG)*QSV_MAX);
+    if (rc == 0)
+    {
+        drive = aulSysInfo[QSV_BOOT_DRIVE - 1];
+        switch(drive)
+        {
+           case 1:
+              strDir = "A:\\OS2\\";
+              break;
+           case 2:
+              strDir = "B:\\OS2\\";
+              break;
+           case 3:
+              strDir = "C:\\OS2\\";
+              break;
+           case 4:
+              strDir = "D:\\OS2\\";
+              break;
+           case 5:
+              strDir = "E:\\OS2\\";
+              break;
+           case 6:
+              strDir = "F:\\OS2\\";
+              break;
+           case 7:
+              strDir = "G:\\OS2\\";
+              break;
+           case 8:
+              strDir = "H:\\OS2\\";
+              break;
+           case 9:
+              strDir = "I:\\OS2\\";
+              break;
+           case 10:
+              strDir = "J:\\OS2\\";
+              break;
+           case 11:
+              strDir = "K:\\OS2\\";
+              break;
+           case 12:
+              strDir = "L:\\OS2\\";
+              break;
+           case 13:
+              strDir = "M:\\OS2\\";
+              break;
+           case 14:
+              strDir = "N:\\OS2\\";
+              break;
+           case 15:
+              strDir = "O:\\OS2\\";
+              break;
+           case 16:
+              strDir = "P:\\OS2\\";
+              break;
+           case 17:
+              strDir = "Q:\\OS2\\";
+              break;
+           case 18:
+              strDir = "R:\\OS2\\";
+              break;
+           case 19:
+              strDir = "S:\\OS2\\";
+              break;
+           case 20:
+              strDir = "T:\\OS2\\";
+              break;
+           case 21:
+              strDir = "U:\\OS2\\";
+              break;
+           case 22:
+              strDir = "V:\\OS2\\";
+              break;
+           case 23:
+              strDir = "W:\\OS2\\";
+              break;
+           case 24:
+              strDir = "X:\\OS2\\";
+              break;
+           case 25:
+              strDir = "Y:\\OS2\\";
+              break;
+           case 26:
+              strDir = "Z:\\OS2\\";
+              break;
+        }
+    }
   #elif defined(__WXSTUBS__)
   #elif defined(__WXSTUBS__)
-    wxASSERT_MSG( FALSE, "TODO" ) ;
+    wxASSERT_MSG( FALSE, wxT("TODO") ) ;
+  #elif defined(__WXMAC__)
+  {
+               short           vRefNum  ;
+               long            dirID ;
+               
+               if ( FindFolder( (short) kOnSystemDisk, kPreferencesFolderType, kDontCreateFolder, &vRefNum, &dirID) == noErr)
+               {
+                       FSSpec file ;
+                       if ( FSMakeFSSpec( vRefNum , dirID , "\p" , &file ) == noErr )
+                       {
+                               strDir = wxMacFSSpec2UnixFilename( &file ) + "/" ;
+                       }
+               }
+  }
   #else // Windows
   #else // Windows
-    char szWinDir[MAX_PATH];
+    wxChar szWinDir[MAX_PATH];
     ::GetWindowsDirectory(szWinDir, MAX_PATH);
 
     strDir = szWinDir;
     ::GetWindowsDirectory(szWinDir, MAX_PATH);
 
     strDir = szWinDir;
-    strDir << '\\';
+    strDir << wxT('\\');
   #endif // Unix/Windows
 
   return strDir;
   #endif // Unix/Windows
 
   return strDir;
@@ -112,47 +227,67 @@ wxString wxFileConfig::GetLocalDir()
 {
   wxString strDir;
 
 {
   wxString strDir;
 
+#ifndef __WXMAC__
   wxGetHomeDir(&strDir);
 
 #ifdef  __UNIX__
   wxGetHomeDir(&strDir);
 
 #ifdef  __UNIX__
-  if (strDir.Last() != '/') strDir << '/';
+#ifdef __VMS
+   if (strDir.Last() != wxT(']'))
+#endif
+   if (strDir.Last() != wxT('/')) strDir << wxT('/');
 #else
 #else
-  if (strDir.Last() != '\\') strDir << '\\';
+  if (strDir.Last() != wxT('\\')) strDir << wxT('\\');
+#endif
+#else
+       // no local dir concept on mac
+       return GetGlobalDir() ;
 #endif
 
   return strDir;
 }
 
 #endif
 
   return strDir;
 }
 
-wxString wxFileConfig::GetGlobalFileName(const char *szFile)
+wxString wxFileConfig::GetGlobalFileName(const wxChar *szFile)
 {
   wxString str = GetGlobalDir();
   str << szFile;
 
 {
   wxString str = GetGlobalDir();
   str << szFile;
 
-  if ( strchr(szFile, '.') == NULL )
+  if ( wxStrchr(szFile, wxT('.')) == NULL )
   #ifdef  __UNIX__
   #ifdef  __UNIX__
-    str << ".conf";
+    str << wxT(".conf");
+  #elif defined( __WXMAC__ )
+     str << " Preferences";
   #else   // Windows
   #else   // Windows
-    str << ".ini";
+    str << wxT(".ini");
   #endif  // UNIX/Win
 
   return str;
 }
 
   #endif  // UNIX/Win
 
   return str;
 }
 
-wxString wxFileConfig::GetLocalFileName(const char *szFile)
+wxString wxFileConfig::GetLocalFileName(const wxChar *szFile)
 {
 {
-  wxString str = GetLocalDir();
-
-  #ifdef  __UNIX__
-    str << '.';
+#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 )
+    str << wxT('.');
   #endif
 
   str << szFile;
 
   #ifdef __WXMSW__
   #endif
 
   str << szFile;
 
   #ifdef __WXMSW__
-    if ( strchr(szFile, '.') == NULL )
-      str << ".ini";
+    if ( wxStrchr(szFile, wxT('.')) == NULL )
+      str << wxT(".ini");
   #endif
 
   #endif
 
+
+  #ifdef __WXMAC__
+     str << " Preferences";
+  #endif
   return str;
 }
 
   return str;
 }
 
@@ -200,15 +335,11 @@ void wxFileConfig::Init()
 wxFileConfig::wxFileConfig(const wxString& appName, const wxString& vendorName,
                            const wxString& strLocal, const wxString& strGlobal,
                            long style)
 wxFileConfig::wxFileConfig(const wxString& appName, const wxString& vendorName,
                            const wxString& strLocal, const wxString& strGlobal,
                            long style)
-            : wxConfigBase(appName, vendorName, strLocal, strGlobal, style),
+            : wxConfigBase(::GetAppName(appName), vendorName,
+                           strLocal, strGlobal,
+                           style),
               m_strLocalFile(strLocal), m_strGlobalFile(strGlobal)
 {
               m_strLocalFile(strLocal), m_strGlobalFile(strGlobal)
 {
-  // Make up an application name if not supplied
-  if (appName.IsEmpty() && wxTheApp)
-  {
-    SetAppName(wxTheApp->GetAppName());
-  }
-
   // Make up names for files if empty
   if ( m_strLocalFile.IsEmpty() && (style & wxCONFIG_USE_LOCAL_FILE) )
   {
   // Make up names for files if empty
   if ( m_strLocalFile.IsEmpty() && (style & wxCONFIG_USE_LOCAL_FILE) )
   {
@@ -229,20 +360,26 @@ wxFileConfig::wxFileConfig(const wxString& appName, const wxString& vendorName,
     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
-  if ( !m_strLocalFile.IsEmpty() && !wxIsAbsolutePath(m_strLocalFile) )
+  // UNLESS wxCONFIG_USE_RELATIVE_PATH style is set
+  if ( !(style & wxCONFIG_USE_RELATIVE_PATH) )
   {
   {
-    wxString strLocal = m_strLocalFile;
-    m_strLocalFile = GetLocalDir();
-    m_strLocalFile << strLocal;
-  }
+      if ( !m_strLocalFile.IsEmpty() && !wxIsAbsolutePath(m_strLocalFile) )
+      {
+          wxString strLocal = m_strLocalFile;
+          m_strLocalFile = GetLocalDir();
+          m_strLocalFile << strLocal;
+      }
 
 
-  if ( !m_strGlobalFile.IsEmpty() && !wxIsAbsolutePath(m_strGlobalFile) )
-  {
-    wxString strGlobal = m_strGlobalFile;
-    m_strGlobalFile = GetGlobalDir();
-    m_strGlobalFile << strGlobal;
+      if ( !m_strGlobalFile.IsEmpty() && !wxIsAbsolutePath(m_strGlobalFile) )
+      {
+          wxString strGlobal = m_strGlobalFile;
+          m_strGlobalFile = GetGlobalDir();
+          m_strGlobalFile << strGlobal;
+      }
   }
 
   }
 
+  SetUmask(-1);
+
   Init();
 }
 
   Init();
 }
 
@@ -271,8 +408,8 @@ wxFileConfig::~wxFileConfig()
 
 void wxFileConfig::Parse(wxTextFile& file, bool bLocal)
 {
 
 void wxFileConfig::Parse(wxTextFile& file, bool bLocal)
 {
-  const char *pStart;
-  const char *pEnd;
+  const wxChar *pStart;
+  const wxChar *pEnd;
   wxString strLine;
 
   size_t nLineCount = file.GetLineCount();
   wxString strLine;
 
   size_t nLineCount = file.GetLineCount();
@@ -284,22 +421,29 @@ void wxFileConfig::Parse(wxTextFile& file, bool bLocal)
       LineListAppend(strLine);
 
     // skip leading spaces
       LineListAppend(strLine);
 
     // skip leading spaces
-    for ( pStart = strLine; isspace(*pStart); pStart++ )
+    for ( pStart = strLine; wxIsspace(*pStart); pStart++ )
       ;
 
     // skip blank/comment lines
       ;
 
     // skip blank/comment lines
-    if ( *pStart == '\0'|| *pStart == ';' || *pStart == '#' )
+    if ( *pStart == wxT('\0')|| *pStart == wxT(';') || *pStart == wxT('#') )
       continue;
 
       continue;
 
-    if ( *pStart == '[' ) {          // a new group
+    if ( *pStart == wxT('[') ) {          // a new group
       pEnd = pStart;
 
       pEnd = pStart;
 
-      while ( *++pEnd != ']' ) {
-        if ( !IsValid(*pEnd) && *pEnd != ' ' )  // allow spaces in group names
-          break;
+      while ( *++pEnd != wxT(']') ) {
+        if ( *pEnd == wxT('\\') ) {
+            // 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."),
                    file.GetName(), *pEnd, n + 1);
         continue; // skip this line
         wxLogError(_("file '%s': unexpected character %c at line %d."),
                    file.GetName(), *pEnd, n + 1);
         continue; // skip this line
@@ -308,7 +452,8 @@ void wxFileConfig::Parse(wxTextFile& file, bool bLocal)
       // group name here is always considered as abs path
       wxString strGroup;
       pStart++;
       // group name here is always considered as abs path
       wxString strGroup;
       pStart++;
-      strGroup << wxCONFIG_PATH_SEPARATOR << wxString(pStart, pEnd - pStart);
+      strGroup << wxCONFIG_PATH_SEPARATOR
+               << FilterInEntryName(wxString(pStart, pEnd - pStart));
 
       // will create it if doesn't yet exist
       SetPath(strGroup);
 
       // will create it if doesn't yet exist
       SetPath(strGroup);
@@ -318,38 +463,48 @@ 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."),
+            wxLogWarning(_("file '%s', line %d: '%s' ignored after group header."),
                          file.GetName(), n + 1, pEnd);
             bCont = FALSE;
         }
       }
     }
     else {                        // a key
                          file.GetName(), n + 1, pEnd);
             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."),
                    file.GetName(), n + 1);
       }
         wxLogError(_("file '%s', line %d: '=' expected."),
                    file.GetName(), n + 1);
       }
@@ -366,8 +521,7 @@ 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."),
+            wxLogWarning(_("file '%s', line %d: value for immutable key '%s' ignored."),
                          file.GetName(), n + 1, strKey.c_str());
             continue;
           }
                          file.GetName(), n + 1, strKey.c_str());
             continue;
           }
@@ -377,8 +531,7 @@ void wxFileConfig::Parse(wxTextFile& file, bool bLocal)
           //  (c) key from global file now found in local one
           // which is exactly what we want.
           else if ( !bLocal || pEntry->IsLocal() ) {
           //  (c) key from global file now found in local one
           // which is exactly what we want.
           else if ( !bLocal || pEntry->IsLocal() ) {
-            wxLogWarning(_("file '%s', line %d: key '%s' was first "
-                           "found at line %d."),
+            wxLogWarning(_("file '%s', line %d: key '%s' was first found at line %d."),
                          file.GetName(), n + 1, strKey.c_str(), pEntry->Line());
 
             if ( bLocal )
                          file.GetName(), n + 1, strKey.c_str(), pEntry->Line());
 
             if ( bLocal )
@@ -387,10 +540,10 @@ void wxFileConfig::Parse(wxTextFile& file, bool bLocal)
         }
 
         // skip whitespace
         }
 
         // skip whitespace
-        while ( isspace(*pEnd) )
+        while ( wxIsspace(*pEnd) )
           pEnd++;
 
           pEnd++;
 
-        pEntry->SetValue(FilterIn(pEnd), FALSE /* read from file */);
+        pEntry->SetValue(FilterInValue(pEnd), FALSE /* read from file */);
       }
     }
   }
       }
     }
   }
@@ -456,7 +609,7 @@ bool wxFileConfig::GetFirstGroup(wxString& str, long& lIndex) const
 bool wxFileConfig::GetNextGroup (wxString& str, long& lIndex) const
 {
   if ( size_t(lIndex) < m_pCurrentGroup->Groups().Count() ) {
 bool wxFileConfig::GetNextGroup (wxString& str, long& lIndex) const
 {
   if ( size_t(lIndex) < m_pCurrentGroup->Groups().Count() ) {
-    str = m_pCurrentGroup->Groups()[lIndex++]->Name();
+    str = m_pCurrentGroup->Groups()[(size_t)lIndex++]->Name();
     return TRUE;
   }
   else
     return TRUE;
   }
   else
@@ -472,7 +625,7 @@ bool wxFileConfig::GetFirstEntry(wxString& str, long& lIndex) const
 bool wxFileConfig::GetNextEntry (wxString& str, long& lIndex) const
 {
   if ( size_t(lIndex) < m_pCurrentGroup->Entries().Count() ) {
 bool wxFileConfig::GetNextEntry (wxString& str, long& lIndex) const
 {
   if ( size_t(lIndex) < m_pCurrentGroup->Entries().Count() ) {
-    str = m_pCurrentGroup->Entries()[lIndex++]->Name();
+    str = m_pCurrentGroup->Entries()[(size_t)lIndex++]->Name();
     return TRUE;
   }
   else
     return TRUE;
   }
   else
@@ -544,10 +697,9 @@ bool wxFileConfig::Read(const wxString& key,
   if (pEntry == NULL) {
     return FALSE;
   }
   if (pEntry == NULL) {
     return FALSE;
   }
-  else {
-    *pStr = ExpandEnvVars(pEntry->Value());
-    return TRUE;
-  }
+
+  *pStr = ExpandEnvVars(pEntry->Value());
+  return TRUE;
 }
 
 bool wxFileConfig::Read(const wxString& key,
 }
 
 bool wxFileConfig::Read(const wxString& key,
@@ -556,28 +708,31 @@ bool wxFileConfig::Read(const wxString& key,
   wxConfigPathChanger path(this, key);
 
   ConfigEntry *pEntry = m_pCurrentGroup->FindEntry(path.Name());
   wxConfigPathChanger path(this, key);
 
   ConfigEntry *pEntry = m_pCurrentGroup->FindEntry(path.Name());
+  bool ok;
   if (pEntry == NULL) {
     if( IsRecordingDefaults() )
       ((wxFileConfig *)this)->Write(key,defVal);
     *pStr = ExpandEnvVars(defVal);
   if (pEntry == NULL) {
     if( IsRecordingDefaults() )
       ((wxFileConfig *)this)->Write(key,defVal);
     *pStr = ExpandEnvVars(defVal);
-    return FALSE;
+    ok = FALSE;
   }
   else {
     *pStr = ExpandEnvVars(pEntry->Value());
   }
   else {
     *pStr = ExpandEnvVars(pEntry->Value());
-    return TRUE;
+    ok = TRUE;
   }
   }
+
+  return ok;
 }
 
 bool wxFileConfig::Read(const wxString& key, long *pl) const
 {
   wxString str;
 }
 
 bool wxFileConfig::Read(const wxString& key, long *pl) const
 {
   wxString str;
-  if ( Read(key, & str) ) {
-    *pl = atol(str);
-    return TRUE;
-  }
-  else {
+  if ( !Read(key, & str) )
+  {
     return FALSE;
   }
     return FALSE;
   }
+
+  *pl = wxAtol(str);
+  return TRUE;
 }
 
 bool wxFileConfig::Write(const wxString& key, const wxString& szValue)
 }
 
 bool wxFileConfig::Write(const wxString& key, const wxString& szValue)
@@ -587,7 +742,7 @@ bool wxFileConfig::Write(const wxString& key, const wxString& szValue)
   wxString strName = path.Name();
   if ( strName.IsEmpty() ) {
     // setting the value of a group is an error
   wxString strName = path.Name();
   if ( strName.IsEmpty() ) {
     // setting the value of a group is an error
-    wxASSERT_MSG( IsEmpty(szValue), _("can't set value of a group!") );
+    wxASSERT_MSG( wxIsEmpty(szValue), wxT("can't set value of a group!") );
 
     // ... except if it's empty in which case it's a way to force it's creation
     m_pCurrentGroup->SetDirty();
 
     // ... except if it's empty in which case it's a way to force it's creation
     m_pCurrentGroup->SetDirty();
@@ -600,19 +755,11 @@ bool wxFileConfig::Write(const wxString& key, const wxString& szValue)
 
     // check that the name is reasonable
     if ( strName[0u] == wxCONFIG_IMMUTABLE_PREFIX ) {
 
     // check that the name is reasonable
     if ( strName[0u] == wxCONFIG_IMMUTABLE_PREFIX ) {
-      wxLogError(_("Entry name can't start with '%c'."),
+      wxLogError(_("Config entry name cannot start with '%c'."),
                  wxCONFIG_IMMUTABLE_PREFIX);
       return FALSE;
     }
 
                  wxCONFIG_IMMUTABLE_PREFIX);
       return FALSE;
     }
 
-    for ( const char *pc = strName; *pc != '\0'; pc++ ) {
-      if ( !IsValid(*pc) ) {
-        wxLogError(_("Character '%c' is invalid in a config entry name."),
-                   *pc);
-        return FALSE;
-      }
-    }
-
     ConfigEntry *pEntry = m_pCurrentGroup->FindEntry(strName);
     if ( pEntry == NULL )
       pEntry = m_pCurrentGroup->AddEntry(strName);
     ConfigEntry *pEntry = m_pCurrentGroup->FindEntry(strName);
     if ( pEntry == NULL )
       pEntry = m_pCurrentGroup->AddEntry(strName);
@@ -627,15 +774,24 @@ bool wxFileConfig::Write(const wxString& key, long lValue)
 {
   // ltoa() is not ANSI :-(
   wxString buf;
 {
   // ltoa() is not ANSI :-(
   wxString buf;
-  buf.Printf("%ld", lValue);
+  buf.Printf(wxT("%ld"), lValue);
   return Write(key, buf);
 }
 
 bool wxFileConfig::Flush(bool /* bCurrentOnly */)
 {
   return Write(key, buf);
 }
 
 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);
 
   if ( !file.IsOpened() ) {
   wxTempFile file(m_strLocalFile);
 
   if ( !file.IsOpened() ) {
@@ -651,7 +807,77 @@ bool wxFileConfig::Flush(bool /* bCurrentOnly */)
     }
   }
 
     }
   }
 
-  return file.Commit();
+  bool ret = file.Commit();
+
+#ifdef __WXMAC__
+  if ( ret )
+  {
+       FSSpec spec ;
+       
+       wxUnixFilename2FSSpec( 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
+    ConfigEntry *oldEntry = m_pCurrentGroup->FindEntry(oldName);
+    if ( !oldEntry )
+        return FALSE;
+
+    // check that the new entry doesn't already exist
+    if ( m_pCurrentGroup->FindEntry(newName) )
+        return FALSE;
+
+    // delete the old entry, create the new one
+    wxString value = oldEntry->Value();
+    if ( !m_pCurrentGroup->DeleteEntry(oldName) )
+        return FALSE;
+
+    ConfigEntry *newEntry = m_pCurrentGroup->AddEntry(newName);
+    newEntry->SetValue(value);
+
+    return TRUE;
+}
+
+bool wxFileConfig::RenameGroup(const wxString& oldName,
+                               const wxString& newName)
+{
+    // check that the group exists
+    ConfigGroup *group = m_pCurrentGroup->FindSubgroup(oldName);
+    if ( !group )
+        return FALSE;
+
+    // check that the new group doesn't already exist
+    if ( m_pCurrentGroup->FindSubgroup(newName) )
+        return FALSE;
+
+    group->Rename(newName);
+
+    return TRUE;
 }
 
 // ----------------------------------------------------------------------------
 }
 
 // ----------------------------------------------------------------------------
@@ -668,7 +894,7 @@ bool wxFileConfig::DeleteEntry(const wxString& key, bool bGroupIfEmptyAlso)
   if ( bGroupIfEmptyAlso && m_pCurrentGroup->IsEmpty() ) {
     if ( m_pCurrentGroup != m_pRootGroup ) {
       ConfigGroup *pGroup = m_pCurrentGroup;
   if ( bGroupIfEmptyAlso && m_pCurrentGroup->IsEmpty() ) {
     if ( m_pCurrentGroup != m_pRootGroup ) {
       ConfigGroup *pGroup = m_pCurrentGroup;
-      SetPath("..");  // changes m_pCurrentGroup!
+      SetPath(wxT(".."));  // changes m_pCurrentGroup!
       m_pCurrentGroup->DeleteSubgroupByName(pGroup->Name());
     }
     //else: never delete the root group
       m_pCurrentGroup->DeleteSubgroupByName(pGroup->Name());
     }
     //else: never delete the root group
@@ -688,12 +914,10 @@ bool wxFileConfig::DeleteAll()
 {
   CleanUp();
 
 {
   CleanUp();
 
-  const char *szFile = m_strLocalFile;
+  if ( wxRemove(m_strLocalFile) == -1 )
+    wxLogSysError(_("can't delete user configuration file '%s'"), m_strLocalFile.c_str());
 
 
-  if ( remove(szFile) == -1 )
-    wxLogSysError(_("can't delete user configuration file '%s'"), szFile);
-
-  m_strLocalFile = m_strGlobalFile = "";
+  m_strLocalFile = m_strGlobalFile = wxT("");
   Init();
 
   return TRUE;
   Init();
 
   return TRUE;
@@ -852,7 +1076,7 @@ void 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
 
 // 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
@@ -865,7 +1089,10 @@ LineList *ConfigGroup::GetGroupLine()
     // this group wasn't present in local config file, add it now
     if ( pParent != NULL ) {
       wxString strFullName;
     // this group wasn't present in local config file, add it now
     if ( pParent != NULL ) {
       wxString strFullName;
-      strFullName << "[" << (GetFullName().c_str() + 1) << "]"; // +1: no '/'
+      strFullName << wxT("[")
+                  // +1: no '/'
+                  << FilterOutEntryName(GetFullName().c_str() + 1)
+                  << wxT("]");
       m_pLine = m_pConfig->LineListInsert(strFullName,
                                           pParent->GetLastGroupLine());
       pParent->SetLastGroup(this);  // we're surely after all the others
       m_pLine = m_pConfig->LineListInsert(strFullName,
                                           pParent->GetLastGroupLine());
       pParent->SetLastGroup(this);  // we're surely after all the others
@@ -917,12 +1144,24 @@ LineList *ConfigGroup::GetLastEntryLine()
 // group name
 // ----------------------------------------------------------------------------
 
 // group name
 // ----------------------------------------------------------------------------
 
+void ConfigGroup::Rename(const wxString& newName)
+{
+    m_strName = newName;
+
+    LineList *line = GetGroupLine();
+    wxString strFullName;
+    strFullName << wxT("[") << (GetFullName().c_str() + 1) << wxT("]"); // +1: no '/'
+    line->SetText(strFullName);
+
+    SetDirty();
+}
+
 wxString ConfigGroup::GetFullName() const
 {
   if ( Parent() )
     return Parent()->GetFullName() + wxCONFIG_PATH_SEPARATOR + Name();
   else
 wxString ConfigGroup::GetFullName() const
 {
   if ( Parent() )
     return Parent()->GetFullName() + wxCONFIG_PATH_SEPARATOR + Name();
   else
-    return "";
+    return wxT("");
 }
 
 // ----------------------------------------------------------------------------
 }
 
 // ----------------------------------------------------------------------------
@@ -931,7 +1170,7 @@ wxString ConfigGroup::GetFullName() const
 
 // use binary search because the array is sorted
 ConfigEntry *
 
 // use binary search because the array is sorted
 ConfigEntry *
-ConfigGroup::FindEntry(const char *szName) const
+ConfigGroup::FindEntry(const wxChar *szName) const
 {
   size_t i,
        lo = 0,
 {
   size_t i,
        lo = 0,
@@ -944,9 +1183,9 @@ ConfigGroup::FindEntry(const char *szName) const
     pEntry = m_aEntries[i];
 
     #if wxCONFIG_CASE_SENSITIVE
     pEntry = m_aEntries[i];
 
     #if wxCONFIG_CASE_SENSITIVE
-      res = strcmp(pEntry->Name(), szName);
+      res = wxStrcmp(pEntry->Name(), szName);
     #else
     #else
-      res = Stricmp(pEntry->Name(), szName);
+      res = wxStricmp(pEntry->Name(), szName);
     #endif
 
     if ( res > 0 )
     #endif
 
     if ( res > 0 )
@@ -961,7 +1200,7 @@ ConfigGroup::FindEntry(const char *szName) const
 }
 
 ConfigGroup *
 }
 
 ConfigGroup *
-ConfigGroup::FindSubgroup(const char *szName) const
+ConfigGroup::FindSubgroup(const wxChar *szName) const
 {
   size_t i,
        lo = 0,
 {
   size_t i,
        lo = 0,
@@ -974,9 +1213,9 @@ ConfigGroup::FindSubgroup(const char *szName) const
     pGroup = m_aSubgroups[i];
 
     #if wxCONFIG_CASE_SENSITIVE
     pGroup = m_aSubgroups[i];
 
     #if wxCONFIG_CASE_SENSITIVE
-      res = strcmp(pGroup->Name(), szName);
+      res = wxStrcmp(pGroup->Name(), szName);
     #else
     #else
-      res = Stricmp(pGroup->Name(), szName);
+      res = wxStricmp(pGroup->Name(), szName);
     #endif
 
     if ( res > 0 )
     #endif
 
     if ( res > 0 )
@@ -1029,7 +1268,7 @@ ConfigGroup::AddSubgroup(const wxString& strName)
   delete several of them.
  */
 
   delete several of them.
  */
 
-bool ConfigGroup::DeleteSubgroupByName(const char *szName)
+bool ConfigGroup::DeleteSubgroupByName(const wxChar *szName)
 {
   return DeleteSubgroup(FindSubgroup(szName));
 }
 {
   return DeleteSubgroup(FindSubgroup(szName));
 }
@@ -1052,7 +1291,7 @@ bool ConfigGroup::DeleteSubgroup(ConfigGroup *pGroup)
   // and subgroups of this sungroup
   nCount = pGroup->m_aSubgroups.Count();
   for ( size_t nGroup = 0; nGroup < nCount; nGroup++ ) {
   // and subgroups of this sungroup
   nCount = pGroup->m_aSubgroups.Count();
   for ( size_t nGroup = 0; nGroup < nCount; nGroup++ ) {
-    pGroup->DeleteSubgroup(pGroup->m_aSubgroups[nGroup]);
+    pGroup->DeleteSubgroup(pGroup->m_aSubgroups[0]);
   }
 
   LineList *pLine = pGroup->m_pLine;
   }
 
   LineList *pLine = pGroup->m_pLine;
@@ -1101,7 +1340,7 @@ bool ConfigGroup::DeleteSubgroup(ConfigGroup *pGroup)
   return TRUE;
 }
 
   return TRUE;
 }
 
-bool ConfigGroup::DeleteEntry(const char *szName)
+bool ConfigGroup::DeleteEntry(const wxChar *szName)
 {
   ConfigEntry *pEntry = FindEntry(szName);
   wxCHECK( pEntry != NULL, FALSE );  // deleting non existing item?
 {
   ConfigEntry *pEntry = FindEntry(szName);
   wxCHECK( pEntry != NULL, FALSE );  // deleting non existing item?
@@ -1218,9 +1457,9 @@ void ConfigEntry::SetValue(const wxString& strValue, bool bUser)
   m_strValue = strValue;
 
   if ( bUser ) {
   m_strValue = strValue;
 
   if ( bUser ) {
-    wxString strVal = FilterOut(strValue);
+    wxString strVal = FilterOutValue(strValue);
     wxString strLine;
     wxString strLine;
-    strLine << m_strName << " = " << strVal;
+    strLine << FilterOutEntryName(m_strName) << wxT('=') << strVal;
 
     if ( m_pLine != NULL ) {
       // entry was read from the local config file, just modify the line
 
     if ( m_pLine != NULL ) {
       // entry was read from the local config file, just modify the line
@@ -1257,9 +1496,9 @@ int CompareEntries(ConfigEntry *p1,
                    ConfigEntry *p2)
 {
   #if wxCONFIG_CASE_SENSITIVE
                    ConfigEntry *p2)
 {
   #if wxCONFIG_CASE_SENSITIVE
-    return strcmp(p1->Name(), p2->Name());
+    return wxStrcmp(p1->Name(), p2->Name());
   #else
   #else
-    return Stricmp(p1->Name(), p2->Name());
+    return wxStricmp(p1->Name(), p2->Name());
   #endif
 }
 
   #endif
 }
 
@@ -1267,9 +1506,9 @@ int CompareGroups(ConfigGroup *p1,
                   ConfigGroup *p2)
 {
   #if wxCONFIG_CASE_SENSITIVE
                   ConfigGroup *p2)
 {
   #if wxCONFIG_CASE_SENSITIVE
-    return strcmp(p1->Name(), p2->Name());
+    return wxStrcmp(p1->Name(), p2->Name());
   #else
   #else
-    return Stricmp(p1->Name(), p2->Name());
+    return wxStricmp(p1->Name(), p2->Name());
   #endif
 }
 
   #endif
 }
 
@@ -1277,8 +1516,8 @@ int CompareGroups(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());
 {
   wxString strResult;
   strResult.Alloc(str.Len());
@@ -1286,31 +1525,31 @@ wxString FilterIn(const wxString& str)
   bool bQuoted = !str.IsEmpty() && str[0] == '"';
 
   for ( size_t n = bQuoted ? 1 : 0; n < str.Len(); n++ ) {
   bool bQuoted = !str.IsEmpty() && str[0] == '"';
 
   for ( size_t n = bQuoted ? 1 : 0; n < str.Len(); n++ ) {
-    if ( str[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'."),
@@ -1324,42 +1563,42 @@ 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.IsEmpty())
+   if ( !str )
       return str;
 
   wxString strResult;
   strResult.Alloc(str.Len());
 
   // quoting is necessary to preserve spaces in the beginning of the string
       return str;
 
   wxString strResult;
   strResult.Alloc(str.Len());
 
   // quoting is necessary to preserve spaces in the beginning of the string
-  bool bQuote = isspace(str[0]) || str[0] == '"';
+  bool bQuote = wxIsspace(str[0]) || str[0] == wxT('"');
 
   if ( bQuote )
 
   if ( bQuote )
-    strResult += '"';
+    strResult += wxT('"');
 
 
-  char c;
+  wxChar c;
   for ( size_t n = 0; n < str.Len(); n++ ) {
     switch ( str[n] ) {
   for ( size_t n = 0; n < str.Len(); 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 '"':
+      case wxT('"'):
         if ( bQuote ) {
         if ( bQuote ) {
-          c = '"';
+          c = wxT('"');
           break;
         }
         //else: fall through
           break;
         }
         //else: fall through
@@ -1370,18 +1609,62 @@ wxString FilterOut(const wxString& str)
     }
 
     // we get here only for special characters
     }
 
     // we get here only for special characters
-    strResult << '\\' << c;
+    strResult << wxT('\\') << c;
   }
 
   if ( bQuote )
   }
 
   if ( bQuote )
-    strResult += '"';
+    strResult += wxT('"');
+
+  return strResult;
+}
+
+// undo FilterOutEntryName
+static wxString FilterInEntryName(const wxString& str)
+{
+  wxString strResult;
+  strResult.Alloc(str.Len());
+
+  for ( const wxChar *pc = str.c_str(); *pc != '\0'; pc++ ) {
+    if ( *pc == wxT('\\') )
+      pc++;
+
+    strResult += *pc;
+  }
 
   return strResult;
 }
 
 
   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