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