?? appconf.cpp
字號:
if ( m_szCurrentPath == NULL || len > strlen(m_szCurrentPath) ) {
// old buffer too small, alloc new one
if ( m_szCurrentPath != NULL )
delete [] m_szCurrentPath;
m_szCurrentPath = new char[len + 1];
}
// copy and delete pointer returned by normalizePath
strcpy(m_szCurrentPath, szNormPath);
delete [] szNormPath;
}
}
void BaseConfig::setCurrentPath(const char *szPath)
{
changeCurrentPath(); // goto root
changeCurrentPath(szPath); // now use relative change
}
const char *BaseConfig::getCurrentPath() const
{
return m_szCurrentPath == NULL ? "" : m_szCurrentPath;
}
// ----------------------------------------------------------------------------
// filters (NB: filterOut(filterIn()) shouldn't change the string)
// ----------------------------------------------------------------------------
// called before writing
char *BaseConfig::filterOut(const char *szValue)
{
// quote entire string if it starts with space or with quote
Bool bDoQuote = isspace(*szValue) || (*szValue == '"');
// calculate the length of resulting string
size_t len = Strlen(szValue);
const char *pcIn = szValue;
while ( *pcIn ) {
switch ( *pcIn++ ) {
case '"':
if ( !bDoQuote )
break;
//else: fall through
case '\n':
case '\t':
case '\\':
// one for extra '\'
len++;
break;
}
}
if ( bDoQuote )
len += 2;
char *szBuf = new char[len + 1];
char *pcOut = szBuf;
if ( bDoQuote )
*pcOut++ = '"';
char c;
for ( pcIn = szValue; *pcIn != '\0'; pcIn++ ) {
switch ( *pcIn ) {
case '\n':
c = 'n';
break;
case '\t':
c = 't';
break;
case '\\':
c = '\\';
break;
case '"':
if ( bDoQuote )
c = '"';
//else: fall through
default:
*pcOut++ = *pcIn;
continue; // skip special character procession
}
// we get here only for special characters
*pcOut++ = '\\';
*pcOut++ = c;
}
if ( bDoQuote )
*pcOut++ = '"';
*pcOut = '\0';
return szBuf;
}
// called after reading
char *BaseConfig::filterIn(const char *szValue)
{
// it will be a bit smaller, but who cares
char *szBuf = new char[Strlen(szValue) + 1];
const char *pcIn = szValue;
char *pcOut = szBuf;
Bool bQuoted = *pcIn == '"';
if ( bQuoted )
pcIn++;
while ( *pcIn != '\0' ) {
switch ( *pcIn ) {
case '\\':
switch ( *++pcIn ) {
case 'n':
*pcOut++ = '\n';
break;
case 't':
*pcOut++ = '\t';
break;
case '\\':
*pcOut++ = '\\';
break;
case '"':
default:
// ignore '\'
*pcOut++ = *pcIn;
}
break;
case '"':
if ( bQuoted ) {
if ( *(pcIn + 1) != '\0' ) {
LogWarning(_("invalid string '%s' in configuration file."), szValue);
}
break;
}
//else: fall through
default:
*pcOut++ = *pcIn;
}
pcIn++;
}
*pcOut = '\0';
return szBuf;
}
// ----------------------------------------------------------------------------
// implementation of Enumerator subclass
// ----------------------------------------------------------------------------
BaseConfig::Enumerator::Enumerator(size_t nCount, Bool bOwnsStrings)
{
m_bOwnsStrings = bOwnsStrings;
m_aszData = new char *[nCount];
m_nCount = 0;
}
// free memory
BaseConfig::Enumerator::~Enumerator()
{
if ( m_bOwnsStrings ) {
for ( size_t n = 0; n < m_nCount; n++ )
delete [] m_aszData[n];
}
delete [] m_aszData;
}
void BaseConfig::Enumerator::AddString(char *sz)
{
m_aszData[m_nCount++] = sz;
}
void BaseConfig::Enumerator::AddString(const char *sz)
{
assert( !m_bOwnsStrings );
// we won't delete it (see assert above), so we can cast in "char *"
m_aszData[m_nCount++] = (char *)sz;
}
// remove duplicate strings
void BaseConfig::Enumerator::MakeUnique()
{
char **aszUnique = new char *[m_nCount];
size_t nUnique = 0;
Bool bUnique;
for ( size_t n = 0; n < m_nCount; n++ ) {
bUnique = TRUE;
for ( size_t n2 = n + 1; n2 < m_nCount; n2++ ) {
if ( StrCmp(m_aszData[n], m_aszData[n2]) == 0 ) {
bUnique = FALSE;
break;
}
}
if ( bUnique )
aszUnique[nUnique++] = m_aszData[n];
else if ( m_bOwnsStrings )
delete [] m_aszData[n];
}
delete [] m_aszData;
m_aszData = aszUnique;
m_nCount = nUnique;
}
// ============================================================================
// implementation of FileConfig class
// ============================================================================
// ----------------------------------------------------------------------------
// FileConfig::ConfigEntry class
// ----------------------------------------------------------------------------
// ctor
FileConfig::ConfigEntry::ConfigEntry(ConfigGroup *pParent,
ConfigEntry *pNext,
const char *szName)
{
m_pParent = pParent;
m_pNext = pNext;
m_szExpValue =
m_szValue =
m_szComment = NULL;
m_bDirty =
m_bLocal = FALSE;
// check for special prefix
if ( *szName == APPCONF_IMMUTABLE_PREFIX ) {
m_bImmutable = TRUE;
szName++; // skip prefix
}
else
m_bImmutable = FALSE;
m_szName = new char[Strlen(szName) + 1];
strcpy(m_szName, szName);
}
// dtor
FileConfig::ConfigEntry::~ConfigEntry()
{
if ( m_szName != NULL )
delete [] m_szName;
if ( m_szValue != NULL )
delete [] m_szValue;
if ( m_szComment != NULL )
delete [] m_szComment;
if ( m_szExpValue != NULL )
delete [] m_szExpValue;
}
// set value and dirty flag
void FileConfig::ConfigEntry::SetValue(const char *szValue,
Bool bLocal, Bool bFromFile)
{
if ( m_szExpValue != NULL ) {
delete [] m_szExpValue;
m_szExpValue = NULL;
}
if ( m_szValue != NULL ) {
// immutable changes can't be overriden (only check it here, because
// they still can be set the first time)
if ( m_bImmutable ) {
LogWarning(_("attempt to change an immutable entry '%s' ignored."),
m_szName);
return;
}
delete [] m_szValue;
}
// immutable entries are never changed and if an entry was just read
// from file it shouldn't be dirty neither
if ( !m_bImmutable && !bFromFile )
SetDirty();
m_bLocal = bLocal;
if ( bLocal ) {
// to ensure that local entries are saved we make them always dirty
SetDirty();
}
if ( szValue != NULL )
{
m_szValue = new char[Strlen(szValue) + 1];
strcpy(m_szValue, szValue);
}
else
{
m_szValue = NULL;
SetDirty(FALSE);
}
}
// set comment associated with this entry
void FileConfig::ConfigEntry::SetComment(char *szComment)
{
assert( m_szComment == NULL ); // should be done only once
// ... because we don't copy, just take the pointer
m_szComment = szComment;
}
// set dirty flag
void FileConfig::ConfigEntry::SetDirty(Bool bDirty)
{
// ## kludge: local entries are always dirty, otherwise they would be lost
m_bDirty = m_bLocal ? TRUE : bDirty;
if ( m_bDirty )
m_pParent->SetDirty();
}
const char *FileConfig::ConfigEntry::ExpandedValue()
{
if ( m_szExpValue == NULL ) {
// we have only to do expansion once
m_szExpValue = ExpandEnvVars(m_szValue);
}
return m_szExpValue;
}
// ----------------------------------------------------------------------------
// FileConfig::ConfigGroup class
// ----------------------------------------------------------------------------
// ctor & dtor
// -----------
FileConfig::ConfigGroup::ConfigGroup(ConfigGroup *pParent,
ConfigGroup *pNext,
const char *szName)
{
m_pParent = pParent;
m_pNext = pNext;
m_pEntries =
m_pLastEntry = NULL;
m_pSubgroups =
m_pLastGroup = NULL;
m_bDirty = FALSE; // no entries yet
m_szComment = NULL;
m_szName = new char[Strlen(szName) + 1];
strcpy(m_szName, szName); }
FileConfig::ConfigGroup::~ConfigGroup()
{
// delete all entries
ConfigEntry *pEntry, *pNextEntry;
for ( pEntry = m_pEntries; pEntry != NULL; pEntry = pNextEntry ) {
pNextEntry = pEntry->Next();
delete pEntry;
}
// delete all subgroups
ConfigGroup *pGroup, *pNextGroup;
for ( pGroup = m_pSubgroups; pGroup != NULL; pGroup = pNextGroup ) {
pNextGroup = pGroup->Next();
delete pGroup;
}
if ( m_szName != NULL )
delete [] m_szName;
}
// find
// ----
FileConfig::ConfigGroup *
FileConfig::ConfigGroup::FindSubgroup(const char *szName) const
{
ConfigGroup *pGroup;
for ( pGroup = m_pSubgroups; pGroup != NULL; pGroup = pGroup->Next() ) {
if ( !StrCmp(pGroup->Name(), szName) )
return pGroup;
}
return NULL;
}
FileConfig::ConfigEntry *
FileConfig::ConfigGroup::FindEntry(const char *szName) const
{
ConfigEntry *pEntry;
for ( pEntry = m_pEntries; pEntry != NULL; pEntry = pEntry->Next() ) {
if ( !StrCmp(pEntry->Name(), szName) )
return pEntry;
}
return NULL;
}
// add
// ---
// add an item at the bottom of the stack (i.e. it's a LILO really)
FileConfig::ConfigGroup *FileConfig::ConfigGroup::AddSubgroup(const char *szName)
{
ConfigGroup *pGroup = new ConfigGroup(this, NULL, szName);
if ( m_pSubgroups == NULL ) {
m_pSubgroups =
m_pLastGroup = pGroup;
}
else {
m_pLastGroup = m_pLastGroup->m_pNext = pGroup;
}
return pGroup;
}
// add an item at the bottom
FileConfig::ConfigEntry *FileConfig::ConfigGroup::AddEntry(const char *szName)
{
ConfigEntry *pEntry = new ConfigEntry(this, NULL, szName);
if ( m_pEntries == NULL ) {
m_pEntries =
m_pLastEntry = pEntry;
}
else {
m_pLastEntry->SetNext(pEntry);
m_pLastEntry = pEntry;
}
return pEntry;
}
// delete
// ------
Bool FileConfig::ConfigGroup::DeleteSubgroup(const char *szName)
{
ConfigGroup *pGroup, *pPrevGroup = NULL;
for ( pGroup = Subgroup(); pGroup != NULL; pGroup = pGroup->Next() ) {
if ( StrCmp(pGroup->Name(), szName) == 0 ) {
break;
}
pPrevGroup = pGroup;
}
if ( pGroup == NULL )
return FALSE;
// remove the next element in the linked list
if ( pPrevGroup == NULL ) {
m_pSubgroups = pGroup->Next();
}
else {
pPrevGroup->m_pNext = pGroup->Next();
}
// adjust pointer to the last element
if ( pGroup->Next() == NULL ) {
m_pLastGroup = pPrevGroup == NULL ? m_pSubgroups : pPrevGroup;
}
// shouldn't have any entries/subgroups or they would be never deleted
// resulting in memory leaks (or we then should delete them here)
assert( pGroup->Entries() == NULL && pGroup->Subgroup() == NULL );
delete pGroup;
return TRUE;
}
Bool FileConfig::ConfigGroup::DeleteEntry(const char *szName)
{
ConfigEntry *pEntry, *pPrevEntry = NULL;
for ( pEntry = Entries(); pEntry != NULL; pEntry = pEntry->Next() ) {
if ( StrCmp(pEntry->Name(), szName) == 0 ) {
break;
}
pPrevEntry = pEntry;
}
if ( pEntry == NULL )
return FALSE;
// remove the element from the linked list
if ( pPrevEntry == NULL ) {
m_pEntries = pEntry->Next();
}
else {
pPrevEntry->SetNext(pEntry->Next());
}
// adjust the pointer to the last element
if ( pEntry->Next() == NULL ) {
m_pLastEntry = pPrevEntry == NULL ? m_pEntries : pPrevEntry;
}
// ... and free memory
delete pEntry;
m_pParent->SetDirty();
return TRUE;
}
// deletes this group if it has no more entries/subgroups
Bool FileConfig::DeleteIfEmpty()
{
// check if there any other subgroups/entries left
if ( m_pCurGroup->Entries() != NULL || m_pCurGroup->Subgroup() != NULL )
return FALSE;
if ( m_pCurGroup->Parent() == NULL ) {
// top group, can't delete it but mark it as not dirty,
// so that local config file will not even be created
m_pCurGroup->SetDirty(FALSE);
}
else {
// delete current group
const char *szName = m_pCurGroup->Name();
m_pCurGroup = m_pCurGroup->Parent();
m_pCurGroup->DeleteSubgroup(szName);
}
// recursively call ourselves
DeleteIfEmpty();
return TRUE;
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -