]> git.saurik.com Git - wxWidgets.git/blame - src/common/string.cpp
Fixed that stupid stream problem.
[wxWidgets.git] / src / common / string.cpp
CommitLineData
c801d85f
KB
1/////////////////////////////////////////////////////////////////////////////
2// Name: string.cpp
3// Purpose: wxString class
4// Author: Vadim Zeitlin
5// Modified by:
6// Created: 29/01/98
7// RCS-ID: $Id$
8// Copyright: (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
9// Licence: wxWindows license
10/////////////////////////////////////////////////////////////////////////////
11
12#ifdef __GNUG__
13#pragma implementation "string.h"
14#endif
15
16/*
17 * About ref counting:
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
21 */
22
23// ===========================================================================
24// headers, declarations, constants
25// ===========================================================================
26
27// For compilers that support precompilation, includes "wx.h".
28#include "wx/wxprec.h"
29
30#ifdef __BORLANDC__
31#pragma hdrstop
32#endif
33
34#ifndef WX_PRECOMP
35#include "wx/defs.h"
36#include "wx/string.h"
37#endif
38
39#include <ctype.h>
40#include <string.h>
41#include <stdlib.h>
42
43#ifdef WXSTRING_IS_WXOBJECT
44 IMPLEMENT_DYNAMIC_CLASS(wxString, wxObject)
45#endif //WXSTRING_IS_WXOBJECT
46
47// ---------------------------------------------------------------------------
48// static class variables definition
49// ---------------------------------------------------------------------------
50
51#ifdef STD_STRING_COMPATIBILITY
52 const size_t wxString::npos = STRING_MAXLEN;
53#endif
54
55// ===========================================================================
56// static class data, special inlines
57// ===========================================================================
58
59// for an empty string, GetStringData() will return this address
60static int g_strEmpty[] = { -1, // ref count (locked)
61 0, // current length
62 0, // allocated memory
63 0 }; // string data
c801d85f
KB
64// empty C style string: points to 'string data' byte of g_strEmpty
65extern const char *g_szNul = (const char *)(&g_strEmpty[3]);
66
67// ===========================================================================
68// global functions
69// ===========================================================================
70
71#ifdef STD_STRING_COMPATIBILITY
72
73// MS Visual C++ version 5.0 provides the new STL headers as well as the old
74// iostream ones.
75//
76// ATTN: you can _not_ use both of these in the same program!
77#if 0 // def _MSC_VER
78 #include <iostream>
79 #define NAMESPACE std::
80#else
81 #include <iostream.h>
82 #define NAMESPACE
83#endif //Visual C++
84
85NAMESPACE istream& operator>>(NAMESPACE istream& is, wxString& WXUNUSED(str))
86{
87#if 0
88 int w = is.width(0);
89 if ( is.ipfx(0) ) {
90 NAMESPACE streambuf *sb = is.rdbuf();
91 str.erase();
92 while ( true ) {
93 int ch = sb->sbumpc ();
94 if ( ch == EOF ) {
95 is.setstate(NAMESPACE ios::eofbit);
96 break;
97 }
98 else if ( isspace(ch) ) {
99 sb->sungetc();
100 break;
101 }
102
103 str += ch;
104 if ( --w == 1 )
105 break;
106 }
107 }
108
109 is.isfx();
110 if ( str.length() == 0 )
111 is.setstate(NAMESPACE ios::failbit);
112#endif
113 return is;
114}
115
116#endif //std::string compatibility
117
118// ===========================================================================
119// wxString class core
120// ===========================================================================
121
122// ---------------------------------------------------------------------------
123// construction
124// ---------------------------------------------------------------------------
125
126// construct an empty string
127wxString::wxString()
128{
129 Init();
130}
131
132// copy constructor
133wxString::wxString(const wxString& stringSrc)
134{
135 wxASSERT( stringSrc.GetStringData()->IsValid() );
136
137 if ( stringSrc.IsEmpty() ) {
138 // nothing to do for an empty string
139 Init();
140 }
141 else {
142 m_pchData = stringSrc.m_pchData; // share same data
143 GetStringData()->Lock(); // => one more copy
144 }
145}
146
147// constructs string of <nLength> copies of character <ch>
148wxString::wxString(char ch, size_t nLength)
149{
150 Init();
151
152 if ( nLength > 0 ) {
153 AllocBuffer(nLength);
f1da2f03 154
c801d85f
KB
155 wxASSERT( sizeof(char) == 1 ); // can't use memset if not
156
157 memset(m_pchData, ch, nLength);
158 }
159}
160
161// takes nLength elements of psz starting at nPos
162void wxString::InitWith(const char *psz, size_t nPos, size_t nLength)
163{
164 Init();
165
166 wxASSERT( nPos <= Strlen(psz) );
167
168 if ( nLength == STRING_MAXLEN )
169 nLength = Strlen(psz + nPos);
170
171 if ( nLength > 0 ) {
172 // trailing '\0' is written in AllocBuffer()
173 AllocBuffer(nLength);
174 memcpy(m_pchData, psz + nPos, nLength*sizeof(char));
175 }
176}
177
178// take first nLength characters of C string psz
179// (default value of STRING_MAXLEN means take all the string)
180wxString::wxString(const char *psz, size_t nLength)
181{
182 InitWith(psz, 0, nLength);
183}
184
185// the same as previous constructor, but for compilers using unsigned char
186wxString::wxString(const unsigned char* psz, size_t nLength)
187{
188 InitWith((const char *)psz, 0, nLength);
189}
190
191#ifdef STD_STRING_COMPATIBILITY
192
193// ctor from a substring
097c080b 194wxString::wxString(const wxString& str, size_t nPos, size_t nLen)
c801d85f 195{
097c080b
VZ
196 wxASSERT( str.GetStringData()->IsValid() );
197
198 InitWith(str.c_str(), nPos, nLen == npos ? 0 : nLen);
c801d85f
KB
199}
200
201// poor man's iterators are "void *" pointers
202wxString::wxString(const void *pStart, const void *pEnd)
203{
204 InitWith((const char *)pStart, 0,
205 (const char *)pEnd - (const char *)pStart);
206}
207
208#endif //std::string compatibility
209
210// from wide string
211wxString::wxString(const wchar_t *pwz)
212{
213 // first get necessary size
214 size_t nLen = wcstombs(NULL, pwz, 0);
215
216 // empty?
217 if ( nLen != 0 ) {
218 AllocBuffer(nLen);
219 wcstombs(m_pchData, pwz, nLen);
220 }
221 else {
222 Init();
223 }
224}
225
226// ---------------------------------------------------------------------------
227// memory allocation
228// ---------------------------------------------------------------------------
229
230// allocates memory needed to store a C string of length nLen
231void wxString::AllocBuffer(size_t nLen)
232{
233 wxASSERT( nLen > 0 ); //
234 wxASSERT( nLen <= INT_MAX-1 ); // max size (enough room for 1 extra)
235
236 // allocate memory:
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)];
241 pData->nRefs = 1;
242 pData->data()[nLen] = '\0';
243 pData->nDataLength = nLen;
244 pData->nAllocLength = nLen;
245 m_pchData = pData->data(); // data starts after wxStringData
246}
247
248// releases the string memory and reinits it
249void wxString::Reinit()
250{
251 GetStringData()->Unlock();
252 Init();
253}
254
255// wrapper around wxString::Reinit
256void wxString::Empty()
257{
258 if ( GetStringData()->nDataLength != 0 )
259 Reinit();
260
261 wxASSERT( GetStringData()->nDataLength == 0 );
262 wxASSERT( GetStringData()->nAllocLength == 0 );
263}
264
265// must be called before changing this string
266void wxString::CopyBeforeWrite()
267{
268 wxStringData* pData = GetStringData();
269
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));
274 }
275
276 wxASSERT( !pData->IsShared() ); // we must be the only owner
277}
278
279// must be called before replacing contents of this string
280void wxString::AllocBeforeWrite(size_t nLen)
281{
282 wxASSERT( nLen != 0 ); // doesn't make any sense
283
284 // must not share string and must have enough space
f1da2f03 285 register wxStringData* pData = GetStringData();
c801d85f
KB
286 if ( pData->IsShared() || (nLen > pData->nAllocLength) ) {
287 // can't work with old buffer, get new one
288 pData->Unlock();
289 AllocBuffer(nLen);
290 }
291
f1da2f03 292 wxASSERT( !GetStringData()->IsShared() ); // we must be the only owner
c801d85f
KB
293}
294
295// get the pointer to writable buffer of (at least) nLen bytes
097c080b 296char *wxString::GetWriteBuf(int nLen)
c801d85f
KB
297{
298 AllocBeforeWrite(nLen);
097c080b
VZ
299
300 wxASSERT( GetStringData()->nRefs == 1 );
301 GetStringData()->Validate(FALSE);
302
c801d85f
KB
303 return m_pchData;
304}
305
097c080b
VZ
306// put string back in a reasonable state after GetWriteBuf
307void wxString::UngetWriteBuf()
308{
309 GetStringData()->nDataLength = strlen(m_pchData);
310 GetStringData()->Validate(TRUE);
311}
312
c801d85f
KB
313// dtor frees memory if no other strings use it
314wxString::~wxString()
315{
316 GetStringData()->Unlock();
317}
318
319// ---------------------------------------------------------------------------
320// data access
321// ---------------------------------------------------------------------------
322
323// all functions are inline in string.h
324
325// ---------------------------------------------------------------------------
326// assignment operators
327// ---------------------------------------------------------------------------
328
329// helper function: does real copy
330void wxString::AssignCopy(size_t nSrcLen, const char *pszSrcData)
331{
332 if ( nSrcLen == 0 ) {
333 Reinit();
334 }
335 else {
336 AllocBeforeWrite(nSrcLen);
337 memcpy(m_pchData, pszSrcData, nSrcLen*sizeof(char));
338 GetStringData()->nDataLength = nSrcLen;
339 m_pchData[nSrcLen] = '\0';
340 }
341}
342
343// assigns one string to another
344wxString& wxString::operator=(const wxString& stringSrc)
345{
097c080b
VZ
346 wxASSERT( stringSrc.GetStringData()->IsValid() );
347
c801d85f
KB
348 // don't copy string over itself
349 if ( m_pchData != stringSrc.m_pchData ) {
350 if ( stringSrc.GetStringData()->IsEmpty() ) {
351 Reinit();
352 }
353 else {
354 // adjust references
355 GetStringData()->Unlock();
356 m_pchData = stringSrc.m_pchData;
357 GetStringData()->Lock();
358 }
359 }
360
361 return *this;
362}
363
364// assigns a single character
365wxString& wxString::operator=(char ch)
366{
367 AssignCopy(1, &ch);
368 return *this;
369}
370
371// assigns C string
372wxString& wxString::operator=(const char *psz)
373{
374 AssignCopy(Strlen(psz), psz);
375 return *this;
376}
377
378// same as 'signed char' variant
379wxString& wxString::operator=(const unsigned char* psz)
380{
381 *this = (const char *)psz;
382 return *this;
383}
384
385wxString& wxString::operator=(const wchar_t *pwz)
386{
387 wxString str(pwz);
388 *this = str;
389 return *this;
390}
391
392// ---------------------------------------------------------------------------
393// string concatenation
394// ---------------------------------------------------------------------------
395
396// concatenate two sources
397// NB: assume that 'this' is a new wxString object
398void wxString::ConcatCopy(int nSrc1Len, const char *pszSrc1Data,
399 int nSrc2Len, const char *pszSrc2Data)
400{
401 int nNewLen = nSrc1Len + nSrc2Len;
402 if ( nNewLen != 0 )
403 {
404 AllocBuffer(nNewLen);
405 memcpy(m_pchData, pszSrc1Data, nSrc1Len*sizeof(char));
406 memcpy(m_pchData + nSrc1Len, pszSrc2Data, nSrc2Len*sizeof(char));
407 }
408}
409
410// add something to this string
411void wxString::ConcatSelf(int nSrcLen, const char *pszSrcData)
412{
413 // concatenating an empty string is a NOP
414 if ( nSrcLen != 0 ) {
415 register wxStringData *pData = GetStringData();
416
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);
424 pOldData->Unlock();
425 }
426 else {
427 // fast concatenation when buffer big enough
428 memcpy(m_pchData + pData->nDataLength, pszSrcData, nSrcLen*sizeof(char));
429 pData->nDataLength += nSrcLen;
430
431 // should be enough space
432 wxASSERT( pData->nDataLength <= pData->nAllocLength );
433
434 m_pchData[pData->nDataLength] = '\0'; // put terminating '\0'
435 }
436 }
437}
438
439/*
440 * string may be concatenated with other string, C string or a character
441 */
442
443void wxString::operator+=(const wxString& string)
444{
097c080b
VZ
445 wxASSERT( string.GetStringData()->IsValid() );
446
c801d85f
KB
447 ConcatSelf(string.Len(), string);
448}
449
450void wxString::operator+=(const char *psz)
451{
452 ConcatSelf(Strlen(psz), psz);
453}
454
455void wxString::operator+=(char ch)
456{
457 ConcatSelf(1, &ch);
458}
459
460/*
461 * Same as above but return the result
462 */
463
464wxString& wxString::operator<<(const wxString& string)
465{
097c080b
VZ
466 wxASSERT( string.GetStringData()->IsValid() );
467
c801d85f
KB
468 ConcatSelf(string.Len(), string);
469 return *this;
470}
471
472wxString& wxString::operator<<(const char *psz)
473{
474 ConcatSelf(Strlen(psz), psz);
475 return *this;
476}
477
478wxString& wxString::operator<<(char ch)
479{
480 ConcatSelf(1, &ch);
481 return *this;
482}
483
484/*
485 * concatenation functions come in 5 flavours:
486 * string + string
487 * char + string and string + char
488 * C str + string and string + C str
489 */
490
491wxString operator+(const wxString& string1, const wxString& string2)
492{
097c080b
VZ
493 wxASSERT( string1.GetStringData()->IsValid() );
494 wxASSERT( string2.GetStringData()->IsValid() );
495
c801d85f
KB
496 wxString s;
497 s.ConcatCopy(string1.GetStringData()->nDataLength, string1.m_pchData,
498 string2.GetStringData()->nDataLength, string2.m_pchData);
499 return s;
500}
501
502wxString operator+(const wxString& string1, char ch)
503{
097c080b
VZ
504 wxASSERT( string1.GetStringData()->IsValid() );
505
c801d85f
KB
506 wxString s;
507 s.ConcatCopy(string1.GetStringData()->nDataLength, string1.m_pchData, 1, &ch);
508 return s;
509}
510
511wxString operator+(char ch, const wxString& string)
512{
097c080b
VZ
513 wxASSERT( string.GetStringData()->IsValid() );
514
c801d85f
KB
515 wxString s;
516 s.ConcatCopy(1, &ch, string.GetStringData()->nDataLength, string.m_pchData);
517 return s;
518}
519
520wxString operator+(const wxString& string, const char *psz)
521{
097c080b
VZ
522 wxASSERT( string.GetStringData()->IsValid() );
523
c801d85f
KB
524 wxString s;
525 s.ConcatCopy(string.GetStringData()->nDataLength, string.m_pchData,
526 Strlen(psz), psz);
527 return s;
528}
529
530wxString operator+(const char *psz, const wxString& string)
531{
097c080b
VZ
532 wxASSERT( string.GetStringData()->IsValid() );
533
c801d85f
KB
534 wxString s;
535 s.ConcatCopy(Strlen(psz), psz,
536 string.GetStringData()->nDataLength, string.m_pchData);
537 return s;
538}
539
540// ===========================================================================
541// other common string functions
542// ===========================================================================
543
544// ---------------------------------------------------------------------------
545// simple sub-string extraction
546// ---------------------------------------------------------------------------
547
548// helper function: clone the data attached to this string
549void wxString::AllocCopy(wxString& dest, int nCopyLen, int nCopyIndex) const
550{
551 if ( nCopyLen == 0 )
552 {
553 dest.Init();
554 }
555 else
556 {
557 dest.AllocBuffer(nCopyLen);
558 memcpy(dest.m_pchData, m_pchData + nCopyIndex, nCopyLen*sizeof(char));
559 }
560}
561
562// extract string of length nCount starting at nFirst
563// default value of nCount is 0 and means "till the end"
564wxString wxString::Mid(size_t nFirst, size_t nCount) const
565{
566 // out-of-bounds requests return sensible things
567 if ( nCount == 0 )
568 nCount = GetStringData()->nDataLength - nFirst;
569
570 if ( nFirst + nCount > (size_t)GetStringData()->nDataLength )
571 nCount = GetStringData()->nDataLength - nFirst;
572 if ( nFirst > (size_t)GetStringData()->nDataLength )
573 nCount = 0;
574
575 wxString dest;
576 AllocCopy(dest, nCount, nFirst);
577 return dest;
578}
579
580// extract nCount last (rightmost) characters
581wxString wxString::Right(size_t nCount) const
582{
583 if ( nCount > (size_t)GetStringData()->nDataLength )
584 nCount = GetStringData()->nDataLength;
585
586 wxString dest;
587 AllocCopy(dest, nCount, GetStringData()->nDataLength - nCount);
588 return dest;
589}
590
591// get all characters after the last occurence of ch
592// (returns the whole string if ch not found)
593wxString wxString::Right(char ch) const
594{
595 wxString str;
596 int iPos = Find(ch, TRUE);
597 if ( iPos == NOT_FOUND )
598 str = *this;
599 else
c8cfb486 600 str = c_str() + iPos + 1;
c801d85f
KB
601
602 return str;
603}
604
605// extract nCount first (leftmost) characters
606wxString wxString::Left(size_t nCount) const
607{
608 if ( nCount > (size_t)GetStringData()->nDataLength )
609 nCount = GetStringData()->nDataLength;
610
611 wxString dest;
612 AllocCopy(dest, nCount, 0);
613 return dest;
614}
615
616// get all characters before the first occurence of ch
617// (returns the whole string if ch not found)
618wxString wxString::Left(char ch) const
619{
620 wxString str;
621 for ( const char *pc = m_pchData; *pc != '\0' && *pc != ch; pc++ )
622 str += *pc;
623
624 return str;
625}
626
627/// get all characters before the last occurence of ch
628/// (returns empty string if ch not found)
629wxString wxString::Before(char ch) const
630{
631 wxString str;
632 int iPos = Find(ch, TRUE);
633 if ( iPos != NOT_FOUND && iPos != 0 )
d1c9bbf6 634 str = wxString(c_str(), iPos);
c801d85f
KB
635
636 return str;
637}
638
639/// get all characters after the first occurence of ch
640/// (returns empty string if ch not found)
641wxString wxString::After(char ch) const
642{
643 wxString str;
644 int iPos = Find(ch);
645 if ( iPos != NOT_FOUND )
646 str = c_str() + iPos + 1;
647
648 return str;
649}
650
651// replace first (or all) occurences of some substring with another one
652uint wxString::Replace(const char *szOld, const char *szNew, bool bReplaceAll)
653{
654 uint uiCount = 0; // count of replacements made
655
656 uint uiOldLen = Strlen(szOld);
657
658 wxString strTemp;
659 const char *pCurrent = m_pchData;
660 const char *pSubstr;
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
665 if ( uiCount == 0 )
666 return 0;
667
668 strTemp += pCurrent; // copy the rest
669 break; // exit the loop
670 }
671 else {
672 // take chars before match
673 strTemp.ConcatSelf(pSubstr - pCurrent, pCurrent);
674 strTemp += szNew;
675 pCurrent = pSubstr + uiOldLen; // restart after match
676
677 uiCount++;
678
679 // stop now?
680 if ( !bReplaceAll ) {
681 strTemp += pCurrent; // copy the rest
682 break; // exit the loop
683 }
684 }
685 }
686
687 // only done if there were replacements, otherwise would have returned above
688 *this = strTemp;
689
690 return uiCount;
691}
692
693bool wxString::IsAscii() const
694{
695 const char *s = (const char*) *this;
696 while(*s){
697 if(!isascii(*s)) return(FALSE);
698 s++;
699 }
700 return(TRUE);
701}
702
703bool wxString::IsWord() const
704{
705 const char *s = (const char*) *this;
706 while(*s){
707 if(!isalpha(*s)) return(FALSE);
708 s++;
709 }
710 return(TRUE);
711}
712
713bool wxString::IsNumber() const
714{
715 const char *s = (const char*) *this;
716 while(*s){
717 if(!isdigit(*s)) return(FALSE);
718 s++;
719 }
720 return(TRUE);
721}
722
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
725bool wxString::IsEmpty() const { return Len() == 0; }
726
727wxString wxString::Strip(stripType w) const
728{
729 wxString s = *this;
730 if ( w & leading ) s.Trim(FALSE);
731 if ( w & trailing ) s.Trim(TRUE);
732 return s;
733}
734
735/// case-insensitive strcmp() (platform independent)
736int Stricmp(const char *psz1, const char *psz2)
737{
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);
744#else
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):
748 /*
749 register char c1, c2;
750 do {
751 c1 = tolower(*psz1++);
752 c2 = tolower(*psz2++);
753 } while ( c1 && (c1 == c2) );
754
755 return c1 - c2;
756 */
757
758 #error "Please define string case-insensitive compare for your OS/compiler"
759#endif // OS/compiler
760}
761
762// ---------------------------------------------------------------------------
763// case conversion
764// ---------------------------------------------------------------------------
765
766wxString& wxString::MakeUpper()
767{
768 CopyBeforeWrite();
769
770 for ( char *p = m_pchData; *p; p++ )
771 *p = (char)toupper(*p);
772
773 return *this;
774}
775
776wxString& wxString::MakeLower()
777{
778 CopyBeforeWrite();
779
780 for ( char *p = m_pchData; *p; p++ )
781 *p = (char)tolower(*p);
782
783 return *this;
784}
785
786// ---------------------------------------------------------------------------
787// trimming and padding
788// ---------------------------------------------------------------------------
789
790// trims spaces (in the sense of isspace) from left or right side
791wxString& wxString::Trim(bool bFromRight)
792{
793 CopyBeforeWrite();
794
795 if ( bFromRight )
796 {
797 // find last non-space character
798 char *psz = m_pchData + GetStringData()->nDataLength - 1;
799 while ( isspace(*psz) && (psz >= m_pchData) )
800 psz--;
801
802 // truncate at trailing space start
803 *++psz = '\0';
804 GetStringData()->nDataLength = psz - m_pchData;
805 }
806 else
807 {
808 // find first non-space character
809 const char *psz = m_pchData;
810 while ( isspace(*psz) )
811 psz++;
812
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;
817 }
818
819 return *this;
820}
821
822// adds nCount characters chPad to the string from either side
823wxString& wxString::Pad(size_t nCount, char chPad, bool bFromRight)
824{
825 wxString s(chPad, nCount);
826
827 if ( bFromRight )
828 *this += s;
829 else
830 {
831 s += *this;
832 *this = s;
833 }
834
835 return *this;
836}
837
838// truncate the string
839wxString& wxString::Truncate(size_t uiLen)
840{
841 *(m_pchData + uiLen) = '\0';
842 GetStringData()->nDataLength = uiLen;
843
844 return *this;
845}
846
847// ---------------------------------------------------------------------------
848// finding (return NOT_FOUND if not found and index otherwise)
849// ---------------------------------------------------------------------------
850
851// find a character
852int wxString::Find(char ch, bool bFromEnd) const
853{
854 const char *psz = bFromEnd ? strrchr(m_pchData, ch) : strchr(m_pchData, ch);
855
856 return (psz == NULL) ? NOT_FOUND : psz - m_pchData;
857}
858
859// find a sub-string (like strstr)
860int wxString::Find(const char *pszSub) const
861{
862 const char *psz = strstr(m_pchData, pszSub);
863
864 return (psz == NULL) ? NOT_FOUND : psz - m_pchData;
865}
866
867// ---------------------------------------------------------------------------
9efd3367 868// formatted output
c801d85f
KB
869// ---------------------------------------------------------------------------
870int wxString::Printf(const char *pszFormat, ...)
871{
872 va_list argptr;
873 va_start(argptr, pszFormat);
874
875 int iLen = PrintfV(pszFormat, argptr);
876
877 va_end(argptr);
878
879 return iLen;
880}
881
882int wxString::PrintfV(const char* pszFormat, va_list argptr)
883{
9efd3367 884 static char s_szScratch[1024];
c801d85f
KB
885
886 int iLen = vsprintf(s_szScratch, pszFormat, argptr);
887 AllocBeforeWrite(iLen);
888 strcpy(m_pchData, s_szScratch);
889
890 return iLen;
891}
892
f0edd824 893#if 0
607d9061
JS
894int wxString::Scanf(const char *pszFormat, ...) const
895{
896 va_list argptr;
897 va_start(argptr, pszFormat);
898
899 int iLen = ScanfV(pszFormat, argptr);
900
901 va_end(argptr);
902
903 return iLen;
904}
905
906int wxString::ScanfV(const char *pszFormat, va_list argptr) const
907{
2049ba38 908#ifdef __WXMSW__
607d9061
JS
909 wxMessageBox("ScanfV not implemented");
910 return 0;
911#else
912 return vsscanf(c_str(), pszFormat, argptr);
913#endif
914}
f0edd824 915#endif
607d9061 916
097c080b
VZ
917// ----------------------------------------------------------------------------
918// misc other operations
919// ----------------------------------------------------------------------------
920bool wxString::Matches(const char *pszMask) const
921{
922 // check char by char
923 const char *pszTxt;
924 for ( pszTxt = c_str(); *pszMask != '\0'; pszMask++, pszTxt++ ) {
925 switch ( *pszMask ) {
926 case '?':
927 if ( *pszTxt == '\0' )
928 return FALSE;
929
930 pszTxt++;
931 pszMask++;
932 break;
933
934 case '*':
935 {
936 // ignore special chars immediately following this one
937 while ( *pszMask == '*' || *pszMask == '?' )
938 pszMask++;
939
940 // if there is nothing more, match
941 if ( *pszMask == '\0' )
942 return TRUE;
943
944 // are there any other metacharacters in the mask?
945 uint uiLenMask;
946 const char *pEndMask = strpbrk(pszMask, "*?");
947
948 if ( pEndMask != NULL ) {
949 // we have to match the string between two metachars
950 uiLenMask = pEndMask - pszMask;
951 }
952 else {
953 // we have to match the remainder of the string
954 uiLenMask = strlen(pszMask);
955 }
956
957 wxString strToMatch(pszMask, uiLenMask);
958 const char* pMatch = strstr(pszTxt, strToMatch);
959 if ( pMatch == NULL )
960 return FALSE;
961
962 // -1 to compensate "++" in the loop
963 pszTxt = pMatch + uiLenMask - 1;
964 pszMask += uiLenMask - 1;
965 }
966 break;
967
968 default:
969 if ( *pszMask != *pszTxt )
970 return FALSE;
971 break;
972 }
973 }
974
975 // match only if nothing left
976 return *pszTxt == '\0';
977}
978
c801d85f
KB
979// ---------------------------------------------------------------------------
980// standard C++ library string functions
981// ---------------------------------------------------------------------------
982#ifdef STD_STRING_COMPATIBILITY
983
984wxString& wxString::insert(size_t nPos, const wxString& str)
985{
097c080b 986 wxASSERT( str.GetStringData()->IsValid() );
c801d85f
KB
987 wxASSERT( nPos <= Len() );
988
989 wxString strTmp;
68919656 990 char *pc = strTmp.GetWriteBuf(Len() + str.Len());
c801d85f
KB
991 strncpy(pc, c_str(), nPos);
992 strcpy(pc + nPos, str);
993 strcpy(pc + nPos + str.Len(), c_str() + nPos);
abc79986 994 strTmp.UngetWriteBuf();
c801d85f
KB
995 *this = strTmp;
996
997 return *this;
998}
999
1000size_t wxString::find(const wxString& str, size_t nStart) const
1001{
097c080b 1002 wxASSERT( str.GetStringData()->IsValid() );
c801d85f
KB
1003 wxASSERT( nStart <= Len() );
1004
1005 const char *p = strstr(c_str() + nStart, str);
1006
1007 return p == NULL ? npos : p - c_str();
1008}
1009
f0b3249b
JS
1010// VC++ 1.5 can't cope with the default argument in the header.
1011#if ! (defined(_MSC_VER) && !defined(__WIN32__))
c801d85f
KB
1012size_t wxString::find(const char* sz, size_t nStart, size_t n) const
1013{
1014 return find(wxString(sz, n == npos ? 0 : n), nStart);
1015}
f0b3249b 1016#endif
c801d85f
KB
1017
1018size_t wxString::find(char ch, size_t nStart) const
1019{
1020 wxASSERT( nStart <= Len() );
1021
1022 const char *p = strchr(c_str() + nStart, ch);
1023
1024 return p == NULL ? npos : p - c_str();
1025}
1026
1027size_t wxString::rfind(const wxString& str, size_t nStart) const
1028{
097c080b 1029 wxASSERT( str.GetStringData()->IsValid() );
c801d85f
KB
1030 wxASSERT( nStart <= Len() );
1031
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();
1037 p--;
1038 }
1039
1040 return npos;
1041}
1042
f0b3249b
JS
1043// VC++ 1.5 can't cope with the default argument in the header.
1044#if ! (defined(_MSC_VER) && !defined(__WIN32__))
c801d85f
KB
1045size_t wxString::rfind(const char* sz, size_t nStart, size_t n) const
1046{
1047 return rfind(wxString(sz, n == npos ? 0 : n), nStart);
1048}
1049
1050size_t wxString::rfind(char ch, size_t nStart) const
1051{
1052 wxASSERT( nStart <= Len() );
1053
1054 const char *p = strrchr(c_str() + nStart, ch);
1055
1056 return p == NULL ? npos : p - c_str();
1057}
f0b3249b 1058#endif
c801d85f
KB
1059
1060wxString wxString::substr(size_t nStart, size_t nLen) const
1061{
1062 // npos means 'take all'
1063 if ( nLen == npos )
1064 nLen = 0;
1065
1066 wxASSERT( nStart + nLen <= Len() );
1067
1068 return wxString(c_str() + nStart, nLen == npos ? 0 : nLen);
1069}
1070
1071wxString& wxString::erase(size_t nStart, size_t nLen)
1072{
1073 wxString strTmp(c_str(), nStart);
1074 if ( nLen != npos ) {
1075 wxASSERT( nStart + nLen <= Len() );
1076
1077 strTmp.append(c_str() + nStart + nLen);
1078 }
1079
1080 *this = strTmp;
1081 return *this;
1082}
1083
1084wxString& wxString::replace(size_t nStart, size_t nLen, const char *sz)
1085{
1086 wxASSERT( nStart + nLen <= Strlen(sz) );
1087
1088 wxString strTmp;
1089 if ( nStart != 0 )
1090 strTmp.append(c_str(), nStart);
1091 strTmp += sz;
1092 strTmp.append(c_str() + nStart + nLen);
1093
1094 *this = strTmp;
1095 return *this;
1096}
1097
1098wxString& wxString::replace(size_t nStart, size_t nLen, size_t nCount, char ch)
1099{
1100 return replace(nStart, nLen, wxString(ch, nCount));
1101}
1102
1103wxString& wxString::replace(size_t nStart, size_t nLen,
097c080b 1104 const wxString& str, size_t nStart2, size_t nLen2)
c801d85f
KB
1105{
1106 return replace(nStart, nLen, str.substr(nStart2, nLen2));
1107}
1108
1109wxString& wxString::replace(size_t nStart, size_t nLen,
1110 const char* sz, size_t nCount)
1111{
1112 return replace(nStart, nLen, wxString(sz, nCount));
1113}
1114
1115#endif //std::string compatibility
1116
1117// ============================================================================
1118// ArrayString
1119// ============================================================================
1120
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)
1125#endif
1126
1127#define STRING(p) ((wxString *)(&(p)))
1128
1129// ctor
1130wxArrayString::wxArrayString()
1131{
1132 m_nSize =
1133 m_nCount = 0;
1134 m_pItems = NULL;
1135}
1136
1137// copy ctor
1138wxArrayString::wxArrayString(const wxArrayString& src)
1139{
1140 m_nSize = src.m_nSize;
1141 m_nCount = src.m_nCount;
1142
1143 if ( m_nSize != 0 )
1144 m_pItems = new char *[m_nSize];
1145 else
1146 m_pItems = NULL;
1147
1148 if ( m_nCount != 0 )
1149 memcpy(m_pItems, src.m_pItems, m_nCount*sizeof(char *));
1150}
1151
1152// copy operator
1153wxArrayString& wxArrayString::operator=(const wxArrayString& src)
1154{
1155 DELETEA(m_pItems);
1156
1157 m_nSize = src.m_nSize;
1158 m_nCount = src.m_nCount;
1159
1160 if ( m_nSize != 0 )
1161 m_pItems = new char *[m_nSize];
1162 else
1163 m_pItems = NULL;
1164
1165 if ( m_nCount != 0 )
1166 memcpy(m_pItems, src.m_pItems, m_nCount*sizeof(char *));
1167
1168 return *this;
1169}
1170
1171// grow the array
1172void wxArrayString::Grow()
1173{
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];
1180 }
1181 else {
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];
1188
1189 // copy data to new location
1190 memcpy(pNew, m_pItems, m_nCount*sizeof(char *));
1191
1192 // delete old memory (but do not release the strings!)
1193 DELETEA(m_pItems);
1194
1195 m_pItems = pNew;
1196 }
1197 }
1198}
1199
1200void wxArrayString::Free()
1201{
1202 for ( size_t n = 0; n < m_nCount; n++ ) {
1203 STRING(m_pItems[n])->GetStringData()->Unlock();
1204 }
1205}
1206
1207// deletes all the strings from the list
1208void wxArrayString::Empty()
1209{
1210 Free();
1211
1212 m_nCount = 0;
1213}
1214
1215// as Empty, but also frees memory
1216void wxArrayString::Clear()
1217{
1218 Free();
1219
1220 m_nSize =
1221 m_nCount = 0;
1222
1223 DELETEA(m_pItems);
1224 m_pItems = NULL;
1225}
1226
1227// dtor
1228wxArrayString::~wxArrayString()
1229{
1230 Free();
1231
1232 DELETEA(m_pItems);
1233}
1234
1235// pre-allocates memory (frees the previous data!)
1236void wxArrayString::Alloc(size_t nSize)
1237{
1238 wxASSERT( nSize > 0 );
1239
1240 // only if old buffer was not big enough
1241 if ( nSize > m_nSize ) {
1242 Free();
1243 DELETEA(m_pItems);
1244 m_pItems = new char *[nSize];
1245 m_nSize = nSize;
1246 }
1247
1248 m_nCount = 0;
1249}
1250
1251// searches the array for an item (forward or backwards)
1252
9efd3367 1253// Robert Roebling (changed to bool from bool)
c801d85f
KB
1254
1255int wxArrayString::Index(const char *sz, bool bCase, bool bFromEnd) const
1256{
1257 if ( bFromEnd ) {
1258 if ( m_nCount > 0 ) {
1259 uint ui = m_nCount;
1260 do {
1261 if ( STRING(m_pItems[--ui])->IsSameAs(sz, bCase) )
1262 return ui;
1263 }
1264 while ( ui != 0 );
1265 }
1266 }
1267 else {
1268 for( uint ui = 0; ui < m_nCount; ui++ ) {
1269 if( STRING(m_pItems[ui])->IsSameAs(sz, bCase) )
1270 return ui;
1271 }
1272 }
1273
1274 return NOT_FOUND;
1275}
1276
1277// add item at the end
097c080b 1278void wxArrayString::Add(const wxString& str)
c801d85f 1279{
097c080b
VZ
1280 wxASSERT( str.GetStringData()->IsValid() );
1281
c801d85f
KB
1282 Grow();
1283
1284 // the string data must not be deleted!
097c080b
VZ
1285 str.GetStringData()->Lock();
1286 m_pItems[m_nCount++] = (char *)str.c_str();
c801d85f
KB
1287}
1288
1289// add item at the given position
097c080b 1290void wxArrayString::Insert(const wxString& str, size_t nIndex)
c801d85f 1291{
097c080b
VZ
1292 wxASSERT( str.GetStringData()->IsValid() );
1293
9efd3367 1294 wxCHECK_RET( nIndex <= m_nCount, "bad index in wxArrayString::Insert" );
c801d85f
KB
1295
1296 Grow();
1297
1298 memmove(&m_pItems[nIndex + 1], &m_pItems[nIndex],
1299 (m_nCount - nIndex)*sizeof(char *));
1300
097c080b
VZ
1301 str.GetStringData()->Lock();
1302 m_pItems[nIndex] = (char *)str.c_str();
c801d85f
KB
1303
1304 m_nCount++;
1305}
1306
1307// removes item from array (by index)
1308void wxArrayString::Remove(size_t nIndex)
1309{
9efd3367 1310 wxCHECK_RET( nIndex <= m_nCount, "bad index in wxArrayString::Remove" );
c801d85f
KB
1311
1312 // release our lock
1313 Item(nIndex).GetStringData()->Unlock();
1314
1315 memmove(&m_pItems[nIndex], &m_pItems[nIndex + 1],
1316 (m_nCount - nIndex - 1)*sizeof(char *));
1317 m_nCount--;
1318}
1319
1320// removes item from array (by value)
1321void wxArrayString::Remove(const char *sz)
1322{
1323 int iIndex = Index(sz);
1324
9efd3367
VZ
1325 wxCHECK_RET( iIndex != NOT_FOUND,
1326 "removing inexistent element in wxArrayString::Remove" );
c801d85f
KB
1327
1328 Remove((size_t)iIndex);
1329}
1330
1331// sort array elements using passed comparaison function
1332
c801d85f
KB
1333void wxArrayString::Sort(bool bCase, bool bReverse)
1334{
1335 //@@@@ TO DO
1336 //qsort(m_pItems, m_nCount, sizeof(char *), fCmp);
1337}