]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/common/string.cpp
gcc signed/unsigned warning fix
[wxWidgets.git] / src / common / string.cpp
... / ...
CommitLineData
1/////////////////////////////////////////////////////////////////////////////
2// Name: src/common/string.cpp
3// Purpose: wxString class
4// Author: Vadim Zeitlin, Ryan Norton
5// Modified by:
6// Created: 29/01/98
7// RCS-ID: $Id$
8// Copyright: (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
9// (c) 2004 Ryan Norton <wxprojects@comcast.net>
10// Licence: wxWindows licence
11/////////////////////////////////////////////////////////////////////////////
12
13/*
14 * About ref counting:
15 * 1) all empty strings use g_strEmpty, nRefs = -1 (set in Init())
16 * 2) AllocBuffer() sets nRefs to 1, Lock() increments it by one
17 * 3) Unlock() decrements nRefs and frees memory if it goes to 0
18 */
19
20// ===========================================================================
21// headers, declarations, constants
22// ===========================================================================
23
24// For compilers that support precompilation, includes "wx.h".
25#include "wx/wxprec.h"
26
27#ifdef __BORLANDC__
28 #pragma hdrstop
29#endif
30
31#ifndef WX_PRECOMP
32 #include "wx/string.h"
33 #include "wx/intl.h"
34 #include "wx/thread.h"
35#endif
36
37#include <ctype.h>
38
39#ifndef __WXWINCE__
40 #include <errno.h>
41#endif
42
43#include <string.h>
44#include <stdlib.h>
45
46#ifdef __SALFORDC__
47 #include <clib.h>
48#endif
49
50// allocating extra space for each string consumes more memory but speeds up
51// the concatenation operations (nLen is the current string's length)
52// NB: EXTRA_ALLOC must be >= 0!
53#define EXTRA_ALLOC (19 - nLen % 16)
54
55// ---------------------------------------------------------------------------
56// static class variables definition
57// ---------------------------------------------------------------------------
58
59#if !wxUSE_STL
60 //According to STL _must_ be a -1 size_t
61 const size_t wxStringBase::npos = (size_t) -1;
62#endif
63
64// ----------------------------------------------------------------------------
65// static data
66// ----------------------------------------------------------------------------
67
68#if wxUSE_STL
69
70extern const wxChar WXDLLIMPEXP_BASE *wxEmptyString = _T("");
71
72#else
73
74// for an empty string, GetStringData() will return this address: this
75// structure has the same layout as wxStringData and it's data() method will
76// return the empty string (dummy pointer)
77static const struct
78{
79 wxStringData data;
80 wxChar dummy;
81} g_strEmpty = { {-1, 0, 0}, wxT('\0') };
82
83// empty C style string: points to 'string data' byte of g_strEmpty
84extern const wxChar WXDLLIMPEXP_BASE *wxEmptyString = &g_strEmpty.dummy;
85
86#endif
87
88// ----------------------------------------------------------------------------
89// global functions
90// ----------------------------------------------------------------------------
91
92#if wxUSE_STD_IOSTREAM
93
94#include <iostream>
95
96wxSTD ostream& operator<<(wxSTD ostream& os, const wxString& str)
97{
98 return os << str.c_str();
99}
100
101wxSTD ostream& operator<<(wxSTD ostream& os, const wxCStrData& str)
102{
103#if wxUSE_UNICODE && !defined(__BORLANDC__)
104 return os << str.AsWChar();
105#else
106 return os << str.AsChar();
107#endif
108}
109
110#endif // wxUSE_STD_IOSTREAM
111
112// ----------------------------------------------------------------------------
113// private classes
114// ----------------------------------------------------------------------------
115
116// this small class is used to gather statistics for performance tuning
117//#define WXSTRING_STATISTICS
118#ifdef WXSTRING_STATISTICS
119 class Averager
120 {
121 public:
122 Averager(const wxChar *sz) { m_sz = sz; m_nTotal = m_nCount = 0; }
123 ~Averager()
124 { wxPrintf("wxString: average %s = %f\n", m_sz, ((float)m_nTotal)/m_nCount); }
125
126 void Add(size_t n) { m_nTotal += n; m_nCount++; }
127
128 private:
129 size_t m_nCount, m_nTotal;
130 const wxChar *m_sz;
131 } g_averageLength("allocation size"),
132 g_averageSummandLength("summand length"),
133 g_averageConcatHit("hit probability in concat"),
134 g_averageInitialLength("initial string length");
135
136 #define STATISTICS_ADD(av, val) g_average##av.Add(val)
137#else
138 #define STATISTICS_ADD(av, val)
139#endif // WXSTRING_STATISTICS
140
141#if !wxUSE_STL
142
143// ===========================================================================
144// wxStringData class deallocation
145// ===========================================================================
146
147#if defined(__VISUALC__) && defined(_MT) && !defined(_DLL)
148# pragma message (__FILE__ ": building with Multithreaded non DLL runtime has a performance impact on wxString!")
149void wxStringData::Free()
150{
151 free(this);
152}
153#endif
154
155// ===========================================================================
156// wxStringBase
157// ===========================================================================
158
159// takes nLength elements of psz starting at nPos
160void wxStringBase::InitWith(const wxChar *psz, size_t nPos, size_t nLength)
161{
162 Init();
163
164 // if the length is not given, assume the string to be NUL terminated
165 if ( nLength == npos ) {
166 wxASSERT_MSG( nPos <= wxStrlen(psz), _T("index out of bounds") );
167
168 nLength = wxStrlen(psz + nPos);
169 }
170
171 STATISTICS_ADD(InitialLength, nLength);
172
173 if ( nLength > 0 ) {
174 // trailing '\0' is written in AllocBuffer()
175 if ( !AllocBuffer(nLength) ) {
176 wxFAIL_MSG( _T("out of memory in wxStringBase::InitWith") );
177 return;
178 }
179 wxTmemcpy(m_pchData, psz + nPos, nLength);
180 }
181}
182
183// poor man's iterators are "void *" pointers
184wxStringBase::wxStringBase(const void *pStart, const void *pEnd)
185{
186 if ( pEnd >= pStart )
187 {
188 InitWith((const wxChar *)pStart, 0,
189 (const wxChar *)pEnd - (const wxChar *)pStart);
190 }
191 else
192 {
193 wxFAIL_MSG( _T("pStart is not before pEnd") );
194 Init();
195 }
196}
197
198wxStringBase::wxStringBase(size_type n, wxUniChar ch)
199{
200 Init();
201 append(n, ch);
202}
203
204// ---------------------------------------------------------------------------
205// memory allocation
206// ---------------------------------------------------------------------------
207
208// allocates memory needed to store a C string of length nLen
209bool wxStringBase::AllocBuffer(size_t nLen)
210{
211 // allocating 0 sized buffer doesn't make sense, all empty strings should
212 // reuse g_strEmpty
213 wxASSERT( nLen > 0 );
214
215 // make sure that we don't overflow
216 wxASSERT( nLen < (INT_MAX / sizeof(wxChar)) -
217 (sizeof(wxStringData) + EXTRA_ALLOC + 1) );
218
219 STATISTICS_ADD(Length, nLen);
220
221 // allocate memory:
222 // 1) one extra character for '\0' termination
223 // 2) sizeof(wxStringData) for housekeeping info
224 wxStringData* pData = (wxStringData*)
225 malloc(sizeof(wxStringData) + (nLen + EXTRA_ALLOC + 1)*sizeof(wxChar));
226
227 if ( pData == NULL ) {
228 // allocation failures are handled by the caller
229 return false;
230 }
231
232 pData->nRefs = 1;
233 pData->nDataLength = nLen;
234 pData->nAllocLength = nLen + EXTRA_ALLOC;
235 m_pchData = pData->data(); // data starts after wxStringData
236 m_pchData[nLen] = wxT('\0');
237 return true;
238}
239
240// must be called before changing this string
241bool wxStringBase::CopyBeforeWrite()
242{
243 wxStringData* pData = GetStringData();
244
245 if ( pData->IsShared() ) {
246 pData->Unlock(); // memory not freed because shared
247 size_t nLen = pData->nDataLength;
248 if ( !AllocBuffer(nLen) ) {
249 // allocation failures are handled by the caller
250 return false;
251 }
252 wxTmemcpy(m_pchData, pData->data(), nLen);
253 }
254
255 wxASSERT( !GetStringData()->IsShared() ); // we must be the only owner
256
257 return true;
258}
259
260// must be called before replacing contents of this string
261bool wxStringBase::AllocBeforeWrite(size_t nLen)
262{
263 wxASSERT( nLen != 0 ); // doesn't make any sense
264
265 // must not share string and must have enough space
266 wxStringData* pData = GetStringData();
267 if ( pData->IsShared() || pData->IsEmpty() ) {
268 // can't work with old buffer, get new one
269 pData->Unlock();
270 if ( !AllocBuffer(nLen) ) {
271 // allocation failures are handled by the caller
272 return false;
273 }
274 }
275 else {
276 if ( nLen > pData->nAllocLength ) {
277 // realloc the buffer instead of calling malloc() again, this is more
278 // efficient
279 STATISTICS_ADD(Length, nLen);
280
281 nLen += EXTRA_ALLOC;
282
283 pData = (wxStringData*)
284 realloc(pData, sizeof(wxStringData) + (nLen + 1)*sizeof(wxChar));
285
286 if ( pData == NULL ) {
287 // allocation failures are handled by the caller
288 // keep previous data since reallocation failed
289 return false;
290 }
291
292 pData->nAllocLength = nLen;
293 m_pchData = pData->data();
294 }
295 }
296
297 wxASSERT( !GetStringData()->IsShared() ); // we must be the only owner
298
299 // it doesn't really matter what the string length is as it's going to be
300 // overwritten later but, for extra safety, set it to 0 for now as we may
301 // have some junk in m_pchData
302 GetStringData()->nDataLength = 0;
303
304 return true;
305}
306
307wxStringBase& wxStringBase::append(size_t n, wxUniChar ch)
308{
309 size_type len = length();
310
311 if ( !Alloc(len + n) || !CopyBeforeWrite() ) {
312 wxFAIL_MSG( _T("out of memory in wxStringBase::append") );
313 }
314 GetStringData()->nDataLength = len + n;
315 m_pchData[len + n] = '\0';
316 for ( size_t i = 0; i < n; ++i )
317 m_pchData[len + i] = ch;
318 return *this;
319}
320
321void wxStringBase::resize(size_t nSize, wxUniChar ch)
322{
323 size_t len = length();
324
325 if ( nSize < len )
326 {
327 erase(begin() + nSize, end());
328 }
329 else if ( nSize > len )
330 {
331 append(nSize - len, ch);
332 }
333 //else: we have exactly the specified length, nothing to do
334}
335
336// allocate enough memory for nLen characters
337bool wxStringBase::Alloc(size_t nLen)
338{
339 wxStringData *pData = GetStringData();
340 if ( pData->nAllocLength <= nLen ) {
341 if ( pData->IsEmpty() ) {
342 nLen += EXTRA_ALLOC;
343
344 pData = (wxStringData *)
345 malloc(sizeof(wxStringData) + (nLen + 1)*sizeof(wxChar));
346
347 if ( pData == NULL ) {
348 // allocation failure handled by caller
349 return false;
350 }
351
352 pData->nRefs = 1;
353 pData->nDataLength = 0;
354 pData->nAllocLength = nLen;
355 m_pchData = pData->data(); // data starts after wxStringData
356 m_pchData[0u] = wxT('\0');
357 }
358 else if ( pData->IsShared() ) {
359 pData->Unlock(); // memory not freed because shared
360 size_t nOldLen = pData->nDataLength;
361 if ( !AllocBuffer(nLen) ) {
362 // allocation failure handled by caller
363 return false;
364 }
365 // +1 to copy the terminator, too
366 memcpy(m_pchData, pData->data(), (nOldLen+1)*sizeof(wxChar));
367 GetStringData()->nDataLength = nOldLen;
368 }
369 else {
370 nLen += EXTRA_ALLOC;
371
372 pData = (wxStringData *)
373 realloc(pData, sizeof(wxStringData) + (nLen + 1)*sizeof(wxChar));
374
375 if ( pData == NULL ) {
376 // allocation failure handled by caller
377 // keep previous data since reallocation failed
378 return false;
379 }
380
381 // it's not important if the pointer changed or not (the check for this
382 // is not faster than assigning to m_pchData in all cases)
383 pData->nAllocLength = nLen;
384 m_pchData = pData->data();
385 }
386 }
387 //else: we've already got enough
388 return true;
389}
390
391wxStringBase::iterator wxStringBase::begin()
392{
393 if (length() > 0)
394 CopyBeforeWrite();
395 return m_pchData;
396}
397
398wxStringBase::iterator wxStringBase::end()
399{
400 if (length() > 0)
401 CopyBeforeWrite();
402 return m_pchData + length();
403}
404
405wxStringBase::iterator wxStringBase::erase(iterator it)
406{
407 size_type idx = it - begin();
408 erase(idx, 1);
409 return begin() + idx;
410}
411
412wxStringBase& wxStringBase::erase(size_t nStart, size_t nLen)
413{
414 wxASSERT(nStart <= length());
415 size_t strLen = length() - nStart;
416 // delete nLen or up to the end of the string characters
417 nLen = strLen < nLen ? strLen : nLen;
418 wxString strTmp(c_str(), nStart);
419 strTmp.append(c_str() + nStart + nLen, length() - nStart - nLen);
420
421 swap(strTmp);
422 return *this;
423}
424
425wxStringBase& wxStringBase::insert(size_t nPos, const wxChar *sz, size_t n)
426{
427 wxASSERT( nPos <= length() );
428
429 if ( n == npos ) n = wxStrlen(sz);
430 if ( n == 0 ) return *this;
431
432 if ( !Alloc(length() + n) || !CopyBeforeWrite() ) {
433 wxFAIL_MSG( _T("out of memory in wxStringBase::insert") );
434 }
435
436 memmove(m_pchData + nPos + n, m_pchData + nPos,
437 (length() - nPos) * sizeof(wxChar));
438 memcpy(m_pchData + nPos, sz, n * sizeof(wxChar));
439 GetStringData()->nDataLength = length() + n;
440 m_pchData[length()] = '\0';
441
442 return *this;
443}
444
445void wxStringBase::swap(wxStringBase& str)
446{
447 wxChar* tmp = str.m_pchData;
448 str.m_pchData = m_pchData;
449 m_pchData = tmp;
450}
451
452size_t wxStringBase::find(const wxStringBase& str, size_t nStart) const
453{
454 // deal with the special case of empty string first
455 const size_t nLen = length();
456 const size_t nLenOther = str.length();
457
458 if ( !nLenOther )
459 {
460 // empty string is a substring of anything
461 return 0;
462 }
463
464 if ( !nLen )
465 {
466 // the other string is non empty so can't be our substring
467 return npos;
468 }
469
470 wxASSERT( str.GetStringData()->IsValid() );
471 wxASSERT( nStart <= nLen );
472
473 const wxChar * const other = str.c_str();
474
475 // anchor
476 const wxChar* p = (const wxChar*)wxTmemchr(c_str() + nStart,
477 *other,
478 nLen - nStart);
479
480 if ( !p )
481 return npos;
482
483 while ( p - c_str() + nLenOther <= nLen && wxTmemcmp(p, other, nLenOther) )
484 {
485 p++;
486
487 // anchor again
488 p = (const wxChar*)wxTmemchr(p, *other, nLen - (p - c_str()));
489
490 if ( !p )
491 return npos;
492 }
493
494 return p - c_str() + nLenOther <= nLen ? p - c_str() : npos;
495}
496
497size_t wxStringBase::find(const wxChar* sz, size_t nStart, size_t n) const
498{
499 return find(wxStringBase(sz, n), nStart);
500}
501
502size_t wxStringBase::find(wxUniChar ch, size_t nStart) const
503{
504 wxASSERT( nStart <= length() );
505
506 const wxChar *p = (const wxChar*)wxTmemchr(c_str() + nStart, ch, length() - nStart);
507
508 return p == NULL ? npos : p - c_str();
509}
510
511size_t wxStringBase::rfind(const wxStringBase& str, size_t nStart) const
512{
513 wxASSERT( str.GetStringData()->IsValid() );
514 wxASSERT( nStart == npos || nStart <= length() );
515
516 if ( length() >= str.length() )
517 {
518 // avoids a corner case later
519 if ( length() == 0 && str.length() == 0 )
520 return 0;
521
522 // "top" is the point where search starts from
523 size_t top = length() - str.length();
524
525 if ( nStart == npos )
526 nStart = length() - 1;
527 if ( nStart < top )
528 top = nStart;
529
530 const wxChar *cursor = c_str() + top;
531 do
532 {
533 if ( wxTmemcmp(cursor, str.c_str(),
534 str.length()) == 0 )
535 {
536 return cursor - c_str();
537 }
538 } while ( cursor-- > c_str() );
539 }
540
541 return npos;
542}
543
544size_t wxStringBase::rfind(const wxChar* sz, size_t nStart, size_t n) const
545{
546 return rfind(wxStringBase(sz, n), nStart);
547}
548
549size_t wxStringBase::rfind(wxUniChar ch, size_t nStart) const
550{
551 if ( nStart == npos )
552 {
553 nStart = length();
554 }
555 else
556 {
557 wxASSERT( nStart <= length() );
558 }
559
560 const wxChar *actual;
561 for ( actual = c_str() + ( nStart == npos ? length() : nStart + 1 );
562 actual > c_str(); --actual )
563 {
564 if ( *(actual - 1) == ch )
565 return (actual - 1) - c_str();
566 }
567
568 return npos;
569}
570
571size_t wxStringBase::find_first_of(const wxChar* sz, size_t nStart) const
572{
573 wxASSERT(nStart <= length());
574
575 size_t len = wxStrlen(sz);
576
577 size_t i;
578 for(i = nStart; i < this->length(); ++i)
579 {
580 if (wxTmemchr(sz, *(c_str() + i), len))
581 break;
582 }
583
584 if(i == this->length())
585 return npos;
586 else
587 return i;
588}
589
590size_t wxStringBase::find_first_of(const wxChar* sz, size_t nStart,
591 size_t n) const
592{
593 return find_first_of(wxStringBase(sz, n), nStart);
594}
595
596size_t wxStringBase::find_last_of(const wxChar* sz, size_t nStart) const
597{
598 if ( nStart == npos )
599 {
600 nStart = length() - 1;
601 }
602 else
603 {
604 wxASSERT_MSG( nStart <= length(),
605 _T("invalid index in find_last_of()") );
606 }
607
608 size_t len = wxStrlen(sz);
609
610 for ( const wxChar *p = c_str() + nStart; p >= c_str(); --p )
611 {
612 if ( wxTmemchr(sz, *p, len) )
613 return p - c_str();
614 }
615
616 return npos;
617}
618
619size_t wxStringBase::find_last_of(const wxChar* sz, size_t nStart,
620 size_t n) const
621{
622 return find_last_of(wxStringBase(sz, n), nStart);
623}
624
625size_t wxStringBase::find_first_not_of(const wxChar* sz, size_t nStart) const
626{
627 if ( nStart == npos )
628 {
629 nStart = length();
630 }
631 else
632 {
633 wxASSERT( nStart <= length() );
634 }
635
636 size_t len = wxStrlen(sz);
637
638 size_t i;
639 for(i = nStart; i < this->length(); ++i)
640 {
641 if (!wxTmemchr(sz, *(c_str() + i), len))
642 break;
643 }
644
645 if(i == this->length())
646 return npos;
647 else
648 return i;
649}
650
651size_t wxStringBase::find_first_not_of(const wxChar* sz, size_t nStart,
652 size_t n) const
653{
654 return find_first_not_of(wxStringBase(sz, n), nStart);
655}
656
657size_t wxStringBase::find_first_not_of(wxUniChar ch, size_t nStart) const
658{
659 wxASSERT( nStart <= length() );
660
661 for ( const_iterator p = begin() + nStart; (bool)*p; ++p ) // FIXME-DMARS
662 {
663 if ( *p != ch )
664 return p - begin();
665 }
666
667 return npos;
668}
669
670size_t wxStringBase::find_last_not_of(const wxChar* sz, size_t nStart) const
671{
672 if ( nStart == npos )
673 {
674 nStart = length() - 1;
675 }
676 else
677 {
678 wxASSERT( nStart <= length() );
679 }
680
681 size_t len = wxStrlen(sz);
682
683 for ( const wxChar *p = c_str() + nStart; p >= c_str(); --p )
684 {
685 if ( !wxTmemchr(sz, *p,len) )
686 return p - c_str();
687 }
688
689 return npos;
690}
691
692size_t wxStringBase::find_last_not_of(const wxChar* sz, size_t nStart,
693 size_t n) const
694{
695 return find_last_not_of(wxStringBase(sz, n), nStart);
696}
697
698size_t wxStringBase::find_last_not_of(wxUniChar ch, size_t nStart) const
699{
700 if ( nStart == npos )
701 {
702 nStart = length() - 1;
703 }
704 else
705 {
706 wxASSERT( nStart <= length() );
707 }
708
709 for ( const_iterator p = begin() + nStart; p != begin(); --p )
710 {
711 if ( *p != ch )
712 return p - begin();
713 }
714
715 return npos;
716}
717
718wxStringBase& wxStringBase::replace(size_t nStart, size_t nLen,
719 const wxChar *sz)
720{
721 wxASSERT_MSG( nStart <= length(),
722 _T("index out of bounds in wxStringBase::replace") );
723 size_t strLen = length() - nStart;
724 nLen = strLen < nLen ? strLen : nLen;
725
726 wxStringBase strTmp;
727 strTmp.reserve(length()); // micro optimisation to avoid multiple mem allocs
728
729 //This is kind of inefficient, but its pretty good considering...
730 //we don't want to use character access operators here because on STL
731 //it will freeze the reference count of strTmp, which means a deep copy
732 //at the end when swap is called
733 //
734 //Also, we can't use append with the full character pointer and must
735 //do it manually because this string can contain null characters
736 for(size_t i1 = 0; i1 < nStart; ++i1)
737 strTmp.append(1, this->c_str()[i1]);
738
739 //its safe to do the full version here because
740 //sz must be a normal c string
741 strTmp.append(sz);
742
743 for(size_t i2 = nStart + nLen; i2 < length(); ++i2)
744 strTmp.append(1, this->c_str()[i2]);
745
746 swap(strTmp);
747 return *this;
748}
749
750wxStringBase& wxStringBase::replace(size_t nStart, size_t nLen,
751 size_t nCount, wxUniChar ch)
752{
753 return replace(nStart, nLen, wxStringBase(nCount, ch).c_str());
754}
755
756wxStringBase& wxStringBase::replace(size_t nStart, size_t nLen,
757 const wxStringBase& str,
758 size_t nStart2, size_t nLen2)
759{
760 return replace(nStart, nLen, str.substr(nStart2, nLen2));
761}
762
763wxStringBase& wxStringBase::replace(size_t nStart, size_t nLen,
764 const wxChar* sz, size_t nCount)
765{
766 return replace(nStart, nLen, wxStringBase(sz, nCount).c_str());
767}
768
769wxStringBase wxStringBase::substr(size_t nStart, size_t nLen) const
770{
771 if ( nLen == npos )
772 nLen = length() - nStart;
773 return wxStringBase(*this, nStart, nLen);
774}
775
776// assigns one string to another
777wxStringBase& wxStringBase::operator=(const wxStringBase& stringSrc)
778{
779 wxASSERT( stringSrc.GetStringData()->IsValid() );
780
781 // don't copy string over itself
782 if ( m_pchData != stringSrc.m_pchData ) {
783 if ( stringSrc.GetStringData()->IsEmpty() ) {
784 Reinit();
785 }
786 else {
787 // adjust references
788 GetStringData()->Unlock();
789 m_pchData = stringSrc.m_pchData;
790 GetStringData()->Lock();
791 }
792 }
793
794 return *this;
795}
796
797// assigns a single character
798wxStringBase& wxStringBase::operator=(wxUniChar ch)
799{
800 wxChar c(ch);
801 if ( !AssignCopy(1, &c) ) {
802 wxFAIL_MSG( _T("out of memory in wxStringBase::operator=(wxChar)") );
803 }
804 return *this;
805}
806
807// assigns C string
808wxStringBase& wxStringBase::operator=(const wxChar *psz)
809{
810 if ( !AssignCopy(wxStrlen(psz), psz) ) {
811 wxFAIL_MSG( _T("out of memory in wxStringBase::operator=(const wxChar *)") );
812 }
813 return *this;
814}
815
816// helper function: does real copy
817bool wxStringBase::AssignCopy(size_t nSrcLen, const wxChar *pszSrcData)
818{
819 if ( nSrcLen == 0 ) {
820 Reinit();
821 }
822 else {
823 if ( !AllocBeforeWrite(nSrcLen) ) {
824 // allocation failure handled by caller
825 return false;
826 }
827 memcpy(m_pchData, pszSrcData, nSrcLen*sizeof(wxChar));
828 GetStringData()->nDataLength = nSrcLen;
829 m_pchData[nSrcLen] = wxT('\0');
830 }
831 return true;
832}
833
834// ---------------------------------------------------------------------------
835// string concatenation
836// ---------------------------------------------------------------------------
837
838// add something to this string
839bool wxStringBase::ConcatSelf(size_t nSrcLen, const wxChar *pszSrcData,
840 size_t nMaxLen)
841{
842 STATISTICS_ADD(SummandLength, nSrcLen);
843
844 nSrcLen = nSrcLen < nMaxLen ? nSrcLen : nMaxLen;
845
846 // concatenating an empty string is a NOP
847 if ( nSrcLen > 0 ) {
848 wxStringData *pData = GetStringData();
849 size_t nLen = pData->nDataLength;
850 size_t nNewLen = nLen + nSrcLen;
851
852 // alloc new buffer if current is too small
853 if ( pData->IsShared() ) {
854 STATISTICS_ADD(ConcatHit, 0);
855
856 // we have to allocate another buffer
857 wxStringData* pOldData = GetStringData();
858 if ( !AllocBuffer(nNewLen) ) {
859 // allocation failure handled by caller
860 return false;
861 }
862 memcpy(m_pchData, pOldData->data(), nLen*sizeof(wxChar));
863 pOldData->Unlock();
864 }
865 else if ( nNewLen > pData->nAllocLength ) {
866 STATISTICS_ADD(ConcatHit, 0);
867
868 reserve(nNewLen);
869 // we have to grow the buffer
870 if ( capacity() < nNewLen ) {
871 // allocation failure handled by caller
872 return false;
873 }
874 }
875 else {
876 STATISTICS_ADD(ConcatHit, 1);
877
878 // the buffer is already big enough
879 }
880
881 // should be enough space
882 wxASSERT( nNewLen <= GetStringData()->nAllocLength );
883
884 // fast concatenation - all is done in our buffer
885 memcpy(m_pchData + nLen, pszSrcData, nSrcLen*sizeof(wxChar));
886
887 m_pchData[nNewLen] = wxT('\0'); // put terminating '\0'
888 GetStringData()->nDataLength = nNewLen; // and fix the length
889 }
890 //else: the string to append was empty
891 return true;
892}
893
894// ---------------------------------------------------------------------------
895// simple sub-string extraction
896// ---------------------------------------------------------------------------
897
898// helper function: clone the data attached to this string
899bool wxStringBase::AllocCopy(wxString& dest, int nCopyLen, int nCopyIndex) const
900{
901 if ( nCopyLen == 0 ) {
902 dest.Init();
903 }
904 else {
905 if ( !dest.AllocBuffer(nCopyLen) ) {
906 // allocation failure handled by caller
907 return false;
908 }
909 memcpy(dest.m_pchData, m_pchData + nCopyIndex, nCopyLen*sizeof(wxChar));
910 }
911 return true;
912}
913
914#endif // !wxUSE_STL
915
916#if !wxUSE_STL || !defined(HAVE_STD_STRING_COMPARE)
917
918#if !wxUSE_STL
919 #define STRINGCLASS wxStringBase
920#else
921 #define STRINGCLASS wxString
922#endif
923
924static inline int wxDoCmp(const wxChar* s1, size_t l1,
925 const wxChar* s2, size_t l2)
926{
927 if( l1 == l2 )
928 return wxTmemcmp(s1, s2, l1);
929 else if( l1 < l2 )
930 {
931 int ret = wxTmemcmp(s1, s2, l1);
932 return ret == 0 ? -1 : ret;
933 }
934 else
935 {
936 int ret = wxTmemcmp(s1, s2, l2);
937 return ret == 0 ? +1 : ret;
938 }
939}
940
941int STRINGCLASS::compare(const wxStringBase& str) const
942{
943 return ::wxDoCmp(data(), length(), str.data(), str.length());
944}
945
946int STRINGCLASS::compare(size_t nStart, size_t nLen,
947 const wxStringBase& str) const
948{
949 wxASSERT(nStart <= length());
950 size_type strLen = length() - nStart;
951 nLen = strLen < nLen ? strLen : nLen;
952 return ::wxDoCmp(data() + nStart, nLen, str.data(), str.length());
953}
954
955int STRINGCLASS::compare(size_t nStart, size_t nLen,
956 const wxStringBase& str,
957 size_t nStart2, size_t nLen2) const
958{
959 wxASSERT(nStart <= length());
960 wxASSERT(nStart2 <= str.length());
961 size_type strLen = length() - nStart,
962 strLen2 = str.length() - nStart2;
963 nLen = strLen < nLen ? strLen : nLen;
964 nLen2 = strLen2 < nLen2 ? strLen2 : nLen2;
965 return ::wxDoCmp(data() + nStart, nLen, str.data() + nStart2, nLen2);
966}
967
968int STRINGCLASS::compare(const wxChar* sz) const
969{
970 size_t nLen = wxStrlen(sz);
971 return ::wxDoCmp(data(), length(), sz, nLen);
972}
973
974int STRINGCLASS::compare(size_t nStart, size_t nLen,
975 const wxChar* sz, size_t nCount) const
976{
977 wxASSERT(nStart <= length());
978 size_type strLen = length() - nStart;
979 nLen = strLen < nLen ? strLen : nLen;
980 if( nCount == npos )
981 nCount = wxStrlen(sz);
982
983 return ::wxDoCmp(data() + nStart, nLen, sz, nCount);
984}
985
986#undef STRINGCLASS
987
988#endif // !wxUSE_STL || !defined(HAVE_STD_STRING_COMPARE)
989
990// ===========================================================================
991// wxString class core
992// ===========================================================================
993
994// ---------------------------------------------------------------------------
995// construction and conversion
996// ---------------------------------------------------------------------------
997
998#if wxUSE_UNICODE
999
1000// from multibyte string
1001wxString::wxString(const char *psz, const wxMBConv& conv, size_t nLength)
1002{
1003 // anything to do?
1004 if ( psz && nLength != 0 )
1005 {
1006 if ( nLength == npos )
1007 {
1008 nLength = wxNO_LEN;
1009 }
1010
1011 size_t nLenWide;
1012 wxWCharBuffer wbuf = conv.cMB2WC(psz, nLength, &nLenWide);
1013
1014 if ( nLenWide )
1015 assign(wbuf, nLenWide);
1016 }
1017}
1018
1019//Convert wxString in Unicode mode to a multi-byte string
1020const wxCharBuffer wxString::mb_str(const wxMBConv& conv) const
1021{
1022 return conv.cWC2MB(c_str(), length() + 1 /* size, not length */, NULL);
1023}
1024
1025#else // ANSI
1026
1027#if wxUSE_WCHAR_T
1028
1029// from wide string
1030wxString::wxString(const wchar_t *pwz, const wxMBConv& conv, size_t nLength)
1031{
1032 // anything to do?
1033 if ( pwz && nLength != 0 )
1034 {
1035 if ( nLength == npos )
1036 {
1037 nLength = wxNO_LEN;
1038 }
1039
1040 size_t nLenMB;
1041 wxCharBuffer buf = conv.cWC2MB(pwz, nLength, &nLenMB);
1042
1043 if ( nLenMB )
1044 assign(buf, nLenMB);
1045 }
1046}
1047
1048//Converts this string to a wide character string if unicode
1049//mode is not enabled and wxUSE_WCHAR_T is enabled
1050const wxWCharBuffer wxString::wc_str(const wxMBConv& conv) const
1051{
1052 return conv.cMB2WC(c_str(), length() + 1 /* size, not length */, NULL);
1053}
1054
1055#endif // wxUSE_WCHAR_T
1056
1057#endif // Unicode/ANSI
1058
1059// shrink to minimal size (releasing extra memory)
1060bool wxString::Shrink()
1061{
1062 wxString tmp(begin(), end());
1063 swap(tmp);
1064 return tmp.length() == length();
1065}
1066
1067#if !wxUSE_STL
1068// get the pointer to writable buffer of (at least) nLen bytes
1069wxChar *wxString::DoGetWriteBuf(size_t nLen)
1070{
1071 if ( !AllocBeforeWrite(nLen) ) {
1072 // allocation failure handled by caller
1073 return NULL;
1074 }
1075
1076 wxASSERT( GetStringData()->nRefs == 1 );
1077 GetStringData()->Validate(false);
1078
1079 return m_pchData;
1080}
1081
1082// put string back in a reasonable state after GetWriteBuf
1083void wxString::DoUngetWriteBuf()
1084{
1085 DoUngetWriteBuf(wxStrlen(m_pchData));
1086}
1087
1088void wxString::DoUngetWriteBuf(size_t nLen)
1089{
1090 wxStringData * const pData = GetStringData();
1091
1092 wxASSERT_MSG( nLen < pData->nAllocLength, _T("buffer overrun") );
1093
1094 // the strings we store are always NUL-terminated
1095 pData->data()[nLen] = _T('\0');
1096 pData->nDataLength = nLen;
1097 pData->Validate(true);
1098}
1099
1100// deprecated compatibility code:
1101#if WXWIN_COMPATIBILITY_2_8
1102wxChar *wxString::GetWriteBuf(size_t nLen)
1103{
1104 return DoGetWriteBuf(nLen);
1105}
1106
1107void wxString::UngetWriteBuf()
1108{
1109 DoUngetWriteBuf();
1110}
1111
1112void wxString::UngetWriteBuf(size_t nLen)
1113{
1114 DoUngetWriteBuf(nLen);
1115}
1116#endif // WXWIN_COMPATIBILITY_2_8
1117
1118#endif // !wxUSE_STL
1119
1120
1121// ---------------------------------------------------------------------------
1122// data access
1123// ---------------------------------------------------------------------------
1124
1125// all functions are inline in string.h
1126
1127// ---------------------------------------------------------------------------
1128// assignment operators
1129// ---------------------------------------------------------------------------
1130
1131#if !wxUSE_UNICODE
1132
1133// same as 'signed char' variant
1134wxString& wxString::operator=(const unsigned char* psz)
1135{
1136 *this = (const char *)psz;
1137 return *this;
1138}
1139
1140#if wxUSE_WCHAR_T
1141wxString& wxString::operator=(const wchar_t *pwz)
1142{
1143 wxString str(pwz);
1144 swap(str);
1145 return *this;
1146}
1147#endif
1148
1149#endif
1150
1151/*
1152 * concatenation functions come in 5 flavours:
1153 * string + string
1154 * char + string and string + char
1155 * C str + string and string + C str
1156 */
1157
1158wxString operator+(const wxString& str1, const wxString& str2)
1159{
1160#if !wxUSE_STL
1161 wxASSERT( str1.GetStringData()->IsValid() );
1162 wxASSERT( str2.GetStringData()->IsValid() );
1163#endif
1164
1165 wxString s = str1;
1166 s += str2;
1167
1168 return s;
1169}
1170
1171wxString operator+(const wxString& str, wxUniChar ch)
1172{
1173#if !wxUSE_STL
1174 wxASSERT( str.GetStringData()->IsValid() );
1175#endif
1176
1177 wxString s = str;
1178 s += ch;
1179
1180 return s;
1181}
1182
1183wxString operator+(wxUniChar ch, const wxString& str)
1184{
1185#if !wxUSE_STL
1186 wxASSERT( str.GetStringData()->IsValid() );
1187#endif
1188
1189 wxString s = ch;
1190 s += str;
1191
1192 return s;
1193}
1194
1195wxString operator+(const wxString& str, const wxChar *psz)
1196{
1197#if !wxUSE_STL
1198 wxASSERT( str.GetStringData()->IsValid() );
1199#endif
1200
1201 wxString s;
1202 if ( !s.Alloc(wxStrlen(psz) + str.length()) ) {
1203 wxFAIL_MSG( _T("out of memory in wxString::operator+") );
1204 }
1205 s += str;
1206 s += psz;
1207
1208 return s;
1209}
1210
1211wxString operator+(const wxChar *psz, const wxString& str)
1212{
1213#if !wxUSE_STL
1214 wxASSERT( str.GetStringData()->IsValid() );
1215#endif
1216
1217 wxString s;
1218 if ( !s.Alloc(wxStrlen(psz) + str.length()) ) {
1219 wxFAIL_MSG( _T("out of memory in wxString::operator+") );
1220 }
1221 s = psz;
1222 s += str;
1223
1224 return s;
1225}
1226
1227// ===========================================================================
1228// other common string functions
1229// ===========================================================================
1230
1231int wxString::Cmp(const wxString& s) const
1232{
1233 return compare(s);
1234}
1235
1236int wxString::Cmp(const wxChar* psz) const
1237{
1238 return compare(psz);
1239}
1240
1241static inline int wxDoCmpNoCase(const wxChar* s1, size_t l1,
1242 const wxChar* s2, size_t l2)
1243{
1244 size_t i;
1245
1246 if( l1 == l2 )
1247 {
1248 for(i = 0; i < l1; ++i)
1249 {
1250 if(wxTolower(s1[i]) != wxTolower(s2[i]))
1251 break;
1252 }
1253 return i == l1 ? 0 : wxTolower(s1[i]) < wxTolower(s2[i]) ? -1 : 1;
1254 }
1255 else if( l1 < l2 )
1256 {
1257 for(i = 0; i < l1; ++i)
1258 {
1259 if(wxTolower(s1[i]) != wxTolower(s2[i]))
1260 break;
1261 }
1262 return i == l1 ? -1 : wxTolower(s1[i]) < wxTolower(s2[i]) ? -1 : 1;
1263 }
1264 else
1265 {
1266 for(i = 0; i < l2; ++i)
1267 {
1268 if(wxTolower(s1[i]) != wxTolower(s2[i]))
1269 break;
1270 }
1271 return i == l2 ? 1 : wxTolower(s1[i]) < wxTolower(s2[i]) ? -1 : 1;
1272 }
1273}
1274
1275int wxString::CmpNoCase(const wxString& s) const
1276{
1277 return wxDoCmpNoCase(data(), length(), s.data(), s.length());
1278}
1279
1280int wxString::CmpNoCase(const wxChar* psz) const
1281{
1282 int nLen = wxStrlen(psz);
1283
1284 return wxDoCmpNoCase(data(), length(), psz, nLen);
1285}
1286
1287
1288#if wxUSE_UNICODE
1289
1290#ifdef __MWERKS__
1291#ifndef __SCHAR_MAX__
1292#define __SCHAR_MAX__ 127
1293#endif
1294#endif
1295
1296wxString wxString::FromAscii(const char *ascii)
1297{
1298 if (!ascii)
1299 return wxEmptyString;
1300
1301 size_t len = strlen( ascii );
1302 wxString res;
1303
1304 if ( len )
1305 {
1306 wxStringBuffer buf(res, len);
1307
1308 wchar_t *dest = buf;
1309
1310 for ( ;; )
1311 {
1312 if ( (*dest++ = (wchar_t)(unsigned char)*ascii++) == L'\0' )
1313 break;
1314 }
1315 }
1316
1317 return res;
1318}
1319
1320wxString wxString::FromAscii(const char ascii)
1321{
1322 // What do we do with '\0' ?
1323
1324 wxString res;
1325 res += (wchar_t)(unsigned char) ascii;
1326
1327 return res;
1328}
1329
1330const wxCharBuffer wxString::ToAscii() const
1331{
1332 // this will allocate enough space for the terminating NUL too
1333 wxCharBuffer buffer(length());
1334
1335
1336 char *dest = buffer.data();
1337
1338 const wchar_t *pwc = c_str();
1339 for ( ;; )
1340 {
1341 *dest++ = (char)(*pwc > SCHAR_MAX ? wxT('_') : *pwc);
1342
1343 // the output string can't have embedded NULs anyhow, so we can safely
1344 // stop at first of them even if we do have any
1345 if ( !*pwc++ )
1346 break;
1347 }
1348
1349 return buffer;
1350}
1351
1352#endif // Unicode
1353
1354// extract string of length nCount starting at nFirst
1355wxString wxString::Mid(size_t nFirst, size_t nCount) const
1356{
1357 size_t nLen = length();
1358
1359 // default value of nCount is npos and means "till the end"
1360 if ( nCount == npos )
1361 {
1362 nCount = nLen - nFirst;
1363 }
1364
1365 // out-of-bounds requests return sensible things
1366 if ( nFirst + nCount > nLen )
1367 {
1368 nCount = nLen - nFirst;
1369 }
1370
1371 if ( nFirst > nLen )
1372 {
1373 // AllocCopy() will return empty string
1374 return wxEmptyString;
1375 }
1376
1377 wxString dest(*this, nFirst, nCount);
1378 if ( dest.length() != nCount )
1379 {
1380 wxFAIL_MSG( _T("out of memory in wxString::Mid") );
1381 }
1382
1383 return dest;
1384}
1385
1386// check that the string starts with prefix and return the rest of the string
1387// in the provided pointer if it is not NULL, otherwise return false
1388bool wxString::StartsWith(const wxChar *prefix, wxString *rest) const
1389{
1390 wxASSERT_MSG( prefix, _T("invalid parameter in wxString::StartsWith") );
1391
1392 // first check if the beginning of the string matches the prefix: note
1393 // that we don't have to check that we don't run out of this string as
1394 // when we reach the terminating NUL, either prefix string ends too (and
1395 // then it's ok) or we break out of the loop because there is no match
1396 const wxChar *p = c_str();
1397 while ( *prefix )
1398 {
1399 if ( *prefix++ != *p++ )
1400 {
1401 // no match
1402 return false;
1403 }
1404 }
1405
1406 if ( rest )
1407 {
1408 // put the rest of the string into provided pointer
1409 *rest = p;
1410 }
1411
1412 return true;
1413}
1414
1415
1416// check that the string ends with suffix and return the rest of it in the
1417// provided pointer if it is not NULL, otherwise return false
1418bool wxString::EndsWith(const wxChar *suffix, wxString *rest) const
1419{
1420 wxASSERT_MSG( suffix, _T("invalid parameter in wxString::EndssWith") );
1421
1422 int start = length() - wxStrlen(suffix);
1423 if ( start < 0 || wxStrcmp(wx_str() + start, suffix) != 0 )
1424 return false;
1425
1426 if ( rest )
1427 {
1428 // put the rest of the string into provided pointer
1429 rest->assign(*this, 0, start);
1430 }
1431
1432 return true;
1433}
1434
1435
1436// extract nCount last (rightmost) characters
1437wxString wxString::Right(size_t nCount) const
1438{
1439 if ( nCount > length() )
1440 nCount = length();
1441
1442 wxString dest(*this, length() - nCount, nCount);
1443 if ( dest.length() != nCount ) {
1444 wxFAIL_MSG( _T("out of memory in wxString::Right") );
1445 }
1446 return dest;
1447}
1448
1449// get all characters after the last occurence of ch
1450// (returns the whole string if ch not found)
1451wxString wxString::AfterLast(wxUniChar ch) const
1452{
1453 wxString str;
1454 int iPos = Find(ch, true);
1455 if ( iPos == wxNOT_FOUND )
1456 str = *this;
1457 else
1458 str = wx_str() + iPos + 1;
1459
1460 return str;
1461}
1462
1463// extract nCount first (leftmost) characters
1464wxString wxString::Left(size_t nCount) const
1465{
1466 if ( nCount > length() )
1467 nCount = length();
1468
1469 wxString dest(*this, 0, nCount);
1470 if ( dest.length() != nCount ) {
1471 wxFAIL_MSG( _T("out of memory in wxString::Left") );
1472 }
1473 return dest;
1474}
1475
1476// get all characters before the first occurence of ch
1477// (returns the whole string if ch not found)
1478wxString wxString::BeforeFirst(wxUniChar ch) const
1479{
1480 int iPos = Find(ch);
1481 if ( iPos == wxNOT_FOUND ) iPos = length();
1482 return wxString(*this, 0, iPos);
1483}
1484
1485/// get all characters before the last occurence of ch
1486/// (returns empty string if ch not found)
1487wxString wxString::BeforeLast(wxUniChar ch) const
1488{
1489 wxString str;
1490 int iPos = Find(ch, true);
1491 if ( iPos != wxNOT_FOUND && iPos != 0 )
1492 str = wxString(c_str(), iPos);
1493
1494 return str;
1495}
1496
1497/// get all characters after the first occurence of ch
1498/// (returns empty string if ch not found)
1499wxString wxString::AfterFirst(wxUniChar ch) const
1500{
1501 wxString str;
1502 int iPos = Find(ch);
1503 if ( iPos != wxNOT_FOUND )
1504 str = wx_str() + iPos + 1;
1505
1506 return str;
1507}
1508
1509// replace first (or all) occurences of some substring with another one
1510size_t wxString::Replace(const wxChar *szOld,
1511 const wxChar *szNew, bool bReplaceAll)
1512{
1513 // if we tried to replace an empty string we'd enter an infinite loop below
1514 wxCHECK_MSG( szOld && *szOld && szNew, 0,
1515 _T("wxString::Replace(): invalid parameter") );
1516
1517 size_t uiCount = 0; // count of replacements made
1518
1519 size_t uiOldLen = wxStrlen(szOld);
1520 size_t uiNewLen = wxStrlen(szNew);
1521
1522 size_t dwPos = 0;
1523
1524 while ( this->c_str()[dwPos] != wxT('\0') )
1525 {
1526 //DO NOT USE STRSTR HERE
1527 //this string can contain embedded null characters,
1528 //so strstr will function incorrectly
1529 dwPos = find(szOld, dwPos);
1530 if ( dwPos == npos )
1531 break; // exit the loop
1532 else
1533 {
1534 //replace this occurance of the old string with the new one
1535 replace(dwPos, uiOldLen, szNew, uiNewLen);
1536
1537 //move up pos past the string that was replaced
1538 dwPos += uiNewLen;
1539
1540 //increase replace count
1541 ++uiCount;
1542
1543 // stop now?
1544 if ( !bReplaceAll )
1545 break; // exit the loop
1546 }
1547 }
1548
1549 return uiCount;
1550}
1551
1552bool wxString::IsAscii() const
1553{
1554 const wxChar *s = (const wxChar*) *this;
1555 while(*s){
1556 if(!isascii(*s)) return(false);
1557 s++;
1558 }
1559 return(true);
1560}
1561
1562bool wxString::IsWord() const
1563{
1564 const wxChar *s = (const wxChar*) *this;
1565 while(*s){
1566 if(!wxIsalpha(*s)) return(false);
1567 s++;
1568 }
1569 return(true);
1570}
1571
1572bool wxString::IsNumber() const
1573{
1574 const wxChar *s = (const wxChar*) *this;
1575 if (wxStrlen(s))
1576 if ((s[0] == wxT('-')) || (s[0] == wxT('+'))) s++;
1577 while(*s){
1578 if(!wxIsdigit(*s)) return(false);
1579 s++;
1580 }
1581 return(true);
1582}
1583
1584wxString wxString::Strip(stripType w) const
1585{
1586 wxString s = *this;
1587 if ( w & leading ) s.Trim(false);
1588 if ( w & trailing ) s.Trim(true);
1589 return s;
1590}
1591
1592// ---------------------------------------------------------------------------
1593// case conversion
1594// ---------------------------------------------------------------------------
1595
1596wxString& wxString::MakeUpper()
1597{
1598 for ( iterator it = begin(), en = end(); it != en; ++it )
1599 *it = (wxChar)wxToupper(*it);
1600
1601 return *this;
1602}
1603
1604wxString& wxString::MakeLower()
1605{
1606 for ( iterator it = begin(), en = end(); it != en; ++it )
1607 *it = (wxChar)wxTolower(*it);
1608
1609 return *this;
1610}
1611
1612// ---------------------------------------------------------------------------
1613// trimming and padding
1614// ---------------------------------------------------------------------------
1615
1616// some compilers (VC++ 6.0 not to name them) return true for a call to
1617