#include <stdlib.h>
#include <ctype.h>
+// ----------------------------------------------------------------------------
+// macros
+// ----------------------------------------------------------------------------
+#define CONST_CAST ((wxFileConfig *)this)->
+
// ----------------------------------------------------------------------------
// global functions declarations
// ----------------------------------------------------------------------------
// but _not_ ']' (group name delimiter)
inline bool IsValid(char c) { return isalnum(c) || strchr("@_/-!.*%", c); }
+// compare functions for sorting the arrays
+static int CompareEntries(wxFileConfig::ConfigEntry *p1,
+ wxFileConfig::ConfigEntry *p2);
+static int CompareGroups(wxFileConfig::ConfigGroup *p1,
+ wxFileConfig::ConfigGroup *p2);
+
// filter strings
static wxString FilterIn(const wxString& str);
static wxString FilterOut(const wxString& str);
const char *szHome = getenv("HOME");
if ( szHome == NULL ) {
// we're homeless...
- wxLogWarning("can't find user's HOME, using current directory.");
+ wxLogWarning(_("can't find user's HOME, using current directory."));
szHome = ".";
}
str << szHome << "/." << szFile;
m_linesHead =
m_linesTail = NULL;
- m_bExpandEnvVars = TRUE;
-
m_strPath.Empty();
}
SetRootPath();
}
else
- wxLogWarning("Can't open global configuration file '%s'.",
+ wxLogWarning(_("can't open global configuration file '%s'."),
strGlobal.c_str());
}
}
SetRootPath();
}
else
- wxLogWarning("Can't open user configuration file '%s'.",
+ wxLogWarning(_("can't open user configuration file '%s'."),
strLocal.c_str());
}
}
{
const char *pStart;
const char *pEnd;
+ wxString strLine;
+
+ uint nLineCount = file.GetLineCount();
+ for ( uint n = 0; n < nLineCount; n++ ) {
+ strLine = file[n];
- for ( uint n = 0; n < file.GetLineCount(); n++ ) {
// add the line to linked list
if ( bLocal )
- LineListAppend(file[n]);
+ LineListAppend(strLine);
// skip leading spaces
- for ( pStart = file[n]; isspace(*pStart); pStart++ )
+ for ( pStart = strLine; isspace(*pStart); pStart++ )
;
// skip blank/comment lines
}
if ( *pEnd != ']' ) {
- wxLogError("file '%s': unexpected character %c at line %d.",
+ wxLogError(_("file '%s': unexpected character %c at line %d."),
file.GetName(), *pEnd, n + 1);
continue; // skip this line
}
break;
default:
- wxLogWarning("file '%s', line %d: '%s' ignored after group header.",
+ wxLogWarning(_("file '%s', line %d: '%s' "
+ "ignored after group header."),
file.GetName(), n + 1, pEnd);
bCont = FALSE;
}
pEnd++;
if ( *pEnd++ != '=' ) {
- wxLogError("file '%s', line %d: '=' expected.", file.GetName(), n + 1);
+ wxLogError(_("file '%s', line %d: '=' expected."),
+ file.GetName(), n + 1);
}
else {
ConfigEntry *pEntry = m_pCurrentGroup->FindEntry(strKey);
else {
if ( bLocal && pEntry->IsImmutable() ) {
// immutable keys can't be changed by user
- wxLogWarning("file '%s', line %d: value for immutable key '%s' ignored.",
+ wxLogWarning(_("file '%s', line %d: value for "
+ "immutable key '%s' ignored."),
file.GetName(), n + 1, strKey.c_str());
continue;
}
// (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.",
+ wxLogWarning(_("file '%s', line %d: key '%s' was first "
+ "found at line %d."),
file.GetName(), n + 1, strKey.c_str(), pEntry->Line());
if ( bLocal )
while ( isspace(*pEnd) )
pEnd++;
- wxString strValue;
- if (m_bExpandEnvVars)
- strValue = ExpandEnvVars(FilterIn(pEnd));
- else
- strValue = FilterIn(pEnd);
- pEntry->SetValue(strValue, FALSE);
+ pEntry->SetValue(FilterIn(pEnd), FALSE /* read from file */);
}
}
}
if ( strPath[0] == APPCONF_PATH_SEPARATOR ) {
// absolute path
- SplitPath(aParts, strPath);
+ wxSplitPath(aParts, strPath);
}
else {
// relative path, combine with current one
wxString strFullPath = m_strPath;
strFullPath << APPCONF_PATH_SEPARATOR << strPath;
- SplitPath(aParts, strFullPath);
+ wxSplitPath(aParts, strFullPath);
}
// change current group
return FALSE;
}
+uint wxFileConfig::GetNumberOfEntries(bool bRecursive) const
+{
+ uint n = m_pCurrentGroup->Entries().Count();
+ if ( bRecursive ) {
+ ConfigGroup *pOldCurrentGroup = m_pCurrentGroup;
+ uint nSubgroups = m_pCurrentGroup->Groups().Count();
+ for ( uint nGroup = 0; nGroup < nSubgroups; nGroup++ ) {
+ CONST_CAST m_pCurrentGroup = m_pCurrentGroup->Groups()[nGroup];
+ n += GetNumberOfEntries(TRUE);
+ CONST_CAST m_pCurrentGroup = pOldCurrentGroup;
+ }
+ }
+
+ return n;
+}
+
+uint wxFileConfig::GetNumberOfGroups(bool bRecursive) const
+{
+ uint n = m_pCurrentGroup->Groups().Count();
+ if ( bRecursive ) {
+ ConfigGroup *pOldCurrentGroup = m_pCurrentGroup;
+ uint nSubgroups = m_pCurrentGroup->Groups().Count();
+ for ( uint nGroup = 0; nGroup < nSubgroups; nGroup++ ) {
+ CONST_CAST m_pCurrentGroup = m_pCurrentGroup->Groups()[nGroup];
+ n += GetNumberOfGroups(TRUE);
+ CONST_CAST m_pCurrentGroup = pOldCurrentGroup;
+ }
+ }
+
+ return n;
+}
+
// ----------------------------------------------------------------------------
// tests for existence
// ----------------------------------------------------------------------------
// read/write values
// ----------------------------------------------------------------------------
-const char *wxFileConfig::Read(const char *szKey,
- const char *szDefault) const
-{
- PathChanger path(this, szKey);
-
- ConfigEntry *pEntry = m_pCurrentGroup->FindEntry(path.Name());
- return pEntry == NULL ? szDefault : pEntry->Value().c_str();
-}
-
bool wxFileConfig::Read(wxString *pstr,
const char *szKey,
const char *szDefault) const
ConfigEntry *pEntry = m_pCurrentGroup->FindEntry(path.Name());
if (pEntry == NULL) {
- *pstr = szDefault;
+ *pstr = ExpandEnvVars(szDefault);
return FALSE;
}
else {
- *pstr = pEntry->Value();
+ *pstr = ExpandEnvVars(pEntry->Value());
return TRUE;
}
}
+const char *wxFileConfig::Read(const char *szKey,
+ const char *szDefault) const
+{
+ static wxString s_str;
+ Read(&s_str, szKey, szDefault);
+
+ return s_str.c_str();
+}
+
bool wxFileConfig::Read(long *pl, const char *szKey, long lDefault) const
{
wxString str;
wxTempFile file(m_strLocalFile);
if ( !file.IsOpened() ) {
- wxLogError("Can't open user configuration file.");
+ wxLogError(_("can't open user configuration file."));
return FALSE;
}
// write all strings to file
for ( LineList *p = m_linesHead; p != NULL; p = p->Next() ) {
if ( !file.Write(p->Text() + wxTextFile::GetEOL()) ) {
- wxLogError("Can't write user configuration file.");
+ wxLogError(_("can't write user configuration file."));
return FALSE;
}
}
Init();
if ( remove(szFile) == -1 )
- wxLogSysError("Can't delete user configuration file '%s'", szFile);
+ wxLogSysError(_("can't delete user configuration file '%s'"), szFile);
szFile = m_strGlobalFile;
if ( remove(szFile) )
- wxLogSysError("Can't delete system configuration file '%s'", szFile);
+ wxLogSysError(_("can't delete system configuration file '%s'"), szFile);
return TRUE;
}
wxFileConfig::ConfigGroup::ConfigGroup(wxFileConfig::ConfigGroup *pParent,
const wxString& strName,
wxFileConfig *pConfig)
- : m_strName(strName)
+ : m_aEntries(CompareEntries),
+ m_aSubgroups(CompareGroups),
+ m_strName(strName)
{
m_pConfig = pConfig;
m_pParent = pParent;
// find an item
// ----------------------------------------------------------------------------
+// use binary search because the array is sorted
wxFileConfig::ConfigEntry *
wxFileConfig::ConfigGroup::FindEntry(const char *szName) const
{
- uint nCount = m_aEntries.Count();
- for ( uint n = 0; n < nCount; n++ ) {
- if ( m_aEntries[n]->Name().IsSameAs(szName, APPCONF_CASE_SENSITIVE) )
- return m_aEntries[n];
+ uint i,
+ lo = 0,
+ hi = m_aEntries.Count();
+ int res;
+ wxFileConfig::ConfigEntry *pEntry;
+
+ while ( lo < hi ) {
+ i = (lo + hi)/2;
+ pEntry = m_aEntries[i];
+
+ #if APPCONF_CASE_SENSITIVE
+ res = strcmp(pEntry->Name(), szName);
+ #else
+ res = Stricmp(pEntry->Name(), szName);
+ #endif
+
+ if ( res > 0 )
+ hi = i;
+ else if ( res < 0 )
+ lo = i + 1;
+ else
+ return pEntry;
}
return NULL;
wxFileConfig::ConfigGroup *
wxFileConfig::ConfigGroup::FindSubgroup(const char *szName) const
{
- uint nCount = m_aSubgroups.Count();
- for ( uint n = 0; n < nCount; n++ ) {
- if ( m_aSubgroups[n]->Name().IsSameAs(szName, APPCONF_CASE_SENSITIVE) )
- return m_aSubgroups[n];
+ uint i,
+ lo = 0,
+ hi = m_aSubgroups.Count();
+ int res;
+ wxFileConfig::ConfigGroup *pGroup;
+
+ while ( lo < hi ) {
+ i = (lo + hi)/2;
+ pGroup = m_aSubgroups[i];
+
+ #if APPCONF_CASE_SENSITIVE
+ res = strcmp(pGroup->Name(), szName);
+ #else
+ res = Stricmp(pGroup->Name(), szName);
+ #endif
+
+ if ( res > 0 )
+ hi = i;
+ else if ( res < 0 )
+ lo = i + 1;
+ else
+ return pGroup;
}
return NULL;
bool wxFileConfig::ConfigGroup::DeleteSubgroup(const char *szName)
{
- uint n, nCount = m_aSubgroups.Count();
- for ( n = 0; n < nCount; n++ ) {
- if ( m_aSubgroups[n]->Name().IsSameAs(szName, APPCONF_CASE_SENSITIVE) )
- break;
- }
+ ConfigGroup *pGroup = FindSubgroup(szName);
+ wxCHECK( pGroup != NULL, FALSE ); // deleting non existing group?
- if ( n == nCount )
- return FALSE;
-
- nCount = m_aEntries.Count();
- for ( n = 0; n < nCount; n++ ) {
- LineList *pLine = m_aEntries[n]->GetLine();
+ // delete all entries
+ uint nCount = pGroup->m_aEntries.Count();
+ for ( uint nEntry = 0; nEntry < nCount; nEntry++ ) {
+ LineList *pLine = pGroup->m_aEntries[nEntry]->GetLine();
if ( pLine != NULL )
m_pConfig->LineListRemove(pLine);
}
- ConfigGroup *pGroup = m_aSubgroups[n];
LineList *pLine = pGroup->m_pLine;
if ( pLine != NULL )
m_pConfig->LineListRemove(pLine);
- delete pGroup;
SetDirty();
- m_aSubgroups.Remove(n);
+ m_aSubgroups.Remove(pGroup);
+ delete pGroup;
+
return TRUE;
}
bool wxFileConfig::ConfigGroup::DeleteEntry(const char *szName)
{
- uint n, nCount = m_aEntries.Count();
- for ( n = 0; n < nCount; n++ ) {
- if ( m_aEntries[n]->Name().IsSameAs(szName, APPCONF_CASE_SENSITIVE) )
- break;
- }
-
- if ( n == nCount )
+ ConfigEntry *pEntry = FindEntry(szName);
+ if ( pEntry == NULL )
return FALSE;
- ConfigEntry *pEntry = m_aEntries[n];
LineList *pLine = pEntry->GetLine();
if ( pLine != NULL )
m_pConfig->LineListRemove(pLine);
- delete pEntry;
SetDirty();
- m_aEntries.Remove(n);
+ m_aEntries.Remove(pEntry);
+ delete pEntry;
+
return TRUE;
}
void wxFileConfig::ConfigEntry::SetLine(LineList *pLine)
{
if ( m_pLine != NULL ) {
- wxLogWarning("Entry '%s' appears more than once in group '%s'",
+ wxLogWarning(_("entry '%s' appears more than once in group '%s'"),
Name().c_str(), m_pParent->GetFullName().c_str());
}
void wxFileConfig::ConfigEntry::SetValue(const wxString& strValue, bool bUser)
{
if ( bUser && IsImmutable() ) {
- wxLogWarning("Attempt to change immutable key '%s' ignored.",
+ wxLogWarning(_("attempt to change immutable key '%s' ignored."),
Name().c_str());
return;
}
// global functions
// ============================================================================
+// ----------------------------------------------------------------------------
+// compare functions for array sorting
+// ----------------------------------------------------------------------------
+
+int CompareEntries(wxFileConfig::ConfigEntry *p1,
+ wxFileConfig::ConfigEntry *p2)
+{
+ #if APPCONF_CASE_SENSITIVE
+ return strcmp(p1->Name(), p2->Name());
+ #else
+ return Stricmp(p1->Name(), p2->Name());
+ #endif
+}
+
+int CompareGroups(wxFileConfig::ConfigGroup *p1,
+ wxFileConfig::ConfigGroup *p2)
+{
+ #if APPCONF_CASE_SENSITIVE
+ return strcmp(p1->Name(), p2->Name());
+ #else
+ return Stricmp(p1->Name(), p2->Name());
+ #endif
+}
+
+// ----------------------------------------------------------------------------
+// filter functions
+// ----------------------------------------------------------------------------
+
// undo FilterOut
wxString FilterIn(const wxString& str)
{
strResult += '\n';
break;
+ case 'r':
+ strResult += '\r';
+ break;
+
case 't':
strResult += '\t';
break;
else {
if ( str[n] != '"' || !bQuoted )
strResult += str[n];
- else if ( n != str.Len() - 1 )
- wxLogWarning("unexpected \" at position %d in '%s'.", n, str.c_str());
+ else if ( n != str.Len() - 1 ) {
+ wxLogWarning(_("unexpected \" at position %d in '%s'."),
+ n, str.c_str());
+ }
//else: it's the last quote of a quoted string, ok
}
}
c = 'n';
break;
+ case '\r':
+ c = 'r';
+ break;
+
case '\t':
c = 't';
break;