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