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