]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/common/string.cpp
Fix crash when using a proxy (m_protocol already gets cleaned up via CleanData())
[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#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
14 #pragma implementation "string.h"
15#endif
16
17/*
18 * About ref counting:
19 * 1) all empty strings use g_strEmpty, nRefs = -1 (set in Init())
20 * 2) AllocBuffer() sets nRefs to 1, Lock() increments it by one
21 * 3) Unlock() decrements nRefs and frees memory if it goes to 0
22 */
23
24// ===========================================================================
25// headers, declarations, constants
26// ===========================================================================
27
28// For compilers that support precompilation, includes "wx.h".
29#include "wx/wxprec.h"
30
31#ifdef __BORLANDC__
32 #pragma hdrstop
33#endif
34
35#ifndef WX_PRECOMP
36 #include "wx/defs.h"
37 #include "wx/string.h"
38 #include "wx/intl.h"
39 #include "wx/thread.h"
40#endif
41
42#include <ctype.h>
43#include <string.h>
44#include <stdlib.h>
45
46#ifndef __WXMSW__
47#include <errno.h>
48#endif
49
50#ifdef __SALFORDC__
51 #include <clib.h>
52#endif
53
54// allocating extra space for each string consumes more memory but speeds up
55// the concatenation operations (nLen is the current string's length)
56// NB: EXTRA_ALLOC must be >= 0!
57#define EXTRA_ALLOC (19 - nLen % 16)
58
59// ---------------------------------------------------------------------------
60// static class variables definition
61// ---------------------------------------------------------------------------
62
63#if !wxUSE_STL
64 //According to STL _must_ be a -1 size_t
65 const size_t wxStringBase::npos = (size_t) -1;
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 wxTmemcpy(m_pchData, psz + nPos, nLength);
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 wxTmemcpy(m_pchData, pData->data(), nLen);
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
321 wxASSERT( !GetStringData()->IsShared() ); // we must be the only owner
322
323 // it doesn't really matter what the string length is as it's going to be
324 // overwritten later but, for extra safety, set it to 0 for now as we may
325 // have some junk in m_pchData
326 GetStringData()->nDataLength = 0;
327
328 return true;
329}
330
331wxStringBase& wxStringBase::append(size_t n, wxChar ch)
332{
333 size_type len = length();
334
335 if ( !Alloc(len + n) || !CopyBeforeWrite() ) {
336 wxFAIL_MSG( _T("out of memory in wxStringBase::append") );
337 }
338 GetStringData()->nDataLength = len + n;
339 m_pchData[len + n] = '\0';
340 for ( size_t i = 0; i < n; ++i )
341 m_pchData[len + i] = ch;
342 return *this;
343}
344
345void wxStringBase::resize(size_t nSize, wxChar ch)
346{
347 size_t len = length();
348
349 if ( nSize < len )
350 {
351 erase(begin() + nSize, end());
352 }
353 else if ( nSize > len )
354 {
355 append(nSize - len, ch);
356 }
357 //else: we have exactly the specified length, nothing to do
358}
359
360// allocate enough memory for nLen characters
361bool wxStringBase::Alloc(size_t nLen)
362{
363 wxStringData *pData = GetStringData();
364 if ( pData->nAllocLength <= nLen ) {
365 if ( pData->IsEmpty() ) {
366 nLen += EXTRA_ALLOC;
367
368 wxStringData* pData = (wxStringData*)
369 malloc(sizeof(wxStringData) + (nLen + 1)*sizeof(wxChar));
370
371 if ( pData == NULL ) {
372 // allocation failure handled by caller
373 return false;
374 }
375
376 pData->nRefs = 1;
377 pData->nDataLength = 0;
378 pData->nAllocLength = nLen;
379 m_pchData = pData->data(); // data starts after wxStringData
380 m_pchData[0u] = wxT('\0');
381 }
382 else if ( pData->IsShared() ) {
383 pData->Unlock(); // memory not freed because shared
384 size_t nOldLen = pData->nDataLength;
385 if ( !AllocBuffer(nLen) ) {
386 // allocation failure handled by caller
387 return false;
388 }
389 // +1 to copy the terminator, too
390 memcpy(m_pchData, pData->data(), (nOldLen+1)*sizeof(wxChar));
391 GetStringData()->nDataLength = nOldLen;
392 }
393 else {
394 nLen += EXTRA_ALLOC;
395
396 pData = (wxStringData *)
397 realloc(pData, sizeof(wxStringData) + (nLen + 1)*sizeof(wxChar));
398
399 if ( pData == NULL ) {
400 // allocation failure handled by caller
401 // keep previous data since reallocation failed
402 return false;
403 }
404
405 // it's not important if the pointer changed or not (the check for this
406 // is not faster than assigning to m_pchData in all cases)
407 pData->nAllocLength = nLen;
408 m_pchData = pData->data();
409 }
410 }
411 //else: we've already got enough
412 return true;
413}
414
415wxStringBase::iterator wxStringBase::begin()
416{
417 if (length() > 0)
418 CopyBeforeWrite();
419 return m_pchData;
420}
421
422wxStringBase::iterator wxStringBase::end()
423{
424 if (length() > 0)
425 CopyBeforeWrite();
426 return m_pchData + length();
427}
428
429wxStringBase::iterator wxStringBase::erase(iterator it)
430{
431 size_type idx = it - begin();
432 erase(idx, 1);
433 return begin() + idx;
434}
435
436wxStringBase& wxStringBase::erase(size_t nStart, size_t nLen)
437{
438 wxASSERT(nStart <= length());
439 size_t strLen = length() - nStart;
440 // delete nLen or up to the end of the string characters
441 nLen = strLen < nLen ? strLen : nLen;
442 wxString strTmp(c_str(), nStart);
443 strTmp.append(c_str() + nStart + nLen, length() - nStart - nLen);
444
445 swap(strTmp);
446 return *this;
447}
448
449wxStringBase& wxStringBase::insert(size_t nPos, const wxChar *sz, size_t n)
450{
451 wxASSERT( nPos <= length() );
452
453 if ( n == npos ) n = wxStrlen(sz);
454 if ( n == 0 ) return *this;
455
456 if ( !Alloc(length() + n) || !CopyBeforeWrite() ) {
457 wxFAIL_MSG( _T("out of memory in wxStringBase::insert") );
458 }
459
460 memmove(m_pchData + nPos + n, m_pchData + nPos,
461 (length() - nPos) * sizeof(wxChar));
462 memcpy(m_pchData + nPos, sz, n * sizeof(wxChar));
463 GetStringData()->nDataLength = length() + n;
464 m_pchData[length()] = '\0';
465
466 return *this;
467}
468
469void wxStringBase::swap(wxStringBase& str)
470{
471 wxChar* tmp = str.m_pchData;
472 str.m_pchData = m_pchData;
473 m_pchData = tmp;
474}
475
476size_t wxStringBase::find(const wxStringBase& str, size_t nStart) const
477{
478 wxASSERT( str.GetStringData()->IsValid() );
479 wxASSERT( nStart <= length() );
480
481 //anchor
482 const wxChar* p = (const wxChar*)wxTmemchr(c_str() + nStart,
483 str.c_str()[0],
484 length() - nStart);
485
486 if(!p)
487 return npos;
488
489 while(p - c_str() + str.length() <= length() &&
490 wxTmemcmp(p, str.c_str(), str.length()) )
491 {
492 //Previosly passed as the first argument to wxTmemchr,
493 //but C/C++ standard does not specify evaluation order
494 //of arguments to functions -
495 //http://embedded.com/showArticle.jhtml?articleID=9900607
496 ++p;
497
498 //anchor again
499 p = (const wxChar*)wxTmemchr(p,
500 str.c_str()[0],
501 length() - (p - c_str()));
502
503 if(!p)
504 return npos;
505 }
506
507 return (p - c_str() + str.length() <= length()) ? p - c_str() : npos;
508}
509
510size_t wxStringBase::find(const wxChar* sz, size_t nStart, size_t n) const
511{
512 return find(wxStringBase(sz, n), nStart);
513}
514
515size_t wxStringBase::find(wxChar ch, size_t nStart) const
516{
517 wxASSERT( nStart <= length() );
518
519 const wxChar *p = (const wxChar*)wxTmemchr(c_str() + nStart, ch, length() - nStart);
520
521 return p == NULL ? npos : p - c_str();
522}
523
524size_t wxStringBase::rfind(const wxStringBase& str, size_t nStart) const
525{
526 wxASSERT( str.GetStringData()->IsValid() );
527 wxASSERT( nStart == npos || nStart <= length() );
528
529 if ( length() >= str.length() )
530 {
531 // avoids a corner case later
532 if ( length() == 0 && str.length() == 0 )
533 return 0;
534
535 // "top" is the point where search starts from
536 size_t top = length() - str.length();
537
538 if ( nStart == npos )
539 nStart = length() - 1;
540 if ( nStart < top )
541 top = nStart;
542
543 const wxChar *cursor = c_str() + top;
544 do
545 {
546 if ( wxTmemcmp(cursor, str.c_str(),
547 str.length()) == 0 )
548 {
549 return cursor - c_str();
550 }
551 } while ( cursor-- > c_str() );
552 }
553
554 return npos;
555}
556
557size_t wxStringBase::rfind(const wxChar* sz, size_t nStart, size_t n) const
558{
559 return rfind(wxStringBase(sz, n), nStart);
560}
561
562size_t wxStringBase::rfind(wxChar ch, size_t nStart) const
563{
564 if ( nStart == npos )
565 {
566 nStart = length();
567 }
568 else
569 {
570 wxASSERT( nStart <= length() );
571 }
572
573 const wxChar *actual;
574 for ( actual = c_str() + ( nStart == npos ? length() : nStart + 1 );
575 actual > c_str(); --actual )
576 {
577 if ( *(actual - 1) == ch )
578 return (actual - 1) - c_str();
579 }
580
581 return npos;
582}
583
584size_t wxStringBase::find_first_of(const wxChar* sz, size_t nStart) const
585{
586 wxASSERT(nStart <= length());
587
588 size_t len = wxStrlen(sz);
589
590 size_t i;
591 for(i = nStart; i < this->length(); ++i)
592 {
593 if (wxTmemchr(sz, *(c_str() + i), len))
594 break;
595 }
596
597 if(i == this->length())
598 return npos;
599 else
600 return i;
601}
602
603size_t wxStringBase::find_first_of(const wxChar* sz, size_t nStart,
604 size_t n) const
605{
606 return find_first_of(wxStringBase(sz, n), nStart);
607}
608
609size_t wxStringBase::find_last_of(const wxChar* sz, size_t nStart) const
610{
611 if ( nStart == npos )
612 {
613 nStart = length() - 1;
614 }
615 else
616 {
617 wxASSERT_MSG( nStart <= length(),
618 _T("invalid index in find_last_of()") );
619 }
620
621 size_t len = wxStrlen(sz);
622
623 for ( const wxChar *p = c_str() + nStart; p >= c_str(); --p )
624 {
625 if ( wxTmemchr(sz, *p, len) )
626 return p - c_str();
627 }
628
629 return npos;
630}
631
632size_t wxStringBase::find_last_of(const wxChar* sz, size_t nStart,
633 size_t n) const
634{
635 return find_last_of(wxStringBase(sz, n), nStart);
636}
637
638size_t wxStringBase::find_first_not_of(const wxChar* sz, size_t nStart) const
639{
640 if ( nStart == npos )
641 {
642 nStart = length();
643 }
644 else
645 {
646 wxASSERT( nStart <= length() );
647 }
648
649 size_t len = wxStrlen(sz);
650
651 size_t i;
652 for(i = nStart; i < this->length(); ++i)
653 {
654 if (!wxTmemchr(sz, *(c_str() + i), len))
655 break;
656 }
657
658 if(i == this->length())
659 return npos;
660 else
661 return i;
662}
663
664size_t wxStringBase::find_first_not_of(const wxChar* sz, size_t nStart,
665 size_t n) const
666{
667 return find_first_not_of(wxStringBase(sz, n), nStart);
668}
669
670size_t wxStringBase::find_first_not_of(wxChar ch, size_t nStart) const
671{
672 wxASSERT( nStart <= length() );
673
674 for ( const wxChar *p = c_str() + nStart; *p; p++ )
675 {
676 if ( *p != ch )
677 return p - c_str();
678 }
679
680 return npos;
681}
682
683size_t wxStringBase::find_last_not_of(const wxChar* sz, size_t nStart) const
684{
685 if ( nStart == npos )
686 {
687 nStart = length() - 1;
688 }
689 else
690 {
691 wxASSERT( nStart <= length() );
692 }
693
694 size_t len = wxStrlen(sz);
695
696 for ( const wxChar *p = c_str() + nStart; p >= c_str(); --p )
697 {
698 if ( !wxTmemchr(sz, *p,len) )
699 return p - c_str();
700 }
701
702 return npos;
703}
704
705size_t wxStringBase::find_last_not_of(const wxChar* sz, size_t nStart,
706 size_t n) const
707{
708 return find_last_not_of(wxStringBase(sz, n), nStart);
709}
710
711size_t wxStringBase::find_last_not_of(wxChar ch, size_t nStart) const
712{
713 if ( nStart == npos )
714 {
715 nStart = length() - 1;
716 }
717 else
718 {
719 wxASSERT( nStart <= length() );
720 }
721
722 for ( const wxChar *p = c_str() + nStart; p >= c_str(); --p )
723 {
724 if ( *p != ch )
725 return p - c_str();
726 }
727
728 return npos;
729}
730
731wxStringBase& wxStringBase::replace(size_t nStart, size_t nLen,
732 const wxChar *sz)
733{
734 wxASSERT_MSG( nStart <= length(),
735 _T("index out of bounds in wxStringBase::replace") );
736 size_t strLen = length() - nStart;
737 nLen = strLen < nLen ? strLen : nLen;
738
739 wxStringBase strTmp;
740 strTmp.reserve(length()); // micro optimisation to avoid multiple mem allocs
741
742 if ( nStart != 0 )
743 strTmp.append(c_str(), nStart);
744 strTmp.append(sz);
745 strTmp.append(c_str() + nStart + nLen);
746
747 swap(strTmp);
748 return *this;
749}
750
751wxStringBase& wxStringBase::replace(size_t nStart, size_t nLen,
752 size_t nCount, wxChar ch)
753{
754 return replace(nStart, nLen, wxStringBase(nCount, ch).c_str());
755}
756
757wxStringBase& wxStringBase::replace(size_t nStart, size_t nLen,
758 const wxStringBase& str,
759 size_t nStart2, size_t nLen2)
760{
761 return replace(nStart, nLen, str.substr(nStart2, nLen2));
762}
763
764wxStringBase& wxStringBase::replace(size_t nStart, size_t nLen,
765 const wxChar* sz, size_t nCount)
766{
767 return replace(nStart, nLen, wxStringBase(sz, nCount).c_str());
768}
769
770wxStringBase wxStringBase::substr(size_t nStart, size_t nLen) const
771{
772 if ( nLen == npos )
773 nLen = length() - nStart;
774 return wxStringBase(*this, nStart, nLen);
775}
776
777// assigns one string to another
778wxStringBase& wxStringBase::operator=(const wxStringBase& stringSrc)
779{
780 wxASSERT( stringSrc.GetStringData()->IsValid() );
781
782 // don't copy string over itself
783 if ( m_pchData != stringSrc.m_pchData ) {
784 if ( stringSrc.GetStringData()->IsEmpty() ) {
785 Reinit();
786 }
787 else {
788 // adjust references
789 GetStringData()->Unlock();
790 m_pchData = stringSrc.m_pchData;
791 GetStringData()->Lock();
792 }
793 }
794
795 return *this;
796}
797
798// assigns a single character
799wxStringBase& wxStringBase::operator=(wxChar ch)
800{
801 if ( !AssignCopy(1, &ch) ) {
802 wxFAIL_MSG( _T("out of memory in wxStringBase::operator=(wxChar)") );
803 }
804 return *this;
805}
806
807// assigns C string
808wxStringBase& wxStringBase::operator=(const wxChar *psz)
809{
810 if ( !AssignCopy(wxStrlen(psz), psz) ) {
811 wxFAIL_MSG( _T("out of memory in wxStringBase::operator=(const wxChar *)") );
812 }
813 return *this;
814}
815
816// helper function: does real copy
817bool wxStringBase::AssignCopy(size_t nSrcLen, const wxChar *pszSrcData)
818{
819 if ( nSrcLen == 0 ) {
820 Reinit();
821 }
822 else {
823 if ( !AllocBeforeWrite(nSrcLen) ) {
824 // allocation failure handled by caller
825 return false;
826 }
827 memcpy(m_pchData, pszSrcData, nSrcLen*sizeof(wxChar));
828 GetStringData()->nDataLength = nSrcLen;
829 m_pchData[nSrcLen] = wxT('\0');
830 }
831 return true;
832}
833
834// ---------------------------------------------------------------------------
835// string concatenation
836// ---------------------------------------------------------------------------
837
838// add something to this string
839bool wxStringBase::ConcatSelf(size_t nSrcLen, const wxChar *pszSrcData,
840 size_t nMaxLen)
841{
842 STATISTICS_ADD(SummandLength, nSrcLen);
843
844 nSrcLen = nSrcLen < nMaxLen ? nSrcLen : nMaxLen;
845
846 // concatenating an empty string is a NOP
847 if ( nSrcLen > 0 ) {
848 wxStringData *pData = GetStringData();
849 size_t nLen = pData->nDataLength;
850 size_t nNewLen = nLen + nSrcLen;
851
852 // alloc new buffer if current is too small
853 if ( pData->IsShared() ) {
854 STATISTICS_ADD(ConcatHit, 0);
855
856 // we have to allocate another buffer
857 wxStringData* pOldData = GetStringData();
858 if ( !AllocBuffer(nNewLen) ) {
859 // allocation failure handled by caller
860 return false;
861 }
862 memcpy(m_pchData, pOldData->data(), nLen*sizeof(wxChar));
863 pOldData->Unlock();
864 }
865 else if ( nNewLen > pData->nAllocLength ) {
866 STATISTICS_ADD(ConcatHit, 0);
867
868 reserve(nNewLen);
869 // we have to grow the buffer
870 if ( capacity() < nNewLen ) {
871 // allocation failure handled by caller
872 return false;
873 }
874 }
875 else {
876 STATISTICS_ADD(ConcatHit, 1);
877
878 // the buffer is already big enough
879 }
880
881 // should be enough space
882 wxASSERT( nNewLen <= GetStringData()->nAllocLength );
883
884 // fast concatenation - all is done in our buffer
885 memcpy(m_pchData + nLen, pszSrcData, nSrcLen*sizeof(wxChar));
886
887 m_pchData[nNewLen] = wxT('\0'); // put terminating '\0'
888 GetStringData()->nDataLength = nNewLen; // and fix the length
889 }
890 //else: the string to append was empty
891 return true;
892}
893
894// ---------------------------------------------------------------------------
895// simple sub-string extraction
896// ---------------------------------------------------------------------------
897
898// helper function: clone the data attached to this string
899bool wxStringBase::AllocCopy(wxString& dest, int nCopyLen, int nCopyIndex) const
900{
901 if ( nCopyLen == 0 ) {
902 dest.Init();
903 }
904 else {
905 if ( !dest.AllocBuffer(nCopyLen) ) {
906 // allocation failure handled by caller
907 return false;
908 }
909 memcpy(dest.m_pchData, m_pchData + nCopyIndex, nCopyLen*sizeof(wxChar));
910 }
911 return true;
912}
913
914#endif // !wxUSE_STL
915
916#if !wxUSE_STL || !defined(HAVE_STD_STRING_COMPARE)
917
918#if !wxUSE_STL
919 #define STRINGCLASS wxStringBase
920#else
921 #define STRINGCLASS wxString
922#endif
923
924static inline int wxDoCmp(const wxChar* s1, size_t l1,
925 const wxChar* s2, size_t l2)
926{
927 if( l1 == l2 )
928 return wxTmemcmp(s1, s2, l1);
929 else if( l1 < l2 )
930 {
931 int ret = wxTmemcmp(s1, s2, l1);
932 return ret == 0 ? -1 : ret;
933 }
934 else
935 {
936 int ret = wxTmemcmp(s1, s2, l2);
937 return ret == 0 ? +1 : ret;
938 }
939}
940
941int STRINGCLASS::compare(const wxStringBase& str) const
942{
943 return ::wxDoCmp(data(), length(), str.data(), str.length());
944}
945
946int STRINGCLASS::compare(size_t nStart, size_t nLen,
947 const wxStringBase& str) const
948{
949 wxASSERT(nStart <= length());
950 size_type strLen = length() - nStart;
951 nLen = strLen < nLen ? strLen : nLen;
952 return ::wxDoCmp(data() + nStart, nLen, str.data(), str.length());
953}
954
955int STRINGCLASS::compare(size_t nStart, size_t nLen,
956 const wxStringBase& str,
957 size_t nStart2, size_t nLen2) const
958{
959 wxASSERT(nStart <= length());
960 wxASSERT(nStart2 <= str.length());
961 size_type strLen = length() - nStart,
962 strLen2 = str.length() - nStart2;
963 nLen = strLen < nLen ? strLen : nLen;
964 nLen2 = strLen2 < nLen2 ? strLen2 : nLen2;
965 return ::wxDoCmp(data() + nStart, nLen, str.data() + nStart2, nLen2);
966}
967
968int STRINGCLASS::compare(const wxChar* sz) const
969{
970 size_t nLen = wxStrlen(sz);
971 return ::wxDoCmp(data(), length(), sz, nLen);
972}
973
974int STRINGCLASS::compare(size_t nStart, size_t nLen,
975 const wxChar* sz, size_t nCount) const
976{
977 wxASSERT(nStart <= length());
978 size_type strLen = length() - nStart;
979 nLen = strLen < nLen ? strLen : nLen;
980 if( nCount == npos )
981 nCount = wxStrlen(sz);
982
983 return ::wxDoCmp(data() + nStart, nLen, sz, nCount);
984}
985
986#undef STRINGCLASS
987
988#endif // !wxUSE_STL || !defined(HAVE_STD_STRING_COMPARE)
989
990// ===========================================================================
991// wxString class core
992// ===========================================================================
993
994// ---------------------------------------------------------------------------
995// construction and conversion
996// ---------------------------------------------------------------------------
997
998#if wxUSE_UNICODE
999
1000// from multibyte string
1001wxString::wxString(const char *psz, wxMBConv& conv, size_t nLength)
1002{
1003 // if nLength != npos, then we have to make a NULL-terminated copy
1004 // of first nLength bytes of psz first because the input buffer to MB2WC
1005 // must always be NULL-terminated:
1006 wxCharBuffer inBuf((const char *)NULL);
1007 if (nLength != npos)
1008 {
1009 wxASSERT( psz != NULL );
1010 wxCharBuffer tmp(nLength);
1011 memcpy(tmp.data(), psz, nLength);
1012 tmp.data()[nLength] = '\0';
1013 inBuf = tmp;
1014 psz = inBuf.data();
1015 }
1016
1017 // first get the size of the buffer we need
1018 size_t nLen;
1019 if ( psz )
1020 {
1021 // calculate the needed size ourselves or use the provided one
1022 if (nLength == npos)
1023 nLen = strlen(psz);
1024 else
1025 nLen = nLength;
1026 }
1027 else
1028 {
1029 // nothing to convert
1030 nLen = 0;
1031 }
1032
1033
1034 // anything to do?
1035 if ( (nLen != 0) && (nLen != (size_t)-1) )
1036 {
1037 //Convert string
1038 size_t nRealSize;
1039 wxWCharBuffer theBuffer = conv.cMB2WC(psz, nLen, &nRealSize);
1040
1041 //Copy
1042 if (nRealSize)
1043 assign( theBuffer.data() , nRealSize - 1 );
1044 }
1045}
1046
1047//Convert wxString in Unicode mode to a multi-byte string
1048const wxCharBuffer wxString::mb_str(wxMBConv& conv) const
1049{
1050 size_t dwOutSize;
1051 return conv.cWC2MB(c_str(), length(), &dwOutSize);
1052}
1053
1054#else // ANSI
1055
1056#if wxUSE_WCHAR_T
1057// from wide string
1058wxString::wxString(const wchar_t *pwz, wxMBConv& conv, size_t nLength)
1059{
1060 // if nLength != npos, then we have to make a NULL-terminated copy
1061 // of first nLength chars of psz first because the input buffer to WC2MB
1062 // must always be NULL-terminated:
1063 wxWCharBuffer inBuf((const wchar_t *)NULL);
1064 if (nLength != npos)
1065 {
1066 wxASSERT( pwz != NULL );
1067 wxWCharBuffer tmp(nLength);
1068 memcpy(tmp.data(), pwz, nLength * sizeof(wchar_t));
1069 tmp.data()[nLength] = '\0';
1070 inBuf = tmp;
1071 pwz = inBuf.data();
1072 }
1073
1074 // first get the size of the buffer we need
1075 size_t nLen;
1076 if ( pwz )
1077 {
1078 // calculate the needed size ourselves or use the provided one
1079 if (nLength == npos)
1080 nLen = wxWcslen(pwz);
1081 else
1082 nLen = nLength;
1083 }
1084 else
1085 {
1086 // nothing to convert
1087 nLen = 0;
1088 }
1089
1090 // anything to do?
1091 if ( (nLen != 0) && (nLen != (size_t)-1) )
1092 {
1093 //Convert string
1094 size_t nRealSize;
1095 wxCharBuffer theBuffer = conv.cWC2MB(pwz, nLen, &nRealSize);
1096
1097 //Copy
1098 if (nRealSize)
1099 assign( theBuffer.data() , nRealSize - 1 );
1100 }
1101}
1102
1103//Converts this string to a wide character string if unicode
1104//mode is not enabled and wxUSE_WCHAR_T is enabled
1105const wxWCharBuffer wxString::wc_str(wxMBConv& conv) const
1106{
1107 size_t dwOutSize;
1108 return conv.cMB2WC(c_str(), length(), &dwOutSize);
1109}
1110
1111#endif // wxUSE_WCHAR_T
1112
1113#endif // Unicode/ANSI
1114
1115// shrink to minimal size (releasing extra memory)
1116bool wxString::Shrink()
1117{
1118 wxString tmp(begin(), end());
1119 swap(tmp);
1120 return tmp.length() == length();
1121}
1122
1123#if !wxUSE_STL
1124// get the pointer to writable buffer of (at least) nLen bytes
1125wxChar *wxString::GetWriteBuf(size_t nLen)
1126{
1127 if ( !AllocBeforeWrite(nLen) ) {
1128 // allocation failure handled by caller
1129 return NULL;
1130 }
1131
1132 wxASSERT( GetStringData()->nRefs == 1 );
1133 GetStringData()->Validate(false);
1134
1135 return m_pchData;
1136}
1137
1138// put string back in a reasonable state after GetWriteBuf
1139void wxString::UngetWriteBuf()
1140{
1141 GetStringData()->nDataLength = wxStrlen(m_pchData);
1142 GetStringData()->Validate(true);
1143}
1144
1145void wxString::UngetWriteBuf(size_t nLen)
1146{
1147 GetStringData()->nDataLength = nLen;
1148 GetStringData()->Validate(true);
1149}
1150#endif
1151
1152// ---------------------------------------------------------------------------
1153// data access
1154// ---------------------------------------------------------------------------
1155
1156// all functions are inline in string.h
1157
1158// ---------------------------------------------------------------------------
1159// assignment operators
1160// ---------------------------------------------------------------------------
1161
1162#if !wxUSE_UNICODE
1163
1164// same as 'signed char' variant
1165wxString& wxString::operator=(const unsigned char* psz)
1166{
1167 *this = (const char *)psz;
1168 return *this;
1169}
1170
1171#if wxUSE_WCHAR_T
1172wxString& wxString::operator=(const wchar_t *pwz)
1173{
1174 wxString str(pwz);
1175 swap(str);
1176 return *this;
1177}
1178#endif
1179
1180#endif
1181
1182/*
1183 * concatenation functions come in 5 flavours:
1184 * string + string
1185 * char + string and string + char
1186 * C str + string and string + C str
1187 */
1188
1189wxString operator+(const wxString& str1, const wxString& str2)
1190{
1191#if !wxUSE_STL
1192 wxASSERT( str1.GetStringData()->IsValid() );
1193 wxASSERT( str2.GetStringData()->IsValid() );
1194#endif
1195
1196 wxString s = str1;
1197 s += str2;
1198
1199 return s;
1200}
1201
1202wxString operator+(const wxString& str, wxChar ch)
1203{
1204#if !wxUSE_STL
1205 wxASSERT( str.GetStringData()->IsValid() );
1206#endif
1207
1208 wxString s = str;
1209 s += ch;
1210
1211 return s;
1212}
1213
1214wxString operator+(wxChar ch, const wxString& str)
1215{
1216#if !wxUSE_STL
1217 wxASSERT( str.GetStringData()->IsValid() );
1218#endif
1219
1220 wxString s = ch;
1221 s += str;
1222
1223 return s;
1224}
1225
1226wxString operator+(const wxString& str, const wxChar *psz)
1227{
1228#if !wxUSE_STL
1229 wxASSERT( str.GetStringData()->IsValid() );
1230#endif
1231
1232 wxString s;
1233 if ( !s.Alloc(wxStrlen(psz) + str.Len()) ) {
1234 wxFAIL_MSG( _T("out of memory in wxString::operator+") );
1235 }
1236 s += str;
1237 s += psz;
1238
1239 return s;
1240}
1241
1242wxString operator+(const wxChar *psz, const wxString& str)
1243{
1244#if !wxUSE_STL
1245 wxASSERT( str.GetStringData()->IsValid() );
1246#endif
1247
1248 wxString s;
1249 if ( !s.Alloc(wxStrlen(psz) + str.Len()) ) {
1250 wxFAIL_MSG( _T("out of memory in wxString::operator+") );
1251 }
1252 s = psz;
1253 s += str;
1254
1255 return s;
1256}
1257
1258// ===========================================================================
1259// other common string functions
1260// ===========================================================================
1261
1262int wxString::Cmp(const wxString& s) const
1263{
1264 return compare(s);
1265}
1266
1267int wxString::Cmp(const wxChar* psz) const
1268{
1269 return compare(psz);
1270}
1271
1272static inline int wxDoCmpNoCase(const wxChar* s1, size_t l1,
1273 const wxChar* s2, size_t l2)
1274{
1275 size_t i;
1276
1277 if( l1 == l2 )
1278 {
1279 for(i = 0; i < l1; ++i)
1280 {
1281 if(wxTolower(s1[i]) != wxTolower(s2[i]))
1282 break;
1283 }
1284 return i == l1 ? 0 : wxTolower(s1[i]) < wxTolower(s2[i]) ? -1 : 1;
1285 }
1286 else if( l1 < l2 )
1287 {
1288 for(i = 0; i < l1; ++i)
1289 {
1290 if(wxTolower(s1[i]) != wxTolower(s2[i]))
1291 break;
1292 }
1293 return i == l1 ? -1 : wxTolower(s1[i]) < wxTolower(s2[i]) ? -1 : 1;
1294 }
1295 else
1296 {
1297 for(i = 0; i < l2; ++i)
1298 {
1299 if(wxTolower(s1[i]) != wxTolower(s2[i]))
1300 break;
1301 }
1302 return i == l2 ? 1 : wxTolower(s1[i]) < wxTolower(s2[i]) ? -1 : 1;
1303 }
1304}
1305
1306int wxString::CmpNoCase(const wxString& s) const
1307{
1308 return wxDoCmpNoCase(data(), length(), s.data(), s.length());
1309}
1310
1311int wxString::CmpNoCase(const wxChar* psz) const
1312{
1313 int nLen = wxStrlen(psz);
1314
1315 return wxDoCmpNoCase(data(), length(), psz, nLen);
1316}
1317
1318
1319#if wxUSE_UNICODE
1320
1321#ifdef __MWERKS__
1322#ifndef __SCHAR_MAX__
1323#define __SCHAR_MAX__ 127
1324#endif
1325#endif
1326
1327wxString wxString::FromAscii(const char *ascii)
1328{
1329 if (!ascii)
1330 return wxEmptyString;
1331
1332 size_t len = strlen( ascii );
1333 wxString res;
1334
1335 if ( len )
1336 {
1337 wxStringBuffer buf(res, len);
1338
1339 wchar_t *dest = buf;
1340
1341 for ( ;; )
1342 {
1343 if ( (*dest++ = (wchar_t)(unsigned char)*ascii++) == L'\0' )
1344 break;
1345 }
1346 }
1347
1348 return res;
1349}
1350
1351wxString wxString::FromAscii(const char ascii)
1352{
1353 // What do we do with '\0' ?
1354
1355 wxString res;
1356 res += (wchar_t)(unsigned char) ascii;
1357
1358 return res;
1359}
1360
1361const wxCharBuffer wxString::ToAscii() const
1362{
1363 // this will allocate enough space for the terminating NUL too
1364 wxCharBuffer buffer(length());
1365
1366
1367 char *dest = buffer.data();
1368
1369 const wchar_t *pwc = c_str();
1370 for ( ;; )
1371 {
1372 *dest++ = (char)(*pwc > SCHAR_MAX ? wxT('_') : *pwc);
1373
1374 // the output string can't have embedded NULs anyhow, so we can safely
1375 // stop at first of them even if we do have any
1376 if ( !*pwc++ )
1377 break;
1378 }
1379
1380 return buffer;
1381}
1382
1383#endif // Unicode
1384
1385// extract string of length nCount starting at nFirst
1386wxString wxString::Mid(size_t nFirst, size_t nCount) const
1387{
1388 size_t nLen = length();
1389
1390 // default value of nCount is npos and means "till the end"
1391 if ( nCount == npos )
1392 {
1393 nCount = nLen - nFirst;
1394 }
1395
1396 // out-of-bounds requests return sensible things
1397 if ( nFirst + nCount > nLen )
1398 {
1399 nCount = nLen - nFirst;
1400 }
1401
1402 if ( nFirst > nLen )
1403 {
1404 // AllocCopy() will return empty string
1405 nCount = 0;
1406 }
1407
1408 wxString dest(*this, nFirst, nCount);
1409 if ( dest.length() != nCount ) {
1410 wxFAIL_MSG( _T("out of memory in wxString::Mid") );
1411 }
1412
1413 return dest;
1414}
1415
1416// check that the string starts with prefix and return the rest of the string
1417// in the provided pointer if it is not NULL, otherwise return false
1418bool wxString::StartsWith(const wxChar *prefix, wxString *rest) const
1419{
1420 wxASSERT_MSG( prefix, _T("invalid parameter in wxString::StartsWith") );
1421
1422 // first check if the beginning of the string matches the prefix: note
1423 // that we don't have to check that we don't run out of this string as
1424 // when we reach the terminating NUL, either prefix string ends too (and
1425 // then it's ok) or we break out of the loop because there is no match
1426 const wxChar *p = c_str();
1427 while ( *prefix )
1428 {
1429 if ( *prefix++ != *p++ )
1430 {
1431 // no match
1432 return false;
1433 }
1434 }
1435
1436 if ( rest )
1437 {
1438 // put the rest of the string into provided pointer
1439 *rest = p;
1440 }
1441
1442 return true;
1443}
1444
1445// extract nCount last (rightmost) characters
1446wxString wxString::Right(size_t nCount) const
1447{
1448 if ( nCount > length() )
1449 nCount = length();
1450
1451 wxString dest(*this, length() - nCount, nCount);
1452 if ( dest.length() != nCount ) {
1453 wxFAIL_MSG( _T("out of memory in wxString::Right") );
1454 }
1455 return dest;
1456}
1457
1458// get all characters after the last occurence of ch
1459// (returns the whole string if ch not found)
1460wxString wxString::AfterLast(wxChar ch) const
1461{
1462 wxString str;
1463 int iPos = Find(ch, true);
1464 if ( iPos == wxNOT_FOUND )
1465 str = *this;
1466 else
1467 str = c_str() + iPos + 1;
1468
1469 return str;
1470}
1471
1472// extract nCount first (leftmost) characters
1473wxString wxString::Left(size_t nCount) const
1474{
1475 if ( nCount > length() )
1476 nCount = length();
1477
1478 wxString dest(*this, 0, nCount);
1479 if ( dest.length() != nCount ) {
1480 wxFAIL_MSG( _T("out of memory in wxString::Left") );
1481 }
1482 return dest;
1483}
1484
1485// get all characters before the first occurence of ch
1486// (returns the whole string if ch not found)
1487wxString wxString::BeforeFirst(wxChar ch) const
1488{
1489 int iPos = Find(ch);
1490 if ( iPos == wxNOT_FOUND ) iPos = length();
1491 return wxString(*this, 0, iPos);
1492}
1493
1494/// get all characters before the last occurence of ch
1495/// (returns empty string if ch not found)
1496wxString wxString::BeforeLast(wxChar ch) const
1497{
1498 wxString str;
1499 int iPos = Find(ch, true);
1500 if ( iPos != wxNOT_FOUND && iPos != 0 )
1501 str = wxString(c_str(), iPos);
1502
1503 return str;
1504}
1505
1506/// get all characters after the first occurence of ch
1507/// (returns empty string if ch not found)
1508wxString wxString::AfterFirst(wxChar ch) const
1509{
1510 wxString str;
1511 int iPos = Find(ch);
1512 if ( iPos != wxNOT_FOUND )
1513 str = c_str() + iPos + 1;
1514
1515 return str;
1516}
1517
1518// replace first (or all) occurences of some substring with another one
1519size_t
1520wxString::Replace(const wxChar *szOld, const wxChar *szNew, bool bReplaceAll)
1521{
1522 // if we tried to replace an empty string we'd enter an infinite loop below
1523 wxCHECK_MSG( szOld && *szOld && szNew, 0,
1524 _T("wxString::Replace(): invalid parameter") );
1525
1526 size_t uiCount = 0; // count of replacements made
1527
1528 size_t uiOldLen = wxStrlen(szOld);
1529
1530 wxString strTemp;
1531 const wxChar *pCurrent = c_str();
1532 const wxChar *pSubstr;
1533 while ( *pCurrent != wxT('\0') ) {
1534 pSubstr = wxStrstr(pCurrent, szOld);
1535 if ( pSubstr == NULL ) {
1536 // strTemp is unused if no replacements were made, so avoid the copy
1537 if ( uiCount == 0 )
1538 return 0;
1539
1540 strTemp += pCurrent; // copy the rest
1541 break; // exit the loop
1542 }
1543 else {
1544 // take chars before match
1545 size_type len = strTemp.length();
1546 strTemp.append(pCurrent, pSubstr - pCurrent);
1547 if ( strTemp.length() != (size_t)(len + pSubstr - pCurrent) ) {
1548 wxFAIL_MSG( _T("out of memory in wxString::Replace") );
1549 return 0;
1550 }
1551 strTemp += szNew;
1552 pCurrent = pSubstr + uiOldLen; // restart after match
1553
1554 uiCount++;
1555
1556 // stop now?
1557 if ( !bReplaceAll ) {
1558 strTemp += pCurrent; // copy the rest
1559 break; // exit the loop
1560 }
1561 }
1562 }
1563
1564 // only done if there were replacements, otherwise would have returned above
1565 swap(strTemp);
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