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 string shares memory with g_strEmpty
65 static wxStringData
*g_strNul
= (wxStringData
*)&g_strEmpty
;
66 // empty C style string: points to 'string data' byte of g_strEmpty
67 extern const char *g_szNul
= (const char *)(&g_strEmpty
[3]);
69 // ===========================================================================
71 // ===========================================================================
73 #ifdef STD_STRING_COMPATIBILITY
75 // MS Visual C++ version 5.0 provides the new STL headers as well as the old
78 // ATTN: you can _not_ use both of these in the same program!
81 #define NAMESPACE std::
87 NAMESPACE istream
& operator>>(NAMESPACE istream
& is
, wxString
& WXUNUSED(str
))
92 NAMESPACE streambuf
*sb
= is
.rdbuf();
95 int ch
= sb
->sbumpc ();
97 is
.setstate(NAMESPACE
ios::eofbit
);
100 else if ( isspace(ch
) ) {
112 if ( str
.length() == 0 )
113 is
.setstate(NAMESPACE
ios::failbit
);
118 #endif //std::string compatibility
120 // ===========================================================================
121 // wxString class core
122 // ===========================================================================
124 // ---------------------------------------------------------------------------
126 // ---------------------------------------------------------------------------
128 // construct an empty string
135 wxString::wxString(const wxString
& stringSrc
)
137 wxASSERT( stringSrc
.GetStringData()->IsValid() );
139 if ( stringSrc
.IsEmpty() ) {
140 // nothing to do for an empty string
144 m_pchData
= stringSrc
.m_pchData
; // share same data
145 GetStringData()->Lock(); // => one more copy
149 // constructs string of <nLength> copies of character <ch>
150 wxString::wxString(char ch
, size_t nLength
)
155 AllocBuffer(nLength
);
157 wxASSERT( sizeof(char) == 1 ); // can't use memset if not
159 memset(m_pchData
, ch
, nLength
);
163 // takes nLength elements of psz starting at nPos
164 void wxString::InitWith(const char *psz
, size_t nPos
, size_t nLength
)
168 wxASSERT( nPos
<= Strlen(psz
) );
170 if ( nLength
== STRING_MAXLEN
)
171 nLength
= Strlen(psz
+ nPos
);
174 // trailing '\0' is written in AllocBuffer()
175 AllocBuffer(nLength
);
176 memcpy(m_pchData
, psz
+ nPos
, nLength
*sizeof(char));
180 // take first nLength characters of C string psz
181 // (default value of STRING_MAXLEN means take all the string)
182 wxString::wxString(const char *psz
, size_t nLength
)
184 InitWith(psz
, 0, nLength
);
187 // the same as previous constructor, but for compilers using unsigned char
188 wxString::wxString(const unsigned char* psz
, size_t nLength
)
190 InitWith((const char *)psz
, 0, nLength
);
193 #ifdef STD_STRING_COMPATIBILITY
195 // ctor from a substring
196 wxString::wxString(const wxString
& str
, size_t nPos
, size_t nLen
)
198 wxASSERT( str
.GetStringData()->IsValid() );
200 InitWith(str
.c_str(), nPos
, nLen
== npos
? 0 : nLen
);
203 // poor man's iterators are "void *" pointers
204 wxString::wxString(const void *pStart
, const void *pEnd
)
206 InitWith((const char *)pStart
, 0,
207 (const char *)pEnd
- (const char *)pStart
);
210 #endif //std::string compatibility
213 wxString::wxString(const wchar_t *pwz
)
215 // first get necessary size
216 size_t nLen
= wcstombs(NULL
, pwz
, 0);
221 wcstombs(m_pchData
, pwz
, nLen
);
228 // ---------------------------------------------------------------------------
230 // ---------------------------------------------------------------------------
232 // allocates memory needed to store a C string of length nLen
233 void wxString::AllocBuffer(size_t nLen
)
235 wxASSERT( nLen
> 0 ); //
236 wxASSERT( nLen
<= INT_MAX
-1 ); // max size (enough room for 1 extra)
239 // 1) one extra character for '\0' termination
240 // 2) sizeof(wxStringData) for housekeeping info
241 wxStringData
* pData
= (wxStringData
*)new char[sizeof(wxStringData
) +
242 (nLen
+ 1)*sizeof(char)];
244 pData
->data()[nLen
] = '\0';
245 pData
->nDataLength
= nLen
;
246 pData
->nAllocLength
= nLen
;
247 m_pchData
= pData
->data(); // data starts after wxStringData
250 // releases the string memory and reinits it
251 void wxString::Reinit()
253 GetStringData()->Unlock();
257 // wrapper around wxString::Reinit
258 void wxString::Empty()
260 if ( GetStringData()->nDataLength
!= 0 )
263 wxASSERT( GetStringData()->nDataLength
== 0 );
264 wxASSERT( GetStringData()->nAllocLength
== 0 );
267 // must be called before changing this string
268 void wxString::CopyBeforeWrite()
270 wxStringData
* pData
= GetStringData();
272 if ( pData
->IsShared() ) {
273 pData
->Unlock(); // memory not freed because shared
274 AllocBuffer(pData
->nDataLength
);
275 memcpy(m_pchData
, pData
->data(), (pData
->nDataLength
+ 1)*sizeof(char));
278 wxASSERT( !pData
->IsShared() ); // we must be the only owner
281 // must be called before replacing contents of this string
282 void wxString::AllocBeforeWrite(size_t nLen
)
284 wxASSERT( nLen
!= 0 ); // doesn't make any sense
286 // must not share string and must have enough space
287 register wxStringData
* pData
= GetStringData();
288 if ( pData
->IsShared() || (nLen
> pData
->nAllocLength
) ) {
289 // can't work with old buffer, get new one
294 wxASSERT( !GetStringData()->IsShared() ); // we must be the only owner
297 // get the pointer to writable buffer of (at least) nLen bytes
298 char *wxString::GetWriteBuf(int nLen
)
300 AllocBeforeWrite(nLen
);
302 wxASSERT( GetStringData()->nRefs
== 1 );
303 GetStringData()->Validate(FALSE
);
308 // put string back in a reasonable state after GetWriteBuf
309 void wxString::UngetWriteBuf()
311 GetStringData()->nDataLength
= strlen(m_pchData
);
312 GetStringData()->Validate(TRUE
);
315 // dtor frees memory if no other strings use it
316 wxString::~wxString()
318 GetStringData()->Unlock();
321 // ---------------------------------------------------------------------------
323 // ---------------------------------------------------------------------------
325 // all functions are inline in string.h
327 // ---------------------------------------------------------------------------
328 // assignment operators
329 // ---------------------------------------------------------------------------
331 // helper function: does real copy
332 void wxString::AssignCopy(size_t nSrcLen
, const char *pszSrcData
)
334 if ( nSrcLen
== 0 ) {
338 AllocBeforeWrite(nSrcLen
);
339 memcpy(m_pchData
, pszSrcData
, nSrcLen
*sizeof(char));
340 GetStringData()->nDataLength
= nSrcLen
;
341 m_pchData
[nSrcLen
] = '\0';
345 // assigns one string to another
346 wxString
& wxString::operator=(const wxString
& stringSrc
)
348 wxASSERT( stringSrc
.GetStringData()->IsValid() );
350 // don't copy string over itself
351 if ( m_pchData
!= stringSrc
.m_pchData
) {
352 if ( stringSrc
.GetStringData()->IsEmpty() ) {
357 GetStringData()->Unlock();
358 m_pchData
= stringSrc
.m_pchData
;
359 GetStringData()->Lock();
366 // assigns a single character
367 wxString
& wxString::operator=(char ch
)
374 wxString
& wxString::operator=(const char *psz
)
376 AssignCopy(Strlen(psz
), psz
);
380 // same as 'signed char' variant
381 wxString
& wxString::operator=(const unsigned char* psz
)
383 *this = (const char *)psz
;
387 wxString
& wxString::operator=(const wchar_t *pwz
)
394 // ---------------------------------------------------------------------------
395 // string concatenation
396 // ---------------------------------------------------------------------------
398 // concatenate two sources
399 // NB: assume that 'this' is a new wxString object
400 void wxString::ConcatCopy(int nSrc1Len
, const char *pszSrc1Data
,
401 int nSrc2Len
, const char *pszSrc2Data
)
403 int nNewLen
= nSrc1Len
+ nSrc2Len
;
406 AllocBuffer(nNewLen
);
407 memcpy(m_pchData
, pszSrc1Data
, nSrc1Len
*sizeof(char));
408 memcpy(m_pchData
+ nSrc1Len
, pszSrc2Data
, nSrc2Len
*sizeof(char));
412 // add something to this string
413 void wxString::ConcatSelf(int nSrcLen
, const char *pszSrcData
)
415 // concatenating an empty string is a NOP
416 if ( nSrcLen
!= 0 ) {
417 register wxStringData
*pData
= GetStringData();
419 // alloc new buffer if current is too small
420 if ( pData
->IsShared() ||
421 pData
->nDataLength
+ nSrcLen
> pData
->nAllocLength
) {
422 // we have to grow the buffer, use the ConcatCopy routine
423 // (which will allocate memory)
424 wxStringData
* pOldData
= GetStringData();
425 ConcatCopy(pOldData
->nDataLength
, m_pchData
, nSrcLen
, pszSrcData
);
429 // fast concatenation when buffer big enough
430 memcpy(m_pchData
+ pData
->nDataLength
, pszSrcData
, nSrcLen
*sizeof(char));
431 pData
->nDataLength
+= nSrcLen
;
433 // should be enough space
434 wxASSERT( pData
->nDataLength
<= pData
->nAllocLength
);
436 m_pchData
[pData
->nDataLength
] = '\0'; // put terminating '\0'
442 * string may be concatenated with other string, C string or a character
445 void wxString::operator+=(const wxString
& string
)
447 wxASSERT( string
.GetStringData()->IsValid() );
449 ConcatSelf(string
.Len(), string
);
452 void wxString::operator+=(const char *psz
)
454 ConcatSelf(Strlen(psz
), psz
);
457 void wxString::operator+=(char ch
)
463 * Same as above but return the result
466 wxString
& wxString::operator<<(const wxString
& string
)
468 wxASSERT( string
.GetStringData()->IsValid() );
470 ConcatSelf(string
.Len(), string
);
474 wxString
& wxString::operator<<(const char *psz
)
476 ConcatSelf(Strlen(psz
), psz
);
480 wxString
& wxString::operator<<(char ch
)
487 * concatenation functions come in 5 flavours:
489 * char + string and string + char
490 * C str + string and string + C str
493 wxString
operator+(const wxString
& string1
, const wxString
& string2
)
495 wxASSERT( string1
.GetStringData()->IsValid() );
496 wxASSERT( string2
.GetStringData()->IsValid() );
499 s
.ConcatCopy(string1
.GetStringData()->nDataLength
, string1
.m_pchData
,
500 string2
.GetStringData()->nDataLength
, string2
.m_pchData
);
504 wxString
operator+(const wxString
& string1
, char ch
)
506 wxASSERT( string1
.GetStringData()->IsValid() );
509 s
.ConcatCopy(string1
.GetStringData()->nDataLength
, string1
.m_pchData
, 1, &ch
);
513 wxString
operator+(char ch
, const wxString
& string
)
515 wxASSERT( string
.GetStringData()->IsValid() );
518 s
.ConcatCopy(1, &ch
, string
.GetStringData()->nDataLength
, string
.m_pchData
);
522 wxString
operator+(const wxString
& string
, const char *psz
)
524 wxASSERT( string
.GetStringData()->IsValid() );
527 s
.ConcatCopy(string
.GetStringData()->nDataLength
, string
.m_pchData
,
532 wxString
operator+(const char *psz
, const wxString
& string
)
534 wxASSERT( string
.GetStringData()->IsValid() );
537 s
.ConcatCopy(Strlen(psz
), psz
,
538 string
.GetStringData()->nDataLength
, string
.m_pchData
);
542 // ===========================================================================
543 // other common string functions
544 // ===========================================================================
546 // ---------------------------------------------------------------------------
547 // simple sub-string extraction
548 // ---------------------------------------------------------------------------
550 // helper function: clone the data attached to this string
551 void wxString::AllocCopy(wxString
& dest
, int nCopyLen
, int nCopyIndex
) const
559 dest
.AllocBuffer(nCopyLen
);
560 memcpy(dest
.m_pchData
, m_pchData
+ nCopyIndex
, nCopyLen
*sizeof(char));
564 // extract string of length nCount starting at nFirst
565 // default value of nCount is 0 and means "till the end"
566 wxString
wxString::Mid(size_t nFirst
, size_t nCount
) const
568 // out-of-bounds requests return sensible things
570 nCount
= GetStringData()->nDataLength
- nFirst
;
572 if ( nFirst
+ nCount
> (size_t)GetStringData()->nDataLength
)
573 nCount
= GetStringData()->nDataLength
- nFirst
;
574 if ( nFirst
> (size_t)GetStringData()->nDataLength
)
578 AllocCopy(dest
, nCount
, nFirst
);
582 // extract nCount last (rightmost) characters
583 wxString
wxString::Right(size_t nCount
) const
585 if ( nCount
> (size_t)GetStringData()->nDataLength
)
586 nCount
= GetStringData()->nDataLength
;
589 AllocCopy(dest
, nCount
, GetStringData()->nDataLength
- nCount
);
593 // get all characters after the last occurence of ch
594 // (returns the whole string if ch not found)
595 wxString
wxString::Right(char ch
) const
598 int iPos
= Find(ch
, TRUE
);
599 if ( iPos
== NOT_FOUND
)
602 str
= c_str() + iPos
+ 1;
607 // extract nCount first (leftmost) characters
608 wxString
wxString::Left(size_t nCount
) const
610 if ( nCount
> (size_t)GetStringData()->nDataLength
)
611 nCount
= GetStringData()->nDataLength
;
614 AllocCopy(dest
, nCount
, 0);
618 // get all characters before the first occurence of ch
619 // (returns the whole string if ch not found)
620 wxString
wxString::Left(char ch
) const
623 for ( const char *pc
= m_pchData
; *pc
!= '\0' && *pc
!= ch
; pc
++ )
629 /// get all characters before the last occurence of ch
630 /// (returns empty string if ch not found)
631 wxString
wxString::Before(char ch
) const
634 int iPos
= Find(ch
, TRUE
);
635 if ( iPos
!= NOT_FOUND
&& iPos
!= 0 )
636 str
= wxString(c_str(), iPos
);
641 /// get all characters after the first occurence of ch
642 /// (returns empty string if ch not found)
643 wxString
wxString::After(char ch
) const
647 if ( iPos
!= NOT_FOUND
)
648 str
= c_str() + iPos
+ 1;
653 // replace first (or all) occurences of some substring with another one
654 uint
wxString::Replace(const char *szOld
, const char *szNew
, bool bReplaceAll
)
656 uint uiCount
= 0; // count of replacements made
658 uint uiOldLen
= Strlen(szOld
);
661 const char *pCurrent
= m_pchData
;
663 while ( *pCurrent
!= '\0' ) {
664 pSubstr
= strstr(pCurrent
, szOld
);
665 if ( pSubstr
== NULL
) {
666 // strTemp is unused if no replacements were made, so avoid the copy
670 strTemp
+= pCurrent
; // copy the rest
671 break; // exit the loop
674 // take chars before match
675 strTemp
.ConcatSelf(pSubstr
- pCurrent
, pCurrent
);
677 pCurrent
= pSubstr
+ uiOldLen
; // restart after match
682 if ( !bReplaceAll
) {
683 strTemp
+= pCurrent
; // copy the rest
684 break; // exit the loop
689 // only done if there were replacements, otherwise would have returned above
695 bool wxString::IsAscii() const
697 const char *s
= (const char*) *this;
699 if(!isascii(*s
)) return(FALSE
);
705 bool wxString::IsWord() const
707 const char *s
= (const char*) *this;
709 if(!isalpha(*s
)) return(FALSE
);
715 bool wxString::IsNumber() const
717 const char *s
= (const char*) *this;
719 if(!isdigit(*s
)) return(FALSE
);
725 // kludge: we don't have declaraton of wxStringData here, so we add offsets
726 // manually to get to the "length" field of wxStringData structure
727 bool wxString::IsEmpty() const { return Len() == 0; }
729 wxString
wxString::Strip(stripType w
) const
732 if ( w
& leading
) s
.Trim(FALSE
);
733 if ( w
& trailing
) s
.Trim(TRUE
);
737 /// case-insensitive strcmp() (platform independent)
738 int Stricmp(const char *psz1
, const char *psz2
)
740 #if defined(_MSC_VER)
741 return _stricmp(psz1
, psz2
);
742 #elif defined(__BORLANDC__)
743 return stricmp(psz1
, psz2
);
744 #elif defined(__UNIX__) || defined(__GNUWIN32__)
745 return strcasecmp(psz1
, psz2
);
747 // almost all compilers/libraries provide this function (unfortunately under
748 // different names), that's why we don't implement our own which will surely
749 // be more efficient than this code (uncomment to use):
751 register char c1, c2;
753 c1 = tolower(*psz1++);
754 c2 = tolower(*psz2++);
755 } while ( c1 && (c1 == c2) );
760 #error "Please define string case-insensitive compare for your OS/compiler"
761 #endif // OS/compiler
764 // ---------------------------------------------------------------------------
766 // ---------------------------------------------------------------------------
768 wxString
& wxString::MakeUpper()
772 for ( char *p
= m_pchData
; *p
; p
++ )
773 *p
= (char)toupper(*p
);
778 wxString
& wxString::MakeLower()
782 for ( char *p
= m_pchData
; *p
; p
++ )
783 *p
= (char)tolower(*p
);
788 // ---------------------------------------------------------------------------
789 // trimming and padding
790 // ---------------------------------------------------------------------------
792 // trims spaces (in the sense of isspace) from left or right side
793 wxString
& wxString::Trim(bool bFromRight
)
799 // find last non-space character
800 char *psz
= m_pchData
+ GetStringData()->nDataLength
- 1;
801 while ( isspace(*psz
) && (psz
>= m_pchData
) )
804 // truncate at trailing space start
806 GetStringData()->nDataLength
= psz
- m_pchData
;
810 // find first non-space character
811 const char *psz
= m_pchData
;
812 while ( isspace(*psz
) )
815 // fix up data and length
816 int nDataLength
= GetStringData()->nDataLength
- (psz
- m_pchData
);
817 memmove(m_pchData
, psz
, (nDataLength
+ 1)*sizeof(char));
818 GetStringData()->nDataLength
= nDataLength
;
824 // adds nCount characters chPad to the string from either side
825 wxString
& wxString::Pad(size_t nCount
, char chPad
, bool bFromRight
)
827 wxString
s(chPad
, nCount
);
840 // truncate the string
841 wxString
& wxString::Truncate(size_t uiLen
)
843 *(m_pchData
+ uiLen
) = '\0';
844 GetStringData()->nDataLength
= uiLen
;
849 // ---------------------------------------------------------------------------
850 // finding (return NOT_FOUND if not found and index otherwise)
851 // ---------------------------------------------------------------------------
854 int wxString::Find(char ch
, bool bFromEnd
) const
856 const char *psz
= bFromEnd
? strrchr(m_pchData
, ch
) : strchr(m_pchData
, ch
);
858 return (psz
== NULL
) ? NOT_FOUND
: psz
- m_pchData
;
861 // find a sub-string (like strstr)
862 int wxString::Find(const char *pszSub
) const
864 const char *psz
= strstr(m_pchData
, pszSub
);
866 return (psz
== NULL
) ? NOT_FOUND
: psz
- m_pchData
;
869 // ---------------------------------------------------------------------------
871 // ---------------------------------------------------------------------------
872 int wxString::Printf(const char *pszFormat
, ...)
875 va_start(argptr
, pszFormat
);
877 int iLen
= PrintfV(pszFormat
, argptr
);
884 int wxString::PrintfV(const char* pszFormat
, va_list argptr
)
886 static char s_szScratch
[1024];
888 int iLen
= vsprintf(s_szScratch
, pszFormat
, argptr
);
889 AllocBeforeWrite(iLen
);
890 strcpy(m_pchData
, s_szScratch
);
896 int wxString::Scanf(const char *pszFormat
, ...) const
899 va_start(argptr
, pszFormat
);
901 int iLen
= ScanfV(pszFormat
, argptr
);
908 int wxString::ScanfV(const char *pszFormat
, va_list argptr
) const
911 wxMessageBox("ScanfV not implemented");
914 return vsscanf(c_str(), pszFormat
, argptr
);
919 // ----------------------------------------------------------------------------
920 // misc other operations
921 // ----------------------------------------------------------------------------
922 bool wxString::Matches(const char *pszMask
) const
924 // check char by char
926 for ( pszTxt
= c_str(); *pszMask
!= '\0'; pszMask
++, pszTxt
++ ) {
927 switch ( *pszMask
) {
929 if ( *pszTxt
== '\0' )
938 // ignore special chars immediately following this one
939 while ( *pszMask
== '*' || *pszMask
== '?' )
942 // if there is nothing more, match
943 if ( *pszMask
== '\0' )
946 // are there any other metacharacters in the mask?
948 const char *pEndMask
= strpbrk(pszMask
, "*?");
950 if ( pEndMask
!= NULL
) {
951 // we have to match the string between two metachars
952 uiLenMask
= pEndMask
- pszMask
;
955 // we have to match the remainder of the string
956 uiLenMask
= strlen(pszMask
);
959 wxString
strToMatch(pszMask
, uiLenMask
);
960 const char* pMatch
= strstr(pszTxt
, strToMatch
);
961 if ( pMatch
== NULL
)
964 // -1 to compensate "++" in the loop
965 pszTxt
= pMatch
+ uiLenMask
- 1;
966 pszMask
+= uiLenMask
- 1;
971 if ( *pszMask
!= *pszTxt
)
977 // match only if nothing left
978 return *pszTxt
== '\0';
981 // ---------------------------------------------------------------------------
982 // standard C++ library string functions
983 // ---------------------------------------------------------------------------
984 #ifdef STD_STRING_COMPATIBILITY
986 wxString
& wxString::insert(size_t nPos
, const wxString
& str
)
988 wxASSERT( str
.GetStringData()->IsValid() );
989 wxASSERT( nPos
<= Len() );
992 char *pc
= strTmp
.GetWriteBuf(Len() + str
.Len());
993 strncpy(pc
, c_str(), nPos
);
994 strcpy(pc
+ nPos
, str
);
995 strcpy(pc
+ nPos
+ str
.Len(), c_str() + nPos
);
1001 size_t wxString::find(const wxString
& str
, size_t nStart
) const
1003 wxASSERT( str
.GetStringData()->IsValid() );
1004 wxASSERT( nStart
<= Len() );
1006 const char *p
= strstr(c_str() + nStart
, str
);
1008 return p
== NULL
? npos
: p
- c_str();
1011 // VC++ 1.5 can't cope with the default argument in the header.
1012 #if ! (defined(_MSC_VER) && !defined(__WIN32__))
1013 size_t wxString::find(const char* sz
, size_t nStart
, size_t n
) const
1015 return find(wxString(sz
, n
== npos
? 0 : n
), nStart
);
1019 size_t wxString::find(char ch
, size_t nStart
) const
1021 wxASSERT( nStart
<= Len() );
1023 const char *p
= strchr(c_str() + nStart
, ch
);
1025 return p
== NULL
? npos
: p
- c_str();
1028 size_t wxString::rfind(const wxString
& str
, size_t nStart
) const
1030 wxASSERT( str
.GetStringData()->IsValid() );
1031 wxASSERT( nStart
<= Len() );
1033 // # could be quicker than that
1034 const char *p
= c_str() + (nStart
== npos
? Len() : nStart
);
1035 while ( p
>= c_str() + str
.Len() ) {
1036 if ( strncmp(p
- str
.Len(), str
, str
.Len()) == 0 )
1037 return p
- str
.Len() - c_str();
1044 // VC++ 1.5 can't cope with the default argument in the header.
1045 #if ! (defined(_MSC_VER) && !defined(__WIN32__))
1046 size_t wxString::rfind(const char* sz
, size_t nStart
, size_t n
) const
1048 return rfind(wxString(sz
, n
== npos
? 0 : n
), nStart
);
1051 size_t wxString::rfind(char ch
, size_t nStart
) const
1053 wxASSERT( nStart
<= Len() );
1055 const char *p
= strrchr(c_str() + nStart
, ch
);
1057 return p
== NULL
? npos
: p
- c_str();
1061 wxString
wxString::substr(size_t nStart
, size_t nLen
) const
1063 // npos means 'take all'
1067 wxASSERT( nStart
+ nLen
<= Len() );
1069 return wxString(c_str() + nStart
, nLen
== npos
? 0 : nLen
);
1072 wxString
& wxString::erase(size_t nStart
, size_t nLen
)
1074 wxString
strTmp(c_str(), nStart
);
1075 if ( nLen
!= npos
) {
1076 wxASSERT( nStart
+ nLen
<= Len() );
1078 strTmp
.append(c_str() + nStart
+ nLen
);
1085 wxString
& wxString::replace(size_t nStart
, size_t nLen
, const char *sz
)
1087 wxASSERT( nStart
+ nLen
<= Strlen(sz
) );
1091 strTmp
.append(c_str(), nStart
);
1093 strTmp
.append(c_str() + nStart
+ nLen
);
1099 wxString
& wxString::replace(size_t nStart
, size_t nLen
, size_t nCount
, char ch
)
1101 return replace(nStart
, nLen
, wxString(ch
, nCount
));
1104 wxString
& wxString::replace(size_t nStart
, size_t nLen
,
1105 const wxString
& str
, size_t nStart2
, size_t nLen2
)
1107 return replace(nStart
, nLen
, str
.substr(nStart2
, nLen2
));
1110 wxString
& wxString::replace(size_t nStart
, size_t nLen
,
1111 const char* sz
, size_t nCount
)
1113 return replace(nStart
, nLen
, wxString(sz
, nCount
));
1116 #endif //std::string compatibility
1118 // ============================================================================
1120 // ============================================================================
1122 // size increment = max(50% of current size, ARRAY_MAXSIZE_INCREMENT)
1123 #define ARRAY_MAXSIZE_INCREMENT 4096
1124 #ifndef ARRAY_DEFAULT_INITIAL_SIZE // also defined in dynarray.h
1125 #define ARRAY_DEFAULT_INITIAL_SIZE (16)
1128 #define STRING(p) ((wxString *)(&(p)))
1131 wxArrayString::wxArrayString()
1139 wxArrayString::wxArrayString(const wxArrayString
& src
)
1141 m_nSize
= src
.m_nSize
;
1142 m_nCount
= src
.m_nCount
;
1145 m_pItems
= new char *[m_nSize
];
1149 if ( m_nCount
!= 0 )
1150 memcpy(m_pItems
, src
.m_pItems
, m_nCount
*sizeof(char *));
1154 wxArrayString
& wxArrayString::operator=(const wxArrayString
& src
)
1158 m_nSize
= src
.m_nSize
;
1159 m_nCount
= src
.m_nCount
;
1162 m_pItems
= new char *[m_nSize
];
1166 if ( m_nCount
!= 0 )
1167 memcpy(m_pItems
, src
.m_pItems
, m_nCount
*sizeof(char *));
1173 void wxArrayString::Grow()
1175 // only do it if no more place
1176 if( m_nCount
== m_nSize
) {
1177 if( m_nSize
== 0 ) {
1178 // was empty, alloc some memory
1179 m_nSize
= ARRAY_DEFAULT_INITIAL_SIZE
;
1180 m_pItems
= new char *[m_nSize
];
1183 // add 50% but not too much
1184 size_t nIncrement
= m_nSize
>> 1;
1185 if ( nIncrement
> ARRAY_MAXSIZE_INCREMENT
)
1186 nIncrement
= ARRAY_MAXSIZE_INCREMENT
;
1187 m_nSize
+= nIncrement
;
1188 char **pNew
= new char *[m_nSize
];
1190 // copy data to new location
1191 memcpy(pNew
, m_pItems
, m_nCount
*sizeof(char *));
1193 // delete old memory (but do not release the strings!)
1201 void wxArrayString::Free()
1203 for ( size_t n
= 0; n
< m_nCount
; n
++ ) {
1204 STRING(m_pItems
[n
])->GetStringData()->Unlock();
1208 // deletes all the strings from the list
1209 void wxArrayString::Empty()
1216 // as Empty, but also frees memory
1217 void wxArrayString::Clear()
1229 wxArrayString::~wxArrayString()
1236 // pre-allocates memory (frees the previous data!)
1237 void wxArrayString::Alloc(size_t nSize
)
1239 wxASSERT( nSize
> 0 );
1241 // only if old buffer was not big enough
1242 if ( nSize
> m_nSize
) {
1245 m_pItems
= new char *[nSize
];
1252 // searches the array for an item (forward or backwards)
1254 // Robert Roebling (changed to bool from bool)
1256 int wxArrayString::Index(const char *sz
, bool bCase
, bool bFromEnd
) const
1259 if ( m_nCount
> 0 ) {
1262 if ( STRING(m_pItems
[--ui
])->IsSameAs(sz
, bCase
) )
1269 for( uint ui
= 0; ui
< m_nCount
; ui
++ ) {
1270 if( STRING(m_pItems
[ui
])->IsSameAs(sz
, bCase
) )
1278 // add item at the end
1279 void wxArrayString::Add(const wxString
& str
)
1281 wxASSERT( str
.GetStringData()->IsValid() );
1285 // the string data must not be deleted!
1286 str
.GetStringData()->Lock();
1287 m_pItems
[m_nCount
++] = (char *)str
.c_str();
1290 // add item at the given position
1291 void wxArrayString::Insert(const wxString
& str
, size_t nIndex
)
1293 wxASSERT( str
.GetStringData()->IsValid() );
1295 wxCHECK_RET( nIndex
<= m_nCount
, "bad index in wxArrayString::Insert" );
1299 memmove(&m_pItems
[nIndex
+ 1], &m_pItems
[nIndex
],
1300 (m_nCount
- nIndex
)*sizeof(char *));
1302 str
.GetStringData()->Lock();
1303 m_pItems
[nIndex
] = (char *)str
.c_str();
1308 // removes item from array (by index)
1309 void wxArrayString::Remove(size_t nIndex
)
1311 wxCHECK_RET( nIndex
<= m_nCount
, "bad index in wxArrayString::Remove" );
1314 Item(nIndex
).GetStringData()->Unlock();
1316 memmove(&m_pItems
[nIndex
], &m_pItems
[nIndex
+ 1],
1317 (m_nCount
- nIndex
- 1)*sizeof(char *));
1321 // removes item from array (by value)
1322 void wxArrayString::Remove(const char *sz
)
1324 int iIndex
= Index(sz
);
1326 wxCHECK_RET( iIndex
!= NOT_FOUND
,
1327 "removing inexistent element in wxArrayString::Remove" );
1329 Remove((size_t)iIndex
);
1332 // sort array elements using passed comparaison function
1334 void wxArrayString::Sort(bool bCase
, bool bReverse
)
1337 //qsort(m_pItems, m_nCount, sizeof(char *), fCmp);