]> git.saurik.com Git - wxWidgets.git/blame - src/msw/iniconf.cpp
Fix another off-by-1 bug in wxMBConv::ToWChar().
[wxWidgets.git] / src / msw / iniconf.cpp
CommitLineData
02569ba8
VZ
1///////////////////////////////////////////////////////////////////////////////
2// Name: src/msw/iniconf.cpp
3// Purpose: implementation of wxIniConfig class
4// Author: Vadim Zeitlin
9869734d 5// Modified by:
02569ba8
VZ
6// Created: 27.07.98
7// RCS-ID: $Id$
8// Copyright: (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
65571936 9// Licence: wxWindows licence
02569ba8
VZ
10///////////////////////////////////////////////////////////////////////////////
11
a3b46648
UU
12// For compilers that support precompilation, includes "wx.h".
13#include "wx/wxprec.h"
02569ba8 14
a3b46648 15#ifdef __BORLANDC__
ad9835c9 16 #pragma hdrstop
a3b46648 17#endif
02569ba8 18
61873536 19#if wxUSE_INICONF
f6bcfd97 20
ad9835c9 21#ifndef WX_PRECOMP
57bd4c60
WS
22 #include "wx/msw/wrapwin.h"
23 #include "wx/dynarray.h"
24 #include "wx/string.h"
25 #include "wx/intl.h"
26 #include "wx/event.h"
27 #include "wx/app.h"
28 #include "wx/utils.h"
29 #include "wx/log.h"
ad9835c9
WS
30#endif //WX_PRECOMP
31
3096bd2f 32#include "wx/config.h"
999836aa 33#include "wx/file.h"
02569ba8 34
3096bd2f 35#include "wx/msw/iniconf.h"
02569ba8 36
02569ba8
VZ
37// ----------------------------------------------------------------------------
38// constants
39// ----------------------------------------------------------------------------
40
41// we replace all path separators with this character
42#define PATH_SEP_REPLACE '_'
43
44// ============================================================================
45// implementation
46// ============================================================================
47
48// ----------------------------------------------------------------------------
49// ctor & dtor
50// ----------------------------------------------------------------------------
c4ec0ce8 51IMPLEMENT_ABSTRACT_CLASS(wxIniConfig, wxConfigBase)
02569ba8 52
9869734d
VZ
53wxIniConfig::wxIniConfig(const wxString& strAppName,
54 const wxString& strVendor,
55 const wxString& localFilename,
56 const wxString& globalFilename,
57 long style)
8f19c916
JS
58 : wxConfigBase(strAppName, strVendor, localFilename, globalFilename, style)
59
60#if 0 // This is too complex for some compilers, e.g. BC++ 5.01
ad9835c9 61 : wxConfigBase((strAppName.empty() && wxTheApp) ? wxTheApp->GetAppName()
d2c7e39b 62 : strAppName,
ad9835c9 63 strVendor.empty() ? (wxTheApp ? wxTheApp->GetVendorName()
d2c7e39b
JS
64 : strAppName)
65 : strVendor,
66 localFilename, globalFilename, style)
8f19c916 67#endif
02569ba8 68{
ad9835c9 69 if (strAppName.empty() && wxTheApp)
8f19c916 70 SetAppName(wxTheApp->GetAppName());
ad9835c9 71 if (strVendor.empty() && wxTheApp)
8f19c916
JS
72 SetVendorName(wxTheApp->GetVendorName());
73
18244936 74 m_strLocalFilename = localFilename;
ad9835c9 75 if (m_strLocalFilename.empty())
18244936 76 {
f6bcfd97 77 m_strLocalFilename = GetAppName() + wxT(".ini");
18244936
JS
78 }
79
80 // append the extension if none given and it's not an absolute file name
81 // (otherwise we assume that they know what they're doing)
82 if ( !wxIsPathSeparator(m_strLocalFilename[0u]) &&
f6bcfd97 83 m_strLocalFilename.Find(wxT('.')) == wxNOT_FOUND )
18244936 84 {
f6bcfd97 85 m_strLocalFilename << wxT(".ini");
18244936
JS
86 }
87
88 // set root path
fda7962d 89 SetPath(wxEmptyString);
02569ba8
VZ
90}
91
92wxIniConfig::~wxIniConfig()
93{
94}
95
96// ----------------------------------------------------------------------------
97// path management
98// ----------------------------------------------------------------------------
99
100void wxIniConfig::SetPath(const wxString& strPath)
101{
102 wxArrayString aParts;
103
ad9835c9 104 if ( strPath.empty() ) {
02569ba8
VZ
105 // nothing
106 }
107 else if ( strPath[0u] == wxCONFIG_PATH_SEPARATOR ) {
108 // absolute path
109 wxSplitPath(aParts, strPath);
110 }
111 else {
112 // relative path, combine with current one
113 wxString strFullPath = GetPath();
114 strFullPath << wxCONFIG_PATH_SEPARATOR << strPath;
115 wxSplitPath(aParts, strFullPath);
116 }
117
c86f1403 118 size_t nPartsCount = aParts.Count();
02569ba8
VZ
119 m_strPath.Empty();
120 if ( nPartsCount == 0 ) {
121 // go to the root
122 m_strGroup = PATH_SEP_REPLACE;
123 }
124 else {
125 // translate
126 m_strGroup = aParts[0u];
c86f1403 127 for ( size_t nPart = 1; nPart < nPartsCount; nPart++ ) {
02569ba8
VZ
128 if ( nPart > 1 )
129 m_strPath << PATH_SEP_REPLACE;
130 m_strPath << aParts[nPart];
131 }
132 }
133
134 // other functions assume that all this is true, i.e. there are no trailing
135 // underscores at the end except if the group is the root one
ad9835c9 136 wxASSERT( (m_strPath.empty() || m_strPath.Last() != PATH_SEP_REPLACE) &&
62448488 137 (m_strGroup == wxString(PATH_SEP_REPLACE) ||
02569ba8
VZ
138 m_strGroup.Last() != PATH_SEP_REPLACE) );
139}
140
141const wxString& wxIniConfig::GetPath() const
142{
143 static wxString s_str;
144
145 // always return abs path
146 s_str = wxCONFIG_PATH_SEPARATOR;
147
ce3ed50d 148 if ( m_strGroup == wxString(PATH_SEP_REPLACE) ) {
02569ba8
VZ
149 // we're at the root level, nothing to do
150 }
151 else {
152 s_str << m_strGroup;
ad9835c9 153 if ( !m_strPath.empty() )
02569ba8 154 s_str << wxCONFIG_PATH_SEPARATOR;
414721d0 155 for ( const wxStringCharType *p = m_strPath.wx_str(); *p != '\0'; p++ ) {
02569ba8
VZ
156 s_str << (*p == PATH_SEP_REPLACE ? wxCONFIG_PATH_SEPARATOR : *p);
157 }
158 }
159
160 return s_str;
161}
162
18244936 163wxString wxIniConfig::GetPrivateKeyName(const wxString& szKey) const
02569ba8
VZ
164{
165 wxString strKey;
166
ad9835c9 167 if ( !m_strPath.empty() )
02569ba8
VZ
168 strKey << m_strPath << PATH_SEP_REPLACE;
169
170 strKey << szKey;
171
172 return strKey;
173}
174
18244936 175wxString wxIniConfig::GetKeyName(const wxString& szKey) const
02569ba8
VZ
176{
177 wxString strKey;
178
62448488 179 if ( m_strGroup != wxString(PATH_SEP_REPLACE) )
02569ba8 180 strKey << m_strGroup << PATH_SEP_REPLACE;
ad9835c9 181 if ( !m_strPath.empty() )
02569ba8
VZ
182 strKey << m_strPath << PATH_SEP_REPLACE;
183
184 strKey << szKey;
185
186 return strKey;
187}
188
189// ----------------------------------------------------------------------------
190// enumeration
191// ----------------------------------------------------------------------------
192
193// not implemented
2eb10e2a 194bool wxIniConfig::GetFirstGroup(wxString& WXUNUSED(str), long& WXUNUSED(lIndex)) const
02569ba8 195{
ad9835c9 196 wxFAIL_MSG("not implemented");
02569ba8 197
ad9835c9 198 return false;
02569ba8
VZ
199}
200
2eb10e2a 201bool wxIniConfig::GetNextGroup (wxString& WXUNUSED(str), long& WXUNUSED(lIndex)) const
02569ba8 202{
ad9835c9 203 wxFAIL_MSG("not implemented");
02569ba8 204
ad9835c9 205 return false;
02569ba8
VZ
206}
207
2eb10e2a 208bool wxIniConfig::GetFirstEntry(wxString& WXUNUSED(str), long& WXUNUSED(lIndex)) const
02569ba8 209{
ad9835c9 210 wxFAIL_MSG("not implemented");
02569ba8 211
ad9835c9 212 return false;
02569ba8
VZ
213}
214
2eb10e2a 215bool wxIniConfig::GetNextEntry (wxString& WXUNUSED(str), long& WXUNUSED(lIndex)) const
02569ba8 216{
ad9835c9 217 wxFAIL_MSG("not implemented");
02569ba8 218
ad9835c9 219 return false;
02569ba8
VZ
220}
221
222// ----------------------------------------------------------------------------
223// misc info
224// ----------------------------------------------------------------------------
225
226// not implemented
2eb10e2a 227size_t wxIniConfig::GetNumberOfEntries(bool WXUNUSED(bRecursive)) const
02569ba8 228{
ad9835c9 229 wxFAIL_MSG("not implemented");
02569ba8 230
ad9835c9 231 return (size_t)-1;
02569ba8
VZ
232}
233
2eb10e2a 234size_t wxIniConfig::GetNumberOfGroups(bool WXUNUSED(bRecursive)) const
02569ba8 235{
ad9835c9 236 wxFAIL_MSG("not implemented");
02569ba8 237
ad9835c9 238 return (size_t)-1;
02569ba8
VZ
239}
240
2eb10e2a 241bool wxIniConfig::HasGroup(const wxString& WXUNUSED(strName)) const
02569ba8 242{
ad9835c9 243 wxFAIL_MSG("not implemented");
02569ba8 244
ad9835c9 245 return false;
02569ba8
VZ
246}
247
2eb10e2a 248bool wxIniConfig::HasEntry(const wxString& WXUNUSED(strName)) const
02569ba8 249{
ad9835c9 250 wxFAIL_MSG("not implemented");
02569ba8 251
ad9835c9 252 return false;
02569ba8
VZ
253}
254
255// is current group empty?
256bool wxIniConfig::IsEmpty() const
257{
7b673bef 258 wxChar szBuf[1024];
02569ba8 259
9a83f860 260 GetPrivateProfileString(m_strGroup.wx_str(), NULL, wxT(""),
414721d0
VZ
261 szBuf, WXSIZEOF(szBuf),
262 m_strLocalFilename.wx_str());
342a2719 263 if ( !wxIsEmpty(szBuf) )
ad9835c9 264 return false;
02569ba8 265
9a83f860 266 GetProfileString(m_strGroup.wx_str(), NULL, wxT(""), szBuf, WXSIZEOF(szBuf));
342a2719 267 if ( !wxIsEmpty(szBuf) )
ad9835c9 268 return false;
02569ba8 269
ad9835c9 270 return true;
02569ba8
VZ
271}
272
273// ----------------------------------------------------------------------------
274// read/write
275// ----------------------------------------------------------------------------
276
2ba41305 277bool wxIniConfig::DoReadString(const wxString& szKey, wxString *pstr) const
02569ba8 278{
18244936 279 wxConfigPathChanger path(this, szKey);
02569ba8
VZ
280 wxString strKey = GetPrivateKeyName(path.Name());
281
7b673bef 282 wxChar szBuf[1024]; // FIXME: should dynamically allocate memory...
02569ba8
VZ
283
284 // first look in the private INI file
285
286 // NB: the lpDefault param to GetPrivateProfileString can't be NULL
9a83f860 287 GetPrivateProfileString(m_strGroup.wx_str(), strKey.wx_str(), wxT(""),
414721d0
VZ
288 szBuf, WXSIZEOF(szBuf),
289 m_strLocalFilename.wx_str());
342a2719 290 if ( wxIsEmpty(szBuf) ) {
02569ba8
VZ
291 // now look in win.ini
292 wxString strKey = GetKeyName(path.Name());
414721d0 293 GetProfileString(m_strGroup.wx_str(), strKey.wx_str(),
9a83f860 294 wxT(""), szBuf, WXSIZEOF(szBuf));
02569ba8
VZ
295 }
296
342a2719 297 if ( wxIsEmpty(szBuf) )
59af881e 298 return false;
0cb50c83
VZ
299
300 *pstr = szBuf;
59af881e 301 return true;
02569ba8
VZ
302}
303
2ba41305 304bool wxIniConfig::DoReadLong(const wxString& szKey, long *pl) const
02569ba8 305{
18244936 306 wxConfigPathChanger path(this, szKey);
02569ba8
VZ
307 wxString strKey = GetPrivateKeyName(path.Name());
308
309 // hack: we have no mean to know if it really found the default value or
310 // didn't find anything, so we call it twice
311
312 static const int nMagic = 17; // 17 is some "rare" number
313 static const int nMagic2 = 28; // arbitrary number != nMagic
414721d0
VZ
314 long lVal = GetPrivateProfileInt(m_strGroup.wx_str(), strKey.wx_str(),
315 nMagic, m_strLocalFilename.wx_str());
02569ba8
VZ
316 if ( lVal != nMagic ) {
317 // the value was read from the file
318 *pl = lVal;
59af881e 319 return true;
02569ba8
VZ
320 }
321
322 // is it really nMagic?
414721d0
VZ
323 lVal = GetPrivateProfileInt(m_strGroup.wx_str(), strKey.wx_str(),
324 nMagic2, m_strLocalFilename.wx_str());
519cb848 325 if ( lVal != nMagic2 ) {
02569ba8
VZ
326 // the nMagic it returned was indeed read from the file
327 *pl = lVal;
59af881e 328 return true;
02569ba8
VZ
329 }
330
519cb848
SC
331 // CS : I have no idea why they should look up in win.ini
332 // and if at all they have to do the same procedure using the two magic numbers
333 // otherwise it always returns true, even if the key was not there at all
334#if 0
02569ba8 335 // no, it was just returning the default value, so now look in win.ini
519cb848 336 *pl = GetProfileInt(GetVendorName(), GetKeyName(szKey), *pl);
02569ba8 337
59af881e 338 return true;
519cb848 339#endif
59af881e 340 return false ;
02569ba8
VZ
341}
342
2ba41305 343bool wxIniConfig::DoWriteString(const wxString& szKey, const wxString& szValue)
02569ba8 344{
18244936 345 wxConfigPathChanger path(this, szKey);
02569ba8
VZ
346 wxString strKey = GetPrivateKeyName(path.Name());
347
414721d0
VZ
348 bool bOk = WritePrivateProfileString(m_strGroup.wx_str(), strKey.wx_str(),
349 szValue.wx_str(),
350 m_strLocalFilename.wx_str()) != 0;
02569ba8
VZ
351
352 if ( !bOk )
43b2d5e7 353 {
f6bcfd97 354 wxLogLastError(wxT("WritePrivateProfileString"));
43b2d5e7 355 }
02569ba8
VZ
356
357 return bOk;
358}
359
2ba41305 360bool wxIniConfig::DoWriteLong(const wxString& szKey, long lValue)
02569ba8 361{
9a83f860 362 return Write(szKey, wxString::Format(wxT("%ld"), lValue));
02569ba8
VZ
363}
364
11c467ef
VZ
365bool wxIniConfig::DoReadBinary(const wxString& WXUNUSED(key),
366 wxMemoryBuffer * WXUNUSED(buf)) const
367{
368 wxFAIL_MSG("not implemented");
369
370 return false;
371}
372
373bool wxIniConfig::DoWriteBinary(const wxString& WXUNUSED(key),
374 const wxMemoryBuffer& WXUNUSED(buf))
375{
376 wxFAIL_MSG("not implemented");
377
378 return false;
379}
380
02569ba8
VZ
381bool wxIniConfig::Flush(bool /* bCurrentOnly */)
382{
383 // this is just the way it works
414721d0
VZ
384 return WritePrivateProfileString(NULL, NULL, NULL,
385 m_strLocalFilename.wx_str()) != 0;
02569ba8
VZ
386}
387
388// ----------------------------------------------------------------------------
389// delete
390// ----------------------------------------------------------------------------
391
1e6d9499 392bool wxIniConfig::DeleteEntry(const wxString& szKey, bool bGroupIfEmptyAlso)
02569ba8
VZ
393{
394 // passing NULL as value to WritePrivateProfileString deletes the key
2432b92d
JS
395 wxConfigPathChanger path(this, szKey);
396 wxString strKey = GetPrivateKeyName(path.Name());
397
414721d0
VZ
398 if (WritePrivateProfileString(m_strGroup.wx_str(), strKey.wx_str(),
399 NULL, m_strLocalFilename.wx_str()) == 0)
59af881e 400 return false;
2432b92d 401
02569ba8 402 if ( !bGroupIfEmptyAlso || !IsEmpty() )
59af881e 403 return true;
02569ba8
VZ
404
405 // delete the current group too
414721d0
VZ
406 bool bOk = WritePrivateProfileString(m_strGroup.wx_str(), NULL,
407 NULL, m_strLocalFilename.wx_str()) != 0;
02569ba8
VZ
408
409 if ( !bOk )
43b2d5e7 410 {
f6bcfd97 411 wxLogLastError(wxT("WritePrivateProfileString"));
43b2d5e7 412 }
02569ba8
VZ
413
414 return bOk;
415}
416
1e6d9499 417bool wxIniConfig::DeleteGroup(const wxString& szKey)
02569ba8 418{
18244936 419 wxConfigPathChanger path(this, szKey);
02569ba8 420
9869734d 421 // passing NULL as section name to WritePrivateProfileString deletes the
02569ba8 422 // whole section according to the docs
414721d0
VZ
423 bool bOk = WritePrivateProfileString(path.Name().wx_str(), NULL,
424 NULL, m_strLocalFilename.wx_str()) != 0;
02569ba8
VZ
425
426 if ( !bOk )
43b2d5e7 427 {
f6bcfd97 428 wxLogLastError(wxT("WritePrivateProfileString"));
43b2d5e7 429 }
02569ba8
VZ
430
431 return bOk;
432}
433
1e6d9499
JS
434#ifndef MAX_PATH
435#define MAX_PATH 256
436#endif
437
02569ba8
VZ
438bool wxIniConfig::DeleteAll()
439{
440 // first delete our group in win.ini
414721d0 441 WriteProfileString(GetVendorName().wx_str(), NULL, NULL);
02569ba8
VZ
442
443 // then delete our own ini file
7b673bef 444 wxChar szBuf[MAX_PATH];
c86f1403 445 size_t nRc = GetWindowsDirectory(szBuf, WXSIZEOF(szBuf));
02569ba8 446 if ( nRc == 0 )
a1665b22 447 {
f6bcfd97 448 wxLogLastError(wxT("GetWindowsDirectory"));
a1665b22 449 }
02569ba8 450 else if ( nRc > WXSIZEOF(szBuf) )
a1665b22 451 {
f6bcfd97 452 wxFAIL_MSG(wxT("buffer is too small for Windows directory."));
a1665b22 453 }
02569ba8
VZ
454
455 wxString strFile = szBuf;
18244936 456 strFile << '\\' << m_strLocalFilename;
02569ba8 457
cb820f80 458 if ( wxFile::Exists(strFile) && !wxRemoveFile(strFile) ) {
02569ba8 459 wxLogSysError(_("Can't delete the INI file '%s'"), strFile.c_str());
59af881e 460 return false;
02569ba8
VZ
461 }
462
59af881e 463 return true;
02569ba8 464}
574c0bbf 465
2eb10e2a
VZ
466bool wxIniConfig::RenameEntry(const wxString& WXUNUSED(oldName),
467 const wxString& WXUNUSED(newName))
574c0bbf
JS
468{
469 // Not implemented
59af881e 470 return false;
574c0bbf
JS
471}
472
2eb10e2a
VZ
473bool wxIniConfig::RenameGroup(const wxString& WXUNUSED(oldName),
474 const wxString& WXUNUSED(newName))
574c0bbf
JS
475{
476 // Not implemented
59af881e 477 return false;
574c0bbf 478}
f6bcfd97 479
61873536 480#endif // wxUSE_INICONF