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