]> git.saurik.com Git - wxWidgets.git/blame - src/common/string.cpp
Applied patch [ 619386 ] uxtheme.dll support
[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
e90c1d2a 82extern const wxChar WXDLLEXPORT *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 {
248 // calculate the needed size ourselves or use a provide one
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") );
263 return;
264 }
2bb67b80 265
2b5f62a0
VZ
266 // MB2WC wants the buffer size, not the string length
267 if ( conv.MB2WC(m_pchData, psz, nLen + 1) != (size_t)-1 )
268 {
269 // initialized ok
270 return;
271 }
272 //else: the conversion failed -- leave the string empty (what else?)
b1801e0e 273 }
2b5f62a0 274
2bb67b80 275 Init();
2bb67b80
OK
276}
277
e90c1d2a 278#else // ANSI
2bb67b80 279
0f3e3e0c 280#if wxUSE_WCHAR_T
c801d85f 281// from wide string
1c2e6a28 282wxString::wxString(const wchar_t *pwz, wxMBConv& conv, size_t nLength)
c801d85f 283{
2b5f62a0
VZ
284 // first get the size of the buffer we need
285 size_t nLen;
286 if ( pwz )
287 {
288 // calculate the needed size ourselves or use a provide one
289 nLen = nLength == wxSTRING_MAXLEN ? conv.WC2MB(NULL, pwz, 0) : nLength;
290 }
1c2e6a28 291 else
2b5f62a0
VZ
292 {
293 // nothing to convert
294 nLen = 0;
295 }
c801d85f 296
2b5f62a0
VZ
297 // anything to do?
298 if ( (nLen != 0) && (nLen != (size_t)-1) )
299 {
300 if ( !AllocBuffer(nLen) )
301 {
302 wxFAIL_MSG( _T("out of memory in wxString::wxString") );
303 return;
304 }
305
306 // WC2MB wants the buffer size, not the string length
307 if ( conv.WC2MB(m_pchData, pwz, nLen + 1) != (size_t)-1 )
308 {
309 // initialized ok
310 return;
311 }
312 //else: the conversion failed -- leave the string empty (what else?)
b1801e0e 313 }
2b5f62a0 314
c801d85f 315 Init();
c801d85f 316}
e90c1d2a 317#endif // wxUSE_WCHAR_T
c801d85f 318
e90c1d2a 319#endif // Unicode/ANSI
2bb67b80 320
c801d85f
KB
321// ---------------------------------------------------------------------------
322// memory allocation
323// ---------------------------------------------------------------------------
324
325// allocates memory needed to store a C string of length nLen
b1801e0e 326bool wxString::AllocBuffer(size_t nLen)
c801d85f 327{
13111b2a
VZ
328 // allocating 0 sized buffer doesn't make sense, all empty strings should
329 // reuse g_strEmpty
330 wxASSERT( nLen > 0 );
331
332 // make sure that we don't overflow
333 wxASSERT( nLen < (INT_MAX / sizeof(wxChar)) -
334 (sizeof(wxStringData) + EXTRA_ALLOC + 1) );
c801d85f 335
3168a13f
VZ
336 STATISTICS_ADD(Length, nLen);
337
c801d85f
KB
338 // allocate memory:
339 // 1) one extra character for '\0' termination
340 // 2) sizeof(wxStringData) for housekeeping info
3168a13f 341 wxStringData* pData = (wxStringData*)
2bb67b80 342 malloc(sizeof(wxStringData) + (nLen + EXTRA_ALLOC + 1)*sizeof(wxChar));
e015c2a3 343
b1801e0e
GD
344 if ( pData == NULL ) {
345 // allocation failures are handled by the caller
346 return FALSE;
347 }
e015c2a3 348
c801d85f 349 pData->nRefs = 1;
c801d85f 350 pData->nDataLength = nLen;
3168a13f 351 pData->nAllocLength = nLen + EXTRA_ALLOC;
c801d85f 352 m_pchData = pData->data(); // data starts after wxStringData
223d09f6 353 m_pchData[nLen] = wxT('\0');
b1801e0e 354 return TRUE;
c801d85f
KB
355}
356
c801d85f 357// must be called before changing this string
b1801e0e 358bool wxString::CopyBeforeWrite()
c801d85f
KB
359{
360 wxStringData* pData = GetStringData();
361
362 if ( pData->IsShared() ) {
363 pData->Unlock(); // memory not freed because shared
c86f1403 364 size_t nLen = pData->nDataLength;
b1801e0e
GD
365 if ( !AllocBuffer(nLen) ) {
366 // allocation failures are handled by the caller
367 return FALSE;
368 }
2bb67b80 369 memcpy(m_pchData, pData->data(), nLen*sizeof(wxChar));
c801d85f
KB
370 }
371
3bbb630a 372 wxASSERT( !GetStringData()->IsShared() ); // we must be the only owner
b1801e0e
GD
373
374 return TRUE;
c801d85f
KB
375}
376
377// must be called before replacing contents of this string
b1801e0e 378bool wxString::AllocBeforeWrite(size_t nLen)
c801d85f
KB
379{
380 wxASSERT( nLen != 0 ); // doesn't make any sense
381
382 // must not share string and must have enough space
3168a13f 383 wxStringData* pData = GetStringData();
fbf0c83d 384 if ( pData->IsShared() || pData->IsEmpty() ) {
c801d85f
KB
385 // can't work with old buffer, get new one
386 pData->Unlock();
b1801e0e
GD
387 if ( !AllocBuffer(nLen) ) {
388 // allocation failures are handled by the caller
389 return FALSE;
390 }
c801d85f 391 }
471aebdd 392 else {
fbf0c83d
VZ
393 if ( nLen > pData->nAllocLength ) {
394 // realloc the buffer instead of calling malloc() again, this is more
395 // efficient
396 STATISTICS_ADD(Length, nLen);
397
398 nLen += EXTRA_ALLOC;
399
fbf0c83d
VZ
400 pData = (wxStringData*)
401 realloc(pData, sizeof(wxStringData) + (nLen + 1)*sizeof(wxChar));
e015c2a3 402
b1801e0e
GD
403 if ( pData == NULL ) {
404 // allocation failures are handled by the caller
405 // keep previous data since reallocation failed
406 return FALSE;
fbf0c83d
VZ
407 }
408
409 pData->nAllocLength = nLen;
410 m_pchData = pData->data();
411 }
412
413 // now we have enough space, just update the string length
471aebdd
VZ
414 pData->nDataLength = nLen;
415 }
c801d85f 416
f1da2f03 417 wxASSERT( !GetStringData()->IsShared() ); // we must be the only owner
b1801e0e
GD
418
419 return TRUE;
c801d85f
KB
420}
421
dd1eaa89 422// allocate enough memory for nLen characters
b1801e0e 423bool wxString::Alloc(size_t nLen)
dd1eaa89
VZ
424{
425 wxStringData *pData = GetStringData();
426 if ( pData->nAllocLength <= nLen ) {
9fbd8b8d
VZ
427 if ( pData->IsEmpty() ) {
428 nLen += EXTRA_ALLOC;
429
430 wxStringData* pData = (wxStringData*)
b1801e0e
GD
431 malloc(sizeof(wxStringData) + (nLen + 1)*sizeof(wxChar));
432
433 if ( pData == NULL ) {
434 // allocation failure handled by caller
435 return FALSE;
436 }
e015c2a3 437
9fbd8b8d
VZ
438 pData->nRefs = 1;
439 pData->nDataLength = 0;
440 pData->nAllocLength = nLen;
441 m_pchData = pData->data(); // data starts after wxStringData
223d09f6 442 m_pchData[0u] = wxT('\0');
9fbd8b8d 443 }
3168a13f
VZ
444 else if ( pData->IsShared() ) {
445 pData->Unlock(); // memory not freed because shared
c86f1403 446 size_t nOldLen = pData->nDataLength;
b1801e0e
GD
447 if ( !AllocBuffer(nLen) ) {
448 // allocation failure handled by caller
449 return FALSE;
450 }
2bb67b80 451 memcpy(m_pchData, pData->data(), nOldLen*sizeof(wxChar));
3168a13f 452 }
dd1eaa89 453 else {
3168a13f
VZ
454 nLen += EXTRA_ALLOC;
455
b1801e0e 456 pData = (wxStringData *)
2bb67b80 457 realloc(pData, sizeof(wxStringData) + (nLen + 1)*sizeof(wxChar));
3168a13f 458
b1801e0e
GD
459 if ( pData == NULL ) {
460 // allocation failure handled by caller
461 // keep previous data since reallocation failed
462 return FALSE;
dd1eaa89 463 }
3168a13f
VZ
464
465 // it's not important if the pointer changed or not (the check for this
466 // is not faster than assigning to m_pchData in all cases)
b1801e0e
GD
467 pData->nAllocLength = nLen;
468 m_pchData = pData->data();
dd1eaa89
VZ
469 }
470 }
471 //else: we've already got enough
b1801e0e 472 return TRUE;
dd1eaa89
VZ
473}
474
475// shrink to minimal size (releasing extra memory)
b1801e0e 476bool wxString::Shrink()
dd1eaa89
VZ
477{
478 wxStringData *pData = GetStringData();
3bbb630a 479
337a0010
VZ
480 size_t nLen = pData->nDataLength;
481 void *p = realloc(pData, sizeof(wxStringData) + (nLen + 1)*sizeof(wxChar));
482
b1801e0e
GD
483 if ( p == NULL) {
484 wxFAIL_MSG( _T("out of memory reallocating wxString data") );
485 // keep previous data since reallocation failed
486 return FALSE;
487 }
337a0010
VZ
488
489 if ( p != pData )
490 {
491 // contrary to what one might believe, some realloc() implementation do
492 // move the memory block even when its size is reduced
493 pData = (wxStringData *)p;
3bbb630a 494
337a0010
VZ
495 m_pchData = pData->data();
496 }
fbf0c83d 497
337a0010 498 pData->nAllocLength = nLen;
b1801e0e
GD
499
500 return TRUE;
dd1eaa89
VZ
501}
502
c801d85f 503// get the pointer to writable buffer of (at least) nLen bytes
2bb67b80 504wxChar *wxString::GetWriteBuf(size_t nLen)
c801d85f 505{
b1801e0e
GD
506 if ( !AllocBeforeWrite(nLen) ) {
507 // allocation failure handled by caller
508 return NULL;
509 }
097c080b
VZ
510
511 wxASSERT( GetStringData()->nRefs == 1 );
512 GetStringData()->Validate(FALSE);
513
c801d85f
KB
514 return m_pchData;
515}
516
097c080b
VZ
517// put string back in a reasonable state after GetWriteBuf
518void wxString::UngetWriteBuf()
519{
2bb67b80 520 GetStringData()->nDataLength = wxStrlen(m_pchData);
097c080b
VZ
521 GetStringData()->Validate(TRUE);
522}
523
8f06a017
RD
524void wxString::UngetWriteBuf(size_t nLen)
525{
526 GetStringData()->nDataLength = nLen;
527 GetStringData()->Validate(TRUE);
528}
529
c801d85f
KB
530// ---------------------------------------------------------------------------
531// data access
532// ---------------------------------------------------------------------------
533
534// all functions are inline in string.h
535
536// ---------------------------------------------------------------------------
537// assignment operators
538// ---------------------------------------------------------------------------
539
dd1eaa89 540// helper function: does real copy
b1801e0e 541bool wxString::AssignCopy(size_t nSrcLen, const wxChar *pszSrcData)
c801d85f
KB
542{
543 if ( nSrcLen == 0 ) {
544 Reinit();
545 }
546 else {
b1801e0e
GD
547 if ( !AllocBeforeWrite(nSrcLen) ) {
548 // allocation failure handled by caller
549 return FALSE;
550 }
2bb67b80 551 memcpy(m_pchData, pszSrcData, nSrcLen*sizeof(wxChar));
c801d85f 552 GetStringData()->nDataLength = nSrcLen;
223d09f6 553 m_pchData[nSrcLen] = wxT('\0');
c801d85f 554 }
b1801e0e 555 return TRUE;
c801d85f
KB
556}
557
558// assigns one string to another
559wxString& wxString::operator=(const wxString& stringSrc)
560{
097c080b
VZ
561 wxASSERT( stringSrc.GetStringData()->IsValid() );
562
c801d85f
KB
563 // don't copy string over itself
564 if ( m_pchData != stringSrc.m_pchData ) {
565 if ( stringSrc.GetStringData()->IsEmpty() ) {
566 Reinit();
567 }
568 else {
569 // adjust references
570 GetStringData()->Unlock();
571 m_pchData = stringSrc.m_pchData;
572 GetStringData()->Lock();
573 }
574 }
575
576 return *this;
577}
578
579// assigns a single character
2bb67b80 580wxString& wxString::operator=(wxChar ch)
c801d85f 581{
b1801e0e
GD
582 if ( !AssignCopy(1, &ch) ) {
583 wxFAIL_MSG( _T("out of memory in wxString::operator=(wxChar)") );
584 }
c801d85f
KB
585 return *this;
586}
587
a3291804 588
c801d85f 589// assigns C string
2bb67b80 590wxString& wxString::operator=(const wxChar *psz)
c801d85f 591{
b1801e0e
GD
592 if ( !AssignCopy(wxStrlen(psz), psz) ) {
593 wxFAIL_MSG( _T("out of memory in wxString::operator=(const wxChar *)") );
594 }
c801d85f
KB
595 return *this;
596}
597
2bb67b80
OK
598#if !wxUSE_UNICODE
599
c801d85f
KB
600// same as 'signed char' variant
601wxString& wxString::operator=(const unsigned char* psz)
602{
603 *this = (const char *)psz;
604 return *this;
605}
606
0f3e3e0c 607#if wxUSE_WCHAR_T
c801d85f
KB
608wxString& wxString::operator=(const wchar_t *pwz)
609{
610 wxString str(pwz);
611 *this = str;
612 return *this;
613}
0f3e3e0c 614#endif
c801d85f 615
2bb67b80
OK
616#endif
617
c801d85f
KB
618// ---------------------------------------------------------------------------
619// string concatenation
620// ---------------------------------------------------------------------------
621
c801d85f 622// add something to this string
083f7497 623bool wxString::ConcatSelf(size_t nSrcLen, const wxChar *pszSrcData)
c801d85f 624{
3168a13f 625 STATISTICS_ADD(SummandLength, nSrcLen);
c801d85f 626
05488905
VZ
627 // concatenating an empty string is a NOP
628 if ( nSrcLen > 0 ) {
629 wxStringData *pData = GetStringData();
630 size_t nLen = pData->nDataLength;
631 size_t nNewLen = nLen + nSrcLen;
c801d85f 632
05488905
VZ
633 // alloc new buffer if current is too small
634 if ( pData->IsShared() ) {
635 STATISTICS_ADD(ConcatHit, 0);
3168a13f 636
05488905
VZ
637 // we have to allocate another buffer
638 wxStringData* pOldData = GetStringData();
b1801e0e
GD
639 if ( !AllocBuffer(nNewLen) ) {
640 // allocation failure handled by caller
641 return FALSE;
642 }
2bb67b80 643 memcpy(m_pchData, pOldData->data(), nLen*sizeof(wxChar));
05488905
VZ
644 pOldData->Unlock();
645 }
646 else if ( nNewLen > pData->nAllocLength ) {
647 STATISTICS_ADD(ConcatHit, 0);
3168a13f 648
05488905 649 // we have to grow the buffer
b1801e0e
GD
650 if ( !Alloc(nNewLen) ) {
651 // allocation failure handled by caller
652 return FALSE;
653 }
05488905
VZ
654 }
655 else {
656 STATISTICS_ADD(ConcatHit, 1);
3168a13f 657
05488905
VZ
658 // the buffer is already big enough
659 }
3168a13f 660
05488905
VZ
661 // should be enough space
662 wxASSERT( nNewLen <= GetStringData()->nAllocLength );
3168a13f 663
05488905 664 // fast concatenation - all is done in our buffer
2bb67b80 665 memcpy(m_pchData + nLen, pszSrcData, nSrcLen*sizeof(wxChar));
3168a13f 666
223d09f6 667 m_pchData[nNewLen] = wxT('\0'); // put terminating '\0'
05488905
VZ
668 GetStringData()->nDataLength = nNewLen; // and fix the length
669 }
670 //else: the string to append was empty
b1801e0e 671 return TRUE;
c801d85f
KB
672}
673
674/*
c801d85f
KB
675 * concatenation functions come in 5 flavours:
676 * string + string
677 * char + string and string + char
678 * C str + string and string + C str
679 */
680
b1801e0e 681wxString operator+(const wxString& str1, const wxString& str2)
c801d85f 682{
b1801e0e
GD
683 wxASSERT( str1.GetStringData()->IsValid() );
684 wxASSERT( str2.GetStringData()->IsValid() );
097c080b 685
b1801e0e
GD
686 wxString s = str1;
687 s += str2;
3168a13f 688
c801d85f
KB
689 return s;
690}
691
b1801e0e 692wxString operator+(const wxString& str, wxChar ch)
c801d85f 693{
b1801e0e 694 wxASSERT( str.GetStringData()->IsValid() );
3168a13f 695
b1801e0e 696 wxString s = str;
3168a13f 697 s += ch;
097c080b 698
c801d85f
KB
699 return s;
700}
701
b1801e0e 702wxString operator+(wxChar ch, const wxString& str)
c801d85f 703{
b1801e0e 704 wxASSERT( str.GetStringData()->IsValid() );
097c080b 705
3168a13f 706 wxString s = ch;
b1801e0e 707 s += str;
3168a13f 708
c801d85f
KB
709 return s;
710}
711
b1801e0e 712wxString operator+(const wxString& str, const wxChar *psz)
c801d85f 713{
b1801e0e 714 wxASSERT( str.GetStringData()->IsValid() );
097c080b 715
c801d85f 716 wxString s;
b1801e0e
GD
717 if ( !s.Alloc(wxStrlen(psz) + str.Len()) ) {
718 wxFAIL_MSG( _T("out of memory in wxString::operator+") );
719 }
720 s = str;
3168a13f
VZ
721 s += psz;
722
c801d85f
KB
723 return s;
724}
725
b1801e0e 726wxString operator+(const wxChar *psz, const wxString& str)
c801d85f 727{
b1801e0e 728 wxASSERT( str.GetStringData()->IsValid() );
097c080b 729
c801d85f 730 wxString s;
b1801e0e
GD
731 if ( !s.Alloc(wxStrlen(psz) + str.Len()) ) {
732 wxFAIL_MSG( _T("out of memory in wxString::operator+") );
733 }
3168a13f 734 s = psz;
b1801e0e 735 s += str;
3168a13f 736
c801d85f
KB
737 return s;
738}
739
740// ===========================================================================
741// other common string functions
742// ===========================================================================
743
b1ac3b56 744#if wxUSE_UNICODE
e015c2a3
VZ
745
746wxString wxString::FromAscii(const char *ascii)
b1ac3b56
RR
747{
748 if (!ascii)
749 return wxEmptyString;
e015c2a3 750
b1ac3b56
RR
751 size_t len = strlen( ascii );
752 wxString res;
e015c2a3
VZ
753
754 if ( len )
755 {
756 wxStringBuffer buf(res, len);
757
758 wchar_t *dest = buf;
759
760 for ( ;; )
761 {
762 if ( (*dest++ = (wchar_t)(unsigned char)*ascii++) == L'\0' )
763 break;
764 }
765 }
766
b1ac3b56
RR
767 return res;
768}
769
2b5f62a0
VZ
770wxString wxString::FromAscii(const char ascii)
771{
772 // What do we do with '\0' ?
773
774 wxString res;
775 res += (wchar_t)(unsigned char) ascii;
776
777 return res;
778}
779
b1ac3b56
RR
780const wxCharBuffer wxString::ToAscii() const
781{
e015c2a3
VZ
782 // this will allocate enough space for the terminating NUL too
783 wxCharBuffer buffer(length());
b1ac3b56 784
e015c2a3
VZ
785 signed char *dest = (signed char *)buffer.data();
786
787 const wchar_t *pwc = c_str();
788 for ( ;; )
b1ac3b56 789 {
e015c2a3
VZ
790 *dest++ = *pwc > SCHAR_MAX ? '_' : *pwc;
791
792 // the output string can't have embedded NULs anyhow, so we can safely
793 // stop at first of them even if we do have any
794 if ( !*pwc++ )
795 break;
b1ac3b56 796 }
e015c2a3 797
b1ac3b56
RR
798 return buffer;
799}
e015c2a3
VZ
800
801#endif // Unicode
b1ac3b56 802
c801d85f
KB
803// ---------------------------------------------------------------------------
804// simple sub-string extraction
805// ---------------------------------------------------------------------------
806
807// helper function: clone the data attached to this string
b1801e0e 808bool wxString::AllocCopy(wxString& dest, int nCopyLen, int nCopyIndex) const
c801d85f 809{
3168a13f 810 if ( nCopyLen == 0 ) {
c801d85f
KB
811 dest.Init();
812 }
3168a13f 813 else {
b1801e0e
GD
814 if ( !dest.AllocBuffer(nCopyLen) ) {
815 // allocation failure handled by caller
816 return FALSE;
817 }
2bb67b80 818 memcpy(dest.m_pchData, m_pchData + nCopyIndex, nCopyLen*sizeof(wxChar));
c801d85f 819 }
b1801e0e 820 return TRUE;
c801d85f
KB
821}
822
823// extract string of length nCount starting at nFirst
c801d85f
KB
824wxString wxString::Mid(size_t nFirst, size_t nCount) const
825{
30d9011f
VZ
826 wxStringData *pData = GetStringData();
827 size_t nLen = pData->nDataLength;
828
566b84d2
VZ
829 // default value of nCount is wxSTRING_MAXLEN and means "till the end"
830 if ( nCount == wxSTRING_MAXLEN )
30d9011f
VZ
831 {
832 nCount = nLen - nFirst;
833 }
834
c801d85f 835 // out-of-bounds requests return sensible things
30d9011f
VZ
836 if ( nFirst + nCount > nLen )
837 {
838 nCount = nLen - nFirst;
839 }
c801d85f 840
30d9011f
VZ
841 if ( nFirst > nLen )
842 {
843 // AllocCopy() will return empty string
c801d85f 844 nCount = 0;
30d9011f 845 }
c801d85f
KB
846
847 wxString dest;
b1801e0e
GD
848 if ( !AllocCopy(dest, nCount, nFirst) ) {
849 wxFAIL_MSG( _T("out of memory in wxString::Mid") );
850 }
30d9011f 851
c801d85f
KB
852 return dest;
853}
854
f6bcfd97
BP
855// check that the tring starts with prefix and return the rest of the string
856// in the provided pointer if it is not NULL, otherwise return FALSE
857bool wxString::StartsWith(const wxChar *prefix, wxString *rest) const
858{
859 wxASSERT_MSG( prefix, _T("invalid parameter in wxString::StartsWith") );
860
861 // first check if the beginning of the string matches the prefix: note
862 // that we don't have to check that we don't run out of this string as
863 // when we reach the terminating NUL, either prefix string ends too (and
864 // then it's ok) or we break out of the loop because there is no match
865 const wxChar *p = c_str();
866 while ( *prefix )
867 {
868 if ( *prefix++ != *p++ )
869 {
870 // no match
871 return FALSE;
872 }
873 }
874
875 if ( rest )
876 {
877 // put the rest of the string into provided pointer
878 *rest = p;
879 }
880
881 return TRUE;
882}
883
c801d85f
KB
884// extract nCount last (rightmost) characters
885wxString wxString::Right(size_t nCount) const
886{
887 if ( nCount > (size_t)GetStringData()->nDataLength )
888 nCount = GetStringData()->nDataLength;
889
890 wxString dest;
b1801e0e
GD
891 if ( !AllocCopy(dest, nCount, GetStringData()->nDataLength - nCount) ) {
892 wxFAIL_MSG( _T("out of memory in wxString::Right") );
893 }
c801d85f
KB
894 return dest;
895}
896
897// get all characters after the last occurence of ch
898// (returns the whole string if ch not found)
2bb67b80 899wxString wxString::AfterLast(wxChar ch) const
c801d85f
KB
900{
901 wxString str;
902 int iPos = Find(ch, TRUE);
3c67202d 903 if ( iPos == wxNOT_FOUND )
c801d85f
KB
904 str = *this;
905 else
c8cfb486 906 str = c_str() + iPos + 1;
c801d85f
KB
907
908 return str;
909}
910
911// extract nCount first (leftmost) characters
912wxString wxString::Left(size_t nCount) const
913{
914 if ( nCount > (size_t)GetStringData()->nDataLength )
915 nCount = GetStringData()->nDataLength;
916
917 wxString dest;
b1801e0e
GD
918 if ( !AllocCopy(dest, nCount, 0) ) {
919 wxFAIL_MSG( _T("out of memory in wxString::Left") );
920 }
c801d85f
KB
921 return dest;
922}
923
924// get all characters before the first occurence of ch
925// (returns the whole string if ch not found)
2bb67b80 926wxString wxString::BeforeFirst(wxChar ch) const
c801d85f
KB
927{
928 wxString str;
223d09f6 929 for ( const wxChar *pc = m_pchData; *pc != wxT('\0') && *pc != ch; pc++ )
c801d85f
KB
930 str += *pc;
931
932 return str;
933}
934
935/// get all characters before the last occurence of ch
936/// (returns empty string if ch not found)
2bb67b80 937wxString wxString::BeforeLast(wxChar ch) const
c801d85f
KB
938{
939 wxString str;
940 int iPos = Find(ch, TRUE);
3c67202d 941 if ( iPos != wxNOT_FOUND && iPos != 0 )
d1c9bbf6 942 str = wxString(c_str(), iPos);
c801d85f
KB
943
944 return str;
945}
946
947/// get all characters after the first occurence of ch
948/// (returns empty string if ch not found)
2bb67b80 949wxString wxString::AfterFirst(wxChar ch) const
c801d85f
KB
950{
951 wxString str;
952 int iPos = Find(ch);
3c67202d 953 if ( iPos != wxNOT_FOUND )
c801d85f
KB
954 str = c_str() + iPos + 1;
955
956 return str;
957}
958
959// replace first (or all) occurences of some substring with another one
2bb67b80 960size_t wxString::Replace(const wxChar *szOld, const wxChar *szNew, bool bReplaceAll)
c801d85f 961{
c86f1403 962 size_t uiCount = 0; // count of replacements made
c801d85f 963
2bb67b80 964 size_t uiOldLen = wxStrlen(szOld);
c801d85f
KB
965
966 wxString strTemp;
2bb67b80
OK
967 const wxChar *pCurrent = m_pchData;
968 const wxChar *pSubstr;
223d09f6 969 while ( *pCurrent != wxT('\0') ) {
2bb67b80 970 pSubstr = wxStrstr(pCurrent, szOld);
c801d85f
KB
971 if ( pSubstr == NULL ) {
972 // strTemp is unused if no replacements were made, so avoid the copy
973 if ( uiCount == 0 )
974 return 0;
975
976 strTemp += pCurrent; // copy the rest
977 break; // exit the loop
978 }
979 else {
980 // take chars before match
b1801e0e
GD
981 if ( !strTemp.ConcatSelf(pSubstr - pCurrent, pCurrent) ) {
982 wxFAIL_MSG( _T("out of memory in wxString::Replace") );
983 return 0;
984 }
c801d85f
KB
985 strTemp += szNew;
986 pCurrent = pSubstr + uiOldLen; // restart after match
987
988 uiCount++;
989
990 // stop now?
991 if ( !bReplaceAll ) {
992 strTemp += pCurrent; // copy the rest
993 break; // exit the loop
994 }
995 }
996 }
997
998 // only done if there were replacements, otherwise would have returned above
999 *this = strTemp;
1000
1001 return uiCount;
1002}
1003
1004bool wxString::IsAscii() const
1005{
2bb67b80 1006 const wxChar *s = (const wxChar*) *this;
c801d85f
KB
1007 while(*s){
1008 if(!isascii(*s)) return(FALSE);
1009 s++;
1010 }
1011 return(TRUE);
1012}
dd1eaa89 1013
c801d85f
KB
1014bool wxString::IsWord() const
1015{
2bb67b80 1016 const wxChar *s = (const wxChar*) *this;
c801d85f 1017 while(*s){
2bb67b80 1018 if(!wxIsalpha(*s)) return(FALSE);
c801d85f
KB
1019 s++;
1020 }
1021 return(TRUE);
1022}
dd1eaa89 1023
c801d85f
KB
1024bool wxString::IsNumber() const
1025{
2bb67b80 1026 const wxChar *s = (const wxChar*) *this;
2f74ed28
GT
1027 if (wxStrlen(s))
1028 if ((s[0] == '-') || (s[0] == '+')) s++;
c801d85f 1029 while(*s){
2bb67b80 1030 if(!wxIsdigit(*s)) return(FALSE);
c801d85f
KB
1031 s++;
1032 }
1033 return(TRUE);
1034}
1035
c801d85f
KB
1036wxString wxString::Strip(stripType w) const
1037{
1038 wxString s = *this;
1039 if ( w & leading ) s.Trim(FALSE);
1040 if ( w & trailing ) s.Trim(TRUE);
1041 return s;
1042}
1043
c801d85f
KB
1044// ---------------------------------------------------------------------------
1045// case conversion
1046// ---------------------------------------------------------------------------
1047
1048wxString& wxString::MakeUpper()
1049{
b1801e0e
GD
1050 if ( !CopyBeforeWrite() ) {
1051 wxFAIL_MSG( _T("out of memory in wxString::MakeUpper") );
1052 return *this;
1053 }
e015c2a3 1054
2bb67b80
OK
1055 for ( wxChar *p = m_pchData; *p; p++ )
1056 *p = (wxChar)wxToupper(*p);
c801d85f
KB
1057
1058 return *this;
1059}
1060
1061wxString& wxString::MakeLower()
1062{
b1801e0e
GD
1063 if ( !CopyBeforeWrite() ) {
1064 wxFAIL_MSG( _T("out of memory in wxString::MakeLower") );
1065 return *this;
1066 }
dd1eaa89 1067
2bb67b80
OK
1068 for ( wxChar *p = m_pchData; *p; p++ )
1069 *p = (wxChar)wxTolower(*p);
c801d85f
KB
1070
1071 return *this;
1072}
1073
1074// ---------------------------------------------------------------------------
1075// trimming and padding
1076// ---------------------------------------------------------------------------
1077
576c608d
VZ
1078// some compilers (VC++ 6.0 not to name them) return TRUE for a call to
1079