]>
git.saurik.com Git - wxWidgets.git/blob - src/common/fileconf.cpp
f25cb997dc44770f7e6c9ec0937d90860f8346f0
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' ignored after group header.",
262 file
.GetName(), n
+ 1, pEnd
);
268 const char *pEnd
= pStart
;
269 while ( IsValid(*pEnd
) )
272 wxString
strKey(pStart
, pEnd
);
275 while ( isspace(*pEnd
) )
278 if ( *pEnd
++ != '=' ) {
279 wxLogError("file '%s', line %d: '=' expected.", file
.GetName(), n
+ 1);
282 ConfigEntry
*pEntry
= m_pCurrentGroup
->FindEntry(strKey
);
284 if ( pEntry
== NULL
) {
286 pEntry
= m_pCurrentGroup
->AddEntry(strKey
, n
);
289 pEntry
->SetLine(m_linesTail
);
292 if ( bLocal
&& pEntry
->IsImmutable() ) {
293 // immutable keys can't be changed by user
294 wxLogWarning("file '%s', line %d: value for immutable key '%s' ignored.",
295 file
.GetName(), n
+ 1, strKey
.c_str());
298 // the condition below catches the cases (a) and (b) but not (c):
299 // (a) global key found second time in global file
300 // (b) key found second (or more) time in local file
301 // (c) key from global file now found in local one
302 // which is exactly what we want.
303 else if ( !bLocal
|| pEntry
->IsLocal() ) {
304 wxLogWarning("file '%s', line %d: key '%s' was first found at line %d.",
305 file
.GetName(), n
+ 1, strKey
.c_str(), pEntry
->Line());
308 pEntry
->SetLine(m_linesTail
);
313 while ( isspace(*pEnd
) )
317 if (m_bExpandEnvVars
)
318 strValue
= ExpandEnvVars(FilterIn(pEnd
));
320 strValue
= FilterIn(pEnd
);
321 pEntry
->SetValue(strValue
, FALSE
);
327 // ----------------------------------------------------------------------------
329 // ----------------------------------------------------------------------------
331 void wxFileConfig::SetRootPath()
334 m_pCurrentGroup
= m_pRootGroup
;
337 void wxFileConfig::SetPath(const wxString
& strPath
)
339 wxArrayString aParts
;
341 if ( strPath
.IsEmpty() ) {
346 if ( strPath
[0] == APPCONF_PATH_SEPARATOR
) {
348 SplitPath(aParts
, strPath
);
351 // relative path, combine with current one
352 wxString strFullPath
= m_strPath
;
353 strFullPath
<< APPCONF_PATH_SEPARATOR
<< strPath
;
354 SplitPath(aParts
, strFullPath
);
357 // change current group
359 m_pCurrentGroup
= m_pRootGroup
;
360 for ( n
= 0; n
< aParts
.Count(); n
++ ) {
361 ConfigGroup
*pNextGroup
= m_pCurrentGroup
->FindSubgroup(aParts
[n
]);
362 if ( pNextGroup
== NULL
)
363 pNextGroup
= m_pCurrentGroup
->AddSubgroup(aParts
[n
]);
364 m_pCurrentGroup
= pNextGroup
;
367 // recombine path parts in one variable
369 for ( n
= 0; n
< aParts
.Count(); n
++ ) {
370 m_strPath
<< APPCONF_PATH_SEPARATOR
<< aParts
[n
];
374 // ----------------------------------------------------------------------------
376 // ----------------------------------------------------------------------------
378 bool wxFileConfig::GetFirstGroup(wxString
& str
, long& lIndex
)
381 return GetNextGroup(str
, lIndex
);
384 bool wxFileConfig::GetNextGroup (wxString
& str
, long& lIndex
)
386 if ( uint(lIndex
) < m_pCurrentGroup
->Groups().Count() ) {
387 str
= m_pCurrentGroup
->Groups()[lIndex
++]->Name();
394 bool wxFileConfig::GetFirstEntry(wxString
& str
, long& lIndex
)
397 return GetNextEntry(str
, lIndex
);
400 bool wxFileConfig::GetNextEntry (wxString
& str
, long& lIndex
)
402 if ( uint(lIndex
) < m_pCurrentGroup
->Entries().Count() ) {
403 str
= m_pCurrentGroup
->Entries()[lIndex
++]->Name();
410 // ----------------------------------------------------------------------------
411 // tests for existence
412 // ----------------------------------------------------------------------------
414 bool wxFileConfig::HasGroup(const wxString
& strName
) const
416 PathChanger
path(this, strName
);
418 ConfigGroup
*pGroup
= m_pCurrentGroup
->FindSubgroup(path
.Name());
419 return pGroup
!= NULL
;
422 bool wxFileConfig::HasEntry(const wxString
& strName
) const
424 PathChanger
path(this, strName
);
426 ConfigEntry
*pEntry
= m_pCurrentGroup
->FindEntry(path
.Name());
427 return pEntry
!= NULL
;
430 // ----------------------------------------------------------------------------
432 // ----------------------------------------------------------------------------
434 const char *wxFileConfig::Read(const char *szKey
,
435 const char *szDefault
) const
437 PathChanger
path(this, szKey
);
439 ConfigEntry
*pEntry
= m_pCurrentGroup
->FindEntry(path
.Name());
440 return pEntry
== NULL
? szDefault
: pEntry
->Value().c_str();
443 bool wxFileConfig::Read(wxString
*pstr
,
445 const char *szDefault
) const
447 PathChanger
path(this, szKey
);
449 ConfigEntry
*pEntry
= m_pCurrentGroup
->FindEntry(path
.Name());
450 if (pEntry
== NULL
) {
455 *pstr
= pEntry
->Value();
460 bool wxFileConfig::Read(long *pl
, const char *szKey
, long lDefault
) const
463 if ( Read(&str
, szKey
) ) {
473 bool wxFileConfig::Write(const char *szKey
, const char *szValue
)
475 PathChanger
path(this, szKey
);
477 ConfigEntry
*pEntry
= m_pCurrentGroup
->FindEntry(path
.Name());
478 if ( pEntry
== NULL
)
479 pEntry
= m_pCurrentGroup
->AddEntry(path
.Name());
480 pEntry
->SetValue(szValue
);
485 bool wxFileConfig::Write(const char *szKey
, long lValue
)
487 // ltoa() is not ANSI :-(
488 char szBuf
[40]; // should be good for sizeof(long) <= 16 (128 bits)
489 sprintf(szBuf
, "%ld", lValue
);
490 return Write(szKey
, szBuf
);
493 bool wxFileConfig::Flush(bool /* bCurrentOnly */)
495 if ( LineListIsEmpty() || !m_pRootGroup
->IsDirty() )
498 wxTempFile
file(m_strLocalFile
);
500 if ( !file
.IsOpened() ) {
501 wxLogError("Can't open user configuration file.");
505 // write all strings to file
506 for ( LineList
*p
= m_linesHead
; p
!= NULL
; p
= p
->Next() ) {
507 if ( !file
.Write(p
->Text() + wxTextFile::GetEOL()) ) {
508 wxLogError("Can't write user configuration file.");
513 return file
.Commit();
516 // ----------------------------------------------------------------------------
517 // delete groups/entries
518 // ----------------------------------------------------------------------------
520 bool wxFileConfig::DeleteEntry(const char *szKey
, bool bGroupIfEmptyAlso
)
522 PathChanger
path(this, szKey
);
524 if ( !m_pCurrentGroup
->DeleteEntry(path
.Name()) )
527 if ( bGroupIfEmptyAlso
&& m_pCurrentGroup
->IsEmpty() ) {
528 if ( m_pCurrentGroup
!= m_pRootGroup
) {
529 ConfigGroup
*pGroup
= m_pCurrentGroup
;
530 SetPath(".."); // changes m_pCurrentGroup!
531 m_pCurrentGroup
->DeleteSubgroup(pGroup
->Name());
533 //else: never delete the root group
539 bool wxFileConfig::DeleteGroup(const char *szKey
)
541 PathChanger
path(this, szKey
);
543 return m_pCurrentGroup
->DeleteSubgroup(path
.Name());
546 bool wxFileConfig::DeleteAll()
548 const char *szFile
= m_strLocalFile
;
552 if ( remove(szFile
) == -1 )
553 wxLogSysError("Can't delete user configuration file '%s'", szFile
);
555 szFile
= m_strGlobalFile
;
556 if ( remove(szFile
) )
557 wxLogSysError("Can't delete system configuration file '%s'", szFile
);
562 // ----------------------------------------------------------------------------
563 // linked list functions
564 // ----------------------------------------------------------------------------
566 // append a new line to the end of the list
567 wxFileConfig::LineList
*wxFileConfig::LineListAppend(const wxString
& str
)
569 LineList
*pLine
= new LineList(str
);
571 if ( m_linesTail
== NULL
) {
577 m_linesTail
->SetNext(pLine
);
578 pLine
->SetPrev(m_linesTail
);
585 // insert a new line after the given one or in the very beginning if !pLine
586 wxFileConfig::LineList
*wxFileConfig::LineListInsert(const wxString
& str
,
589 if ( pLine
== m_linesTail
)
590 return LineListAppend(str
);
592 LineList
*pNewLine
= new LineList(str
);
593 if ( pLine
== NULL
) {
594 // prepend to the list
595 pNewLine
->SetNext(m_linesHead
);
596 m_linesHead
->SetPrev(pNewLine
);
597 m_linesHead
= pNewLine
;
600 // insert before pLine
601 LineList
*pNext
= pLine
->Next();
602 pNewLine
->SetNext(pNext
);
603 pNewLine
->SetPrev(pLine
);
604 pNext
->SetPrev(pNewLine
);
605 pLine
->SetNext(pNewLine
);
611 void wxFileConfig::LineListRemove(LineList
*pLine
)
613 LineList
*pPrev
= pLine
->Prev(),
614 *pNext
= pLine
->Next();
615 if ( pPrev
== NULL
) {
616 // deleting the first entry
620 // not the first entry
621 pPrev
->SetNext(pNext
);
624 pNext
->SetPrev(pPrev
);
629 bool wxFileConfig::LineListIsEmpty()
631 return m_linesHead
== NULL
;
634 // ============================================================================
635 // wxFileConfig::ConfigGroup
636 // ============================================================================
638 // ----------------------------------------------------------------------------
640 // ----------------------------------------------------------------------------
643 wxFileConfig::ConfigGroup::ConfigGroup(wxFileConfig::ConfigGroup
*pParent
,
644 const wxString
& strName
,
645 wxFileConfig
*pConfig
)
646 : m_aEntries(CompareEntries
),
647 m_aSubgroups(CompareGroups
),
658 // dtor deletes all children
659 wxFileConfig::ConfigGroup::~ConfigGroup()
662 uint n
, nCount
= m_aEntries
.Count();
663 for ( n
= 0; n
< nCount
; n
++ )
664 delete m_aEntries
[n
];
667 nCount
= m_aSubgroups
.Count();
668 for ( n
= 0; n
< nCount
; n
++ )
669 delete m_aSubgroups
[n
];
672 // ----------------------------------------------------------------------------
674 // ----------------------------------------------------------------------------
676 void wxFileConfig::ConfigGroup::SetLine(LineList
*pLine
)
678 wxASSERT( m_pLine
== NULL
); // shouldn't be called twice
683 // return the line which contains "[our name]"
684 wxFileConfig::LineList
*wxFileConfig::ConfigGroup::GetGroupLine()
686 if ( m_pLine
== NULL
) {
687 // this group wasn't present in local config file, add it now
688 if ( Parent() != NULL
) {
689 wxString strFullName
;
690 strFullName
<< "[" << GetFullName().c_str() + 1 << "]"; // +1: no '/'
691 m_pLine
= m_pConfig
->LineListInsert(strFullName
,
692 Parent()->GetLastGroupLine());
693 Parent()->SetLastGroup(this);
696 // we return NULL, so that LineListInsert() will insert us in the
704 // return the last line belonging to the subgroups of this group
705 // (after which we can add a new subgroup)
706 wxFileConfig::LineList
*wxFileConfig::ConfigGroup::GetLastGroupLine()
708 // if we have any subgroups, our last line is the last line of the last
710 if ( m_pLastGroup
!= NULL
)
711 return m_pLastGroup
->GetLastGroupLine();
713 // if we have any entries, our last line is the last entry
714 if ( m_pLastEntry
!= NULL
)
715 return m_pLastEntry
->GetLine();
717 // nothing at all: last line is the first one
718 return GetGroupLine();
721 // return the last line belonging to the entries of this group
722 // (after which we can add a new entry)
723 wxFileConfig::LineList
*wxFileConfig::ConfigGroup::GetLastEntryLine()
725 if ( m_pLastEntry
!= NULL
) {
726 wxFileConfig::LineList
*pLine
= m_pLastEntry
->GetLine();
728 wxASSERT( pLine
!= NULL
); // last entry must have !NULL associated line
732 // no entrues: insert after the group header
733 return GetGroupLine();
736 // ----------------------------------------------------------------------------
738 // ----------------------------------------------------------------------------
740 wxString
wxFileConfig::ConfigGroup::GetFullName() const
743 return Parent()->GetFullName() + APPCONF_PATH_SEPARATOR
+ Name();
748 // ----------------------------------------------------------------------------
750 // ----------------------------------------------------------------------------
752 // use binary search because the array is sorted
753 wxFileConfig::ConfigEntry
*
754 wxFileConfig::ConfigGroup::FindEntry(const char *szName
) const
758 hi
= m_aEntries
.Count();
760 wxFileConfig::ConfigEntry
*pEntry
;
764 pEntry
= m_aEntries
[i
];
766 #if APPCONF_CASE_SENSITIVE
767 res
= strcmp(pEntry
->Name(), szName
);
769 res
= Stricmp(pEntry
->Name(), szName
);
783 wxFileConfig::ConfigGroup
*
784 wxFileConfig::ConfigGroup::FindSubgroup(const char *szName
) const
788 hi
= m_aSubgroups
.Count();
790 wxFileConfig::ConfigGroup
*pGroup
;
794 pGroup
= m_aSubgroups
[i
];
796 #if APPCONF_CASE_SENSITIVE
797 res
= strcmp(pGroup
->Name(), szName
);
799 res
= Stricmp(pGroup
->Name(), szName
);
813 // ----------------------------------------------------------------------------
815 // ----------------------------------------------------------------------------
817 // create a new entry and add it to the current group
818 wxFileConfig::ConfigEntry
*
819 wxFileConfig::ConfigGroup::AddEntry(const wxString
& strName
, int nLine
)
821 wxASSERT( FindEntry(strName
) == NULL
);
823 ConfigEntry
*pEntry
= new ConfigEntry(this, strName
, nLine
);
824 m_aEntries
.Add(pEntry
);
829 // create a new group and add it to the current group
830 wxFileConfig::ConfigGroup
*
831 wxFileConfig::ConfigGroup::AddSubgroup(const wxString
& strName
)
833 wxASSERT( FindSubgroup(strName
) == NULL
);
835 ConfigGroup
*pGroup
= new ConfigGroup(this, strName
, m_pConfig
);
836 m_aSubgroups
.Add(pGroup
);
841 // ----------------------------------------------------------------------------
843 // ----------------------------------------------------------------------------
845 bool wxFileConfig::ConfigGroup::DeleteSubgroup(const char *szName
)
847 uint n
, nCount
= m_aSubgroups
.Count();
848 for ( n
= 0; n
< nCount
; n
++ ) {
849 if ( m_aSubgroups
[n
]->Name().IsSameAs(szName
, APPCONF_CASE_SENSITIVE
) )
856 nCount
= m_aEntries
.Count();
857 for ( n
= 0; n
< nCount
; n
++ ) {
858 LineList
*pLine
= m_aEntries
[n
]->GetLine();
860 m_pConfig
->LineListRemove(pLine
);
863 ConfigGroup
*pGroup
= m_aSubgroups
[n
];
864 LineList
*pLine
= pGroup
->m_pLine
;
866 m_pConfig
->LineListRemove(pLine
);
871 m_aSubgroups
.Remove(n
);
875 bool wxFileConfig::ConfigGroup::DeleteEntry(const char *szName
)
877 uint n
, nCount
= m_aEntries
.Count();
878 for ( n
= 0; n
< nCount
; n
++ ) {
879 if ( m_aEntries
[n
]->Name().IsSameAs(szName
, APPCONF_CASE_SENSITIVE
) )
886 ConfigEntry
*pEntry
= m_aEntries
[n
];
887 LineList
*pLine
= pEntry
->GetLine();
889 m_pConfig
->LineListRemove(pLine
);
894 m_aEntries
.Remove(n
);
898 // ----------------------------------------------------------------------------
900 // ----------------------------------------------------------------------------
901 void wxFileConfig::ConfigGroup::SetDirty()
904 if ( Parent() != NULL
) // propagate upwards
905 Parent()->SetDirty();
908 // ============================================================================
909 // wxFileConfig::ConfigEntry
910 // ============================================================================
912 // ----------------------------------------------------------------------------
914 // ----------------------------------------------------------------------------
915 wxFileConfig::ConfigEntry::ConfigEntry(wxFileConfig::ConfigGroup
*pParent
,
916 const wxString
& strName
,
926 m_bImmutable
= strName
[0] == APPCONF_IMMUTABLE_PREFIX
;
928 m_strName
.erase(0, 1); // remove first character
931 // ----------------------------------------------------------------------------
933 // ----------------------------------------------------------------------------
935 void wxFileConfig::ConfigEntry::SetLine(LineList
*pLine
)
937 if ( m_pLine
!= NULL
) {
938 wxLogWarning("Entry '%s' appears more than once in group '%s'",
939 Name().c_str(), m_pParent
->GetFullName().c_str());
943 Group()->SetLastEntry(this);
946 // second parameter is FALSE if we read the value from file and prevents the
947 // entry from being marked as 'dirty'
948 void wxFileConfig::ConfigEntry::SetValue(const wxString
& strValue
, bool bUser
)
950 if ( bUser
&& IsImmutable() ) {
951 wxLogWarning("Attempt to change immutable key '%s' ignored.",
956 // do nothing if it's the same value
957 if ( strValue
== m_strValue
)
960 m_strValue
= strValue
;
963 wxString strVal
= FilterOut(strValue
);
965 strLine
<< m_strName
<< " = " << strVal
;
967 if ( m_pLine
!= NULL
) {
968 // entry was read from the local config file, just modify the line
969 m_pLine
->SetText(strLine
);
972 // add a new line to the file
973 wxASSERT( m_nLine
== NOT_FOUND
); // consistency check
975 m_pLine
= Group()->Config()->LineListInsert(strLine
,
976 Group()->GetLastEntryLine());
977 Group()->SetLastEntry(this);
984 void wxFileConfig::ConfigEntry::SetDirty()
990 // ============================================================================
992 // ============================================================================
994 // ----------------------------------------------------------------------------
995 // compare functions for array sorting
996 // ----------------------------------------------------------------------------
998 int CompareEntries(wxFileConfig::ConfigEntry
*p1
,
999 wxFileConfig::ConfigEntry
*p2
)
1001 #if APPCONF_CASE_SENSITIVE
1002 return strcmp(p1
->Name(), p2
->Name());
1004 return Stricmp(p1
->Name(), p2
->Name());
1008 int CompareGroups(wxFileConfig::ConfigGroup
*p1
,
1009 wxFileConfig::ConfigGroup
*p2
)
1011 #if APPCONF_CASE_SENSITIVE
1012 return strcmp(p1
->Name(), p2
->Name());
1014 return Stricmp(p1
->Name(), p2
->Name());
1018 // ----------------------------------------------------------------------------
1020 // ----------------------------------------------------------------------------
1023 wxString
FilterIn(const wxString
& str
)
1026 strResult
.Alloc(str
.Len());
1028 bool bQuoted
= !str
.IsEmpty() && str
[0] == '"';
1030 for ( uint n
= bQuoted
? 1 : 0; n
< str
.Len(); n
++ ) {
1031 if ( str
[n
] == '\\' ) {
1032 switch ( str
[++n
] ) {
1051 if ( str
[n
] != '"' || !bQuoted
)
1052 strResult
+= str
[n
];
1053 else if ( n
!= str
.Len() - 1 )
1054 wxLogWarning("unexpected \" at position %d in '%s'.", n
, str
.c_str());
1055 //else: it's the last quote of a quoted string, ok
1062 // quote the string before writing it to file
1063 wxString
FilterOut(const wxString
& str
)
1066 strResult
.Alloc(str
.Len());
1068 // quoting is necessary to preserve spaces in the beginning of the string
1069 bool bQuote
= isspace(str
[0]) || str
[0] == '"';
1075 for ( uint n
= 0; n
< str
.Len(); n
++ ) {
1092 //else: fall through
1095 strResult
+= str
[n
];
1096 continue; // nothing special to do
1099 // we get here only for special characters
1100 strResult
<< '\\' << c
;