]>
git.saurik.com Git - wxWidgets.git/blob - src/common/fileconf.cpp
1 ///////////////////////////////////////////////////////////////////////////////
3 // Purpose: implementation of wxFileConfig derivation of wxConfig
4 // Author: Vadim Zeitlin
6 // Created: 07.04.98 (adapted from appconf.cpp)
8 // Copyright: (c) 1997 Karsten Ballüder & Vadim Zeitlin
9 // Ballueder@usa.net <zeitlin@dptmaths.ens-cachan.fr>
10 // Licence: wxWindows license
11 ///////////////////////////////////////////////////////////////////////////////
14 #pragma implementation "fileconf.h"
17 // ============================================================================
19 // ============================================================================
21 // ----------------------------------------------------------------------------
23 // ----------------------------------------------------------------------------
24 #include "wx/wxprec.h"
31 #include <wx/string.h>
35 #include <wx/dynarray.h>
38 #include <wx/textfile.h>
39 #include <wx/config.h>
40 #include <wx/fileconf.h>
42 // _WINDOWS_ is defined when windows.h is included,
43 // __WXMSW__ is defined for MS Windows compilation
44 #if defined(__WXMSW__) && !defined(_WINDOWS_)
51 // ----------------------------------------------------------------------------
52 // global functions declarations
53 // ----------------------------------------------------------------------------
55 // is 'c' a valid character in group name?
56 // NB: APPCONF_IMMUTABLE_PREFIX and APPCONF_PATH_SEPARATOR must be valid chars,
57 // but _not_ ']' (group name delimiter)
58 inline bool IsValid(char c
) { return isalnum(c
) || strchr("@_/-!.*%", c
); }
60 // compare functions for sorting the arrays
61 static int CompareEntries(wxFileConfig::ConfigEntry
*p1
,
62 wxFileConfig::ConfigEntry
*p2
);
63 static int CompareGroups(wxFileConfig::ConfigGroup
*p1
,
64 wxFileConfig::ConfigGroup
*p2
);
67 static wxString
FilterIn(const wxString
& str
);
68 static wxString
FilterOut(const wxString
& str
);
70 // ============================================================================
72 // ============================================================================
74 // ----------------------------------------------------------------------------
76 // ----------------------------------------------------------------------------
77 wxString
wxFileConfig::GetGlobalFileName(const char *szFile
)
81 bool bNoExt
= strchr(szFile
, '.') == NULL
;
84 str
<< "/etc/" << szFile
;
92 char szWinDir
[_MAX_PATH
];
93 ::GetWindowsDirectory(szWinDir
, _MAX_PATH
);
94 str
<< szWinDir
<< "\\" << szFile
;
102 wxString
wxFileConfig::GetLocalFileName(const char *szFile
)
107 const char *szHome
= getenv("HOME");
108 if ( szHome
== NULL
) {
110 wxLogWarning(_("can't find user's HOME, using current directory."));
113 str
<< szHome
<< "/." << szFile
;
116 const char *szHome
= getenv("HOMEDRIVE");
117 if ( szHome
!= NULL
)
119 szHome
= getenv("HOMEPATH");
120 if ( szHome
!= NULL
)
123 if ( strchr(szFile
, '.') == NULL
)
126 // Win16 has no idea about home, so use the current directory instead
127 str
<< ".\\" << szFile
;
134 // ----------------------------------------------------------------------------
136 // ----------------------------------------------------------------------------
138 void wxFileConfig::Init()
141 m_pRootGroup
= new ConfigGroup(NULL
, "", this);
146 m_bExpandEnvVars
= TRUE
;
151 wxFileConfig::wxFileConfig(const wxString
& strLocal
, const wxString
& strGlobal
)
152 : m_strLocalFile(strLocal
), m_strGlobalFile(strGlobal
)
156 // it's not an error if (one of the) file(s) doesn't exist
158 // parse the global file
159 if ( !strGlobal
.IsEmpty() ) {
160 if ( wxFile::Exists(strGlobal
) ) {
161 wxTextFile
fileGlobal(strGlobal
);
163 if ( fileGlobal
.Open() ) {
164 Parse(fileGlobal
, FALSE
/* global */);
168 wxLogWarning(_("can't open global configuration file '%s'."),
173 // parse the local file
174 if ( wxFile::Exists(strLocal
) ) {
175 wxTextFile
fileLocal(strLocal
);
176 if ( fileLocal
.Open() ) {
177 Parse(fileLocal
, TRUE
/* local */);
181 wxLogWarning(_("can't open user configuration file '%s'."),
186 wxFileConfig::~wxFileConfig()
191 LineList
*pCur
= m_linesHead
;
192 while ( pCur
!= NULL
) {
193 LineList
*pNext
= pCur
->Next();
199 // ----------------------------------------------------------------------------
200 // parse a config file
201 // ----------------------------------------------------------------------------
203 void wxFileConfig::Parse(wxTextFile
& file
, bool bLocal
)
208 for ( uint n
= 0; n
< file
.GetLineCount(); n
++ ) {
209 // add the line to linked list
211 LineListAppend(file
[n
]);
213 // skip leading spaces
214 for ( pStart
= file
[n
]; isspace(*pStart
); pStart
++ )
217 // skip blank/comment lines
218 if ( *pStart
== '\0'|| *pStart
== ';' || *pStart
== '#' )
221 if ( *pStart
== '[' ) { // a new group
224 while ( *++pEnd
!= ']' ) {
225 if ( !IsValid(*pEnd
) && *pEnd
!= ' ' ) // allow spaces in group names
229 if ( *pEnd
!= ']' ) {
230 wxLogError(_("file '%s': unexpected character %c at line %d."),
231 file
.GetName(), *pEnd
, n
+ 1);
232 continue; // skip this line
235 // group name here is always considered as abs path
238 strGroup
<< APPCONF_PATH_SEPARATOR
<< wxString(pStart
, pEnd
- pStart
);
240 // will create it if doesn't yet exist
244 m_pCurrentGroup
->SetLine(m_linesTail
);
246 // check that there is nothing except comments left on this line
248 while ( *++pEnd
!= '\0' && bCont
) {
257 // ignore whitespace ('\n' impossible here)
261 wxLogWarning(_("file '%s', line %d: '%s' "
262 "ignored after group header."),
263 file
.GetName(), n
+ 1, pEnd
);
269 const char *pEnd
= pStart
;
270 while ( IsValid(*pEnd
) )
273 wxString
strKey(pStart
, pEnd
);
276 while ( isspace(*pEnd
) )
279 if ( *pEnd
++ != '=' ) {
280 wxLogError(_("file '%s', line %d: '=' expected."),
281 file
.GetName(), n
+ 1);
284 ConfigEntry
*pEntry
= m_pCurrentGroup
->FindEntry(strKey
);
286 if ( pEntry
== NULL
) {
288 pEntry
= m_pCurrentGroup
->AddEntry(strKey
, n
);
291 pEntry
->SetLine(m_linesTail
);
294 if ( bLocal
&& pEntry
->IsImmutable() ) {
295 // immutable keys can't be changed by user
296 wxLogWarning(_("file '%s', line %d: value for "
297 "immutable key '%s' ignored."),
298 file
.GetName(), n
+ 1, strKey
.c_str());
301 // the condition below catches the cases (a) and (b) but not (c):
302 // (a) global key found second time in global file
303 // (b) key found second (or more) time in local file
304 // (c) key from global file now found in local one
305 // which is exactly what we want.
306 else if ( !bLocal
|| pEntry
->IsLocal() ) {
307 wxLogWarning(_("file '%s', line %d: key '%s' was first "
308 "found at line %d."),
309 file
.GetName(), n
+ 1, strKey
.c_str(), pEntry
->Line());
312 pEntry
->SetLine(m_linesTail
);
317 while ( isspace(*pEnd
) )
321 if (m_bExpandEnvVars
)
322 strValue
= ExpandEnvVars(FilterIn(pEnd
));
324 strValue
= FilterIn(pEnd
);
325 pEntry
->SetValue(strValue
, FALSE
);
331 // ----------------------------------------------------------------------------
333 // ----------------------------------------------------------------------------
335 void wxFileConfig::SetRootPath()
338 m_pCurrentGroup
= m_pRootGroup
;
341 void wxFileConfig::SetPath(const wxString
& strPath
)
343 wxArrayString aParts
;
345 if ( strPath
.IsEmpty() ) {
350 if ( strPath
[0] == APPCONF_PATH_SEPARATOR
) {
352 SplitPath(aParts
, strPath
);
355 // relative path, combine with current one
356 wxString strFullPath
= m_strPath
;
357 strFullPath
<< APPCONF_PATH_SEPARATOR
<< strPath
;
358 SplitPath(aParts
, strFullPath
);
361 // change current group
363 m_pCurrentGroup
= m_pRootGroup
;
364 for ( n
= 0; n
< aParts
.Count(); n
++ ) {
365 ConfigGroup
*pNextGroup
= m_pCurrentGroup
->FindSubgroup(aParts
[n
]);
366 if ( pNextGroup
== NULL
)
367 pNextGroup
= m_pCurrentGroup
->AddSubgroup(aParts
[n
]);
368 m_pCurrentGroup
= pNextGroup
;
371 // recombine path parts in one variable
373 for ( n
= 0; n
< aParts
.Count(); n
++ ) {
374 m_strPath
<< APPCONF_PATH_SEPARATOR
<< aParts
[n
];
378 // ----------------------------------------------------------------------------
380 // ----------------------------------------------------------------------------
382 bool wxFileConfig::GetFirstGroup(wxString
& str
, long& lIndex
)
385 return GetNextGroup(str
, lIndex
);
388 bool wxFileConfig::GetNextGroup (wxString
& str
, long& lIndex
)
390 if ( uint(lIndex
) < m_pCurrentGroup
->Groups().Count() ) {
391 str
= m_pCurrentGroup
->Groups()[lIndex
++]->Name();
398 bool wxFileConfig::GetFirstEntry(wxString
& str
, long& lIndex
)
401 return GetNextEntry(str
, lIndex
);
404 bool wxFileConfig::GetNextEntry (wxString
& str
, long& lIndex
)
406 if ( uint(lIndex
) < m_pCurrentGroup
->Entries().Count() ) {
407 str
= m_pCurrentGroup
->Entries()[lIndex
++]->Name();
414 // ----------------------------------------------------------------------------
415 // tests for existence
416 // ----------------------------------------------------------------------------
418 bool wxFileConfig::HasGroup(const wxString
& strName
) const
420 PathChanger
path(this, strName
);
422 ConfigGroup
*pGroup
= m_pCurrentGroup
->FindSubgroup(path
.Name());
423 return pGroup
!= NULL
;
426 bool wxFileConfig::HasEntry(const wxString
& strName
) const
428 PathChanger
path(this, strName
);
430 ConfigEntry
*pEntry
= m_pCurrentGroup
->FindEntry(path
.Name());
431 return pEntry
!= NULL
;
434 // ----------------------------------------------------------------------------
436 // ----------------------------------------------------------------------------
438 const char *wxFileConfig::Read(const char *szKey
,
439 const char *szDefault
) const
441 PathChanger
path(this, szKey
);
443 ConfigEntry
*pEntry
= m_pCurrentGroup
->FindEntry(path
.Name());
444 return pEntry
== NULL
? szDefault
: pEntry
->Value().c_str();
447 bool wxFileConfig::Read(wxString
*pstr
,
449 const char *szDefault
) const
451 PathChanger
path(this, szKey
);
453 ConfigEntry
*pEntry
= m_pCurrentGroup
->FindEntry(path
.Name());
454 if (pEntry
== NULL
) {
459 *pstr
= pEntry
->Value();
464 bool wxFileConfig::Read(long *pl
, const char *szKey
, long lDefault
) const
467 if ( Read(&str
, szKey
) ) {
477 bool wxFileConfig::Write(const char *szKey
, const char *szValue
)
479 PathChanger
path(this, szKey
);
481 ConfigEntry
*pEntry
= m_pCurrentGroup
->FindEntry(path
.Name());
482 if ( pEntry
== NULL
)
483 pEntry
= m_pCurrentGroup
->AddEntry(path
.Name());
484 pEntry
->SetValue(szValue
);
489 bool wxFileConfig::Write(const char *szKey
, long lValue
)
491 // ltoa() is not ANSI :-(
492 char szBuf
[40]; // should be good for sizeof(long) <= 16 (128 bits)
493 sprintf(szBuf
, "%ld", lValue
);
494 return Write(szKey
, szBuf
);
497 bool wxFileConfig::Flush(bool /* bCurrentOnly */)
499 if ( LineListIsEmpty() || !m_pRootGroup
->IsDirty() )
502 wxTempFile
file(m_strLocalFile
);
504 if ( !file
.IsOpened() ) {
505 wxLogError(_("can't open user configuration file."));
509 // write all strings to file
510 for ( LineList
*p
= m_linesHead
; p
!= NULL
; p
= p
->Next() ) {
511 if ( !file
.Write(p
->Text() + wxTextFile::GetEOL()) ) {
512 wxLogError(_("can't write user configuration file."));
517 return file
.Commit();
520 // ----------------------------------------------------------------------------
521 // delete groups/entries
522 // ----------------------------------------------------------------------------
524 bool wxFileConfig::DeleteEntry(const char *szKey
, bool bGroupIfEmptyAlso
)
526 PathChanger
path(this, szKey
);
528 if ( !m_pCurrentGroup
->DeleteEntry(path
.Name()) )
531 if ( bGroupIfEmptyAlso
&& m_pCurrentGroup
->IsEmpty() ) {
532 if ( m_pCurrentGroup
!= m_pRootGroup
) {
533 ConfigGroup
*pGroup
= m_pCurrentGroup
;
534 SetPath(".."); // changes m_pCurrentGroup!
535 m_pCurrentGroup
->DeleteSubgroup(pGroup
->Name());
537 //else: never delete the root group
543 bool wxFileConfig::DeleteGroup(const char *szKey
)
545 PathChanger
path(this, szKey
);
547 return m_pCurrentGroup
->DeleteSubgroup(path
.Name());
550 bool wxFileConfig::DeleteAll()
552 const char *szFile
= m_strLocalFile
;
556 if ( remove(szFile
) == -1 )
557 wxLogSysError(_("can't delete user configuration file '%s'"), szFile
);
559 szFile
= m_strGlobalFile
;
560 if ( remove(szFile
) )
561 wxLogSysError(_("can't delete system configuration file '%s'"), szFile
);
566 // ----------------------------------------------------------------------------
567 // linked list functions
568 // ----------------------------------------------------------------------------
570 // append a new line to the end of the list
571 wxFileConfig::LineList
*wxFileConfig::LineListAppend(const wxString
& str
)
573 LineList
*pLine
= new LineList(str
);
575 if ( m_linesTail
== NULL
) {
581 m_linesTail
->SetNext(pLine
);
582 pLine
->SetPrev(m_linesTail
);
589 // insert a new line after the given one or in the very beginning if !pLine
590 wxFileConfig::LineList
*wxFileConfig::LineListInsert(const wxString
& str
,
593 if ( pLine
== m_linesTail
)
594 return LineListAppend(str
);
596 LineList
*pNewLine
= new LineList(str
);
597 if ( pLine
== NULL
) {
598 // prepend to the list
599 pNewLine
->SetNext(m_linesHead
);
600 m_linesHead
->SetPrev(pNewLine
);
601 m_linesHead
= pNewLine
;
604 // insert before pLine
605 LineList
*pNext
= pLine
->Next();
606 pNewLine
->SetNext(pNext
);
607 pNewLine
->SetPrev(pLine
);
608 pNext
->SetPrev(pNewLine
);
609 pLine
->SetNext(pNewLine
);
615 void wxFileConfig::LineListRemove(LineList
*pLine
)
617 LineList
*pPrev
= pLine
->Prev(),
618 *pNext
= pLine
->Next();
619 if ( pPrev
== NULL
) {
620 // deleting the first entry
624 // not the first entry
625 pPrev
->SetNext(pNext
);
628 pNext
->SetPrev(pPrev
);
633 bool wxFileConfig::LineListIsEmpty()
635 return m_linesHead
== NULL
;
638 // ============================================================================
639 // wxFileConfig::ConfigGroup
640 // ============================================================================
642 // ----------------------------------------------------------------------------
644 // ----------------------------------------------------------------------------
647 wxFileConfig::ConfigGroup::ConfigGroup(wxFileConfig::ConfigGroup
*pParent
,
648 const wxString
& strName
,
649 wxFileConfig
*pConfig
)
650 : m_aEntries(CompareEntries
),
651 m_aSubgroups(CompareGroups
),
662 // dtor deletes all children
663 wxFileConfig::ConfigGroup::~ConfigGroup()
666 uint n
, nCount
= m_aEntries
.Count();
667 for ( n
= 0; n
< nCount
; n
++ )
668 delete m_aEntries
[n
];
671 nCount
= m_aSubgroups
.Count();
672 for ( n
= 0; n
< nCount
; n
++ )
673 delete m_aSubgroups
[n
];
676 // ----------------------------------------------------------------------------
678 // ----------------------------------------------------------------------------
680 void wxFileConfig::ConfigGroup::SetLine(LineList
*pLine
)
682 wxASSERT( m_pLine
== NULL
); // shouldn't be called twice
687 // return the line which contains "[our name]"
688 wxFileConfig::LineList
*wxFileConfig::ConfigGroup::GetGroupLine()
690 if ( m_pLine
== NULL
) {
691 // this group wasn't present in local config file, add it now
692 if ( Parent() != NULL
) {
693 wxString strFullName
;
694 strFullName
<< "[" << GetFullName().c_str() + 1 << "]"; // +1: no '/'
695 m_pLine
= m_pConfig
->LineListInsert(strFullName
,
696 Parent()->GetLastGroupLine());
697 Parent()->SetLastGroup(this);
700 // we return NULL, so that LineListInsert() will insert us in the
708 // return the last line belonging to the subgroups of this group
709 // (after which we can add a new subgroup)
710 wxFileConfig::LineList
*wxFileConfig::ConfigGroup::GetLastGroupLine()
712 // if we have any subgroups, our last line is the last line of the last
714 if ( m_pLastGroup
!= NULL
)
715 return m_pLastGroup
->GetLastGroupLine();
717 // if we have any entries, our last line is the last entry
718 if ( m_pLastEntry
!= NULL
)
719 return m_pLastEntry
->GetLine();
721 // nothing at all: last line is the first one
722 return GetGroupLine();
725 // return the last line belonging to the entries of this group
726 // (after which we can add a new entry)
727 wxFileConfig::LineList
*wxFileConfig::ConfigGroup::GetLastEntryLine()
729 if ( m_pLastEntry
!= NULL
) {
730 wxFileConfig::LineList
*pLine
= m_pLastEntry
->GetLine();
732 wxASSERT( pLine
!= NULL
); // last entry must have !NULL associated line
736 // no entrues: insert after the group header
737 return GetGroupLine();
740 // ----------------------------------------------------------------------------
742 // ----------------------------------------------------------------------------
744 wxString
wxFileConfig::ConfigGroup::GetFullName() const
747 return Parent()->GetFullName() + APPCONF_PATH_SEPARATOR
+ Name();
752 // ----------------------------------------------------------------------------
754 // ----------------------------------------------------------------------------
756 // use binary search because the array is sorted
757 wxFileConfig::ConfigEntry
*
758 wxFileConfig::ConfigGroup::FindEntry(const char *szName
) const
762 hi
= m_aEntries
.Count();
764 wxFileConfig::ConfigEntry
*pEntry
;
768 pEntry
= m_aEntries
[i
];
770 #if APPCONF_CASE_SENSITIVE
771 res
= strcmp(pEntry
->Name(), szName
);
773 res
= Stricmp(pEntry
->Name(), szName
);
787 wxFileConfig::ConfigGroup
*
788 wxFileConfig::ConfigGroup::FindSubgroup(const char *szName
) const
792 hi
= m_aSubgroups
.Count();
794 wxFileConfig::ConfigGroup
*pGroup
;
798 pGroup
= m_aSubgroups
[i
];
800 #if APPCONF_CASE_SENSITIVE
801 res
= strcmp(pGroup
->Name(), szName
);
803 res
= Stricmp(pGroup
->Name(), szName
);
817 // ----------------------------------------------------------------------------
819 // ----------------------------------------------------------------------------
821 // create a new entry and add it to the current group
822 wxFileConfig::ConfigEntry
*
823 wxFileConfig::ConfigGroup::AddEntry(const wxString
& strName
, int nLine
)
825 wxASSERT( FindEntry(strName
) == NULL
);
827 ConfigEntry
*pEntry
= new ConfigEntry(this, strName
, nLine
);
828 m_aEntries
.Add(pEntry
);
833 // create a new group and add it to the current group
834 wxFileConfig::ConfigGroup
*
835 wxFileConfig::ConfigGroup::AddSubgroup(const wxString
& strName
)
837 wxASSERT( FindSubgroup(strName
) == NULL
);
839 ConfigGroup
*pGroup
= new ConfigGroup(this, strName
, m_pConfig
);
840 m_aSubgroups
.Add(pGroup
);
845 // ----------------------------------------------------------------------------
847 // ----------------------------------------------------------------------------
849 bool wxFileConfig::ConfigGroup::DeleteSubgroup(const char *szName
)
851 uint n
, nCount
= m_aSubgroups
.Count();
852 for ( n
= 0; n
< nCount
; n
++ ) {
853 if ( m_aSubgroups
[n
]->Name().IsSameAs(szName
, APPCONF_CASE_SENSITIVE
) )
860 nCount
= m_aEntries
.Count();
861 for ( n
= 0; n
< nCount
; n
++ ) {
862 LineList
*pLine
= m_aEntries
[n
]->GetLine();
864 m_pConfig
->LineListRemove(pLine
);
867 ConfigGroup
*pGroup
= m_aSubgroups
[n
];
868 LineList
*pLine
= pGroup
->m_pLine
;
870 m_pConfig
->LineListRemove(pLine
);
875 m_aSubgroups
.Remove(n
);
879 bool wxFileConfig::ConfigGroup::DeleteEntry(const char *szName
)
881 uint n
, nCount
= m_aEntries
.Count();
882 for ( n
= 0; n
< nCount
; n
++ ) {
883 if ( m_aEntries
[n
]->Name().IsSameAs(szName
, APPCONF_CASE_SENSITIVE
) )
890 ConfigEntry
*pEntry
= m_aEntries
[n
];
891 LineList
*pLine
= pEntry
->GetLine();
893 m_pConfig
->LineListRemove(pLine
);
898 m_aEntries
.Remove(n
);
902 // ----------------------------------------------------------------------------
904 // ----------------------------------------------------------------------------
905 void wxFileConfig::ConfigGroup::SetDirty()
908 if ( Parent() != NULL
) // propagate upwards
909 Parent()->SetDirty();
912 // ============================================================================
913 // wxFileConfig::ConfigEntry
914 // ============================================================================
916 // ----------------------------------------------------------------------------
918 // ----------------------------------------------------------------------------
919 wxFileConfig::ConfigEntry::ConfigEntry(wxFileConfig::ConfigGroup
*pParent
,
920 const wxString
& strName
,
930 m_bImmutable
= strName
[0] == APPCONF_IMMUTABLE_PREFIX
;
932 m_strName
.erase(0, 1); // remove first character
935 // ----------------------------------------------------------------------------
937 // ----------------------------------------------------------------------------
939 void wxFileConfig::ConfigEntry::SetLine(LineList
*pLine
)
941 if ( m_pLine
!= NULL
) {
942 wxLogWarning(_("entry '%s' appears more than once in group '%s'"),
943 Name().c_str(), m_pParent
->GetFullName().c_str());
947 Group()->SetLastEntry(this);
950 // second parameter is FALSE if we read the value from file and prevents the
951 // entry from being marked as 'dirty'
952 void wxFileConfig::ConfigEntry::SetValue(const wxString
& strValue
, bool bUser
)
954 if ( bUser
&& IsImmutable() ) {
955 wxLogWarning(_("attempt to change immutable key '%s' ignored."),
960 // do nothing if it's the same value
961 if ( strValue
== m_strValue
)
964 m_strValue
= strValue
;
967 wxString strVal
= FilterOut(strValue
);
969 strLine
<< m_strName
<< " = " << strVal
;
971 if ( m_pLine
!= NULL
) {
972 // entry was read from the local config file, just modify the line
973 m_pLine
->SetText(strLine
);
976 // add a new line to the file
977 wxASSERT( m_nLine
== NOT_FOUND
); // consistency check
979 m_pLine
= Group()->Config()->LineListInsert(strLine
,
980 Group()->GetLastEntryLine());
981 Group()->SetLastEntry(this);
988 void wxFileConfig::ConfigEntry::SetDirty()
994 // ============================================================================
996 // ============================================================================
998 // ----------------------------------------------------------------------------
999 // compare functions for array sorting
1000 // ----------------------------------------------------------------------------
1002 int CompareEntries(wxFileConfig::ConfigEntry
*p1
,
1003 wxFileConfig::ConfigEntry
*p2
)
1005 #if APPCONF_CASE_SENSITIVE
1006 return strcmp(p1
->Name(), p2
->Name());
1008 return Stricmp(p1
->Name(), p2
->Name());
1012 int CompareGroups(wxFileConfig::ConfigGroup
*p1
,
1013 wxFileConfig::ConfigGroup
*p2
)
1015 #if APPCONF_CASE_SENSITIVE
1016 return strcmp(p1
->Name(), p2
->Name());
1018 return Stricmp(p1
->Name(), p2
->Name());
1022 // ----------------------------------------------------------------------------
1024 // ----------------------------------------------------------------------------
1027 wxString
FilterIn(const wxString
& str
)
1030 strResult
.Alloc(str
.Len());
1032 bool bQuoted
= !str
.IsEmpty() && str
[0] == '"';
1034 for ( uint n
= bQuoted
? 1 : 0; n
< str
.Len(); n
++ ) {
1035 if ( str
[n
] == '\\' ) {
1036 switch ( str
[++n
] ) {
1059 if ( str
[n
] != '"' || !bQuoted
)
1060 strResult
+= str
[n
];
1061 else if ( n
!= str
.Len() - 1 ) {
1062 wxLogWarning(_("unexpected \" at position %d in '%s'."),
1065 //else: it's the last quote of a quoted string, ok
1072 // quote the string before writing it to file
1073 wxString
FilterOut(const wxString
& str
)
1076 strResult
.Alloc(str
.Len());
1078 // quoting is necessary to preserve spaces in the beginning of the string
1079 bool bQuote
= isspace(str
[0]) || str
[0] == '"';
1085 for ( uint n
= 0; n
< str
.Len(); n
++ ) {
1106 //else: fall through
1109 strResult
+= str
[n
];
1110 continue; // nothing special to do
1113 // we get here only for special characters
1114 strResult
<< '\\' << c
;