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