// Licence: wxWindows licence
///////////////////////////////////////////////////////////////////////////////
-#ifdef __GNUG__
+#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
#pragma implementation "fileconf.h"
#endif
#pragma hdrstop
#endif //__BORLANDC__
-#if wxUSE_CONFIG
+#if wxUSE_CONFIG && wxUSE_FILECONFIG
#ifndef WX_PRECOMP
#include "wx/string.h"
// "template" array types
// ----------------------------------------------------------------------------
-WX_DEFINE_SORTED_EXPORTED_ARRAY(wxFileConfigEntry *, ArrayEntries);
-WX_DEFINE_SORTED_EXPORTED_ARRAY(wxFileConfigGroup *, ArrayGroups);
+#ifdef WXMAKINGDLL_BASE
+ WX_DEFINE_SORTED_USER_EXPORTED_ARRAY(wxFileConfigEntry *, ArrayEntries,
+ WXDLLIMPEXP_BASE);
+ WX_DEFINE_SORTED_USER_EXPORTED_ARRAY(wxFileConfigGroup *, ArrayGroups,
+ WXDLLIMPEXP_BASE);
+#else
+ WX_DEFINE_SORTED_ARRAY(wxFileConfigEntry *, ArrayEntries);
+ WX_DEFINE_SORTED_ARRAY(wxFileConfigGroup *, ArrayGroups);
+#endif
// ----------------------------------------------------------------------------
// wxFileConfigLineList
GetLine() const { return m_pLine; }
// modify entry attributes
- void SetValue(const wxString& strValue, bool bUser = TRUE);
+ void SetValue(const wxString& strValue, bool bUser = true);
void SetDirty();
void SetLine(wxFileConfigLineList *pLine);
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
+ bool m_bDirty; // if false => all subgroups are not dirty
wxFileConfigLineList *m_pLine; // pointer to our line in the linked list
wxFileConfigEntry *m_pLastEntry; // last entry/subgroup of this group in the
wxFileConfigGroup *m_pLastGroup; // local file (we insert new ones after it)
wxFileConfigGroup *FindSubgroup(const wxChar *szName) const;
wxFileConfigEntry *FindEntry (const wxChar *szName) const;
- // delete entry/subgroup, return FALSE if doesn't exist
+ // delete entry/subgroup, return false if doesn't exist
bool DeleteSubgroupByName(const wxChar *szName);
bool DeleteEntry(const wxChar *szName);
wxFileConfigLineList *GetLastGroupLine(); // after which the next group starts
// called by entries/subgroups when they're created/deleted
- void SetLastEntry(wxFileConfigEntry *pEntry) { m_pLastEntry = pEntry; }
- void SetLastGroup(wxFileConfigGroup *pGroup) { m_pLastGroup = pGroup; }
+ void SetLastEntry(wxFileConfigEntry *pEntry);
+ void SetLastGroup(wxFileConfigGroup *pGroup)
+ { m_pLastGroup = pGroup; }
- DECLARE_NO_COPY_CLASS(wxFileConfigGroup)
+ DECLARE_NO_COPY_CLASS(wxFileConfigGroup)
};
// ============================================================================
strDir.Printf(wxT("%c:\\OS2\\"), 'A'+drive-1);
}
#elif defined(__WXSTUBS__)
- wxASSERT_MSG( FALSE, wxT("TODO") ) ;
+ wxASSERT_MSG( false, wxT("TODO") ) ;
#elif defined(__DOS__)
// There's no such thing as global cfg dir in MS-DOS, let's return
// current directory (FIXME_MGL?)
if ( fileGlobal.Open(m_conv/*ignored in ANSI build*/) )
{
- Parse(fileGlobal, FALSE /* global */);
+ Parse(fileGlobal, false /* global */);
SetRootPath();
}
else
wxTextFile fileLocal(m_strLocalFile);
if ( fileLocal.Open(m_conv/*ignored in ANSI build*/) )
{
- Parse(fileLocal, TRUE /* local */);
+ Parse(fileLocal, true /* local */);
SetRootPath();
}
else
wxString strTmp;
char buf[1024];
- while ( !inStream.Read(buf, WXSIZEOF(buf)).Eof() )
- strTmp.append(wxConvertMB2WX(buf), inStream.LastRead());
+ do
+ {
+ inStream.Read(buf, WXSIZEOF(buf));
+
+ const wxStreamError err = inStream.GetLastError();
+
+ if ( err != wxSTREAM_NO_ERROR && err != wxSTREAM_EOF )
+ {
+ wxLogError(_("Error reading config options."));
+ break;
+ }
- strTmp.append(wxConvertMB2WX(buf), inStream.LastRead());
+ strTmp.append(wxConvertMB2WX(buf), inStream.LastRead());
+ }
+ while ( !inStream.Eof() );
strTrans = wxTextBuffer::Translate(strTmp);
}
memText.AddLine(strTrans);
// Finally we can parse it all.
- Parse(memText, TRUE /* local */);
+ Parse(memText, true /* local */);
SetRootPath();
}
SetPath(strGroup);
if ( bLocal )
+ {
+ if ( m_pCurrentGroup->Parent() )
+ m_pCurrentGroup->Parent()->SetLastGroup(m_pCurrentGroup);
m_pCurrentGroup->SetLine(m_linesTail);
+ }
// check that there is nothing except comments left on this line
- bool bCont = TRUE;
+ bool bCont = true;
while ( *++pEnd != wxT('\0') && bCont ) {
switch ( *pEnd ) {
case wxT('#'):
case wxT(';'):
- bCont = FALSE;
+ bCont = false;
break;
case wxT(' '):
default:
wxLogWarning(_("file '%s', line %d: '%s' ignored after group header."),
buffer.GetName(), n + 1, pEnd);
- bCont = FALSE;
+ bCont = false;
}
}
}
else { // a key
const wxChar *pEnd = pStart;
- while ( *pEnd && *pEnd != wxT('=') && !wxIsspace(*pEnd) ) {
+ while ( *pEnd && *pEnd != wxT('=') /* && !wxIsspace(*pEnd)*/ ) {
if ( *pEnd == wxT('\\') ) {
// next character may be space or not - still take it because it's
// quoted (unless there is nothing)
pEnd++;
}
- wxString strKey(FilterInEntryName(wxString(pStart, pEnd)));
+ wxString strKey(FilterInEntryName(wxString(pStart, pEnd).Trim()));
// skip whitespace
while ( wxIsspace(*pEnd) )
if ( pEntry == NULL ) {
// new entry
pEntry = m_pCurrentGroup->AddEntry(strKey, n);
-
- if ( bLocal )
- pEntry->SetLine(m_linesTail);
}
else {
if ( bLocal && pEntry->IsImmutable() ) {
wxLogWarning(_("file '%s', line %d: key '%s' was first found at line %d."),
buffer.GetName(), n + 1, strKey.c_str(), pEntry->Line());
- if ( bLocal )
- pEntry->SetLine(m_linesTail);
}
}
+ if ( bLocal )
+ pEntry->SetLine(m_linesTail);
+
// skip whitespace
while ( wxIsspace(*pEnd) )
pEnd++;
if ( !(GetStyle() & wxCONFIG_USE_NO_ESCAPE_CHARACTERS) )
value = FilterInValue(value);
- pEntry->SetValue(value, FALSE);
+ pEntry->SetValue(value, false);
}
}
}
{
if ( size_t(lIndex) < m_pCurrentGroup->Groups().Count() ) {
str = m_pCurrentGroup->Groups()[(size_t)lIndex++]->Name();
- return TRUE;
+ return true;
}
else
- return FALSE;
+ return false;
}
bool wxFileConfig::GetFirstEntry(wxString& str, long& lIndex) const
{
if ( size_t(lIndex) < m_pCurrentGroup->Entries().Count() ) {
str = m_pCurrentGroup->Entries()[(size_t)lIndex++]->Name();
- return TRUE;
+ return true;
}
else
- return FALSE;
+ return false;
}
size_t wxFileConfig::GetNumberOfEntries(bool bRecursive) const
size_t nSubgroups = m_pCurrentGroup->Groups().Count();
for ( size_t nGroup = 0; nGroup < nSubgroups; nGroup++ ) {
CONST_CAST m_pCurrentGroup = m_pCurrentGroup->Groups()[nGroup];
- n += GetNumberOfEntries(TRUE);
+ n += GetNumberOfEntries(true);
CONST_CAST m_pCurrentGroup = pOldCurrentGroup;
}
}
size_t nSubgroups = m_pCurrentGroup->Groups().Count();
for ( size_t nGroup = 0; nGroup < nSubgroups; nGroup++ ) {
CONST_CAST m_pCurrentGroup = m_pCurrentGroup->Groups()[nGroup];
- n += GetNumberOfGroups(TRUE);
+ n += GetNumberOfGroups(true);
CONST_CAST m_pCurrentGroup = pOldCurrentGroup;
}
}
wxFileConfigEntry *pEntry = m_pCurrentGroup->FindEntry(path.Name());
if (pEntry == NULL) {
- return FALSE;
+ return false;
}
*pStr = pEntry->Value();
- return TRUE;
+ return true;
}
bool wxFileConfig::DoReadLong(const wxString& key, long *pl) const
{
- wxString str;
- if ( !Read(key, & str) )
- {
- return FALSE;
- }
- return str.ToLong(pl) ;
+ wxString str;
+ if ( !Read(key, &str) )
+ return false;
+
+ // extra spaces shouldn't prevent us from reading numeric values
+ str.Trim();
+
+ return str.ToLong(pl);
}
bool wxFileConfig::DoWriteString(const wxString& key, const wxString& szValue)
{
wxLogError( _("Config entry name cannot start with '%c'."),
wxCONFIG_IMMUTABLE_PREFIX);
- return FALSE;
+ return false;
}
wxFileConfigEntry *pEntry = m_pCurrentGroup->FindEntry(strName);
pEntry->SetValue(szValue);
}
- return TRUE;
+ return true;
}
bool wxFileConfig::DoWriteLong(const wxString& key, long lValue)
bool wxFileConfig::Flush(bool /* bCurrentOnly */)
{
if ( LineListIsEmpty() || !m_pRootGroup->IsDirty() || !m_strLocalFile )
- return TRUE;
+ return true;
#ifdef __UNIX__
// set the umask if needed
if ( !file.IsOpened() )
{
wxLogError(_("can't open user configuration file."));
- return FALSE;
+ return false;
}
// write all strings to file
if ( !file.Write(line, m_conv) )
{
wxLogError(_("can't write user configuration file."));
- return FALSE;
+ return false;
}
}
bool ret = file.Commit();
#if defined(__WXMAC__)
- if ( ret )
- {
- FSSpec spec ;
-
- wxMacFilename2FSSpec( m_strLocalFile , &spec ) ;
- FInfo finfo ;
- if ( FSpGetFInfo( &spec , &finfo ) == noErr )
- {
- finfo.fdType = 'TEXT' ;
- finfo.fdCreator = 'ttxt' ;
- FSpSetFInfo( &spec , &finfo ) ;
- }
- }
+ if ( ret )
+ {
+ FSRef fsRef ;
+ FSCatalogInfo catInfo;
+ FileInfo *finfo ;
+
+ if ( wxMacPathToFSRef( m_strLocalFile , &fsRef ) == noErr )
+ {
+ if ( FSGetCatalogInfo (&fsRef, kFSCatInfoFinderInfo, &catInfo, NULL, NULL, NULL) == noErr )
+ {
+ finfo = (FileInfo*)&catInfo.finderInfo;
+ finfo->fileType = 'TEXT' ;
+ finfo->fileCreator = 'ttxt' ;
+ FSSetCatalogInfo( &fsRef, kFSCatInfoFinderInfo, &catInfo ) ;
+ }
+ }
+ }
#endif // __WXMAC__
#ifdef __UNIX__
// check that the entry exists
wxFileConfigEntry *oldEntry = m_pCurrentGroup->FindEntry(oldName);
if ( !oldEntry )
- return FALSE;
+ return false;
// check that the new entry doesn't already exist
if ( m_pCurrentGroup->FindEntry(newName) )
- return FALSE;
+ return false;
// delete the old entry, create the new one
wxString value = oldEntry->Value();
if ( !m_pCurrentGroup->DeleteEntry(oldName) )
- return FALSE;
+ return false;
wxFileConfigEntry *newEntry = m_pCurrentGroup->AddEntry(newName);
newEntry->SetValue(value);
- return TRUE;
+ return true;
}
bool wxFileConfig::RenameGroup(const wxString& oldName,
// check that the group exists
wxFileConfigGroup *group = m_pCurrentGroup->FindSubgroup(oldName);
if ( !group )
- return FALSE;
+ return false;
// check that the new group doesn't already exist
if ( m_pCurrentGroup->FindSubgroup(newName) )
- return FALSE;
+ return false;
group->Rename(newName);
- return TRUE;
+ return true;
}
// ----------------------------------------------------------------------------
wxConfigPathChanger path(this, key);
if ( !m_pCurrentGroup->DeleteEntry(path.Name()) )
- return FALSE;
+ return false;
if ( bGroupIfEmptyAlso && m_pCurrentGroup->IsEmpty() ) {
if ( m_pCurrentGroup != m_pRootGroup ) {
//else: never delete the root group
}
- return TRUE;
+ return true;
}
bool wxFileConfig::DeleteGroup(const wxString& key)
{
CleanUp();
- if ( wxRemove(m_strLocalFile) == -1 )
- wxLogSysError(_("can't delete user configuration file '%s'"), m_strLocalFile.c_str());
+ if ( wxFile::Exists(m_strLocalFile) && wxRemove(m_strLocalFile) == -1 )
+ {
+ wxLogSysError(_("can't delete user configuration file '%s'"), m_strLocalFile.c_str());
+ return false;
+ }
m_strLocalFile = m_strGlobalFile = wxT("");
Init();
- return TRUE;
+ return true;
}
// ----------------------------------------------------------------------------
return m_linesTail;
}
- // insert a new line after the given one or in the very beginning if !pLine
-
+// insert a new line after the given one or in the very beginning if !pLine
wxFileConfigLineList *wxFileConfig::LineListInsert(const wxString& str,
wxFileConfigLineList *pLine)
{
{
m_pConfig = pConfig;
m_pParent = pParent;
- m_bDirty = FALSE;
+ m_bDirty = false;
m_pLine = NULL;
m_pLastEntry = NULL;
_T(" GetGroupLine() for Group '%s'"),
Name().c_str() );
- if ( m_pLine == 0 )
+ if ( !m_pLine )
{
wxLogTrace( _T("wxFileConfig"),
_T(" Getting Line item pointer") );
wxFileConfigGroup *pParent = Parent();
- // this group wasn't present in local config file, add it now
-
- if ( pParent != 0 )
+ // this group wasn't present in local config file, add it now
+ if ( pParent )
{
wxLogTrace( _T("wxFileConfig"),
_T(" checking parent '%s'"),
wxString strFullName;
- strFullName << wxT("[") // +1: no '/'
+ // add 1 to the name because we don't want to start with '/'
+ strFullName << wxT("[")
<< FilterOutEntryName(GetFullName().c_str() + 1)
<< wxT("]");
m_pLine = m_pConfig->LineListInsert(strFullName,
pParent->GetLastGroupLine());
pParent->SetLastGroup(this); // we're surely after all the others
}
- else
- {
- // we return NULL, so that LineListInsert() will insert us in the
- // very beginning
- }
+ //else: this is the root group and so we return NULL because we don't
+ // have any group line
}
return m_pLine;
// last line is the group line (m_pLine) itself.
wxFileConfigLineList *wxFileConfigGroup::GetLastGroupLine()
{
- // if we have any subgroups, our last line is
- // the last line of the last subgroup
-
- if ( m_pLastGroup != 0 )
+ // if we have any subgroups, our last line is the last line of the last
+ // subgroup
+ if ( m_pLastGroup )
{
wxFileConfigLineList *pLine = m_pLastGroup->GetLastGroupLine();
- wxASSERT( pLine != 0 ); // last group must have !NULL associated line
+ wxASSERT_MSG( pLine, _T("last group must have !NULL associated line") );
+
return pLine;
}
- // no subgroups, so the last line is the line of thelast entry (if any)
-
+ // no subgroups, so the last line is the line of thelast entry (if any)
return GetLastEntryLine();
}
_T(" GetLastEntryLine() for Group '%s'"),
Name().c_str() );
- if ( m_pLastEntry != 0 )
+ if ( m_pLastEntry )
{
wxFileConfigLineList *pLine = m_pLastEntry->GetLine();
- wxASSERT( pLine != 0 ); // last entry must have !NULL associated line
+ wxASSERT_MSG( pLine, _T("last entry must have !NULL associated line") );
+
return pLine;
}
- // no entries: insert after the group header
-
+ // no entries: insert after the group header, if any
return GetGroupLine();
}
+void wxFileConfigGroup::SetLastEntry(wxFileConfigEntry *pEntry)
+{
+ m_pLastEntry = pEntry;
+
+ if ( !m_pLine )
+ {
+ // the only situation in which a group without its own line can have
+ // an entry is when the first entry is added to the initially empty
+ // root pseudo-group
+ wxASSERT_MSG( !m_pParent, _T("unexpected for non root group") );
+
+ // let the group know that it does have a line in the file now
+ m_pLine = pEntry->GetLine();
+ }
+}
+
// ----------------------------------------------------------------------------
// group name
// ----------------------------------------------------------------------------
void wxFileConfigGroup::Rename(const wxString& newName)
{
+ wxCHECK_RET( m_pParent, _T("the root group can't be renamed") );
+
m_strName = newName;
- wxFileConfigLineList *line = GetGroupLine();
+ // +1: no leading '/'
wxString strFullName;
- strFullName << wxT("[") << (GetFullName().c_str() + 1) << wxT("]"); // +1: no '/'
+ strFullName << wxT("[") << (GetFullName().c_str() + 1) << wxT("]");
+
+ wxFileConfigLineList *line = GetGroupLine();
+ wxCHECK_RET( line, _T("a non root group must have a corresponding line!") );
+
line->SetText(strFullName);
SetDirty();
{
wxFileConfigGroup * const pGroup = FindSubgroup(szName);
- return pGroup ? DeleteSubgroup(pGroup) : FALSE;
+ return pGroup ? DeleteSubgroup(pGroup) : false;
}
// Delete the subgroup and remove all references to it from
// other data structures.
bool wxFileConfigGroup::DeleteSubgroup(wxFileConfigGroup *pGroup)
{
- wxCHECK_MSG( pGroup, FALSE, _T("deleting non existing group?") );
+ wxCHECK_MSG( pGroup, false, _T("deleting non existing group?") );
wxLogTrace( _T("wxFileConfig"),
_T("Deleting group '%s' from '%s'"),
m_aSubgroups.Remove(pGroup);
delete pGroup;
- return TRUE;
+ return true;
}
bool wxFileConfigGroup::DeleteEntry(const wxChar *szName)
{
wxFileConfigEntry *pEntry = FindEntry(szName);
- wxCHECK( pEntry != NULL, FALSE ); // deleting non existing item?
+ wxCHECK( pEntry != NULL, false ); // deleting non existing item?
wxFileConfigLineList *pLine = pEntry->GetLine();
if ( pLine != NULL ) {
m_aEntries.Remove(pEntry);
delete pEntry;
- return TRUE;
+ return true;
}
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
void wxFileConfigGroup::SetDirty()
{
- m_bDirty = TRUE;
+ m_bDirty = true;
if ( Parent() != NULL ) // propagate upwards
Parent()->SetDirty();
}
m_pLine = NULL;
m_bDirty =
- m_bHasValue = FALSE;
+ m_bHasValue = false;
m_bImmutable = strName[0] == wxCONFIG_IMMUTABLE_PREFIX;
if ( m_bImmutable )
Group()->SetLastEntry(this);
}
-// second parameter is FALSE if we read the value from file and prevents the
+// second parameter is false if we read the value from file and prevents the
// entry from being marked as 'dirty'
void wxFileConfigEntry::SetValue(const wxString& strValue, bool bUser)
{
if ( m_bHasValue && strValue == m_strValue )
return;
- m_bHasValue = TRUE;
+ m_bHasValue = true;
m_strValue = strValue;
if ( bUser )
wxString strLine;
strLine << FilterOutEntryName(m_strName) << wxT('=') << strValFiltered;
- if ( m_pLine != 0 )
+ if ( m_pLine )
{
// entry was read from the local config file, just modify the line
m_pLine->SetText(strLine);
}
- else {
+ else // this entry didn't exist in the local file
+ {
// add a new line to the file
- wxASSERT( m_nLine == wxNOT_FOUND ); // consistency check
+ wxFileConfigLineList *line = Group()->GetLastEntryLine();
+ m_pLine = Group()->Config()->LineListInsert(strLine, line);
- m_pLine = Group()->Config()->LineListInsert(strLine,
- Group()->GetLastEntryLine());
Group()->SetLastEntry(this);
}
void wxFileConfigEntry::SetDirty()
{
- m_bDirty = TRUE;
+ m_bDirty = true;
Group()->SetDirty();
}
strResult.Alloc(str.Len());
for ( const wxChar *pc = str.c_str(); *pc != wxT('\0'); pc++ ) {
- wxChar c = *pc;
+ const wxChar c = *pc;
// we explicitly allow some of "safe" chars and 8bit ASCII characters
- // which will probably never have special meaning
+ // which will probably never have special meaning and with which we can't
+ // use isalnum() anyhow (in ASCII built, in Unicode it's just fine)
+ //
// NB: note that wxCONFIG_IMMUTABLE_PREFIX and wxCONFIG_PATH_SEPARATOR
// should *not* be quoted
- if ( !wxIsalnum(c) && !wxStrchr(wxT("@_/-!.*%"), c) && ((c & 0x80) == 0) )
+ if (
+#if !wxUSE_UNICODE
+ ((unsigned char)c < 127) &&
+#endif // ANSI
+ !wxIsalnum(c) && !wxStrchr(wxT("@_/-!.*%"), c) )
+ {
strResult += wxT('\\');
+ }
strResult += c;
}