// RCS-ID: $Id$
// Copyright: (c) 1997 Karsten Ballüder & Vadim Zeitlin
// Ballueder@usa.net <zeitlin@dptmaths.ens-cachan.fr>
-// Licence: wxWindows license
+// 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
wxString m_strLine; // line contents
wxFileConfigLineList *m_pNext, // next node
*m_pPrev; // previous one
+
+ DECLARE_NO_COPY_CLASS(wxFileConfigLineList)
};
// ----------------------------------------------------------------------------
void SetValue(const wxString& strValue, bool bUser = TRUE);
void SetDirty();
void SetLine(wxFileConfigLineList *pLine);
+
+ DECLARE_NO_COPY_CLASS(wxFileConfigEntry)
};
// ----------------------------------------------------------------------------
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)
};
// ============================================================================
if ( wxStrchr(szFile, wxT('.')) == NULL )
#if defined( __WXMAC__ )
- str << " Preferences";
+ str << wxT(" Preferences") ;
#elif defined( __UNIX__ )
str << wxT(".conf");
#else // Windows
wxString wxFileConfig::GetLocalFileName(const wxChar *szFile)
{
-#ifdef __VMS__
+#ifdef __VMS__
// On VMS I saw the problem that the home directory was appended
// twice for the configuration file. Does that also happen for
// other platforms?
#endif
#ifdef __WXMAC__
- str << " Preferences";
+ str << wxT(" Preferences") ;
#endif
return str;
{
wxTextFile fileGlobal(m_strGlobalFile);
-#if defined(__WXGTK20__) && wxUSE_UNICODE
- if ( fileGlobal.Open( wxConvUTF8 ) )
-#else
- if ( fileGlobal.Open() )
-#endif
+ if ( fileGlobal.Open(m_conv/*ignored in ANSI build*/) )
{
Parse(fileGlobal, FALSE /* global */);
SetRootPath();
if ( !m_strLocalFile.IsEmpty() && wxFile::Exists(m_strLocalFile) )
{
wxTextFile fileLocal(m_strLocalFile);
-#if defined(__WXGTK20__) && wxUSE_UNICODE
- if ( fileLocal.Open( wxConvUTF8 ) )
-#else
- if ( fileLocal.Open() )
-#endif
+ if ( fileLocal.Open(m_conv/*ignored in ANSI build*/) )
{
Parse(fileLocal, TRUE /* local */);
SetRootPath();
// constructor supports creation of wxFileConfig objects of any type
wxFileConfig::wxFileConfig(const wxString& appName, const wxString& vendorName,
const wxString& strLocal, const wxString& strGlobal,
- long style)
+ long style, wxMBConv& conv)
: wxConfigBase(::GetAppName(appName), vendorName,
strLocal, strGlobal,
style),
- m_strLocalFile(strLocal), m_strGlobalFile(strGlobal)
+ m_strLocalFile(strLocal), m_strGlobalFile(strGlobal),
+ m_conv(conv)
{
// Make up names for files if empty
if ( m_strLocalFile.IsEmpty() && (style & wxCONFIG_USE_LOCAL_FILE) )
}
SetUmask(-1);
-
+
Init();
}
#if wxUSE_STREAMS
-wxFileConfig::wxFileConfig(wxInputStream &inStream)
+wxFileConfig::wxFileConfig(wxInputStream &inStream, wxMBConv& conv)
+ : m_conv(conv)
{
// always local_file when this constructor is called (?)
SetStyle(GetStyle() | wxCONFIG_USE_LOCAL_FILE);
wxString strTmp;
char buf[1024];
- while ( !inStream.Read(buf, WXSIZEOF(buf)).Eof() )
- strTmp.append(wxConvertMB2WX(buf), inStream.LastRead());
+ do
+ {
+ inStream.Read(buf, WXSIZEOF(buf));
- strTmp.append(wxConvertMB2WX(buf), inStream.LastRead());
+ 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());
+ }
+ while ( !inStream.Eof() );
strTrans = wxTextBuffer::Translate(strTmp);
}
wxString strLine;
size_t nLineCount = buffer.GetLineCount();
-
+
for ( size_t n = 0; n < nLineCount; n++ )
{
strLine = buffer[n];
// add the line to linked list
if ( bLocal )
+ {
LineListAppend(strLine);
+ // let the root group have it start line as well
+ if ( !n )
+ {
+ m_pCurrentGroup->SetLine(m_linesTail);
+ }
+ }
+
+
// skip leading spaces
for ( pStart = strLine; wxIsspace(*pStart); pStart++ )
;
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;
}
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++;
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)
{
wxConfigPathChanger path(this, key);
wxString strName = path.Name();
-
+
wxLogTrace( _T("wxFileConfig"),
_T(" Writing String '%s' = '%s' to Group '%s'"),
strName.c_str(),
{
wxString line = p->Text();
line += wxTextFile::GetEOL();
-#if wxUSE_UNICODE
- wxCharBuffer buf = wxConvLocal.cWX2MB( line );
- if ( !file.Write( (const char*)buf, strlen( (const char*) buf ) ) )
-#else
- if ( !file.Write( line.c_str(), line.Len() ) )
-#endif
+ if ( !file.Write(line, m_conv) )
{
wxLogError(_("can't write user configuration file."));
return FALSE;
{
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 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)
{
_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();
bool wxFileConfigGroup::DeleteSubgroupByName(const wxChar *szName)
{
- return DeleteSubgroup(FindSubgroup(szName));
+ wxFileConfigGroup * const pGroup = FindSubgroup(szName);
+
+ 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?") );
+
wxLogTrace( _T("wxFileConfig"),
_T("Deleting group '%s' from '%s'"),
pGroup->Name().c_str(),
_T(" text: '%s'"),
((m_pLine) ? m_pLine->Text().c_str() : wxEmptyString) );
- wxCHECK_MSG( pGroup != 0, FALSE, _T("deleting non existing group?") );
-
- // delete all entries
-
- size_t nCount = pGroup->m_aEntries.Count();
+ // delete all entries
+ size_t nCount = pGroup->m_aEntries.Count();
wxLogTrace(_T("wxFileConfig"),
_T("Removing %lu Entries"),
{
wxLogTrace( _T("wxFileConfig"),
_T(" ------- No previous group found -------") );
-
+
wxASSERT_MSG( !pNewLast || m_pLine == 0,
_T("how comes it has the same line as we?") );
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);
}
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;
}