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