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