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