📄 appconf.cpp
字号:
strncpy(szGroupName, pBegin, len);
szGroupName[len - 1] = '\0';
ConfigGroup *pGroup = m_pCurGroup->FindSubgroup(szGroupName);
if ( pGroup == NULL ) {
// not found: insert new group in the list
m_pCurGroup = m_pCurGroup->AddSubgroup(szGroupName);
}
else {
m_pCurGroup = pGroup;
}
if ( *pEnd == APPCONF_PATH_SEPARATOR ) {
pBegin = ++pEnd;
}
}while ( *pEnd != '\0' );
if ( szGroupName != NULL )
delete [] szGroupName;
}
// set value of a key, creating it if doesn't yet exist
Bool FileConfig::writeEntry(const char *szKey, const char *szValue)
{
ConfigEntry *pEntry = m_pCurGroup->FindEntry(szKey);
if ( pEntry == NULL ) {
pEntry = m_pCurGroup->AddEntry(szKey);
}
pEntry->SetValue(szValue);
return TRUE;
}
// delete entry and the parent group if it's the last entry in this group
Bool FileConfig::deleteEntry(const char *szKey)
{
Bool bDeleted = m_pCurGroup->DeleteEntry(szKey);
DeleteIfEmpty();
return bDeleted;
}
// ----------------------------------------------------------------------------
// functions which update data on disk (or wherever...)
// ----------------------------------------------------------------------------
Bool FileConfig::flush(Bool bCurrentOnly)
{
ConfigGroup *pRootGroup = bCurrentOnly ? m_pCurGroup : m_pRootGroup;
if ( m_pRootGroup->IsDirty() ) {
std::fstream outStream(LocalConfigFile(), std::ios::out);
Bool bOk = pRootGroup->flush(&outStream);
// special case: [comment and blank] lines following the last entry
// were not yet written to the file, do it now.
if ( m_szComment != NULL ) {
outStream << m_szComment;
}
outStream.sync();
return bOk;
}
else
return TRUE;
}
Bool FileConfig::flush(std::ostream *oStream, Bool bCurrentOnly)
{
ConfigGroup *pRootGroup = bCurrentOnly ? m_pCurGroup : m_pRootGroup;
if ( m_pRootGroup->IsDirty() ) {
Bool bOk = pRootGroup->flush(oStream);
// special case: [comment and blank] lines following the last entry
// were not yet written to the file, do it now.
if ( m_szComment != NULL ) {
*oStream << m_szComment;
}
return bOk;
}
else
return TRUE;
}
// ----------------------------------------------------------------------------
// Comments management
// ## another kludge: this function is always called, but does nothing when
// parsing global file (we can't write these comments back anyhow)
// ----------------------------------------------------------------------------
void FileConfig::AppendCommentLine(const char *szComment)
{
if ( !m_bParsingLocal )
return;
size_t len = Strlen(m_szComment) + strlen(szComment) + 1;
char *szNewComment = new char[len + 1];
if ( m_szComment == NULL ) {
szNewComment[0] = '\0';
}
else {
strcpy(szNewComment, m_szComment);
delete [] m_szComment;
}
strcat(szNewComment, szComment);
strcat(szNewComment, "\n");
m_szComment = szNewComment;
}
// ----------------------------------------------------------------------------
// Enumeration of entries/subgroups
// ----------------------------------------------------------------------------
BaseConfig::Enumerator *FileConfig::enumSubgroups() const
{
size_t nGroups = 0;
ConfigGroup *pGroup = m_pCurGroup->Subgroup();
while ( pGroup != NULL ) {
nGroups++;
pGroup = pGroup->Next();
}
BaseConfig::Enumerator *pEnum = new Enumerator(nGroups, FALSE);
pGroup = m_pCurGroup->Subgroup();
for ( size_t n = 0; n < nGroups; n++ ) {
pEnum->AddString(pGroup->Name());
pGroup = pGroup->Next();
}
return pEnum;
}
BaseConfig::Enumerator *FileConfig::enumEntries() const
{
size_t nEntries = 0;
ConfigEntry *pEntry = m_pCurGroup->Entries();
while ( pEntry != NULL ) {
nEntries++;
pEntry = pEntry->Next();
}
BaseConfig::Enumerator *pEnum = new Enumerator(nEntries, FALSE);
pEntry = m_pCurGroup->Entries();
for ( size_t n = 0; n < nEntries; n++ ) {
pEnum->AddString(pEntry->Name());
pEntry = pEntry->Next();
}
return pEnum;
}
// ============================================================================
// implementation of the class RegistryConfig
// ============================================================================
#ifdef __WIN32__
// ----------------------------------------------------------------------------
// ctor & dtor
// ----------------------------------------------------------------------------
// ctor opens our root key under HKLM
RegistryConfig::RegistryConfig(const char *szRootKey)
{
static const char szPrefix[] = "Software";
char *szKey = new char[strlen(szPrefix) + Strlen(szRootKey) + 2];
strcpy(szKey, szPrefix);
strcat(szKey, "\\");
strcat(szKey, szRootKey);
// don't create if doesn't exist
LONG lRc = RegOpenKey(HKEY_LOCAL_MACHINE, szKey, &m_hGlobalRootKey);
m_bOk = lRc == ERROR_SUCCESS;
if ( !m_bOk )
m_hGlobalRootKey = NULL;
m_hGlobalCurKey = m_hGlobalRootKey;
// create if doesn't exist
lRc = RegCreateKey(HKEY_CURRENT_USER, szKey, &m_hLocalRootKey);
m_hLocalCurKey = m_hLocalRootKey;
if ( !m_bOk )
m_bOk = lRc;
m_pLastRead = NULL;
delete [] szKey;
}
// free resources
RegistryConfig::~RegistryConfig()
{
if ( m_pLastRead != NULL )
delete [] m_pLastRead;
if ( m_hGlobalRootKey != NULL )
RegCloseKey(m_hGlobalRootKey);
if ( m_hLocalRootKey != NULL )
RegCloseKey(m_hLocalRootKey);
// don't close same key twice
if ( m_hGlobalCurKey != NULL && m_hGlobalCurKey != m_hGlobalRootKey )
RegCloseKey(m_hGlobalCurKey);
if ( m_hLocalCurKey != NULL && m_hLocalCurKey != m_hLocalRootKey )
RegCloseKey(m_hLocalCurKey);
}
// ----------------------------------------------------------------------------
// read/write entry - no buffering, data goes directly to the registry
// ----------------------------------------------------------------------------
// helper for readEntry which needs to read both the global and local ones
// ### MT unsafe because of m_pLastRead
const char *RegistryConfig::ReadValue(void *hKey, const char *szValue) const
{
// get size of data first
DWORD dwSize;
LONG lRc = RegQueryValueEx(hKey, szValue, 0, NULL, NULL, &dwSize);
if ( lRc != ERROR_SUCCESS )
return NULL;
char *szBuffer = new char[dwSize];
DWORD dwType;
lRc = RegQueryValueEx(hKey, szValue, 0, &dwType,
(unsigned char *)szBuffer, &dwSize);
if ( lRc != ERROR_SUCCESS ) {
// it's not normal for it to fail now (i.e. after the first call was ok)
LogWarning(_("can't query the value '%s' (%s)."), szValue, SysError());
return NULL;
}
// always automatically expand strings of this type
if ( dwType == REG_EXPAND_SZ ) {
// first get length
DWORD dwLen = ExpandEnvironmentStrings(szBuffer, NULL, 0);
// alloc memory and expand
char *szBufferExp = new char[dwLen + 1];
ExpandEnvironmentStrings(szBuffer, szBufferExp, dwLen + 1);
// copy to the original buffer
delete [] szBuffer;
szBuffer = szBufferExp;
}
// free old pointer (last thing we returned from here)
if ( m_pLastRead != NULL )
delete [] m_pLastRead;
// const_cast
((RegistryConfig *)this)->m_pLastRead = filterIn((const char *)szBuffer);
delete [] szBuffer;
return m_pLastRead;
}
// read value from the current key
// first try the user's setting, than the system.
const char *RegistryConfig::readEntry(const char *szKey,
const char *szDefault) const
{
const char *pRetValue = ReadValue(m_hLocalCurKey, szKey);
// if no local value exist and current path exists in global part, try it
if ( pRetValue == NULL && m_hGlobalCurKey != NULL )
pRetValue = ReadValue(m_hGlobalCurKey, szKey);
if(pRetValue != NULL)
return pRetValue;
else
{
if(m_bRecordDefaults)
writeEntry(szKey, szDefault);
return szDefault;
}
}
// write (or create) value under current key
// NB: only to user's part
Bool RegistryConfig::writeEntry(const char *szKey, const char *szValue)
{
char *szFiltered = filterOut(szValue);
long lRc = RegSetValueEx(m_hLocalCurKey, szKey, 0, REG_SZ,
(unsigned char *)szFiltered,
Strlen(szFiltered) + 1);
delete [] szFiltered;
return lRc == ERROR_SUCCESS;
}
// delete the key and the key which contains it if this is the last subkey
Bool RegistryConfig::deleteEntry(const char *szKey)
{
Bool bDeleted = RegDeleteValue(m_hLocalCurKey, szKey) == ERROR_SUCCESS;
if ( !bDeleted ) {
// # don't output error message if the key is not found?
LogWarning(_("can't delete entry '%s': %s"), szKey, SysError());
}
// even if there was an error before, still check if the key is not empty:
// otherwise an attempt to delete a non existing entry would _create_ a
// new subkey!
while ( KeyIsEmpty(m_hLocalCurKey) ) {
// delete this key
const char *szPath = getCurrentPath();
const char *szKeyName = strrchr(szPath, APPCONF_PATH_SEPARATOR);
if ( szKeyName == NULL )
szKeyName = szPath;
else
szKeyName++; // to skip APPCONF_PATH_SEPARATOR
// must copy it because the call to changeCurrentPath will change it!
char *aszSubkey = new char[strlen(szKeyName) + 1];
strcpy(aszSubkey, szKeyName);
// don't delete root key
if ( *szKeyName != '\0' ) {
changeCurrentPath("..");
if ( RegDeleteKey(m_hLocalCurKey, aszSubkey) != ERROR_SUCCESS )
LogWarning(_("can't delete key '%s': %s"), aszSubkey, SysError());
}
delete [] aszSubkey;
}
return bDeleted;
}
// ----------------------------------------------------------------------------
// Enumeration of entries/subgroups (both system and user)
// ### this code is messy :-( The problem is that we try to enumerate both the
// global and local keys at once, but we don't want keys common to both
// branches appear twice, hence we check for each global key that it
// doesn't appear locally at the end (very inefficient too).
// ----------------------------------------------------------------------------
BaseConfig::Enumerator *RegistryConfig::enumSubgroups() const
{
DWORD dwKeysLocal, dwKeysGlobal, // number of subkeys
dwKeyLenLocal, dwKeyLenGlobal; // length of the longest subkey
long lRc = RegQueryInfoKey(m_hLocalCurKey, NULL, NULL, NULL,
&dwKeysLocal, &dwKeyLenLocal,
NULL, NULL, NULL, NULL, NULL, NULL);
assert( lRc == ERROR_SUCCESS ); // it should never fail here
if ( m_hGlobalCurKey == NULL ) {
// key doesn't exist
dwKeysGlobal = dwKeyLenGlobal = 0;
}
else {
lRc = RegQueryInfoKey(m_hGlobalCurKey, NULL, NULL, NULL, &dwKeysGlobal,
&dwKeyLenGlobal, NULL, NULL, NULL, NULL, NULL, NULL);
assert( lRc == ERROR_SUCCESS ); // it should never fail here
}
DWORD dwKeys = dwKeysLocal + dwKeysGlobal;
DWORD dwKeyLen = max(dwKeyLenLocal, dwKeyLenGlobal);
BaseConfig::Enumerator *pEnum = new Enumerator((size_t)dwKeys, TRUE);
char *szKey;
HKEY hKey = m_hGlobalCurKey;
for ( DWORD dwKey = 0; dwKeys > 0; dwKey++, dwKeys-- ) {
if ( dwKeys == dwKeysLocal ) {
// finished with global keys, now for local ones
hKey = m_hLocalCurKey;
dwKey = 0;
}
szKey = new char[dwKeyLen + 1];
if ( RegEnumKey(hKey, dwKey, szKey, dwKeyLen + 1) != ERROR_SUCCESS ) {
delete [] szKey;
break;
}
pEnum->AddString(szKey); // enumerator will delete it
}
pEnum->MakeUnique();
return pEnum;
}
BaseConfig::Enumerator *RegistryConfig::enumEntries() const
{
DWORD dwEntriesLocal, dwEntriesGlobal, // number of values
dwEntryLenLocal, dwEntryLenGlobal; // length of the longest value name
long lRc = RegQueryInfoKey(m_hLocalCurKey, NULL, NULL, NULL,
NULL, NULL, NULL,
&dwEntriesLocal, &dwEntryLenLocal,
NULL, NULL, NULL);
assert( lRc == ERROR_SUCCESS ); // it should never fail here
if ( m_hGlobalCurKey == NULL ) {
// key doesn't exist
dwEntriesGlobal = dwEntryLenGlobal = 0;
}
else {
lRc = RegQueryInfoKey(m_hGlobalCurKey,
NULL, NULL, NULL,
NULL, NULL, NULL,
&dwEntriesGlobal,
&dwEntryLenGlobal,
NULL, NULL, NULL);
assert( lRc == ERROR_SUCCESS ); // it should never fail here
}
DWORD dwEntries = dwEntriesLocal + dwEntriesGlobal;
DWORD dwEntryLen = max(dwEntryLenLocal, dwEntryLenGlobal);
BaseConfig::Enumerator *pEnum = new Enumerator((size_t)dwEntries, TRUE);
char *szVal;
DWORD dwLen;
HKEY hKey = m_hGlobalCurKey;
for ( DWORD dwEntry = 0; dwEntries > 0; dwEntry++, dwEntries-- ) {
if ( dwEntries == dwEntriesLocal ) {
// finished with global keys, now for local ones
hKey = m_hLocalCurKey;
dwEntry = 0;
}
dwLen = dwEntryLen + 1;
szVal = new char [dwLen];
lRc = RegEnumValue(hKey, dwEntry, szVal, &dwLen, 0, NULL, NULL, NULL);
if ( lRc != ERROR_SUCCESS ) {
delete [] szVal;
break;
}
pEnum->AddString(szVal); // enumerator will delete it
}
pEnum->MakeUnique();
return pEnum;
}
// ----------------------------------------------------------------------------
// change current key
// ----------------------------------------------------------------------------
// only in user's registry hive (not in global one)
void RegistryConfig::changeCurrentPath(const char *szPath)
{
// normalize path
BaseConfig::changeCurrentPath(szPath);
szPath = getCurrentPath();
// special case because RegCreateKey(hKey, "") fails!
if ( *szPath == '\0' ) {
if ( m_hLocalCurKey != m_hLocalRootKey ) {
RegCloseKey(m_hLocalCurKey);
m_hLocalCurKey = m_hLocalRootKey;
}
if ( m_hGlobalCurKey != m_hGlobalRootKey ) {
RegCloseKey(m_hGlobalCurKey);
m_hGlobalCurKey = m_hGlobalRootKey;
}
return;
}
char *szRegPath = new char[Strlen(szPath) + 1];
strcpy(szRegPath, szPath);
// replace all APPCONF_PATH_SEPARATORs with '\'
char *pcSeparator = szRegPath;
while ( pcSeparator != NULL ) {
pcSeparator = strchr(pcSeparator, APPCONF_PATH_SEPARATOR);
if ( pcSeparator != NULL )
*pcSeparator = '\\';
}
HKEY hOldKey = m_hLocalCurKey;
if ( RegCreateKey(m_hLocalRootKey, szRegPath,
&m_hLocalCurKey) == ERROR_SUCCESS ) {
// at any time, we keep open two keys
// here we check that we don't close them
if ( (m_hLocalCurKey != hOldKey) && (hOldKey != m_hLocalRootKey) )
RegCloseKey(hOldKey);
}
else {
LogWarning(_("can not open key '%s' (%s)."), szPath, SysError());
}
if ( m_hGlobalCurKey != 0 ) {
hOldKey = m_hGlobalCurKey;
if ( RegOpenKey(m_hGlobalRootKey, szRegPath,
&m_hGlobalCurKey) == ERROR_SUCCESS ) {
if ( (m_hGlobalCurKey != hOldKey) && (hOldKey != m_hGlobalRootKey) )
RegCloseKey(hOldKey);
}
else {
// no such key
if ( m_hGlobalCurKey != m_hGlobalRootKey )
RegCloseKey(m_hGlobalCurKey);
m_hGlobalCurKey = NULL;
}
}
delete [] szRegPath;
}
// ----------------------------------------------------------------------------
// helper function: return TRUE if the key has no subkeys/values
// ----------------------------------------------------------------------------
Bool RegistryConfig::KeyIsEmpty(void *hKey)
{
DWORD dwKeys, dwValues;
long lRc = RegQueryInfoKey(hKey, NULL, NULL, NULL, &dwKeys, NULL, NULL,
&dwValues, NULL, NULL, NULL, NULL);
return (lRc == ERROR_SUCCESS) && (dwValues == 0) && (dwKeys == 0);
}
#endif // WIN32
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -