1 ///////////////////////////////////////////////////////////////////////////////
2 // Name:        src/msw/regconf.cpp
3 // Purpose:
4 // Author:      Vadim Zeitlin
5 // Modified by:
6 // Created:     27.04.98
7 // Copyright:   (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
8 // Licence:     wxWindows licence
9 ///////////////////////////////////////////////////////////////////////////////
10 
11 // For compilers that support precompilation, includes "wx.h".
12 #include "wx/wxprec.h"
13 
14 #ifdef __BORLANDC__
15     #pragma hdrstop
16 #endif
17 
18 #if wxUSE_CONFIG && wxUSE_REGKEY
19 
20 #include "wx/config.h"
21 
22 #ifndef WX_PRECOMP
23     #include  "wx/string.h"
24     #include  "wx/intl.h"
25     #include "wx/log.h"
26     #include "wx/event.h"
27     #include "wx/app.h"
28 #endif //WX_PRECOMP
29 
30 #include "wx/msw/registry.h"
31 #include "wx/msw/regconf.h"
32 
33 // ----------------------------------------------------------------------------
34 // constants
35 // ----------------------------------------------------------------------------
36 
37 // we put our data in HKLM\SOFTWARE_KEY\appname
38 #define SOFTWARE_KEY    wxString(wxT("Software\\"))
39 
40 // ----------------------------------------------------------------------------
41 // global functions
42 // ----------------------------------------------------------------------------
43 
44 // get the value if the key is opened and it exists
TryGetValue(const wxRegKey & key,const wxString & str,wxString & strVal)45 bool TryGetValue(const wxRegKey& key, const wxString& str, wxString& strVal)
46 {
47   return key.IsOpened() && key.HasValue(str) && key.QueryValue(str, strVal);
48 }
49 
TryGetValue(const wxRegKey & key,const wxString & str,long * plVal)50 bool TryGetValue(const wxRegKey& key, const wxString& str, long *plVal)
51 {
52   return key.IsOpened() && key.HasValue(str) && key.QueryValue(str, plVal);
53 }
54 
TryGetValue(const wxRegKey & key,const wxString & str,wxMemoryBuffer & plVal)55 bool TryGetValue(const wxRegKey& key, const wxString& str, wxMemoryBuffer &plVal)
56 {
57   return key.IsOpened() && key.HasValue(str) && key.QueryValue(str, plVal);
58 }
59 
60 // ============================================================================
61 // implementation
62 // ============================================================================
63 
64 // ----------------------------------------------------------------------------
65 // ctor/dtor
66 // ----------------------------------------------------------------------------
IMPLEMENT_ABSTRACT_CLASS(wxRegConfig,wxConfigBase)67 IMPLEMENT_ABSTRACT_CLASS(wxRegConfig, wxConfigBase)
68 
69 // create the config object which stores its data under HKCU\vendor\app and, if
70 // style & wxCONFIG_USE_GLOBAL_FILE, under HKLM\vendor\app
71 wxRegConfig::wxRegConfig(const wxString& appName, const wxString& vendorName,
72                          const wxString& strLocal, const wxString& strGlobal,
73                          long style)
74            : wxConfigBase(appName, vendorName, strLocal, strGlobal, style)
75 {
76   wxString strRoot;
77 
78   bool bDoUseGlobal = (style & wxCONFIG_USE_GLOBAL_FILE) != 0;
79 
80   // the convention is to put the programs keys under <vendor>\<appname>
81   // (but it can be overridden by specifying the paths explicitly in strLocal
82   // and/or strGlobal)
83   if ( strLocal.empty() || (strGlobal.empty() && bDoUseGlobal) )
84   {
85     if ( vendorName.empty() )
86     {
87       if ( wxTheApp )
88         strRoot = wxTheApp->GetVendorName();
89     }
90     else
91     {
92       strRoot = vendorName;
93     }
94 
95     // no '\\' needed if no vendor name
96     if ( !strRoot.empty() )
97     {
98       strRoot += '\\';
99     }
100 
101     if ( appName.empty() )
102     {
103       wxCHECK_RET( wxTheApp, wxT("No application name in wxRegConfig ctor!") );
104       strRoot << wxTheApp->GetAppName();
105     }
106     else
107     {
108       strRoot << appName;
109     }
110   }
111   //else: we don't need to do all the complicated stuff above
112 
113   wxString str = strLocal.empty() ? strRoot : strLocal;
114 
115   // as we're going to change the name of these keys fairly often and as
116   // there are only few of wxRegConfig objects (usually 1), we can allow
117   // ourselves to be generous and spend some memory to significantly improve
118   // performance of SetPath()
119   static const size_t MEMORY_PREALLOC = 512;
120 
121   m_keyLocalRoot.ReserveMemoryForName(MEMORY_PREALLOC);
122   m_keyLocal.ReserveMemoryForName(MEMORY_PREALLOC);
123 
124   m_keyLocalRoot.SetName(wxRegKey::HKCU, SOFTWARE_KEY + str);
125   m_keyLocal.SetName(m_keyLocalRoot, wxEmptyString);
126 
127   if ( bDoUseGlobal )
128   {
129     str = strGlobal.empty() ? strRoot : strGlobal;
130 
131     m_keyGlobalRoot.ReserveMemoryForName(MEMORY_PREALLOC);
132     m_keyGlobal.ReserveMemoryForName(MEMORY_PREALLOC);
133 
134     m_keyGlobalRoot.SetName(wxRegKey::HKLM, SOFTWARE_KEY + str);
135     m_keyGlobal.SetName(m_keyGlobalRoot, wxEmptyString);
136   }
137 
138   // Create() will Open() if key already exists
139   m_keyLocalRoot.Create();
140 
141   // as it's the same key, Open() shouldn't fail (i.e. no need for Create())
142   m_keyLocal.Open();
143 
144   // OTOH, this key may perfectly not exist, so suppress error messages the call
145   // to Open() might generate
146   if ( bDoUseGlobal )
147   {
148     wxLogNull nolog;
149     m_keyGlobalRoot.Open(wxRegKey::Read);
150     m_keyGlobal.Open(wxRegKey::Read);
151   }
152 }
153 
154 // ----------------------------------------------------------------------------
155 // path management
156 // ----------------------------------------------------------------------------
157 
158 // this function is called a *lot* of times (as I learned after seeing from
159 // profiler output that it is called ~12000 times from Mahogany start up code!)
160 // so it is important to optimize it - in particular, avoid using generic
161 // string functions here and do everything manually because it is faster
162 //
163 // I still kept the old version to be able to check that the optimized code has
164 // the same output as the non optimized version.
SetPath(const wxString & strPath)165 void wxRegConfig::SetPath(const wxString& strPath)
166 {
167     // remember the old path
168     wxString strOldPath = m_strPath;
169 
170 #ifdef WX_DEBUG_SET_PATH // non optimized version kept here for testing
171     wxString m_strPathAlt;
172 
173     {
174         wxArrayString aParts;
175 
176         // because GetPath() returns "" when we're at root, we must understand
177         // empty string as "/"
178         if ( strPath.empty() || (strPath[0] == wxCONFIG_PATH_SEPARATOR) ) {
179             // absolute path
180             wxSplitPath(aParts, strPath);
181         }
182         else {
183             // relative path, combine with current one
184             wxString strFullPath = GetPath();
185             strFullPath << wxCONFIG_PATH_SEPARATOR << strPath;
186             wxSplitPath(aParts, strFullPath);
187         }
188 
189         // recombine path parts in one variable
190         wxString strRegPath;
191         m_strPathAlt.Empty();
192         for ( size_t n = 0; n < aParts.Count(); n++ ) {
193             strRegPath << '\\' << aParts[n];
194             m_strPathAlt << wxCONFIG_PATH_SEPARATOR << aParts[n];
195         }
196     }
197 #endif // 0
198 
199     // check for the most common case first
200     if ( strPath.empty() )
201     {
202         m_strPath = wxCONFIG_PATH_SEPARATOR;
203     }
204     else // not root
205     {
206         // construct the full path
207         wxString strFullPath;
208         if ( strPath[0u] == wxCONFIG_PATH_SEPARATOR )
209         {
210             // absolute path
211             strFullPath = strPath;
212         }
213         else // relative path
214         {
215             strFullPath.reserve(2*m_strPath.length());
216 
217             strFullPath << m_strPath;
218             if ( strFullPath.Len() == 0 ||
219                  strFullPath.Last() != wxCONFIG_PATH_SEPARATOR )
220                 strFullPath << wxCONFIG_PATH_SEPARATOR;
221             strFullPath << strPath;
222         }
223 
224         // simplify it: we need to handle ".." here
225 
226         // count the total number of slashes we have to know if we can go upper
227         size_t totalSlashes = 0;
228 
229         // position of the last slash to be able to backtrack to it quickly if
230         // needed, but we set it to -1 if we don't have a valid position
231         //
232         // we only remember the last position which means that we handle ".."
233         // quite efficiently but not "../.." - however the latter should be
234         // much more rare, so it is probably ok
235         int posLastSlash = -1;
236 
237         const wxChar *src = strFullPath.c_str();
238         size_t len = strFullPath.length();
239         const wxChar *end = src + len;
240 
241         wxStringBufferLength buf(m_strPath, len);
242         wxChar *dst = buf;
243         wxChar *start = dst;
244 
245         for ( ; src < end; src++, dst++ )
246         {
247             if ( *src == wxCONFIG_PATH_SEPARATOR )
248             {
249                 // check for "/.."
250 
251                 // note that we don't have to check for src < end here as
252                 // *end == 0 so can't be '.'
253                 if ( src[1] == wxT('.') && src[2] == wxT('.') &&
254                      (src + 3 == end || src[3] == wxCONFIG_PATH_SEPARATOR) )
255                 {
256                     if ( !totalSlashes )
257                     {
258                         wxLogWarning(_("'%s' has extra '..', ignored."),
259                                      strFullPath.c_str());
260                     }
261                     else // return to the previous path component
262                     {
263                         // do we already have its position?
264                         if ( posLastSlash == -1 )
265                         {
266                             // no, find it: note that we are sure to have one
267                             // because totalSlashes > 0 so we don't have to
268                             // check the boundary condition below
269 
270                             // this is more efficient than strrchr()
271                             dst--;
272                             while ( *dst != wxCONFIG_PATH_SEPARATOR )
273                             {
274                                 dst--;
275                             }
276                         }
277                         else // the position of last slash was stored
278                         {
279                             // go directly there
280                             dst = start + posLastSlash;
281 
282                             // invalidate posLastSlash
283                             posLastSlash = -1;
284                         }
285 
286                         // we must have found a slash one way or another!
287                         wxASSERT_MSG( *dst == wxCONFIG_PATH_SEPARATOR,
288                                       wxT("error in wxRegConfig::SetPath") );
289 
290                         // stay at the same position
291                         dst--;
292 
293                         // we killed one
294                         totalSlashes--;
295                     }
296 
297                     // skip both dots
298                     src += 2;
299                 }
300                 else // not "/.."
301                 {
302                     if ( (dst == start) || (dst[-1] != wxCONFIG_PATH_SEPARATOR) )
303                     {
304                         *dst = wxCONFIG_PATH_SEPARATOR;
305 
306                         posLastSlash = dst - start;
307 
308                         totalSlashes++;
309                     }
310                     else // previous char was a slash too
311                     {
312                         // squeeze several subsequent slashes into one: i.e.
313                         // just ignore this one
314                         dst--;
315                     }
316                 }
317             }
318             else // normal character
319             {
320                 // just copy
321                 *dst = *src;
322             }
323         }
324 
325         // NUL terminate the string
326         if ( dst[-1] == wxCONFIG_PATH_SEPARATOR && (dst != start + 1) )
327         {
328             // if it has a trailing slash we remove it unless it is the only
329             // string character
330             dst--;
331         }
332 
333         *dst = wxT('\0');
334         buf.SetLength(dst - start);
335     }
336 
337 #ifdef WX_DEBUG_SET_PATH
338     wxASSERT( m_strPath == m_strPathAlt );
339 #endif
340 
341     if ( m_strPath == strOldPath )
342         return;
343 
344     // registry APIs want backslashes instead of slashes
345     wxString strRegPath;
346     if ( !m_strPath.empty() )
347     {
348         size_t len = m_strPath.length();
349 
350         const wxChar *src = m_strPath.c_str();
351         wxStringBufferLength buf(strRegPath, len);
352         wxChar *dst = buf;
353 
354         const wxChar *end = src + len;
355         for ( ; src < end; src++, dst++ )
356         {
357             if ( *src == wxCONFIG_PATH_SEPARATOR )
358                 *dst = wxT('\\');
359             else
360                 *dst = *src;
361         }
362 
363         buf.SetLength(len);
364     }
365 
366     // this is not needed any longer as we don't create keys unnecessarily any
367     // more (now it is done on demand, i.e. only when they're going to contain
368     // something)
369 #if 0
370     // as we create the registry key when SetPath(key) is done, we can be left
371     // with plenty of empty keys if this was only done to try to read some
372     // value which, in fact, doesn't exist - to prevent this from happening we
373     // automatically delete the old key if it was empty
374     if ( m_keyLocal.Exists() && LocalKey().IsEmpty() )
375     {
376         m_keyLocal.DeleteSelf();
377     }
378 #endif // 0
379 
380     // change current key(s)
381     m_keyLocal.SetName(m_keyLocalRoot, strRegPath);
382 
383     if ( GetStyle() & wxCONFIG_USE_GLOBAL_FILE )
384     {
385       m_keyGlobal.SetName(m_keyGlobalRoot, strRegPath);
386 
387       wxLogNull nolog;
388       m_keyGlobal.Open(wxRegKey::Read);
389     }
390 }
391 
392 // ----------------------------------------------------------------------------
393 // enumeration (works only with current group)
394 // ----------------------------------------------------------------------------
395 
396 /*
397   We want to enumerate all local keys/values after the global ones, but, of
398   course, we don't want to repeat a key which appears locally as well as
399   globally twice.
400 
401   We use the 15th bit of lIndex for distinction between global and local.
402  */
403 
404 #define LOCAL_MASK        0x8000
405 #define IS_LOCAL_INDEX(l) (((l) & LOCAL_MASK) != 0)
406 
GetFirstGroup(wxString & str,long & lIndex) const407 bool wxRegConfig::GetFirstGroup(wxString& str, long& lIndex) const
408 {
409   lIndex = 0;
410   return GetNextGroup(str, lIndex);
411 }
412 
GetNextGroup(wxString & str,long & lIndex) const413 bool wxRegConfig::GetNextGroup(wxString& str, long& lIndex) const
414 {
415   // are we already enumerating local entries?
416   if ( m_keyGlobal.IsOpened() && !IS_LOCAL_INDEX(lIndex) ) {
417     // try to find a global entry which doesn't appear locally
418     while ( m_keyGlobal.GetNextKey(str, lIndex) ) {
419       if ( !m_keyLocal.Exists() || !LocalKey().HasSubKey(str) ) {
420         // ok, found one - return it
421         return true;
422       }
423     }
424 
425     // no more global entries
426     lIndex |= LOCAL_MASK;
427   }
428 
429   // if we don't have the key at all, don't try to enumerate anything under it
430   if ( !m_keyLocal.Exists() )
431       return false;
432 
433   // much easier with local entries: get the next one we find
434   // (don't forget to clear our flag bit and set it again later)
435   lIndex &= ~LOCAL_MASK;
436   bool bOk = LocalKey().GetNextKey(str, lIndex);
437   lIndex |= LOCAL_MASK;
438 
439   return bOk;
440 }
441 
GetFirstEntry(wxString & str,long & lIndex) const442 bool wxRegConfig::GetFirstEntry(wxString& str, long& lIndex) const
443 {
444   lIndex = 0;
445   return GetNextEntry(str, lIndex);
446 }
447 
GetNextEntry(wxString & str,long & lIndex) const448 bool wxRegConfig::GetNextEntry(wxString& str, long& lIndex) const
449 {
450   // are we already enumerating local entries?
451   if ( m_keyGlobal.IsOpened() && !IS_LOCAL_INDEX(lIndex) ) {
452     // try to find a global entry which doesn't appear locally
453     while ( m_keyGlobal.GetNextValue(str, lIndex) ) {
454       if ( !m_keyLocal.Exists() || !LocalKey().HasValue(str) ) {
455         // ok, found one - return it
456         return true;
457       }
458     }
459 
460     // no more global entries
461     lIndex |= LOCAL_MASK;
462   }
463 
464   // if we don't have the key at all, don't try to enumerate anything under it
465   if ( !m_keyLocal.Exists() )
466       return false;
467 
468   // much easier with local entries: get the next one we find
469   // (don't forget to clear our flag bit and set it again later)
470   lIndex &= ~LOCAL_MASK;
471   bool bOk = LocalKey().GetNextValue(str, lIndex);
472   lIndex |= LOCAL_MASK;
473 
474   return bOk;
475 }
476 
GetNumberOfEntries(bool WXUNUSED (bRecursive)) const477 size_t wxRegConfig::GetNumberOfEntries(bool WXUNUSED(bRecursive)) const
478 {
479   size_t nEntries = 0;
480 
481   // dummy vars
482   wxString str;
483   long l;
484   bool bCont = ((wxRegConfig*)this)->GetFirstEntry(str, l);
485   while ( bCont ) {
486     nEntries++;
487 
488     bCont = ((wxRegConfig*)this)->GetNextEntry(str, l);
489   }
490 
491   return nEntries;
492 }
493 
GetNumberOfGroups(bool WXUNUSED (bRecursive)) const494 size_t wxRegConfig::GetNumberOfGroups(bool WXUNUSED(bRecursive)) const
495 {
496   size_t nGroups = 0;
497 
498   // dummy vars
499   wxString str;
500   long l;
501   bool bCont = ((wxRegConfig*)this)->GetFirstGroup(str, l);
502   while ( bCont ) {
503     nGroups++;
504 
505     bCont = ((wxRegConfig*)this)->GetNextGroup(str, l);
506   }
507 
508   return nGroups;
509 }
510 
511 // ----------------------------------------------------------------------------
512 // tests for existence
513 // ----------------------------------------------------------------------------
514 
HasGroup(const wxString & key) const515 bool wxRegConfig::HasGroup(const wxString& key) const
516 {
517     wxConfigPathChanger path(this, key);
518 
519     wxString strName(path.Name());
520 
521     return (m_keyLocal.Exists() && LocalKey().HasSubKey(strName)) ||
522            m_keyGlobal.HasSubKey(strName);
523 }
524 
HasEntry(const wxString & key) const525 bool wxRegConfig::HasEntry(const wxString& key) const
526 {
527     wxConfigPathChanger path(this, key);
528 
529     wxString strName(path.Name());
530 
531     return (m_keyLocal.Exists() && LocalKey().HasValue(strName)) ||
532            m_keyGlobal.HasValue(strName);
533 }
534 
GetEntryType(const wxString & key) const535 wxConfigBase::EntryType wxRegConfig::GetEntryType(const wxString& key) const
536 {
537     wxConfigPathChanger path(this, key);
538 
539     wxString strName(path.Name());
540 
541     bool isNumeric;
542     if ( m_keyLocal.Exists() && LocalKey().HasValue(strName) )
543         isNumeric = m_keyLocal.IsNumericValue(strName);
544     else if ( m_keyGlobal.HasValue(strName) )
545         isNumeric = m_keyGlobal.IsNumericValue(strName);
546     else
547         return wxConfigBase::Type_Unknown;
548 
549     return isNumeric ? wxConfigBase::Type_Integer : wxConfigBase::Type_String;
550 }
551 
552 // ----------------------------------------------------------------------------
553 // reading/writing
554 // ----------------------------------------------------------------------------
555 
DoReadString(const wxString & key,wxString * pStr) const556 bool wxRegConfig::DoReadString(const wxString& key, wxString *pStr) const
557 {
558     wxCHECK_MSG( pStr, false, wxT("wxRegConfig::Read(): NULL param") );
559 
560   wxConfigPathChanger path(this, key);
561 
562   bool bQueryGlobal = true;
563 
564   // if immutable key exists in global key we must check that it's not
565   // overridden by the local key with the same name
566   if ( IsImmutable(path.Name()) ) {
567     if ( TryGetValue(m_keyGlobal, path.Name(), *pStr) ) {
568       if ( m_keyLocal.Exists() && LocalKey().HasValue(path.Name()) ) {
569         wxLogWarning(wxT("User value for immutable key '%s' ignored."),
570                    path.Name().c_str());
571       }
572 
573       return true;
574     }
575     else {
576       // don't waste time - it's not there anyhow
577       bQueryGlobal = false;
578     }
579   }
580 
581   // first try local key
582   if ( (m_keyLocal.Exists() && TryGetValue(LocalKey(), path.Name(), *pStr)) ||
583        (bQueryGlobal && TryGetValue(m_keyGlobal, path.Name(), *pStr)) ) {
584     return true;
585   }
586 
587   return false;
588 }
589 
590 // this exactly reproduces the string version above except for ExpandEnvVars(),
591 // we really should avoid this code duplication somehow...
592 
DoReadLong(const wxString & key,long * plResult) const593 bool wxRegConfig::DoReadLong(const wxString& key, long *plResult) const
594 {
595     wxCHECK_MSG( plResult, false, wxT("wxRegConfig::Read(): NULL param") );
596 
597   wxConfigPathChanger path(this, key);
598 
599   bool bQueryGlobal = true;
600 
601   // if immutable key exists in global key we must check that it's not
602   // overridden by the local key with the same name
603   if ( IsImmutable(path.Name()) ) {
604     if ( TryGetValue(m_keyGlobal, path.Name(), plResult) ) {
605       if ( m_keyLocal.Exists() && LocalKey().HasValue(path.Name()) ) {
606         wxLogWarning(wxT("User value for immutable key '%s' ignored."),
607                      path.Name().c_str());
608       }
609 
610       return true;
611     }
612     else {
613       // don't waste time - it's not there anyhow
614       bQueryGlobal = false;
615     }
616   }
617 
618   // first try local key
619   if ( (m_keyLocal.Exists() && TryGetValue(LocalKey(), path.Name(), plResult)) ||
620        (bQueryGlobal && TryGetValue(m_keyGlobal, path.Name(), plResult)) ) {
621     return true;
622   }
623 
624   return false;
625 }
626 
DoReadBinary(const wxString & key,wxMemoryBuffer * buf) const627 bool wxRegConfig::DoReadBinary(const wxString& key, wxMemoryBuffer *buf) const
628 {
629     wxCHECK_MSG( buf, false, wxT("wxRegConfig::Read(): NULL param") );
630 
631   wxConfigPathChanger path(this, key);
632 
633   bool bQueryGlobal = true;
634 
635   // if immutable key exists in global key we must check that it's not
636   // overridden by the local key with the same name
637   if ( IsImmutable(path.Name()) ) {
638     if ( TryGetValue(m_keyGlobal, path.Name(), *buf) ) {
639       if ( m_keyLocal.Exists() && LocalKey().HasValue(path.Name()) ) {
640         wxLogWarning(wxT("User value for immutable key '%s' ignored."),
641                    path.Name().c_str());
642       }
643 
644       return true;
645     }
646     else {
647       // don't waste time - it's not there anyhow
648       bQueryGlobal = false;
649     }
650   }
651 
652   // first try local key
653   if ( (m_keyLocal.Exists() && TryGetValue(LocalKey(), path.Name(), *buf)) ||
654        (bQueryGlobal && TryGetValue(m_keyGlobal, path.Name(), *buf)) ) {
655     return true;
656   }
657 
658   return false;
659 }
660 
DoWriteString(const wxString & key,const wxString & szValue)661 bool wxRegConfig::DoWriteString(const wxString& key, const wxString& szValue)
662 {
663   wxConfigPathChanger path(this, key);
664 
665   if ( IsImmutable(path.Name()) ) {
666     wxLogError(wxT("Can't change immutable entry '%s'."), path.Name().c_str());
667     return false;
668   }
669 
670   return LocalKey().SetValue(path.Name(), szValue);
671 }
672 
DoWriteLong(const wxString & key,long lValue)673 bool wxRegConfig::DoWriteLong(const wxString& key, long lValue)
674 {
675   wxConfigPathChanger path(this, key);
676 
677   if ( IsImmutable(path.Name()) ) {
678     wxLogError(wxT("Can't change immutable entry '%s'."), path.Name().c_str());
679     return false;
680   }
681 
682   return LocalKey().SetValue(path.Name(), lValue);
683 }
684 
DoWriteBinary(const wxString & key,const wxMemoryBuffer & buf)685 bool wxRegConfig::DoWriteBinary(const wxString& key, const wxMemoryBuffer& buf)
686 {
687   wxConfigPathChanger path(this, key);
688 
689   if ( IsImmutable(path.Name()) ) {
690     wxLogError(wxT("Can't change immutable entry '%s'."), path.Name().c_str());
691     return false;
692   }
693 
694   return LocalKey().SetValue(path.Name(), buf);
695 }
696 
697 // ----------------------------------------------------------------------------
698 // renaming
699 // ----------------------------------------------------------------------------
700 
RenameEntry(const wxString & oldName,const wxString & newName)701 bool wxRegConfig::RenameEntry(const wxString& oldName, const wxString& newName)
702 {
703     // check that the old entry exists...
704     if ( !HasEntry(oldName) )
705         return false;
706 
707     // and that the new one doesn't
708     if ( HasEntry(newName) )
709         return false;
710 
711     return m_keyLocal.RenameValue(oldName, newName);
712 }
713 
RenameGroup(const wxString & oldName,const wxString & newName)714 bool wxRegConfig::RenameGroup(const wxString& oldName, const wxString& newName)
715 {
716     // check that the old group exists...
717     if ( !HasGroup(oldName) )
718         return false;
719 
720     // and that the new one doesn't
721     if ( HasGroup(newName) )
722         return false;
723 
724     return wxRegKey(m_keyLocal, oldName).Rename(newName);
725 }
726 
727 // ----------------------------------------------------------------------------
728 // deleting
729 // ----------------------------------------------------------------------------
730 
DeleteEntry(const wxString & value,bool bGroupIfEmptyAlso)731 bool wxRegConfig::DeleteEntry(const wxString& value, bool bGroupIfEmptyAlso)
732 {
733   wxConfigPathChanger path(this, value);
734 
735   if ( m_keyLocal.Exists() ) {
736     if ( !m_keyLocal.DeleteValue(path.Name()) )
737       return false;
738 
739     if ( bGroupIfEmptyAlso && m_keyLocal.IsEmpty() ) {
740       wxString strKey = GetPath().AfterLast(wxCONFIG_PATH_SEPARATOR);
741       SetPath(wxT(".."));  // changes m_keyLocal
742       return LocalKey().DeleteKey(strKey);
743     }
744   }
745 
746   return true;
747 }
748 
DeleteGroup(const wxString & key)749 bool wxRegConfig::DeleteGroup(const wxString& key)
750 {
751   wxConfigPathChanger path(this, RemoveTrailingSeparator(key));
752 
753   if ( !m_keyLocal.Exists() )
754   {
755       // nothing to do
756       return true;
757   }
758 
759   if ( !LocalKey().DeleteKey(path.Name()) )
760       return false;
761 
762   path.UpdateIfDeleted();
763 
764   return true;
765 }
766 
DeleteAll()767 bool wxRegConfig::DeleteAll()
768 {
769   m_keyLocal.Close();
770   m_keyGlobal.Close();
771 
772   bool bOk = m_keyLocalRoot.DeleteSelf();
773 
774   // make sure that we opened m_keyGlobalRoot and so it has a reasonable name:
775   // otherwise we will delete HKEY_CLASSES_ROOT recursively
776   if ( bOk && m_keyGlobalRoot.IsOpened() )
777     bOk = m_keyGlobalRoot.DeleteSelf();
778 
779   return bOk;
780 }
781 
782 #endif // wxUSE_CONFIG && wxUSE_REGKEY
783