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