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