diff --git a/include/wx/config.h b/include/wx/config.h index 00aaf1f233..ecb4782ebb 100644 --- a/include/wx/config.h +++ b/include/wx/config.h @@ -3,16 +3,16 @@ // Purpose: declaration of the base class of all config implementations // (see also: fileconf.h and msw/regconf.h) // Author: Karsten Ballüder & Vadim Zeitlin -// Modified by: +// Modified by: // Created: 07.04.98 (adapted from appconf.h) // RCS-ID: $Id$ -// Copyright: (c) 1997 Karsten Ballüder Ballueder@usa.net +// Copyright: (c) 1997 Karsten Ballüder Ballueder@usa.net // Vadim Zeitlin // Licence: wxWindows license /////////////////////////////////////////////////////////////////////////////// -#ifndef _APPCONF_H -#define _APPCONF_H +#ifndef _wxCONFIG_H +#define _wxCONFIG_H #ifdef __GNUG__ #pragma interface "config.h" @@ -32,23 +32,26 @@ // ---------------------------------------------------------------------------- /// shall we be case sensitive in parsing variable names? -#ifndef APPCONF_CASE_SENSITIVE - #define APPCONF_CASE_SENSITIVE FALSE +#ifndef wxCONFIG_CASE_SENSITIVE + #define wxCONFIG_CASE_SENSITIVE FALSE #endif -/// separates group and entry names -#ifndef APPCONF_PATH_SEPARATOR - #define APPCONF_PATH_SEPARATOR '/' +/// separates group and entry names (probably shouldn't be changed) +#ifndef wxCONFIG_PATH_SEPARATOR + #define wxCONFIG_PATH_SEPARATOR '/' #endif /// introduces immutable entries -#ifndef APPCONF_IMMUTABLE_PREFIX - #define APPCONF_IMMUTABLE_PREFIX '!' +// (i.e. the ones which can't be changed from the local config file) +#ifndef wxCONFIG_IMMUTABLE_PREFIX + #define wxCONFIG_IMMUTABLE_PREFIX '!' #endif /// should we use registry instead of configuration files under Win32? -#ifndef APPCONF_WIN32_NATIVE - #define APPCONF_WIN32_NATIVE TRUE +// (i.e. whether wxConfig::Create() will create a wxFileConfig (if it's FALSE) or +// wxRegConfig (if it's true and we're under Win32) or wxIniConfig (Win16)) +#ifndef wxCONFIG_WIN32_NATIVE + #define wxCONFIG_WIN32_NATIVE TRUE #endif // ---------------------------------------------------------------------------- @@ -70,8 +73,8 @@ extern void wxSplitPath(wxArrayString& aParts, const char *sz); // ---------------------------------------------------------------------------- // abstract base class wxConfig which defines the interface for derived classes // -// wxConfig organizes the items in a tree-like structure (modeled after the -// Unix/Dos filesystem). There are groups (directories) and keys (files). +// wxConfig organizes the items in a tree-like structure (modeled after the +// Unix/Dos filesystem). There are groups (directories) and keys (files). // There is always one current group given by the current path. // // Keys are pairs "key_name = value" where value may be of string or integer @@ -85,16 +88,21 @@ public: static wxConfig *Set(wxConfig *pConfig); // get the config object, creates it on demand static wxConfig *Get() { if ( !ms_pConfig ) Create(); return ms_pConfig; } - // create a new config object - static void Create(); + // create a new config object: this function will create the "best" + // implementation of wxConfig available for the current platform, see + // comments near definition wxCONFIG_WIN32_NATIVE for details. It returns + // the created object and also sets it as ms_pConfig. + static wxConfig *Create(); // ctor & virtual dtor + // environment variable expansion is on by default wxConfig() { m_bExpandEnvVars = TRUE; } - virtual ~wxConfig(); + // empty but ensures that dtor of all derived classes is virtual + virtual ~wxConfig() { } // path management // set current path: if the first character is '/', it's the absolute path, - // otherwise it's a relative path. '..' is supported. If the strPath + // otherwise it's a relative path. '..' is supported. If the strPath // doesn't exist it is created. virtual void SetPath(const wxString& strPath) = 0; // retrieve the current path (always as absolute path) @@ -171,8 +179,8 @@ public: } protected: - static bool IsImmutable(const char *szKey) - { return *szKey == APPCONF_IMMUTABLE_PREFIX; } + static bool IsImmutable(const char *szKey) + { return *szKey == wxCONFIG_IMMUTABLE_PREFIX; } // a handy little class which changes current path to the path of given entry // and restores it in dtor: so if you declare a local variable of this type, @@ -186,7 +194,7 @@ protected: ~PathChanger(); // get the key name - const wxString& Name() const { return m_strName; } + const wxString& Name() const { return m_strName; } private: wxConfig *m_pContainer; // object we live in @@ -203,5 +211,5 @@ private: static wxConfig *ms_pConfig; }; -#endif //_APPCONF_H +#endif //_wxCONFIG_H diff --git a/include/wx/fileconf.h b/include/wx/fileconf.h index 4b4d1a470d..5ea1073489 100644 --- a/include/wx/fileconf.h +++ b/include/wx/fileconf.h @@ -1,17 +1,14 @@ -/*****************************************************************************\ - * Project: CppLib: C++ library for Windows/UNIX platfroms * - * File: fileconf.h - file based implementation of Config * - *---------------------------------------------------------------------------* - * Language: C++ * - * Platfrom: Any * - *---------------------------------------------------------------------------* - * Classes: * - *---------------------------------------------------------------------------* - * Author: Vadim Zeitlin zeitlin@dptmaths.ens-cachan.fr> * - * adapted from earlier class by VZ & Karsten Ballüder * - * History: * - * 27.04.98 created * -\*****************************************************************************/ +/////////////////////////////////////////////////////////////////////////////// +// Name: fileconf.h +// Purpose: wxFileConfig derivation of wxConfig +// Author: Vadim Zeitlin +// Modified by: +// Created: 07.04.98 (adapted from appconf.cpp) +// RCS-ID: $Id$ +// Copyright: (c) 1997 Karsten Ballüder & Vadim Zeitlin +// Ballueder@usa.net +// Licence: wxWindows license +/////////////////////////////////////////////////////////////////////////////// #ifndef _FILECONF_H #define _FILECONF_H @@ -83,7 +80,19 @@ and local value is ignored. Of course, the changes are always written to local file only. - @@@@ describe environment variable expansion + The names of these files can be specified in a number of ways. First of all, + you can use the standard convention: using the ctor which takes 'strAppName' + parameter will probably be sufficient for 90% of cases. If, for whatever + reason you wish to use the files with some other names, you can always use the + second ctor. + + wxFileConfig also may automatically expand the values of environment variables + in the entries it reads: for example, if you have an entry + score_file = $HOME/.score + a call to Read(&str, "score_file") will return a complete path to .score file + unless the expansion was previousle disabled with SetExpandEnvVars(FALSE) call + (it's on by default, the current status can be retrieved with + IsExpandingEnvVars function). */ class wxFileConfig : public wxConfig @@ -103,9 +112,17 @@ public: static wxString GetLocalFileName(const char *szFile); // ctor & dtor - // if strGlobal is empty, only local config file is used - wxFileConfig(const wxString& strLocal, - const wxString& strGlobal = ""); + // the names of local and global (if not disabled) config files are + // constructed using Get{Local|Global}FileName functions described above + // (szAppName is just the (short) name of your application) + wxFileConfig(const char *szAppName, bool bLocalOnly = FALSE); + // this ctor allows you to specify custom names for both files (if strGlobal + // isn't a full path, it's considered to be relative to the standard + // directory, i.e. /etc under Unix and %windir% under Windows, if strLocal + // is not an absolute path, it's considered to be relative to the user's + // directory). If either of strings is empty, the corresponding file is not + // used. + wxFileConfig(const wxString& strLocal, const wxString& strGlobal); // dtor will save unsaved data virtual ~wxFileConfig(); @@ -176,9 +193,17 @@ public: bool LineListIsEmpty(); private: - // put the object in the initial state + // GetXXXFileame helpers: return ('/' terminated) directory names + static wxString GetGlobalDir(); + static wxString GetLocalDir(); + + // common part of all ctors (assumes that m_str{Local|Global}File are already + // initialized void Init(); + // common part of from dtor and DeleteAll + void CleanUp(); + // parse the whole file void Parse(wxTextFile& file, bool bLocal); diff --git a/src/common/config.cpp b/src/common/config.cpp index d2cc81d6c1..f9d449b7f2 100644 --- a/src/common/config.cpp +++ b/src/common/config.cpp @@ -37,9 +37,19 @@ #include #include #include -#include -#include +// we must include (one of) these files for wxConfig::Create +#if defined(__MSWIN__) && defined(wxCONFIG_WIN32_NATIVE) + #ifdef __WIN32__ + #include + #else //WIN16 + #include + #endif +#else // either we're under Unix or wish to use files even under Windows + #include +#endif + +#include #include // for isalnum() // ---------------------------------------------------------------------------- @@ -55,9 +65,6 @@ wxConfig *wxConfig::ms_pConfig = NULL; // ---------------------------------------------------------------------------- // wxConfig // ---------------------------------------------------------------------------- -wxConfig::~wxConfig() -{ -} wxConfig *wxConfig::Set(wxConfig *pConfig) { @@ -66,9 +73,19 @@ wxConfig *wxConfig::Set(wxConfig *pConfig) return pOld; } -void wxConfig::Create() +wxConfig *wxConfig::Create() { - ms_pConfig = wxTheApp->CreateConfig(); + return ms_pConfig = +#if defined(__MSWIN__) && defined(wxCONFIG_WIN32_NATIVE) + #ifdef __WIN32__ + new wxRegConfig(wxTheApp->GetAppName(), wxTheApp->GetVendorName()); + #else //WIN16 + #error "Sorry, no wxIniConfig yet..." + //new wxIniConfig(wxTheApp->GetAppName(), wxTheApp->GetVendorName()); + #endif +#else // either we're under Unix or wish to use files even under Windows + new wxFileConfig(wxTheApp->GetAppName()); +#endif } const char *wxConfig::Read(const char *szKey, const char *szDefault) const @@ -89,18 +106,18 @@ wxConfig::PathChanger::PathChanger(const wxConfig *pContainer, const wxString& strEntry) { m_pContainer = (wxConfig *)pContainer; - wxString strPath = strEntry.Before(APPCONF_PATH_SEPARATOR); + wxString strPath = strEntry.Before(wxCONFIG_PATH_SEPARATOR); // special case of "/keyname" when there is nothing before "/" - if ( strPath.IsEmpty() && strEntry[0] == APPCONF_PATH_SEPARATOR ) - strPath = APPCONF_PATH_SEPARATOR; + if ( strPath.IsEmpty() && strEntry[0] == wxCONFIG_PATH_SEPARATOR ) + strPath = wxCONFIG_PATH_SEPARATOR; if ( !strPath.IsEmpty() ) { // do change the path m_bChanged = TRUE; - m_strName = strEntry.Right(APPCONF_PATH_SEPARATOR); + m_strName = strEntry.Right(wxCONFIG_PATH_SEPARATOR); m_strOldPath = m_pContainer->GetPath(); - m_strOldPath += APPCONF_PATH_SEPARATOR; + m_strOldPath += wxCONFIG_PATH_SEPARATOR; m_pContainer->SetPath(strPath); } else { @@ -231,7 +248,7 @@ void wxSplitPath(wxArrayString& aParts, const char *sz) wxString strCurrent; const char *pc = sz; for ( ;; ) { - if ( *pc == '\0' || *pc == APPCONF_PATH_SEPARATOR ) { + if ( *pc == '\0' || *pc == wxCONFIG_PATH_SEPARATOR ) { if ( strCurrent == "." ) { // ignore } diff --git a/src/common/fileconf.cpp b/src/common/fileconf.cpp index 5ae5d75b8a..ae3f3087dc 100644 --- a/src/common/fileconf.cpp +++ b/src/common/fileconf.cpp @@ -58,7 +58,7 @@ // ---------------------------------------------------------------------------- // is 'c' a valid character in group name? -// NB: APPCONF_IMMUTABLE_PREFIX and APPCONF_PATH_SEPARATOR must be valid chars, +// NB: wxCONFIG_IMMUTABLE_PREFIX and wxCONFIG_PATH_SEPARATOR must be valid chars, // but _not_ ']' (group name delimiter) inline bool IsValid(char c) { return isalnum(c) || strchr("@_/-!.*%", c); } @@ -79,26 +79,67 @@ static wxString FilterOut(const wxString& str); // ---------------------------------------------------------------------------- // static functions // ---------------------------------------------------------------------------- -wxString wxFileConfig::GetGlobalFileName(const char *szFile) +wxString wxFileConfig::GetGlobalDir() { - wxString str; + wxString strDir; - bool bNoExt = strchr(szFile, '.') == NULL; - - #ifdef __UNIX__ - str << "/etc/" << szFile; - if ( bNoExt ) - str << ".conf"; - #else // Windows + #ifdef __UNIX__ + strDir = "/etc/"; + #else // Windows #ifndef _MAX_PATH #define _MAX_PATH 512 #endif char szWinDir[_MAX_PATH]; ::GetWindowsDirectory(szWinDir, _MAX_PATH); - str << szWinDir << "\\" << szFile; - if ( bNoExt ) - str << ".ini"; + + strDir = szWinDir; + strDir << '\\'; + #endif // Unix/Windows + + return strDir; +} + +wxString wxFileConfig::GetLocalDir() +{ + wxString strDir; + + #ifdef __UNIX__ + const char *szHome = getenv("HOME"); + if ( szHome == NULL ) { + // we're homeless... + wxLogWarning(_("can't find user's HOME, using current directory.")); + strDir = "."; + } + else + strDir = szHome; + #else // Windows + #ifdef __WIN32__ + const char *szHome = getenv("HOMEDRIVE"); + if ( szHome != NULL ) + strDir << szHome; + szHome = getenv("HOMEPATH"); + if ( szHome != NULL ) + strDir << szHome; + #else // Win16 + // Win16 has no idea about home, so use the current directory instead + strDir = ".\\"; + #endif // WIN16/32 + #endif // UNIX/Win + + return strDir; +} + +wxString wxFileConfig::GetGlobalFileName(const char *szFile) +{ + wxString str = GetLocalDir(); + str << szFile; + + if ( strchr(szFile, '.') == NULL ) + #ifdef __UNIX__ + str << ".conf"; + #else // Windows + str << ".ini"; #endif // UNIX/Win return str; @@ -106,32 +147,17 @@ wxString wxFileConfig::GetGlobalFileName(const char *szFile) wxString wxFileConfig::GetLocalFileName(const char *szFile) { - wxString str; + wxString str = GetLocalDir(); #ifdef __UNIX__ - const char *szHome = getenv("HOME"); - if ( szHome == NULL ) { - // we're homeless... - wxLogWarning(_("can't find user's HOME, using current directory.")); - szHome = "."; - } - str << szHome << "/." << szFile; - #else // Windows - #ifdef __WIN32__ - const char *szHome = getenv("HOMEDRIVE"); - if ( szHome != NULL ) - str << szHome; - szHome = getenv("HOMEPATH"); - if ( szHome != NULL ) - str << szHome; - str << szFile; - if ( strchr(szFile, '.') == NULL ) - str << ".ini"; - #else // Win16 - // Win16 has no idea about home, so use the current directory instead - str << ".\\" << szFile; - #endif // WIN16/32 - #endif // UNIX/Win + str << '.'; + #endif + + str << szFile; + + #ifdef __WXMSW__ + str << ".ini"; + #endif return str; } @@ -148,47 +174,64 @@ void wxFileConfig::Init() m_linesHead = m_linesTail = NULL; - m_strPath.Empty(); -} - -wxFileConfig::wxFileConfig(const wxString& strLocal, const wxString& strGlobal) - : m_strLocalFile(strLocal), m_strGlobalFile(strGlobal) -{ - Init(); - // it's not an error if (one of the) file(s) doesn't exist // parse the global file - if ( !strGlobal.IsEmpty() ) { - if ( wxFile::Exists(strGlobal) ) { - wxTextFile fileGlobal(strGlobal); + if ( !m_strGlobalFile.IsEmpty() && wxFile::Exists(m_strGlobalFile) ) { + wxTextFile fileGlobal(m_strGlobalFile); - if ( fileGlobal.Open() ) { - Parse(fileGlobal, FALSE /* global */); - SetRootPath(); - } - else - wxLogWarning(_("can't open global configuration file '%s'."), - strGlobal.c_str()); + if ( fileGlobal.Open() ) { + Parse(fileGlobal, FALSE /* global */); + SetRootPath(); } + else + wxLogWarning(_("can't open global configuration file '%s'."), + m_strGlobalFile.c_str()); } // parse the local file - if ( wxFile::Exists(strLocal) ) { - wxTextFile fileLocal(strLocal); + if ( !m_strLocalFile.IsEmpty() && wxFile::Exists(m_strLocalFile) ) { + wxTextFile fileLocal(m_strLocalFile); if ( fileLocal.Open() ) { Parse(fileLocal, TRUE /* local */); SetRootPath(); } else wxLogWarning(_("can't open user configuration file '%s'."), - strLocal.c_str()); + m_strLocalFile.c_str()); } } -wxFileConfig::~wxFileConfig() +wxFileConfig::wxFileConfig(const char *szAppName, bool bLocalOnly) +{ + wxASSERT( !IsEmpty(szAppName) ); // invent a name for your application! + + m_strLocalFile = GetLocalFileName(szAppName); + if ( !bLocalOnly ) + m_strGlobalFile = GetGlobalFileName(szAppName); + //else: it's going to be empty and we won't use the global file + + Init(); +} + +wxFileConfig::wxFileConfig(const wxString& strLocal, const wxString& strGlobal) + : m_strLocalFile(strLocal), m_strGlobalFile(strGlobal) +{ + // if the path is not absolute, prepend the standard directory to it + + if ( !strLocal.IsEmpty() && !wxIsPathSeparator(strLocal[0u]) ) + m_strLocalFile = GetLocalDir(); + m_strLocalFile << strLocal; + + if ( !strGlobal.IsEmpty() && !wxIsPathSeparator(strGlobal[0u]) ) + m_strGlobalFile = GetGlobalDir(); + m_strGlobalFile << strGlobal; + + Init(); +} + +void wxFileConfig::CleanUp() { - Flush(); delete m_pRootGroup; LineList *pCur = m_linesHead; @@ -199,6 +242,13 @@ wxFileConfig::~wxFileConfig() } } +wxFileConfig::~wxFileConfig() +{ + Flush(); + + CleanUp(); +} + // ---------------------------------------------------------------------------- // parse a config file // ---------------------------------------------------------------------------- @@ -242,7 +292,7 @@ void wxFileConfig::Parse(wxTextFile& file, bool bLocal) // group name here is always considered as abs path wxString strGroup; pStart++; - strGroup << APPCONF_PATH_SEPARATOR << wxString(pStart, pEnd - pStart); + strGroup << wxCONFIG_PATH_SEPARATOR << wxString(pStart, pEnd - pStart); // will create it if doesn't yet exist SetPath(strGroup); @@ -349,14 +399,14 @@ void wxFileConfig::SetPath(const wxString& strPath) return; } - if ( strPath[0] == APPCONF_PATH_SEPARATOR ) { + if ( strPath[0] == wxCONFIG_PATH_SEPARATOR ) { // absolute path wxSplitPath(aParts, strPath); } else { // relative path, combine with current one wxString strFullPath = m_strPath; - strFullPath << APPCONF_PATH_SEPARATOR << strPath; + strFullPath << wxCONFIG_PATH_SEPARATOR << strPath; wxSplitPath(aParts, strFullPath); } @@ -373,7 +423,7 @@ void wxFileConfig::SetPath(const wxString& strPath) // recombine path parts in one variable m_strPath.Empty(); for ( n = 0; n < aParts.Count(); n++ ) { - m_strPath << APPCONF_PATH_SEPARATOR << aParts[n]; + m_strPath << wxCONFIG_PATH_SEPARATOR << aParts[n]; } } @@ -527,9 +577,9 @@ bool wxFileConfig::Write(const char *szKey, const char *szValue) // writing an entry // check that the name is reasonable - if ( strName[0u] == APPCONF_IMMUTABLE_PREFIX ) { + if ( strName[0u] == wxCONFIG_IMMUTABLE_PREFIX ) { wxLogError(_("Entry name can't start with '%c'."), - APPCONF_IMMUTABLE_PREFIX); + wxCONFIG_IMMUTABLE_PREFIX); return FALSE; } @@ -614,10 +664,13 @@ bool wxFileConfig::DeleteGroup(const char *szKey) bool wxFileConfig::DeleteAll() { - const char *szFile = m_strLocalFile; - delete m_pRootGroup; + CleanUp(); + + m_strLocalFile = m_strGlobalFile = ""; Init(); + const char *szFile = m_strLocalFile; + if ( remove(szFile) == -1 ) wxLogSysError(_("can't delete user configuration file '%s'"), szFile); @@ -849,7 +902,7 @@ wxFileConfig::LineList *wxFileConfig::ConfigGroup::GetLastEntryLine() wxString wxFileConfig::ConfigGroup::GetFullName() const { if ( Parent() ) - return Parent()->GetFullName() + APPCONF_PATH_SEPARATOR + Name(); + return Parent()->GetFullName() + wxCONFIG_PATH_SEPARATOR + Name(); else return ""; } @@ -872,7 +925,7 @@ wxFileConfig::ConfigGroup::FindEntry(const char *szName) const i = (lo + hi)/2; pEntry = m_aEntries[i]; - #if APPCONF_CASE_SENSITIVE + #if wxCONFIG_CASE_SENSITIVE res = strcmp(pEntry->Name(), szName); #else res = Stricmp(pEntry->Name(), szName); @@ -902,7 +955,7 @@ wxFileConfig::ConfigGroup::FindSubgroup(const char *szName) const i = (lo + hi)/2; pGroup = m_aSubgroups[i]; - #if APPCONF_CASE_SENSITIVE + #if wxCONFIG_CASE_SENSITIVE res = strcmp(pGroup->Name(), szName); #else res = Stricmp(pGroup->Name(), szName); @@ -1097,7 +1150,7 @@ wxFileConfig::ConfigEntry::ConfigEntry(wxFileConfig::ConfigGroup *pParent, m_bDirty = FALSE; - m_bImmutable = strName[0] == APPCONF_IMMUTABLE_PREFIX; + m_bImmutable = strName[0] == wxCONFIG_IMMUTABLE_PREFIX; if ( m_bImmutable ) m_strName.erase(0, 1); // remove first character } @@ -1172,7 +1225,7 @@ void wxFileConfig::ConfigEntry::SetDirty() int CompareEntries(wxFileConfig::ConfigEntry *p1, wxFileConfig::ConfigEntry *p2) { - #if APPCONF_CASE_SENSITIVE + #if wxCONFIG_CASE_SENSITIVE return strcmp(p1->Name(), p2->Name()); #else return Stricmp(p1->Name(), p2->Name()); @@ -1182,7 +1235,7 @@ int CompareEntries(wxFileConfig::ConfigEntry *p1, int CompareGroups(wxFileConfig::ConfigGroup *p1, wxFileConfig::ConfigGroup *p2) { - #if APPCONF_CASE_SENSITIVE + #if wxCONFIG_CASE_SENSITIVE return strcmp(p1->Name(), p2->Name()); #else return Stricmp(p1->Name(), p2->Name());