]> git.saurik.com Git - wxWidgets.git/blobdiff - src/common/fileconf.cpp
Very bad wxPrintData destructor... fixed typo.
[wxWidgets.git] / src / common / fileconf.cpp
index c887bc6b8664edfae8eb68918f75c3deab764e95..cf8ad6879af2862b4cfc8079eacb2d6875254855 100644 (file)
 // 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 CompareEntries(ConfigEntry *p1, ConfigEntry *p2);
+static int 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);
 
 // ============================================================================
 // implementation
 
 // ============================================================================
 // implementation
@@ -97,6 +93,8 @@ wxString wxFileConfig::GetGlobalDir()
     strDir = "/etc/";
   #elif defined(__WXSTUBS__)
     wxASSERT_MSG( FALSE, "TODO" ) ;
     strDir = "/etc/";
   #elif defined(__WXSTUBS__)
     wxASSERT_MSG( FALSE, "TODO" ) ;
+  #elif defined(__WXMAC__)
+    wxASSERT_MSG( FALSE, "TODO" ) ;
   #else // Windows
     char szWinDir[MAX_PATH];
     ::GetWindowsDirectory(szWinDir, MAX_PATH);
   #else // Windows
     char szWinDir[MAX_PATH];
     ::GetWindowsDirectory(szWinDir, MAX_PATH);
@@ -295,8 +293,8 @@ void wxFileConfig::Parse(wxTextFile& file, bool bLocal)
       pEnd = pStart;
 
       while ( *++pEnd != ']' ) {
       pEnd = pStart;
 
       while ( *++pEnd != ']' ) {
-        if ( !IsValid(*pEnd) && *pEnd != ' ' )  // allow spaces in group names
-          break;
+        if ( *pEnd == '\n' || *pEnd == '\0' )
+            break;
       }
 
       if ( *pEnd != ']' ) {
       }
 
       if ( *pEnd != ']' ) {
@@ -308,7 +306,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);
@@ -340,10 +339,17 @@ void wxFileConfig::Parse(wxTextFile& file, bool bLocal)
     }
     else {                        // a key
       const char *pEnd = pStart;
     }
     else {                        // a key
       const char *pEnd = pStart;
-      while ( IsValid(*pEnd) )
+      while ( !isspace(*pEnd) ) {
+        if ( *pEnd == '\\' ) {
+          // next character may be space or not - still take it because it's
+          // quoted
+          pEnd++;
+        }
+
         pEnd++;
         pEnd++;
+      }
 
 
-      wxString strKey(pStart, pEnd);
+      wxString strKey(FilterInEntryName(wxString(pStart, pEnd)));
 
       // skip whitespace
       while ( isspace(*pEnd) )
 
       // skip whitespace
       while ( isspace(*pEnd) )
@@ -390,7 +396,7 @@ void wxFileConfig::Parse(wxTextFile& file, bool bLocal)
         while ( isspace(*pEnd) )
           pEnd++;
 
         while ( isspace(*pEnd) )
           pEnd++;
 
-        pEntry->SetValue(FilterIn(pEnd), FALSE /* read from file */);
+        pEntry->SetValue(FilterInValue(pEnd), FALSE /* read from file */);
       }
     }
   }
       }
     }
   }
@@ -587,7 +593,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( IsEmpty(szValue), "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,18 +606,12 @@ 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;
-      }
-    }
+    strName = FilterOutEntryName(strName);
 
     ConfigEntry *pEntry = m_pCurrentGroup->FindEntry(strName);
     if ( pEntry == NULL )
 
     ConfigEntry *pEntry = m_pCurrentGroup->FindEntry(strName);
     if ( pEntry == NULL )
@@ -654,6 +654,50 @@ bool wxFileConfig::Flush(bool /* bCurrentOnly */)
   return file.Commit();
 }
 
   return file.Commit();
 }
 
+// ----------------------------------------------------------------------------
+// renaming groups/entries
+// ----------------------------------------------------------------------------
+
+bool wxFileConfig::RenameEntry(const wxString& oldName,
+                               const wxString& newName)
+{
+    // check that the entry exists
+    ConfigEntry *oldEntry = m_pCurrentGroup->FindEntry(oldName);
+    if ( !oldEntry )
+        return FALSE;
+
+    // check that the new entry doesn't already exist
+    if ( m_pCurrentGroup->FindEntry(newName) )
+        return FALSE;
+
+    // delete the old entry, create the new one
+    wxString value = oldEntry->Value();
+    if ( !m_pCurrentGroup->DeleteEntry(oldName) )
+        return FALSE;
+
+    ConfigEntry *newEntry = m_pCurrentGroup->AddEntry(newName);
+    newEntry->SetValue(value);
+
+    return TRUE;
+}
+
+bool wxFileConfig::RenameGroup(const wxString& oldName,
+                               const wxString& newName)
+{
+    // check that the group exists
+    ConfigGroup *group = m_pCurrentGroup->FindSubgroup(oldName);
+    if ( !group )
+        return FALSE;
+
+    // check that the new group doesn't already exist
+    if ( m_pCurrentGroup->FindSubgroup(newName) )
+        return FALSE;
+
+    group->Rename(newName);
+
+    return TRUE;
+}
+
 // ----------------------------------------------------------------------------
 // delete groups/entries
 // ----------------------------------------------------------------------------
 // ----------------------------------------------------------------------------
 // delete groups/entries
 // ----------------------------------------------------------------------------
@@ -852,7 +896,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
@@ -917,6 +961,18 @@ LineList *ConfigGroup::GetLastEntryLine()
 // group name
 // ----------------------------------------------------------------------------
 
 // group name
 // ----------------------------------------------------------------------------
 
+void ConfigGroup::Rename(const wxString& newName)
+{
+    m_strName = newName;
+
+    LineList *line = GetGroupLine();
+    wxString strFullName;
+    strFullName << "[" << (GetFullName().c_str() + 1) << "]"; // +1: no '/'
+    line->SetText(strFullName);
+
+    SetDirty();
+}
+
 wxString ConfigGroup::GetFullName() const
 {
   if ( Parent() )
 wxString ConfigGroup::GetFullName() const
 {
   if ( Parent() )
@@ -1218,7 +1274,7 @@ 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;
     strLine << m_strName << " = " << strVal;
 
     wxString strLine;
     strLine << m_strName << " = " << strVal;
 
@@ -1277,8 +1333,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());
@@ -1324,9 +1380,9 @@ 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;
       return str;
 
   wxString strResult;
@@ -1379,9 +1435,41 @@ wxString FilterOut(const wxString& str)
   return strResult;
 }
 
   return strResult;
 }
 
+// undo FilterOutEntryName
+static wxString FilterInEntryName(const wxString& str)
+{
+  wxString strResult;
+  strResult.Alloc(str.Len());
+
+  for ( const char *pc = str.c_str(); *pc != '\0'; pc++ ) {
+    if ( *pc == '\\' )
+      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 char *pc = str.c_str(); *pc != '\0'; pc++ ) {
+    char 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 ( !isalnum(c) && !strchr("@_/-!.*%", c) && ((c & 0x80) == 0) )
+      strResult += '\\';
 
 
+    strResult += c;
+  }
 
 
+  return strResult;
+}