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