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