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