X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/6a23cbcede2d878401c64df3be34bef6331e1dcd..69659fd770f615210efac4b4fa741b3ad6223616:/src/msw/regconf.cpp?ds=sidebyside diff --git a/src/msw/regconf.cpp b/src/msw/regconf.cpp index c326c6a0da..4d5388cf4c 100644 --- a/src/msw/regconf.cpp +++ b/src/msw/regconf.cpp @@ -1,51 +1,42 @@ /////////////////////////////////////////////////////////////////////////////// -// Name: msw/regconf.cpp +// Name: src/msw/regconf.cpp // Purpose: // Author: Vadim Zeitlin // Modified by: // Created: 27.04.98 // RCS-ID: $Id$ // Copyright: (c) 1998 Vadim Zeitlin -// Licence: wxWindows license +// Licence: wxWindows licence /////////////////////////////////////////////////////////////////////////////// -#ifdef __GNUG__ -#pragma implementation "regconf.h" -#endif - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" -#ifdef __GNUG__ - #pragma implementation "regconf.h" +#ifdef __BORLANDC__ + #pragma hdrstop #endif -#include "wx/wxprec.h" +#if wxUSE_CONFIG -#ifdef __BORLANDC__ - #pragma hdrstop -#endif //__BORLANDC__ +#include "wx/config.h" #ifndef WX_PRECOMP - #include + #include "wx/string.h" + #include "wx/intl.h" + #include "wx/log.h" + #include "wx/event.h" + #include "wx/app.h" #endif //WX_PRECOMP -#include -#include -#include -#include +#include "wx/msw/registry.h" +#include "wx/msw/regconf.h" // ---------------------------------------------------------------------------- // constants // ---------------------------------------------------------------------------- // we put our data in HKLM\SOFTWARE_KEY\appname -#define SOFTWARE_KEY wxString("Software\\") +#define SOFTWARE_KEY wxString(wxT("Software\\")) // ---------------------------------------------------------------------------- // global functions @@ -62,6 +53,11 @@ bool TryGetValue(const wxRegKey& key, const wxString& str, long *plVal) return key.IsOpened() && key.HasValue(str) && key.QueryValue(str, plVal); } +bool TryGetValue(const wxRegKey& key, const wxString& str, wxMemoryBuffer &plVal) +{ + return key.IsOpened() && key.HasValue(str) && key.QueryValue(str, plVal); +} + // ============================================================================ // implementation // ============================================================================ @@ -69,60 +65,329 @@ bool TryGetValue(const wxRegKey& key, const wxString& str, long *plVal) // ---------------------------------------------------------------------------- // ctor/dtor // ---------------------------------------------------------------------------- -wxRegConfig::wxRegConfig(const wxString& strRoot) - : m_keyLocalRoot(wxRegKey::HKCU, SOFTWARE_KEY + strRoot), - m_keyLocal(m_keyLocalRoot, ""), - m_keyGlobalRoot(wxRegKey::HKLM, SOFTWARE_KEY + strRoot), - m_keyGlobal(m_keyGlobalRoot, "") +IMPLEMENT_ABSTRACT_CLASS(wxRegConfig, wxConfigBase) + +// create the config object which stores its data under HKCU\vendor\app and, if +// style & wxCONFIG_USE_GLOBAL_FILE, under HKLM\vendor\app +wxRegConfig::wxRegConfig(const wxString& appName, const wxString& vendorName, + const wxString& strLocal, const wxString& strGlobal, + long style) + : wxConfigBase(appName, vendorName, strLocal, strGlobal, style) { + wxString strRoot; + + bool bDoUseGlobal = (style & wxCONFIG_USE_GLOBAL_FILE) != 0; + + // the convention is to put the programs keys under \ + // (but it can be overriden by specifying the pathes explicitly in strLocal + // and/or strGlobal) + if ( strLocal.empty() || (strGlobal.empty() && bDoUseGlobal) ) + { + if ( vendorName.empty() ) + { + if ( wxTheApp ) + strRoot = wxTheApp->GetVendorName(); + } + else + { + strRoot = vendorName; + } + + // no '\\' needed if no vendor name + if ( !strRoot.empty() ) + { + strRoot += '\\'; + } + + if ( appName.empty() ) + { + wxCHECK_RET( wxTheApp, wxT("No application name in wxRegConfig ctor!") ); + strRoot << wxTheApp->GetAppName(); + } + else + { + strRoot << appName; + } + } + //else: we don't need to do all the complicated stuff above + + wxString str = strLocal.empty() ? strRoot : strLocal; + + // as we're going to change the name of these keys fairly often and as + // there are only few of wxRegConfig objects (usually 1), we can allow + // ourselves to be generous and spend some memory to significantly improve + // performance of SetPath() + static const size_t MEMORY_PREALLOC = 512; + + m_keyLocalRoot.ReserveMemoryForName(MEMORY_PREALLOC); + m_keyLocal.ReserveMemoryForName(MEMORY_PREALLOC); + + m_keyLocalRoot.SetName(wxRegKey::HKCU, SOFTWARE_KEY + str); + m_keyLocal.SetName(m_keyLocalRoot, wxEmptyString); + + if ( bDoUseGlobal ) + { + str = strGlobal.empty() ? strRoot : strGlobal; + + m_keyGlobalRoot.ReserveMemoryForName(MEMORY_PREALLOC); + m_keyGlobal.ReserveMemoryForName(MEMORY_PREALLOC); + + m_keyGlobalRoot.SetName(wxRegKey::HKLM, SOFTWARE_KEY + str); + m_keyGlobal.SetName(m_keyGlobalRoot, wxEmptyString); + } + // Create() will Open() if key already exists m_keyLocalRoot.Create(); - wxLogNull nolog; - m_keyGlobalRoot.Open(); -} + // as it's the same key, Open() shouldn't fail (i.e. no need for Create()) + m_keyLocal.Open(); -wxRegConfig::~wxRegConfig() -{ - // nothing to do - key will be closed in their dtors + // OTOH, this key may perfectly not exist, so suppress error messages the call + // to Open() might generate + if ( bDoUseGlobal ) + { + wxLogNull nolog; + m_keyGlobalRoot.Open(wxRegKey::Read); + m_keyGlobal.Open(wxRegKey::Read); + } } // ---------------------------------------------------------------------------- // path management // ---------------------------------------------------------------------------- + +// this function is called a *lot* of times (as I learned after seeing from +// profiler output that it is called ~12000 times from Mahogany start up code!) +// so it is important to optimize it - in particular, avoid using generic +// string functions here and do everything manually because it is faster +// +// I still kept the old version to be able to check that the optimized code has +// the same output as the non optimized version. void wxRegConfig::SetPath(const wxString& strPath) { - wxArrayString aParts; + // remember the old path + wxString strOldPath = m_strPath; + +#ifdef WX_DEBUG_SET_PATH // non optimized version kept here for testing + wxString m_strPathAlt; + + { + wxArrayString aParts; + + // because GetPath() returns "" when we're at root, we must understand + // empty string as "/" + if ( strPath.empty() || (strPath[0] == wxCONFIG_PATH_SEPARATOR) ) { + // absolute path + wxSplitPath(aParts, strPath); + } + else { + // relative path, combine with current one + wxString strFullPath = GetPath(); + strFullPath << wxCONFIG_PATH_SEPARATOR << strPath; + wxSplitPath(aParts, strFullPath); + } + + // recombine path parts in one variable + wxString strRegPath; + m_strPathAlt.Empty(); + for ( size_t n = 0; n < aParts.Count(); n++ ) { + strRegPath << '\\' << aParts[n]; + m_strPathAlt << wxCONFIG_PATH_SEPARATOR << aParts[n]; + } + } +#endif // 0 + + // check for the most common case first + if ( strPath.empty() ) + { + m_strPath = wxCONFIG_PATH_SEPARATOR; + } + else // not root + { + // construct the full path + wxString strFullPath; + if ( strPath[0u] == wxCONFIG_PATH_SEPARATOR ) + { + // absolute path + strFullPath = strPath; + } + else // relative path + { + strFullPath.reserve(2*m_strPath.length()); + + strFullPath << m_strPath; + if ( strFullPath.Len() == 0 || + strFullPath.Last() != wxCONFIG_PATH_SEPARATOR ) + strFullPath << wxCONFIG_PATH_SEPARATOR; + strFullPath << strPath; + } + + // simplify it: we need to handle ".." here + + // count the total number of slashes we have to know if we can go upper + size_t totalSlashes = 0; + + // position of the last slash to be able to backtrack to it quickly if + // needed, but we set it to -1 if we don't have a valid position + // + // we only remember the last position which means that we handle ".." + // quite efficiently but not "../.." - however the latter should be + // much more rare, so it is probably ok + int posLastSlash = -1; + + const wxChar *src = strFullPath.c_str(); + size_t len = strFullPath.length(); + const wxChar *end = src + len; + + wxStringBufferLength buf(m_strPath, len); + wxChar *dst = buf; + wxChar *start = dst; + + for ( ; src < end; src++, dst++ ) + { + if ( *src == wxCONFIG_PATH_SEPARATOR ) + { + // check for "/.." + + // note that we don't have to check for src < end here as + // *end == 0 so can't be '.' + if ( src[1] == _T('.') && src[2] == _T('.') && + (src + 3 == end || src[3] == wxCONFIG_PATH_SEPARATOR) ) + { + if ( !totalSlashes ) + { + wxLogWarning(_("'%s' has extra '..', ignored."), + strFullPath.c_str()); + } + else // return to the previous path component + { + // do we already have its position? + if ( posLastSlash == -1 ) + { + // no, find it: note that we are sure to have one + // because totalSlashes > 0 so we don't have to + // check the boundary condition below + + // this is more efficient than strrchr() + dst--; + while ( *dst != wxCONFIG_PATH_SEPARATOR ) + { + dst--; + } + } + else // the position of last slash was stored + { + // go directly there + dst = start + posLastSlash; + + // invalidate posLastSlash + posLastSlash = -1; + } + + // we must have found a slash one way or another! + wxASSERT_MSG( *dst == wxCONFIG_PATH_SEPARATOR, + _T("error in wxRegConfig::SetPath") ); + + // stay at the same position + dst--; + + // we killed one + totalSlashes--; + } + + // skip both dots + src += 2; + } + else // not "/.." + { + if ( (dst == start) || (dst[-1] != wxCONFIG_PATH_SEPARATOR) ) + { + *dst = wxCONFIG_PATH_SEPARATOR; + + posLastSlash = dst - start; + + totalSlashes++; + } + else // previous char was a slash too + { + // squeeze several subsequent slashes into one: i.e. + // just ignore this one + dst--; + } + } + } + else // normal character + { + // just copy + *dst = *src; + } + } + + // NUL terminate the string + if ( dst[-1] == wxCONFIG_PATH_SEPARATOR && (dst != start + 1) ) + { + // if it has a trailing slash we remove it unless it is the only + // string character + dst--; + } + + *dst = _T('\0'); + buf.SetLength(dst - start); + } - if ( strPath.IsEmpty() ) - return; +#ifdef WX_DEBUG_SET_PATH + wxASSERT( m_strPath == m_strPathAlt ); +#endif - if ( strPath[0] == APPCONF_PATH_SEPARATOR ) { - // absolute path - wxSplitPath(aParts, strPath); - } - else { - // relative path, combine with current one - wxString strFullPath = GetPath(); - strFullPath << APPCONF_PATH_SEPARATOR << strPath; - wxSplitPath(aParts, strFullPath); - } + if ( m_strPath == strOldPath ) + return; + + // registry APIs want backslashes instead of slashes + wxString strRegPath; + if ( !m_strPath.empty() ) + { + size_t len = m_strPath.length(); + + const wxChar *src = m_strPath.c_str(); + wxStringBufferLength buf(strRegPath, len); + wxChar *dst = buf; + + const wxChar *end = src + len; + for ( ; src < end; src++, dst++ ) + { + if ( *src == wxCONFIG_PATH_SEPARATOR ) + *dst = _T('\\'); + else + *dst = *src; + } + + buf.SetLength(len); + } - // recombine path parts in one variable - wxString strRegPath; - m_strPath.Empty(); - for ( uint n = 0; n < aParts.Count(); n++ ) { - strRegPath << '\\' << aParts[n]; - m_strPath << APPCONF_PATH_SEPARATOR << aParts[n]; - } + // this is not needed any longer as we don't create keys unnecessarily any + // more (now it is done on demand, i.e. only when they're going to contain + // something) +#if 0 + // as we create the registry key when SetPath(key) is done, we can be left + // with plenty of empty keys if this was only done to try to read some + // value which, in fact, doesn't exist - to prevent this from happening we + // automatically delete the old key if it was empty + if ( m_keyLocal.Exists() && LocalKey().IsEmpty() ) + { + m_keyLocal.DeleteSelf(); + } +#endif // 0 - // change current key(s) - m_keyLocal.SetName(m_keyLocalRoot, strRegPath); - m_keyGlobal.SetName(m_keyGlobalRoot, strRegPath); - m_keyLocal.Create(); + // change current key(s) + m_keyLocal.SetName(m_keyLocalRoot, strRegPath); - wxLogNull nolog; - m_keyGlobal.Open(); + if ( GetStyle() & wxCONFIG_USE_GLOBAL_FILE ) + { + m_keyGlobal.SetName(m_keyGlobalRoot, strRegPath); + + wxLogNull nolog; + m_keyGlobal.Open(wxRegKey::Read); + } } // ---------------------------------------------------------------------------- @@ -140,67 +405,79 @@ void wxRegConfig::SetPath(const wxString& strPath) #define LOCAL_MASK 0x8000 #define IS_LOCAL_INDEX(l) (((l) & LOCAL_MASK) != 0) -bool wxRegConfig::GetFirstGroup(wxString& str, long& lIndex) +bool wxRegConfig::GetFirstGroup(wxString& str, long& lIndex) const { lIndex = 0; return GetNextGroup(str, lIndex); } -bool wxRegConfig::GetNextGroup(wxString& str, long& lIndex) +bool wxRegConfig::GetNextGroup(wxString& str, long& lIndex) const { // are we already enumerating local entries? if ( m_keyGlobal.IsOpened() && !IS_LOCAL_INDEX(lIndex) ) { // try to find a global entry which doesn't appear locally - do { - if ( !m_keyGlobal.GetNextKey(str, lIndex) ) { - // no more global entries - lIndex |= LOCAL_MASK; - break; + while ( m_keyGlobal.GetNextKey(str, lIndex) ) { + if ( !m_keyLocal.Exists() || !LocalKey().HasSubKey(str) ) { + // ok, found one - return it + return true; } - } while( m_keyLocal.HasSubKey(str) ); + } + + // no more global entries + lIndex |= LOCAL_MASK; } + // if we don't have the key at all, don't try to enumerate anything under it + if ( !m_keyLocal.Exists() ) + return false; + // much easier with local entries: get the next one we find // (don't forget to clear our flag bit and set it again later) lIndex &= ~LOCAL_MASK; - bool bOk = m_keyLocal.GetNextKey(str, lIndex); + bool bOk = LocalKey().GetNextKey(str, lIndex); lIndex |= LOCAL_MASK; return bOk; } -bool wxRegConfig::GetFirstEntry(wxString& str, long& lIndex) +bool wxRegConfig::GetFirstEntry(wxString& str, long& lIndex) const { lIndex = 0; return GetNextEntry(str, lIndex); } -bool wxRegConfig::GetNextEntry(wxString& str, long& lIndex) +bool wxRegConfig::GetNextEntry(wxString& str, long& lIndex) const { // are we already enumerating local entries? if ( m_keyGlobal.IsOpened() && !IS_LOCAL_INDEX(lIndex) ) { // try to find a global entry which doesn't appear locally - do { - if ( !m_keyGlobal.GetNextValue(str, lIndex) ) { - // no more global entries - lIndex |= LOCAL_MASK; - break; + while ( m_keyGlobal.GetNextValue(str, lIndex) ) { + if ( !m_keyLocal.Exists() || !LocalKey().HasValue(str) ) { + // ok, found one - return it + return true; } - } while( m_keyLocal.HasValue(str) ); + } + + // no more global entries + lIndex |= LOCAL_MASK; } + // if we don't have the key at all, don't try to enumerate anything under it + if ( !m_keyLocal.Exists() ) + return false; + // much easier with local entries: get the next one we find // (don't forget to clear our flag bit and set it again later) lIndex &= ~LOCAL_MASK; - bool bOk = m_keyLocal.GetNextValue(str, lIndex); + bool bOk = LocalKey().GetNextValue(str, lIndex); lIndex |= LOCAL_MASK; return bOk; } -uint wxRegConfig::GetNumberOfEntries(bool bRecursive) const +size_t wxRegConfig::GetNumberOfEntries(bool WXUNUSED(bRecursive)) const { - uint nEntries = 0; + size_t nEntries = 0; // dummy vars wxString str; @@ -215,9 +492,9 @@ uint wxRegConfig::GetNumberOfEntries(bool bRecursive) const return nEntries; } -uint wxRegConfig::GetNumberOfGroups(bool bRecursive) const +size_t wxRegConfig::GetNumberOfGroups(bool WXUNUSED(bRecursive)) const { - uint nGroups = 0; + size_t nGroups = 0; // dummy vars wxString str; @@ -236,138 +513,256 @@ uint wxRegConfig::GetNumberOfGroups(bool bRecursive) const // tests for existence // ---------------------------------------------------------------------------- -bool wxRegConfig::HasGroup(const wxString& strName) const +bool wxRegConfig::HasGroup(const wxString& key) const { - return m_keyLocal.HasSubKey(strName) || m_keyGlobal.HasSubKey(strName); + wxConfigPathChanger path(this, key); + + wxString strName(path.Name()); + + return (m_keyLocal.Exists() && LocalKey().HasSubKey(strName)) || + m_keyGlobal.HasSubKey(strName); +} + +bool wxRegConfig::HasEntry(const wxString& key) const +{ + wxConfigPathChanger path(this, key); + + wxString strName(path.Name()); + + return (m_keyLocal.Exists() && LocalKey().HasValue(strName)) || + m_keyGlobal.HasValue(strName); } -bool wxRegConfig::HasEntry(const wxString& strName) const +wxConfigBase::EntryType wxRegConfig::GetEntryType(const wxString& key) const { - return m_keyLocal.HasValue(strName) || m_keyGlobal.HasValue(strName); + wxConfigPathChanger path(this, key); + + wxString strName(path.Name()); + + bool isNumeric; + if ( m_keyLocal.Exists() && LocalKey().HasValue(strName) ) + isNumeric = m_keyLocal.IsNumericValue(strName); + else if ( m_keyGlobal.HasValue(strName) ) + isNumeric = m_keyGlobal.IsNumericValue(strName); + else + return wxConfigBase::Type_Unknown; + + return isNumeric ? wxConfigBase::Type_Integer : wxConfigBase::Type_String; } // ---------------------------------------------------------------------------- // reading/writing // ---------------------------------------------------------------------------- -bool wxRegConfig::Read(wxString& str, - const char *szKey, - const char *szDefault) const +bool wxRegConfig::DoReadString(const wxString& key, wxString *pStr) const { - PathChanger path(this, szKey); + wxCHECK_MSG( pStr, false, _T("wxRegConfig::Read(): NULL param") ); - bool bQueryGlobal = TRUE; + wxConfigPathChanger path(this, key); + + bool bQueryGlobal = true; // if immutable key exists in global key we must check that it's not // overriden by the local key with the same name if ( IsImmutable(path.Name()) ) { - if ( TryGetValue(m_keyGlobal, path.Name(), str) ) { - if ( m_keyLocal.HasValue(path.Name()) ) { - wxLogWarning("User value for immutable key '%s' ignored.", + if ( TryGetValue(m_keyGlobal, path.Name(), *pStr) ) { + if ( m_keyLocal.Exists() && LocalKey().HasValue(path.Name()) ) { + wxLogWarning(wxT("User value for immutable key '%s' ignored."), path.Name().c_str()); } - return TRUE; + return true; } else { // don't waste time - it's not there anyhow - bQueryGlobal = FALSE; + bQueryGlobal = false; } } // first try local key - if ( TryGetValue(m_keyLocal, path.Name(), str) || - (bQueryGlobal && TryGetValue(m_keyGlobal, path.Name(), str)) ) { - return TRUE; + if ( (m_keyLocal.Exists() && TryGetValue(LocalKey(), path.Name(), *pStr)) || + (bQueryGlobal && TryGetValue(m_keyGlobal, path.Name(), *pStr)) ) { + return true; } - // default value - str = szDefault; - return FALSE; + return false; } -bool wxRegConfig::Read(long &lValue, const char *szKey, long lDefault) const +// this exactly reproduces the string version above except for ExpandEnvVars(), +// we really should avoid this code duplication somehow... + +bool wxRegConfig::DoReadLong(const wxString& key, long *plResult) const { - PathChanger path(this, szKey); + wxCHECK_MSG( plResult, false, _T("wxRegConfig::Read(): NULL param") ); + + wxConfigPathChanger path(this, key); - bool bQueryGlobal = TRUE; + bool bQueryGlobal = true; // if immutable key exists in global key we must check that it's not // overriden by the local key with the same name if ( IsImmutable(path.Name()) ) { - if ( TryGetValue(m_keyGlobal, path.Name(), &lValue) ) { - if ( m_keyLocal.HasValue(path.Name()) ) { - wxLogWarning("User value for immutable key '%s' ignored.", + if ( TryGetValue(m_keyGlobal, path.Name(), plResult) ) { + if ( m_keyLocal.Exists() && LocalKey().HasValue(path.Name()) ) { + wxLogWarning(wxT("User value for immutable key '%s' ignored."), path.Name().c_str()); } - return TRUE; + return true; + } + else { + // don't waste time - it's not there anyhow + bQueryGlobal = false; + } + } + + // first try local key + if ( (m_keyLocal.Exists() && TryGetValue(LocalKey(), path.Name(), plResult)) || + (bQueryGlobal && TryGetValue(m_keyGlobal, path.Name(), plResult)) ) { + return true; + } + + return false; +} + +bool wxRegConfig::DoReadBinary(const wxString& key, wxMemoryBuffer *buf) const +{ + wxCHECK_MSG( buf, false, _T("wxRegConfig::Read(): NULL param") ); + + wxConfigPathChanger path(this, key); + + bool bQueryGlobal = true; + + // if immutable key exists in global key we must check that it's not + // overriden by the local key with the same name + if ( IsImmutable(path.Name()) ) { + if ( TryGetValue(m_keyGlobal, path.Name(), *buf) ) { + if ( m_keyLocal.Exists() && LocalKey().HasValue(path.Name()) ) { + wxLogWarning(wxT("User value for immutable key '%s' ignored."), + path.Name().c_str()); + } + + return true; } else { // don't waste time - it's not there anyhow - bQueryGlobal = FALSE; + bQueryGlobal = false; } } // first try local key - if ( TryGetValue(m_keyLocal, path.Name(), &lValue) || - (bQueryGlobal && TryGetValue(m_keyGlobal, path.Name(), &lValue)) ) { - return TRUE; + if ( (m_keyLocal.Exists() && TryGetValue(LocalKey(), path.Name(), *buf)) || + (bQueryGlobal && TryGetValue(m_keyGlobal, path.Name(), *buf)) ) { + return true; } - // default - lValue = lDefault; - return FALSE; + return false; } -bool wxRegConfig::Write(const char *szKey, const char *szValue) +bool wxRegConfig::DoWriteString(const wxString& key, const wxString& szValue) { - PathChanger path(this, szKey); + wxConfigPathChanger path(this, key); if ( IsImmutable(path.Name()) ) { - wxLogError("Can't change immutable entry '%s'.", path.Name().c_str()); - return FALSE; + wxLogError(wxT("Can't change immutable entry '%s'."), path.Name().c_str()); + return false; } - return m_keyLocal.SetValue(path.Name(), szValue); + return LocalKey().SetValue(path.Name(), szValue); } -bool wxRegConfig::Write(const char *szKey, long lValue) +bool wxRegConfig::DoWriteLong(const wxString& key, long lValue) { - PathChanger path(this, szKey); + wxConfigPathChanger path(this, key); if ( IsImmutable(path.Name()) ) { - wxLogError("Can't change immutable entry '%s'.", path.Name().c_str()); - return FALSE; + wxLogError(wxT("Can't change immutable entry '%s'."), path.Name().c_str()); + return false; } - return m_keyLocal.SetValue(path.Name(), lValue); + return LocalKey().SetValue(path.Name(), lValue); +} + +bool wxRegConfig::DoWriteBinary(const wxString& key, const wxMemoryBuffer& buf) +{ + wxConfigPathChanger path(this, key); + + if ( IsImmutable(path.Name()) ) { + wxLogError(wxT("Can't change immutable entry '%s'."), path.Name().c_str()); + return false; + } + + return LocalKey().SetValue(path.Name(), buf); +} + +// ---------------------------------------------------------------------------- +// renaming +// ---------------------------------------------------------------------------- + +bool wxRegConfig::RenameEntry(const wxString& oldName, const wxString& newName) +{ + // check that the old entry exists... + if ( !HasEntry(oldName) ) + return false; + + // and that the new one doesn't + if ( HasEntry(newName) ) + return false; + + return m_keyLocal.RenameValue(oldName, newName); +} + +bool wxRegConfig::RenameGroup(const wxString& oldName, const wxString& newName) +{ + // check that the old group exists... + if ( !HasGroup(oldName) ) + return false; + + // and that the new one doesn't + if ( HasGroup(newName) ) + return false; + + return wxRegKey(m_keyLocal, oldName).Rename(newName); } // ---------------------------------------------------------------------------- // deleting // ---------------------------------------------------------------------------- -bool wxRegConfig::DeleteEntry(const char *szValue, bool bGroupIfEmptyAlso) + +bool wxRegConfig::DeleteEntry(const wxString& value, bool bGroupIfEmptyAlso) { - PathChanger path(this, szValue); + wxConfigPathChanger path(this, value); - if ( !m_keyLocal.DeleteValue(path.Name()) ) - return FALSE; + if ( m_keyLocal.Exists() ) { + if ( !m_keyLocal.DeleteValue(path.Name()) ) + return false; - if ( !m_keyLocal.HasSubkeys() ) { - wxString strKey = GetPath().Right(APPCONF_PATH_SEPARATOR); - SetPath(".."); // changes m_keyLocal - return m_keyLocal.DeleteKey(strKey); + if ( bGroupIfEmptyAlso && m_keyLocal.IsEmpty() ) { + wxString strKey = GetPath().AfterLast(wxCONFIG_PATH_SEPARATOR); + SetPath(_T("..")); // changes m_keyLocal + return LocalKey().DeleteKey(strKey); + } } - return TRUE; + return true; } -bool wxRegConfig::DeleteGroup(const char *szKey) +bool wxRegConfig::DeleteGroup(const wxString& key) { - PathChanger path(this, szKey); + wxConfigPathChanger path(this, RemoveTrailingSeparator(key)); + + if ( !m_keyLocal.Exists() ) + { + // nothing to do + return true; + } + + if ( !LocalKey().DeleteKey(path.Name()) ) + return false; - return m_keyLocal.DeleteKey(path.Name()); + path.UpdateIfDeleted(); + + return true; } bool wxRegConfig::DeleteAll() @@ -376,8 +771,13 @@ bool wxRegConfig::DeleteAll() m_keyGlobal.Close(); bool bOk = m_keyLocalRoot.DeleteSelf(); - if ( bOk ) + + // make sure that we opened m_keyGlobalRoot and so it has a reasonable name: + // otherwise we will delete HKEY_CLASSES_ROOT recursively + if ( bOk && m_keyGlobalRoot.IsOpened() ) bOk = m_keyGlobalRoot.DeleteSelf(); return bOk; } + +#endif // wxUSE_CONFIG