fileconf.cpp
来自「A*算法 A*算法 A*算法 A*算法A*算法A*算法」· C++ 代码 · 共 2,084 行 · 第 1/5 页
CPP
2,084 行
{
wxLogWarning(_("can't open user configuration file '%s'."), m_strLocalFile.c_str() );
}
}
m_isDirty = false;
}
// 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, wxMBConv& conv)
: wxConfigBase(::GetAppName(appName), vendorName,
strLocal, strGlobal,
style),
m_strLocalFile(strLocal), m_strGlobalFile(strGlobal),
m_conv(conv)
{
// Make up names for files if empty
if ( m_strLocalFile.empty() && (style & wxCONFIG_USE_LOCAL_FILE) )
m_strLocalFile = GetLocalFileName(GetAppName());
if ( m_strGlobalFile.empty() && (style & wxCONFIG_USE_GLOBAL_FILE) )
m_strGlobalFile = GetGlobalFileName(GetAppName());
// Check if styles are not supplied, but filenames are, in which case
// add the correct styles.
if ( !m_strLocalFile.empty() )
SetStyle(GetStyle() | wxCONFIG_USE_LOCAL_FILE);
if ( !m_strGlobalFile.empty() )
SetStyle(GetStyle() | wxCONFIG_USE_GLOBAL_FILE);
// if the path is not absolute, prepend the standard directory to it
// UNLESS wxCONFIG_USE_RELATIVE_PATH style is set
if ( !(style & wxCONFIG_USE_RELATIVE_PATH) )
{
if ( !m_strLocalFile.empty() && !wxIsAbsolutePath(m_strLocalFile) )
{
wxString strLocal = m_strLocalFile;
m_strLocalFile = GetLocalDir();
m_strLocalFile << strLocal;
}
if ( !m_strGlobalFile.empty() && !wxIsAbsolutePath(m_strGlobalFile) )
{
wxString strGlobal = m_strGlobalFile;
m_strGlobalFile = GetGlobalDir();
m_strGlobalFile << strGlobal;
}
}
SetUmask(-1);
Init();
}
#if wxUSE_STREAMS
wxFileConfig::wxFileConfig(wxInputStream &inStream, wxMBConv& conv)
: m_conv(conv)
{
// always local_file when this constructor is called (?)
SetStyle(GetStyle() | wxCONFIG_USE_LOCAL_FILE);
m_pCurrentGroup =
m_pRootGroup = new wxFileConfigGroup(NULL, wxEmptyString, this);
m_linesHead =
m_linesTail = NULL;
// translate everything to the current (platform-dependent) line
// termination character
wxString strTrans;
{
wxString strTmp;
char buf[1024];
do
{
inStream.Read(buf, WXSIZEOF(buf)-1); // leave room for the NULL
const wxStreamError err = inStream.GetLastError();
if ( err != wxSTREAM_NO_ERROR && err != wxSTREAM_EOF )
{
wxLogError(_("Error reading config options."));
break;
}
// FIXME: this is broken because if we have part of multibyte
// character in the buffer (and another part hasn't been
// read yet) we're going to lose data because of conversion
// errors
buf[inStream.LastRead()] = '\0';
strTmp += conv.cMB2WX(buf);
}
while ( !inStream.Eof() );
strTrans = wxTextBuffer::Translate(strTmp);
}
wxMemoryText memText;
// Now we can add the text to the memory text. To do this we extract line
// by line from the translated string, until we've reached the end.
//
// VZ: all this is horribly inefficient, we should do the translation on
// the fly in one pass saving both memory and time (TODO)
const wxChar *pEOL = wxTextBuffer::GetEOL(wxTextBuffer::typeDefault);
const size_t EOLLen = wxStrlen(pEOL);
int posLineStart = strTrans.Find(pEOL);
while ( posLineStart != -1 )
{
wxString line(strTrans.Left(posLineStart));
memText.AddLine(line);
strTrans = strTrans.Mid(posLineStart + EOLLen);
posLineStart = strTrans.Find(pEOL);
}
// also add whatever we have left in the translated string.
if ( !strTrans.empty() )
memText.AddLine(strTrans);
// Finally we can parse it all.
Parse(memText, true /* local */);
SetRootPath();
ResetDirty();
}
#endif // wxUSE_STREAMS
void wxFileConfig::CleanUp()
{
delete m_pRootGroup;
wxFileConfigLineList *pCur = m_linesHead;
while ( pCur != NULL ) {
wxFileConfigLineList *pNext = pCur->Next();
delete pCur;
pCur = pNext;
}
}
wxFileConfig::~wxFileConfig()
{
Flush();
CleanUp();
}
// ----------------------------------------------------------------------------
// parse a config file
// ----------------------------------------------------------------------------
void wxFileConfig::Parse(wxTextBuffer& buffer, bool bLocal)
{
const wxChar *pStart;
const wxChar *pEnd;
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 its start line as well
if ( !n )
{
m_pCurrentGroup->SetLine(m_linesTail);
}
}
// skip leading spaces
for ( pStart = strLine; wxIsspace(*pStart); pStart++ )
;
// skip blank/comment lines
if ( *pStart == wxT('\0')|| *pStart == wxT(';') || *pStart == wxT('#') )
continue;
if ( *pStart == wxT('[') ) { // a new group
pEnd = pStart;
while ( *++pEnd != wxT(']') ) {
if ( *pEnd == wxT('\\') ) {
// the next char is escaped, so skip it even if it is ']'
pEnd++;
}
if ( *pEnd == wxT('\n') || *pEnd == wxT('\0') ) {
// we reached the end of line, break out of the loop
break;
}
}
if ( *pEnd != wxT(']') ) {
wxLogError(_("file '%s': unexpected character %c at line %d."),
buffer.GetName(), *pEnd, n + 1);
continue; // skip this line
}
// group name here is always considered as abs path
wxString strGroup;
pStart++;
strGroup << wxCONFIG_PATH_SEPARATOR
<< FilterInEntryName(wxString(pStart, pEnd - pStart));
// will create it if doesn't yet exist
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;
while ( *++pEnd != wxT('\0') && bCont ) {
switch ( *pEnd ) {
case wxT('#'):
case wxT(';'):
bCont = false;
break;
case wxT(' '):
case wxT('\t'):
// ignore whitespace ('\n' impossible here)
break;
default:
wxLogWarning(_("file '%s', line %d: '%s' ignored after group header."),
buffer.GetName(), n + 1, pEnd);
bCont = false;
}
}
}
else { // a key
const wxChar *pEnd = pStart;
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++;
if ( !*pEnd ) {
// the error message will be given below anyhow
break;
}
}
pEnd++;
}
wxString strKey(FilterInEntryName(wxString(pStart, pEnd).Trim()));
// skip whitespace
while ( wxIsspace(*pEnd) )
pEnd++;
if ( *pEnd++ != wxT('=') ) {
wxLogError(_("file '%s', line %d: '=' expected."),
buffer.GetName(), n + 1);
}
else {
wxFileConfigEntry *pEntry = m_pCurrentGroup->FindEntry(strKey);
if ( pEntry == NULL ) {
// new entry
pEntry = m_pCurrentGroup->AddEntry(strKey, n);
}
else {
if ( bLocal && pEntry->IsImmutable() ) {
// immutable keys can't be changed by user
wxLogWarning(_("file '%s', line %d: value for immutable key '%s' ignored."),
buffer.GetName(), n + 1, strKey.c_str());
continue;
}
// the condition below catches the cases (a) and (b) but not (c):
// (a) global key found second time in global file
// (b) key found second (or more) time in local file
// (c) key from global file now found in local one
// which is exactly what we want.
else if ( !bLocal || pEntry->IsLocal() ) {
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);
// skip whitespace
while ( wxIsspace(*pEnd) )
pEnd++;
wxString value = pEnd;
if ( !(GetStyle() & wxCONFIG_USE_NO_ESCAPE_CHARACTERS) )
value = FilterInValue(value);
pEntry->SetValue(value, false);
}
}
}
}
// ----------------------------------------------------------------------------
// set/retrieve path
// ----------------------------------------------------------------------------
void wxFileConfig::SetRootPath()
{
m_strPath.Empty();
m_pCurrentGroup = m_pRootGroup;
}
bool
wxFileConfig::DoSetPath(const wxString& strPath, bool createMissingComponents)
{
wxArrayString aParts;
if ( strPath.empty() ) {
SetRootPath();
return true;
}
if ( strPath[0] == wxCONFIG_PATH_SEPARATOR ) {
// absolute path
wxSplitPath(aParts, strPath);
}
else {
// relative path, combine with current one
wxString strFullPath = m_strPath;
strFullPath << wxCONFIG_PATH_SEPARATOR << strPath;
wxSplitPath(aParts, strFullPath);
}
// change current group
size_t n;
m_pCurrentGroup = m_pRootGroup;
for ( n = 0; n < aParts.Count(); n++ ) {
wxFileConfigGroup *pNextGroup = m_pCurrentGroup->FindSubgroup(aParts[n]);
if ( pNextGroup == NULL )
{
if ( !createMissingComponents )
return false;
pNextGroup = m_pCurrentGroup->AddSubgroup(aParts[n]);
}
m_pCurrentGroup = pNextGroup;
}
// recombine path parts in one variable
m_strPath.Empty();
for ( n = 0; n < aParts.Count(); n++ ) {
m_strPath << wxCONFIG_PATH_SEPARATOR << aParts[n];
}
return true;
}
void wxFileConfig::SetPath(const wxString& strPath)
{
DoSetPath(strPath, true /* create missing path components */);
}
// ----------------------------------------------------------------------------
// enumeration
// ----------------------------------------------------------------------------
bool wxFileConfig::GetFirstGroup(wxString& str, long& lIndex) const
{
lIndex = 0;
return GetNextGroup(str, lIndex);
}
bool wxFileConfig::GetNextGroup (wxString& str, long& lIndex) const
{
if ( size_t(lIndex) < m_pCurrentGroup->Groups().Count() ) {
str = m_pCurrentGroup->Groups()[(size_t)lIndex++]->Name();
return true;
}
else
return false;
}
bool wxFileConfig::GetFirstEntry(wxString& str, long& lIndex) const
{
lIndex = 0;
return GetNextEntry(str, lIndex);
}
bool wxFileConfig::GetNextEntry (wxString& str, long& lIndex) const
{
if ( size_t(lIndex) < m_pCurrentGroup->Entries().Count() ) {
str = m_pCurrentGroup->Entries()[(size_t)lIndex++]->Name();
return true;
}
else
return false;
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?