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