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: iniconf.cpp 41054 2006-09-07 19:01:45Z ABX $
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 
wxIniConfig(const wxString & strAppName,const wxString & strVendor,const wxString & localFilename,const wxString & globalFilename,long style)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 
~wxIniConfig()93 wxIniConfig::~wxIniConfig()
94 {
95 }
96 
97 // ----------------------------------------------------------------------------
98 // path management
99 // ----------------------------------------------------------------------------
100 
SetPath(const wxString & strPath)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 
GetPath() const142 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 
GetPrivateKeyName(const wxString & szKey) const164 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 
GetKeyName(const wxString & szKey) const176 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
GetFirstGroup(wxString & WXUNUSED (str),long & WXUNUSED (lIndex)) const195 bool wxIniConfig::GetFirstGroup(wxString& WXUNUSED(str), long& WXUNUSED(lIndex)) const
196 {
197     wxFAIL_MSG("not implemented");
198 
199     return false;
200 }
201 
GetNextGroup(wxString & WXUNUSED (str),long & WXUNUSED (lIndex)) const202 bool wxIniConfig::GetNextGroup (wxString& WXUNUSED(str), long& WXUNUSED(lIndex)) const
203 {
204     wxFAIL_MSG("not implemented");
205 
206     return false;
207 }
208 
GetFirstEntry(wxString & WXUNUSED (str),long & WXUNUSED (lIndex)) const209 bool wxIniConfig::GetFirstEntry(wxString& WXUNUSED(str), long& WXUNUSED(lIndex)) const
210 {
211     wxFAIL_MSG("not implemented");
212 
213     return false;
214 }
215 
GetNextEntry(wxString & WXUNUSED (str),long & WXUNUSED (lIndex)) const216 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
GetNumberOfEntries(bool WXUNUSED (bRecursive)) const228 size_t wxIniConfig::GetNumberOfEntries(bool WXUNUSED(bRecursive)) const
229 {
230     wxFAIL_MSG("not implemented");
231 
232     return (size_t)-1;
233 }
234 
GetNumberOfGroups(bool WXUNUSED (bRecursive)) const235 size_t wxIniConfig::GetNumberOfGroups(bool WXUNUSED(bRecursive)) const
236 {
237     wxFAIL_MSG("not implemented");
238 
239     return (size_t)-1;
240 }
241 
HasGroup(const wxString & WXUNUSED (strName)) const242 bool wxIniConfig::HasGroup(const wxString& WXUNUSED(strName)) const
243 {
244     wxFAIL_MSG("not implemented");
245 
246     return false;
247 }
248 
HasEntry(const wxString & WXUNUSED (strName)) const249 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?
IsEmpty() const257 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 
DoReadString(const wxString & szKey,wxString * pstr) const277 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 
DoReadLong(const wxString & szKey,long * pl) const302 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 
DoWriteString(const wxString & szKey,const wxString & szValue)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 
DoWriteLong(const wxString & szKey,long lValue)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 
Flush(bool)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 
DeleteEntry(const wxString & szKey,bool bGroupIfEmptyAlso)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 
DeleteGroup(const wxString & szKey)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 
DeleteAll()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 
RenameEntry(const wxString & WXUNUSED (oldName),const wxString & WXUNUSED (newName))442 bool wxIniConfig::RenameEntry(const wxString& WXUNUSED(oldName),
443                               const wxString& WXUNUSED(newName))
444 {
445     // Not implemented
446     return false;
447 }
448 
RenameGroup(const wxString & WXUNUSED (oldName),const wxString & WXUNUSED (newName))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
458