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