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