]> git.saurik.com Git - wxWidgets.git/blob - src/msw/iniconf.cpp
5ebc45df7a8c0f6549d6d3d6548e9edefcee8e95
[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 licence
10 ///////////////////////////////////////////////////////////////////////////////
11
12 // For compilers that support precompilation, includes "wx.h".
13 #include "wx/wxprec.h"
14
15 #ifdef __BORLANDC__
16 #pragma hdrstop
17 #endif
18
19 #if wxUSE_CONFIG
20
21 #ifndef WX_PRECOMP
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"
30 #endif //WX_PRECOMP
31
32 #include "wx/config.h"
33 #include "wx/file.h"
34
35 #include "wx/msw/iniconf.h"
36
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 // ----------------------------------------------------------------------------
51 IMPLEMENT_ABSTRACT_CLASS(wxIniConfig, wxConfigBase)
52
53 wxIniConfig::wxIniConfig(const wxString& strAppName,
54 const wxString& strVendor,
55 const wxString& localFilename,
56 const wxString& globalFilename,
57 long style)
58 : wxConfigBase(strAppName, strVendor, localFilename, globalFilename, style)
59
60 #if 0 // This is too complex for some compilers, e.g. BC++ 5.01
61 : wxConfigBase((strAppName.empty() && wxTheApp) ? wxTheApp->GetAppName()
62 : strAppName,
63 strVendor.empty() ? (wxTheApp ? wxTheApp->GetVendorName()
64 : strAppName)
65 : strVendor,
66 localFilename, globalFilename, style)
67 #endif
68 {
69 if (strAppName.empty() && wxTheApp)
70 SetAppName(wxTheApp->GetAppName());
71 if (strVendor.empty() && wxTheApp)
72 SetVendorName(wxTheApp->GetVendorName());
73
74 m_strLocalFilename = localFilename;
75 if (m_strLocalFilename.empty())
76 {
77 m_strLocalFilename = GetAppName() + wxT(".ini");
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]) &&
83 m_strLocalFilename.Find(wxT('.')) == wxNOT_FOUND )
84 {
85 m_strLocalFilename << wxT(".ini");
86 }
87
88 // set root path
89 SetPath(wxEmptyString);
90 }
91
92 wxIniConfig::~wxIniConfig()
93 {
94 }
95
96 // ----------------------------------------------------------------------------
97 // path management
98 // ----------------------------------------------------------------------------
99
100 void wxIniConfig::SetPath(const wxString& strPath)
101 {
102 wxArrayString aParts;
103
104 if ( strPath.empty() ) {
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
118 size_t nPartsCount = aParts.Count();
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];
127 for ( size_t nPart = 1; nPart < nPartsCount; nPart++ ) {
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
136 wxASSERT( (m_strPath.empty() || m_strPath.Last() != PATH_SEP_REPLACE) &&
137 (m_strGroup == wxString(PATH_SEP_REPLACE) ||
138 m_strGroup.Last() != PATH_SEP_REPLACE) );
139 }
140
141 const wxString& wxIniConfig::GetPath() const
142 {
143 static wxString s_str;
144
145 // always return abs path
146 s_str = wxCONFIG_PATH_SEPARATOR;
147
148 if ( m_strGroup == wxString(PATH_SEP_REPLACE) ) {
149 // we're at the root level, nothing to do
150 }
151 else {
152 s_str << m_strGroup;
153 if ( !m_strPath.empty() )
154 s_str << wxCONFIG_PATH_SEPARATOR;
155 for ( const wxChar *p = m_strPath; *p != '\0'; p++ ) {
156 s_str << (*p == PATH_SEP_REPLACE ? wxCONFIG_PATH_SEPARATOR : *p);
157 }
158 }
159
160 return s_str;
161 }
162
163 wxString wxIniConfig::GetPrivateKeyName(const wxString& szKey) const
164 {
165 wxString strKey;
166
167 if ( !m_strPath.empty() )
168 strKey << m_strPath << PATH_SEP_REPLACE;
169
170 strKey << szKey;
171
172 return strKey;
173 }
174
175 wxString wxIniConfig::GetKeyName(const wxString& szKey) const
176 {
177 wxString strKey;
178
179 if ( m_strGroup != wxString(PATH_SEP_REPLACE) )
180 strKey << m_strGroup << PATH_SEP_REPLACE;
181 if ( !m_strPath.empty() )
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
194 bool wxIniConfig::GetFirstGroup(wxString& WXUNUSED(str), long& WXUNUSED(lIndex)) const
195 {
196 wxFAIL_MSG("not implemented");
197
198 return false;
199 }
200
201 bool wxIniConfig::GetNextGroup (wxString& WXUNUSED(str), long& WXUNUSED(lIndex)) const
202 {
203 wxFAIL_MSG("not implemented");
204
205 return false;
206 }
207
208 bool wxIniConfig::GetFirstEntry(wxString& WXUNUSED(str), long& WXUNUSED(lIndex)) const
209 {
210 wxFAIL_MSG("not implemented");
211
212 return false;
213 }
214
215 bool wxIniConfig::GetNextEntry (wxString& WXUNUSED(str), long& WXUNUSED(lIndex)) const
216 {
217 wxFAIL_MSG("not implemented");
218
219 return false;
220 }
221
222 // ----------------------------------------------------------------------------
223 // misc info
224 // ----------------------------------------------------------------------------
225
226 // not implemented
227 size_t wxIniConfig::GetNumberOfEntries(bool WXUNUSED(bRecursive)) const
228 {
229 wxFAIL_MSG("not implemented");
230
231 return (size_t)-1;
232 }
233
234 size_t wxIniConfig::GetNumberOfGroups(bool WXUNUSED(bRecursive)) const
235 {
236 wxFAIL_MSG("not implemented");
237
238 return (size_t)-1;
239 }
240
241 bool wxIniConfig::HasGroup(const wxString& WXUNUSED(strName)) const
242 {
243 wxFAIL_MSG("not implemented");
244
245 return false;
246 }
247
248 bool wxIniConfig::HasEntry(const wxString& WXUNUSED(strName)) const
249 {
250 wxFAIL_MSG("not implemented");
251
252 return false;
253 }
254
255 // is current group empty?
256 bool wxIniConfig::IsEmpty() const
257 {
258 wxChar szBuf[1024];
259
260 GetPrivateProfileString(m_strGroup, NULL, _T(""),
261 szBuf, WXSIZEOF(szBuf), m_strLocalFilename);
262 if ( !wxIsEmpty(szBuf) )
263 return false;
264
265 GetProfileString(m_strGroup, NULL, _T(""), szBuf, WXSIZEOF(szBuf));
266 if ( !wxIsEmpty(szBuf) )
267 return false;
268
269 return true;
270 }
271
272 // ----------------------------------------------------------------------------
273 // read/write
274 // ----------------------------------------------------------------------------
275
276 bool wxIniConfig::DoReadString(const wxString& szKey, wxString *pstr) const
277 {
278 wxConfigPathChanger path(this, szKey);
279 wxString strKey = GetPrivateKeyName(path.Name());
280
281 wxChar szBuf[1024]; // FIXME: should dynamically allocate memory...
282
283 // first look in the private INI file
284
285 // NB: the lpDefault param to GetPrivateProfileString can't be NULL
286 GetPrivateProfileString(m_strGroup, strKey, _T(""),
287 szBuf, WXSIZEOF(szBuf), m_strLocalFilename);
288 if ( wxIsEmpty(szBuf) ) {
289 // now look in win.ini
290 wxString strKey = GetKeyName(path.Name());
291 GetProfileString(m_strGroup, strKey, _T(""), szBuf, WXSIZEOF(szBuf));
292 }
293
294 if ( wxIsEmpty(szBuf) )
295 return false;
296
297 *pstr = szBuf;
298 return true;
299 }
300
301 bool wxIniConfig::DoReadLong(const wxString& szKey, long *pl) const
302 {
303 wxConfigPathChanger path(this, szKey);
304 wxString strKey = GetPrivateKeyName(path.Name());
305
306 // hack: we have no mean to know if it really found the default value or
307 // didn't find anything, so we call it twice
308
309 static const int nMagic = 17; // 17 is some "rare" number
310 static const int nMagic2 = 28; // arbitrary number != nMagic
311 long lVal = GetPrivateProfileInt(m_strGroup, strKey, nMagic, m_strLocalFilename);
312 if ( lVal != nMagic ) {
313 // the value was read from the file
314 *pl = lVal;
315 return true;
316 }
317
318 // is it really nMagic?
319 lVal = GetPrivateProfileInt(m_strGroup, strKey, nMagic2, m_strLocalFilename);
320 if ( lVal != nMagic2 ) {
321 // the nMagic it returned was indeed read from the file
322 *pl = lVal;
323 return true;
324 }
325
326 // CS : I have no idea why they should look up in win.ini
327 // and if at all they have to do the same procedure using the two magic numbers
328 // otherwise it always returns true, even if the key was not there at all
329 #if 0
330 // no, it was just returning the default value, so now look in win.ini
331 *pl = GetProfileInt(GetVendorName(), GetKeyName(szKey), *pl);
332
333 return true;
334 #endif
335 return false ;
336 }
337
338 bool wxIniConfig::DoWriteString(const wxString& szKey, const wxString& szValue)
339 {
340 wxConfigPathChanger path(this, szKey);
341 wxString strKey = GetPrivateKeyName(path.Name());
342
343 bool bOk = WritePrivateProfileString(m_strGroup, strKey,
344 szValue, m_strLocalFilename) != 0;
345
346 if ( !bOk )
347 wxLogLastError(wxT("WritePrivateProfileString"));
348
349 return bOk;
350 }
351
352 bool wxIniConfig::DoWriteLong(const wxString& szKey, long lValue)
353 {
354 return Write(szKey, wxString::Format(_T("%ld"), lValue));
355 }
356
357 bool wxIniConfig::Flush(bool /* bCurrentOnly */)
358 {
359 // this is just the way it works
360 return WritePrivateProfileString(NULL, NULL, NULL, m_strLocalFilename) != 0;
361 }
362
363 // ----------------------------------------------------------------------------
364 // delete
365 // ----------------------------------------------------------------------------
366
367 bool wxIniConfig::DeleteEntry(const wxString& szKey, bool bGroupIfEmptyAlso)
368 {
369 // passing NULL as value to WritePrivateProfileString deletes the key
370 wxConfigPathChanger path(this, szKey);
371 wxString strKey = GetPrivateKeyName(path.Name());
372
373 if (WritePrivateProfileString(m_strGroup, strKey,
374 NULL, m_strLocalFilename) == 0)
375 return false;
376
377 if ( !bGroupIfEmptyAlso || !IsEmpty() )
378 return true;
379
380 // delete the current group too
381 bool bOk = WritePrivateProfileString(m_strGroup, NULL,
382 NULL, m_strLocalFilename) != 0;
383
384 if ( !bOk )
385 wxLogLastError(wxT("WritePrivateProfileString"));
386
387 return bOk;
388 }
389
390 bool wxIniConfig::DeleteGroup(const wxString& szKey)
391 {
392 wxConfigPathChanger path(this, szKey);
393
394 // passing NULL as section name to WritePrivateProfileString deletes the
395 // whole section according to the docs
396 bool bOk = WritePrivateProfileString(path.Name(), NULL,
397 NULL, m_strLocalFilename) != 0;
398
399 if ( !bOk )
400 wxLogLastError(wxT("WritePrivateProfileString"));
401
402 return bOk;
403 }
404
405 #ifndef MAX_PATH
406 #define MAX_PATH 256
407 #endif
408
409 bool wxIniConfig::DeleteAll()
410 {
411 // first delete our group in win.ini
412 WriteProfileString(GetVendorName(), NULL, NULL);
413
414 // then delete our own ini file
415 wxChar szBuf[MAX_PATH];
416 size_t nRc = GetWindowsDirectory(szBuf, WXSIZEOF(szBuf));
417 if ( nRc == 0 )
418 {
419 wxLogLastError(wxT("GetWindowsDirectory"));
420 }
421 else if ( nRc > WXSIZEOF(szBuf) )
422 {
423 wxFAIL_MSG(wxT("buffer is too small for Windows directory."));
424 }
425
426 wxString strFile = szBuf;
427 strFile << '\\' << m_strLocalFilename;
428
429 if ( wxFile::Exists(strFile) && !wxRemoveFile(strFile) ) {
430 wxLogSysError(_("Can't delete the INI file '%s'"), strFile.c_str());
431 return false;
432 }
433
434 return true;
435 }
436
437 bool wxIniConfig::RenameEntry(const wxString& WXUNUSED(oldName),
438 const wxString& WXUNUSED(newName))
439 {
440 // Not implemented
441 return false;
442 }
443
444 bool wxIniConfig::RenameGroup(const wxString& WXUNUSED(oldName),
445 const wxString& WXUNUSED(newName))
446 {
447 // Not implemented
448 return false;
449 }
450
451 #endif // wxUSE_CONFIG