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