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