1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: wxString class
4 // Author: Vadim Zeitlin
8 // Copyright: (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
9 // Licence: wxWindows license
10 /////////////////////////////////////////////////////////////////////////////
13 #pragma implementation "string.h"
18 * 1) all empty strings use g_strEmpty, nRefs = -1 (set in Init())
19 * 2) AllocBuffer() sets nRefs to 1, Lock() increments it by one
20 * 3) Unlock() decrements nRefs and frees memory if it goes to 0
23 // ===========================================================================
24 // headers, declarations, constants
25 // ===========================================================================
27 // For compilers that support precompilation, includes "wx.h".
28 #include "wx/wxprec.h"
36 #include "wx/string.h"
43 #ifdef WXSTRING_IS_WXOBJECT
44 IMPLEMENT_DYNAMIC_CLASS(wxString
, wxObject
)
45 #endif //WXSTRING_IS_WXOBJECT
47 // ---------------------------------------------------------------------------
48 // static class variables definition
49 // ---------------------------------------------------------------------------
51 #ifdef STD_STRING_COMPATIBILITY
52 const size_t wxString::npos
= STRING_MAXLEN
;
55 // ===========================================================================
56 // static class data, special inlines
57 // ===========================================================================
59 // for an empty string, GetStringData() will return this address
60 static int g_strEmpty
[] = { -1, // ref count (locked)
62 0, // allocated memory
64 // empty C style string: points to 'string data' byte of g_strEmpty
65 extern const char *g_szNul
= (const char *)(&g_strEmpty
[3]);
67 // ===========================================================================
69 // ===========================================================================
71 #ifdef STD_STRING_COMPATIBILITY
73 // MS Visual C++ version 5.0 provides the new STL headers as well as the old
76 // ATTN: you can _not_ use both of these in the same program!
79 #define NAMESPACE std::
85 NAMESPACE istream
& operator>>(NAMESPACE istream
& is
, wxString
& WXUNUSED(str
))
90 NAMESPACE streambuf
*sb
= is
.rdbuf();
93 int ch
= sb
->sbumpc ();
95 is
.setstate(NAMESPACE
ios::eofbit
);
98 else if ( isspace(ch
) ) {
110 if ( str
.length() == 0 )
111 is
.setstate(NAMESPACE
ios::failbit
);
116 #endif //std::string compatibility
118 // ===========================================================================
119 // wxString class core
120 // ===========================================================================
122 // ---------------------------------------------------------------------------
124 // ---------------------------------------------------------------------------
126 // construct an empty string
133 wxString::wxString(const wxString
& stringSrc
)
135 wxASSERT( stringSrc
.GetStringData()->IsValid() );
137 if ( stringSrc
.IsEmpty() ) {
138 // nothing to do for an empty string
142 m_pchData
= stringSrc
.m_pchData
; // share same data
143 GetStringData()->Lock(); // => one more copy
147 // constructs string of <nLength> copies of character <ch>
148 wxString::wxString(char ch
, size_t nLength
)
153 AllocBuffer(nLength
);
155 wxASSERT( sizeof(char) == 1 ); // can't use memset if not
157 memset(m_pchData
, ch
, nLength
);
161 // takes nLength elements of psz starting at nPos
162 void wxString::InitWith(const char *psz
, size_t nPos
, size_t nLength
)
166 wxASSERT( nPos
<= Strlen(psz
) );
168 if ( nLength
== STRING_MAXLEN
)
169 nLength
= Strlen(psz
+ nPos
);
172 // trailing '\0' is written in AllocBuffer()
173 AllocBuffer(nLength
);
174 memcpy(m_pchData
, psz
+ nPos
, nLength
*sizeof(char));
178 // take first nLength characters of C string psz
179 // (default value of STRING_MAXLEN means take all the string)
180 wxString::wxString(const char *psz
, size_t nLength
)
182 InitWith(psz
, 0, nLength
);
185 // the same as previous constructor, but for compilers using unsigned char
186 wxString::wxString(const unsigned char* psz
, size_t nLength
)
188 InitWith((const char *)psz
, 0, nLength
);
191 #ifdef STD_STRING_COMPATIBILITY
193 // ctor from a substring
194 wxString::wxString(const wxString
& str
, size_t nPos
, size_t nLen
)
196 wxASSERT( str
.GetStringData()->IsValid() );
198 InitWith(str
.c_str(), nPos
, nLen
== npos
? 0 : nLen
);
201 // poor man's iterators are "void *" pointers
202 wxString::wxString(const void *pStart
, const void *pEnd
)
204 InitWith((const char *)pStart
, 0,
205 (const char *)pEnd
- (const char *)pStart
);
208 #endif //std::string compatibility
211 wxString::wxString(const wchar_t *pwz
)
213 // first get necessary size
214 size_t nLen
= wcstombs(NULL
, pwz
, 0);
219 wcstombs(m_pchData
, pwz
, nLen
);
226 // ---------------------------------------------------------------------------
228 // ---------------------------------------------------------------------------
230 // allocates memory needed to store a C string of length nLen
231 void wxString::AllocBuffer(size_t nLen
)
233 wxASSERT( nLen
> 0 ); //
234 wxASSERT( nLen
<= INT_MAX
-1 ); // max size (enough room for 1 extra)
237 // 1) one extra character for '\0' termination
238 // 2) sizeof(wxStringData) for housekeeping info
239 wxStringData
* pData
= (wxStringData
*)new char[sizeof(wxStringData
) +
240 (nLen
+ 1)*sizeof(char)];
242 pData
->data()[nLen
] = '\0';
243 pData
->nDataLength
= nLen
;
244 pData
->nAllocLength
= nLen
;
245 m_pchData
= pData
->data(); // data starts after wxStringData
248 // releases the string memory and reinits it
249 void wxString::Reinit()
251 GetStringData()->Unlock();
255 // wrapper around wxString::Reinit
256 void wxString::Empty()
258 if ( GetStringData()->nDataLength
!= 0 )
261 wxASSERT( GetStringData()->nDataLength
== 0 );
262 wxASSERT( GetStringData()->nAllocLength
== 0 );
265 // must be called before changing this string
266 void wxString::CopyBeforeWrite()
268 wxStringData
* pData
= GetStringData();
270 if ( pData
->IsShared() ) {
271 pData
->Unlock(); // memory not freed because shared
272 AllocBuffer(pData
->nDataLength
);
273 memcpy(m_pchData
, pData
->data(), (pData
->nDataLength
+ 1)*sizeof(char));
276 wxASSERT( !pData
->IsShared() ); // we must be the only owner
279 // must be called before replacing contents of this string
280 void wxString::AllocBeforeWrite(size_t nLen
)
282 wxASSERT( nLen
!= 0 ); // doesn't make any sense
284 // must not share string and must have enough space
285 register wxStringData
* pData
= GetStringData();
286 if ( pData
->IsShared() || (nLen
> pData
->nAllocLength
) ) {
287 // can't work with old buffer, get new one
292 wxASSERT( !GetStringData()->IsShared() ); // we must be the only owner
295 // get the pointer to writable buffer of (at least) nLen bytes
296 char *wxString::GetWriteBuf(int nLen
)
298 AllocBeforeWrite(nLen
);
300 wxASSERT( GetStringData()->nRefs
== 1 );
301 GetStringData()->Validate(FALSE
);
306 // put string back in a reasonable state after GetWriteBuf
307 void wxString::UngetWriteBuf()
309 GetStringData()->nDataLength
= strlen(m_pchData
);
310 GetStringData()->Validate(TRUE
);
313 // dtor frees memory if no other strings use it
314 wxString::~wxString()
316 GetStringData()->Unlock();
319 // ---------------------------------------------------------------------------
321 // ---------------------------------------------------------------------------
323 // all functions are inline in string.h
325 // ---------------------------------------------------------------------------
326 // assignment operators
327 // ---------------------------------------------------------------------------
329 // helper function: does real copy
330 void wxString::AssignCopy(size_t nSrcLen
, const char *pszSrcData
)
332 if ( nSrcLen
== 0 ) {
336 AllocBeforeWrite(nSrcLen
);
337 memcpy(m_pchData
, pszSrcData
, nSrcLen
*sizeof(char));
338 GetStringData()->nDataLength
= nSrcLen
;
339 m_pchData
[nSrcLen
] = '\0';
343 // assigns one string to another
344 wxString
& wxString::operator=(const wxString
& stringSrc
)
346 wxASSERT( stringSrc
.GetStringData()->IsValid() );
348 // don't copy string over itself
349 if ( m_pchData
!= stringSrc
.m_pchData
) {
350 if ( stringSrc
.GetStringData()->IsEmpty() ) {
355 GetStringData()->Unlock();
356 m_pchData
= stringSrc
.m_pchData
;
357 GetStringData()->Lock();
364 // assigns a single character
365 wxString
& wxString::operator=(char ch
)
372 wxString
& wxString::operator=(const char *psz
)
374 AssignCopy(Strlen(psz
), psz
);
378 // same as 'signed char' variant
379 wxString
& wxString::operator=(const unsigned char* psz
)
381 *this = (const char *)psz
;
385 wxString
& wxString::operator=(const wchar_t *pwz
)
392 // ---------------------------------------------------------------------------
393 // string concatenation
394 // ---------------------------------------------------------------------------
396 // concatenate two sources
397 // NB: assume that 'this' is a new wxString object
398 void wxString::ConcatCopy(int nSrc1Len
, const char *pszSrc1Data
,
399 int nSrc2Len
, const char *pszSrc2Data
)
401 int nNewLen
= nSrc1Len
+ nSrc2Len
;
404 AllocBuffer(nNewLen
);
405 memcpy(m_pchData
, pszSrc1Data
, nSrc1Len
*sizeof(char));
406 memcpy(m_pchData
+ nSrc1Len
, pszSrc2Data
, nSrc2Len
*sizeof(char));
410 // add something to this string
411 void wxString::ConcatSelf(int nSrcLen
, const char *pszSrcData
)
413 // concatenating an empty string is a NOP
414 if ( nSrcLen
!= 0 ) {
415 register wxStringData
*pData
= GetStringData();
417 // alloc new buffer if current is too small
418 if ( pData
->IsShared() ||
419 pData
->nDataLength
+ nSrcLen
> pData
->nAllocLength
) {
420 // we have to grow the buffer, use the ConcatCopy routine
421 // (which will allocate memory)
422 wxStringData
* pOldData
= GetStringData();
423 ConcatCopy(pOldData
->nDataLength
, m_pchData
, nSrcLen
, pszSrcData
);
427 // fast concatenation when buffer big enough
428 memcpy(m_pchData
+ pData
->nDataLength
, pszSrcData
, nSrcLen
*sizeof(char));
429 pData
->nDataLength
+= nSrcLen
;
431 // should be enough space
432 wxASSERT( pData
->nDataLength
<= pData
->nAllocLength
);
434 m_pchData
[pData
->nDataLength
] = '\0'; // put terminating '\0'
440 * string may be concatenated with other string, C string or a character
443 void wxString::operator+=(const wxString
& string
)
445 wxASSERT( string
.GetStringData()->IsValid() );
447 ConcatSelf(string
.Len(), string
);
450 void wxString::operator+=(const char *psz
)
452 ConcatSelf(Strlen(psz
), psz
);
455 void wxString::operator+=(char ch
)
461 * Same as above but return the result
464 wxString
& wxString::operator<<(const wxString
& string
)
466 wxASSERT( string
.GetStringData()->IsValid() );
468 ConcatSelf(string
.Len(), string
);
472 wxString
& wxString::operator<<(const char *psz
)
474 ConcatSelf(Strlen(psz
), psz
);
478 wxString
& wxString::operator<<(char ch
)
485 * concatenation functions come in 5 flavours:
487 * char + string and string + char
488 * C str + string and string + C str
491 wxString
operator+(const wxString
& string1
, const wxString
& string2
)
493 wxASSERT( string1
.GetStringData()->IsValid() );
494 wxASSERT( string2
.GetStringData()->IsValid() );
497 s
.ConcatCopy(string1
.GetStringData()->nDataLength
, string1
.m_pchData
,
498 string2
.GetStringData()->nDataLength
, string2
.m_pchData
);
502 wxString
operator+(const wxString
& string1
, char ch
)
504 wxASSERT( string1
.GetStringData()->IsValid() );
507 s
.ConcatCopy(string1
.GetStringData()->nDataLength
, string1
.m_pchData
, 1, &ch
);
511 wxString
operator+(char ch
, const wxString
& string
)
513 wxASSERT( string
.GetStringData()->IsValid() );
516 s
.ConcatCopy(1, &ch
, string
.GetStringData()->nDataLength
, string
.m_pchData
);
520 wxString
operator+(const wxString
& string
, const char *psz
)
522 wxASSERT( string
.GetStringData()->IsValid() );
525 s
.ConcatCopy(string
.GetStringData()->nDataLength
, string
.m_pchData
,
530 wxString
operator+(const char *psz
, const wxString
& string
)
532 wxASSERT( string
.GetStringData()->IsValid() );
535 s
.ConcatCopy(Strlen(psz
), psz
,
536 string
.GetStringData()->nDataLength
, string
.m_pchData
);
540 // ===========================================================================
541 // other common string functions
542 // ===========================================================================
544 // ---------------------------------------------------------------------------
545 // simple sub-string extraction
546 // ---------------------------------------------------------------------------
548 // helper function: clone the data attached to this string
549 void wxString::AllocCopy(wxString
& dest
, int nCopyLen
, int nCopyIndex
) const
557 dest
.AllocBuffer(nCopyLen
);
558 memcpy(dest
.m_pchData
, m_pchData
+ nCopyIndex
, nCopyLen
*sizeof(char));
562 // extract string of length nCount starting at nFirst
563 // default value of nCount is 0 and means "till the end"
564 wxString
wxString::Mid(size_t nFirst
, size_t nCount
) const
566 // out-of-bounds requests return sensible things
568 nCount
= GetStringData()->nDataLength
- nFirst
;
570 if ( nFirst
+ nCount
> (size_t)GetStringData()->nDataLength
)
571 nCount
= GetStringData()->nDataLength
- nFirst
;
572 if ( nFirst
> (size_t)GetStringData()->nDataLength
)
576 AllocCopy(dest
, nCount
, nFirst
);
580 // extract nCount last (rightmost) characters
581 wxString
wxString::Right(size_t nCount
) const
583 if ( nCount
> (size_t)GetStringData()->nDataLength
)
584 nCount
= GetStringData()->nDataLength
;
587 AllocCopy(dest
, nCount
, GetStringData()->nDataLength
- nCount
);
591 // get all characters after the last occurence of ch
592 // (returns the whole string if ch not found)
593 wxString
wxString::Right(char ch
) const
596 int iPos
= Find(ch
, TRUE
);
597 if ( iPos
== NOT_FOUND
)
600 str
= c_str() + iPos
+ 1;
605 // extract nCount first (leftmost) characters
606 wxString
wxString::Left(size_t nCount
) const
608 if ( nCount
> (size_t)GetStringData()->nDataLength
)
609 nCount
= GetStringData()->nDataLength
;
612 AllocCopy(dest
, nCount
, 0);
616 // get all characters before the first occurence of ch
617 // (returns the whole string if ch not found)
618 wxString
wxString::Left(char ch
) const
621 for ( const char *pc
= m_pchData
; *pc
!= '\0' && *pc
!= ch
; pc
++ )
627 /// get all characters before the last occurence of ch
628 /// (returns empty string if ch not found)
629 wxString
wxString::Before(char ch
) const
632 int iPos
= Find(ch
, TRUE
);
633 if ( iPos
!= NOT_FOUND
&& iPos
!= 0 )
634 str
= wxString(c_str(), iPos
);
639 /// get all characters after the first occurence of ch
640 /// (returns empty string if ch not found)
641 wxString
wxString::After(char ch
) const
645 if ( iPos
!= NOT_FOUND
)
646 str
= c_str() + iPos
+ 1;
651 // replace first (or all) occurences of some substring with another one
652 uint
wxString::Replace(const char *szOld
, const char *szNew
, bool bReplaceAll
)
654 uint uiCount
= 0; // count of replacements made
656 uint uiOldLen
= Strlen(szOld
);
659 const char *pCurrent
= m_pchData
;
661 while ( *pCurrent
!= '\0' ) {
662 pSubstr
= strstr(pCurrent
, szOld
);
663 if ( pSubstr
== NULL
) {
664 // strTemp is unused if no replacements were made, so avoid the copy
668 strTemp
+= pCurrent
; // copy the rest
669 break; // exit the loop
672 // take chars before match
673 strTemp
.ConcatSelf(pSubstr
- pCurrent
, pCurrent
);
675 pCurrent
= pSubstr
+ uiOldLen
; // restart after match
680 if ( !bReplaceAll
) {
681 strTemp
+= pCurrent
; // copy the rest
682 break; // exit the loop
687 // only done if there were replacements, otherwise would have returned above
693 bool wxString::IsAscii() const
695 const char *s
= (const char*) *this;
697 if(!isascii(*s
)) return(FALSE
);
703 bool wxString::IsWord() const
705 const char *s
= (const char*) *this;
707 if(!isalpha(*s
)) return(FALSE
);
713 bool wxString::IsNumber() const
715 const char *s
= (const char*) *this;
717 if(!isdigit(*s
)) return(FALSE
);
723 // kludge: we don't have declaraton of wxStringData here, so we add offsets
724 // manually to get to the "length" field of wxStringData structure
725 bool wxString::IsEmpty() const { return Len() == 0; }
727 wxString
wxString::Strip(stripType w
) const
730 if ( w
& leading
) s
.Trim(FALSE
);
731 if ( w
& trailing
) s
.Trim(TRUE
);
735 /// case-insensitive strcmp() (platform independent)
736 int Stricmp(const char *psz1
, const char *psz2
)
738 #if defined(_MSC_VER)
739 return _stricmp(psz1
, psz2
);
740 #elif defined(__BORLANDC__)
741 return stricmp(psz1
, psz2
);
742 #elif defined(__UNIX__) || defined(__GNUWIN32__)
743 return strcasecmp(psz1
, psz2
);
745 // almost all compilers/libraries provide this function (unfortunately under
746 // different names), that's why we don't implement our own which will surely
747 // be more efficient than this code (uncomment to use):
749 register char c1, c2;
751 c1 = tolower(*psz1++);
752 c2 = tolower(*psz2++);
753 } while ( c1 && (c1 == c2) );
758 #error "Please define string case-insensitive compare for your OS/compiler"
759 #endif // OS/compiler
762 // ---------------------------------------------------------------------------
764 // ---------------------------------------------------------------------------
766 wxString
& wxString::MakeUpper()
770 for ( char *p
= m_pchData
; *p
; p
++ )
771 *p
= (char)toupper(*p
);
776 wxString
& wxString::MakeLower()
780 for ( char *p
= m_pchData
; *p
; p
++ )
781 *p
= (char)tolower(*p
);
786 // ---------------------------------------------------------------------------
787 // trimming and padding
788 // ---------------------------------------------------------------------------
790 // trims spaces (in the sense of isspace) from left or right side
791 wxString
& wxString::Trim(bool bFromRight
)
797 // find last non-space character
798 char *psz
= m_pchData
+ GetStringData()->nDataLength
- 1;
799 while ( isspace(*psz
) && (psz
>= m_pchData
) )
802 // truncate at trailing space start
804 GetStringData()->nDataLength
= psz
- m_pchData
;
808 // find first non-space character
809 const char *psz
= m_pchData
;
810 while ( isspace(*psz
) )
813 // fix up data and length
814 int nDataLength
= GetStringData()->nDataLength
- (psz
- m_pchData
);
815 memmove(m_pchData
, psz
, (nDataLength
+ 1)*sizeof(char));
816 GetStringData()->nDataLength
= nDataLength
;
822 // adds nCount characters chPad to the string from either side
823 wxString
& wxString::Pad(size_t nCount
, char chPad
, bool bFromRight
)
825 wxString
s(chPad
, nCount
);
838 // truncate the string
839 wxString
& wxString::Truncate(size_t uiLen
)
841 *(m_pchData
+ uiLen
) = '\0';
842 GetStringData()->nDataLength
= uiLen
;
847 // ---------------------------------------------------------------------------
848 // finding (return NOT_FOUND if not found and index otherwise)
849 // ---------------------------------------------------------------------------
852 int wxString::Find(char ch
, bool bFromEnd
) const
854 const char *psz
= bFromEnd
? strrchr(m_pchData
, ch
) : strchr(m_pchData
, ch
);
856 return (psz
== NULL
) ? NOT_FOUND
: psz
- m_pchData
;
859 // find a sub-string (like strstr)
860 int wxString::Find(const char *pszSub
) const
862 const char *psz
= strstr(m_pchData
, pszSub
);
864 return (psz
== NULL
) ? NOT_FOUND
: psz
- m_pchData
;
867 // ---------------------------------------------------------------------------
869 // ---------------------------------------------------------------------------
870 int wxString::Printf(const char *pszFormat
, ...)
873 va_start(argptr
, pszFormat
);
875 int iLen
= PrintfV(pszFormat
, argptr
);
882 int wxString::PrintfV(const char* pszFormat
, va_list argptr
)
884 static char s_szScratch
[1024];
886 int iLen
= vsprintf(s_szScratch
, pszFormat
, argptr
);
887 AllocBeforeWrite(iLen
);
888 strcpy(m_pchData
, s_szScratch
);
894 int wxString::Scanf(const char *pszFormat
, ...) const
897 va_start(argptr
, pszFormat
);
899 int iLen
= ScanfV(pszFormat
, argptr
);
906 int wxString::ScanfV(const char *pszFormat
, va_list argptr
) const
909 wxMessageBox("ScanfV not implemented");
912 return vsscanf(c_str(), pszFormat
, argptr
);
917 // ----------------------------------------------------------------------------
918 // misc other operations
919 // ----------------------------------------------------------------------------
920 bool wxString::Matches(const char *pszMask
) const
922 // check char by char
924 for ( pszTxt
= c_str(); *pszMask
!= '\0'; pszMask
++, pszTxt
++ ) {
925 switch ( *pszMask
) {
927 if ( *pszTxt
== '\0' )
936 // ignore special chars immediately following this one
937 while ( *pszMask
== '*' || *pszMask
== '?' )
940 // if there is nothing more, match
941 if ( *pszMask
== '\0' )
944 // are there any other metacharacters in the mask?
946 const char *pEndMask
= strpbrk(pszMask
, "*?");
948 if ( pEndMask
!= NULL
) {
949 // we have to match the string between two metachars
950 uiLenMask
= pEndMask
- pszMask
;
953 // we have to match the remainder of the string
954 uiLenMask
= strlen(pszMask
);
957 wxString
strToMatch(pszMask
, uiLenMask
);
958 const char* pMatch
= strstr(pszTxt
, strToMatch
);
959 if ( pMatch
== NULL
)
962 // -1 to compensate "++" in the loop
963 pszTxt
= pMatch
+ uiLenMask
- 1;
964 pszMask
+= uiLenMask
- 1;
969 if ( *pszMask
!= *pszTxt
)
975 // match only if nothing left
976 return *pszTxt
== '\0';
979 // ---------------------------------------------------------------------------
980 // standard C++ library string functions
981 // ---------------------------------------------------------------------------
982 #ifdef STD_STRING_COMPATIBILITY
984 wxString
& wxString::insert(size_t nPos
, const wxString
& str
)
986 wxASSERT( str
.GetStringData()->IsValid() );
987 wxASSERT( nPos
<= Len() );
990 char *pc
= strTmp
.GetWriteBuf(Len() + str
.Len());
991 strncpy(pc
, c_str(), nPos
);
992 strcpy(pc
+ nPos
, str
);
993 strcpy(pc
+ nPos
+ str
.Len(), c_str() + nPos
);
994 strTmp
.UngetWriteBuf();
1000 size_t wxString::find(const wxString
& str
, size_t nStart
) const
1002 wxASSERT( str
.GetStringData()->IsValid() );
1003 wxASSERT( nStart
<= Len() );
1005 const char *p
= strstr(c_str() + nStart
, str
);
1007 return p
== NULL
? npos
: p
- c_str();
1010 // VC++ 1.5 can't cope with the default argument in the header.
1011 #if ! (defined(_MSC_VER) && !defined(__WIN32__))
1012 size_t wxString::find(const char* sz
, size_t nStart
, size_t n
) const
1014 return find(wxString(sz
, n
== npos
? 0 : n
), nStart
);
1018 size_t wxString::find(char ch
, size_t nStart
) const
1020 wxASSERT( nStart
<= Len() );
1022 const char *p
= strchr(c_str() + nStart
, ch
);
1024 return p
== NULL
? npos
: p
- c_str();
1027 size_t wxString::rfind(const wxString
& str
, size_t nStart
) const
1029 wxASSERT( str
.GetStringData()->IsValid() );
1030 wxASSERT( nStart
<= Len() );
1032 // # could be quicker than that
1033 const char *p
= c_str() + (nStart
== npos
? Len() : nStart
);
1034 while ( p
>= c_str() + str
.Len() ) {
1035 if ( strncmp(p
- str
.Len(), str
, str
.Len()) == 0 )
1036 return p
- str
.Len() - c_str();
1043 // VC++ 1.5 can't cope with the default argument in the header.
1044 #if ! (defined(_MSC_VER) && !defined(__WIN32__))
1045 size_t wxString::rfind(const char* sz
, size_t nStart
, size_t n
) const
1047 return rfind(wxString(sz
, n
== npos
? 0 : n
), nStart
);
1050 size_t wxString::rfind(char ch
, size_t nStart
) const
1052 wxASSERT( nStart
<= Len() );
1054 const char *p
= strrchr(c_str() + nStart
, ch
);
1056 return p
== NULL
? npos
: p
- c_str();
1060 wxString
wxString::substr(size_t nStart
, size_t nLen
) const
1062 // npos means 'take all'
1066 wxASSERT( nStart
+ nLen
<= Len() );
1068 return wxString(c_str() + nStart
, nLen
== npos
? 0 : nLen
);
1071 wxString
& wxString::erase(size_t nStart
, size_t nLen
)
1073 wxString
strTmp(c_str(), nStart
);
1074 if ( nLen
!= npos
) {
1075 wxASSERT( nStart
+ nLen
<= Len() );
1077 strTmp
.append(c_str() + nStart
+ nLen
);
1084 wxString
& wxString::replace(size_t nStart
, size_t nLen
, const char *sz
)
1086 wxASSERT( nStart
+ nLen
<= Strlen(sz
) );
1090 strTmp
.append(c_str(), nStart
);
1092 strTmp
.append(c_str() + nStart
+ nLen
);
1098 wxString
& wxString::replace(size_t nStart
, size_t nLen
, size_t nCount
, char ch
)
1100 return replace(nStart
, nLen
, wxString(ch
, nCount
));
1103 wxString
& wxString::replace(size_t nStart
, size_t nLen
,
1104 const wxString
& str
, size_t nStart2
, size_t nLen2
)
1106 return replace(nStart
, nLen
, str
.substr(nStart2
, nLen2
));
1109 wxString
& wxString::replace(size_t nStart
, size_t nLen
,
1110 const char* sz
, size_t nCount
)
1112 return replace(nStart
, nLen
, wxString(sz
, nCount
));
1115 #endif //std::string compatibility
1117 // ============================================================================
1119 // ============================================================================
1121 // size increment = max(50% of current size, ARRAY_MAXSIZE_INCREMENT)
1122 #define ARRAY_MAXSIZE_INCREMENT 4096
1123 #ifndef ARRAY_DEFAULT_INITIAL_SIZE // also defined in dynarray.h
1124 #define ARRAY_DEFAULT_INITIAL_SIZE (16)
1127 #define STRING(p) ((wxString *)(&(p)))
1130 wxArrayString::wxArrayString()
1138 wxArrayString::wxArrayString(const wxArrayString
& src
)
1140 m_nSize
= src
.m_nSize
;
1141 m_nCount
= src
.m_nCount
;
1144 m_pItems
= new char *[m_nSize
];
1148 if ( m_nCount
!= 0 )
1149 memcpy(m_pItems
, src
.m_pItems
, m_nCount
*sizeof(char *));
1153 wxArrayString
& wxArrayString::operator=(const wxArrayString
& src
)
1157 m_nSize
= src
.m_nSize
;
1158 m_nCount
= src
.m_nCount
;
1161 m_pItems
= new char *[m_nSize
];
1165 if ( m_nCount
!= 0 )
1166 memcpy(m_pItems
, src
.m_pItems
, m_nCount
*sizeof(char *));
1172 void wxArrayString::Grow()
1174 // only do it if no more place
1175 if( m_nCount
== m_nSize
) {
1176 if( m_nSize
== 0 ) {
1177 // was empty, alloc some memory
1178 m_nSize
= ARRAY_DEFAULT_INITIAL_SIZE
;
1179 m_pItems
= new char *[m_nSize
];
1182 // add 50% but not too much
1183 size_t nIncrement
= m_nSize
>> 1;
1184 if ( nIncrement
> ARRAY_MAXSIZE_INCREMENT
)
1185 nIncrement
= ARRAY_MAXSIZE_INCREMENT
;
1186 m_nSize
+= nIncrement
;
1187 char **pNew
= new char *[m_nSize
];
1189 // copy data to new location
1190 memcpy(pNew
, m_pItems
, m_nCount
*sizeof(char *));
1192 // delete old memory (but do not release the strings!)
1200 void wxArrayString::Free()
1202 for ( size_t n
= 0; n
< m_nCount
; n
++ ) {
1203 STRING(m_pItems
[n
])->GetStringData()->Unlock();
1207 // deletes all the strings from the list
1208 void wxArrayString::Empty()
1215 // as Empty, but also frees memory
1216 void wxArrayString::Clear()
1228 wxArrayString::~wxArrayString()
1235 // pre-allocates memory (frees the previous data!)
1236 void wxArrayString::Alloc(size_t nSize
)
1238 wxASSERT( nSize
> 0 );
1240 // only if old buffer was not big enough
1241 if ( nSize
> m_nSize
) {
1244 m_pItems
= new char *[nSize
];
1251 // searches the array for an item (forward or backwards)
1253 // Robert Roebling (changed to bool from bool)
1255 int wxArrayString::Index(const char *sz
, bool bCase
, bool bFromEnd
) const
1258 if ( m_nCount
> 0 ) {
1261 if ( STRING(m_pItems
[--ui
])->IsSameAs(sz
, bCase
) )
1268 for( uint ui
= 0; ui
< m_nCount
; ui
++ ) {
1269 if( STRING(m_pItems
[ui
])->IsSameAs(sz
, bCase
) )
1277 // add item at the end
1278 void wxArrayString::Add(const wxString
& str
)
1280 wxASSERT( str
.GetStringData()->IsValid() );
1284 // the string data must not be deleted!
1285 str
.GetStringData()->Lock();
1286 m_pItems
[m_nCount
++] = (char *)str
.c_str();
1289 // add item at the given position
1290 void wxArrayString::Insert(const wxString
& str
, size_t nIndex
)
1292 wxASSERT( str
.GetStringData()->IsValid() );
1294 wxCHECK_RET( nIndex
<= m_nCount
, "bad index in wxArrayString::Insert" );
1298 memmove(&m_pItems
[nIndex
+ 1], &m_pItems
[nIndex
],
1299 (m_nCount
- nIndex
)*sizeof(char *));
1301 str
.GetStringData()->Lock();
1302 m_pItems
[nIndex
] = (char *)str
.c_str();
1307 // removes item from array (by index)
1308 void wxArrayString::Remove(size_t nIndex
)
1310 wxCHECK_RET( nIndex
<= m_nCount
, "bad index in wxArrayString::Remove" );
1313 Item(nIndex
).GetStringData()->Unlock();
1315 memmove(&m_pItems
[nIndex
], &m_pItems
[nIndex
+ 1],
1316 (m_nCount
- nIndex
- 1)*sizeof(char *));
1320 // removes item from array (by value)
1321 void wxArrayString::Remove(const char *sz
)
1323 int iIndex
= Index(sz
);
1325 wxCHECK_RET( iIndex
!= NOT_FOUND
,
1326 "removing inexistent element in wxArrayString::Remove" );
1328 Remove((size_t)iIndex
);
1331 // sort array elements using passed comparaison function
1333 void wxArrayString::Sort(bool bCase
, bool bReverse
)
1336 //qsort(m_pItems, m_nCount, sizeof(char *), fCmp);