1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/msw/iniconf.cpp
3 // Purpose: implementation of wxIniConfig class
4 // Author: Vadim Zeitlin
8 // Copyright: (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
9 // Licence: wxWindows licence
10 ///////////////////////////////////////////////////////////////////////////////
12 // For compilers that support precompilation, includes "wx.h".
13 #include "wx/wxprec.h"
22 #include "wx/msw/wrapwin.h"
23 #include "wx/dynarray.h"
24 #include "wx/string.h"
32 #include "wx/config.h"
35 #include "wx/msw/iniconf.h"
37 // ----------------------------------------------------------------------------
39 // ----------------------------------------------------------------------------
41 // we replace all path separators with this character
42 #define PATH_SEP_REPLACE '_'
44 // ============================================================================
46 // ============================================================================
48 // ----------------------------------------------------------------------------
50 // ----------------------------------------------------------------------------
51 IMPLEMENT_ABSTRACT_CLASS(wxIniConfig
, wxConfigBase
)
53 wxIniConfig::wxIniConfig(const wxString
& strAppName
,
54 const wxString
& strVendor
,
55 const wxString
& localFilename
,
56 const wxString
& globalFilename
,
58 : wxConfigBase(strAppName
, strVendor
, localFilename
, globalFilename
, style
)
60 #if 0 // This is too complex for some compilers, e.g. BC++ 5.01
61 : wxConfigBase((strAppName
.empty() && wxTheApp
) ? wxTheApp
->GetAppName()
63 strVendor
.empty() ? (wxTheApp
? wxTheApp
->GetVendorName()
66 localFilename
, globalFilename
, style
)
69 if (strAppName
.empty() && wxTheApp
)
70 SetAppName(wxTheApp
->GetAppName());
71 if (strVendor
.empty() && wxTheApp
)
72 SetVendorName(wxTheApp
->GetVendorName());
74 m_strLocalFilename
= localFilename
;
75 if (m_strLocalFilename
.empty())
77 m_strLocalFilename
= GetAppName() + wxT(".ini");
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
)
85 m_strLocalFilename
<< wxT(".ini");
89 SetPath(wxEmptyString
);
92 wxIniConfig::~wxIniConfig()
96 // ----------------------------------------------------------------------------
98 // ----------------------------------------------------------------------------
100 void wxIniConfig::SetPath(const wxString
& strPath
)
102 wxArrayString aParts
;
104 if ( strPath
.empty() ) {
107 else if ( strPath
[0u] == wxCONFIG_PATH_SEPARATOR
) {
109 wxSplitPath(aParts
, strPath
);
112 // relative path, combine with current one
113 wxString strFullPath
= GetPath();
114 strFullPath
<< wxCONFIG_PATH_SEPARATOR
<< strPath
;
115 wxSplitPath(aParts
, strFullPath
);
118 size_t nPartsCount
= aParts
.Count();
120 if ( nPartsCount
== 0 ) {
122 m_strGroup
= PATH_SEP_REPLACE
;
126 m_strGroup
= aParts
[0u];
127 for ( size_t nPart
= 1; nPart
< nPartsCount
; nPart
++ ) {
129 m_strPath
<< PATH_SEP_REPLACE
;
130 m_strPath
<< aParts
[nPart
];
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
) );
141 const wxString
& wxIniConfig::GetPath() const
143 static wxString s_str
;
145 // always return abs path
146 s_str
= wxCONFIG_PATH_SEPARATOR
;
148 if ( m_strGroup
== wxString(PATH_SEP_REPLACE
) ) {
149 // we're at the root level, nothing to do
153 if ( !m_strPath
.empty() )
154 s_str
<< wxCONFIG_PATH_SEPARATOR
;
155 for ( const wxStringCharType
*p
= m_strPath
.wx_str(); *p
!= '\0'; p
++ ) {
156 s_str
<< (*p
== PATH_SEP_REPLACE
? wxCONFIG_PATH_SEPARATOR
: *p
);
163 wxString
wxIniConfig::GetPrivateKeyName(const wxString
& szKey
) const
167 if ( !m_strPath
.empty() )
168 strKey
<< m_strPath
<< PATH_SEP_REPLACE
;
175 wxString
wxIniConfig::GetKeyName(const wxString
& szKey
) const
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
;
189 // ----------------------------------------------------------------------------
191 // ----------------------------------------------------------------------------
194 bool wxIniConfig::GetFirstGroup(wxString
& WXUNUSED(str
), long& WXUNUSED(lIndex
)) const
196 wxFAIL_MSG("not implemented");
201 bool wxIniConfig::GetNextGroup (wxString
& WXUNUSED(str
), long& WXUNUSED(lIndex
)) const
203 wxFAIL_MSG("not implemented");
208 bool wxIniConfig::GetFirstEntry(wxString
& WXUNUSED(str
), long& WXUNUSED(lIndex
)) const
210 wxFAIL_MSG("not implemented");
215 bool wxIniConfig::GetNextEntry (wxString
& WXUNUSED(str
), long& WXUNUSED(lIndex
)) const
217 wxFAIL_MSG("not implemented");
222 // ----------------------------------------------------------------------------
224 // ----------------------------------------------------------------------------
227 size_t wxIniConfig::GetNumberOfEntries(bool WXUNUSED(bRecursive
)) const
229 wxFAIL_MSG("not implemented");
234 size_t wxIniConfig::GetNumberOfGroups(bool WXUNUSED(bRecursive
)) const
236 wxFAIL_MSG("not implemented");
241 bool wxIniConfig::HasGroup(const wxString
& WXUNUSED(strName
)) const
243 wxFAIL_MSG("not implemented");
248 bool wxIniConfig::HasEntry(const wxString
& WXUNUSED(strName
)) const
250 wxFAIL_MSG("not implemented");
255 // is current group empty?
256 bool wxIniConfig::IsEmpty() const
260 GetPrivateProfileString(m_strGroup
.wx_str(), NULL
, wxT(""),
261 szBuf
, WXSIZEOF(szBuf
),
262 m_strLocalFilename
.wx_str());
263 if ( !wxIsEmpty(szBuf
) )
266 GetProfileString(m_strGroup
.wx_str(), NULL
, wxT(""), szBuf
, WXSIZEOF(szBuf
));
267 if ( !wxIsEmpty(szBuf
) )
273 // ----------------------------------------------------------------------------
275 // ----------------------------------------------------------------------------
277 bool wxIniConfig::DoReadString(const wxString
& szKey
, wxString
*pstr
) const
279 wxConfigPathChanger
path(this, szKey
);
280 wxString strKey
= GetPrivateKeyName(path
.Name());
282 wxChar szBuf
[1024]; // FIXME: should dynamically allocate memory...
284 // first look in the private INI file
286 // NB: the lpDefault param to GetPrivateProfileString can't be NULL
287 GetPrivateProfileString(m_strGroup
.wx_str(), strKey
.wx_str(), wxT(""),
288 szBuf
, WXSIZEOF(szBuf
),
289 m_strLocalFilename
.wx_str());
290 if ( wxIsEmpty(szBuf
) ) {
291 // now look in win.ini
292 wxString strKey
= GetKeyName(path
.Name());
293 GetProfileString(m_strGroup
.wx_str(), strKey
.wx_str(),
294 wxT(""), szBuf
, WXSIZEOF(szBuf
));
297 if ( wxIsEmpty(szBuf
) )
304 bool wxIniConfig::DoReadLong(const wxString
& szKey
, long *pl
) const
306 wxConfigPathChanger
path(this, szKey
);
307 wxString strKey
= GetPrivateKeyName(path
.Name());
309 // hack: we have no mean to know if it really found the default value or
310 // didn't find anything, so we call it twice
312 static const int nMagic
= 17; // 17 is some "rare" number
313 static const int nMagic2
= 28; // arbitrary number != nMagic
314 long lVal
= GetPrivateProfileInt(m_strGroup
.wx_str(), strKey
.wx_str(),
315 nMagic
, m_strLocalFilename
.wx_str());
316 if ( lVal
!= nMagic
) {
317 // the value was read from the file
322 // is it really nMagic?
323 lVal
= GetPrivateProfileInt(m_strGroup
.wx_str(), strKey
.wx_str(),
324 nMagic2
, m_strLocalFilename
.wx_str());
325 if ( lVal
!= nMagic2
) {
326 // the nMagic it returned was indeed read from the file
331 // CS : I have no idea why they should look up in win.ini
332 // and if at all they have to do the same procedure using the two magic numbers
333 // otherwise it always returns true, even if the key was not there at all
335 // no, it was just returning the default value, so now look in win.ini
336 *pl
= GetProfileInt(GetVendorName(), GetKeyName(szKey
), *pl
);
343 bool wxIniConfig::DoWriteString(const wxString
& szKey
, const wxString
& szValue
)
345 wxConfigPathChanger
path(this, szKey
);
346 wxString strKey
= GetPrivateKeyName(path
.Name());
348 bool bOk
= WritePrivateProfileString(m_strGroup
.wx_str(), strKey
.wx_str(),
350 m_strLocalFilename
.wx_str()) != 0;
354 wxLogLastError(wxT("WritePrivateProfileString"));
360 bool wxIniConfig::DoWriteLong(const wxString
& szKey
, long lValue
)
362 return Write(szKey
, wxString::Format(wxT("%ld"), lValue
));
365 bool wxIniConfig::DoReadBinary(const wxString
& WXUNUSED(key
),
366 wxMemoryBuffer
* WXUNUSED(buf
)) const
368 wxFAIL_MSG("not implemented");
373 bool wxIniConfig::DoWriteBinary(const wxString
& WXUNUSED(key
),
374 const wxMemoryBuffer
& WXUNUSED(buf
))
376 wxFAIL_MSG("not implemented");
381 bool wxIniConfig::Flush(bool /* bCurrentOnly */)
383 // this is just the way it works
384 return WritePrivateProfileString(NULL
, NULL
, NULL
,
385 m_strLocalFilename
.wx_str()) != 0;
388 // ----------------------------------------------------------------------------
390 // ----------------------------------------------------------------------------
392 bool wxIniConfig::DeleteEntry(const wxString
& szKey
, bool bGroupIfEmptyAlso
)
394 // passing NULL as value to WritePrivateProfileString deletes the key
395 wxConfigPathChanger
path(this, szKey
);
396 wxString strKey
= GetPrivateKeyName(path
.Name());
398 if (WritePrivateProfileString(m_strGroup
.wx_str(), strKey
.wx_str(),
399 NULL
, m_strLocalFilename
.wx_str()) == 0)
402 if ( !bGroupIfEmptyAlso
|| !IsEmpty() )
405 // delete the current group too
406 bool bOk
= WritePrivateProfileString(m_strGroup
.wx_str(), NULL
,
407 NULL
, m_strLocalFilename
.wx_str()) != 0;
411 wxLogLastError(wxT("WritePrivateProfileString"));
417 bool wxIniConfig::DeleteGroup(const wxString
& szKey
)
419 wxConfigPathChanger
path(this, szKey
);
421 // passing NULL as section name to WritePrivateProfileString deletes the
422 // whole section according to the docs
423 bool bOk
= WritePrivateProfileString(path
.Name().wx_str(), NULL
,
424 NULL
, m_strLocalFilename
.wx_str()) != 0;
428 wxLogLastError(wxT("WritePrivateProfileString"));
438 bool wxIniConfig::DeleteAll()
440 // first delete our group in win.ini
441 WriteProfileString(GetVendorName().wx_str(), NULL
, NULL
);
443 // then delete our own ini file
444 wxChar szBuf
[MAX_PATH
];
445 size_t nRc
= GetWindowsDirectory(szBuf
, WXSIZEOF(szBuf
));
448 wxLogLastError(wxT("GetWindowsDirectory"));
450 else if ( nRc
> WXSIZEOF(szBuf
) )
452 wxFAIL_MSG(wxT("buffer is too small for Windows directory."));
455 wxString strFile
= szBuf
;
456 strFile
<< '\\' << m_strLocalFilename
;
458 if ( wxFile::Exists(strFile
) && !wxRemoveFile(strFile
) ) {
459 wxLogSysError(_("Can't delete the INI file '%s'"), strFile
.c_str());
466 bool wxIniConfig::RenameEntry(const wxString
& WXUNUSED(oldName
),
467 const wxString
& WXUNUSED(newName
))
473 bool wxIniConfig::RenameGroup(const wxString
& WXUNUSED(oldName
),
474 const wxString
& WXUNUSED(newName
))
480 #endif // wxUSE_INICONF