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