]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/common/string.cpp
adding OS level Window Menu by default
[wxWidgets.git] / src / common / string.cpp
... / ...
CommitLineData
1/////////////////////////////////////////////////////////////////////////////
2// Name: string.cpp
3// Purpose: wxString class
4// Author: Vadim Zeitlin, Ryan Norton
5// Modified by:
6// Created: 29/01/98
7// RCS-ID: $Id$
8// Copyright: (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
9// (c) 2004 Ryan Norton <wxprojects@comcast.net>
10// Licence: wxWindows licence
11/////////////////////////////////////////////////////////////////////////////
12
13/*
14 * About ref counting:
15 * 1) all empty strings use g_strEmpty, nRefs = -1 (set in Init())
16 * 2) AllocBuffer() sets nRefs to 1, Lock() increments it by one
17 * 3) Unlock() decrements nRefs and frees memory if it goes to 0
18 */
19
20// ===========================================================================
21// headers, declarations, constants
22// ===========================================================================
23
24// For compilers that support precompilation, includes "wx.h".
25#include "wx/wxprec.h"
26
27#ifdef __BORLANDC__
28 #pragma hdrstop
29#endif
30
31#ifndef WX_PRECOMP
32 #include "wx/defs.h"
33 #include "wx/string.h"
34 #include "wx/intl.h"
35 #include "wx/thread.h"
36#endif
37
38#include <ctype.h>
39#include <string.h>
40#include <stdlib.h>
41
42#ifndef __WXMSW__
43#include <errno.h>
44#endif
45
46#ifdef __SALFORDC__
47 #include <clib.h>
48#endif
49
50// allocating extra space for each string consumes more memory but speeds up
51// the concatenation operations (nLen is the current string's length)
52// NB: EXTRA_ALLOC must be >= 0!
53#define EXTRA_ALLOC (19 - nLen % 16)
54
55// ---------------------------------------------------------------------------
56// static class variables definition
57// ---------------------------------------------------------------------------
58
59#if !wxUSE_STL
60 //According to STL _must_ be a -1 size_t
61 const size_t wxStringBase::npos = (size_t) -1;
62#endif
63
64// ----------------------------------------------------------------------------
65// static data
66// ----------------------------------------------------------------------------
67
68#if wxUSE_STL
69
70extern const wxChar WXDLLIMPEXP_BASE *wxEmptyString = _T("");
71
72#else
73
74// for an empty string, GetStringData() will return this address: this
75// structure has the same layout as wxStringData and it's data() method will
76// return the empty string (dummy pointer)
77static const struct
78{
79 wxStringData data;
80 wxChar dummy;
81} g_strEmpty = { {-1, 0, 0}, wxT('\0') };
82
83// empty C style string: points to 'string data' byte of g_strEmpty
84extern const wxChar WXDLLIMPEXP_BASE *wxEmptyString = &g_strEmpty.dummy;
85
86#endif
87
88// ----------------------------------------------------------------------------
89// global functions
90// ----------------------------------------------------------------------------
91
92#if wxUSE_STD_IOSTREAM
93
94// MS Visual C++ version 5.0 provides the new STL headers as well as the old
95// iostream ones.
96//
97// ATTN: you can _not_ use both of these in the same program!
98
99#include <iostream>
100
101wxSTD istream& operator>>(wxSTD istream& is, wxString& WXUNUSED(str))
102{
103#if 0
104 int w = is.width(0);
105 if ( is.ipfx(0) ) {
106 streambuf *sb = is.rdbuf();
107 str.erase();
108 while ( true ) {
109 int ch = sb->sbumpc ();
110 if ( ch == EOF ) {
111 is.setstate(ios::eofbit);
112 break;
113 }
114 else if ( isspace(ch) ) {
115 sb->sungetc();
116 break;
117 }
118
119 str += ch;
120 if ( --w == 1 )
121 break;
122 }
123 }
124
125 is.isfx();
126 if ( str.length() == 0 )
127 is.setstate(ios::failbit);
128#endif
129 return is;
130}
131
132wxSTD ostream& operator<<(wxSTD ostream& os, const wxString& str)
133{
134#ifdef __BORLANDC__
135 os << str.mb_str();
136#else
137 os << str.c_str();
138#endif
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 //This is kind of inefficient, but its pretty good considering...
743 //we don't want to use character access operators here because on STL
744 //it will freeze the reference count of strTmp, which means a deep copy
745 //at the end when swap is called
746 //
747 //Also, we can't use append with the full character pointer and must
748 //do it manually because this string can contain null characters
749 for(size_t i1 = 0; i1 < nStart; ++i1)
750 strTmp.append(1, this->c_str()[i1]);
751
752 //its safe to do the full version here because
753 //sz must be a normal c string
754 strTmp.append(sz);
755
756 for(size_t i2 = nStart + nLen; i2 < length(); ++i2)
757 strTmp.append(1, this->c_str()[i2]);
758
759 swap(strTmp);
760 return *this;
761}
762
763wxStringBase& wxStringBase::replace(size_t nStart, size_t nLen,
764 size_t nCount, wxChar ch)
765{
766 return replace(nStart, nLen, wxStringBase(nCount, ch).c_str());
767}
768
769wxStringBase& wxStringBase::replace(size_t nStart, size_t nLen,
770 const wxStringBase& str,
771 size_t nStart2, size_t nLen2)
772{
773 return replace(nStart, nLen, str.substr(nStart2, nLen2));
774}
775
776wxStringBase& wxStringBase::replace(size_t nStart, size_t nLen,
777 const wxChar* sz, size_t nCount)
778{
779 return replace(nStart, nLen, wxStringBase(sz, nCount).c_str());
780}
781
782wxStringBase wxStringBase::substr(size_t nStart, size_t nLen) const
783{
784 if ( nLen == npos )
785 nLen = length() - nStart;
786 return wxStringBase(*this, nStart, nLen);
787}
788
789// assigns one string to another
790wxStringBase& wxStringBase::operator=(const wxStringBase& stringSrc)
791{
792 wxASSERT( stringSrc.GetStringData()->IsValid() );
793
794 // don't copy string over itself
795 if ( m_pchData != stringSrc.m_pchData ) {
796 if ( stringSrc.GetStringData()->IsEmpty() ) {
797 Reinit();
798 }
799 else {
800 // adjust references
801 GetStringData()->Unlock();
802 m_pchData = stringSrc.m_pchData;
803 GetStringData()->Lock();
804 }
805 }
806
807 return *this;
808}
809
810// assigns a single character
811wxStringBase& wxStringBase::operator=(wxChar ch)
812{
813 if ( !AssignCopy(1, &ch) ) {
814 wxFAIL_MSG( _T("out of memory in wxStringBase::operator=(wxChar)") );
815 }
816 return *this;
817}
818
819// assigns C string
820wxStringBase& wxStringBase::operator=(const wxChar *psz)
821{
822 if ( !AssignCopy(wxStrlen(psz), psz) ) {
823 wxFAIL_MSG( _T("out of memory in wxStringBase::operator=(const wxChar *)") );
824 }
825 return *this;
826}
827
828// helper function: does real copy
829bool wxStringBase::AssignCopy(size_t nSrcLen, const wxChar *pszSrcData)
830{
831 if ( nSrcLen == 0 ) {
832 Reinit();
833 }
834 else {
835 if ( !AllocBeforeWrite(nSrcLen) ) {
836 // allocation failure handled by caller
837 return false;
838 }
839 memcpy(m_pchData, pszSrcData, nSrcLen*sizeof(wxChar));
840 GetStringData()->nDataLength = nSrcLen;
841 m_pchData[nSrcLen] = wxT('\0');
842 }
843 return true;
844}
845
846// ---------------------------------------------------------------------------
847// string concatenation
848// ---------------------------------------------------------------------------
849
850// add something to this string
851bool wxStringBase::ConcatSelf(size_t nSrcLen, const wxChar *pszSrcData,
852 size_t nMaxLen)
853{
854 STATISTICS_ADD(SummandLength, nSrcLen);
855
856 nSrcLen = nSrcLen < nMaxLen ? nSrcLen : nMaxLen;
857
858 // concatenating an empty string is a NOP
859 if ( nSrcLen > 0 ) {
860 wxStringData *pData = GetStringData();
861 size_t nLen = pData->nDataLength;
862 size_t nNewLen = nLen + nSrcLen;
863
864 // alloc new buffer if current is too small
865 if ( pData->IsShared() ) {
866 STATISTICS_ADD(ConcatHit, 0);
867
868 // we have to allocate another buffer
869 wxStringData* pOldData = GetStringData();
870 if ( !AllocBuffer(nNewLen) ) {
871 // allocation failure handled by caller
872 return false;
873 }
874 memcpy(m_pchData, pOldData->data(), nLen*sizeof(wxChar));
875 pOldData->Unlock();
876 }
877 else if ( nNewLen > pData->nAllocLength ) {
878 STATISTICS_ADD(ConcatHit, 0);
879
880 reserve(nNewLen);
881 // we have to grow the buffer
882 if ( capacity() < nNewLen ) {
883 // allocation failure handled by caller
884 return false;
885 }
886 }
887 else {
888 STATISTICS_ADD(ConcatHit, 1);
889
890 // the buffer is already big enough
891 }
892
893 // should be enough space
894 wxASSERT( nNewLen <= GetStringData()->nAllocLength );
895
896 // fast concatenation - all is done in our buffer
897 memcpy(m_pchData + nLen, pszSrcData, nSrcLen*sizeof(wxChar));
898
899 m_pchData[nNewLen] = wxT('\0'); // put terminating '\0'
900 GetStringData()->nDataLength = nNewLen; // and fix the length
901 }
902 //else: the string to append was empty
903 return true;
904}
905
906// ---------------------------------------------------------------------------
907// simple sub-string extraction
908// ---------------------------------------------------------------------------
909
910// helper function: clone the data attached to this string
911bool wxStringBase::AllocCopy(wxString& dest, int nCopyLen, int nCopyIndex) const
912{
913 if ( nCopyLen == 0 ) {
914 dest.Init();
915 }
916 else {
917 if ( !dest.AllocBuffer(nCopyLen) ) {
918 // allocation failure handled by caller
919 return false;
920 }
921 memcpy(dest.m_pchData, m_pchData + nCopyIndex, nCopyLen*sizeof(wxChar));
922 }
923 return true;
924}
925
926#endif // !wxUSE_STL
927
928#if !wxUSE_STL || !defined(HAVE_STD_STRING_COMPARE)
929
930#if !wxUSE_STL
931 #define STRINGCLASS wxStringBase
932#else
933 #define STRINGCLASS wxString
934#endif
935
936static inline int wxDoCmp(const wxChar* s1, size_t l1,
937 const wxChar* s2, size_t l2)
938{
939 if( l1 == l2 )
940 return wxTmemcmp(s1, s2, l1);
941 else if( l1 < l2 )
942 {
943 int ret = wxTmemcmp(s1, s2, l1);
944 return ret == 0 ? -1 : ret;
945 }
946 else
947 {
948 int ret = wxTmemcmp(s1, s2, l2);
949 return ret == 0 ? +1 : ret;
950 }
951}
952
953int STRINGCLASS::compare(const wxStringBase& str) const
954{
955 return ::wxDoCmp(data(), length(), str.data(), str.length());
956}
957
958int STRINGCLASS::compare(size_t nStart, size_t nLen,
959 const wxStringBase& str) const
960{
961 wxASSERT(nStart <= length());
962 size_type strLen = length() - nStart;
963 nLen = strLen < nLen ? strLen : nLen;
964 return ::wxDoCmp(data() + nStart, nLen, str.data(), str.length());
965}
966
967int STRINGCLASS::compare(size_t nStart, size_t nLen,
968 const wxStringBase& str,
969 size_t nStart2, size_t nLen2) const
970{
971 wxASSERT(nStart <= length());
972 wxASSERT(nStart2 <= str.length());
973 size_type strLen = length() - nStart,
974 strLen2 = str.length() - nStart2;
975 nLen = strLen < nLen ? strLen : nLen;
976 nLen2 = strLen2 < nLen2 ? strLen2 : nLen2;
977 return ::wxDoCmp(data() + nStart, nLen, str.data() + nStart2, nLen2);
978}
979
980int STRINGCLASS::compare(const wxChar* sz) const
981{
982 size_t nLen = wxStrlen(sz);
983 return ::wxDoCmp(data(), length(), sz, nLen);
984}
985
986int STRINGCLASS::compare(size_t nStart, size_t nLen,
987 const wxChar* sz, size_t nCount) const
988{
989 wxASSERT(nStart <= length());
990 size_type strLen = length() - nStart;
991 nLen = strLen < nLen ? strLen : nLen;
992 if( nCount == npos )
993 nCount = wxStrlen(sz);
994
995 return ::wxDoCmp(data() + nStart, nLen, sz, nCount);
996}
997
998#undef STRINGCLASS
999
1000#endif // !wxUSE_STL || !defined(HAVE_STD_STRING_COMPARE)
1001
1002// ===========================================================================
1003// wxString class core
1004// ===========================================================================
1005
1006// ---------------------------------------------------------------------------
1007// construction and conversion
1008// ---------------------------------------------------------------------------
1009
1010#if wxUSE_UNICODE
1011
1012// from multibyte string
1013wxString::wxString(const char *psz, wxMBConv& conv, size_t nLength)
1014{
1015 // if nLength != npos, then we have to make a NULL-terminated copy
1016 // of first nLength bytes of psz first because the input buffer to MB2WC
1017 // must always be NULL-terminated:
1018 wxCharBuffer inBuf((const char *)NULL);
1019 if (nLength != npos)
1020 {
1021 wxASSERT( psz != NULL );
1022 wxCharBuffer tmp(nLength);
1023 memcpy(tmp.data(), psz, nLength);
1024 tmp.data()[nLength] = '\0';
1025 inBuf = tmp;
1026 psz = inBuf.data();
1027 }
1028
1029 // first get the size of the buffer we need
1030 size_t nLen;
1031 if ( psz )
1032 {
1033 // calculate the needed size ourselves or use the provided one
1034 if (nLength == npos)
1035 nLen = strlen(psz);
1036 else
1037 nLen = nLength;
1038 }
1039 else
1040 {
1041 // nothing to convert
1042 nLen = 0;
1043 }
1044
1045
1046 // anything to do?
1047 if ( (nLen != 0) && (nLen != (size_t)-1) )
1048 {
1049 //Convert string
1050 size_t nRealSize;
1051 wxWCharBuffer theBuffer = conv.cMB2WC(psz, nLen, &nRealSize);
1052
1053 //Copy
1054 if (nRealSize)
1055 assign( theBuffer.data() , nRealSize - 1 );
1056 }
1057}
1058
1059//Convert wxString in Unicode mode to a multi-byte string
1060const wxCharBuffer wxString::mb_str(wxMBConv& conv) const
1061{
1062 size_t dwOutSize;
1063 return conv.cWC2MB(c_str(), length(), &dwOutSize);
1064}
1065
1066#else // ANSI
1067
1068#if wxUSE_WCHAR_T
1069// from wide string
1070wxString::wxString(const wchar_t *pwz, wxMBConv& conv, size_t nLength)
1071{
1072 // if nLength != npos, then we have to make a NULL-terminated copy
1073 // of first nLength chars of psz first because the input buffer to WC2MB
1074 // must always be NULL-terminated:
1075 wxWCharBuffer inBuf((const wchar_t *)NULL);
1076 if (nLength != npos)
1077 {
1078 wxASSERT( pwz != NULL );
1079 wxWCharBuffer tmp(nLength);
1080 memcpy(tmp.data(), pwz, nLength * sizeof(wchar_t));
1081 tmp.data()[nLength] = '\0';
1082 inBuf = tmp;
1083 pwz = inBuf.data();
1084 }
1085
1086 // first get the size of the buffer we need
1087 size_t nLen;
1088 if ( pwz )
1089 {
1090 // calculate the needed size ourselves or use the provided one
1091 if (nLength == npos)
1092 nLen = wxWcslen(pwz);
1093 else
1094 nLen = nLength;
1095 }
1096 else
1097 {
1098 // nothing to convert
1099 nLen = 0;
1100 }
1101
1102 // anything to do?
1103 if ( (nLen != 0) && (nLen != (size_t)-1) )
1104 {
1105 //Convert string
1106 size_t nRealSize;
1107 wxCharBuffer theBuffer = conv.cWC2MB(pwz, nLen, &nRealSize);
1108
1109 //Copy
1110 if (nRealSize)
1111 assign( theBuffer.data() , nRealSize - 1 );
1112 }
1113}
1114
1115//Converts this string to a wide character string if unicode
1116//mode is not enabled and wxUSE_WCHAR_T is enabled
1117const wxWCharBuffer wxString::wc_str(wxMBConv& conv) const
1118{
1119 size_t dwOutSize;
1120 return conv.cMB2WC(c_str(), length(), &dwOutSize);
1121}
1122
1123#endif // wxUSE_WCHAR_T
1124
1125#endif // Unicode/ANSI
1126
1127// shrink to minimal size (releasing extra memory)
1128bool wxString::Shrink()
1129{
1130 wxString tmp(begin(), end());
1131 swap(tmp);
1132 return tmp.length() == length();
1133}
1134
1135#if !wxUSE_STL
1136// get the pointer to writable buffer of (at least) nLen bytes
1137wxChar *wxString::GetWriteBuf(size_t nLen)
1138{
1139 if ( !AllocBeforeWrite(nLen) ) {
1140 // allocation failure handled by caller
1141 return NULL;
1142 }
1143
1144 wxASSERT( GetStringData()->nRefs == 1 );
1145 GetStringData()->Validate(false);
1146
1147 return m_pchData;
1148}
1149
1150// put string back in a reasonable state after GetWriteBuf
1151void wxString::UngetWriteBuf()
1152{
1153 GetStringData()->nDataLength = wxStrlen(m_pchData);
1154 GetStringData()->Validate(true);
1155}
1156
1157void wxString::UngetWriteBuf(size_t nLen)
1158{
1159 GetStringData()->nDataLength = nLen;
1160 GetStringData()->Validate(true);
1161}
1162#endif
1163
1164// ---------------------------------------------------------------------------
1165// data access
1166// ---------------------------------------------------------------------------
1167
1168// all functions are inline in string.h
1169
1170// ---------------------------------------------------------------------------
1171// assignment operators
1172// ---------------------------------------------------------------------------
1173
1174#if !wxUSE_UNICODE
1175
1176// same as 'signed char' variant
1177wxString& wxString::operator=(const unsigned char* psz)
1178{
1179 *this = (const char *)psz;
1180 return *this;
1181}
1182
1183#if wxUSE_WCHAR_T
1184wxString& wxString::operator=(const wchar_t *pwz)
1185{
1186 wxString str(pwz);
1187 swap(str);
1188 return *this;
1189}
1190#endif
1191
1192#endif
1193
1194/*
1195 * concatenation functions come in 5 flavours:
1196 * string + string
1197 * char + string and string + char
1198 * C str + string and string + C str
1199 */
1200
1201wxString operator+(const wxString& str1, const wxString& str2)
1202{
1203#if !wxUSE_STL
1204 wxASSERT( str1.GetStringData()->IsValid() );
1205 wxASSERT( str2.GetStringData()->IsValid() );
1206#endif
1207
1208 wxString s = str1;
1209 s += str2;
1210
1211 return s;
1212}
1213
1214wxString operator+(const wxString& str, wxChar ch)
1215{
1216#if !wxUSE_STL
1217 wxASSERT( str.GetStringData()->IsValid() );
1218#endif
1219
1220 wxString s = str;
1221 s += ch;
1222
1223 return s;
1224}
1225
1226wxString operator+(wxChar ch, const wxString& str)
1227{
1228#if !wxUSE_STL
1229 wxASSERT( str.GetStringData()->IsValid() );
1230#endif
1231
1232 wxString s = ch;
1233 s += str;
1234
1235 return s;
1236}
1237
1238wxString operator+(const wxString& str, const wxChar *psz)
1239{
1240#if !wxUSE_STL
1241 wxASSERT( str.GetStringData()->IsValid() );
1242#endif
1243
1244 wxString s;
1245 if ( !s.Alloc(wxStrlen(psz) + str.Len()) ) {
1246 wxFAIL_MSG( _T("out of memory in wxString::operator+") );
1247 }
1248 s += str;
1249 s += psz;
1250
1251 return s;
1252}
1253
1254wxString operator+(const wxChar *psz, const wxString& str)
1255{
1256#if !wxUSE_STL
1257 wxASSERT( str.GetStringData()->IsValid() );
1258#endif
1259
1260 wxString s;
1261 if ( !s.Alloc(wxStrlen(psz) + str.Len()) ) {
1262 wxFAIL_MSG( _T("out of memory in wxString::operator+") );
1263 }
1264 s = psz;
1265 s += str;
1266
1267 return s;
1268}
1269
1270// ===========================================================================
1271// other common string functions
1272// ===========================================================================
1273
1274int wxString::Cmp(const wxString& s) const
1275{
1276 return compare(s);
1277}
1278
1279int wxString::Cmp(const wxChar* psz) const
1280{
1281 return compare(psz);
1282}
1283
1284static inline int wxDoCmpNoCase(const wxChar* s1, size_t l1,
1285 const wxChar* s2, size_t l2)
1286{
1287 size_t i;
1288
1289 if( l1 == l2 )
1290 {
1291 for(i = 0; i < l1; ++i)
1292 {
1293 if(wxTolower(s1[i]) != wxTolower(s2[i]))
1294 break;
1295 }
1296 return i == l1 ? 0 : wxTolower(s1[i]) < wxTolower(s2[i]) ? -1 : 1;
1297 }
1298 else if( l1 < l2 )
1299 {
1300 for(i = 0; i < l1; ++i)
1301 {
1302 if(wxTolower(s1[i]) != wxTolower(s2[i]))
1303 break;
1304 }
1305 return i == l1 ? -1 : wxTolower(s1[i]) < wxTolower(s2[i]) ? -1 : 1;
1306 }
1307 else
1308 {
1309 for(i = 0; i < l2; ++i)
1310 {
1311 if(wxTolower(s1[i]) != wxTolower(s2[i]))
1312 break;
1313 }
1314 return i == l2 ? 1 : wxTolower(s1[i]) < wxTolower(s2[i]) ? -1 : 1;
1315 }
1316}
1317
1318int wxString::CmpNoCase(const wxString& s) const
1319{
1320 return wxDoCmpNoCase(data(), length(), s.data(), s.length());
1321}
1322
1323int wxString::CmpNoCase(const wxChar* psz) const
1324{
1325 int nLen = wxStrlen(psz);
1326
1327 return wxDoCmpNoCase(data(), length(), psz, nLen);
1328}
1329
1330
1331#if wxUSE_UNICODE
1332
1333#ifdef __MWERKS__
1334#ifndef __SCHAR_MAX__
1335#define __SCHAR_MAX__ 127
1336#endif
1337#endif
1338
1339wxString wxString::FromAscii(const char *ascii)
1340{
1341 if (!ascii)
1342 return wxEmptyString;
1343
1344 size_t len = strlen( ascii );
1345 wxString res;
1346
1347 if ( len )
1348 {
1349 wxStringBuffer buf(res, len);
1350
1351 wchar_t *dest = buf;
1352
1353 for ( ;; )
1354 {
1355 if ( (*dest++ = (wchar_t)(unsigned char)*ascii++) == L'\0' )
1356 break;
1357 }
1358 }
1359
1360 return res;
1361}
1362
1363wxString wxString::FromAscii(const char ascii)
1364{
1365 // What do we do with '\0' ?
1366
1367 wxString res;
1368 res += (wchar_t)(unsigned char) ascii;
1369
1370 return res;
1371}
1372
1373const wxCharBuffer wxString::ToAscii() const
1374{
1375 // this will allocate enough space for the terminating NUL too
1376 wxCharBuffer buffer(length());
1377
1378
1379 char *dest = buffer.data();
1380
1381 const wchar_t *pwc = c_str();
1382 for ( ;; )
1383 {
1384 *dest++ = (char)(*pwc > SCHAR_MAX ? wxT('_') : *pwc);
1385
1386 // the output string can't have embedded NULs anyhow, so we can safely
1387 // stop at first of them even if we do have any
1388 if ( !*pwc++ )
1389 break;
1390 }
1391
1392 return buffer;
1393}
1394
1395#endif // Unicode
1396
1397// extract string of length nCount starting at nFirst
1398wxString wxString::Mid(size_t nFirst, size_t nCount) const
1399{
1400 size_t nLen = length();
1401
1402 // default value of nCount is npos and means "till the end"
1403 if ( nCount == npos )
1404 {
1405 nCount = nLen - nFirst;
1406 }
1407
1408 // out-of-bounds requests return sensible things
1409 if ( nFirst + nCount > nLen )
1410 {
1411 nCount = nLen - nFirst;
1412 }
1413
1414 if ( nFirst > nLen )
1415 {
1416 // AllocCopy() will return empty string
1417 nCount = 0;
1418 }
1419
1420 wxString dest(*this, nFirst, nCount);
1421 if ( dest.length() != nCount ) {
1422 wxFAIL_MSG( _T("out of memory in wxString::Mid") );
1423 }
1424
1425 return dest;
1426}
1427
1428// check that the string starts with prefix and return the rest of the string
1429// in the provided pointer if it is not NULL, otherwise return false
1430bool wxString::StartsWith(const wxChar *prefix, wxString *rest) const
1431{
1432 wxASSERT_MSG( prefix, _T("invalid parameter in wxString::StartsWith") );
1433
1434 // first check if the beginning of the string matches the prefix: note
1435 // that we don't have to check that we don't run out of this string as
1436 // when we reach the terminating NUL, either prefix string ends too (and
1437 // then it's ok) or we break out of the loop because there is no match
1438 const wxChar *p = c_str();
1439 while ( *prefix )
1440 {
1441 if ( *prefix++ != *p++ )
1442 {
1443 // no match
1444 return false;
1445 }
1446 }
1447
1448 if ( rest )
1449 {
1450 // put the rest of the string into provided pointer
1451 *rest = p;
1452 }
1453
1454 return true;
1455}
1456
1457// extract nCount last (rightmost) characters
1458wxString wxString::Right(size_t nCount) const
1459{
1460 if ( nCount > length() )
1461 nCount = length();
1462
1463 wxString dest(*this, length() - nCount, nCount);
1464 if ( dest.length() != nCount ) {
1465 wxFAIL_MSG( _T("out of memory in wxString::Right") );
1466 }
1467 return dest;
1468}
1469
1470// get all characters after the last occurence of ch
1471// (returns the whole string if ch not found)
1472wxString wxString::AfterLast(wxChar ch) const
1473{
1474 wxString str;
1475 int iPos = Find(ch, true);
1476 if ( iPos == wxNOT_FOUND )
1477 str = *this;
1478 else
1479 str = c_str() + iPos + 1;
1480
1481 return str;
1482}
1483
1484// extract nCount first (leftmost) characters
1485wxString wxString::Left(size_t nCount) const
1486{
1487 if ( nCount > length() )
1488 nCount = length();
1489
1490 wxString dest(*this, 0, nCount);
1491 if ( dest.length() != nCount ) {
1492 wxFAIL_MSG( _T("out of memory in wxString::Left") );
1493 }
1494 return dest;
1495}
1496
1497// get all characters before the first occurence of ch
1498// (returns the whole string if ch not found)
1499wxString wxString::BeforeFirst(wxChar ch) const
1500{
1501 int iPos = Find(ch);
1502 if ( iPos == wxNOT_FOUND ) iPos = length();
1503 return wxString(*this, 0, iPos);
1504}
1505
1506/// get all characters before the last occurence of ch
1507/// (returns empty string if ch not found)
1508wxString wxString::BeforeLast(wxChar ch) const
1509{
1510 wxString str;
1511 int iPos = Find(ch, true);
1512 if ( iPos != wxNOT_FOUND && iPos != 0 )
1513 str = wxString(c_str(), iPos);
1514
1515 return str;
1516}
1517
1518/// get all characters after the first occurence of ch
1519/// (returns empty string if ch not found)
1520wxString wxString::AfterFirst(wxChar ch) const
1521{
1522 wxString str;
1523 int iPos = Find(ch);
1524 if ( iPos != wxNOT_FOUND )
1525 str = c_str() + iPos + 1;
1526
1527 return str;
1528}
1529
1530// replace first (or all) occurences of some substring with another one
1531size_t wxString::Replace(const wxChar *szOld,
1532 const wxChar *szNew, bool bReplaceAll)
1533{
1534 // if we tried to replace an empty string we'd enter an infinite loop below
1535 wxCHECK_MSG( szOld && *szOld && szNew, 0,
1536 _T("wxString::Replace(): invalid parameter") );
1537
1538 size_t uiCount = 0; // count of replacements made
1539
1540 size_t uiOldLen = wxStrlen(szOld);
1541 size_t uiNewLen = wxStrlen(szNew);
1542
1543 size_t dwPos = 0;
1544
1545 while ( this->c_str()[dwPos] != wxT('\0') )
1546 {
1547 //DO NOT USE STRSTR HERE
1548 //this string can contain embedded null characters,
1549 //so strstr will function incorrectly
1550 dwPos = find(szOld, dwPos);
1551 if ( dwPos == npos )
1552 break; // exit the loop
1553 else
1554 {
1555 //replace this occurance of the old string with the new one
1556 replace(dwPos, uiOldLen, szNew, uiNewLen);
1557
1558 //move up pos past the string that was replaced
1559 dwPos += uiNewLen;
1560
1561 //increase replace count
1562 ++uiCount;
1563
1564 // stop now?
1565 if ( !bReplaceAll )
1566 break; // exit the loop
1567 }
1568 }
1569
1570 return uiCount;
1571}
1572
1573bool wxString::IsAscii() const
1574{
1575 const wxChar *s = (const wxChar*) *this;
1576 while(*s){
1577 if(!isascii(*s)) return(false);
1578 s++;
1579 }
1580 return(true);
1581}
1582
1583bool wxString::IsWord() const
1584{
1585 const wxChar *s = (const wxChar*) *this;
1586 while(*s){
1587 if(!wxIsalpha(*s)) return(false);
1588 s++;
1589 }
1590 return(true);
1591}
1592
1593bool wxString::IsNumber() const
1594{
1595 const wxChar *s = (const wxChar*) *this;
1596 if (wxStrlen(s))
1597 if ((s[0] == wxT('-')) || (s[0] == wxT('+'))) s++;
1598 while(*s){
1599 if(!wxIsdigit(*s)) return(false);
1600 s++;
1601 }
1602 return(true);
1603}
1604
1605wxString wxString::Strip(stripType w) const
1606{
1607 wxString s = *this;
1608 if ( w & leading ) s.Trim(false);
1609 if ( w & trailing ) s.Trim(true);
1610 return s;
1611}
1612
1613// ---------------------------------------------------------------------------
1614// case conversion
1615// ---------------------------------------------------------------------------
1616
1617wxString& wxString::MakeUpper()
1618{
1619 for ( iterator it = begin(), en = end(); it != en; ++it )
1620 *it = (wxChar)wxToupper(*it);
1621
1622 return *this;
1623}
1624
1625wxString& wxString::MakeLower()
1626{
1627 for ( iterator it = begin(), en = end(); it != en; ++it )
1628 *it = (wxChar)wxTolower(*it);
1629
1630 return *this;
1631}
1632
1633// ---------------------------------------------------------------------------
1634// trimming and padding
1635// ---------------------------------------------------------------------------
1636
1637// some compilers (VC++ 6.0 not to name them) return true for a call to
1638