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