]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/common/string.cpp
fixed wxBase compilation (what was msgdlg.h doing in wxchar.cpp?)
[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// ----------------------------------------------------------------------------
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; }
200 ~Averager()
201 { printf("wxString: average %s = %f\n", m_sz, ((float)m_nTotal)/m_nCount); }
202
203 void Add(size_t n) { m_nTotal += n; m_nCount++; }
204
205 private:
206 size_t m_nCount, m_nTotal;
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
218// ===========================================================================
219// wxString class core
220// ===========================================================================
221
222// ---------------------------------------------------------------------------
223// construction
224// ---------------------------------------------------------------------------
225
226// constructs string of <nLength> copies of character <ch>
227wxString::wxString(wxChar ch, size_t nLength)
228{
229 Init();
230
231 if ( nLength > 0 ) {
232 if ( !AllocBuffer(nLength) ) {
233 wxFAIL_MSG( _T("out of memory in wxString::wxString") );
234 return;
235 }
236
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
241 memset(m_pchData, ch, nLength);
242#endif
243 }
244}
245
246// takes nLength elements of psz starting at nPos
247void wxString::InitWith(const wxChar *psz, size_t nPos, size_t nLength)
248{
249 Init();
250
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") );
254
255 nLength = wxStrlen(psz + nPos);
256 }
257
258 STATISTICS_ADD(InitialLength, nLength);
259
260 if ( nLength > 0 ) {
261 // trailing '\0' is written in AllocBuffer()
262 if ( !AllocBuffer(nLength) ) {
263 wxFAIL_MSG( _T("out of memory in wxString::InitWith") );
264 return;
265 }
266 memcpy(m_pchData, psz + nPos, nLength*sizeof(wxChar));
267 }
268}
269
270#ifdef wxSTD_STRING_COMPATIBILITY
271
272// poor man's iterators are "void *" pointers
273wxString::wxString(const void *pStart, const void *pEnd)
274{
275 InitWith((const wxChar *)pStart, 0,
276 (const wxChar *)pEnd - (const wxChar *)pStart);
277}
278
279#endif //std::string compatibility
280
281#if wxUSE_UNICODE
282
283// from multibyte string
284wxString::wxString(const char *psz, wxMBConv& conv, size_t nLength)
285{
286 // first get necessary size
287 size_t nLen = psz ? conv.MB2WC((wchar_t *) NULL, psz, 0) : 0;
288
289 // nLength is number of *Unicode* characters here!
290 if ((nLen != (size_t)-1) && (nLen > nLength))
291 nLen = nLength;
292
293 // empty?
294 if ( (nLen != 0) && (nLen != (size_t)-1) ) {
295 if ( !AllocBuffer(nLen) ) {
296 wxFAIL_MSG( _T("out of memory in wxString::wxString") );
297 return;
298 }
299 conv.MB2WC(m_pchData, psz, nLen);
300 }
301 else {
302 Init();
303 }
304}
305
306#else // ANSI
307
308#if wxUSE_WCHAR_T
309// from wide string
310wxString::wxString(const wchar_t *pwz, wxMBConv& conv, size_t nLength)
311{
312 // first get necessary size
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 }
321
322 // empty?
323 if ( (nLen != 0) && (nLen != (size_t)-1) ) {
324 if ( !AllocBuffer(nLen) ) {
325 wxFAIL_MSG( _T("out of memory in wxString::wxString") );
326 return;
327 }
328 conv.WC2MB(m_pchData, pwz, nLen);
329 }
330 else {
331 Init();
332 }
333}
334#endif // wxUSE_WCHAR_T
335
336#endif // Unicode/ANSI
337
338// ---------------------------------------------------------------------------
339// memory allocation
340// ---------------------------------------------------------------------------
341
342// allocates memory needed to store a C string of length nLen
343bool wxString::AllocBuffer(size_t nLen)
344{
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) );
352
353 STATISTICS_ADD(Length, nLen);
354
355 // allocate memory:
356 // 1) one extra character for '\0' termination
357 // 2) sizeof(wxStringData) for housekeeping info
358 wxStringData* pData = (wxStringData*)
359 malloc(sizeof(wxStringData) + (nLen + EXTRA_ALLOC + 1)*sizeof(wxChar));
360
361 if ( pData == NULL ) {
362 // allocation failures are handled by the caller
363 return FALSE;
364 }
365
366 pData->nRefs = 1;
367 pData->nDataLength = nLen;
368 pData->nAllocLength = nLen + EXTRA_ALLOC;
369 m_pchData = pData->data(); // data starts after wxStringData
370 m_pchData[nLen] = wxT('\0');
371 return TRUE;
372}
373
374// must be called before changing this string
375bool wxString::CopyBeforeWrite()
376{
377 wxStringData* pData = GetStringData();
378
379 if ( pData->IsShared() ) {
380 pData->Unlock(); // memory not freed because shared
381 size_t nLen = pData->nDataLength;
382 if ( !AllocBuffer(nLen) ) {
383 // allocation failures are handled by the caller
384 return FALSE;
385 }
386 memcpy(m_pchData, pData->data(), nLen*sizeof(wxChar));
387 }
388
389 wxASSERT( !GetStringData()->IsShared() ); // we must be the only owner
390
391 return TRUE;
392}
393
394// must be called before replacing contents of this string
395bool wxString::AllocBeforeWrite(size_t nLen)
396{
397 wxASSERT( nLen != 0 ); // doesn't make any sense
398
399 // must not share string and must have enough space
400 wxStringData* pData = GetStringData();
401 if ( pData->IsShared() || pData->IsEmpty() ) {
402 // can't work with old buffer, get new one
403 pData->Unlock();
404 if ( !AllocBuffer(nLen) ) {
405 // allocation failures are handled by the caller
406 return FALSE;
407 }
408 }
409 else {
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
417 pData = (wxStringData*)
418 realloc(pData, sizeof(wxStringData) + (nLen + 1)*sizeof(wxChar));
419
420 if ( pData == NULL ) {
421 // allocation failures are handled by the caller
422 // keep previous data since reallocation failed
423 return FALSE;
424 }
425
426 pData->nAllocLength = nLen;
427 m_pchData = pData->data();
428 }
429
430 // now we have enough space, just update the string length
431 pData->nDataLength = nLen;
432 }
433
434 wxASSERT( !GetStringData()->IsShared() ); // we must be the only owner
435
436 return TRUE;
437}
438
439// allocate enough memory for nLen characters
440bool wxString::Alloc(size_t nLen)
441{
442 wxStringData *pData = GetStringData();
443 if ( pData->nAllocLength <= nLen ) {
444 if ( pData->IsEmpty() ) {
445 nLen += EXTRA_ALLOC;
446
447 wxStringData* pData = (wxStringData*)
448 malloc(sizeof(wxStringData) + (nLen + 1)*sizeof(wxChar));
449
450 if ( pData == NULL ) {
451 // allocation failure handled by caller
452 return FALSE;
453 }
454
455 pData->nRefs = 1;
456 pData->nDataLength = 0;
457 pData->nAllocLength = nLen;
458 m_pchData = pData->data(); // data starts after wxStringData
459 m_pchData[0u] = wxT('\0');
460 }
461 else if ( pData->IsShared() ) {
462 pData->Unlock(); // memory not freed because shared
463 size_t nOldLen = pData->nDataLength;
464 if ( !AllocBuffer(nLen) ) {
465 // allocation failure handled by caller
466 return FALSE;
467 }
468 memcpy(m_pchData, pData->data(), nOldLen*sizeof(wxChar));
469 }
470 else {
471 nLen += EXTRA_ALLOC;
472
473 pData = (wxStringData *)
474 realloc(pData, sizeof(wxStringData) + (nLen + 1)*sizeof(wxChar));
475
476 if ( pData == NULL ) {
477 // allocation failure handled by caller
478 // keep previous data since reallocation failed
479 return FALSE;
480 }
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)
484 pData->nAllocLength = nLen;
485 m_pchData = pData->data();
486 }
487 }
488 //else: we've already got enough
489 return TRUE;
490}
491
492// shrink to minimal size (releasing extra memory)
493bool wxString::Shrink()
494{
495 wxStringData *pData = GetStringData();
496
497 size_t nLen = pData->nDataLength;
498 void *p = realloc(pData, sizeof(wxStringData) + (nLen + 1)*sizeof(wxChar));
499
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 }
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;
511
512 m_pchData = pData->data();
513 }
514
515 pData->nAllocLength = nLen;
516
517 return TRUE;
518}
519
520// get the pointer to writable buffer of (at least) nLen bytes
521wxChar *wxString::GetWriteBuf(size_t nLen)
522{
523 if ( !AllocBeforeWrite(nLen) ) {
524 // allocation failure handled by caller
525 return NULL;
526 }
527
528 wxASSERT( GetStringData()->nRefs == 1 );
529 GetStringData()->Validate(FALSE);
530
531 return m_pchData;
532}
533
534// put string back in a reasonable state after GetWriteBuf
535void wxString::UngetWriteBuf()
536{
537 GetStringData()->nDataLength = wxStrlen(m_pchData);
538 GetStringData()->Validate(TRUE);
539}
540
541void wxString::UngetWriteBuf(size_t nLen)
542{
543 GetStringData()->nDataLength = nLen;
544 GetStringData()->Validate(TRUE);
545}
546
547// ---------------------------------------------------------------------------
548// data access
549// ---------------------------------------------------------------------------
550
551// all functions are inline in string.h
552
553// ---------------------------------------------------------------------------
554// assignment operators
555// ---------------------------------------------------------------------------
556
557// helper function: does real copy
558bool wxString::AssignCopy(size_t nSrcLen, const wxChar *pszSrcData)
559{
560 if ( nSrcLen == 0 ) {
561 Reinit();
562 }
563 else {
564 if ( !AllocBeforeWrite(nSrcLen) ) {
565 // allocation failure handled by caller
566 return FALSE;
567 }
568 memcpy(m_pchData, pszSrcData, nSrcLen*sizeof(wxChar));
569 GetStringData()->nDataLength = nSrcLen;
570 m_pchData[nSrcLen] = wxT('\0');
571 }
572 return TRUE;
573}
574
575// assigns one string to another
576wxString& wxString::operator=(const wxString& stringSrc)
577{
578 wxASSERT( stringSrc.GetStringData()->IsValid() );
579
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
597wxString& wxString::operator=(wxChar ch)
598{
599 if ( !AssignCopy(1, &ch) ) {
600 wxFAIL_MSG( _T("out of memory in wxString::operator=(wxChar)") );
601 }
602 return *this;
603}
604
605
606// assigns C string
607wxString& wxString::operator=(const wxChar *psz)
608{
609 if ( !AssignCopy(wxStrlen(psz), psz) ) {
610 wxFAIL_MSG( _T("out of memory in wxString::operator=(const wxChar *)") );
611 }
612 return *this;
613}
614
615#if !wxUSE_UNICODE
616
617// same as 'signed char' variant
618wxString& wxString::operator=(const unsigned char* psz)
619{
620 *this = (const char *)psz;
621 return *this;
622}
623
624#if wxUSE_WCHAR_T
625wxString& wxString::operator=(const wchar_t *pwz)
626{
627 wxString str(pwz);
628 *this = str;
629 return *this;
630}
631#endif
632
633#endif
634
635// ---------------------------------------------------------------------------
636// string concatenation
637// ---------------------------------------------------------------------------
638
639// add something to this string
640bool wxString::ConcatSelf(int nSrcLen, const wxChar *pszSrcData)
641{
642 STATISTICS_ADD(SummandLength, nSrcLen);
643
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;
649
650 // alloc new buffer if current is too small
651 if ( pData->IsShared() ) {
652 STATISTICS_ADD(ConcatHit, 0);
653
654 // we have to allocate another buffer
655 wxStringData* pOldData = GetStringData();
656 if ( !AllocBuffer(nNewLen) ) {
657 // allocation failure handled by caller
658 return FALSE;
659 }
660 memcpy(m_pchData, pOldData->data(), nLen*sizeof(wxChar));
661 pOldData->Unlock();
662 }
663 else if ( nNewLen > pData->nAllocLength ) {
664 STATISTICS_ADD(ConcatHit, 0);
665
666 // we have to grow the buffer
667 if ( !Alloc(nNewLen) ) {
668 // allocation failure handled by caller
669 return FALSE;
670 }
671 }
672 else {
673 STATISTICS_ADD(ConcatHit, 1);
674
675 // the buffer is already big enough
676 }
677
678 // should be enough space
679 wxASSERT( nNewLen <= GetStringData()->nAllocLength );
680
681 // fast concatenation - all is done in our buffer
682 memcpy(m_pchData + nLen, pszSrcData, nSrcLen*sizeof(wxChar));
683
684 m_pchData[nNewLen] = wxT('\0'); // put terminating '\0'
685 GetStringData()->nDataLength = nNewLen; // and fix the length
686 }
687 //else: the string to append was empty
688 return TRUE;
689}
690
691/*
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
698wxString operator+(const wxString& str1, const wxString& str2)
699{
700 wxASSERT( str1.GetStringData()->IsValid() );
701 wxASSERT( str2.GetStringData()->IsValid() );
702
703 wxString s = str1;
704 s += str2;
705
706 return s;
707}
708
709wxString operator+(const wxString& str, wxChar ch)
710{
711 wxASSERT( str.GetStringData()->IsValid() );
712
713 wxString s = str;
714 s += ch;
715
716 return s;
717}
718
719wxString operator+(wxChar ch, const wxString& str)
720{
721 wxASSERT( str.GetStringData()->IsValid() );
722
723 wxString s = ch;
724 s += str;
725
726 return s;
727}
728
729wxString operator+(const wxString& str, const wxChar *psz)
730{
731 wxASSERT( str.GetStringData()->IsValid() );
732
733 wxString s;
734 if ( !s.Alloc(wxStrlen(psz) + str.Len()) ) {
735 wxFAIL_MSG( _T("out of memory in wxString::operator+") );
736 }
737 s = str;
738 s += psz;
739
740 return s;
741}
742
743wxString operator+(const wxChar *psz, const wxString& str)
744{
745 wxASSERT( str.GetStringData()->IsValid() );
746
747 wxString s;
748 if ( !s.Alloc(wxStrlen(psz) + str.Len()) ) {
749 wxFAIL_MSG( _T("out of memory in wxString::operator+") );
750 }
751 s = psz;
752 s += str;
753
754 return s;
755}
756
757// ===========================================================================
758// other common string functions
759// ===========================================================================
760
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
800// ---------------------------------------------------------------------------
801// simple sub-string extraction
802// ---------------------------------------------------------------------------
803
804// helper function: clone the data attached to this string
805bool wxString::AllocCopy(wxString& dest, int nCopyLen, int nCopyIndex) const
806{
807 if ( nCopyLen == 0 ) {
808 dest.Init();
809 }
810 else {
811 if ( !dest.AllocBuffer(nCopyLen) ) {
812 // allocation failure handled by caller
813 return FALSE;
814 }
815 memcpy(dest.m_pchData, m_pchData + nCopyIndex, nCopyLen*sizeof(wxChar));
816 }
817 return TRUE;
818}
819
820// extract string of length nCount starting at nFirst
821wxString wxString::Mid(size_t nFirst, size_t nCount) const
822{
823 wxStringData *pData = GetStringData();
824 size_t nLen = pData->nDataLength;
825
826 // default value of nCount is wxSTRING_MAXLEN and means "till the end"
827 if ( nCount == wxSTRING_MAXLEN )
828 {
829 nCount = nLen - nFirst;
830 }
831
832 // out-of-bounds requests return sensible things
833 if ( nFirst + nCount > nLen )
834 {
835 nCount = nLen - nFirst;
836 }
837
838 if ( nFirst > nLen )
839 {
840 // AllocCopy() will return empty string
841 nCount = 0;
842 }
843
844 wxString dest;
845 if ( !AllocCopy(dest, nCount, nFirst) ) {
846 wxFAIL_MSG( _T("out of memory in wxString::Mid") );
847 }
848
849 return dest;
850}
851
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
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;
888 if ( !AllocCopy(dest, nCount, GetStringData()->nDataLength - nCount) ) {
889 wxFAIL_MSG( _T("out of memory in wxString::Right") );
890 }
891 return dest;
892}
893
894// get all characters after the last occurence of ch
895// (returns the whole string if ch not found)
896wxString wxString::AfterLast(wxChar ch) const
897{
898 wxString str;
899 int iPos = Find(ch, TRUE);
900 if ( iPos == wxNOT_FOUND )
901 str = *this;
902 else
903 str = c_str() + iPos + 1;
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;
915 if ( !AllocCopy(dest, nCount, 0) ) {
916 wxFAIL_MSG( _T("out of memory in wxString::Left") );
917 }
918 return dest;
919}
920
921// get all characters before the first occurence of ch
922// (returns the whole string if ch not found)
923wxString wxString::BeforeFirst(wxChar ch) const
924{
925 wxString str;
926 for ( const wxChar *pc = m_pchData; *pc != wxT('\0') && *pc != ch; pc++ )
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)
934wxString wxString::BeforeLast(wxChar ch) const
935{
936 wxString str;
937 int iPos = Find(ch, TRUE);
938 if ( iPos != wxNOT_FOUND && iPos != 0 )
939 str = wxString(c_str(), iPos);
940
941 return str;
942}
943
944/// get all characters after the first occurence of ch
945/// (returns empty string if ch not found)
946wxString wxString::AfterFirst(wxChar ch) const
947{
948 wxString str;
949 int iPos = Find(ch);
950 if ( iPos != wxNOT_FOUND )
951 str = c_str() + iPos + 1;
952
953 return str;
954}
955
956// replace first (or all) occurences of some substring with another one
957size_t wxString::Replace(const wxChar *szOld, const wxChar *szNew, bool bReplaceAll)
958{
959 size_t uiCount = 0; // count of replacements made
960
961 size_t uiOldLen = wxStrlen(szOld);
962
963 wxString strTemp;
964 const wxChar *pCurrent = m_pchData;
965 const wxChar *pSubstr;
966 while ( *pCurrent != wxT('\0') ) {
967 pSubstr = wxStrstr(pCurrent, szOld);
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
978 if ( !strTemp.ConcatSelf(pSubstr - pCurrent, pCurrent) ) {
979 wxFAIL_MSG( _T("out of memory in wxString::Replace") );
980 return 0;
981 }
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{
1003 const wxChar *s = (const wxChar*) *this;
1004 while(*s){
1005 if(!isascii(*s)) return(FALSE);
1006 s++;
1007 }
1008 return(TRUE);
1009}
1010
1011bool wxString::IsWord() const
1012{
1013 const wxChar *s = (const wxChar*) *this;
1014 while(*s){
1015 if(!wxIsalpha(*s)) return(FALSE);
1016 s++;
1017 }
1018 return(TRUE);
1019}
1020
1021bool wxString::IsNumber() const
1022{
1023 const wxChar *s = (const wxChar*) *this;
1024 if (wxStrlen(s))
1025 if ((s[0] == '-') || (s[0] == '+')) s++;
1026 while(*s){
1027 if(!wxIsdigit(*s)) return(FALSE);
1028 s++;
1029 }
1030 return(TRUE);
1031}
1032
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
1041// ---------------------------------------------------------------------------
1042// case conversion
1043// ---------------------------------------------------------------------------
1044
1045wxString& wxString::MakeUpper()
1046{
1047 if ( !CopyBeforeWrite() ) {
1048 wxFAIL_MSG( _T("out of memory in wxString::MakeUpper") );
1049 return *this;
1050 }
1051
1052 for ( wxChar *p = m_pchData; *p; p++ )
1053 *p = (wxChar)wxToupper(*p);
1054
1055 return *this;
1056}
1057
1058wxString& wxString::MakeLower()
1059{
1060 if ( !CopyBeforeWrite() ) {
1061 wxFAIL_MSG( _T("out of memory in wxString::MakeLower") );
1062 return *this;
1063 }
1064
1065 for ( wxChar *p = m_pchData; *p; p++ )
1066 *p = (wxChar)wxTolower(*p);
1067
1068 return *this;
1069}
1070
1071// ---------------------------------------------------------------------------
1072// trimming and padding
1073// ---------------------------------------------------------------------------
1074
1075// some compilers (VC++ 6.0 not to name them) return TRUE for a call to
1076