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