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