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