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