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