#pragma implementation "fileconf.h"
#endif
-// ============================================================================
-// declarations
-// ============================================================================
-
// ----------------------------------------------------------------------------
// headers
// ----------------------------------------------------------------------------
+
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif //__BORLANDC__
+#if wxUSE_CONFIG
+
#ifndef WX_PRECOMP
#include "wx/string.h"
#include "wx/intl.h"
#if defined(__WXMSW__) && !defined(_WINDOWS_)
#include <windows.h>
#endif //windows.h
+#if defined(__WXPM__)
+ #define INCL_DOS
+ #include <os2.h>
+#endif
#include <stdlib.h>
#include <ctype.h>
+// headers needed for umask()
+#ifdef __UNIX__
+ #include <sys/types.h>
+ #include <sys/stat.h>
+#endif // __UNIX__
+
// ----------------------------------------------------------------------------
// macros
// ----------------------------------------------------------------------------
// global functions declarations
// ----------------------------------------------------------------------------
-// is 'c' a valid character in group name?
-// NB: wxCONFIG_IMMUTABLE_PREFIX and wxCONFIG_PATH_SEPARATOR must be valid chars,
-// 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);
+static int LINKAGEMODE CompareEntries(ConfigEntry *p1, ConfigEntry *p2);
+static int LINKAGEMODE CompareGroups(ConfigGroup *p1, ConfigGroup *p2);
// filter strings
-static wxString FilterIn(const wxString& str);
-static wxString FilterOut(const wxString& str);
+static wxString FilterInValue(const wxString& str);
+static wxString FilterOutValue(const wxString& str);
+
+static wxString FilterInEntryName(const wxString& str);
+static wxString FilterOutEntryName(const wxString& str);
+
+// get the name to use in wxFileConfig ctor
+static wxString GetAppName(const wxString& appname);
// ============================================================================
// implementation
{
wxString strDir;
- #ifdef __UNIX__
- strDir = "/etc/";
+ #ifdef __VMS__ // Note if __VMS is defined __UNIX is also defined
+ strDir = wxT("sys$manager:");
+ #elif defined( __UNIX__ )
+ strDir = wxT("/etc/");
+ #elif defined(__WXPM__)
+ ULONG aulSysInfo[QSV_MAX] = {0};
+ UINT drive;
+ APIRET rc;
+
+ rc = DosQuerySysInfo( 1L, QSV_MAX, (PVOID)aulSysInfo, sizeof(ULONG)*QSV_MAX);
+ if (rc == 0)
+ {
+ drive = aulSysInfo[QSV_BOOT_DRIVE - 1];
+ switch(drive)
+ {
+ case 1:
+ strDir = "A:\\OS2\\";
+ break;
+ case 2:
+ strDir = "B:\\OS2\\";
+ break;
+ case 3:
+ strDir = "C:\\OS2\\";
+ break;
+ case 4:
+ strDir = "D:\\OS2\\";
+ break;
+ case 5:
+ strDir = "E:\\OS2\\";
+ break;
+ case 6:
+ strDir = "F:\\OS2\\";
+ break;
+ case 7:
+ strDir = "G:\\OS2\\";
+ break;
+ case 8:
+ strDir = "H:\\OS2\\";
+ break;
+ case 9:
+ strDir = "I:\\OS2\\";
+ break;
+ case 10:
+ strDir = "J:\\OS2\\";
+ break;
+ case 11:
+ strDir = "K:\\OS2\\";
+ break;
+ case 12:
+ strDir = "L:\\OS2\\";
+ break;
+ case 13:
+ strDir = "M:\\OS2\\";
+ break;
+ case 14:
+ strDir = "N:\\OS2\\";
+ break;
+ case 15:
+ strDir = "O:\\OS2\\";
+ break;
+ case 16:
+ strDir = "P:\\OS2\\";
+ break;
+ case 17:
+ strDir = "Q:\\OS2\\";
+ break;
+ case 18:
+ strDir = "R:\\OS2\\";
+ break;
+ case 19:
+ strDir = "S:\\OS2\\";
+ break;
+ case 20:
+ strDir = "T:\\OS2\\";
+ break;
+ case 21:
+ strDir = "U:\\OS2\\";
+ break;
+ case 22:
+ strDir = "V:\\OS2\\";
+ break;
+ case 23:
+ strDir = "W:\\OS2\\";
+ break;
+ case 24:
+ strDir = "X:\\OS2\\";
+ break;
+ case 25:
+ strDir = "Y:\\OS2\\";
+ break;
+ case 26:
+ strDir = "Z:\\OS2\\";
+ break;
+ }
+ }
#elif defined(__WXSTUBS__)
- wxASSERT_MSG( FALSE, "TODO" ) ;
+ wxASSERT_MSG( FALSE, wxT("TODO") ) ;
+ #elif defined(__WXMAC__)
+ strDir = wxMacFindFolder( (short) kOnSystemDisk, kPreferencesFolderType, kDontCreateFolder ) ;
#else // Windows
- char szWinDir[MAX_PATH];
+ wxChar szWinDir[MAX_PATH];
::GetWindowsDirectory(szWinDir, MAX_PATH);
strDir = szWinDir;
- strDir << '\\';
+ strDir << wxT('\\');
#endif // Unix/Windows
return strDir;
wxString wxFileConfig::GetLocalDir()
{
wxString strDir;
-
+
+#ifndef __WXMAC__
wxGetHomeDir(&strDir);
+#ifdef __UNIX__
+#ifdef __VMS
+ if (strDir.Last() != wxT(']'))
+#endif
+ if (strDir.Last() != wxT('/')) strDir << wxT('/');
+#else
+ if (strDir.Last() != wxT('\\')) strDir << wxT('\\');
+#endif
+#else
+ // no local dir concept on mac
+ return GetGlobalDir() ;
+#endif
+
return strDir;
}
-wxString wxFileConfig::GetGlobalFileName(const char *szFile)
+wxString wxFileConfig::GetGlobalFileName(const wxChar *szFile)
{
wxString str = GetGlobalDir();
str << szFile;
- if ( strchr(szFile, '.') == NULL )
+ if ( wxStrchr(szFile, wxT('.')) == NULL )
#ifdef __UNIX__
- str << ".conf";
+ str << wxT(".conf");
+ #elif defined( __WXMAC__ )
+ str << " Preferences";
#else // Windows
- str << ".ini";
+ str << wxT(".ini");
#endif // UNIX/Win
return str;
}
-wxString wxFileConfig::GetLocalFileName(const char *szFile)
+wxString wxFileConfig::GetLocalFileName(const wxChar *szFile)
{
- wxString str = GetLocalDir();
-
- #ifdef __UNIX__
- str << '.';
+#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?
+ wxString str = wxT( '.' );
+#else
+ wxString str = GetLocalDir();
+#endif
+
+ #if defined( __UNIX__ ) && !defined( __VMS )
+ str << wxT('.');
#endif
str << szFile;
#ifdef __WXMSW__
- if ( strchr(szFile, '.') == NULL )
- str << ".ini";
+ if ( wxStrchr(szFile, wxT('.')) == NULL )
+ str << wxT(".ini");
#endif
+
+ #ifdef __WXMAC__
+ str << " Preferences";
+ #endif
return str;
}
wxFileConfig::wxFileConfig(const wxString& appName, const wxString& vendorName,
const wxString& strLocal, const wxString& strGlobal,
long style)
- : wxConfigBase(appName, vendorName, strLocal, strGlobal, style),
+ : wxConfigBase(::GetAppName(appName), vendorName,
+ strLocal, strGlobal,
+ style),
m_strLocalFile(strLocal), m_strGlobalFile(strGlobal)
{
- // Make up an application name if not supplied
- if (appName.IsEmpty() && wxTheApp)
- {
- SetAppName(wxTheApp->GetAppName());
- }
-
// Make up names for files if empty
if ( m_strLocalFile.IsEmpty() && (style & wxCONFIG_USE_LOCAL_FILE) )
{
SetStyle(GetStyle() | wxCONFIG_USE_GLOBAL_FILE);
// if the path is not absolute, prepend the standard directory to it
- if ( !m_strLocalFile.IsEmpty() && !wxIsAbsolutePath(m_strLocalFile) )
+ // UNLESS wxCONFIG_USE_RELATIVE_PATH style is set
+ if ( !(style & wxCONFIG_USE_RELATIVE_PATH) )
{
- wxString strLocal = m_strLocalFile;
- m_strLocalFile = GetLocalDir();
- m_strLocalFile << strLocal;
- }
+ if ( !m_strLocalFile.IsEmpty() && !wxIsAbsolutePath(m_strLocalFile) )
+ {
+ wxString strLocal = m_strLocalFile;
+ m_strLocalFile = GetLocalDir();
+ m_strLocalFile << strLocal;
+ }
- if ( !m_strGlobalFile.IsEmpty() && !wxIsAbsolutePath(m_strGlobalFile) )
- {
- wxString strGlobal = m_strGlobalFile;
- m_strGlobalFile = GetGlobalDir();
- m_strGlobalFile << strGlobal;
+ if ( !m_strGlobalFile.IsEmpty() && !wxIsAbsolutePath(m_strGlobalFile) )
+ {
+ wxString strGlobal = m_strGlobalFile;
+ m_strGlobalFile = GetGlobalDir();
+ m_strGlobalFile << strGlobal;
+ }
}
+ SetUmask(-1);
+
Init();
}
void wxFileConfig::Parse(wxTextFile& file, bool bLocal)
{
- const char *pStart;
- const char *pEnd;
+ const wxChar *pStart;
+ const wxChar *pEnd;
wxString strLine;
size_t nLineCount = file.GetLineCount();
LineListAppend(strLine);
// skip leading spaces
- for ( pStart = strLine; isspace(*pStart); pStart++ )
+ for ( pStart = strLine; wxIsspace(*pStart); pStart++ )
;
// skip blank/comment lines
- if ( *pStart == '\0'|| *pStart == ';' || *pStart == '#' )
+ if ( *pStart == wxT('\0')|| *pStart == wxT(';') || *pStart == wxT('#') )
continue;
- if ( *pStart == '[' ) { // a new group
+ if ( *pStart == wxT('[') ) { // a new group
pEnd = pStart;
- while ( *++pEnd != ']' ) {
- if ( !IsValid(*pEnd) && *pEnd != ' ' ) // allow spaces in group names
- break;
+ 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 != ']' ) {
+ if ( *pEnd != wxT(']') ) {
wxLogError(_("file '%s': unexpected character %c at line %d."),
file.GetName(), *pEnd, n + 1);
continue; // skip this line
// group name here is always considered as abs path
wxString strGroup;
pStart++;
- strGroup << wxCONFIG_PATH_SEPARATOR << wxString(pStart, pEnd - pStart);
+ strGroup << wxCONFIG_PATH_SEPARATOR
+ << FilterInEntryName(wxString(pStart, pEnd - pStart));
// will create it if doesn't yet exist
SetPath(strGroup);
// check that there is nothing except comments left on this line
bool bCont = TRUE;
- while ( *++pEnd != '\0' && bCont ) {
+ while ( *++pEnd != wxT('\0') && bCont ) {
switch ( *pEnd ) {
- case '#':
- case ';':
+ case wxT('#'):
+ case wxT(';'):
bCont = FALSE;
break;
- case ' ':
- case '\t':
+ case wxT(' '):
+ case wxT('\t'):
// ignore whitespace ('\n' impossible here)
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;
}
}
}
else { // a key
- const char *pEnd = pStart;
- while ( IsValid(*pEnd) )
+ 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(pStart, pEnd);
+ wxString strKey(FilterInEntryName(wxString(pStart, pEnd)));
// skip whitespace
- while ( isspace(*pEnd) )
+ while ( wxIsspace(*pEnd) )
pEnd++;
- if ( *pEnd++ != '=' ) {
+ if ( *pEnd++ != wxT('=') ) {
wxLogError(_("file '%s', line %d: '=' expected."),
file.GetName(), n + 1);
}
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 )
}
// skip whitespace
- while ( isspace(*pEnd) )
+ while ( wxIsspace(*pEnd) )
pEnd++;
- pEntry->SetValue(FilterIn(pEnd), FALSE /* read from file */);
+ pEntry->SetValue(FilterInValue(pEnd), FALSE /* read from file */);
}
}
}
bool wxFileConfig::GetNextGroup (wxString& str, long& lIndex) const
{
if ( size_t(lIndex) < m_pCurrentGroup->Groups().Count() ) {
- str = m_pCurrentGroup->Groups()[lIndex++]->Name();
+ str = m_pCurrentGroup->Groups()[(size_t)lIndex++]->Name();
return TRUE;
}
else
bool wxFileConfig::GetNextEntry (wxString& str, long& lIndex) const
{
if ( size_t(lIndex) < m_pCurrentGroup->Entries().Count() ) {
- str = m_pCurrentGroup->Entries()[lIndex++]->Name();
+ str = m_pCurrentGroup->Entries()[(size_t)lIndex++]->Name();
return TRUE;
}
else
if (pEntry == NULL) {
return FALSE;
}
- else {
- *pStr = ExpandEnvVars(pEntry->Value());
- return TRUE;
- }
+
+ *pStr = ExpandEnvVars(pEntry->Value());
+ return TRUE;
}
bool wxFileConfig::Read(const wxString& key,
wxConfigPathChanger path(this, key);
ConfigEntry *pEntry = m_pCurrentGroup->FindEntry(path.Name());
+ bool ok;
if (pEntry == NULL) {
if( IsRecordingDefaults() )
((wxFileConfig *)this)->Write(key,defVal);
*pStr = ExpandEnvVars(defVal);
- return FALSE;
+ ok = FALSE;
}
else {
*pStr = ExpandEnvVars(pEntry->Value());
- return TRUE;
+ ok = TRUE;
}
+
+ return ok;
}
bool wxFileConfig::Read(const wxString& key, long *pl) const
{
wxString str;
- if ( Read(key, & str) ) {
- *pl = atol(str);
- return TRUE;
- }
- else {
+ if ( !Read(key, & str) )
+ {
return FALSE;
}
+
+ *pl = wxAtol(str);
+ return TRUE;
}
bool wxFileConfig::Write(const wxString& key, const wxString& szValue)
wxString strName = path.Name();
if ( strName.IsEmpty() ) {
// setting the value of a group is an error
- wxASSERT_MSG( IsEmpty(szValue), _("can't set value of a group!") );
+ wxASSERT_MSG( wxIsEmpty(szValue), wxT("can't set value of a group!") );
// ... except if it's empty in which case it's a way to force it's creation
m_pCurrentGroup->SetDirty();
// check that the name is reasonable
if ( strName[0u] == wxCONFIG_IMMUTABLE_PREFIX ) {
- wxLogError(_("Entry name can't start with '%c'."),
+ wxLogError(_("Config entry name cannot start with '%c'."),
wxCONFIG_IMMUTABLE_PREFIX);
return FALSE;
}
- for ( const char *pc = strName; *pc != '\0'; pc++ ) {
- if ( !IsValid(*pc) ) {
- wxLogError(_("Character '%c' is invalid in a config entry name."),
- *pc);
- return FALSE;
- }
- }
-
ConfigEntry *pEntry = m_pCurrentGroup->FindEntry(strName);
if ( pEntry == NULL )
pEntry = m_pCurrentGroup->AddEntry(strName);
bool wxFileConfig::Write(const wxString& key, long lValue)
{
// ltoa() is not ANSI :-(
- char szBuf[40]; // should be good for sizeof(long) <= 16 (128 bits)
- sprintf(szBuf, "%ld", lValue);
- return Write(key, szBuf);
+ wxString buf;
+ buf.Printf(wxT("%ld"), lValue);
+ return Write(key, buf);
}
bool wxFileConfig::Flush(bool /* bCurrentOnly */)
{
- if ( LineListIsEmpty() || !m_pRootGroup->IsDirty() )
+ if ( LineListIsEmpty() || !m_pRootGroup->IsDirty() || !m_strLocalFile )
return TRUE;
+#ifdef __UNIX__
+ // set the umask if needed
+ mode_t umaskOld = 0;
+ if ( m_umask != -1 )
+ {
+ umaskOld = umask((mode_t)m_umask);
+ }
+#endif // __UNIX__
+
wxTempFile file(m_strLocalFile);
if ( !file.IsOpened() ) {
}
}
- return file.Commit();
+ bool ret = file.Commit();
+
+#if defined(__WXMAC__) && !defined(__UNIX__)
+ if ( ret )
+ {
+ FSSpec spec ;
+
+ wxUnixFilename2FSSpec( m_strLocalFile , &spec ) ;
+ FInfo finfo ;
+ if ( FSpGetFInfo( &spec , &finfo ) == noErr )
+ {
+ finfo.fdType = 'TEXT' ;
+ finfo.fdCreator = 'ttxt' ;
+ FSpSetFInfo( &spec , &finfo ) ;
+ }
+ }
+#endif // __WXMAC__ && !__UNIX__
+
+#ifdef __UNIX__
+ // restore the old umask if we changed it
+ if ( m_umask != -1 )
+ {
+ (void)umask(umaskOld);
+ }
+#endif // __UNIX__
+
+ return ret;
+}
+
+// ----------------------------------------------------------------------------
+// renaming groups/entries
+// ----------------------------------------------------------------------------
+
+bool wxFileConfig::RenameEntry(const wxString& oldName,
+ const wxString& newName)
+{
+ // check that the entry exists
+ ConfigEntry *oldEntry = m_pCurrentGroup->FindEntry(oldName);
+ if ( !oldEntry )
+ return FALSE;
+
+ // check that the new entry doesn't already exist
+ if ( m_pCurrentGroup->FindEntry(newName) )
+ return FALSE;
+
+ // delete the old entry, create the new one
+ wxString value = oldEntry->Value();
+ if ( !m_pCurrentGroup->DeleteEntry(oldName) )
+ return FALSE;
+
+ ConfigEntry *newEntry = m_pCurrentGroup->AddEntry(newName);
+ newEntry->SetValue(value);
+
+ return TRUE;
+}
+
+bool wxFileConfig::RenameGroup(const wxString& oldName,
+ const wxString& newName)
+{
+ // check that the group exists
+ ConfigGroup *group = m_pCurrentGroup->FindSubgroup(oldName);
+ if ( !group )
+ return FALSE;
+
+ // check that the new group doesn't already exist
+ if ( m_pCurrentGroup->FindSubgroup(newName) )
+ return FALSE;
+
+ group->Rename(newName);
+
+ return TRUE;
}
// ----------------------------------------------------------------------------
if ( bGroupIfEmptyAlso && m_pCurrentGroup->IsEmpty() ) {
if ( m_pCurrentGroup != m_pRootGroup ) {
ConfigGroup *pGroup = m_pCurrentGroup;
- SetPath(".."); // changes m_pCurrentGroup!
+ SetPath(wxT("..")); // changes m_pCurrentGroup!
m_pCurrentGroup->DeleteSubgroupByName(pGroup->Name());
}
//else: never delete the root group
{
CleanUp();
- const char *szFile = m_strLocalFile;
-
- if ( remove(szFile) == -1 )
- wxLogSysError(_("can't delete user configuration file '%s'"), szFile);
+ if ( wxRemove(m_strLocalFile) == -1 )
+ wxLogSysError(_("can't delete user configuration file '%s'"), m_strLocalFile.c_str());
- m_strLocalFile = m_strGlobalFile = "";
+ m_strLocalFile = m_strGlobalFile = wxT("");
Init();
return TRUE;
// ----------------------------------------------------------------------------
// append a new line to the end of the list
-wxFileConfig::LineList *wxFileConfig::LineListAppend(const wxString& str)
+LineList *wxFileConfig::LineListAppend(const wxString& str)
{
LineList *pLine = new LineList(str);
}
// insert a new line after the given one or in the very beginning if !pLine
-wxFileConfig::LineList *wxFileConfig::LineListInsert(const wxString& str,
+LineList *wxFileConfig::LineListInsert(const wxString& str,
LineList *pLine)
{
if ( pLine == m_linesTail )
// last entry?
if ( pNext == NULL )
m_linesTail = pPrev;
- else
+ else
pNext->SetPrev(pPrev);
delete pLine;
// ----------------------------------------------------------------------------
// ctor
-wxFileConfig::ConfigGroup::ConfigGroup(wxFileConfig::ConfigGroup *pParent,
+ConfigGroup::ConfigGroup(ConfigGroup *pParent,
const wxString& strName,
wxFileConfig *pConfig)
: m_aEntries(CompareEntries),
}
// dtor deletes all children
-wxFileConfig::ConfigGroup::~ConfigGroup()
+ConfigGroup::~ConfigGroup()
{
// entries
size_t n, nCount = m_aEntries.Count();
// line
// ----------------------------------------------------------------------------
-void wxFileConfig::ConfigGroup::SetLine(LineList *pLine)
+void ConfigGroup::SetLine(LineList *pLine)
{
wxASSERT( m_pLine == NULL ); // shouldn't be called twice
backwards in the config file (OTOH, it's not that important) and as we
would still need to do it for the subgroups the code wouldn't have been
significantly less complicated.
- */
+*/
// Return the line which contains "[our name]". If we're still not in the list,
// add our line to it immediately after the last line of our parent group if we
// have it or in the very beginning if we're the root group.
-wxFileConfig::LineList *wxFileConfig::ConfigGroup::GetGroupLine()
+LineList *ConfigGroup::GetGroupLine()
{
if ( m_pLine == NULL ) {
ConfigGroup *pParent = Parent();
// this group wasn't present in local config file, add it now
if ( pParent != NULL ) {
wxString strFullName;
- strFullName << "[" << GetFullName().c_str() + 1 << "]"; // +1: no '/'
+ strFullName << wxT("[")
+ // +1: no '/'
+ << FilterOutEntryName(GetFullName().c_str() + 1)
+ << wxT("]");
m_pLine = m_pConfig->LineListInsert(strFullName,
pParent->GetLastGroupLine());
pParent->SetLastGroup(this); // we're surely after all the others
// Return the last line belonging to the subgroups of this group (after which
// we can add a new subgroup), if we don't have any subgroups or entries our
// last line is the group line (m_pLine) itself.
-wxFileConfig::LineList *wxFileConfig::ConfigGroup::GetLastGroupLine()
+LineList *ConfigGroup::GetLastGroupLine()
{
// if we have any subgroups, our last line is the last line of the last
// subgroup
if ( m_pLastGroup != NULL ) {
- wxFileConfig::LineList *pLine = m_pLastGroup->GetLastGroupLine();
+ LineList *pLine = m_pLastGroup->GetLastGroupLine();
wxASSERT( pLine != NULL ); // last group must have !NULL associated line
return pLine;
// return the last line belonging to the entries of this group (after which
// we can add a new entry), if we don't have any entries we will add the new
// one immediately after the group line itself.
-wxFileConfig::LineList *wxFileConfig::ConfigGroup::GetLastEntryLine()
+LineList *ConfigGroup::GetLastEntryLine()
{
if ( m_pLastEntry != NULL ) {
- wxFileConfig::LineList *pLine = m_pLastEntry->GetLine();
+ LineList *pLine = m_pLastEntry->GetLine();
wxASSERT( pLine != NULL ); // last entry must have !NULL associated line
return pLine;
// group name
// ----------------------------------------------------------------------------
-wxString wxFileConfig::ConfigGroup::GetFullName() const
+void ConfigGroup::Rename(const wxString& newName)
+{
+ m_strName = newName;
+
+ LineList *line = GetGroupLine();
+ wxString strFullName;
+ strFullName << wxT("[") << (GetFullName().c_str() + 1) << wxT("]"); // +1: no '/'
+ line->SetText(strFullName);
+
+ SetDirty();
+}
+
+wxString ConfigGroup::GetFullName() const
{
if ( Parent() )
return Parent()->GetFullName() + wxCONFIG_PATH_SEPARATOR + Name();
else
- return "";
+ return wxT("");
}
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// use binary search because the array is sorted
-wxFileConfig::ConfigEntry *
-wxFileConfig::ConfigGroup::FindEntry(const char *szName) const
+ConfigEntry *
+ConfigGroup::FindEntry(const wxChar *szName) const
{
size_t i,
lo = 0,
hi = m_aEntries.Count();
int res;
- wxFileConfig::ConfigEntry *pEntry;
+ ConfigEntry *pEntry;
while ( lo < hi ) {
i = (lo + hi)/2;
pEntry = m_aEntries[i];
#if wxCONFIG_CASE_SENSITIVE
- res = strcmp(pEntry->Name(), szName);
+ res = wxStrcmp(pEntry->Name(), szName);
#else
- res = Stricmp(pEntry->Name(), szName);
+ res = wxStricmp(pEntry->Name(), szName);
#endif
if ( res > 0 )
return NULL;
}
-wxFileConfig::ConfigGroup *
-wxFileConfig::ConfigGroup::FindSubgroup(const char *szName) const
+ConfigGroup *
+ConfigGroup::FindSubgroup(const wxChar *szName) const
{
size_t i,
lo = 0,
hi = m_aSubgroups.Count();
int res;
- wxFileConfig::ConfigGroup *pGroup;
+ ConfigGroup *pGroup;
while ( lo < hi ) {
i = (lo + hi)/2;
pGroup = m_aSubgroups[i];
#if wxCONFIG_CASE_SENSITIVE
- res = strcmp(pGroup->Name(), szName);
+ res = wxStrcmp(pGroup->Name(), szName);
#else
- res = Stricmp(pGroup->Name(), szName);
+ res = wxStricmp(pGroup->Name(), szName);
#endif
if ( res > 0 )
// ----------------------------------------------------------------------------
// create a new entry and add it to the current group
-wxFileConfig::ConfigEntry *
-wxFileConfig::ConfigGroup::AddEntry(const wxString& strName, int nLine)
+ConfigEntry *
+ConfigGroup::AddEntry(const wxString& strName, int nLine)
{
wxASSERT( FindEntry(strName) == NULL );
}
// create a new group and add it to the current group
-wxFileConfig::ConfigGroup *
-wxFileConfig::ConfigGroup::AddSubgroup(const wxString& strName)
+ConfigGroup *
+ConfigGroup::AddSubgroup(const wxString& strName)
{
wxASSERT( FindSubgroup(strName) == NULL );
delete several of them.
*/
-bool wxFileConfig::ConfigGroup::DeleteSubgroupByName(const char *szName)
+bool ConfigGroup::DeleteSubgroupByName(const wxChar *szName)
{
return DeleteSubgroup(FindSubgroup(szName));
}
// doesn't delete the subgroup itself, but does remove references to it from
// all other data structures (and normally the returned pointer should be
// deleted a.s.a.p. because there is nothing much to be done with it anyhow)
-bool wxFileConfig::ConfigGroup::DeleteSubgroup(ConfigGroup *pGroup)
+bool ConfigGroup::DeleteSubgroup(ConfigGroup *pGroup)
{
wxCHECK( pGroup != NULL, FALSE ); // deleting non existing group?
// and subgroups of this sungroup
nCount = pGroup->m_aSubgroups.Count();
for ( size_t nGroup = 0; nGroup < nCount; nGroup++ ) {
- pGroup->DeleteSubgroup(pGroup->m_aSubgroups[nGroup]);
+ pGroup->DeleteSubgroup(pGroup->m_aSubgroups[0]);
}
LineList *pLine = pGroup->m_pLine;
return TRUE;
}
-bool wxFileConfig::ConfigGroup::DeleteEntry(const char *szName)
+bool ConfigGroup::DeleteEntry(const wxChar *szName)
{
ConfigEntry *pEntry = FindEntry(szName);
wxCHECK( pEntry != NULL, FALSE ); // deleting non existing item?
// ----------------------------------------------------------------------------
//
// ----------------------------------------------------------------------------
-void wxFileConfig::ConfigGroup::SetDirty()
+void ConfigGroup::SetDirty()
{
m_bDirty = TRUE;
if ( Parent() != NULL ) // propagate upwards
// ----------------------------------------------------------------------------
// ctor
// ----------------------------------------------------------------------------
-wxFileConfig::ConfigEntry::ConfigEntry(wxFileConfig::ConfigGroup *pParent,
+ConfigEntry::ConfigEntry(ConfigGroup *pParent,
const wxString& strName,
int nLine)
: m_strName(strName)
// set value
// ----------------------------------------------------------------------------
-void wxFileConfig::ConfigEntry::SetLine(LineList *pLine)
+void ConfigEntry::SetLine(LineList *pLine)
{
if ( m_pLine != NULL ) {
wxLogWarning(_("entry '%s' appears more than once in group '%s'"),
// second parameter is FALSE if we read the value from file and prevents the
// entry from being marked as 'dirty'
-void wxFileConfig::ConfigEntry::SetValue(const wxString& strValue, bool bUser)
+void ConfigEntry::SetValue(const wxString& strValue, bool bUser)
{
if ( bUser && IsImmutable() ) {
wxLogWarning(_("attempt to change immutable key '%s' ignored."),
m_strValue = strValue;
if ( bUser ) {
- wxString strVal = FilterOut(strValue);
+ wxString strVal = FilterOutValue(strValue);
wxString strLine;
- strLine << m_strName << " = " << strVal;
+ strLine << FilterOutEntryName(m_strName) << wxT('=') << strVal;
if ( m_pLine != NULL ) {
// entry was read from the local config file, just modify the line
}
else {
// add a new line to the file
- wxASSERT( m_nLine == NOT_FOUND ); // consistency check
+ wxASSERT( m_nLine == wxNOT_FOUND ); // consistency check
m_pLine = Group()->Config()->LineListInsert(strLine,
Group()->GetLastEntryLine());
}
}
-void wxFileConfig::ConfigEntry::SetDirty()
+void ConfigEntry::SetDirty()
{
m_bDirty = TRUE;
Group()->SetDirty();
// compare functions for array sorting
// ----------------------------------------------------------------------------
-int CompareEntries(wxFileConfig::ConfigEntry *p1,
- wxFileConfig::ConfigEntry *p2)
+int CompareEntries(ConfigEntry *p1,
+ ConfigEntry *p2)
{
#if wxCONFIG_CASE_SENSITIVE
- return strcmp(p1->Name(), p2->Name());
+ return wxStrcmp(p1->Name(), p2->Name());
#else
- return Stricmp(p1->Name(), p2->Name());
+ return wxStricmp(p1->Name(), p2->Name());
#endif
}
-int CompareGroups(wxFileConfig::ConfigGroup *p1,
- wxFileConfig::ConfigGroup *p2)
+int CompareGroups(ConfigGroup *p1,
+ ConfigGroup *p2)
{
#if wxCONFIG_CASE_SENSITIVE
- return strcmp(p1->Name(), p2->Name());
+ return wxStrcmp(p1->Name(), p2->Name());
#else
- return Stricmp(p1->Name(), p2->Name());
+ return wxStricmp(p1->Name(), p2->Name());
#endif
}
// filter functions
// ----------------------------------------------------------------------------
-// undo FilterOut
-wxString FilterIn(const wxString& str)
+// undo FilterOutValue
+static wxString FilterInValue(const wxString& str)
{
wxString strResult;
strResult.Alloc(str.Len());
bool bQuoted = !str.IsEmpty() && str[0] == '"';
for ( size_t n = bQuoted ? 1 : 0; n < str.Len(); n++ ) {
- if ( str[n] == '\\' ) {
+ if ( str[n] == wxT('\\') ) {
switch ( str[++n] ) {
- case 'n':
- strResult += '\n';
+ case wxT('n'):
+ strResult += wxT('\n');
break;
- case 'r':
- strResult += '\r';
+ case wxT('r'):
+ strResult += wxT('\r');
break;
- case 't':
- strResult += '\t';
+ case wxT('t'):
+ strResult += wxT('\t');
break;
- case '\\':
- strResult += '\\';
+ case wxT('\\'):
+ strResult += wxT('\\');
break;
- case '"':
- strResult += '"';
+ case wxT('"'):
+ strResult += wxT('"');
break;
}
}
else {
- if ( str[n] != '"' || !bQuoted )
+ if ( str[n] != wxT('"') || !bQuoted )
strResult += str[n];
else if ( n != str.Len() - 1 ) {
wxLogWarning(_("unexpected \" at position %d in '%s'."),
}
// quote the string before writing it to file
-wxString FilterOut(const wxString& str)
+static wxString FilterOutValue(const wxString& str)
{
- if(str.IsEmpty())
+ if ( !str )
return str;
-
+
wxString strResult;
strResult.Alloc(str.Len());
// quoting is necessary to preserve spaces in the beginning of the string
- bool bQuote = isspace(str[0]) || str[0] == '"';
+ bool bQuote = wxIsspace(str[0]) || str[0] == wxT('"');
if ( bQuote )
- strResult += '"';
+ strResult += wxT('"');
- char c;
+ wxChar c;
for ( size_t n = 0; n < str.Len(); n++ ) {
switch ( str[n] ) {
- case '\n':
- c = 'n';
+ case wxT('\n'):
+ c = wxT('n');
break;
- case '\r':
- c = 'r';
+ case wxT('\r'):
+ c = wxT('r');
break;
- case '\t':
- c = 't';
+ case wxT('\t'):
+ c = wxT('t');
break;
- case '\\':
- c = '\\';
+ case wxT('\\'):
+ c = wxT('\\');
break;
- case '"':
+ case wxT('"'):
if ( bQuote ) {
- c = '"';
+ c = wxT('"');
break;
}
//else: fall through
}
// we get here only for special characters
- strResult << '\\' << c;
+ strResult << wxT('\\') << c;
}
if ( bQuote )
- strResult += '"';
+ strResult += wxT('"');
return strResult;
}
+
+// undo FilterOutEntryName
+static wxString FilterInEntryName(const wxString& str)
+{
+ wxString strResult;
+ strResult.Alloc(str.Len());
+
+ for ( const wxChar *pc = str.c_str(); *pc != '\0'; pc++ ) {
+ if ( *pc == wxT('\\') )
+ pc++;
+
+ strResult += *pc;
+ }
+
+ return strResult;
+}
+
+// sanitize entry or group name: insert '\\' before any special characters
+static wxString FilterOutEntryName(const wxString& str)
+{
+ wxString strResult;
+ strResult.Alloc(str.Len());
+
+ for ( const wxChar *pc = str.c_str(); *pc != wxT('\0'); pc++ ) {
+ wxChar c = *pc;
+
+ // we explicitly allow some of "safe" chars and 8bit ASCII characters
+ // which will probably never have special meaning
+ // NB: note that wxCONFIG_IMMUTABLE_PREFIX and wxCONFIG_PATH_SEPARATOR
+ // should *not* be quoted
+ if ( !wxIsalnum(c) && !wxStrchr(wxT("@_/-!.*%"), c) && ((c & 0x80) == 0) )
+ strResult += wxT('\\');
+
+ strResult += c;
+ }
+
+ return strResult;
+}
+
+// we can't put ?: in the ctor initializer list because it confuses some
+// broken compilers (Borland C++)
+static wxString GetAppName(const wxString& appName)
+{
+ if ( !appName && wxTheApp )
+ return wxTheApp->GetAppName();
+ else
+ return appName;
+}
+
+#endif // wxUSE_CONFIG
+