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 54wxIniConfig::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 93wxIniConfig::~wxIniConfig() 94{ 95} 96 97// ---------------------------------------------------------------------------- 98// path management 99// ---------------------------------------------------------------------------- 100 101void 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 142const 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 164wxString 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 176wxString 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 195bool wxIniConfig::GetFirstGroup(wxString& WXUNUSED(str), long& WXUNUSED(lIndex)) const 196{ 197 wxFAIL_MSG("not implemented"); 198 199 return false; 200} 201 202bool wxIniConfig::GetNextGroup (wxString& WXUNUSED(str), long& WXUNUSED(lIndex)) const 203{ 204 wxFAIL_MSG("not implemented"); 205 206 return false; 207} 208 209bool wxIniConfig::GetFirstEntry(wxString& WXUNUSED(str), long& WXUNUSED(lIndex)) const 210{ 211 wxFAIL_MSG("not implemented"); 212 213 return false; 214} 215 216bool 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 228size_t wxIniConfig::GetNumberOfEntries(bool WXUNUSED(bRecursive)) const 229{ 230 wxFAIL_MSG("not implemented"); 231 232 return (size_t)-1; 233} 234 235size_t wxIniConfig::GetNumberOfGroups(bool WXUNUSED(bRecursive)) const 236{ 237 wxFAIL_MSG("not implemented"); 238 239 return (size_t)-1; 240} 241 242bool wxIniConfig::HasGroup(const wxString& WXUNUSED(strName)) const 243{ 244 wxFAIL_MSG("not implemented"); 245 246 return false; 247} 248 249bool wxIniConfig::HasEntry(const wxString& WXUNUSED(strName)) const 250{ 251 wxFAIL_MSG("not implemented"); 252 253 return false; 254} 255 256// is current group empty? 257bool 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 277bool 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 302bool 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 339bool 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 353bool 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 362bool 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 372bool 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 395bool 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 414bool 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 442bool wxIniConfig::RenameEntry(const wxString& WXUNUSED(oldName), 443 const wxString& WXUNUSED(newName)) 444{ 445 // Not implemented 446 return false; 447} 448 449bool 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