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