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