wxFileConfig now has it's own header, the config file name may be given to

it's ctor (and not hard coded). Static wxFileConfig methods
Get{Global|Local}FileName can be used to retrieve the standard config file
path.


git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@32 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin
1998-05-26 15:07:48 +00:00
parent 61b027446e
commit 1f905dc575
2 changed files with 387 additions and 425 deletions

269
include/wx/fileconf.h Normal file
View File

@@ -0,0 +1,269 @@
/*****************************************************************************\
* 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<6C>der *
* History: *
* 27.04.98 created *
\*****************************************************************************/
#ifndef _FILECONF_H
#define _FILECONF_H
// ----------------------------------------------------------------------------
// wxFileConfig
// ----------------------------------------------------------------------------
/*
wxFileConfig derives from base Config and implements file based config class,
i.e. it uses ASCII disk files to store the information. These files are
alternatively called INI, .conf or .rc in the documentation. They are
organized in groups or sections, which can nest (i.e. a group contains
subgroups, which contain their own subgroups &c). Each group has some
number of entries, which are "key = value" pairs. More precisely, the format
is:
# comments are allowed after either ';' or '#' (Win/UNIX standard)
# blank lines (as above) are ignored
# global entries are members of special (no name) top group
written_for = Windows
platform = Linux
# the start of the group 'Foo'
[Foo] # may put comments like this also
# following 3 lines are entries
key = value
another_key = " strings with spaces in the beginning should be quoted, \
otherwise the spaces are lost"
last_key = but you don't have to put " normally (nor quote them, like here)
# subgroup of the group 'Foo'
# (order is not important, only the name is: separator is '/', as in paths)
[Foo/Bar]
# entries prefixed with "!" are immutable, i.e. can't be changed if they are
# set in the system-wide config file
!special_key = value
bar_entry = whatever
[Foo/Bar/Fubar] # depth is (theoretically :-) unlimited
# may have the same name as key in another section
bar_entry = whatever not
You have {read/write/delete}Entry functions (guess what they do) and also
setCurrentPath to select current group. enum{Subgroups/Entries} allow you
to get all entries in the config file (in the current group). Finally,
flush() writes immediately all changed entries to disk (otherwise it would
be done automatically in dtor)
wxFileConfig manages not less than 2 config files for each program: global
and local (or system and user if you prefer). Entries are read from both of
them and the local entries override the global ones unless the latter is
immutable (prefixed with '!') in which case a warning message is generated
and local value is ignored. Of course, the changes are always written to local
file only.
@@@@ describe environment variable expansion
*/
class wxFileConfig : public wxConfig
{
public:
// construct the "standard" full name for global (system-wide) and
// local (user-specific) config files from the base file name.
//
// the following are the filenames returned by this functions:
// global local
// Unix /etc/file.ext ~/.file
// Win %windir%\file.ext %USERPROFILE%\file.ext
//
// where file is the basename of szFile, ext is it's extension
// or .conf (Unix) or .ini (Win) if it has none
static wxString GetGlobalFileName(const char *szFile);
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 = "");
// dtor will save unsaved data
virtual ~wxFileConfig();
// implement inherited pure virtual functions
virtual void SetPath(const wxString& strPath);
virtual const wxString& GetPath() const { return m_strPath; }
virtual bool GetFirstGroup(wxString& str, long& lIndex);
virtual bool GetNextGroup (wxString& str, long& lIndex);
virtual bool GetFirstEntry(wxString& str, long& lIndex);
virtual bool GetNextEntry (wxString& str, long& lIndex);
virtual bool Read(wxString *pstr, const char *szKey,
const char *szDefault = 0) const;
virtual const char *Read(const char *szKey,
const char *szDefault = 0) const;
virtual bool Read(long *pl, const char *szKey, long lDefault) const;
virtual bool Write(const char *szKey, const char *szValue);
virtual bool Write(const char *szKey, long lValue);
virtual bool Flush(bool bCurrentOnly = FALSE);
virtual bool DeleteEntry(const char *szKey, bool bGroupIfEmptyAlso);
virtual bool DeleteGroup(const char *szKey);
virtual bool DeleteAll();
public:
// fwd decl
class ConfigGroup;
class ConfigEntry;
// we store all lines of the local config file as a linked list in memory
class LineList
{
public:
// ctor
LineList(const wxString& str, LineList *pNext = NULL) : m_strLine(str)
{ SetNext(pNext); }
//
LineList *Next() const { return m_pNext; }
void SetNext(LineList *pNext) { m_pNext = pNext; }
//
void SetText(const wxString& str) { m_strLine = str; }
const wxString& Text() const { return m_strLine; }
private:
wxString m_strLine; // line contents
LineList *m_pNext; // next node
};
// functions to work with this list
LineList *LineListAppend(const wxString& str);
LineList *LineListInsert(const wxString& str,
LineList *pLine); // NULL => Append()
bool LineListIsEmpty();
private:
// put the object in the initial state
void Init();
// parse the whole file
void Parse(wxTextFile& file, bool bLocal);
// the same as SetPath("/")
void SetRootPath();
// member variables
// ----------------
LineList *m_linesHead, // head of the linked list
*m_linesTail; // tail
wxString m_strLocalFile, // local file name passed to ctor
m_strGlobalFile; // global
wxString m_strPath; // current path (not '/' terminated)
ConfigGroup *m_pRootGroup, // the top (unnamed) group
*m_pCurrentGroup; // the current group
//protected: --- if wxFileConfig::ConfigEntry is not public, functions in
// ConfigGroup such as Find/AddEntry can't return "ConfigEntry *"
public:
WX_DEFINE_ARRAY(ConfigEntry *, ArrayEntries);
WX_DEFINE_ARRAY(ConfigGroup *, ArrayGroups);
class ConfigEntry
{
private:
ConfigGroup *m_pParent; // group that contains us
wxString m_strName, // entry name
m_strValue; // value
bool m_bDirty, // changed since last read?
m_bImmutable; // can be overriden locally?
int m_nLine; // used if m_pLine == NULL only
LineList *m_pLine; // pointer to our line in the linked list
// or NULL if it was found in global file
public:
ConfigEntry(ConfigGroup *pParent, const wxString& strName, int nLine);
// simple accessors
const wxString& Name() const { return m_strName; }
const wxString& Value() const { return m_strValue; }
ConfigGroup *Group() const { return m_pParent; }
bool IsDirty() const { return m_bDirty; }
bool IsImmutable() const { return m_bImmutable; }
bool IsLocal() const { return m_pLine != 0; }
int Line() const { return m_nLine; }
LineList *GetLine() const { return m_pLine; }
// modify entry attributes
void SetValue(const wxString& strValue, bool bUser = TRUE);
void SetDirty();
void SetLine(LineList *pLine);
};
protected:
class ConfigGroup
{
private:
wxFileConfig *m_pConfig; // config object we belong to
ConfigGroup *m_pParent; // parent group (NULL for root group)
ArrayEntries m_aEntries; // entries in this group
ArrayGroups m_aSubgroups; // subgroups
wxString m_strName; // group's name
bool m_bDirty; // if FALSE => all subgroups are not dirty
LineList *m_pLine; // pointer to our line in the linked list
int m_nLastEntry, // last here means "last added"
m_nLastGroup; //
public:
// ctor
ConfigGroup(ConfigGroup *pParent, const wxString& strName, wxFileConfig *);
// dtor deletes all entries and subgroups also
~ConfigGroup();
// simple accessors
const wxString& Name() const { return m_strName; }
ConfigGroup *Parent() const { return m_pParent; }
wxFileConfig *Config() const { return m_pConfig; }
bool IsDirty() const { return m_bDirty; }
bool IsEmpty() const { return Entries().IsEmpty() && Groups().IsEmpty(); }
const ArrayEntries& Entries() const { return m_aEntries; }
const ArrayGroups& Groups() const { return m_aSubgroups; }
// find entry/subgroup (NULL if not found)
ConfigGroup *FindSubgroup(const char *szName) const;
ConfigEntry *FindEntry (const char *szName) const;
// delete entry/subgroup, return FALSE if doesn't exist
bool DeleteSubgroup(const char *szName);
bool DeleteEntry(const char *szName);
// create new entry/subgroup returning pointer to newly created element
ConfigGroup *AddSubgroup(const wxString& strName);
ConfigEntry *AddEntry (const wxString& strName, int nLine = NOT_FOUND);
// will also recursively set parent's dirty flag
void SetDirty();
void SetLine(LineList *pLine);
wxString GetFullName() const;
// get the last line belonging to an entry/subgroup of this group
LineList *GetGroupLine();
LineList *GetLastEntryLine();
LineList *GetLastGroupLine();
};
};
#endif //_FILECONF_H

View File

@@ -33,10 +33,13 @@
#include <wx/log.h> #include <wx/log.h>
#include <wx/textfile.h> #include <wx/textfile.h>
#include <wx/config.h> #include <wx/config.h>
#include <wx/fileconf.h>
#ifdef __WINDOWS__ // _WINDOWS_ is defined when windows.h is included,
#include <windows.h> // __WINDOWS__ is defined for MS Windows compilation
#endif #if defined(__WINDOWS__) && !defined(_WINDOWS_)
#include <windows.h>
#endif //windows.h
#include <stdlib.h> #include <stdlib.h>
#include <ctype.h> #include <ctype.h>
@@ -50,277 +53,74 @@
// but _not_ ']' (group name delimiter) // but _not_ ']' (group name delimiter)
inline bool IsValid(char c) { return isalnum(c) || strchr("_/-!.*%", c); } inline bool IsValid(char c) { return isalnum(c) || strchr("_/-!.*%", c); }
// get the system wide and user configuration file full path
static const char *GetGlobalFileName(const char *szFile);
static const char *GetLocalFileName(const char *szFile);
// split path into parts removing '..' in progress
static void SplitPath(wxArrayString& aParts, const char *sz);
// filter strings // filter strings
static wxString FilterIn(const wxString& str); static wxString FilterIn(const wxString& str);
static wxString FilterOut(const wxString& str); static wxString FilterOut(const wxString& str);
// ----------------------------------------------------------------------------
// wxFileConfig
// ----------------------------------------------------------------------------
/*
FileConfig derives from BaseConfig and implements file based config class,
i.e. it uses ASCII disk files to store the information. These files are
alternatively called INI, .conf or .rc in the documentation. They are
organized in groups or sections, which can nest (i.e. a group contains
subgroups, which contain their own subgroups &c). Each group has some
number of entries, which are "key = value" pairs. More precisely, the format
is:
# comments are allowed after either ';' or '#' (Win/UNIX standard)
# blank lines (as above) are ignored
# global entries are members of special (no name) top group
written_for = wxWindows
platform = Linux
# the start of the group 'Foo'
[Foo] # may put comments like this also
# following 3 lines are entries
key = value
another_key = " strings with spaces in the beginning should be quoted, \
otherwise the spaces are lost"
last_key = but you don't have to put " normally (nor quote them, like here)
# subgroup of the group 'Foo'
# (order is not important, only the name is: separator is '/', as in paths)
[Foo/Bar]
# entries prefixed with "!" are immutable, i.e. can't be changed if they are
# set in the system-wide config file
!special_key = value
bar_entry = whatever
[Foo/Bar/Fubar] # depth is (theoretically :-) unlimited
# may have the same name as key in another section
bar_entry = whatever not
You have {read/write/delete}Entry functions (guess what they do) and also
setCurrentPath to select current group. enum{Subgroups/Entries} allow you
to get all entries in the config file (in the current group). Finally,
flush() writes immediately all changed entries to disk (otherwise it would
be done automatically in dtor)
FileConfig manages not less than 2 config files for each program: global
and local (or system and user if you prefer). Entries are read from both of
them and the local entries override the global ones unless the latter is
immutable (prefixed with '!') in which case a warning message is generated
and local value is ignored. Of course, the changes are always written to local
file only.
*/
class wxFileConfig : public wxConfig
{
public:
// ctor & dtor
// the config file is searched in the following locations
// global local
// Unix /etc/file.ext ~/.file
// Win %windir%\file.ext %USERPROFILE%\file.ext
//
// where file is the basename of strFile, ext is it's extension
// or .conf (Unix) or .ini (Win) if it has none
wxFileConfig(const wxString& strFile, bool bLocalOnly = FALSE);
// dtor will save unsaved data
virtual ~wxFileConfig();
// implement inherited pure virtual functions
virtual void SetPath(const wxString& strPath);
virtual const wxString& GetPath() const { return m_strPath; }
virtual bool GetFirstGroup(wxString& str, long& lIndex);
virtual bool GetNextGroup (wxString& str, long& lIndex);
virtual bool GetFirstEntry(wxString& str, long& lIndex);
virtual bool GetNextEntry (wxString& str, long& lIndex);
virtual const char *Read(const char *szKey, const char *szDefault = 0) const;
virtual long Read(const char *szKey, long lDefault) const;
virtual bool Write(const char *szKey, const char *szValue);
virtual bool Write(const char *szKey, long Value);
virtual bool Flush(bool bCurrentOnly = FALSE);
virtual bool DeleteEntry(const char *szKey, bool bGroupIfEmptyAlso);
virtual bool DeleteGroup(const char *szKey);
virtual bool DeleteAll();
public:
// fwd decl
class ConfigGroup;
class ConfigEntry;
// we store all lines of the local config file as a linked list in memory
class LineList
{
public:
// ctor
LineList(const wxString& str, LineList *pNext = NULL) : m_strLine(str)
{ SetNext(pNext); }
//
LineList *Next() const { return m_pNext; }
void SetNext(LineList *pNext) { m_pNext = pNext; }
//
void SetText(const wxString& str) { m_strLine = str; }
const wxString& Text() const { return m_strLine; }
private:
wxString m_strLine; // line contents
LineList *m_pNext; // next node
};
// functions to work with this list
LineList *LineListAppend(const wxString& str);
LineList *LineListInsert(const wxString& str,
LineList *pLine); // NULL => Append()
bool LineListIsEmpty();
private:
// put the object in the initial state
void Init();
// parse the whole file
void Parse(wxTextFile& file, bool bLocal);
// the same as SetPath("/")
void SetRootPath();
// member variables
// ----------------
LineList *m_linesHead, // head of the linked list
*m_linesTail; // tail
wxString m_strFile; // file name passed to ctor
wxString m_strPath; // current path (not '/' terminated)
ConfigGroup *m_pRootGroup, // the top (unnamed) group
*m_pCurrentGroup; // the current group
// 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,
// you work in the entry directory and the path is automatically restored
// when function returns
class PathChanger
{
public:
// ctor/dtor do path changing/restorin
PathChanger(const wxFileConfig *pContainer, const wxString& strEntry);
~PathChanger();
// get the key name
const wxString& Name() const { return m_strName; }
private:
wxFileConfig *m_pContainer; // object we live in
wxString m_strName, // name of entry (i.e. name only)
m_strOldPath; // saved path
bool m_bChanged; // was the path changed?
};
//protected: --- if FileConfig::ConfigEntry is not public, functions in
// ConfigGroup such as Find/AddEntry can't return "ConfigEntry *"
public:
WX_DEFINE_ARRAY(ConfigEntry *, ArrayEntries);
WX_DEFINE_ARRAY(ConfigGroup *, ArrayGroups);
class ConfigEntry
{
private:
ConfigGroup *m_pParent; // group that contains us
wxString m_strName, // entry name
m_strValue; // value
bool m_bDirty, // changed since last read?
m_bImmutable; // can be overriden locally?
int m_nLine; // used if m_pLine == NULL only
LineList *m_pLine; // pointer to our line in the linked list
// or NULL if it was found in global file
public:
ConfigEntry(ConfigGroup *pParent, const wxString& strName, int nLine);
// simple accessors
const wxString& Name() const { return m_strName; }
const wxString& Value() const { return m_strValue; }
ConfigGroup *Group() const { return m_pParent; }
bool IsDirty() const { return m_bDirty; }
bool IsImmutable() const { return m_bImmutable; }
bool IsLocal() const { return m_pLine != 0; }
int Line() const { return m_nLine; }
LineList *GetLine() const { return m_pLine; }
// modify entry attributes
void SetValue(const wxString& strValue, bool bUser = TRUE);
void SetDirty();
void SetLine(LineList *pLine);
};
protected:
class ConfigGroup
{
private:
wxFileConfig *m_pConfig; // config object we belong to
ConfigGroup *m_pParent; // parent group (NULL for root group)
ArrayEntries m_aEntries; // entries in this group
ArrayGroups m_aSubgroups; // subgroups
wxString m_strName; // group's name
bool m_bDirty; // if FALSE => all subgroups are not dirty
LineList *m_pLine; // pointer to our line in the linked list
int m_nLastEntry, // last here means "last added"
m_nLastGroup; //
public:
// ctor
ConfigGroup(ConfigGroup *pParent, const wxString& strName, wxFileConfig *);
// dtor deletes all entries and subgroups also
~ConfigGroup();
// simple accessors
const wxString& Name() const { return m_strName; }
ConfigGroup *Parent() const { return m_pParent; }
wxFileConfig *Config() const { return m_pConfig; }
bool IsDirty() const { return m_bDirty; }
bool IsEmpty() const { return Entries().IsEmpty() && Groups().IsEmpty(); }
const ArrayEntries& Entries() const { return m_aEntries; }
const ArrayGroups& Groups() const { return m_aSubgroups; }
// find entry/subgroup (NULL if not found)
ConfigGroup *FindSubgroup(const char *szName) const;
ConfigEntry *FindEntry (const char *szName) const;
// delete entry/subgroup, return FALSE if doesn't exist
bool DeleteSubgroup(const char *szName);
bool DeleteEntry(const char *szName);
// create new entry/subgroup returning pointer to newly created element
ConfigGroup *AddSubgroup(const wxString& strName);
ConfigEntry *AddEntry (const wxString& strName, int nLine = NOT_FOUND);
// will also recursively set parent's dirty flag
void SetDirty();
void SetLine(LineList *pLine);
wxString GetFullName() const;
// get the last line belonging to an entry/subgroup of this group
LineList *GetGroupLine();
LineList *GetLastEntryLine();
LineList *GetLastGroupLine();
};
};
// ============================================================================ // ============================================================================
// implementation // implementation
// ============================================================================ // ============================================================================
// ----------------------------------------------------------------------------
// static functions
// ----------------------------------------------------------------------------
wxString wxFileConfig::GetGlobalFileName(const char *szFile)
{
wxString str;
bool bNoExt = strchr(szFile, '.') == NULL;
#ifdef __UNIX__
str << "/etc/" << szFile;
if ( bNoExt )
str << ".conf";
#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";
#endif // UNIX/Win
return str;
}
wxString wxFileConfig::GetLocalFileName(const char *szFile)
{
wxString str;
#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
return str;
}
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// ctor // ctor
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@@ -338,40 +138,38 @@ void wxFileConfig::Init()
m_strPath.Empty(); m_strPath.Empty();
} }
wxFileConfig::wxFileConfig(const wxString& strFile, bool bLocalOnly) wxFileConfig::wxFileConfig(const wxString& strLocal, const wxString& strGlobal)
: m_strFile(strFile) : m_strLocalFile(strLocal), m_strGlobalFile(strGlobal)
{ {
Init(); Init();
const char *szFile;
// it's not an error if (one of the) file(s) doesn't exist // it's not an error if (one of the) file(s) doesn't exist
// parse the global file // parse the global file
if ( !bLocalOnly ) { if ( !strGlobal.IsEmpty() ) {
szFile = GetGlobalFileName(strFile); if ( wxFile::Exists(strGlobal) ) {
if ( wxFile::Exists(szFile) ) { wxTextFile fileGlobal(strGlobal);
wxTextFile fileGlobal(szFile);
if ( fileGlobal.Open() ) { if ( fileGlobal.Open() ) {
Parse(fileGlobal, FALSE /* global */); Parse(fileGlobal, FALSE /* global */);
SetRootPath(); SetRootPath();
} }
else else
wxLogWarning("Can't open global configuration file."); wxLogWarning("Can't open global configuration file '%s'.",
strGlobal.c_str());
} }
} }
// parse the local file // parse the local file
szFile = GetLocalFileName(strFile); if ( wxFile::Exists(strLocal) ) {
if ( wxFile::Exists(szFile) ) { wxTextFile fileLocal(strLocal);
wxTextFile fileLocal(szFile);
if ( fileLocal.Open() ) { if ( fileLocal.Open() ) {
Parse(fileLocal, TRUE /* local */); Parse(fileLocal, TRUE /* local */);
SetRootPath(); SetRootPath();
} }
else else
wxLogWarning("Can't open user configuration file."); wxLogWarning("Can't open user configuration file '%s'.",
strLocal.c_str());
} }
} }
@@ -594,22 +392,43 @@ bool wxFileConfig::GetNextEntry (wxString& str, long& lIndex)
// read/write values // read/write values
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
const char *wxFileConfig::Read(const char *szKey, const char *szDefault) const const char *wxFileConfig::Read(const char *szKey,
const char *szDefault) const
{ {
PathChanger path(this, szKey); PathChanger path(this, szKey);
ConfigEntry *pEntry = m_pCurrentGroup->FindEntry(path.Name()); ConfigEntry *pEntry = m_pCurrentGroup->FindEntry(path.Name());
if (pEntry == NULL) return pEntry == NULL ? szDefault : pEntry->Value().c_str();
return szDefault;
else
return pEntry->Value();
// return pEntry == NULL ? szDefault : pEntry->Value();
} }
long wxFileConfig::Read(const char *szKey, long lDefault) const bool wxFileConfig::Read(wxString *pstr,
const char *szKey,
const char *szDefault) const
{ {
const char *pc = Read(szKey); PathChanger path(this, szKey);
return pc == NULL ? lDefault : atol(pc);
ConfigEntry *pEntry = m_pCurrentGroup->FindEntry(path.Name());
if (pEntry == NULL) {
*pstr = szDefault;
return FALSE;
}
else {
*pstr = pEntry->Value();
return TRUE;
}
}
bool wxFileConfig::Read(long *pl, const char *szKey, long lDefault) const
{
wxString str;
if ( Read(&str, szKey) ) {
*pl = atol(str);
return TRUE;
}
else {
*pl = lDefault;
return FALSE;
}
} }
bool wxFileConfig::Write(const char *szKey, const char *szValue) bool wxFileConfig::Write(const char *szKey, const char *szValue)
@@ -637,7 +456,7 @@ bool wxFileConfig::Flush(bool /* bCurrentOnly */)
if ( LineListIsEmpty() || !m_pRootGroup->IsDirty() ) if ( LineListIsEmpty() || !m_pRootGroup->IsDirty() )
return TRUE; return TRUE;
wxTempFile file(GetLocalFileName(m_strFile)); wxTempFile file(m_strLocalFile);
if ( !file.IsOpened() ) { if ( !file.IsOpened() ) {
wxLogError("Can't open user configuration file."); wxLogError("Can't open user configuration file.");
@@ -687,14 +506,14 @@ bool wxFileConfig::DeleteGroup(const char *szKey)
bool wxFileConfig::DeleteAll() bool wxFileConfig::DeleteAll()
{ {
const char *szFile = GetLocalFileName(m_strFile); const char *szFile = m_strLocalFile;
delete m_pRootGroup; delete m_pRootGroup;
Init(); Init();
if ( remove(szFile) == -1 ) if ( remove(szFile) == -1 )
wxLogSysError("Can't delete user configuration file '%s'", szFile); wxLogSysError("Can't delete user configuration file '%s'", szFile);
szFile = GetGlobalFileName(m_strFile); szFile = m_strGlobalFile;
if ( remove(szFile) ) if ( remove(szFile) )
wxLogSysError("Can't delete system configuration file '%s'", szFile); wxLogSysError("Can't delete system configuration file '%s'", szFile);
@@ -982,7 +801,10 @@ wxFileConfig::ConfigEntry::ConfigEntry(wxFileConfig::ConfigGroup *pParent,
void wxFileConfig::ConfigEntry::SetLine(LineList *pLine) void wxFileConfig::ConfigEntry::SetLine(LineList *pLine)
{ {
wxASSERT( m_pLine == NULL ); if ( m_pLine != NULL ) {
wxLogWarning("Entry '%s' appears more than once in group '%s'",
Name().c_str(), m_pParent->GetFullName().c_str());
}
m_pLine = pLine; m_pLine = pLine;
} }
@@ -1029,140 +851,16 @@ void wxFileConfig::ConfigEntry::SetDirty()
Group()->SetDirty(); Group()->SetDirty();
} }
// ============================================================================
// wxFileConfig::PathChanger
// ============================================================================
wxFileConfig::PathChanger::PathChanger(const wxFileConfig *pContainer,
const wxString& strEntry)
{
m_pContainer = (wxFileConfig *)pContainer;
wxString strPath = strEntry.Before(APPCONF_PATH_SEPARATOR);
if ( !strPath.IsEmpty() ) {
// do change the path
m_bChanged = TRUE;
m_strName = strEntry.Right(APPCONF_PATH_SEPARATOR);
m_strOldPath = m_pContainer->GetPath();
m_strOldPath += APPCONF_PATH_SEPARATOR;
m_pContainer->SetPath(strPath);
}
else {
// it's a name only, without path - nothing to do
m_bChanged = FALSE;
m_strName = strEntry;
}
}
wxFileConfig::PathChanger::~PathChanger()
{
// only restore path if it was changed
if ( m_bChanged ) {
m_pContainer->SetPath(m_strOldPath);
}
}
// ============================================================================ // ============================================================================
// global functions // global functions
// ============================================================================ // ============================================================================
const char *GetGlobalFileName(const char *szFile)
{
static wxString s_str;
s_str.Empty();
bool bNoExt = strchr(szFile, '.') == NULL;
#ifdef __UNIX__
s_str << "/etc/" << szFile;
if ( bNoExt )
s_str << ".conf";
#else // Windows
#ifndef _MAX_PATH
#define _MAX_PATH 512
#endif
char szWinDir[_MAX_PATH];
::GetWindowsDirectory(szWinDir, _MAX_PATH);
s_str << szWinDir << "\\" << szFile;
if ( bNoExt )
s_str << ".INI";
#endif // UNIX/Win
return s_str.c_str();
}
const char *GetLocalFileName(const char *szFile)
{
static wxString s_str;
s_str.Empty();
#ifdef __UNIX__
const char *szHome = getenv("HOME");
if ( szHome == NULL ) {
// we're homeless...
wxLogWarning("can't find user's HOME, using current directory.");
szHome = ".";
}
s_str << szHome << "/." << szFile;
#else // Windows
#ifdef __WIN32__
const char *szHome = getenv("HOMEDRIVE");
if ( szHome == NULL )
szHome = "";
s_str << szHome;
szHome = getenv("HOMEPATH");
s_str << ( szHome == NULL ? "." : szHome ) << szFile;
if ( strchr(szFile, '.') == NULL )
s_str << ".INI";
#else // Win16
// Win16 has no idea about home, so use the current directory instead
s_str << ".\\" << szFile;
#endif // WIN16/32
#endif // UNIX/Win
return s_str.c_str();
}
void SplitPath(wxArrayString& aParts, const char *sz)
{
aParts.Empty();
wxString strCurrent;
const char *pc = sz;
for ( ;; ) {
if ( *pc == '\0' || *pc == APPCONF_PATH_SEPARATOR ) {
if ( strCurrent == "." ) {
// ignore
}
else if ( strCurrent == ".." ) {
// go up one level
if ( aParts.IsEmpty() )
wxLogWarning("'%s' has extra '..', ignored.", sz);
else
aParts.Remove(aParts.Count() - 1);
}
else if ( !strCurrent.IsEmpty() ) {
aParts.Add(strCurrent);
strCurrent.Empty();
}
//else:
// could log an error here, but we prefer to ignore extra '/'
if ( *pc == '\0' )
return;
}
else
strCurrent += *pc;
pc++;
}
}
// undo FilterOut // undo FilterOut
wxString FilterIn(const wxString& str) wxString FilterIn(const wxString& str)
{ {
wxString strResult; wxString strResult;
bool bQuoted = str[0] == '"'; bool bQuoted = !str.IsEmpty() && str[0] == '"';
for ( uint n = bQuoted ? 1 : 0; n < str.Len(); n++ ) { for ( uint n = bQuoted ? 1 : 0; n < str.Len(); n++ ) {
if ( str[n] == '\\' ) { if ( str[n] == '\\' ) {
@@ -1241,8 +939,3 @@ wxString FilterOut(const wxString& str)
return strResult; return strResult;
} }
wxConfig *CreateFileConfig(const wxString& strFile, bool bLocalOnly)
{
return new wxFileConfig(strFile, bLocalOnly);
}