]> git.saurik.com Git - wxWidgets.git/blame - src/msw/regconf.cpp
The octal escaping code needs to escape the escape character
[wxWidgets.git] / src / msw / regconf.cpp
CommitLineData
19454fa0
VZ
1///////////////////////////////////////////////////////////////////////////////
2// Name: msw/regconf.cpp
6d833566 3// Purpose:
19454fa0 4// Author: Vadim Zeitlin
6d833566 5// Modified by:
19454fa0
VZ
6// Created: 27.04.98
7// RCS-ID: $Id$
8// Copyright: (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
65571936 9// Licence: wxWindows licence
19454fa0
VZ
10///////////////////////////////////////////////////////////////////////////////
11
14f355c2 12#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
cfe780fb
JS
13#pragma implementation "regconf.h"
14#endif
15
a3b46648
UU
16// For compilers that support precompilation, includes "wx.h".
17#include "wx/wxprec.h"
19454fa0 18
a3b46648
UU
19#ifdef __BORLANDC__
20#pragma hdrstop
82cf4761
VZ
21#endif
22
82cf4761 23#ifndef WX_PRECOMP
61ba49f2 24 #include "wx/string.h"
1f3943e0 25 #include "wx/intl.h"
82cf4761
VZ
26#endif //WX_PRECOMP
27
61ba49f2
VZ
28#include "wx/event.h"
29#include "wx/app.h"
30#include "wx/log.h"
f6bcfd97
BP
31
32#if wxUSE_CONFIG
33
61ba49f2 34#include "wx/config.h"
3d05544e 35
61ba49f2
VZ
36#include "wx/msw/registry.h"
37#include "wx/msw/regconf.h"
19454fa0
VZ
38
39// ----------------------------------------------------------------------------
40// constants
41// ----------------------------------------------------------------------------
42
43// we put our data in HKLM\SOFTWARE_KEY\appname
2b5f62a0 44#define SOFTWARE_KEY wxString(wxT("Software\\"))
19454fa0
VZ
45
46// ----------------------------------------------------------------------------
47// global functions
48// ----------------------------------------------------------------------------
49
50// get the value if the key is opened and it exists
51bool TryGetValue(const wxRegKey& key, const wxString& str, wxString& strVal)
52{
53 return key.IsOpened() && key.HasValue(str) && key.QueryValue(str, strVal);
54}
55
56bool TryGetValue(const wxRegKey& key, const wxString& str, long *plVal)
57{
58 return key.IsOpened() && key.HasValue(str) && key.QueryValue(str, plVal);
59}
60
61// ============================================================================
62// implementation
63// ============================================================================
64
65// ----------------------------------------------------------------------------
66// ctor/dtor
67// ----------------------------------------------------------------------------
18244936 68
040f0110
VZ
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
71wxRegConfig::wxRegConfig(const wxString& appName, const wxString& vendorName,
72 const wxString& strLocal, const wxString& strGlobal,
73 long style)
74 : wxConfigBase(appName, vendorName, strLocal, strGlobal, style)
19454fa0 75{
040f0110 76 wxString strRoot;
19454fa0 77
040f0110 78 bool bDoUseGlobal = (style & wxCONFIG_USE_GLOBAL_FILE) != 0;
41286812 79
040f0110
VZ
80 // the convention is to put the programs keys under <vendor>\<appname>
81 // (but it can be overriden by specifying the pathes explicitly in strLocal
82 // and/or strGlobal)
83 if ( strLocal.IsEmpty() || (strGlobal.IsEmpty() && bDoUseGlobal) )
84 {
85 if ( vendorName.IsEmpty() )
86 {
87 if ( wxTheApp )
88 strRoot = wxTheApp->GetVendorName();
89 }
90 else
91 {
92 strRoot = vendorName;
93 }
18244936 94
040f0110
VZ
95 // no '\\' needed if no vendor name
96 if ( !strRoot.IsEmpty() )
18244936 97 {
040f0110 98 strRoot += '\\';
18244936 99 }
18244936 100
040f0110
VZ
101 if ( appName.IsEmpty() )
102 {
223d09f6 103 wxCHECK_RET( wxTheApp, wxT("No application name in wxRegConfig ctor!") );
040f0110
VZ
104 strRoot << wxTheApp->GetAppName();
105 }
106 else
18244936 107 {
040f0110 108 strRoot << appName;
18244936 109 }
040f0110
VZ
110 }
111 //else: we don't need to do all the complicated stuff above
18244936 112
040f0110 113 wxString str = strLocal.IsEmpty() ? strRoot : strLocal;
807a903e
VZ
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
040f0110 124 m_keyLocalRoot.SetName(wxRegKey::HKCU, SOFTWARE_KEY + str);
fda7962d 125 m_keyLocal.SetName(m_keyLocalRoot, wxEmptyString);
18244936 126
040f0110
VZ
127 if ( bDoUseGlobal )
128 {
129 str = strGlobal.IsEmpty() ? strRoot : strGlobal;
807a903e
VZ
130
131 m_keyGlobalRoot.ReserveMemoryForName(MEMORY_PREALLOC);
132 m_keyGlobal.ReserveMemoryForName(MEMORY_PREALLOC);
133
040f0110 134 m_keyGlobalRoot.SetName(wxRegKey::HKLM, SOFTWARE_KEY + str);
fda7962d 135 m_keyGlobal.SetName(m_keyGlobalRoot, wxEmptyString);
040f0110 136 }
18244936
JS
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
040f0110
VZ
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;
9a85c87d
VZ
149 m_keyGlobalRoot.Open(wxRegKey::Read);
150 m_keyGlobal.Open(wxRegKey::Read);
040f0110 151 }
18244936 152}
19454fa0 153
19454fa0
VZ
154// ----------------------------------------------------------------------------
155// path management
156// ----------------------------------------------------------------------------
807a903e
VZ
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.
19454fa0
VZ
165void wxRegConfig::SetPath(const wxString& strPath)
166{
807a903e
VZ
167 // remember the old path
168 wxString strOldPath = m_strPath;
19454fa0 169
807a903e
VZ
170#ifdef WX_DEBUG_SET_PATH // non optimized version kept here for testing
171 wxString m_strPathAlt;
19454fa0 172
807a903e
VZ
173 {
174 wxArrayString aParts;
175
176 // because GetPath() returns "" when we're at root, we must understand
177 // empty string as "/"
178 if ( strPath.IsEmpty() || (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
19454fa0 198
807a903e
VZ
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
e9c4c02c 217 strFullPath << m_strPath;
4d08943e 218 if ( strFullPath.Len() == 0 ||
e9c4c02c 219 strFullPath.Last() != wxCONFIG_PATH_SEPARATOR )
4d08943e 220 strFullPath << wxCONFIG_PATH_SEPARATOR;
e9c4c02c 221 strFullPath << strPath;
807a903e
VZ
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
de564874
MB
241 wxStringBufferLength buf(m_strPath, len);
242 wxChar *dst = buf;
807a903e
VZ
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] == _T('.') && src[2] == _T('.') &&
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()
79c3b7b2 271 dst--;
807a903e
VZ
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
79c3b7b2 286 // we must have found a slash one way or another!
807a903e
VZ
287 wxASSERT_MSG( *dst == wxCONFIG_PATH_SEPARATOR,
288 _T("error in wxRegConfig::SetPath") );
289
79c3b7b2
VZ
290 // stay at the same position
291 dst--;
292
807a903e
VZ
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 }
eaac8805
VZ
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 }
807a903e
VZ
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 = _T('\0');
de564874 334 buf.SetLength(dst - start);
807a903e 335 }
b568d04f 336
807a903e
VZ
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;
275dea46
VZ
346 if ( !m_strPath.empty() )
347 {
348 size_t len = m_strPath.length();
b568d04f 349
275dea46 350 const wxChar *src = m_strPath.c_str();
de564874
MB
351 wxStringBufferLength buf(strRegPath, len);
352 wxChar *dst = buf;
807a903e 353
275dea46
VZ
354 const wxChar *end = src + len;
355 for ( ; src < end; src++, dst++ )
356 {
357 if ( *src == wxCONFIG_PATH_SEPARATOR )
358 *dst = _T('\\');
359 else
360 *dst = *src;
361 }
807a903e 362
de564874 363 buf.SetLength(len);
275dea46 364 }
807a903e
VZ
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
19454fa0 379
807a903e
VZ
380 // change current key(s)
381 m_keyLocal.SetName(m_keyLocalRoot, strRegPath);
807a903e 382
72957aa3
VZ
383 if ( GetStyle() & wxCONFIG_USE_GLOBAL_FILE )
384 {
385 m_keyGlobal.SetName(m_keyGlobalRoot, strRegPath);
807a903e 386
72957aa3 387 wxLogNull nolog;
9a85c87d 388 m_keyGlobal.Open(wxRegKey::Read);
72957aa3 389 }
19454fa0
VZ
390}
391
392// ----------------------------------------------------------------------------
393// enumeration (works only with current group)
394// ----------------------------------------------------------------------------
395
396/*
6d833566 397 We want to enumerate all local keys/values after the global ones, but, of
19454fa0
VZ
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
02569ba8 407bool wxRegConfig::GetFirstGroup(wxString& str, long& lIndex) const
19454fa0
VZ
408{
409 lIndex = 0;
410 return GetNextGroup(str, lIndex);
411}
412
02569ba8 413bool wxRegConfig::GetNextGroup(wxString& str, long& lIndex) const
19454fa0
VZ
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
09f50eb3 418 while ( m_keyGlobal.GetNextKey(str, lIndex) ) {
807a903e 419 if ( !m_keyLocal.Exists() || !LocalKey().HasSubKey(str) ) {
09f50eb3 420 // ok, found one - return it
4d08943e 421 return true;
19454fa0 422 }
09f50eb3
VZ
423 }
424
425 // no more global entries
426 lIndex |= LOCAL_MASK;
19454fa0
VZ
427 }
428
807a903e
VZ
429 // if we don't have the key at all, don't try to enumerate anything under it
430 if ( !m_keyLocal.Exists() )
4d08943e 431 return false;
807a903e 432
19454fa0
VZ
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;
807a903e 436 bool bOk = LocalKey().GetNextKey(str, lIndex);
19454fa0
VZ
437 lIndex |= LOCAL_MASK;
438
439 return bOk;
440}
441
02569ba8 442bool wxRegConfig::GetFirstEntry(wxString& str, long& lIndex) const
19454fa0
VZ
443{
444 lIndex = 0;
82cf4761 445 return GetNextEntry(str, lIndex);
19454fa0
VZ
446}
447
02569ba8 448bool wxRegConfig::GetNextEntry(wxString& str, long& lIndex) const
19454fa0
VZ
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
50f7d0a3 453 while ( m_keyGlobal.GetNextValue(str, lIndex) ) {
807a903e 454 if ( !m_keyLocal.Exists() || !LocalKey().HasValue(str) ) {
50f7d0a3 455 // ok, found one - return it
4d08943e 456 return true;
19454fa0 457 }
50f7d0a3
VZ
458 }
459
460 // no more global entries
461 lIndex |= LOCAL_MASK;
19454fa0
VZ
462 }
463
807a903e
VZ
464 // if we don't have the key at all, don't try to enumerate anything under it
465 if ( !m_keyLocal.Exists() )
4d08943e 466 return false;
807a903e 467
19454fa0
VZ
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;
807a903e 471 bool bOk = LocalKey().GetNextValue(str, lIndex);
19454fa0
VZ
472 lIndex |= LOCAL_MASK;
473
474 return bOk;
475}
476
33ac7e6f 477size_t wxRegConfig::GetNumberOfEntries(bool WXUNUSED(bRecursive)) const
82cf4761 478{
c86f1403 479 size_t nEntries = 0;
82cf4761
VZ
480
481 // dummy vars
482 wxString str;
483 long l;
6a23cbce 484 bool bCont = ((wxRegConfig*)this)->GetFirstEntry(str, l);
82cf4761
VZ
485 while ( bCont ) {
486 nEntries++;
487
6a23cbce 488 bCont = ((wxRegConfig*)this)->GetNextEntry(str, l);
82cf4761
VZ
489 }
490
491 return nEntries;
492}
493
33ac7e6f 494size_t wxRegConfig::GetNumberOfGroups(bool WXUNUSED(bRecursive)) const
82cf4761 495{
c86f1403 496 size_t nGroups = 0;
82cf4761
VZ
497
498 // dummy vars
499 wxString str;
500 long l;
6a23cbce 501 bool bCont = ((wxRegConfig*)this)->GetFirstGroup(str, l);
82cf4761
VZ
502 while ( bCont ) {
503 nGroups++;
504
6a23cbce 505 bCont = ((wxRegConfig*)this)->GetNextGroup(str, l);
82cf4761
VZ
506 }
507
508 return nGroups;
509}
510
6d833566
VZ
511// ----------------------------------------------------------------------------
512// tests for existence
513// ----------------------------------------------------------------------------
514
61ba49f2 515bool wxRegConfig::HasGroup(const wxString& key) const
6d833566 516{
61ba49f2
VZ
517 wxConfigPathChanger path(this, key);
518
519 wxString strName(path.Name());
520
807a903e
VZ
521 return (m_keyLocal.Exists() && LocalKey().HasSubKey(strName)) ||
522 m_keyGlobal.HasSubKey(strName);
6d833566
VZ
523}
524
61ba49f2 525bool wxRegConfig::HasEntry(const wxString& key) const
6d833566 526{
61ba49f2
VZ
527 wxConfigPathChanger path(this, key);
528
529 wxString strName(path.Name());
530
807a903e
VZ
531 return (m_keyLocal.Exists() && LocalKey().HasValue(strName)) ||
532 m_keyGlobal.HasValue(strName);
61ba49f2
VZ
533}
534
535wxConfigBase::EntryType wxRegConfig::GetEntryType(const wxString& key) const
536{
537 wxConfigPathChanger path(this, key);
538
539 wxString strName(path.Name());
540
541 bool isNumeric;
807a903e 542 if ( m_keyLocal.Exists() && LocalKey().HasValue(strName) )
61ba49f2
VZ
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;
6d833566
VZ
550}
551
19454fa0
VZ
552// ----------------------------------------------------------------------------
553// reading/writing
554// ----------------------------------------------------------------------------
555
2ba41305 556bool wxRegConfig::DoReadString(const wxString& key, wxString *pStr) const
19454fa0 557{
4d08943e 558 wxCHECK_MSG( pStr, false, _T("wxRegConfig::Read(): NULL param") );
19454fa0 559
18244936
JS
560 wxConfigPathChanger path(this, key);
561
4d08943e 562 bool bQueryGlobal = true;
18244936
JS
563
564 // if immutable key exists in global key we must check that it's not
565 // overriden by the local key with the same name
566 if ( IsImmutable(path.Name()) ) {
567 if ( TryGetValue(m_keyGlobal, path.Name(), *pStr) ) {
807a903e 568 if ( m_keyLocal.Exists() && LocalKey().HasValue(path.Name()) ) {
223d09f6 569 wxLogWarning(wxT("User value for immutable key '%s' ignored."),
18244936
JS
570 path.Name().c_str());
571 }
572
4d08943e 573 return true;
18244936
JS
574 }
575 else {
576 // don't waste time - it's not there anyhow
4d08943e 577 bQueryGlobal = false;
18244936
JS
578 }
579 }
580
581 // first try local key
807a903e 582 if ( (m_keyLocal.Exists() && TryGetValue(LocalKey(), path.Name(), *pStr)) ||
18244936 583 (bQueryGlobal && TryGetValue(m_keyGlobal, path.Name(), *pStr)) ) {
4d08943e 584 return true;
41286812 585 }
baeed289 586
4d08943e 587 return false;
19454fa0
VZ
588}
589
2ba41305
VZ
590// this exactly reproduces the string version above except for ExpandEnvVars(),
591// we really should avoid this code duplication somehow...
592
593bool wxRegConfig::DoReadLong(const wxString& key, long *plResult) const
19454fa0 594{
4d08943e 595 wxCHECK_MSG( plResult, false, _T("wxRegConfig::Read(): NULL param") );
2ba41305 596
18244936 597 wxConfigPathChanger path(this, key);
19454fa0 598
4d08943e 599 bool bQueryGlobal = true;
19454fa0
VZ
600
601 // if immutable key exists in global key we must check that it's not
602 // overriden by the local key with the same name
603 if ( IsImmutable(path.Name()) ) {
02569ba8 604 if ( TryGetValue(m_keyGlobal, path.Name(), plResult) ) {
807a903e 605 if ( m_keyLocal.Exists() && LocalKey().HasValue(path.Name()) ) {
223d09f6 606 wxLogWarning(wxT("User value for immutable key '%s' ignored."),
19454fa0
VZ
607 path.Name().c_str());
608 }
609
4d08943e 610 return true;
19454fa0
VZ
611 }
612 else {
613 // don't waste time - it's not there anyhow
4d08943e 614 bQueryGlobal = false;
19454fa0
VZ
615 }
616 }
617
618 // first try local key
807a903e 619 if ( (m_keyLocal.Exists() && TryGetValue(LocalKey(), path.Name(), plResult)) ||
02569ba8 620 (bQueryGlobal && TryGetValue(m_keyGlobal, path.Name(), plResult)) ) {
4d08943e 621 return true;
19454fa0 622 }
2ba41305 623
4d08943e 624 return false;
19454fa0
VZ
625}
626
2ba41305 627bool wxRegConfig::DoWriteString(const wxString& key, const wxString& szValue)
19454fa0 628{
18244936 629 wxConfigPathChanger path(this, key);
19454fa0
VZ
630
631 if ( IsImmutable(path.Name()) ) {
223d09f6 632 wxLogError(wxT("Can't change immutable entry '%s'."), path.Name().c_str());
4d08943e 633 return false;
19454fa0
VZ
634 }
635
807a903e 636 return LocalKey().SetValue(path.Name(), szValue);
19454fa0
VZ
637}
638
2ba41305 639bool wxRegConfig::DoWriteLong(const wxString& key, long lValue)
19454fa0 640{
18244936 641 wxConfigPathChanger path(this, key);
19454fa0
VZ
642
643 if ( IsImmutable(path.Name()) ) {
223d09f6 644 wxLogError(wxT("Can't change immutable entry '%s'."), path.Name().c_str());
4d08943e 645 return false;
19454fa0
VZ
646 }
647
807a903e 648 return LocalKey().SetValue(path.Name(), lValue);
19454fa0
VZ
649}
650
651// ----------------------------------------------------------------------------
89077ebc
VZ
652// renaming
653// ----------------------------------------------------------------------------
654
655bool wxRegConfig::RenameEntry(const wxString& oldName, const wxString& newName)
656{
657 // check that the old entry exists...
658 if ( !HasEntry(oldName) )
4d08943e 659 return false;
89077ebc
VZ
660
661 // and that the new one doesn't
662 if ( HasEntry(newName) )
4d08943e 663 return false;
89077ebc 664
442d08ce 665 return m_keyLocal.RenameValue(oldName, newName);
89077ebc
VZ
666}
667
668bool wxRegConfig::RenameGroup(const wxString& oldName, const wxString& newName)
669{
670 // check that the old group exists...
671 if ( !HasGroup(oldName) )
4d08943e 672 return false;
89077ebc
VZ
673
674 // and that the new one doesn't
675 if ( HasGroup(newName) )
4d08943e 676 return false;
89077ebc 677
442d08ce 678 return wxRegKey(m_keyLocal, oldName).Rename(newName);
89077ebc
VZ
679}
680
681// ----------------------------------------------------------------------------
19454fa0
VZ
682// deleting
683// ----------------------------------------------------------------------------
1ad6d522
VZ
684
685bool wxRegConfig::DeleteEntry(const wxString& value, bool bGroupIfEmptyAlso)
19454fa0 686{
18244936 687 wxConfigPathChanger path(this, value);
19454fa0 688
807a903e
VZ
689 if ( m_keyLocal.Exists() ) {
690 if ( !m_keyLocal.DeleteValue(path.Name()) )
4d08943e 691 return false;
19454fa0 692
1ad6d522 693 if ( bGroupIfEmptyAlso && m_keyLocal.IsEmpty() ) {
807a903e 694 wxString strKey = GetPath().AfterLast(wxCONFIG_PATH_SEPARATOR);
2b5f62a0 695 SetPath(_T("..")); // changes m_keyLocal
807a903e
VZ
696 return LocalKey().DeleteKey(strKey);
697 }
19454fa0
VZ
698 }
699
4d08943e 700 return true;
19454fa0
VZ
701}
702
18244936 703bool wxRegConfig::DeleteGroup(const wxString& key)
19454fa0 704{
18244936 705 wxConfigPathChanger path(this, key);
19454fa0 706
4d08943e 707 return m_keyLocal.Exists() ? LocalKey().DeleteKey(path.Name()) : true;
19454fa0
VZ
708}
709
710bool wxRegConfig::DeleteAll()
711{
19454fa0
VZ
712 m_keyLocal.Close();
713 m_keyGlobal.Close();
90186e52 714
19454fa0 715 bool bOk = m_keyLocalRoot.DeleteSelf();
90186e52
VZ
716
717 // make sure that we opened m_keyGlobalRoot and so it has a reasonable name:
718 // otherwise we will delete HKEY_CLASSES_ROOT recursively
719 if ( bOk && m_keyGlobalRoot.IsOpened() )
19454fa0
VZ
720 bOk = m_keyGlobalRoot.DeleteSelf();
721
722 return bOk;
723}
3d05544e 724
f6bcfd97
BP
725#endif
726 // wxUSE_CONFIG