]> git.saurik.com Git - wxWidgets.git/blame - src/common/string.cpp
moved SEH stuff to crashrpt.cpp
[wxWidgets.git] / src / common / string.cpp
CommitLineData
c801d85f
KB
1/////////////////////////////////////////////////////////////////////////////
2// Name: string.cpp
3// Purpose: wxString class
4// Author: Vadim Zeitlin
5// Modified by:
6// Created: 29/01/98
7// RCS-ID: $Id$
8// Copyright: (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
55d99c7a 9// Licence: wxWindows licence
c801d85f
KB
10/////////////////////////////////////////////////////////////////////////////
11
12#ifdef __GNUG__
30b21f9a 13 #pragma implementation "string.h"
c801d85f
KB
14#endif
15
16/*
17 * About ref counting:
18 * 1) all empty strings use g_strEmpty, nRefs = -1 (set in Init())
19 * 2) AllocBuffer() sets nRefs to 1, Lock() increments it by one
20 * 3) Unlock() decrements nRefs and frees memory if it goes to 0
21 */
22
23// ===========================================================================
24// headers, declarations, constants
25// ===========================================================================
26
27// For compilers that support precompilation, includes "wx.h".
28#include "wx/wxprec.h"
29
30#ifdef __BORLANDC__
30b21f9a 31 #pragma hdrstop
c801d85f
KB
32#endif
33
34#ifndef WX_PRECOMP
3c024cc2
VZ
35 #include "wx/defs.h"
36 #include "wx/string.h"
37 #include "wx/intl.h"
3096bd2f 38 #include "wx/thread.h"
6b769f3d 39#endif
c801d85f
KB
40
41#include <ctype.h>
42#include <string.h>
43#include <stdlib.h>
44
ce3ed50d 45#ifdef __SALFORDC__
30b21f9a 46 #include <clib.h>
ce3ed50d
JS
47#endif
48
3168a13f
VZ
49// allocating extra space for each string consumes more memory but speeds up
50// the concatenation operations (nLen is the current string's length)
77ca46e7
VZ
51// NB: EXTRA_ALLOC must be >= 0!
52#define EXTRA_ALLOC (19 - nLen % 16)
3168a13f 53
c801d85f
KB
54// ---------------------------------------------------------------------------
55// static class variables definition
56// ---------------------------------------------------------------------------
57
75ad8feb
DW
58#if defined(__VISAGECPP__) && __IBMCPP__ >= 400
59// must define this static for VA or else you get multiply defined symbols
60// everywhere
61const unsigned int wxSTRING_MAXLEN = UINT_MAX - 100;
62#endif // Visual Age
63
8de2e39c 64#ifdef wxSTD_STRING_COMPATIBILITY
566b84d2 65 const size_t wxString::npos = wxSTRING_MAXLEN;
8de2e39c 66#endif // wxSTD_STRING_COMPATIBILITY
c801d85f 67
3168a13f
VZ
68// ----------------------------------------------------------------------------
69// static data
70// ----------------------------------------------------------------------------
c801d85f 71
3c024cc2
VZ
72// for an empty string, GetStringData() will return this address: this
73// structure has the same layout as wxStringData and it's data() method will
74// return the empty string (dummy pointer)
75static const struct
76{
77 wxStringData data;
2bb67b80 78 wxChar dummy;
223d09f6 79} g_strEmpty = { {-1, 0, 0}, wxT('\0') };
3c024cc2 80
c801d85f 81// empty C style string: points to 'string data' byte of g_strEmpty
fd242375 82extern const wxChar WXDLLIMPEXP_BASE *wxEmptyString = &g_strEmpty.dummy;
c801d85f 83
3168a13f 84// ----------------------------------------------------------------------------
c801d85f 85// global functions
3168a13f 86// ----------------------------------------------------------------------------
c801d85f 87
a533f5c1 88#if defined(wxSTD_STRING_COMPATIBILITY) && wxUSE_STD_IOSTREAM
c801d85f
KB
89
90// MS Visual C++ version 5.0 provides the new STL headers as well as the old
91// iostream ones.
92//
93// ATTN: you can _not_ use both of these in the same program!
a38b83c3 94
dd107c50 95wxSTD istream& operator>>(wxSTD istream& is, wxString& WXUNUSED(str))
c801d85f
KB
96{
97#if 0
98 int w = is.width(0);
99 if ( is.ipfx(0) ) {
3f4a0c5b 100 streambuf *sb = is.rdbuf();
c801d85f
KB
101 str.erase();
102 while ( true ) {
103 int ch = sb->sbumpc ();
104 if ( ch == EOF ) {
3f4a0c5b 105 is.setstate(ios::eofbit);
c801d85f
KB
106 break;
107 }
108 else if ( isspace(ch) ) {
109 sb->sungetc();
110 break;
111 }
dd1eaa89 112
c801d85f
KB
113 str += ch;
114 if ( --w == 1 )
115 break;
116 }
117 }
118
119 is.isfx();
120 if ( str.length() == 0 )
3f4a0c5b 121 is.setstate(ios::failbit);
c801d85f
KB
122#endif
123 return is;
124}
125
dd107c50 126wxSTD ostream& operator<<(wxSTD ostream& os, const wxString& str)
825ba8f0
SB
127{
128 os << str.c_str();
129 return os;
130}
131
c801d85f
KB
132#endif //std::string compatibility
133
3168a13f
VZ
134// ----------------------------------------------------------------------------
135// private classes
136// ----------------------------------------------------------------------------
137
138// this small class is used to gather statistics for performance tuning
139//#define WXSTRING_STATISTICS
140#ifdef WXSTRING_STATISTICS
141 class Averager
142 {
143 public:
f6f5941b 144 Averager(const wxChar *sz) { m_sz = sz; m_nTotal = m_nCount = 0; }
2c3b684c 145 ~Averager()
f6f5941b 146 { wxPrintf("wxString: average %s = %f\n", m_sz, ((float)m_nTotal)/m_nCount); }
3168a13f 147
c86f1403 148 void Add(size_t n) { m_nTotal += n; m_nCount++; }
3168a13f
VZ
149
150 private:
c86f1403 151 size_t m_nCount, m_nTotal;
f6f5941b 152 const wxChar *m_sz;
3168a13f
VZ
153 } g_averageLength("allocation size"),
154 g_averageSummandLength("summand length"),
155 g_averageConcatHit("hit probability in concat"),
156 g_averageInitialLength("initial string length");
157
158 #define STATISTICS_ADD(av, val) g_average##av.Add(val)
159#else
160 #define STATISTICS_ADD(av, val)
161#endif // WXSTRING_STATISTICS
162
ca5e07c7
GD
163// ===========================================================================
164// wxStringData class deallocation
165// ===========================================================================
166
8ecf21b7
GD
167#if defined(__VISUALC__) && defined(_MT) && !defined(_DLL)
168# pragma message (__FILE__ ": building with Multithreaded non DLL runtime has a performance impact on wxString!")
ca5e07c7
GD
169void wxStringData::Free()
170{
171 free(this);
172}
8ecf21b7 173#endif
ca5e07c7 174
c801d85f
KB
175// ===========================================================================
176// wxString class core
177// ===========================================================================
178
179// ---------------------------------------------------------------------------
180// construction
181// ---------------------------------------------------------------------------
182
c801d85f 183// constructs string of <nLength> copies of character <ch>
2bb67b80 184wxString::wxString(wxChar ch, size_t nLength)
c801d85f
KB
185{
186 Init();
187
188 if ( nLength > 0 ) {
b1801e0e
GD
189 if ( !AllocBuffer(nLength) ) {
190 wxFAIL_MSG( _T("out of memory in wxString::wxString") );
191 return;
192 }
f1da2f03 193
2bb67b80 194#if wxUSE_UNICODE
f6f5941b
VZ
195 // memset only works on chars
196 for ( size_t n = 0; n < nLength; n++ )
197 m_pchData[n] = ch;
2bb67b80 198#else
c801d85f 199 memset(m_pchData, ch, nLength);
2bb67b80 200#endif
c801d85f
KB
201 }
202}
203
204// takes nLength elements of psz starting at nPos
2bb67b80 205void wxString::InitWith(const wxChar *psz, size_t nPos, size_t nLength)
c801d85f
KB
206{
207 Init();
208
f6bcfd97
BP
209 // if the length is not given, assume the string to be NUL terminated
210 if ( nLength == wxSTRING_MAXLEN ) {
211 wxASSERT_MSG( nPos <= wxStrlen(psz), _T("index out of bounds") );
c801d85f 212
f6bcfd97
BP
213 nLength = wxStrlen(psz + nPos);
214 }
6c68273f 215
3168a13f
VZ
216 STATISTICS_ADD(InitialLength, nLength);
217
c801d85f
KB
218 if ( nLength > 0 ) {
219 // trailing '\0' is written in AllocBuffer()
b1801e0e
GD
220 if ( !AllocBuffer(nLength) ) {
221 wxFAIL_MSG( _T("out of memory in wxString::InitWith") );
222 return;
223 }
2bb67b80 224 memcpy(m_pchData, psz + nPos, nLength*sizeof(wxChar));
c801d85f
KB
225 }
226}
dd1eaa89 227
8de2e39c 228#ifdef wxSTD_STRING_COMPATIBILITY
c801d85f 229
c801d85f
KB
230// poor man's iterators are "void *" pointers
231wxString::wxString(const void *pStart, const void *pEnd)
232{
2bb67b80
OK
233 InitWith((const wxChar *)pStart, 0,
234 (const wxChar *)pEnd - (const wxChar *)pStart);
c801d85f
KB
235}
236
237#endif //std::string compatibility
238
2bb67b80
OK
239#if wxUSE_UNICODE
240
241// from multibyte string
cf2f341a 242wxString::wxString(const char *psz, wxMBConv& conv, size_t nLength)
2bb67b80 243{
2b5f62a0
VZ
244 // first get the size of the buffer we need
245 size_t nLen;
246 if ( psz )
247 {
251a8ce8 248 // calculate the needed size ourselves or use the provided one
2b5f62a0
VZ
249 nLen = nLength == wxSTRING_MAXLEN ? conv.MB2WC(NULL, psz, 0) : nLength;
250 }
251 else
252 {
253 // nothing to convert
254 nLen = 0;
255 }
2bb67b80 256
2b5f62a0
VZ
257 // anything to do?
258 if ( (nLen != 0) && (nLen != (size_t)-1) )
259 {
260 if ( !AllocBuffer(nLen) )
261 {
262 wxFAIL_MSG( _T("out of memory in wxString::wxString") );
2b5f62a0 263 }
50dee7e0 264 else
2b5f62a0 265 {
251a8ce8
VZ
266 // MB2WC wants the buffer size, not the string length hence +1
267 nLen = conv.MB2WC(m_pchData, psz, nLen + 1);
268
269 if ( nLen != (size_t)-1 )
50dee7e0 270 {
251a8ce8
VZ
271 // initialized ok, set the real length as nLength specified by
272 // the caller could be greater than the real string length
273 GetStringData()->nDataLength = nLen;
50dee7e0
VZ
274 m_pchData[nLen] = 0;
275 return;
276 }
277 //else: the conversion failed -- leave the string empty (what else?)
2b5f62a0 278 }
b1801e0e 279 }
2b5f62a0 280
2bb67b80 281 Init();
2bb67b80
OK
282}
283
e90c1d2a 284#else // ANSI
2bb67b80 285
0f3e3e0c 286#if wxUSE_WCHAR_T
c801d85f 287// from wide string
1c2e6a28 288wxString::wxString(const wchar_t *pwz, wxMBConv& conv, size_t nLength)
c801d85f 289{
2b5f62a0
VZ
290 // first get the size of the buffer we need
291 size_t nLen;
292 if ( pwz )
293 {
251a8ce8 294 // calculate the needed size ourselves or use the provided one
2b5f62a0
VZ
295 nLen = nLength == wxSTRING_MAXLEN ? conv.WC2MB(NULL, pwz, 0) : nLength;
296 }
1c2e6a28 297 else
2b5f62a0
VZ
298 {
299 // nothing to convert
300 nLen = 0;
301 }
c801d85f 302
2b5f62a0
VZ
303 // anything to do?
304 if ( (nLen != 0) && (nLen != (size_t)-1) )
305 {
306 if ( !AllocBuffer(nLen) )
307 {
308 wxFAIL_MSG( _T("out of memory in wxString::wxString") );
2b5f62a0 309 }
50dee7e0 310 else
2b5f62a0 311 {
50dee7e0
VZ
312 // WC2MB wants the buffer size, not the string length
313 if ( conv.WC2MB(m_pchData, pwz, nLen + 1) != (size_t)-1 )
314 {
315 // initialized ok
316 return;
317 }
318 //else: the conversion failed -- leave the string empty (what else?)
2b5f62a0 319 }
b1801e0e 320 }
2b5f62a0 321
c801d85f 322 Init();
c801d85f 323}
e90c1d2a 324#endif // wxUSE_WCHAR_T
c801d85f 325
e90c1d2a 326#endif // Unicode/ANSI
2bb67b80 327
c801d85f
KB
328// ---------------------------------------------------------------------------
329// memory allocation
330// ---------------------------------------------------------------------------
331
332// allocates memory needed to store a C string of length nLen
b1801e0e 333bool wxString::AllocBuffer(size_t nLen)
c801d85f 334{
13111b2a
VZ
335 // allocating 0 sized buffer doesn't make sense, all empty strings should
336 // reuse g_strEmpty
337 wxASSERT( nLen > 0 );
338
339 // make sure that we don't overflow
340 wxASSERT( nLen < (INT_MAX / sizeof(wxChar)) -
341 (sizeof(wxStringData) + EXTRA_ALLOC + 1) );
c801d85f 342
3168a13f
VZ
343 STATISTICS_ADD(Length, nLen);
344
c801d85f
KB
345 // allocate memory:
346 // 1) one extra character for '\0' termination
347 // 2) sizeof(wxStringData) for housekeeping info
3168a13f 348 wxStringData* pData = (wxStringData*)
2bb67b80 349 malloc(sizeof(wxStringData) + (nLen + EXTRA_ALLOC + 1)*sizeof(wxChar));
e015c2a3 350
b1801e0e
GD
351 if ( pData == NULL ) {
352 // allocation failures are handled by the caller
353 return FALSE;
354 }
e015c2a3 355
c801d85f 356 pData->nRefs = 1;
c801d85f 357 pData->nDataLength = nLen;
3168a13f 358 pData->nAllocLength = nLen + EXTRA_ALLOC;
c801d85f 359 m_pchData = pData->data(); // data starts after wxStringData
223d09f6 360 m_pchData[nLen] = wxT('\0');
b1801e0e 361 return TRUE;
c801d85f
KB
362}
363
c801d85f 364// must be called before changing this string
b1801e0e 365bool wxString::CopyBeforeWrite()
c801d85f
KB
366{
367 wxStringData* pData = GetStringData();
368
369 if ( pData->IsShared() ) {
370 pData->Unlock(); // memory not freed because shared
c86f1403 371 size_t nLen = pData->nDataLength;
b1801e0e
GD
372 if ( !AllocBuffer(nLen) ) {
373 // allocation failures are handled by the caller
374 return FALSE;
375 }
2bb67b80 376 memcpy(m_pchData, pData->data(), nLen*sizeof(wxChar));
c801d85f
KB
377 }
378
3bbb630a 379 wxASSERT( !GetStringData()->IsShared() ); // we must be the only owner
b1801e0e
GD
380
381 return TRUE;
c801d85f
KB
382}
383
384// must be called before replacing contents of this string
b1801e0e 385bool wxString::AllocBeforeWrite(size_t nLen)
c801d85f
KB
386{
387 wxASSERT( nLen != 0 ); // doesn't make any sense
388
389 // must not share string and must have enough space
3168a13f 390 wxStringData* pData = GetStringData();
fbf0c83d 391 if ( pData->IsShared() || pData->IsEmpty() ) {
c801d85f
KB
392 // can't work with old buffer, get new one
393 pData->Unlock();
b1801e0e
GD
394 if ( !AllocBuffer(nLen) ) {
395 // allocation failures are handled by the caller
396 return FALSE;
397 }
c801d85f 398 }
471aebdd 399 else {
fbf0c83d
VZ
400 if ( nLen > pData->nAllocLength ) {
401 // realloc the buffer instead of calling malloc() again, this is more
402 // efficient
403 STATISTICS_ADD(Length, nLen);
404
405 nLen += EXTRA_ALLOC;
406
fbf0c83d
VZ
407 pData = (wxStringData*)
408 realloc(pData, sizeof(wxStringData) + (nLen + 1)*sizeof(wxChar));
e015c2a3 409
b1801e0e
GD
410 if ( pData == NULL ) {
411 // allocation failures are handled by the caller
412 // keep previous data since reallocation failed
413 return FALSE;
fbf0c83d
VZ
414 }
415
416 pData->nAllocLength = nLen;
417 m_pchData = pData->data();
418 }
419
420 // now we have enough space, just update the string length
471aebdd
VZ
421 pData->nDataLength = nLen;
422 }
c801d85f 423
f1da2f03 424 wxASSERT( !GetStringData()->IsShared() ); // we must be the only owner
b1801e0e
GD
425
426 return TRUE;
c801d85f
KB
427}
428
dd1eaa89 429// allocate enough memory for nLen characters
b1801e0e 430bool wxString::Alloc(size_t nLen)
dd1eaa89
VZ
431{
432 wxStringData *pData = GetStringData();
433 if ( pData->nAllocLength <= nLen ) {
9fbd8b8d
VZ
434 if ( pData->IsEmpty() ) {
435 nLen += EXTRA_ALLOC;
436
437 wxStringData* pData = (wxStringData*)
b1801e0e
GD
438 malloc(sizeof(wxStringData) + (nLen + 1)*sizeof(wxChar));
439
440 if ( pData == NULL ) {
441 // allocation failure handled by caller
442 return FALSE;
443 }
e015c2a3 444
9fbd8b8d
VZ
445 pData->nRefs = 1;
446 pData->nDataLength = 0;
447 pData->nAllocLength = nLen;
448 m_pchData = pData->data(); // data starts after wxStringData
223d09f6 449 m_pchData[0u] = wxT('\0');
9fbd8b8d 450 }
3168a13f
VZ
451 else if ( pData->IsShared() ) {
452 pData->Unlock(); // memory not freed because shared
c86f1403 453 size_t nOldLen = pData->nDataLength;
b1801e0e
GD
454 if ( !AllocBuffer(nLen) ) {
455 // allocation failure handled by caller
456 return FALSE;
457 }
2bb67b80 458 memcpy(m_pchData, pData->data(), nOldLen*sizeof(wxChar));
3168a13f 459 }
dd1eaa89 460 else {
3168a13f
VZ
461 nLen += EXTRA_ALLOC;
462
b1801e0e 463 pData = (wxStringData *)
2bb67b80 464 realloc(pData, sizeof(wxStringData) + (nLen + 1)*sizeof(wxChar));
3168a13f 465
b1801e0e
GD
466 if ( pData == NULL ) {
467 // allocation failure handled by caller
468 // keep previous data since reallocation failed
469 return FALSE;
dd1eaa89 470 }
3168a13f
VZ
471
472 // it's not important if the pointer changed or not (the check for this
473 // is not faster than assigning to m_pchData in all cases)
b1801e0e
GD
474 pData->nAllocLength = nLen;
475 m_pchData = pData->data();
dd1eaa89
VZ
476 }
477 }
478 //else: we've already got enough
b1801e0e 479 return TRUE;
dd1eaa89
VZ
480}
481
482// shrink to minimal size (releasing extra memory)
b1801e0e 483bool wxString::Shrink()
dd1eaa89
VZ
484{
485 wxStringData *pData = GetStringData();
3bbb630a 486
337a0010
VZ
487 size_t nLen = pData->nDataLength;
488 void *p = realloc(pData, sizeof(wxStringData) + (nLen + 1)*sizeof(wxChar));
489
b1801e0e
GD
490 if ( p == NULL) {
491 wxFAIL_MSG( _T("out of memory reallocating wxString data") );
492 // keep previous data since reallocation failed
493 return FALSE;
494 }
337a0010
VZ
495
496 if ( p != pData )
497 {
498 // contrary to what one might believe, some realloc() implementation do
499 // move the memory block even when its size is reduced
500 pData = (wxStringData *)p;
3bbb630a 501
337a0010
VZ
502 m_pchData = pData->data();
503 }
fbf0c83d 504
337a0010 505 pData->nAllocLength = nLen;
b1801e0e
GD
506
507 return TRUE;
dd1eaa89
VZ
508}
509
c801d85f 510// get the pointer to writable buffer of (at least) nLen bytes
2bb67b80 511wxChar *wxString::GetWriteBuf(size_t nLen)
c801d85f 512{
b1801e0e
GD
513 if ( !AllocBeforeWrite(nLen) ) {
514 // allocation failure handled by caller
515 return NULL;
516 }
097c080b
VZ
517
518 wxASSERT( GetStringData()->nRefs == 1 );
519 GetStringData()->Validate(FALSE);
520
c801d85f
KB
521 return m_pchData;
522}
523
097c080b
VZ
524// put string back in a reasonable state after GetWriteBuf
525void wxString::UngetWriteBuf()
526{
2bb67b80 527 GetStringData()->nDataLength = wxStrlen(m_pchData);
097c080b
VZ
528 GetStringData()->Validate(TRUE);
529}
530
8f06a017
RD
531void wxString::UngetWriteBuf(size_t nLen)
532{
533 GetStringData()->nDataLength = nLen;
534 GetStringData()->Validate(TRUE);
535}
536
c801d85f
KB
537// ---------------------------------------------------------------------------
538// data access
539// ---------------------------------------------------------------------------
540
541// all functions are inline in string.h
542
543// ---------------------------------------------------------------------------
544// assignment operators
545// ---------------------------------------------------------------------------
546
dd1eaa89 547// helper function: does real copy
b1801e0e 548bool wxString::AssignCopy(size_t nSrcLen, const wxChar *pszSrcData)
c801d85f
KB
549{
550 if ( nSrcLen == 0 ) {
551 Reinit();
552 }
553 else {
b1801e0e
GD
554 if ( !AllocBeforeWrite(nSrcLen) ) {
555 // allocation failure handled by caller
556 return FALSE;
557 }
2bb67b80 558 memcpy(m_pchData, pszSrcData, nSrcLen*sizeof(wxChar));
c801d85f 559 GetStringData()->nDataLength = nSrcLen;
223d09f6 560 m_pchData[nSrcLen] = wxT('\0');
c801d85f 561 }
b1801e0e 562 return TRUE;
c801d85f
KB
563}
564
565// assigns one string to another
566wxString& wxString::operator=(const wxString& stringSrc)
567{
097c080b
VZ
568 wxASSERT( stringSrc.GetStringData()->IsValid() );
569
c801d85f
KB
570 // don't copy string over itself
571 if ( m_pchData != stringSrc.m_pchData ) {
572 if ( stringSrc.GetStringData()->IsEmpty() ) {
573 Reinit();
574 }
575 else {
576 // adjust references
577 GetStringData()->Unlock();
578 m_pchData = stringSrc.m_pchData;
579 GetStringData()->Lock();
580 }
581 }
582
583 return *this;
584}
585
586// assigns a single character
2bb67b80 587wxString& wxString::operator=(wxChar ch)
c801d85f 588{
b1801e0e
GD
589 if ( !AssignCopy(1, &ch) ) {
590 wxFAIL_MSG( _T("out of memory in wxString::operator=(wxChar)") );
591 }
c801d85f
KB
592 return *this;
593}
594
a3291804 595
c801d85f 596// assigns C string
2bb67b80 597wxString& wxString::operator=(const wxChar *psz)
c801d85f 598{
b1801e0e
GD
599 if ( !AssignCopy(wxStrlen(psz), psz) ) {
600 wxFAIL_MSG( _T("out of memory in wxString::operator=(const wxChar *)") );
601 }
c801d85f
KB
602 return *this;
603}
604
2bb67b80
OK
605#if !wxUSE_UNICODE
606
c801d85f
KB
607// same as 'signed char' variant
608wxString& wxString::operator=(const unsigned char* psz)
609{
610 *this = (const char *)psz;
611 return *this;
612}
613
0f3e3e0c 614#if wxUSE_WCHAR_T
c801d85f
KB
615wxString& wxString::operator=(const wchar_t *pwz)
616{
617 wxString str(pwz);
618 *this = str;
619 return *this;
620}
0f3e3e0c 621#endif
c801d85f 622
2bb67b80
OK
623#endif
624
c801d85f
KB
625// ---------------------------------------------------------------------------
626// string concatenation
627// ---------------------------------------------------------------------------
628
c801d85f 629// add something to this string
083f7497 630bool wxString::ConcatSelf(size_t nSrcLen, const wxChar *pszSrcData)
c801d85f 631{
3168a13f 632 STATISTICS_ADD(SummandLength, nSrcLen);
c801d85f 633
05488905
VZ
634 // concatenating an empty string is a NOP
635 if ( nSrcLen > 0 ) {
636 wxStringData *pData = GetStringData();
637 size_t nLen = pData->nDataLength;
638 size_t nNewLen = nLen + nSrcLen;
c801d85f 639
05488905
VZ
640 // alloc new buffer if current is too small
641 if ( pData->IsShared() ) {
642 STATISTICS_ADD(ConcatHit, 0);
3168a13f 643
05488905
VZ
644 // we have to allocate another buffer
645 wxStringData* pOldData = GetStringData();
b1801e0e
GD
646 if ( !AllocBuffer(nNewLen) ) {
647 // allocation failure handled by caller
648 return FALSE;
649 }
2bb67b80 650 memcpy(m_pchData, pOldData->data(), nLen*sizeof(wxChar));
05488905
VZ
651 pOldData->Unlock();
652 }
653 else if ( nNewLen > pData->nAllocLength ) {
654 STATISTICS_ADD(ConcatHit, 0);
3168a13f 655
05488905 656 // we have to grow the buffer
b1801e0e
GD
657 if ( !Alloc(nNewLen) ) {
658 // allocation failure handled by caller
659 return FALSE;
660 }
05488905
VZ
661 }
662 else {
663 STATISTICS_ADD(ConcatHit, 1);
3168a13f 664
05488905
VZ
665 // the buffer is already big enough
666 }
3168a13f 667
05488905
VZ
668 // should be enough space
669 wxASSERT( nNewLen <= GetStringData()->nAllocLength );
3168a13f 670
05488905 671 // fast concatenation - all is done in our buffer
2bb67b80 672 memcpy(m_pchData + nLen, pszSrcData, nSrcLen*sizeof(wxChar));
3168a13f 673
223d09f6 674 m_pchData[nNewLen] = wxT('\0'); // put terminating '\0'
05488905
VZ
675 GetStringData()->nDataLength = nNewLen; // and fix the length
676 }
677 //else: the string to append was empty
b1801e0e 678 return TRUE;
c801d85f
KB
679}
680
681/*
c801d85f
KB
682 * concatenation functions come in 5 flavours:
683 * string + string
684 * char + string and string + char
685 * C str + string and string + C str
686 */
687
b1801e0e 688wxString operator+(const wxString& str1, const wxString& str2)
c801d85f 689{
b1801e0e
GD
690 wxASSERT( str1.GetStringData()->IsValid() );
691 wxASSERT( str2.GetStringData()->IsValid() );
097c080b 692
b1801e0e
GD
693 wxString s = str1;
694 s += str2;
3168a13f 695
c801d85f
KB
696 return s;
697}
698
b1801e0e 699wxString operator+(const wxString& str, wxChar ch)
c801d85f 700{
b1801e0e 701 wxASSERT( str.GetStringData()->IsValid() );
3168a13f 702
b1801e0e 703 wxString s = str;
3168a13f 704 s += ch;
097c080b 705
c801d85f
KB
706 return s;
707}
708
b1801e0e 709wxString operator+(wxChar ch, const wxString& str)
c801d85f 710{
b1801e0e 711 wxASSERT( str.GetStringData()->IsValid() );
097c080b 712
3168a13f 713 wxString s = ch;
b1801e0e 714 s += str;
3168a13f 715
c801d85f
KB
716 return s;
717}
718
b1801e0e 719wxString operator+(const wxString& str, const wxChar *psz)
c801d85f 720{
b1801e0e 721 wxASSERT( str.GetStringData()->IsValid() );
097c080b 722
c801d85f 723 wxString s;
b1801e0e
GD
724 if ( !s.Alloc(wxStrlen(psz) + str.Len()) ) {
725 wxFAIL_MSG( _T("out of memory in wxString::operator+") );
726 }
727 s = str;
3168a13f
VZ
728 s += psz;
729
c801d85f
KB
730 return s;
731}
732
b1801e0e 733wxString operator+(const wxChar *psz, const wxString& str)
c801d85f 734{
b1801e0e 735 wxASSERT( str.GetStringData()->IsValid() );
097c080b 736
c801d85f 737 wxString s;
b1801e0e
GD
738 if ( !s.Alloc(wxStrlen(psz) + str.Len()) ) {
739 wxFAIL_MSG( _T("out of memory in wxString::operator+") );
740 }
3168a13f 741 s = psz;
b1801e0e 742 s += str;
3168a13f 743
c801d85f
KB
744 return s;
745}
746
747// ===========================================================================
748// other common string functions
749// ===========================================================================
750
b1ac3b56 751#if wxUSE_UNICODE
e015c2a3
VZ
752
753wxString wxString::FromAscii(const char *ascii)
b1ac3b56
RR
754{
755 if (!ascii)
756 return wxEmptyString;
e015c2a3 757
b1ac3b56
RR
758 size_t len = strlen( ascii );
759 wxString res;
e015c2a3
VZ
760
761 if ( len )
762 {
763 wxStringBuffer buf(res, len);
764
765 wchar_t *dest = buf;
766
767 for ( ;; )
768 {
769 if ( (*dest++ = (wchar_t)(unsigned char)*ascii++) == L'\0' )
770 break;
771 }
772 }
773
b1ac3b56
RR
774 return res;
775}
776
2b5f62a0
VZ
777wxString wxString::FromAscii(const char ascii)
778{
779 // What do we do with '\0' ?
780
781 wxString res;
782 res += (wchar_t)(unsigned char) ascii;
8760bc65 783
2b5f62a0
VZ
784 return res;
785}
786
b1ac3b56
RR
787const wxCharBuffer wxString::ToAscii() const
788{
e015c2a3
VZ
789 // this will allocate enough space for the terminating NUL too
790 wxCharBuffer buffer(length());
b1ac3b56 791
e015c2a3
VZ
792 signed char *dest = (signed char *)buffer.data();
793
794 const wchar_t *pwc = c_str();
795 for ( ;; )
b1ac3b56 796 {
e015c2a3
VZ
797 *dest++ = *pwc > SCHAR_MAX ? '_' : *pwc;
798
799 // the output string can't have embedded NULs anyhow, so we can safely
800 // stop at first of them even if we do have any
801 if ( !*pwc++ )
802 break;
b1ac3b56 803 }
e015c2a3 804
b1ac3b56
RR
805 return buffer;
806}
e015c2a3
VZ
807
808#endif // Unicode
b1ac3b56 809
c801d85f
KB
810// ---------------------------------------------------------------------------
811// simple sub-string extraction
812// ---------------------------------------------------------------------------
813
814// helper function: clone the data attached to this string
b1801e0e 815bool wxString::AllocCopy(wxString& dest, int nCopyLen, int nCopyIndex) const
c801d85f 816{
3168a13f 817 if ( nCopyLen == 0 ) {
c801d85f
KB
818 dest.Init();
819 }
3168a13f 820 else {
b1801e0e
GD
821 if ( !dest.AllocBuffer(nCopyLen) ) {
822 // allocation failure handled by caller
823 return FALSE;
824 }
2bb67b80 825 memcpy(dest.m_pchData, m_pchData + nCopyIndex, nCopyLen*sizeof(wxChar));
c801d85f 826 }
b1801e0e 827 return TRUE;
c801d85f
KB
828}
829
830// extract string of length nCount starting at nFirst
c801d85f
KB
831wxString wxString::Mid(size_t nFirst, size_t nCount) const
832{
30d9011f
VZ
833 wxStringData *pData = GetStringData();
834 size_t nLen = pData->nDataLength;
835
566b84d2
VZ
836 // default value of nCount is wxSTRING_MAXLEN and means "till the end"
837 if ( nCount == wxSTRING_MAXLEN )
30d9011f
VZ
838 {
839 nCount = nLen - nFirst;
840 }
841
c801d85f 842 // out-of-bounds requests return sensible things
30d9011f
VZ
843 if ( nFirst + nCount > nLen )
844 {
845 nCount = nLen - nFirst;
846 }
c801d85f 847
30d9011f
VZ
848 if ( nFirst > nLen )
849 {
850 // AllocCopy() will return empty string
c801d85f 851 nCount = 0;
30d9011f 852 }
c801d85f
KB
853
854 wxString dest;
b1801e0e
GD
855 if ( !AllocCopy(dest, nCount, nFirst) ) {
856 wxFAIL_MSG( _T("out of memory in wxString::Mid") );
857 }
30d9011f 858
c801d85f
KB
859 return dest;
860}
861
f6bcfd97
BP
862// check that the tring starts with prefix and return the rest of the string
863// in the provided pointer if it is not NULL, otherwise return FALSE
864bool wxString::StartsWith(const wxChar *prefix, wxString *rest) const
865{
866 wxASSERT_MSG( prefix, _T("invalid parameter in wxString::StartsWith") );
867
868 // first check if the beginning of the string matches the prefix: note
869 // that we don't have to check that we don't run out of this string as
870 // when we reach the terminating NUL, either prefix string ends too (and
871 // then it's ok) or we break out of the loop because there is no match
872 const wxChar *p = c_str();
873 while ( *prefix )
874 {
875 if ( *prefix++ != *p++ )
876 {
877 // no match
878 return FALSE;
879 }
880 }
881
882 if ( rest )
883 {
884 // put the rest of the string into provided pointer
885 *rest = p;
886 }
887
888 return TRUE;
889}
890
c801d85f
KB
891// extract nCount last (rightmost) characters
892wxString wxString::Right(size_t nCount) const
893{
894 if ( nCount > (size_t)GetStringData()->nDataLength )
895 nCount = GetStringData()->nDataLength;
896
897 wxString dest;
b1801e0e
GD
898 if ( !AllocCopy(dest, nCount, GetStringData()->nDataLength - nCount) ) {
899 wxFAIL_MSG( _T("out of memory in wxString::Right") );
900 }
c801d85f
KB
901 return dest;
902}
903
904// get all characters after the last occurence of ch
905// (returns the whole string if ch not found)
2bb67b80 906wxString wxString::AfterLast(wxChar ch) const
c801d85f
KB
907{
908 wxString str;
909 int iPos = Find(ch, TRUE);
3c67202d 910 if ( iPos == wxNOT_FOUND )
c801d85f
KB
911 str = *this;
912 else
c8cfb486 913 str = c_str() + iPos + 1;
c801d85f
KB
914
915 return str;
916}
917
918// extract nCount first (leftmost) characters
919wxString wxString::Left(size_t nCount) const
920{
921 if ( nCount > (size_t)GetStringData()->nDataLength )
922 nCount = GetStringData()->nDataLength;
923
924 wxString dest;
b1801e0e
GD
925 if ( !AllocCopy(dest, nCount, 0) ) {
926 wxFAIL_MSG( _T("out of memory in wxString::Left") );
927 }
c801d85f
KB
928 return dest;
929}
930
931// get all characters before the first occurence of ch
932// (returns the whole string if ch not found)
2bb67b80 933wxString wxString::BeforeFirst(wxChar ch) const
c801d85f
KB
934{
935 wxString str;
223d09f6 936 for ( const wxChar *pc = m_pchData; *pc != wxT('\0') && *pc != ch; pc++ )
c801d85f
KB
937 str += *pc;
938
939 return str;
940}
941
942/// get all characters before the last occurence of ch
943/// (returns empty string if ch not found)
2bb67b80 944wxString wxString::BeforeLast(wxChar ch) const
c801d85f
KB
945{
946 wxString str;
947 int iPos = Find(ch, TRUE);
3c67202d 948 if ( iPos != wxNOT_FOUND && iPos != 0 )
d1c9bbf6 949 str = wxString(c_str(), iPos);
c801d85f
KB
950
951 return str;
952}
953
954/// get all characters after the first occurence of ch
955/// (returns empty string if ch not found)
2bb67b80 956wxString wxString::AfterFirst(wxChar ch) const
c801d85f
KB
957{
958 wxString str;
959 int iPos = Find(ch);
3c67202d 960 if ( iPos != wxNOT_FOUND )
c801d85f
KB
961 str = c_str() + iPos + 1;
962
963 return str;
964}
965
966// replace first (or all) occurences of some substring with another one
a8f1f1b2
VZ
967size_t
968wxString::Replace(const wxChar *szOld, const wxChar *szNew, bool bReplaceAll)
c801d85f 969{
a8f1f1b2
VZ
970 // if we tried to replace an empty string we'd enter an infinite loop below
971 wxCHECK_MSG( szOld && *szOld && szNew, 0,
972 _T("wxString::Replace(): invalid parameter") );
973
c86f1403 974 size_t uiCount = 0; // count of replacements made
c801d85f 975
2bb67b80 976 size_t uiOldLen = wxStrlen(szOld);
c801d85f
KB
977
978 wxString strTemp;
2bb67b80
OK
979 const wxChar *pCurrent = m_pchData;
980 const wxChar *pSubstr;
223d09f6 981 while ( *pCurrent != wxT('\0') ) {
2bb67b80 982 pSubstr = wxStrstr(pCurrent, szOld);
c801d85f
KB
983 if ( pSubstr == NULL ) {
984 // strTemp is unused if no replacements were made, so avoid the copy
985 if ( uiCount == 0 )
986 return 0;
987
988 strTemp += pCurrent; // copy the rest
989 break; // exit the loop
990 }
991 else {
992 // take chars before match
b1801e0e
GD
993 if ( !strTemp.ConcatSelf(pSubstr - pCurrent, pCurrent) ) {
994 wxFAIL_MSG( _T("out of memory in wxString::Replace") );
995 return 0;
996 }
c801d85f
KB
997 strTemp += szNew;
998 pCurrent = pSubstr + uiOldLen; // restart after match
999
1000 uiCount++;
1001
1002 // stop now?
1003 if ( !bReplaceAll ) {
1004 strTemp += pCurrent; // copy the rest
1005 break; // exit the loop
1006 }
1007 }
1008 }
1009
1010 // only done if there were replacements, otherwise would have returned above
1011 *this = strTemp;
1012
1013 return uiCount;
1014}
1015
4676948b
JS
1016#ifdef __WXWINCE__
1017inline int isascii(wxChar c) { return (c >= 0) && (c <=127); }
1018#endif
1019
c801d85f
KB
1020bool wxString::IsAscii() const
1021{
2bb67b80 1022 const wxChar *s = (const wxChar*) *this;
c801d85f 1023 while(*s){
b1e4e7cc 1024 if(!isascii(*s)) return(FALSE);
c801d85f
KB
1025 s++;
1026 }
1027 return(TRUE);
1028}
dd1eaa89 1029
c801d85f
KB
1030bool wxString::IsWord() const
1031{
2bb67b80 1032 const wxChar *s = (const wxChar*) *this;
c801d85f 1033 while(*s){
2bb67b80 1034 if(!wxIsalpha(*s)) return(FALSE);
c801d85f
KB
1035 s++;
1036 }
1037 return(TRUE);
1038}
dd1eaa89 1039
c801d85f
KB
1040bool wxString::IsNumber() const
1041{
2bb67b80 1042 const wxChar *s = (const wxChar*) *this;
2f74ed28
GT
1043 if (wxStrlen(s))
1044 if ((s[0] == '-') || (s[0] == '+')) s++;
c801d85f 1045 while(*s){
2bb67b80 1046 if(!wxIsdigit(*s)) return(FALSE);
c801d85f
KB
1047 s++;
1048 }
1049 return(TRUE);
1050}
1051
c801d85f
KB
1052wxString wxString::Strip(stripType w) const
1053{
1054 wxString s = *this;
1055 if ( w & leading ) s.Trim(FALSE);
1056 if ( w & trailing ) s.Trim(TRUE);
1057 return s;
1058}
1059
c801d85f
KB
1060// ---------------------------------------------------------------------------
1061// case conversion
1062// ---------------------------------------------------------------------------
1063
1064wxString& wxString::MakeUpper()
1065{
b1801e0e
GD
1066 if ( !CopyBeforeWrite() ) {
1067 wxFAIL_MSG( _T("out of memory in wxString::MakeUpper") );
1068 return *this;
1069 }
e015c2a3 1070
2bb67b80
OK
1071 for ( wxChar *p = m_pchData; *p; p++ )
1072 *p = (wxChar)wxToupper(*p);
c801d85f
KB
1073
1074 return *this;
1075}
1076
1077wxString& wxString::MakeLower()
1078{
b1801e0e
GD
1079 if ( !CopyBeforeWrite() ) {
1080 wxFAIL_MSG( _T("out of memory in wxString::MakeLower") );
1081 return *this;
1082 }
dd1eaa89 1083
2bb67b80
OK
1084 for ( wxChar *p = m_pchData; *p; p++ )
1085 *p = (wxChar)wxTolower(*p);
c801d85f
KB
1086
1087 return *this;
1088}
1089
1090// ---------------------------------------------------------------------------
1091// trimming and padding
1092// ---------------------------------------------------------------------------
1093
576c608d
VZ
1094// some compilers (VC++ 6.0 not to name them) return TRUE for a call to
1095