]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/common/string.cpp
include compiler name in plugin DLL name on Windows
[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
103wxSTD istream& operator>>(wxSTD istream& is, wxString& WXUNUSED(str))
104{
105#if 0
106 int w = is.width(0);
107 if ( is.ipfx(0) ) {
108 streambuf *sb = is.rdbuf();
109 str.erase();
110 while ( true ) {
111 int ch = sb->sbumpc ();
112 if ( ch == EOF ) {
113 is.setstate(ios::eofbit);
114 break;
115 }
116 else if ( isspace(ch) ) {
117 sb->sungetc();
118 break;
119 }
120
121 str += ch;
122 if ( --w == 1 )
123 break;
124 }
125 }
126
127 is.isfx();
128 if ( str.length() == 0 )
129 is.setstate(ios::failbit);
130#endif
131 return is;
132}
133
134wxSTD ostream& operator<<(wxSTD ostream& os, const wxString& str)
135{
136 os << str.c_str();
137 return os;
138}
139
140#endif // wxUSE_STD_IOSTREAM
141
142// ----------------------------------------------------------------------------
143// private classes
144// ----------------------------------------------------------------------------
145
146// this small class is used to gather statistics for performance tuning
147//#define WXSTRING_STATISTICS
148#ifdef WXSTRING_STATISTICS
149 class Averager
150 {
151 public:
152 Averager(const wxChar *sz) { m_sz = sz; m_nTotal = m_nCount = 0; }
153 ~Averager()
154 { wxPrintf("wxString: average %s = %f\n", m_sz, ((float)m_nTotal)/m_nCount); }
155
156 void Add(size_t n) { m_nTotal += n; m_nCount++; }
157
158 private:
159 size_t m_nCount, m_nTotal;
160 const wxChar *m_sz;
161 } g_averageLength("allocation size"),
162 g_averageSummandLength("summand length"),
163 g_averageConcatHit("hit probability in concat"),
164 g_averageInitialLength("initial string length");
165
166 #define STATISTICS_ADD(av, val) g_average##av.Add(val)
167#else
168 #define STATISTICS_ADD(av, val)
169#endif // WXSTRING_STATISTICS
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#if !wxUSE_STL
184
185// ===========================================================================
186// wxStringBase
187// ===========================================================================
188
189// takes nLength elements of psz starting at nPos
190void wxStringBase::InitWith(const wxChar *psz, size_t nPos, size_t nLength)
191{
192 Init();
193
194 // if the length is not given, assume the string to be NUL terminated
195 if ( nLength == npos ) {
196 wxASSERT_MSG( nPos <= wxStrlen(psz), _T("index out of bounds") );
197
198 nLength = wxStrlen(psz + nPos);
199 }
200
201 STATISTICS_ADD(InitialLength, nLength);
202
203 if ( nLength > 0 ) {
204 // trailing '\0' is written in AllocBuffer()
205 if ( !AllocBuffer(nLength) ) {
206 wxFAIL_MSG( _T("out of memory in wxStringBase::InitWith") );
207 return;
208 }
209 memcpy(m_pchData, psz + nPos, nLength*sizeof(wxChar));
210 }
211}
212
213// poor man's iterators are "void *" pointers
214wxStringBase::wxStringBase(const void *pStart, const void *pEnd)
215{
216 InitWith((const wxChar *)pStart, 0,
217 (const wxChar *)pEnd - (const wxChar *)pStart);
218}
219
220wxStringBase::wxStringBase(size_type n, wxChar ch)
221{
222 Init();
223 append(n, ch);
224}
225
226// ---------------------------------------------------------------------------
227// memory allocation
228// ---------------------------------------------------------------------------
229
230// allocates memory needed to store a C string of length nLen
231bool wxStringBase::AllocBuffer(size_t nLen)
232{
233 // allocating 0 sized buffer doesn't make sense, all empty strings should
234 // reuse g_strEmpty
235 wxASSERT( nLen > 0 );
236
237 // make sure that we don't overflow
238 wxASSERT( nLen < (INT_MAX / sizeof(wxChar)) -
239 (sizeof(wxStringData) + EXTRA_ALLOC + 1) );
240
241 STATISTICS_ADD(Length, nLen);
242
243 // allocate memory:
244 // 1) one extra character for '\0' termination
245 // 2) sizeof(wxStringData) for housekeeping info
246 wxStringData* pData = (wxStringData*)
247 malloc(sizeof(wxStringData) + (nLen + EXTRA_ALLOC + 1)*sizeof(wxChar));
248
249 if ( pData == NULL ) {
250 // allocation failures are handled by the caller
251 return FALSE;
252 }
253
254 pData->nRefs = 1;
255 pData->nDataLength = nLen;
256 pData->nAllocLength = nLen + EXTRA_ALLOC;
257 m_pchData = pData->data(); // data starts after wxStringData
258 m_pchData[nLen] = wxT('\0');
259 return TRUE;
260}
261
262// must be called before changing this string
263bool wxStringBase::CopyBeforeWrite()
264{
265 wxStringData* pData = GetStringData();
266
267 if ( pData->IsShared() ) {
268 pData->Unlock(); // memory not freed because shared
269 size_t nLen = pData->nDataLength;
270 if ( !AllocBuffer(nLen) ) {
271 // allocation failures are handled by the caller
272 return FALSE;
273 }
274 memcpy(m_pchData, pData->data(), nLen*sizeof(wxChar));
275 }
276
277 wxASSERT( !GetStringData()->IsShared() ); // we must be the only owner
278
279 return TRUE;
280}
281
282// must be called before replacing contents of this string
283bool wxStringBase::AllocBeforeWrite(size_t nLen)
284{
285 wxASSERT( nLen != 0 ); // doesn't make any sense
286
287 // must not share string and must have enough space
288 wxStringData* pData = GetStringData();
289 if ( pData->IsShared() || pData->IsEmpty() ) {
290 // can't work with old buffer, get new one
291 pData->Unlock();
292 if ( !AllocBuffer(nLen) ) {
293 // allocation failures are handled by the caller
294 return FALSE;
295 }
296 }
297 else {
298 if ( nLen > pData->nAllocLength ) {
299 // realloc the buffer instead of calling malloc() again, this is more
300 // efficient
301 STATISTICS_ADD(Length, nLen);
302
303 nLen += EXTRA_ALLOC;
304
305 pData = (wxStringData*)
306 realloc(pData, sizeof(wxStringData) + (nLen + 1)*sizeof(wxChar));
307
308 if ( pData == NULL ) {
309 // allocation failures are handled by the caller
310 // keep previous data since reallocation failed
311 return FALSE;
312 }
313
314 pData->nAllocLength = nLen;
315 m_pchData = pData->data();
316 }
317
318 // now we have enough space, just update the string length
319 pData->nDataLength = nLen;
320 }
321
322 wxASSERT( !GetStringData()->IsShared() ); // we must be the only owner
323
324 return TRUE;
325}
326
327wxStringBase& wxStringBase::append(size_t n, wxChar ch)
328{
329 size_type len = length();
330
331 if ( !CopyBeforeWrite() || !Alloc(len + n) ) {
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 wxStringData* 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 memcpy(m_pchData, pData->data(), nOldLen*sizeof(wxChar));
386 }
387 else {
388 nLen += EXTRA_ALLOC;
389
390 pData = (wxStringData *)
391 realloc(pData, sizeof(wxStringData) + (nLen + 1)*sizeof(wxChar));
392
393 if ( pData == NULL ) {
394 // allocation failure handled by caller
395 // keep previous data since reallocation failed
396 return FALSE;
397 }
398
399 // it's not important if the pointer changed or not (the check for this
400 // is not faster than assigning to m_pchData in all cases)
401 pData->nAllocLength = nLen;
402 m_pchData = pData->data();
403 }
404 }
405 //else: we've already got enough
406 return TRUE;
407}
408
409wxStringBase::iterator wxStringBase::erase(iterator it)
410{
411 size_type idx = it - begin();
412 erase(idx, 1);
413 return begin() + idx;
414}
415
416wxStringBase& wxStringBase::erase(size_t nStart, size_t nLen)
417{
418 wxASSERT(nStart <= length());
419 size_t strLen = length() - nStart;
420 // delete nLen or up to the end of the string characters
421 nLen = strLen < nLen ? strLen : nLen;
422 wxString strTmp(c_str(), nStart);
423 strTmp.append(c_str() + nStart + nLen, length() - nStart - nLen);
424
425 swap(strTmp);
426 return *this;
427}
428
429wxStringBase& wxStringBase::insert(size_t nPos, const wxChar *sz, size_t n)
430{
431 wxASSERT( nPos <= length() );
432
433 if ( n == npos ) n = wxStrlen(sz);
434 if ( n == 0 ) return *this;
435
436 if ( !CopyBeforeWrite() || !Alloc(length() + n) ) {
437 wxFAIL_MSG( _T("out of memory in wxStringBase::insert") );
438 }
439
440 memmove(m_pchData + nPos + n, m_pchData + nPos,
441 (length() - nPos) * sizeof(wxChar));
442 memcpy(m_pchData + nPos, sz, n * sizeof(wxChar));
443 GetStringData()->nDataLength = length() + n;
444 m_pchData[length()] = '\0';
445
446 return *this;
447}
448
449void wxStringBase::swap(wxStringBase& str)
450{
451 wxChar* tmp = str.m_pchData;
452 str.m_pchData = m_pchData;
453 m_pchData = tmp;
454}
455
456size_t wxStringBase::find(const wxStringBase& str, size_t nStart) const
457{
458 wxASSERT( str.GetStringData()->IsValid() );
459 wxASSERT( nStart <= length() );
460
461 const wxChar *p = wxStrstr(c_str() + nStart, str.c_str());
462
463 return p == NULL ? npos : p - c_str();
464}
465
466size_t wxStringBase::find(const wxChar* sz, size_t nStart, size_t n) const
467{
468 return find(wxStringBase(sz, n), nStart);
469}
470
471size_t wxStringBase::find(wxChar ch, size_t nStart) const
472{
473 wxASSERT( nStart <= length() );
474
475 const wxChar *p = wxStrchr(c_str() + nStart, ch);
476
477 return p == NULL ? npos : p - c_str();
478}
479
480size_t wxStringBase::rfind(const wxStringBase& str, size_t nStart) const
481{
482 wxASSERT( str.GetStringData()->IsValid() );
483 wxASSERT( nStart == npos || nStart <= length() );
484
485 // TODO could be made much quicker than that
486 const wxChar *p = c_str() + (nStart == npos ? length() : nStart);
487 while ( p >= c_str() + str.length() ) {
488 if ( wxStrncmp(p - str.length(), str.c_str(), str.length()) == 0 )
489 return p - str.length() - c_str();
490 p--;
491 }
492
493 return npos;
494}
495
496size_t wxStringBase::rfind(const wxChar* sz, size_t nStart, size_t n) const
497{
498 return rfind(wxStringBase(sz, n), nStart);
499}
500
501size_t wxStringBase::rfind(wxChar ch, size_t nStart) const
502{
503 if ( nStart == npos )
504 {
505 nStart = length();
506 }
507 else
508 {
509 wxASSERT( nStart <= length() );
510 }
511
512 const wxChar *p = wxStrrchr(c_str(), ch);
513
514 if ( p == NULL )
515 return npos;
516
517 size_t result = p - c_str();
518 return ( result > nStart ) ? npos : result;
519}
520
521size_t wxStringBase::find_first_of(const wxChar* sz, size_t nStart) const
522{
523 const wxChar *start = c_str() + nStart;
524 const wxChar *firstOf = wxStrpbrk(start, sz);
525 if ( firstOf )
526 return firstOf - c_str();
527 else
528 return npos;
529}
530
531size_t wxStringBase::find_last_of(const wxChar* sz, size_t nStart) const
532{
533 if ( nStart == npos )
534 {
535 nStart = length();
536 }
537 else
538 {
539 wxASSERT_MSG( nStart <= length(),
540 _T("invalid index in find_last_of()") );
541 }
542
543 for ( const wxChar *p = c_str() + nStart - 1; p >= c_str(); p-- )
544 {
545 if ( wxStrchr(sz, *p) )
546 return p - c_str();
547 }
548
549 return npos;
550}
551
552size_t wxStringBase::find_first_not_of(const wxChar* sz, size_t nStart) const
553{
554 if ( nStart == npos )
555 {
556 nStart = length();
557 }
558 else
559 {
560 wxASSERT( nStart <= length() );
561 }
562
563 size_t nAccept = wxStrspn(c_str() + nStart, sz);
564 if ( nAccept >= length() - nStart )
565 return npos;
566 else
567 return nAccept;
568}
569
570size_t wxStringBase::find_first_not_of(wxChar ch, size_t nStart) const
571{
572 wxASSERT( nStart <= length() );
573
574 for ( const wxChar *p = c_str() + nStart; *p; p++ )
575 {
576 if ( *p != ch )
577 return p - c_str();
578 }
579
580 return npos;
581}
582
583size_t wxStringBase::find_last_not_of(const wxChar* sz, size_t nStart) const
584{
585 if ( nStart == npos )
586 {
587 nStart = length();
588 }
589 else
590 {
591 wxASSERT( nStart <= length() );
592 }
593
594 for ( const wxChar *p = c_str() + nStart - 1; p >= c_str(); p-- )
595 {
596 if ( !wxStrchr(sz, *p) )
597 return p - c_str();
598 }
599
600 return npos;
601}
602
603size_t wxStringBase::find_last_not_of(wxChar ch, size_t nStart) const
604{
605 if ( nStart == npos )
606 {
607 nStart = length();
608 }
609 else
610 {
611 wxASSERT( nStart <= length() );
612 }
613
614 for ( const wxChar *p = c_str() + nStart - 1; p >= c_str(); p-- )
615 {
616 if ( *p != ch )
617 return p - c_str();
618 }
619
620 return npos;
621}
622
623wxStringBase& wxStringBase::replace(size_t nStart, size_t nLen,
624 const wxChar *sz)
625{
626 wxASSERT_MSG( nStart <= length(),
627 _T("index out of bounds in wxStringBase::replace") );
628 size_t strLen = length() - nStart;
629 nLen = strLen < nLen ? strLen : nLen;
630
631 wxStringBase strTmp;
632 strTmp.reserve(length()); // micro optimisation to avoid multiple mem allocs
633
634 if ( nStart != 0 )
635 strTmp.append(c_str(), nStart);
636 strTmp.append(sz);
637 strTmp.append(c_str() + nStart + nLen);
638
639 swap(strTmp);
640 return *this;
641}
642
643wxStringBase& wxStringBase::replace(size_t nStart, size_t nLen,
644 size_t nCount, wxChar ch)
645{
646 return replace(nStart, nLen, wxStringBase(ch, nCount).c_str());
647}
648
649wxStringBase& wxStringBase::replace(size_t nStart, size_t nLen,
650 const wxStringBase& str,
651 size_t nStart2, size_t nLen2)
652{
653 return replace(nStart, nLen, str.substr(nStart2, nLen2));
654}
655
656wxStringBase& wxStringBase::replace(size_t nStart, size_t nLen,
657 const wxChar* sz, size_t nCount)
658{
659 return replace(nStart, nLen, wxStringBase(sz, nCount).c_str());
660}
661
662wxStringBase wxStringBase::substr(size_t nStart, size_t nLen) const
663{
664 if ( nLen == npos )
665 nLen = length() - nStart;
666 return wxStringBase(*this, nStart, nLen);
667}
668
669// assigns one string to another
670wxStringBase& wxStringBase::operator=(const wxStringBase& stringSrc)
671{
672 wxASSERT( stringSrc.GetStringData()->IsValid() );
673
674 // don't copy string over itself
675 if ( m_pchData != stringSrc.m_pchData ) {
676 if ( stringSrc.GetStringData()->IsEmpty() ) {
677 Reinit();
678 }
679 else {
680 // adjust references
681 GetStringData()->Unlock();
682 m_pchData = stringSrc.m_pchData;
683 GetStringData()->Lock();
684 }
685 }
686
687 return *this;
688}
689
690// assigns a single character
691wxStringBase& wxStringBase::operator=(wxChar ch)
692{
693 if ( !AssignCopy(1, &ch) ) {
694 wxFAIL_MSG( _T("out of memory in wxStringBase::operator=(wxChar)") );
695 }
696 return *this;
697}
698
699// assigns C string
700wxStringBase& wxStringBase::operator=(const wxChar *psz)
701{
702 if ( !AssignCopy(wxStrlen(psz), psz) ) {
703 wxFAIL_MSG( _T("out of memory in wxStringBase::operator=(const wxChar *)") );
704 }
705 return *this;
706}
707
708// helper function: does real copy
709bool wxStringBase::AssignCopy(size_t nSrcLen, const wxChar *pszSrcData)
710{
711 if ( nSrcLen == 0 ) {
712 Reinit();
713 }
714 else {
715 if ( !AllocBeforeWrite(nSrcLen) ) {
716 // allocation failure handled by caller
717 return FALSE;
718 }
719 memcpy(m_pchData, pszSrcData, nSrcLen*sizeof(wxChar));
720 GetStringData()->nDataLength = nSrcLen;
721 m_pchData[nSrcLen] = wxT('\0');
722 }
723 return TRUE;
724}
725
726// ---------------------------------------------------------------------------
727// string concatenation
728// ---------------------------------------------------------------------------
729
730// add something to this string
731bool wxStringBase::ConcatSelf(size_t nSrcLen, const wxChar *pszSrcData,
732 size_t nMaxLen)
733{
734 STATISTICS_ADD(SummandLength, nSrcLen);
735
736 nSrcLen = nSrcLen < nMaxLen ? nSrcLen : nMaxLen;
737
738 // concatenating an empty string is a NOP
739 if ( nSrcLen > 0 ) {
740 wxStringData *pData = GetStringData();
741 size_t nLen = pData->nDataLength;
742 size_t nNewLen = nLen + nSrcLen;
743
744 // alloc new buffer if current is too small
745 if ( pData->IsShared() ) {
746 STATISTICS_ADD(ConcatHit, 0);
747
748 // we have to allocate another buffer
749 wxStringData* pOldData = GetStringData();
750 if ( !AllocBuffer(nNewLen) ) {
751 // allocation failure handled by caller
752 return FALSE;
753 }
754 memcpy(m_pchData, pOldData->data(), nLen*sizeof(wxChar));
755 pOldData->Unlock();
756 }
757 else if ( nNewLen > pData->nAllocLength ) {
758 STATISTICS_ADD(ConcatHit, 0);
759
760 reserve(nNewLen);
761 // we have to grow the buffer
762 if ( capacity() < nNewLen ) {
763 // allocation failure handled by caller
764 return FALSE;
765 }
766 }
767 else {
768 STATISTICS_ADD(ConcatHit, 1);
769
770 // the buffer is already big enough
771 }
772
773 // should be enough space
774 wxASSERT( nNewLen <= GetStringData()->nAllocLength );
775
776 // fast concatenation - all is done in our buffer
777 memcpy(m_pchData + nLen, pszSrcData, nSrcLen*sizeof(wxChar));
778
779 m_pchData[nNewLen] = wxT('\0'); // put terminating '\0'
780 GetStringData()->nDataLength = nNewLen; // and fix the length
781 }
782 //else: the string to append was empty
783 return TRUE;
784}
785
786// ---------------------------------------------------------------------------
787// simple sub-string extraction
788// ---------------------------------------------------------------------------
789
790// helper function: clone the data attached to this string
791bool wxStringBase::AllocCopy(wxString& dest, int nCopyLen, int nCopyIndex) const
792{
793 if ( nCopyLen == 0 ) {
794 dest.Init();
795 }
796 else {
797 if ( !dest.AllocBuffer(nCopyLen) ) {
798 // allocation failure handled by caller
799 return FALSE;
800 }
801 memcpy(dest.m_pchData, m_pchData + nCopyIndex, nCopyLen*sizeof(wxChar));
802 }
803 return TRUE;
804}
805
806#endif // !wxUSE_STL
807
808#if !wxUSE_STL || !defined(HAVE_STD_STRING_COMPARE)
809
810#if !wxUSE_STL
811 #define STRINGCLASS wxStringBase
812#else
813 #define STRINGCLASS wxString
814#endif
815
816static inline int wxDoCmp(const wxChar* s1, size_t l1,
817 const wxChar* s2, size_t l2)
818{
819 if( l1 == l2 )
820 return wxStrncmp(s1, s2, l1);
821 else if( l1 < l2 )
822 {
823 int ret = wxStrncmp(s1, s2, l1);
824 return ret == 0 ? -1 : ret;
825 }
826 else if( l1 > l2 )
827 {
828 int ret = wxStrncmp(s1, s2, l2);
829 return ret == 0 ? +1 : ret;
830 }
831
832 wxFAIL; // must never get there
833 return 0; // quiet compilers
834}
835
836#if wxUSE_STL
837
838int STRINGCLASS::compare(const wxStringBase& str) const
839{
840 return ::wxDoCmp(data(), length(), str.data(), str.length());
841}
842
843#endif
844
845int STRINGCLASS::compare(size_t nStart, size_t nLen,
846 const wxStringBase& str) const
847{
848 wxASSERT(nStart <= length());
849 size_type strLen = length() - nStart;
850 nLen = strLen < nLen ? strLen : nLen;
851 return ::wxDoCmp(data() + nStart, nLen, str.data(), str.length());
852}
853
854int STRINGCLASS::compare(size_t nStart, size_t nLen,
855 const wxStringBase& str,
856 size_t nStart2, size_t nLen2) const
857{
858 wxASSERT(nStart <= length());
859 wxASSERT(nStart2 <= str.length());
860 size_type strLen = length() - nStart,
861 strLen2 = str.length() - nStart2;
862 nLen = strLen < nLen ? strLen : nLen;
863 nLen2 = strLen2 < nLen2 ? strLen2 : nLen2;
864 return ::wxDoCmp(data() + nStart, nLen, str.data() + nStart2, nLen2);
865}
866
867#if wxUSE_STL
868
869int STRINGCLASS::compare(const wxChar* sz) const
870{
871 size_t nLen = wxStrlen(sz);
872 return ::wxDoCmp(data(), length(), sz, nLen);
873}
874
875#endif
876
877int STRINGCLASS::compare(size_t nStart, size_t nLen,
878 const wxChar* sz, size_t nCount) const
879{
880 wxASSERT(nStart <= length());
881 size_type strLen = length() - nStart;
882 nLen = strLen < nLen ? strLen : nLen;
883 if( nCount == npos )
884 nCount = wxStrlen(sz);
885
886 return ::wxDoCmp(data() + nStart, nLen, sz, nCount);
887}
888
889#undef STRINGCLASS
890
891#endif // !wxUSE_STL || !defined(HAVE_STD_STRING_COMPARE)
892
893// ===========================================================================
894// wxString class core
895// ===========================================================================
896
897// ---------------------------------------------------------------------------
898// construction
899// ---------------------------------------------------------------------------
900
901#if wxUSE_UNICODE
902
903// from multibyte string
904wxString::wxString(const char *psz, wxMBConv& conv, size_t nLength)
905{
906 // first get the size of the buffer we need
907 size_t nLen;
908 if ( psz )
909 {
910 // calculate the needed size ourselves or use the provided one
911 nLen = nLength == npos ? conv.MB2WC(NULL, psz, 0) : nLength;
912 }
913 else
914 {
915 // nothing to convert
916 nLen = 0;
917 }
918
919 // anything to do?
920 if ( (nLen != 0) && (nLen != (size_t)-1) )
921 {
922 if ( !Alloc(nLen) )
923 {
924 wxFAIL_MSG( _T("out of memory in wxString::wxString") );
925 }
926 else
927 {
928 wxWCharBuffer buf(nLen + 1);
929 // MB2WC wants the buffer size, not the string length hence +1
930 nLen = conv.MB2WC(buf.data(), psz, nLen + 1);
931
932 if ( nLen != (size_t)-1 )
933 {
934 // initialized ok, set the real length as nLength specified by
935 // the caller could be greater than the real string length
936 assign(buf.data(), nLen);
937 return;
938 }
939 //else: the conversion failed -- leave the string empty (what else?)
940 }
941 }
942}
943
944#else // ANSI
945
946#if wxUSE_WCHAR_T
947// from wide string
948wxString::wxString(const wchar_t *pwz, wxMBConv& conv, size_t nLength)
949{
950 // first get the size of the buffer we need
951 size_t nLen;
952 if ( pwz )
953 {
954 // calculate the needed size ourselves or use the provided one
955 nLen = nLength == npos ? conv.WC2MB(NULL, pwz, 0) : nLength;
956 }
957 else
958 {
959 // nothing to convert
960 nLen = 0;
961 }
962
963 // anything to do?
964 if ( (nLen != 0) && (nLen != (size_t)-1) )
965 {
966 if ( !Alloc(nLen) )
967 {
968 wxFAIL_MSG( _T("out of memory in wxString::wxString") );
969 }
970 else
971 {
972 wxCharBuffer buf(nLen);
973 // WC2MB wants the buffer size, not the string length
974 if ( conv.WC2MB(buf.data(), pwz, nLen + 1) != (size_t)-1 )
975 {
976 // initialized ok
977 assign(buf.data(), nLen);
978 return;
979 }
980 //else: the conversion failed -- leave the string empty (what else?)
981 }
982 }
983
984 // leave empty
985}
986#endif // wxUSE_WCHAR_T
987
988#endif // Unicode/ANSI
989
990// shrink to minimal size (releasing extra memory)
991bool wxString::Shrink()
992{
993 wxString tmp(begin(), end());
994 swap(tmp);
995 return tmp.length() == length();
996}
997
998#if !wxUSE_STL
999// get the pointer to writable buffer of (at least) nLen bytes
1000wxChar *wxString::GetWriteBuf(size_t nLen)
1001{
1002 if ( !AllocBeforeWrite(nLen) ) {
1003 // allocation failure handled by caller
1004 return NULL;
1005 }
1006
1007 wxASSERT( GetStringData()->nRefs == 1 );
1008 GetStringData()->Validate(FALSE);
1009
1010 return m_pchData;
1011}
1012
1013// put string back in a reasonable state after GetWriteBuf
1014void wxString::UngetWriteBuf()
1015{
1016 GetStringData()->nDataLength = wxStrlen(m_pchData);
1017 GetStringData()->Validate(TRUE);
1018}
1019
1020void wxString::UngetWriteBuf(size_t nLen)
1021{
1022 GetStringData()->nDataLength = nLen;
1023 GetStringData()->Validate(TRUE);
1024}
1025#endif
1026
1027// ---------------------------------------------------------------------------
1028// data access
1029// ---------------------------------------------------------------------------
1030
1031// all functions are inline in string.h
1032
1033// ---------------------------------------------------------------------------
1034// assignment operators
1035// ---------------------------------------------------------------------------
1036
1037#if !wxUSE_UNICODE
1038
1039// same as 'signed char' variant
1040wxString& wxString::operator=(const unsigned char* psz)
1041{
1042 *this = (const char *)psz;
1043 return *this;
1044}
1045
1046#if wxUSE_WCHAR_T
1047wxString& wxString::operator=(const wchar_t *pwz)
1048{
1049 wxString str(pwz);
1050 swap(str);
1051 return *this;
1052}
1053#endif
1054
1055#endif
1056
1057/*
1058 * concatenation functions come in 5 flavours:
1059 * string + string
1060 * char + string and string + char
1061 * C str + string and string + C str
1062 */
1063
1064wxString operator+(const wxString& str1, const wxString& str2)
1065{
1066#if !wxUSE_STL
1067 wxASSERT( str1.GetStringData()->IsValid() );
1068 wxASSERT( str2.GetStringData()->IsValid() );
1069#endif
1070
1071 wxString s = str1;
1072 s += str2;
1073
1074 return s;
1075}
1076
1077wxString operator+(const wxString& str, wxChar ch)
1078{
1079#if !wxUSE_STL
1080 wxASSERT( str.GetStringData()->IsValid() );
1081#endif
1082
1083 wxString s = str;
1084 s += ch;
1085
1086 return s;
1087}
1088
1089wxString operator+(wxChar ch, const wxString& str)
1090{
1091#if !wxUSE_STL
1092 wxASSERT( str.GetStringData()->IsValid() );
1093#endif
1094
1095 wxString s = ch;
1096 s += str;
1097
1098 return s;
1099}
1100
1101wxString operator+(const wxString& str, const wxChar *psz)
1102{
1103#if !wxUSE_STL
1104 wxASSERT( str.GetStringData()->IsValid() );
1105#endif
1106
1107 wxString s;
1108 if ( !s.Alloc(wxStrlen(psz) + str.Len()) ) {
1109 wxFAIL_MSG( _T("out of memory in wxString::operator+") );
1110 }
1111 s = str;
1112 s += psz;
1113
1114 return s;
1115}
1116
1117wxString operator+(const wxChar *psz, const wxString& str)
1118{
1119#if !wxUSE_STL
1120 wxASSERT( str.GetStringData()->IsValid() );
1121#endif
1122
1123 wxString s;
1124 if ( !s.Alloc(wxStrlen(psz) + str.Len()) ) {
1125 wxFAIL_MSG( _T("out of memory in wxString::operator+") );
1126 }
1127 s = psz;
1128 s += str;
1129
1130 return s;
1131}
1132
1133// ===========================================================================
1134// other common string functions
1135// ===========================================================================
1136
1137#if wxUSE_UNICODE
1138
1139wxString wxString::FromAscii(const char *ascii)
1140{
1141 if (!ascii)
1142 return wxEmptyString;
1143
1144 size_t len = strlen( ascii );
1145 wxString res;
1146
1147 if ( len )
1148 {
1149 wxStringBuffer buf(res, len);
1150
1151 wchar_t *dest = buf;
1152
1153 for ( ;; )
1154 {
1155 if ( (*dest++ = (wchar_t)(unsigned char)*ascii++) == L'\0' )
1156 break;
1157 }
1158 }
1159
1160 return res;
1161}
1162
1163wxString wxString::FromAscii(const char ascii)
1164{
1165 // What do we do with '\0' ?
1166
1167 wxString res;
1168 res += (wchar_t)(unsigned char) ascii;
1169
1170 return res;
1171}
1172
1173const wxCharBuffer wxString::ToAscii() const
1174{
1175 // this will allocate enough space for the terminating NUL too
1176 wxCharBuffer buffer(length());
1177
1178 signed char *dest = (signed char *)buffer.data();
1179
1180 const wchar_t *pwc = c_str();
1181 for ( ;; )
1182 {
1183 *dest++ = *pwc > SCHAR_MAX ? '_' : *pwc;
1184
1185 // the output string can't have embedded NULs anyhow, so we can safely
1186 // stop at first of them even if we do have any
1187 if ( !*pwc++ )
1188 break;
1189 }
1190
1191 return buffer;
1192}
1193
1194#endif // Unicode
1195
1196// extract string of length nCount starting at nFirst
1197wxString wxString::Mid(size_t nFirst, size_t nCount) const
1198{
1199 size_t nLen = length();
1200
1201 // default value of nCount is npos and means "till the end"
1202 if ( nCount == npos )
1203 {
1204 nCount = nLen - nFirst;
1205 }
1206
1207 // out-of-bounds requests return sensible things
1208 if ( nFirst + nCount > nLen )
1209 {
1210 nCount = nLen - nFirst;
1211 }
1212
1213 if ( nFirst > nLen )
1214 {
1215 // AllocCopy() will return empty string
1216 nCount = 0;
1217 }
1218
1219 wxString dest(*this, nFirst, nCount);
1220 if ( dest.length() != nCount ) {
1221 wxFAIL_MSG( _T("out of memory in wxString::Mid") );
1222 }
1223
1224 return dest;
1225}
1226
1227// check that the string starts with prefix and return the rest of the string
1228// in the provided pointer if it is not NULL, otherwise return FALSE
1229bool wxString::StartsWith(const wxChar *prefix, wxString *rest) const
1230{
1231 wxASSERT_MSG( prefix, _T("invalid parameter in wxString::StartsWith") );
1232
1233 // first check if the beginning of the string matches the prefix: note
1234 // that we don't have to check that we don't run out of this string as
1235 // when we reach the terminating NUL, either prefix string ends too (and
1236 // then it's ok) or we break out of the loop because there is no match
1237 const wxChar *p = c_str();
1238 while ( *prefix )
1239 {
1240 if ( *prefix++ != *p++ )
1241 {
1242 // no match
1243 return FALSE;
1244 }
1245 }
1246
1247 if ( rest )
1248 {
1249 // put the rest of the string into provided pointer
1250 *rest = p;
1251 }
1252
1253 return TRUE;
1254}
1255
1256// extract nCount last (rightmost) characters
1257wxString wxString::Right(size_t nCount) const
1258{
1259 if ( nCount > length() )
1260 nCount = length();
1261
1262 wxString dest(*this, length() - nCount, nCount);
1263 if ( dest.length() != nCount ) {
1264 wxFAIL_MSG( _T("out of memory in wxString::Right") );
1265 }
1266 return dest;
1267}
1268
1269// get all characters after the last occurence of ch
1270// (returns the whole string if ch not found)
1271wxString wxString::AfterLast(wxChar ch) const
1272{
1273 wxString str;
1274 int iPos = Find(ch, TRUE);
1275 if ( iPos == wxNOT_FOUND )
1276 str = *this;
1277 else
1278 str = c_str() + iPos + 1;
1279
1280 return str;
1281}
1282
1283// extract nCount first (leftmost) characters
1284wxString wxString::Left(size_t nCount) const
1285{
1286 if ( nCount > length() )
1287 nCount = length();
1288
1289 wxString dest(*this, 0, nCount);
1290 if ( dest.length() != nCount ) {
1291 wxFAIL_MSG( _T("out of memory in wxString::Left") );
1292 }
1293 return dest;
1294}
1295
1296// get all characters before the first occurence of ch
1297// (returns the whole string if ch not found)
1298wxString wxString::BeforeFirst(wxChar ch) const
1299{
1300 int iPos = Find(ch);
1301 if ( iPos == wxNOT_FOUND ) iPos = length();
1302 return wxString(*this, 0, iPos);
1303}
1304
1305/// get all characters before the last occurence of ch
1306/// (returns empty string if ch not found)
1307wxString wxString::BeforeLast(wxChar ch) const
1308{
1309 wxString str;
1310 int iPos = Find(ch, TRUE);
1311 if ( iPos != wxNOT_FOUND && iPos != 0 )
1312 str = wxString(c_str(), iPos);
1313
1314 return str;
1315}
1316
1317/// get all characters after the first occurence of ch
1318/// (returns empty string if ch not found)
1319wxString wxString::AfterFirst(wxChar ch) const
1320{
1321 wxString str;
1322 int iPos = Find(ch);
1323 if ( iPos != wxNOT_FOUND )
1324 str = c_str() + iPos + 1;
1325
1326 return str;
1327}
1328
1329// replace first (or all) occurences of some substring with another one
1330size_t
1331wxString::Replace(const wxChar *szOld, const wxChar *szNew, bool bReplaceAll)
1332{
1333 // if we tried to replace an empty string we'd enter an infinite loop below
1334 wxCHECK_MSG( szOld && *szOld && szNew, 0,
1335 _T("wxString::Replace(): invalid parameter") );
1336
1337 size_t uiCount = 0; // count of replacements made
1338
1339 size_t uiOldLen = wxStrlen(szOld);
1340
1341 wxString strTemp;
1342 const wxChar *pCurrent = c_str();
1343 const wxChar *pSubstr;
1344 while ( *pCurrent != wxT('\0') ) {
1345 pSubstr = wxStrstr(pCurrent, szOld);
1346 if ( pSubstr == NULL ) {
1347 // strTemp is unused if no replacements were made, so avoid the copy
1348 if ( uiCount == 0 )
1349 return 0;
1350
1351 strTemp += pCurrent; // copy the rest
1352 break; // exit the loop
1353 }
1354 else {
1355 // take chars before match
1356 size_type len = strTemp.length();
1357 strTemp.append(pCurrent, pSubstr - pCurrent);
1358 if ( strTemp.length() != (size_t)(len + pSubstr - pCurrent) ) {
1359 wxFAIL_MSG( _T("out of memory in wxString::Replace") );
1360 return 0;
1361 }
1362 strTemp += szNew;
1363 pCurrent = pSubstr + uiOldLen; // restart after match
1364
1365 uiCount++;
1366
1367 // stop now?
1368 if ( !bReplaceAll ) {
1369 strTemp += pCurrent; // copy the rest
1370 break; // exit the loop
1371 }
1372 }
1373 }
1374
1375 // only done if there were replacements, otherwise would have returned above
1376 swap(strTemp);
1377
1378 return uiCount;
1379}
1380
1381bool wxString::IsAscii() const
1382{
1383 const wxChar *s = (const wxChar*) *this;
1384 while(*s){
1385 if(!isascii(*s)) return(FALSE);
1386 s++;
1387 }
1388 return(TRUE);
1389}
1390
1391bool wxString::IsWord() const
1392{
1393 const wxChar *s = (const wxChar*) *this;
1394 while(*s){
1395 if(!wxIsalpha(*s)) return(FALSE);
1396 s++;
1397 }
1398 return(TRUE);
1399}
1400
1401bool wxString::IsNumber() const
1402{
1403 const wxChar *s = (const wxChar*) *this;
1404 if (wxStrlen(s))
1405 if ((s[0] == '-') || (s[0] == '+')) s++;
1406 while(*s){
1407 if(!wxIsdigit(*s)) return(FALSE);
1408 s++;
1409 }
1410 return(TRUE);
1411}
1412
1413wxString wxString::Strip(stripType w) const
1414{
1415 wxString s = *this;
1416 if ( w & leading ) s.Trim(FALSE);
1417 if ( w & trailing ) s.Trim(TRUE);
1418 return s;
1419}
1420
1421// ---------------------------------------------------------------------------
1422// case conversion
1423// ---------------------------------------------------------------------------
1424
1425wxString& wxString::MakeUpper()
1426{
1427 for ( iterator it = begin(), en = end(); it != en; ++it )
1428 *it = (wxChar)wxToupper(*it);
1429
1430 return *this;
1431}
1432
1433wxString& wxString::MakeLower()
1434{
1435 for ( iterator it = begin(), en = end(); it != en; ++it )
1436 *it = (wxChar)wxTolower(*it);
1437
1438 return *this;
1439}
1440
1441// ---------------------------------------------------------------------------
1442// trimming and padding
1443// ---------------------------------------------------------------------------
1444
1445// some compilers (VC++ 6.0 not to name them) return TRUE for a call to
1446