]> git.saurik.com Git - wxWidgets.git/blob - src/msw/iniconf.cpp
fixed the vsprintf() problem once and for all
[wxWidgets.git] / src / msw / iniconf.cpp
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
56 wxIniConfig::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
99 wxIniConfig::~wxIniConfig()
100 {
101 }
102
103 // ----------------------------------------------------------------------------
104 // path management
105 // ----------------------------------------------------------------------------
106
107 void 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
148 const 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
170 wxString 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
182 wxString 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
201 bool wxIniConfig::GetFirstGroup(wxString& str, long& lIndex) const
202 {
203 wxFAIL_MSG("not implemented");
204
205 return FALSE;
206 }
207
208 bool wxIniConfig::GetNextGroup (wxString& str, long& lIndex) const
209 {
210 wxFAIL_MSG("not implemented");
211
212 return FALSE;
213 }
214
215 bool wxIniConfig::GetFirstEntry(wxString& str, long& lIndex) const
216 {
217 wxFAIL_MSG("not implemented");
218
219 return FALSE;
220 }
221
222 bool 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
234 size_t wxIniConfig::GetNumberOfEntries(bool bRecursive) const
235 {
236 wxFAIL_MSG("not implemented");
237
238 return (size_t)-1;
239 }
240
241 size_t wxIniConfig::GetNumberOfGroups(bool bRecursive) const
242 {
243 wxFAIL_MSG("not implemented");
244
245 return (size_t)-1;
246 }
247
248 bool wxIniConfig::HasGroup(const wxString& strName) const
249 {
250 wxFAIL_MSG("not implemented");
251
252 return FALSE;
253 }
254
255 bool wxIniConfig::HasEntry(const wxString& strName) const
256 {
257 wxFAIL_MSG("not implemented");
258
259 return FALSE;
260 }
261
262 // is current group empty?
263 bool 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
283 bool 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
309 bool 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
337 bool 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
368 bool 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
382 bool 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
391 bool 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
401 bool 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
420 bool 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
435 bool 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 }