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