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