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