]> git.saurik.com Git - wxWidgets.git/blame - src/common/string.cpp
handle 0 timeout in RunLoop() correctly
[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
e87b7833 59#if !wxUSE_STL
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
e87b7833
MB
68#if wxUSE_STL
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
4cc6a9db
VZ
141#if !wxUSE_STL
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
894// ---------------------------------------------------------------------------
895// simple sub-string extraction
896// ---------------------------------------------------------------------------
897
898// helper function: clone the data attached to this string
899bool wxStringBase::AllocCopy(wxString& dest, int nCopyLen, int nCopyIndex) const
900{
901 if ( nCopyLen == 0 ) {
902 dest.Init();
903 }
904 else {
905 if ( !dest.AllocBuffer(nCopyLen) ) {
906 // allocation failure handled by caller
d775fa82 907 return false;
e87b7833
MB
908 }
909 memcpy(dest.m_pchData, m_pchData + nCopyIndex, nCopyLen*sizeof(wxChar));
910 }
d775fa82 911 return true;
e87b7833
MB
912}
913
914#endif // !wxUSE_STL
915
916#if !wxUSE_STL || !defined(HAVE_STD_STRING_COMPARE)
917
918#if !wxUSE_STL
919 #define STRINGCLASS wxStringBase
920#else
921 #define STRINGCLASS wxString
922#endif
923
924static inline int wxDoCmp(const wxChar* s1, size_t l1,
925 const wxChar* s2, size_t l2)
926{
927 if( l1 == l2 )
2c09fb3b 928 return wxTmemcmp(s1, s2, l1);
e87b7833
MB
929 else if( l1 < l2 )
930 {
2c09fb3b 931 int ret = wxTmemcmp(s1, s2, l1);
e87b7833
MB
932 return ret == 0 ? -1 : ret;
933 }
2c09fb3b 934 else
e87b7833 935 {
2c09fb3b 936 int ret = wxTmemcmp(s1, s2, l2);
e87b7833
MB
937 return ret == 0 ? +1 : ret;
938 }
e87b7833
MB
939}
940
e87b7833
MB
941int STRINGCLASS::compare(const wxStringBase& str) const
942{
943 return ::wxDoCmp(data(), length(), str.data(), str.length());
944}
945
e87b7833
MB
946int STRINGCLASS::compare(size_t nStart, size_t nLen,
947 const wxStringBase& str) const
948{
949 wxASSERT(nStart <= length());
950 size_type strLen = length() - nStart;
951 nLen = strLen < nLen ? strLen : nLen;
952 return ::wxDoCmp(data() + nStart, nLen, str.data(), str.length());
953}
954
955int STRINGCLASS::compare(size_t nStart, size_t nLen,
956 const wxStringBase& str,
957 size_t nStart2, size_t nLen2) const
958{
959 wxASSERT(nStart <= length());
960 wxASSERT(nStart2 <= str.length());
961 size_type strLen = length() - nStart,
962 strLen2 = str.length() - nStart2;
963 nLen = strLen < nLen ? strLen : nLen;
964 nLen2 = strLen2 < nLen2 ? strLen2 : nLen2;
965 return ::wxDoCmp(data() + nStart, nLen, str.data() + nStart2, nLen2);
966}
967
e87b7833
MB
968int STRINGCLASS::compare(const wxChar* sz) const
969{
970 size_t nLen = wxStrlen(sz);
971 return ::wxDoCmp(data(), length(), sz, nLen);
972}
973
e87b7833
MB
974int STRINGCLASS::compare(size_t nStart, size_t nLen,
975 const wxChar* sz, size_t nCount) const
976{
977 wxASSERT(nStart <= length());
978 size_type strLen = length() - nStart;
979 nLen = strLen < nLen ? strLen : nLen;
980 if( nCount == npos )
981 nCount = wxStrlen(sz);
982
983 return ::wxDoCmp(data() + nStart, nLen, sz, nCount);
984}
985
986#undef STRINGCLASS
987
988#endif // !wxUSE_STL || !defined(HAVE_STD_STRING_COMPARE)
989
990// ===========================================================================
991// wxString class core
992// ===========================================================================
993
06386448
RN
994// ---------------------------------------------------------------------------
995// construction and conversion
e87b7833
MB
996// ---------------------------------------------------------------------------
997
998#if wxUSE_UNICODE
999
1000// from multibyte string
830f8f11 1001wxString::wxString(const char *psz, const wxMBConv& conv, size_t nLength)
e87b7833 1002{
e87b7833 1003 // anything to do?
eec47cc6 1004 if ( psz && nLength != 0 )
e87b7833 1005 {
eec47cc6
VZ
1006 if ( nLength == npos )
1007 {
467e0479 1008 nLength = wxNO_LEN;
eec47cc6
VZ
1009 }
1010
1011 size_t nLenWide;
1012 wxWCharBuffer wbuf = conv.cMB2WC(psz, nLength, &nLenWide);
e4e3bbb4 1013
eec47cc6
VZ
1014 if ( nLenWide )
1015 assign(wbuf, nLenWide);
e87b7833 1016 }
7663d0d4 1017}
265d5cce 1018
06386448 1019//Convert wxString in Unicode mode to a multi-byte string
830f8f11 1020const wxCharBuffer wxString::mb_str(const wxMBConv& conv) const
265d5cce 1021{
eec47cc6 1022 return conv.cWC2MB(c_str(), length() + 1 /* size, not length */, NULL);
e87b7833
MB
1023}
1024
1025#else // ANSI
1026
1027#if wxUSE_WCHAR_T
eec47cc6 1028
e87b7833 1029// from wide string
830f8f11 1030wxString::wxString(const wchar_t *pwz, const wxMBConv& conv, size_t nLength)
e87b7833 1031{
e87b7833 1032 // anything to do?
eec47cc6 1033 if ( pwz && nLength != 0 )
e87b7833 1034 {
eec47cc6
VZ
1035 if ( nLength == npos )
1036 {
467e0479 1037 nLength = wxNO_LEN;
eec47cc6
VZ
1038 }
1039
1040 size_t nLenMB;
1041 wxCharBuffer buf = conv.cWC2MB(pwz, nLength, &nLenMB);
e4e3bbb4 1042
eec47cc6
VZ
1043 if ( nLenMB )
1044 assign(buf, nLenMB);
e87b7833 1045 }
e87b7833 1046}
265d5cce 1047
7663d0d4 1048//Converts this string to a wide character string if unicode
06386448 1049//mode is not enabled and wxUSE_WCHAR_T is enabled
830f8f11 1050const wxWCharBuffer wxString::wc_str(const wxMBConv& conv) const
265d5cce 1051{
eec47cc6 1052 return conv.cMB2WC(c_str(), length() + 1 /* size, not length */, NULL);
265d5cce 1053}
7663d0d4 1054
e87b7833
MB
1055#endif // wxUSE_WCHAR_T
1056
1057#endif // Unicode/ANSI
1058
1059// shrink to minimal size (releasing extra memory)
1060bool wxString::Shrink()
1061{
1062 wxString tmp(begin(), end());
1063 swap(tmp);
1064 return tmp.length() == length();
1065}
1066
1067#if !wxUSE_STL
1068// get the pointer to writable buffer of (at least) nLen bytes
d8a4b666 1069wxChar *wxString::DoGetWriteBuf(size_t nLen)
e87b7833
MB
1070{
1071 if ( !AllocBeforeWrite(nLen) ) {
1072 // allocation failure handled by caller
1073 return NULL;
1074 }
1075
1076 wxASSERT( GetStringData()->nRefs == 1 );
d775fa82 1077 GetStringData()->Validate(false);
e87b7833
MB
1078
1079 return m_pchData;
1080}
1081
1082// put string back in a reasonable state after GetWriteBuf
d8a4b666 1083void wxString::DoUngetWriteBuf()
e87b7833 1084{
d8a4b666 1085 DoUngetWriteBuf(wxStrlen(m_pchData));
e87b7833
MB
1086}
1087
d8a4b666 1088void wxString::DoUngetWriteBuf(size_t nLen)
e87b7833 1089{
c56d73fe
VZ
1090 wxStringData * const pData = GetStringData();
1091
1092 wxASSERT_MSG( nLen < pData->nAllocLength, _T("buffer overrun") );
1093
1094 // the strings we store are always NUL-terminated
1095 pData->data()[nLen] = _T('\0');
1096 pData->nDataLength = nLen;
1097 pData->Validate(true);
e87b7833 1098}
d8a4b666
VS
1099
1100// deprecated compatibility code:
1101#if WXWIN_COMPATIBILITY_2_8
1102wxChar *wxString::GetWriteBuf(size_t nLen)
1103{
1104 return DoGetWriteBuf(nLen);
1105}
1106
1107void wxString::UngetWriteBuf()
1108{
1109 DoUngetWriteBuf();
1110}
1111
1112void wxString::UngetWriteBuf(size_t nLen)
1113{
1114 DoUngetWriteBuf(nLen);
1115}
1116#endif // WXWIN_COMPATIBILITY_2_8
1117
c56d73fe 1118#endif // !wxUSE_STL
e87b7833 1119
d8a4b666 1120
e87b7833
MB
1121// ---------------------------------------------------------------------------
1122// data access
1123// ---------------------------------------------------------------------------
1124
1125// all functions are inline in string.h
1126
1127// ---------------------------------------------------------------------------
1128// assignment operators
1129// ---------------------------------------------------------------------------
1130
1131#if !wxUSE_UNICODE
1132
1133// same as 'signed char' variant
1134wxString& wxString::operator=(const unsigned char* psz)
1135{
1136 *this = (const char *)psz;
1137 return *this;
1138}
1139
1140#if wxUSE_WCHAR_T
1141wxString& wxString::operator=(const wchar_t *pwz)
1142{
1143 wxString str(pwz);
1144 swap(str);
1145 return *this;
c801d85f 1146}
e87b7833
MB
1147#endif
1148
1149#endif
c801d85f
KB
1150
1151/*
c801d85f
KB
1152 * concatenation functions come in 5 flavours:
1153 * string + string
1154 * char + string and string + char
1155 * C str + string and string + C str
1156 */
1157
b1801e0e 1158wxString operator+(const wxString& str1, const wxString& str2)
c801d85f 1159{
e87b7833 1160#if !wxUSE_STL
3458e408
WS
1161 wxASSERT( str1.GetStringData()->IsValid() );
1162 wxASSERT( str2.GetStringData()->IsValid() );
e87b7833 1163#endif
097c080b 1164
3458e408
WS
1165 wxString s = str1;
1166 s += str2;
3168a13f 1167
3458e408 1168 return s;
c801d85f
KB
1169}
1170
c9f78968 1171wxString operator+(const wxString& str, wxUniChar ch)
c801d85f 1172{
e87b7833 1173#if !wxUSE_STL
3458e408 1174 wxASSERT( str.GetStringData()->IsValid() );
e87b7833 1175#endif
3168a13f 1176
3458e408
WS
1177 wxString s = str;
1178 s += ch;
097c080b 1179
3458e408 1180 return s;
c801d85f
KB
1181}
1182
c9f78968 1183wxString operator+(wxUniChar ch, const wxString& str)
c801d85f 1184{
e87b7833 1185#if !wxUSE_STL
3458e408 1186 wxASSERT( str.GetStringData()->IsValid() );
e87b7833 1187#endif
097c080b 1188
3458e408
WS
1189 wxString s = ch;
1190 s += str;
3168a13f 1191
3458e408 1192 return s;
c801d85f
KB
1193}
1194
b1801e0e 1195wxString operator+(const wxString& str, const wxChar *psz)
c801d85f 1196{
e87b7833 1197#if !wxUSE_STL
3458e408 1198 wxASSERT( str.GetStringData()->IsValid() );
e87b7833 1199#endif
097c080b 1200
3458e408
WS
1201 wxString s;
1202 if ( !s.Alloc(wxStrlen(psz) + str.length()) ) {
1203 wxFAIL_MSG( _T("out of memory in wxString::operator+") );
1204 }
1205 s += str;
1206 s += psz;
3168a13f 1207
3458e408 1208 return s;
c801d85f
KB
1209}
1210
b1801e0e 1211wxString operator+(const wxChar *psz, const wxString& str)
c801d85f 1212{
e87b7833 1213#if !wxUSE_STL
3458e408 1214 wxASSERT( str.GetStringData()->IsValid() );
e87b7833 1215#endif
097c080b 1216
3458e408
WS
1217 wxString s;
1218 if ( !s.Alloc(wxStrlen(psz) + str.length()) ) {
1219 wxFAIL_MSG( _T("out of memory in wxString::operator+") );
1220 }
1221 s = psz;
1222 s += str;
3168a13f 1223
3458e408 1224 return s;
c801d85f
KB
1225}
1226
1227// ===========================================================================
1228// other common string functions
1229// ===========================================================================
1230
dcb68102
RN
1231int wxString::Cmp(const wxString& s) const
1232{
1233 return compare(s);
1234}
1235
1236int wxString::Cmp(const wxChar* psz) const
1237{
1238 return compare(psz);
1239}
1240
1241static inline int wxDoCmpNoCase(const wxChar* s1, size_t l1,
1242 const wxChar* s2, size_t l2)
1243{
1244 size_t i;
1245
1246 if( l1 == l2 )
1247 {
1248 for(i = 0; i < l1; ++i)
1249 {
1250 if(wxTolower(s1[i]) != wxTolower(s2[i]))
1251 break;
1252 }
59059feb 1253 return i == l1 ? 0 : wxTolower(s1[i]) < wxTolower(s2[i]) ? -1 : 1;
dcb68102
RN
1254 }
1255 else if( l1 < l2 )
1256 {
1257 for(i = 0; i < l1; ++i)
1258 {
1259 if(wxTolower(s1[i]) != wxTolower(s2[i]))
1260 break;
1261 }
59059feb 1262 return i == l1 ? -1 : wxTolower(s1[i]) < wxTolower(s2[i]) ? -1 : 1;
dcb68102 1263 }
2c09fb3b 1264 else
dcb68102
RN
1265 {
1266 for(i = 0; i < l2; ++i)
1267 {
1268 if(wxTolower(s1[i]) != wxTolower(s2[i]))
1269 break;
1270 }
35b4f9ca 1271 return i == l2 ? 1 : wxTolower(s1[i]) < wxTolower(s2[i]) ? -1 : 1;
dcb68102 1272 }
dcb68102
RN
1273}
1274
1275int wxString::CmpNoCase(const wxString& s) const
1276{
1277 return wxDoCmpNoCase(data(), length(), s.data(), s.length());
1278}
1279
1280int wxString::CmpNoCase(const wxChar* psz) const
1281{
1282 int nLen = wxStrlen(psz);
1283
1284 return wxDoCmpNoCase(data(), length(), psz, nLen);
1285}
1286
1287
b1ac3b56 1288#if wxUSE_UNICODE
e015c2a3 1289
cf6bedce
SC
1290#ifdef __MWERKS__
1291#ifndef __SCHAR_MAX__
1292#define __SCHAR_MAX__ 127
1293#endif
1294#endif
1295
e015c2a3 1296wxString wxString::FromAscii(const char *ascii)
b1ac3b56
RR
1297{
1298 if (!ascii)
1299 return wxEmptyString;
e015c2a3 1300
b1ac3b56
RR
1301 size_t len = strlen( ascii );
1302 wxString res;
e015c2a3
VZ
1303
1304 if ( len )
1305 {
1306 wxStringBuffer buf(res, len);
1307
1308 wchar_t *dest = buf;
1309
1310 for ( ;; )
1311 {
1312 if ( (*dest++ = (wchar_t)(unsigned char)*ascii++) == L'\0' )
1313 break;
1314 }
1315 }
1316
b1ac3b56
RR
1317 return res;
1318}
1319
2b5f62a0
VZ
1320wxString wxString::FromAscii(const char ascii)
1321{
1322 // What do we do with '\0' ?
1323
1324 wxString res;
1325 res += (wchar_t)(unsigned char) ascii;
8760bc65 1326
2b5f62a0
VZ
1327 return res;
1328}
1329
b1ac3b56
RR
1330const wxCharBuffer wxString::ToAscii() const
1331{
e015c2a3
VZ
1332 // this will allocate enough space for the terminating NUL too
1333 wxCharBuffer buffer(length());
b1ac3b56 1334
be7eecf8 1335
6e394fc6 1336 char *dest = buffer.data();
e015c2a3
VZ
1337
1338 const wchar_t *pwc = c_str();
1339 for ( ;; )
b1ac3b56 1340 {
6e394fc6 1341 *dest++ = (char)(*pwc > SCHAR_MAX ? wxT('_') : *pwc);
e015c2a3
VZ
1342
1343 // the output string can't have embedded NULs anyhow, so we can safely
1344 // stop at first of them even if we do have any
1345 if ( !*pwc++ )
1346 break;
b1ac3b56 1347 }
e015c2a3 1348
b1ac3b56
RR
1349 return buffer;
1350}
e015c2a3
VZ
1351
1352#endif // Unicode
b1ac3b56 1353
c801d85f 1354// extract string of length nCount starting at nFirst
c801d85f
KB
1355wxString wxString::Mid(size_t nFirst, size_t nCount) const
1356{
73f507f5 1357 size_t nLen = length();
30d9011f 1358
73f507f5
WS
1359 // default value of nCount is npos and means "till the end"
1360 if ( nCount == npos )
1361 {
1362 nCount = nLen - nFirst;
1363 }
30d9011f 1364
73f507f5
WS
1365 // out-of-bounds requests return sensible things
1366 if ( nFirst + nCount > nLen )
1367 {
1368 nCount = nLen - nFirst;
1369 }
c801d85f 1370
73f507f5
WS
1371 if ( nFirst > nLen )
1372 {
1373 // AllocCopy() will return empty string
1374 return wxEmptyString;
1375 }
c801d85f 1376
73f507f5
WS
1377 wxString dest(*this, nFirst, nCount);
1378 if ( dest.length() != nCount )
1379 {
1380 wxFAIL_MSG( _T("out of memory in wxString::Mid") );
1381 }
30d9011f 1382
73f507f5 1383 return dest;
c801d85f
KB
1384}
1385
e87b7833 1386// check that the string starts with prefix and return the rest of the string
d775fa82 1387// in the provided pointer if it is not NULL, otherwise return false
f6bcfd97
BP
1388bool wxString::StartsWith(const wxChar *prefix, wxString *rest) const
1389{
1390 wxASSERT_MSG( prefix, _T("invalid parameter in wxString::StartsWith") );
1391
1392 // first check if the beginning of the string matches the prefix: note
1393 // that we don't have to check that we don't run out of this string as
1394 // when we reach the terminating NUL, either prefix string ends too (and
1395 // then it's ok) or we break out of the loop because there is no match
1396 const wxChar *p = c_str();
1397 while ( *prefix )
1398 {
1399 if ( *prefix++ != *p++ )
1400 {
1401 // no match
d775fa82 1402 return false;
f6bcfd97
BP
1403 }
1404 }
1405
1406 if ( rest )
1407 {
1408 // put the rest of the string into provided pointer
1409 *rest = p;
1410 }
1411
d775fa82 1412 return true;
f6bcfd97
BP
1413}
1414
3affcd07
VZ
1415
1416// check that the string ends with suffix and return the rest of it in the
1417// provided pointer if it is not NULL, otherwise return false
1418bool wxString::EndsWith(const wxChar *suffix, wxString *rest) const
1419{
1420 wxASSERT_MSG( suffix, _T("invalid parameter in wxString::EndssWith") );
1421
1422 int start = length() - wxStrlen(suffix);
c9f78968 1423 if ( start < 0 || wxStrcmp(wx_str() + start, suffix) != 0 )
3affcd07
VZ
1424 return false;
1425
1426 if ( rest )
1427 {
1428 // put the rest of the string into provided pointer
1429 rest->assign(*this, 0, start);
1430 }
1431
1432 return true;
1433}
1434
1435
c801d85f
KB
1436// extract nCount last (rightmost) characters
1437wxString wxString::Right(size_t nCount) const
1438{
e87b7833
MB
1439 if ( nCount > length() )
1440 nCount = length();
c801d85f 1441
e87b7833
MB
1442 wxString dest(*this, length() - nCount, nCount);
1443 if ( dest.length() != nCount ) {
b1801e0e
GD
1444 wxFAIL_MSG( _T("out of memory in wxString::Right") );
1445 }
c801d85f
KB
1446 return dest;
1447}
1448
1449// get all characters after the last occurence of ch
1450// (returns the whole string if ch not found)
c9f78968 1451wxString wxString::AfterLast(wxUniChar ch) const
c801d85f
KB
1452{
1453 wxString str;
d775fa82 1454 int iPos = Find(ch, true);
3c67202d 1455 if ( iPos == wxNOT_FOUND )
c801d85f
KB
1456 str = *this;
1457 else
c9f78968 1458 str = wx_str() + iPos + 1;
c801d85f
KB
1459
1460 return str;
1461}
1462
1463// extract nCount first (leftmost) characters
1464wxString wxString::Left(size_t nCount) const
1465{
e87b7833
MB
1466 if ( nCount > length() )
1467 nCount = length();
c801d85f 1468
e87b7833
MB
1469 wxString dest(*this, 0, nCount);
1470 if ( dest.length() != nCount ) {
b1801e0e
GD
1471 wxFAIL_MSG( _T("out of memory in wxString::Left") );
1472 }
c801d85f
KB
1473 return dest;
1474}
1475
1476// get all characters before the first occurence of ch
1477// (returns the whole string if ch not found)
c9f78968 1478wxString wxString::BeforeFirst(wxUniChar ch) const
c801d85f 1479{
e87b7833
MB
1480 int iPos = Find(ch);
1481 if ( iPos == wxNOT_FOUND ) iPos = length();
1482 return wxString(*this, 0, iPos);
c801d85f
KB
1483}
1484
1485/// get all characters before the last occurence of ch
1486/// (returns empty string if ch not found)
c9f78968 1487wxString wxString::BeforeLast(wxUniChar ch) const
c801d85f
KB
1488{
1489 wxString str;
d775fa82 1490 int iPos = Find(ch, true);
3c67202d 1491 if ( iPos != wxNOT_FOUND && iPos != 0 )
d1c9bbf6 1492 str = wxString(c_str(), iPos);
c801d85f
KB
1493
1494 return str;
1495}
1496
1497/// get all characters after the first occurence of ch
1498/// (returns empty string if ch not found)
c9f78968 1499wxString wxString::AfterFirst(wxUniChar ch) const
c801d85f
KB
1500{
1501 wxString str;
1502 int iPos = Find(ch);
3c67202d 1503 if ( iPos != wxNOT_FOUND )
c9f78968 1504 str = wx_str() + iPos + 1;
c801d85f
KB
1505
1506 return str;
1507}
1508
1509// replace first (or all) occurences of some substring with another one
ad5bb7d6 1510size_t wxString::Replace(const wxChar *szOld,
510bb748 1511 const wxChar *szNew, bool bReplaceAll)
c801d85f 1512{
a8f1f1b2
VZ
1513 // if we tried to replace an empty string we'd enter an infinite loop below
1514 wxCHECK_MSG( szOld && *szOld && szNew, 0,
1515 _T("wxString::Replace(): invalid parameter") );
1516
510bb748 1517 size_t uiCount = 0; // count of replacements made
c801d85f 1518
510bb748
RN
1519 size_t uiOldLen = wxStrlen(szOld);
1520 size_t uiNewLen = wxStrlen(szNew);
c801d85f 1521
510bb748 1522 size_t dwPos = 0;
c801d85f 1523
ad5bb7d6 1524 while ( this->c_str()[dwPos] != wxT('\0') )
510bb748
RN
1525 {
1526 //DO NOT USE STRSTR HERE
1527 //this string can contain embedded null characters,
1528 //so strstr will function incorrectly
1529 dwPos = find(szOld, dwPos);
ad5bb7d6 1530 if ( dwPos == npos )
510bb748 1531 break; // exit the loop
ad5bb7d6 1532 else
510bb748
RN
1533 {
1534 //replace this occurance of the old string with the new one
1535 replace(dwPos, uiOldLen, szNew, uiNewLen);
1536
2df0258e
RN
1537 //move up pos past the string that was replaced
1538 dwPos += uiNewLen;
510bb748
RN
1539
1540 //increase replace count
1541 ++uiCount;
ad5bb7d6 1542
510bb748 1543 // stop now?
ad5bb7d6 1544 if ( !bReplaceAll )
510bb748
RN
1545 break; // exit the loop
1546 }
c801d85f 1547 }
c801d85f 1548
510bb748 1549 return uiCount;
c801d85f
KB
1550}
1551
1552bool wxString::IsAscii() const
1553{
2bb67b80 1554 const wxChar *s = (const wxChar*) *this;
c801d85f 1555 while(*s){
d775fa82 1556 if(!isascii(*s)) return(false);
c801d85f
KB
1557 s++;
1558 }
d775fa82 1559 return(true);
c801d85f 1560}
dd1eaa89 1561
c801d85f
KB
1562bool wxString::IsWord() const
1563{
2bb67b80 1564 const wxChar *s = (const wxChar*) *this;
c801d85f 1565 while(*s){
d775fa82 1566 if(!wxIsalpha(*s)) return(false);
c801d85f
KB
1567 s++;
1568 }
d775fa82 1569 return(true);
c801d85f 1570}
dd1eaa89 1571
c801d85f
KB
1572bool wxString::IsNumber() const
1573{
2bb67b80 1574 const wxChar *s = (const wxChar*) *this;
2f74ed28 1575 if (wxStrlen(s))
930357bd 1576 if ((s[0] == wxT('-')) || (s[0] == wxT('+'))) s++;
c801d85f 1577 while(*s){
d775fa82 1578 if(!wxIsdigit(*s)) return(false);
c801d85f
KB
1579 s++;
1580 }
d775fa82 1581 return(true);
c801d85f
KB
1582}
1583
c801d85f
KB
1584wxString wxString::Strip(stripType w) const
1585{
1586 wxString s = *this;
d775fa82
WS
1587 if ( w & leading ) s.Trim(false);
1588 if ( w & trailing ) s.Trim(true);
c801d85f
KB
1589 return s;
1590}
1591
c801d85f
KB
1592// ---------------------------------------------------------------------------
1593// case conversion
1594// ---------------------------------------------------------------------------
1595
1596wxString& wxString::MakeUpper()
1597{
e87b7833
MB
1598 for ( iterator it = begin(), en = end(); it != en; ++it )
1599 *it = (wxChar)wxToupper(*it);
c801d85f
KB
1600
1601 return *this;
1602}
1603
1604wxString& wxString::MakeLower()
1605{
e87b7833
MB
1606 for ( iterator it = begin(), en = end(); it != en; ++it )
1607 *it = (wxChar)wxTolower(*it);
c801d85f
KB
1608
1609 return *this;
1610}
1611
1612// ---------------------------------------------------------------------------
1613// trimming and padding
1614// ---------------------------------------------------------------------------
1615
d775fa82 1616// some compilers (VC++ 6.0 not to name them) return true for a call to
576c608d
VZ
1617