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