]> git.saurik.com Git - wxWidgets.git/blob - src/common/string.cpp
Corrected statements about wxString correctly handling
[wxWidgets.git] / src / common / string.cpp
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 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
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
61 const unsigned int wxSTRING_MAXLEN = UINT_MAX - 100;
62 #endif // Visual Age
63
64 #if !wxUSE_STL
65 const size_t wxStringBase::npos = wxSTRING_MAXLEN;
66 #endif
67
68 // ----------------------------------------------------------------------------
69 // static data
70 // ----------------------------------------------------------------------------
71
72 #if wxUSE_STL
73
74 extern const wxChar WXDLLIMPEXP_BASE *wxEmptyString = _T("");
75
76 #else
77
78 // for an empty string, GetStringData() will return this address: this
79 // structure has the same layout as wxStringData and it's data() method will
80 // return the empty string (dummy pointer)
81 static const struct
82 {
83 wxStringData data;
84 wxChar dummy;
85 } g_strEmpty = { {-1, 0, 0}, wxT('\0') };
86
87 // empty C style string: points to 'string data' byte of g_strEmpty
88 extern const wxChar WXDLLIMPEXP_BASE *wxEmptyString = &g_strEmpty.dummy;
89
90 #endif
91
92 // ----------------------------------------------------------------------------
93 // global functions
94 // ----------------------------------------------------------------------------
95
96 #if wxUSE_STD_IOSTREAM
97
98 // MS Visual C++ version 5.0 provides the new STL headers as well as the old
99 // iostream ones.
100 //
101 // ATTN: you can _not_ use both of these in the same program!
102
103 wxSTD istream& operator>>(wxSTD istream& is, wxString& WXUNUSED(str))
104 {
105 #if 0
106 int w = is.width(0);
107 if ( is.ipfx(0) ) {
108 streambuf *sb = is.rdbuf();
109 str.erase();
110 while ( true ) {
111 int ch = sb->sbumpc ();
112 if ( ch == EOF ) {
113 is.setstate(ios::eofbit);
114 break;
115 }
116 else if ( isspace(ch) ) {
117 sb->sungetc();
118 break;
119 }
120
121 str += ch;
122 if ( --w == 1 )
123 break;
124 }
125 }
126
127 is.isfx();
128 if ( str.length() == 0 )
129 is.setstate(ios::failbit);
130 #endif
131 return is;
132 }
133
134 wxSTD ostream& operator<<(wxSTD ostream& os, const wxString& str)
135 {
136 os << str.c_str();
137 return os;
138 }
139
140 #endif // wxUSE_STD_IOSTREAM
141
142 // ----------------------------------------------------------------------------
143 // private classes
144 // ----------------------------------------------------------------------------
145
146 // this small class is used to gather statistics for performance tuning
147 //#define WXSTRING_STATISTICS
148 #ifdef WXSTRING_STATISTICS
149 class Averager
150 {
151 public:
152 Averager(const wxChar *sz) { m_sz = sz; m_nTotal = m_nCount = 0; }
153 ~Averager()
154 { wxPrintf("wxString: average %s = %f\n", m_sz, ((float)m_nTotal)/m_nCount); }
155
156 void Add(size_t n) { m_nTotal += n; m_nCount++; }
157
158 private:
159 size_t m_nCount, m_nTotal;
160 const wxChar *m_sz;
161 } g_averageLength("allocation size"),
162 g_averageSummandLength("summand length"),
163 g_averageConcatHit("hit probability in concat"),
164 g_averageInitialLength("initial string length");
165
166 #define STATISTICS_ADD(av, val) g_average##av.Add(val)
167 #else
168 #define STATISTICS_ADD(av, val)
169 #endif // WXSTRING_STATISTICS
170
171 // ===========================================================================
172 // wxStringData class deallocation
173 // ===========================================================================
174
175 #if defined(__VISUALC__) && defined(_MT) && !defined(_DLL)
176 # pragma message (__FILE__ ": building with Multithreaded non DLL runtime has a performance impact on wxString!")
177 void wxStringData::Free()
178 {
179 free(this);
180 }
181 #endif
182
183 #if !wxUSE_STL
184
185 // ===========================================================================
186 // wxStringBase
187 // ===========================================================================
188
189 // takes nLength elements of psz starting at nPos
190 void wxStringBase::InitWith(const wxChar *psz, size_t nPos, size_t nLength)
191 {
192 Init();
193
194 // if the length is not given, assume the string to be NUL terminated
195 if ( nLength == npos ) {
196 wxASSERT_MSG( nPos <= wxStrlen(psz), _T("index out of bounds") );
197
198 nLength = wxStrlen(psz + nPos);
199 }
200
201 STATISTICS_ADD(InitialLength, nLength);
202
203 if ( nLength > 0 ) {
204 // trailing '\0' is written in AllocBuffer()
205 if ( !AllocBuffer(nLength) ) {
206 wxFAIL_MSG( _T("out of memory in wxStringBase::InitWith") );
207 return;
208 }
209 memcpy(m_pchData, psz + nPos, nLength*sizeof(wxChar));
210 }
211 }
212
213 // poor man's iterators are "void *" pointers
214 wxStringBase::wxStringBase(const void *pStart, const void *pEnd)
215 {
216 InitWith((const wxChar *)pStart, 0,
217 (const wxChar *)pEnd - (const wxChar *)pStart);
218 }
219
220 wxStringBase::wxStringBase(size_type n, wxChar ch)
221 {
222 Init();
223 append(n, ch);
224 }
225
226 // ---------------------------------------------------------------------------
227 // memory allocation
228 // ---------------------------------------------------------------------------
229
230 // allocates memory needed to store a C string of length nLen
231 bool wxStringBase::AllocBuffer(size_t nLen)
232 {
233 // allocating 0 sized buffer doesn't make sense, all empty strings should
234 // reuse g_strEmpty
235 wxASSERT( nLen > 0 );
236
237 // make sure that we don't overflow
238 wxASSERT( nLen < (INT_MAX / sizeof(wxChar)) -
239 (sizeof(wxStringData) + EXTRA_ALLOC + 1) );
240
241 STATISTICS_ADD(Length, nLen);
242
243 // allocate memory:
244 // 1) one extra character for '\0' termination
245 // 2) sizeof(wxStringData) for housekeeping info
246 wxStringData* pData = (wxStringData*)
247 malloc(sizeof(wxStringData) + (nLen + EXTRA_ALLOC + 1)*sizeof(wxChar));
248
249 if ( pData == NULL ) {
250 // allocation failures are handled by the caller
251 return FALSE;
252 }
253
254 pData->nRefs = 1;
255 pData->nDataLength = nLen;
256 pData->nAllocLength = nLen + EXTRA_ALLOC;
257 m_pchData = pData->data(); // data starts after wxStringData
258 m_pchData[nLen] = wxT('\0');
259 return TRUE;
260 }
261
262 // must be called before changing this string
263 bool wxStringBase::CopyBeforeWrite()
264 {
265 wxStringData* pData = GetStringData();
266
267 if ( pData->IsShared() ) {
268 pData->Unlock(); // memory not freed because shared
269 size_t nLen = pData->nDataLength;
270 if ( !AllocBuffer(nLen) ) {
271 // allocation failures are handled by the caller
272 return FALSE;
273 }
274 memcpy(m_pchData, pData->data(), nLen*sizeof(wxChar));
275 }
276
277 wxASSERT( !GetStringData()->IsShared() ); // we must be the only owner
278
279 return TRUE;
280 }
281
282 // must be called before replacing contents of this string
283 bool wxStringBase::AllocBeforeWrite(size_t nLen)
284 {
285 wxASSERT( nLen != 0 ); // doesn't make any sense
286
287 // must not share string and must have enough space
288 wxStringData* pData = GetStringData();
289 if ( pData->IsShared() || pData->IsEmpty() ) {
290 // can't work with old buffer, get new one
291 pData->Unlock();
292 if ( !AllocBuffer(nLen) ) {
293 // allocation failures are handled by the caller
294 return FALSE;
295 }
296 }
297 else {
298 if ( nLen > pData->nAllocLength ) {
299 // realloc the buffer instead of calling malloc() again, this is more
300 // efficient
301 STATISTICS_ADD(Length, nLen);
302
303 nLen += EXTRA_ALLOC;
304
305 pData = (wxStringData*)
306 realloc(pData, sizeof(wxStringData) + (nLen + 1)*sizeof(wxChar));
307
308 if ( pData == NULL ) {
309 // allocation failures are handled by the caller
310 // keep previous data since reallocation failed
311 return FALSE;
312 }
313
314 pData->nAllocLength = nLen;
315 m_pchData = pData->data();
316 }
317
318 // now we have enough space, just update the string length
319 pData->nDataLength = nLen;
320 }
321
322 wxASSERT( !GetStringData()->IsShared() ); // we must be the only owner
323
324 return TRUE;
325 }
326
327 wxStringBase& wxStringBase::append(size_t n, wxChar ch)
328 {
329 size_type len = length();
330
331 if ( !CopyBeforeWrite() || !Alloc(len + n) ) {
332 wxFAIL_MSG( _T("out of memory in wxStringBase::append") );
333 }
334 GetStringData()->nDataLength = len + n;
335 m_pchData[len + n] = '\0';
336 for ( size_t i = 0; i < n; ++i )
337 m_pchData[len + i] = ch;
338 return *this;
339 }
340
341 void wxStringBase::resize(size_t nSize, wxChar ch)
342 {
343 size_t len = length();
344
345 if ( nSize < len )
346 {
347 erase(begin() + nSize, end());
348 }
349 else if ( nSize > len )
350 {
351 append(nSize - len, ch);
352 }
353 //else: we have exactly the specified length, nothing to do
354 }
355
356 // allocate enough memory for nLen characters
357 bool wxStringBase::Alloc(size_t nLen)
358 {
359 wxStringData *pData = GetStringData();
360 if ( pData->nAllocLength <= nLen ) {
361 if ( pData->IsEmpty() ) {
362 nLen += EXTRA_ALLOC;
363
364 wxStringData* pData = (wxStringData*)
365 malloc(sizeof(wxStringData) + (nLen + 1)*sizeof(wxChar));
366
367 if ( pData == NULL ) {
368 // allocation failure handled by caller
369 return FALSE;
370 }
371
372 pData->nRefs = 1;
373 pData->nDataLength = 0;
374 pData->nAllocLength = nLen;
375 m_pchData = pData->data(); // data starts after wxStringData
376 m_pchData[0u] = wxT('\0');
377 }
378 else if ( pData->IsShared() ) {
379 pData->Unlock(); // memory not freed because shared
380 size_t nOldLen = pData->nDataLength;
381 if ( !AllocBuffer(nLen) ) {
382 // allocation failure handled by caller
383 return FALSE;
384 }
385 memcpy(m_pchData, pData->data(), nOldLen*sizeof(wxChar));
386 }
387 else {
388 nLen += EXTRA_ALLOC;
389
390 pData = (wxStringData *)
391 realloc(pData, sizeof(wxStringData) + (nLen + 1)*sizeof(wxChar));
392
393 if ( pData == NULL ) {
394 // allocation failure handled by caller
395 // keep previous data since reallocation failed
396 return FALSE;
397 }
398
399 // it's not important if the pointer changed or not (the check for this
400 // is not faster than assigning to m_pchData in all cases)
401 pData->nAllocLength = nLen;
402 m_pchData = pData->data();
403 }
404 }
405 //else: we've already got enough
406 return TRUE;
407 }
408
409 wxStringBase::iterator wxStringBase::erase(iterator it)
410 {
411 size_type idx = it - begin();
412 erase(idx, 1);
413 return begin() + idx;
414 }
415
416 wxStringBase& wxStringBase::erase(size_t nStart, size_t nLen)
417 {
418 wxASSERT(nStart <= length());
419 size_t strLen = length() - nStart;
420 // delete nLen or up to the end of the string characters
421 nLen = strLen < nLen ? strLen : nLen;
422 wxString strTmp(c_str(), nStart);
423 strTmp.append(c_str() + nStart + nLen, length() - nStart - nLen);
424
425 swap(strTmp);
426 return *this;
427 }
428
429 wxStringBase& wxStringBase::insert(size_t nPos, const wxChar *sz, size_t n)
430 {
431 wxASSERT( nPos <= length() );
432
433 if ( n == npos ) n = wxStrlen(sz);
434 if ( n == 0 ) return *this;
435
436 if ( !CopyBeforeWrite() || !Alloc(length() + n) ) {
437 wxFAIL_MSG( _T("out of memory in wxStringBase::insert") );
438 }
439
440 memmove(m_pchData + nPos + n, m_pchData + nPos,
441 (length() - nPos) * sizeof(wxChar));
442 memcpy(m_pchData + nPos, sz, n * sizeof(wxChar));
443 GetStringData()->nDataLength = length() + n;
444 m_pchData[length()] = '\0';
445
446 return *this;
447 }
448
449 void wxStringBase::swap(wxStringBase& str)
450 {
451 wxChar* tmp = str.m_pchData;
452 str.m_pchData = m_pchData;
453 m_pchData = tmp;
454 }
455
456 size_t wxStringBase::find(const wxStringBase& str, size_t nStart) const
457 {
458 wxASSERT( str.GetStringData()->IsValid() );
459 wxASSERT( nStart <= length() );
460
461 const wxChar *p = wxStrstr(c_str() + nStart, str.c_str());
462
463 return p == NULL ? npos : p - c_str();
464 }
465
466 size_t wxStringBase::find(const wxChar* sz, size_t nStart, size_t n) const
467 {
468 return find(wxStringBase(sz, n), nStart);
469 }
470
471 size_t wxStringBase::find(wxChar ch, size_t nStart) const
472 {
473 wxASSERT( nStart <= length() );
474
475 const wxChar *p = wxStrchr(c_str() + nStart, ch);
476
477 return p == NULL ? npos : p - c_str();
478 }
479
480 size_t wxStringBase::rfind(const wxStringBase& str, size_t nStart) const
481 {
482 wxASSERT( str.GetStringData()->IsValid() );
483 wxASSERT( nStart == npos || nStart <= length() );
484
485 if ( length() >= str.length() )
486 {
487 // avoids a corner case later
488 if ( length() == 0 && str.length() == 0 )
489 return 0;
490
491 // "top" is the point where search starts from
492 size_t top = length() - str.length();
493
494 if ( nStart == npos )
495 nStart = length() - 1;
496 if ( nStart < top )
497 top = nStart;
498
499 const wxChar *cursor = c_str() + top;
500 do
501 {
502 if ( memcmp(cursor, str.c_str(),
503 str.length() * sizeof(wxChar)) == 0 )
504 {
505 return cursor - c_str();
506 }
507 --cursor;
508 } while ( cursor > c_str() );
509 }
510
511 return npos;
512 }
513
514 size_t wxStringBase::rfind(const wxChar* sz, size_t nStart, size_t n) const
515 {
516 return rfind(wxStringBase(sz, n), nStart);
517 }
518
519 size_t wxStringBase::rfind(wxChar ch, size_t nStart) const
520 {
521 if ( nStart == npos )
522 {
523 nStart = length();
524 }
525 else
526 {
527 wxASSERT( nStart <= length() );
528 }
529
530 const wxChar *actual;
531 for ( actual = c_str() + ( nStart == npos ? length() : nStart + 1 );
532 actual > c_str(); --actual )
533 {
534 if ( *(actual - 1) == ch )
535 return (actual - 1) - c_str();
536 }
537
538 return npos;
539 }
540
541 size_t wxStringBase::find_first_of(const wxChar* sz, size_t nStart) const
542 {
543 const wxChar *start = c_str() + nStart;
544 const wxChar *firstOf = wxStrpbrk(start, sz);
545 if ( firstOf )
546 return firstOf - c_str();
547 else
548 return npos;
549 }
550
551 size_t wxStringBase::find_first_of(const wxChar* sz, size_t nStart,
552 size_t n) const
553 {
554 return find_first_of(wxStringBase(sz, n), nStart);
555 }
556
557 size_t wxStringBase::find_last_of(const wxChar* sz, size_t nStart) const
558 {
559 if ( nStart == npos )
560 {
561 nStart = length() - 1;
562 }
563 else
564 {
565 wxASSERT_MSG( nStart <= length(),
566 _T("invalid index in find_last_of()") );
567 }
568
569 for ( const wxChar *p = c_str() + nStart; p >= c_str(); --p )
570 {
571 if ( wxStrchr(sz, *p) )
572 return p - c_str();
573 }
574
575 return npos;
576 }
577
578 size_t wxStringBase::find_last_of(const wxChar* sz, size_t nStart,
579 size_t n) const
580 {
581 return find_last_of(wxStringBase(sz, n), nStart);
582 }
583
584 size_t wxStringBase::find_first_not_of(const wxChar* sz, size_t nStart) const
585 {
586 if ( nStart == npos )
587 {
588 nStart = length();
589 }
590 else
591 {
592 wxASSERT( nStart <= length() );
593 }
594
595 size_t nAccept = wxStrspn(c_str() + nStart, sz);
596 if ( nAccept >= length() - nStart )
597 return npos;
598 else
599 return nStart + nAccept;
600 }
601
602 size_t wxStringBase::find_first_not_of(const wxChar* sz, size_t nStart,
603 size_t n) const
604 {
605 return find_first_not_of(wxStringBase(sz, n), nStart);
606 }
607
608 size_t wxStringBase::find_first_not_of(wxChar ch, size_t nStart) const
609 {
610 wxASSERT( nStart <= length() );
611
612 for ( const wxChar *p = c_str() + nStart; *p; p++ )
613 {
614 if ( *p != ch )
615 return p - c_str();
616 }
617
618 return npos;
619 }
620
621 size_t wxStringBase::find_last_not_of(const wxChar* sz, size_t nStart) const
622 {
623 if ( nStart == npos )
624 {
625 nStart = length() - 1;
626 }
627 else
628 {
629 wxASSERT( nStart <= length() );
630 }
631
632 for ( const wxChar *p = c_str() + nStart; p >= c_str(); --p )
633 {
634 if ( !wxStrchr(sz, *p) )
635 return p - c_str();
636 }
637
638 return npos;
639 }
640
641 size_t wxStringBase::find_last_not_of(const wxChar* sz, size_t nStart,
642 size_t n) const
643 {
644 return find_last_not_of(wxStringBase(sz, n), nStart);
645 }
646
647 size_t wxStringBase::find_last_not_of(wxChar ch, size_t nStart) const
648 {
649 if ( nStart == npos )
650 {
651 nStart = length() - 1;
652 }
653 else
654 {
655 wxASSERT( nStart <= length() );
656 }
657
658 for ( const wxChar *p = c_str() + nStart; p >= c_str(); --p )
659 {
660 if ( *p != ch )
661 return p - c_str();
662 }
663
664 return npos;
665 }
666
667 wxStringBase& wxStringBase::replace(size_t nStart, size_t nLen,
668 const wxChar *sz)
669 {
670 wxASSERT_MSG( nStart <= length(),
671 _T("index out of bounds in wxStringBase::replace") );
672 size_t strLen = length() - nStart;
673 nLen = strLen < nLen ? strLen : nLen;
674
675 wxStringBase strTmp;
676 strTmp.reserve(length()); // micro optimisation to avoid multiple mem allocs
677
678 if ( nStart != 0 )
679 strTmp.append(c_str(), nStart);
680 strTmp.append(sz);
681 strTmp.append(c_str() + nStart + nLen);
682
683 swap(strTmp);
684 return *this;
685 }
686
687 wxStringBase& wxStringBase::replace(size_t nStart, size_t nLen,
688 size_t nCount, wxChar ch)
689 {
690 return replace(nStart, nLen, wxStringBase(ch, nCount).c_str());
691 }
692
693 wxStringBase& wxStringBase::replace(size_t nStart, size_t nLen,
694 const wxStringBase& str,
695 size_t nStart2, size_t nLen2)
696 {
697 return replace(nStart, nLen, str.substr(nStart2, nLen2));
698 }
699
700 wxStringBase& wxStringBase::replace(size_t nStart, size_t nLen,
701 const wxChar* sz, size_t nCount)
702 {
703 return replace(nStart, nLen, wxStringBase(sz, nCount).c_str());
704 }
705
706 wxStringBase wxStringBase::substr(size_t nStart, size_t nLen) const
707 {
708 if ( nLen == npos )
709 nLen = length() - nStart;
710 return wxStringBase(*this, nStart, nLen);
711 }
712
713 // assigns one string to another
714 wxStringBase& wxStringBase::operator=(const wxStringBase& stringSrc)
715 {
716 wxASSERT( stringSrc.GetStringData()->IsValid() );
717
718 // don't copy string over itself
719 if ( m_pchData != stringSrc.m_pchData ) {
720 if ( stringSrc.GetStringData()->IsEmpty() ) {
721 Reinit();
722 }
723 else {
724 // adjust references
725 GetStringData()->Unlock();
726 m_pchData = stringSrc.m_pchData;
727 GetStringData()->Lock();
728 }
729 }
730
731 return *this;
732 }
733
734 // assigns a single character
735 wxStringBase& wxStringBase::operator=(wxChar ch)
736 {
737 if ( !AssignCopy(1, &ch) ) {
738 wxFAIL_MSG( _T("out of memory in wxStringBase::operator=(wxChar)") );
739 }
740 return *this;
741 }
742
743 // assigns C string
744 wxStringBase& wxStringBase::operator=(const wxChar *psz)
745 {
746 if ( !AssignCopy(wxStrlen(psz), psz) ) {
747 wxFAIL_MSG( _T("out of memory in wxStringBase::operator=(const wxChar *)") );
748 }
749 return *this;
750 }
751
752 // helper function: does real copy
753 bool wxStringBase::AssignCopy(size_t nSrcLen, const wxChar *pszSrcData)
754 {
755 if ( nSrcLen == 0 ) {
756 Reinit();
757 }
758 else {
759 if ( !AllocBeforeWrite(nSrcLen) ) {
760 // allocation failure handled by caller
761 return FALSE;
762 }
763 memcpy(m_pchData, pszSrcData, nSrcLen*sizeof(wxChar));
764 GetStringData()->nDataLength = nSrcLen;
765 m_pchData[nSrcLen] = wxT('\0');
766 }
767 return TRUE;
768 }
769
770 // ---------------------------------------------------------------------------
771 // string concatenation
772 // ---------------------------------------------------------------------------
773
774 // add something to this string
775 bool wxStringBase::ConcatSelf(size_t nSrcLen, const wxChar *pszSrcData,
776 size_t nMaxLen)
777 {
778 STATISTICS_ADD(SummandLength, nSrcLen);
779
780 nSrcLen = nSrcLen < nMaxLen ? nSrcLen : nMaxLen;
781
782 // concatenating an empty string is a NOP
783 if ( nSrcLen > 0 ) {
784 wxStringData *pData = GetStringData();
785 size_t nLen = pData->nDataLength;
786 size_t nNewLen = nLen + nSrcLen;
787
788 // alloc new buffer if current is too small
789 if ( pData->IsShared() ) {
790 STATISTICS_ADD(ConcatHit, 0);
791
792 // we have to allocate another buffer
793 wxStringData* pOldData = GetStringData();
794 if ( !AllocBuffer(nNewLen) ) {
795 // allocation failure handled by caller
796 return FALSE;
797 }
798 memcpy(m_pchData, pOldData->data(), nLen*sizeof(wxChar));
799 pOldData->Unlock();
800 }
801 else if ( nNewLen > pData->nAllocLength ) {
802 STATISTICS_ADD(ConcatHit, 0);
803
804 reserve(nNewLen);
805 // we have to grow the buffer
806 if ( capacity() < nNewLen ) {
807 // allocation failure handled by caller
808 return FALSE;
809 }
810 }
811 else {
812 STATISTICS_ADD(ConcatHit, 1);
813
814 // the buffer is already big enough
815 }
816
817 // should be enough space
818 wxASSERT( nNewLen <= GetStringData()->nAllocLength );
819
820 // fast concatenation - all is done in our buffer
821 memcpy(m_pchData + nLen, pszSrcData, nSrcLen*sizeof(wxChar));
822
823 m_pchData[nNewLen] = wxT('\0'); // put terminating '\0'
824 GetStringData()->nDataLength = nNewLen; // and fix the length
825 }
826 //else: the string to append was empty
827 return TRUE;
828 }
829
830 // ---------------------------------------------------------------------------
831 // simple sub-string extraction
832 // ---------------------------------------------------------------------------
833
834 // helper function: clone the data attached to this string
835 bool wxStringBase::AllocCopy(wxString& dest, int nCopyLen, int nCopyIndex) const
836 {
837 if ( nCopyLen == 0 ) {
838 dest.Init();
839 }
840 else {
841 if ( !dest.AllocBuffer(nCopyLen) ) {
842 // allocation failure handled by caller
843 return FALSE;
844 }
845 memcpy(dest.m_pchData, m_pchData + nCopyIndex, nCopyLen*sizeof(wxChar));
846 }
847 return TRUE;
848 }
849
850 #endif // !wxUSE_STL
851
852 #if !wxUSE_STL || !defined(HAVE_STD_STRING_COMPARE)
853
854 #if !wxUSE_STL
855 #define STRINGCLASS wxStringBase
856 #else
857 #define STRINGCLASS wxString
858 #endif
859
860 static inline int wxDoCmp(const wxChar* s1, size_t l1,
861 const wxChar* s2, size_t l2)
862 {
863 if( l1 == l2 )
864 return wxStrncmp(s1, s2, l1);
865 else if( l1 < l2 )
866 {
867 int ret = wxStrncmp(s1, s2, l1);
868 return ret == 0 ? -1 : ret;
869 }
870 else if( l1 > l2 )
871 {
872 int ret = wxStrncmp(s1, s2, l2);
873 return ret == 0 ? +1 : ret;
874 }
875
876 wxFAIL; // must never get there
877 return 0; // quiet compilers
878 }
879
880 #if wxUSE_STL
881
882 int STRINGCLASS::compare(const wxStringBase& str) const
883 {
884 return ::wxDoCmp(data(), length(), str.data(), str.length());
885 }
886
887 #endif
888
889 int STRINGCLASS::compare(size_t nStart, size_t nLen,
890 const wxStringBase& str) const
891 {
892 wxASSERT(nStart <= length());
893 size_type strLen = length() - nStart;
894 nLen = strLen < nLen ? strLen : nLen;
895 return ::wxDoCmp(data() + nStart, nLen, str.data(), str.length());
896 }
897
898 int STRINGCLASS::compare(size_t nStart, size_t nLen,
899 const wxStringBase& str,
900 size_t nStart2, size_t nLen2) const
901 {
902 wxASSERT(nStart <= length());
903 wxASSERT(nStart2 <= str.length());
904 size_type strLen = length() - nStart,
905 strLen2 = str.length() - nStart2;
906 nLen = strLen < nLen ? strLen : nLen;
907 nLen2 = strLen2 < nLen2 ? strLen2 : nLen2;
908 return ::wxDoCmp(data() + nStart, nLen, str.data() + nStart2, nLen2);
909 }
910
911 #if wxUSE_STL
912
913 int STRINGCLASS::compare(const wxChar* sz) const
914 {
915 size_t nLen = wxStrlen(sz);
916 return ::wxDoCmp(data(), length(), sz, nLen);
917 }
918
919 #endif
920
921 int STRINGCLASS::compare(size_t nStart, size_t nLen,
922 const wxChar* sz, size_t nCount) const
923 {
924 wxASSERT(nStart <= length());
925 size_type strLen = length() - nStart;
926 nLen = strLen < nLen ? strLen : nLen;
927 if( nCount == npos )
928 nCount = wxStrlen(sz);
929
930 return ::wxDoCmp(data() + nStart, nLen, sz, nCount);
931 }
932
933 #undef STRINGCLASS
934
935 #endif // !wxUSE_STL || !defined(HAVE_STD_STRING_COMPARE)
936
937 // ===========================================================================
938 // wxString class core
939 // ===========================================================================
940
941 // ---------------------------------------------------------------------------
942 // construction
943 // ---------------------------------------------------------------------------
944
945 #if wxUSE_UNICODE
946
947 // from multibyte string
948 wxString::wxString(const char *psz, wxMBConv& conv, size_t nLength)
949 {
950 // first get the size of the buffer we need
951 size_t nLen;
952 if ( psz )
953 {
954 // calculate the needed size ourselves or use the provided one
955 nLen = nLength == npos ? conv.MB2WC(NULL, psz, 0) : nLength;
956 }
957 else
958 {
959 // nothing to convert
960 nLen = 0;
961 }
962
963 // anything to do?
964 if ( (nLen != 0) && (nLen != (size_t)-1) )
965 {
966 if ( !Alloc(nLen) )
967 {
968 wxFAIL_MSG( _T("out of memory in wxString::wxString") );
969 }
970 else
971 {
972 wxWCharBuffer buf(nLen + 1);
973 // MB2WC wants the buffer size, not the string length hence +1
974 nLen = conv.MB2WC(buf.data(), psz, nLen + 1);
975
976 if ( nLen != (size_t)-1 )
977 {
978 // initialized ok, set the real length as nLength specified by
979 // the caller could be greater than the real string length
980 assign(buf.data(), nLen);
981 return;
982 }
983 //else: the conversion failed -- leave the string empty (what else?)
984 }
985 }
986 }
987
988 #else // ANSI
989
990 #if wxUSE_WCHAR_T
991 // from wide string
992 wxString::wxString(const wchar_t *pwz, wxMBConv& conv, size_t nLength)
993 {
994 // first get the size of the buffer we need
995 size_t nLen;
996 if ( pwz )
997 {
998 // calculate the needed size ourselves or use the provided one
999 nLen = nLength == npos ? conv.WC2MB(NULL, pwz, 0) : nLength;
1000 }
1001 else
1002 {
1003 // nothing to convert
1004 nLen = 0;
1005 }
1006
1007 // anything to do?
1008 if ( (nLen != 0) && (nLen != (size_t)-1) )
1009 {
1010 if ( !Alloc(nLen) )
1011 {
1012 wxFAIL_MSG( _T("out of memory in wxString::wxString") );
1013 }
1014 else
1015 {
1016 wxCharBuffer buf(nLen);
1017 // WC2MB wants the buffer size, not the string length
1018 if ( conv.WC2MB(buf.data(), pwz, nLen + 1) != (size_t)-1 )
1019 {
1020 // initialized ok
1021 assign(buf.data(), nLen);
1022 return;
1023 }
1024 //else: the conversion failed -- leave the string empty (what else?)
1025 }
1026 }
1027
1028 // leave empty
1029 }
1030 #endif // wxUSE_WCHAR_T
1031
1032 #endif // Unicode/ANSI
1033
1034 // shrink to minimal size (releasing extra memory)
1035 bool wxString::Shrink()
1036 {
1037 wxString tmp(begin(), end());
1038 swap(tmp);
1039 return tmp.length() == length();
1040 }
1041
1042 #if !wxUSE_STL
1043 // get the pointer to writable buffer of (at least) nLen bytes
1044 wxChar *wxString::GetWriteBuf(size_t nLen)
1045 {
1046 if ( !AllocBeforeWrite(nLen) ) {
1047 // allocation failure handled by caller
1048 return NULL;
1049 }
1050
1051 wxASSERT( GetStringData()->nRefs == 1 );
1052 GetStringData()->Validate(FALSE);
1053
1054 return m_pchData;
1055 }
1056
1057 // put string back in a reasonable state after GetWriteBuf
1058 void wxString::UngetWriteBuf()
1059 {
1060 GetStringData()->nDataLength = wxStrlen(m_pchData);
1061 GetStringData()->Validate(TRUE);
1062 }
1063
1064 void wxString::UngetWriteBuf(size_t nLen)
1065 {
1066 GetStringData()->nDataLength = nLen;
1067 GetStringData()->Validate(TRUE);
1068 }
1069 #endif
1070
1071 // ---------------------------------------------------------------------------
1072 // data access
1073 // ---------------------------------------------------------------------------
1074
1075 // all functions are inline in string.h
1076
1077 // ---------------------------------------------------------------------------
1078 // assignment operators
1079 // ---------------------------------------------------------------------------
1080
1081 #if !wxUSE_UNICODE
1082
1083 // same as 'signed char' variant
1084 wxString& wxString::operator=(const unsigned char* psz)
1085 {
1086 *this = (const char *)psz;
1087 return *this;
1088 }
1089
1090 #if wxUSE_WCHAR_T
1091 wxString& wxString::operator=(const wchar_t *pwz)
1092 {
1093 wxString str(pwz);
1094 swap(str);
1095 return *this;
1096 }
1097 #endif
1098
1099 #endif
1100
1101 /*
1102 * concatenation functions come in 5 flavours:
1103 * string + string
1104 * char + string and string + char
1105 * C str + string and string + C str
1106 */
1107
1108 wxString operator+(const wxString& str1, const wxString& str2)
1109 {
1110 #if !wxUSE_STL
1111 wxASSERT( str1.GetStringData()->IsValid() );
1112 wxASSERT( str2.GetStringData()->IsValid() );
1113 #endif
1114
1115 wxString s = str1;
1116 s += str2;
1117
1118 return s;
1119 }
1120
1121 wxString operator+(const wxString& str, wxChar ch)
1122 {
1123 #if !wxUSE_STL
1124 wxASSERT( str.GetStringData()->IsValid() );
1125 #endif
1126
1127 wxString s = str;
1128 s += ch;
1129
1130 return s;
1131 }
1132
1133 wxString operator+(wxChar ch, const wxString& str)
1134 {
1135 #if !wxUSE_STL
1136 wxASSERT( str.GetStringData()->IsValid() );
1137 #endif
1138
1139 wxString s = ch;
1140 s += str;
1141
1142 return s;
1143 }
1144
1145 wxString operator+(const wxString& str, const wxChar *psz)
1146 {
1147 #if !wxUSE_STL
1148 wxASSERT( str.GetStringData()->IsValid() );
1149 #endif
1150
1151 wxString s;
1152 if ( !s.Alloc(wxStrlen(psz) + str.Len()) ) {
1153 wxFAIL_MSG( _T("out of memory in wxString::operator+") );
1154 }
1155 s = str;
1156 s += psz;
1157
1158 return s;
1159 }
1160
1161 wxString operator+(const wxChar *psz, const wxString& str)
1162 {
1163 #if !wxUSE_STL
1164 wxASSERT( str.GetStringData()->IsValid() );
1165 #endif
1166
1167 wxString s;
1168 if ( !s.Alloc(wxStrlen(psz) + str.Len()) ) {
1169 wxFAIL_MSG( _T("out of memory in wxString::operator+") );
1170 }
1171 s = psz;
1172 s += str;
1173
1174 return s;
1175 }
1176
1177 // ===========================================================================
1178 // other common string functions
1179 // ===========================================================================
1180
1181 #if wxUSE_UNICODE
1182
1183 wxString wxString::FromAscii(const char *ascii)
1184 {
1185 if (!ascii)
1186 return wxEmptyString;
1187
1188 size_t len = strlen( ascii );
1189 wxString res;
1190
1191 if ( len )
1192 {
1193 wxStringBuffer buf(res, len);
1194
1195 wchar_t *dest = buf;
1196
1197 for ( ;; )
1198 {
1199 if ( (*dest++ = (wchar_t)(unsigned char)*ascii++) == L'\0' )
1200 break;
1201 }
1202 }
1203
1204 return res;
1205 }
1206
1207 wxString wxString::FromAscii(const char ascii)
1208 {
1209 // What do we do with '\0' ?
1210
1211 wxString res;
1212 res += (wchar_t)(unsigned char) ascii;
1213
1214 return res;
1215 }
1216
1217 const wxCharBuffer wxString::ToAscii() const
1218 {
1219 // this will allocate enough space for the terminating NUL too
1220 wxCharBuffer buffer(length());
1221
1222 signed char *dest = (signed char *)buffer.data();
1223
1224 const wchar_t *pwc = c_str();
1225 for ( ;; )
1226 {
1227 *dest++ = *pwc > SCHAR_MAX ? '_' : *pwc;
1228
1229 // the output string can't have embedded NULs anyhow, so we can safely
1230 // stop at first of them even if we do have any
1231 if ( !*pwc++ )
1232 break;
1233 }
1234
1235 return buffer;
1236 }
1237
1238 #endif // Unicode
1239
1240 // extract string of length nCount starting at nFirst
1241 wxString wxString::Mid(size_t nFirst, size_t nCount) const
1242 {
1243 size_t nLen = length();
1244
1245 // default value of nCount is npos and means "till the end"
1246 if ( nCount == npos )
1247 {
1248 nCount = nLen - nFirst;
1249 }
1250
1251 // out-of-bounds requests return sensible things
1252 if ( nFirst + nCount > nLen )
1253 {
1254 nCount = nLen - nFirst;
1255 }
1256
1257 if ( nFirst > nLen )
1258 {
1259 // AllocCopy() will return empty string
1260 nCount = 0;
1261 }
1262
1263 wxString dest(*this, nFirst, nCount);
1264 if ( dest.length() != nCount ) {
1265 wxFAIL_MSG( _T("out of memory in wxString::Mid") );
1266 }
1267
1268 return dest;
1269 }
1270
1271 // check that the string starts with prefix and return the rest of the string
1272 // in the provided pointer if it is not NULL, otherwise return FALSE
1273 bool wxString::StartsWith(const wxChar *prefix, wxString *rest) const
1274 {
1275 wxASSERT_MSG( prefix, _T("invalid parameter in wxString::StartsWith") );
1276
1277 // first check if the beginning of the string matches the prefix: note
1278 // that we don't have to check that we don't run out of this string as
1279 // when we reach the terminating NUL, either prefix string ends too (and
1280 // then it's ok) or we break out of the loop because there is no match
1281 const wxChar *p = c_str();
1282 while ( *prefix )
1283 {
1284 if ( *prefix++ != *p++ )
1285 {
1286 // no match
1287 return FALSE;
1288 }
1289 }
1290
1291 if ( rest )
1292 {
1293 // put the rest of the string into provided pointer
1294 *rest = p;
1295 }
1296
1297 return TRUE;
1298 }
1299
1300 // extract nCount last (rightmost) characters
1301 wxString wxString::Right(size_t nCount) const
1302 {
1303 if ( nCount > length() )
1304 nCount = length();
1305
1306 wxString dest(*this, length() - nCount, nCount);
1307 if ( dest.length() != nCount ) {
1308 wxFAIL_MSG( _T("out of memory in wxString::Right") );
1309 }
1310 return dest;
1311 }
1312
1313 // get all characters after the last occurence of ch
1314 // (returns the whole string if ch not found)
1315 wxString wxString::AfterLast(wxChar ch) const
1316 {
1317 wxString str;
1318 int iPos = Find(ch, TRUE);
1319 if ( iPos == wxNOT_FOUND )
1320 str = *this;
1321 else
1322 str = c_str() + iPos + 1;
1323
1324 return str;
1325 }
1326
1327 // extract nCount first (leftmost) characters
1328 wxString wxString::Left(size_t nCount) const
1329 {
1330 if ( nCount > length() )
1331 nCount = length();
1332
1333 wxString dest(*this, 0, nCount);
1334 if ( dest.length() != nCount ) {
1335 wxFAIL_MSG( _T("out of memory in wxString::Left") );
1336 }
1337 return dest;
1338 }
1339
1340 // get all characters before the first occurence of ch
1341 // (returns the whole string if ch not found)
1342 wxString wxString::BeforeFirst(wxChar ch) const
1343 {
1344 int iPos = Find(ch);
1345 if ( iPos == wxNOT_FOUND ) iPos = length();
1346 return wxString(*this, 0, iPos);
1347 }
1348
1349 /// get all characters before the last occurence of ch
1350 /// (returns empty string if ch not found)
1351 wxString wxString::BeforeLast(wxChar ch) const
1352 {
1353 wxString str;
1354 int iPos = Find(ch, TRUE);
1355 if ( iPos != wxNOT_FOUND && iPos != 0 )
1356 str = wxString(c_str(), iPos);
1357
1358 return str;
1359 }
1360
1361 /// get all characters after the first occurence of ch
1362 /// (returns empty string if ch not found)
1363 wxString wxString::AfterFirst(wxChar ch) const
1364 {
1365 wxString str;
1366 int iPos = Find(ch);
1367 if ( iPos != wxNOT_FOUND )
1368 str = c_str() + iPos + 1;
1369
1370 return str;
1371 }
1372
1373 // replace first (or all) occurences of some substring with another one
1374 size_t
1375 wxString::Replace(const wxChar *szOld, const wxChar *szNew, bool bReplaceAll)
1376 {
1377 // if we tried to replace an empty string we'd enter an infinite loop below
1378 wxCHECK_MSG( szOld && *szOld && szNew, 0,
1379 _T("wxString::Replace(): invalid parameter") );
1380
1381 size_t uiCount = 0; // count of replacements made
1382
1383 size_t uiOldLen = wxStrlen(szOld);
1384
1385 wxString strTemp;
1386 const wxChar *pCurrent = c_str();
1387 const wxChar *pSubstr;
1388 while ( *pCurrent != wxT('\0') ) {
1389 pSubstr = wxStrstr(pCurrent, szOld);
1390 if ( pSubstr == NULL ) {
1391 // strTemp is unused if no replacements were made, so avoid the copy
1392 if ( uiCount == 0 )
1393 return 0;
1394
1395 strTemp += pCurrent; // copy the rest
1396 break; // exit the loop
1397 }
1398 else {
1399 // take chars before match
1400 size_type len = strTemp.length();
1401 strTemp.append(pCurrent, pSubstr - pCurrent);
1402 if ( strTemp.length() != (size_t)(len + pSubstr - pCurrent) ) {
1403 wxFAIL_MSG( _T("out of memory in wxString::Replace") );
1404 return 0;
1405 }
1406 strTemp += szNew;
1407 pCurrent = pSubstr + uiOldLen; // restart after match
1408
1409 uiCount++;
1410
1411 // stop now?
1412 if ( !bReplaceAll ) {
1413 strTemp += pCurrent; // copy the rest
1414 break; // exit the loop
1415 }
1416 }
1417 }
1418
1419 // only done if there were replacements, otherwise would have returned above
1420 swap(strTemp);
1421
1422 return uiCount;
1423 }
1424
1425 bool wxString::IsAscii() const
1426 {
1427 const wxChar *s = (const wxChar*) *this;
1428 while(*s){
1429 if(!isascii(*s)) return(FALSE);
1430 s++;
1431 }
1432 return(TRUE);
1433 }
1434
1435 bool wxString::IsWord() const
1436 {
1437 const wxChar *s = (const wxChar*) *this;
1438 while(*s){
1439 if(!wxIsalpha(*s)) return(FALSE);
1440 s++;
1441 }
1442 return(TRUE);
1443 }
1444
1445 bool wxString::IsNumber() const
1446 {
1447 const wxChar *s = (const wxChar*) *this;
1448 if (wxStrlen(s))
1449 if ((s[0] == '-') || (s[0] == '+')) s++;
1450 while(*s){
1451 if(!wxIsdigit(*s)) return(FALSE);
1452 s++;
1453 }
1454 return(TRUE);
1455 }
1456
1457 wxString wxString::Strip(stripType w) const
1458 {
1459 wxString s = *this;
1460 if ( w & leading ) s.Trim(FALSE);
1461 if ( w & trailing ) s.Trim(TRUE);
1462 return s;
1463 }
1464
1465 // ---------------------------------------------------------------------------
1466 // case conversion
1467 // ---------------------------------------------------------------------------
1468
1469 wxString& wxString::MakeUpper()
1470 {
1471 for ( iterator it = begin(), en = end(); it != en; ++it )
1472 *it = (wxChar)wxToupper(*it);
1473
1474 return *this;
1475 }
1476
1477 wxString& wxString::MakeLower()
1478 {
1479 for ( iterator it = begin(), en = end(); it != en; ++it )
1480 *it = (wxChar)wxTolower(*it);
1481
1482 return *this;
1483 }
1484
1485 // ---------------------------------------------------------------------------
1486 // trimming and padding
1487 // ---------------------------------------------------------------------------
1488
1489 // some compilers (VC++ 6.0 not to name them) return TRUE for a call to
1490 // isspace('ê') in the C locale which seems to be broken to me, but we have to
1491 // live with this by checking that the character is a 7 bit one - even if this
1492 // may fail to detect some spaces (I don't know if Unicode doesn't have
1493 // space-like symbols somewhere except in the first 128 chars), it is arguably
1494 // still better than trimming away accented letters
1495 inline int wxSafeIsspace(wxChar ch) { return (ch < 127) && wxIsspace(ch); }
1496
1497 // trims spaces (in the sense of isspace) from left or right side
1498 wxString& wxString::Trim(bool bFromRight)
1499 {
1500 // first check if we're going to modify the string at all
1501 if ( !IsEmpty() &&
1502 (
1503 (bFromRight && wxSafeIsspace(GetChar(Len() - 1))) ||
1504 (!bFromRight && wxSafeIsspace(GetChar(0u)))
1505 )
1506 )
1507 {
1508 if ( bFromRight )
1509 {
1510 // find last non-space character
1511 iterator psz = begin() + length() - 1;
1512 while ( wxSafeIsspace(*psz) && (psz >= begin()) )
1513 psz--;
1514
1515 // truncate at trailing space start
1516 *++psz = wxT('\0');
1517 erase(psz, end());
1518 }
1519 else
1520 {
1521 // find first non-space character
1522 iterator psz = begin();
1523 while ( wxSafeIsspace(*psz) )
1524 psz++;
1525
1526 // fix up data and length
1527 erase(begin(), psz);
1528 }
1529 }
1530
1531 return *this;
1532 }
1533
1534 // adds nCount characters chPad to the string from either side
1535 wxString& wxString::Pad(size_t nCount, wxChar chPad, bool bFromRight)
1536 {
1537 wxString s(chPad, nCount);
1538
1539 if ( bFromRight )
1540 *this += s;
1541 else
1542 {
1543 s += *this;
1544 swap(s);
1545 }
1546
1547 return *this;
1548 }
1549
1550 // truncate the string
1551 wxString& wxString::Truncate(size_t uiLen)
1552 {
1553 if ( uiLen < Len() ) {
1554 erase(begin() + uiLen, end());
1555 }
1556 //else: nothing to do, string is already short enough
1557
1558 return *this;
1559 }
1560
1561 // ---------------------------------------------------------------------------
1562 // finding (return wxNOT_FOUND if not found and index otherwise)
1563 // ---------------------------------------------------------------------------
1564
1565 // find a character
1566 int wxString::Find(wxChar ch, bool bFromEnd) const
1567 {
1568 size_type idx = bFromEnd ? find_last_of(ch) : find_first_of(ch);
1569
1570 return (idx == npos) ? wxNOT_FOUND : (int)idx;
1571 }
1572
1573 // find a sub-string (like strstr)
1574 int wxString::Find(const wxChar *pszSub) const
1575 {
1576 size_type idx = find(pszSub);
1577
1578 return (idx == npos) ? wxNOT_FOUND : (int)idx;
1579 }
1580
1581 // ----------------------------------------------------------------------------
1582 // conversion to numbers
1583 // ----------------------------------------------------------------------------
1584
1585 bool wxString::ToLong(long *val, int base) const
1586 {
1587 wxCHECK_MSG( val, FALSE, _T("NULL pointer in wxString::ToLong") );
1588 wxASSERT_MSG( !base || (base > 1 && base <= 36), _T("invalid base") );
1589
1590 const wxChar *start = c_str();
1591 wxChar *end;
1592 *val = wxStrtol(start, &end, base);
1593
1594 // return TRUE only if scan was stopped by the terminating NUL and if the
1595 // string was not empty to start with
1596 return !*end && (end != start);
1597 }
1598
1599 bool wxString::ToULong(unsigned long *val, int base) const
1600 {
1601 wxCHECK_MSG( val, FALSE, _T("NULL pointer in wxString::ToULong") );
1602 wxASSERT_MSG( !base || (base > 1 && base <= 36), _T("invalid base") );
1603
1604 const wxChar *start = c_str();
1605 wxChar *end;
1606 *val = wxStrtoul(start, &end, base);
1607
1608 // return TRUE only if scan was stopped by the terminating NUL and if the
1609 // string was not empty to start with
1610 return !*end && (end != start);
1611 }
1612
1613 bool wxString::ToDouble(double *val) const
1614 {
1615 wxCHECK_MSG( val, FALSE, _T("NULL pointer in wxString::ToDouble") );
1616
1617 const wxChar *start = c_str();
1618 wxChar *end;
1619 *val = wxStrtod(start, &end);
1620
1621 // return TRUE only if scan was stopped by the terminating NUL and if the
1622 // string was not empty to start with
1623 return !*end && (end != start);
1624 }
1625
1626 // ---------------------------------------------------------------------------
1627 // formatted output
1628 // ---------------------------------------------------------------------------
1629
1630 /* static */
1631 wxString wxString::Format(const wxChar *pszFormat, ...)
1632 {
1633 va_list argptr;
1634 va_start(argptr, pszFormat);
1635
1636 wxString s;
1637 s.PrintfV(pszFormat, argptr);
1638
1639 va_end(argptr);
1640
1641 return s;
1642 }
1643
1644 /* static */
1645 wxString wxString::FormatV(const wxChar *pszFormat, va_list argptr)
1646 {
1647 wxString s;
1648 s.PrintfV(pszFormat, argptr);
1649 return s;
1650 }
1651
1652 int wxString::Printf(const wxChar *pszFormat, ...)
1653 {
1654 va_list argptr;
1655 va_start(argptr, pszFormat);
1656
1657 int iLen = PrintfV(pszFormat, argptr);
1658
1659 va_end(argptr);
1660
1661 return iLen;
1662 }
1663
1664 int wxString::PrintfV(const wxChar* pszFormat, va_list argptr)
1665 {
1666 int size = 1024;
1667 int len;
1668
1669 for ( ;; )
1670 {
1671 {
1672 wxStringBuffer tmp(*this, size + 1);
1673 wxChar* buf = tmp;
1674
1675 if ( !buf )
1676 {
1677 // out of memory
1678 return -1;
1679 }
1680
1681 len = wxVsnprintf(buf, size, pszFormat, argptr);
1682
1683 // some implementations of vsnprintf() don't NUL terminate
1684 // the string if there is not enough space for it so
1685 // always do it manually
1686 buf[size] = _T('\0');
1687 }
1688
1689 if ( len >= 0 )
1690 {
1691 // ok, there was enough space
1692 break;
1693 }
1694
1695 // still not enough, double it again
1696 size *= 2;
1697 }
1698
1699 // we could have overshot
1700 Shrink();
1701
1702 return Len();
1703 }
1704
1705 // ----------------------------------------------------------------------------
1706 // misc other operations
1707 // ----------------------------------------------------------------------------
1708
1709 // returns TRUE if the string matches the pattern which may contain '*' and
1710 // '?' metacharacters (as usual, '?' matches any character and '*' any number
1711 // of them)
1712 bool wxString::Matches(const wxChar *pszMask) const
1713 {
1714 // I disable this code as it doesn't seem to be faster (in fact, it seems
1715 // to be much slower) than the old, hand-written code below and using it
1716 // here requires always linking with libregex even if the user code doesn't
1717 // use it
1718 #if 0 // wxUSE_REGEX
1719 // first translate the shell-like mask into a regex
1720 wxString pattern;
1721 pattern.reserve(wxStrlen(pszMask));
1722
1723 pattern += _T('^');
1724 while ( *pszMask )
1725 {
1726 switch ( *pszMask )
1727 {
1728 case _T('?'):
1729 pattern += _T('.');
1730 break;
1731
1732 case _T('*'):
1733 pattern += _T(".*");
1734 break;
1735
1736 case _T('^'):
1737 case _T('.'):
1738 case _T('$'):
1739 case _T('('):
1740 case _T(')'):
1741 case _T('|'):
1742 case _T('+'):
1743 case _T('\\'):
1744 // these characters are special in a RE, quote them
1745 // (however note that we don't quote '[' and ']' to allow
1746 // using them for Unix shell like matching)
1747 pattern += _T('\\');
1748 // fall through
1749
1750 default:
1751 pattern += *pszMask;
1752 }
1753
1754 pszMask++;
1755 }
1756 pattern += _T('$');
1757
1758 // and now use it
1759 return wxRegEx(pattern, wxRE_NOSUB | wxRE_EXTENDED).Matches(c_str());
1760 #else // !wxUSE_REGEX
1761 // TODO: this is, of course, awfully inefficient...
1762
1763 // the char currently being checked
1764 const wxChar *pszTxt = c_str();
1765
1766 // the last location where '*' matched
1767 const wxChar *pszLastStarInText = NULL;
1768 const wxChar *pszLastStarInMask = NULL;
1769
1770 match:
1771 for ( ; *pszMask != wxT('\0'); pszMask++, pszTxt++ ) {
1772 switch ( *pszMask ) {
1773 case wxT('?'):
1774 if ( *pszTxt == wxT('\0') )
1775 return FALSE;
1776
1777 // pszTxt and pszMask will be incremented in the loop statement
1778
1779 break;
1780
1781 case wxT('*'):
1782 {
1783 // remember where we started to be able to backtrack later
1784 pszLastStarInText = pszTxt;
1785 pszLastStarInMask = pszMask;
1786
1787 // ignore special chars immediately following this one
1788 // (should this be an error?)
1789 while ( *pszMask == wxT('*') || *pszMask == wxT('?') )
1790 pszMask++;
1791
1792 // if there is nothing more, match
1793 if ( *pszMask == wxT('\0') )
1794 return TRUE;
1795
1796 // are there any other metacharacters in the mask?
1797 size_t uiLenMask;
1798 const wxChar *pEndMask = wxStrpbrk(pszMask, wxT("*?"));
1799
1800 if ( pEndMask != NULL ) {
1801 // we have to match the string between two metachars
1802 uiLenMask = pEndMask - pszMask;
1803 }
1804 else {
1805 // we have to match the remainder of the string
1806 uiLenMask = wxStrlen(pszMask);
1807 }
1808
1809 wxString strToMatch(pszMask, uiLenMask);
1810 const wxChar* pMatch = wxStrstr(pszTxt, strToMatch);
1811 if ( pMatch == NULL )
1812 return FALSE;
1813
1814 // -1 to compensate "++" in the loop
1815 pszTxt = pMatch + uiLenMask - 1;
1816 pszMask += uiLenMask - 1;
1817 }
1818 break;
1819
1820 default:
1821 if ( *pszMask != *pszTxt )
1822 return FALSE;
1823 break;
1824 }
1825 }
1826
1827 // match only if nothing left
1828 if ( *pszTxt == wxT('\0') )
1829 return TRUE;
1830
1831 // if we failed to match, backtrack if we can
1832 if ( pszLastStarInText ) {
1833 pszTxt = pszLastStarInText + 1;
1834 pszMask = pszLastStarInMask;
1835
1836 pszLastStarInText = NULL;
1837
1838 // don't bother resetting pszLastStarInMask, it's unnecessary
1839
1840 goto match;
1841 }
1842
1843 return FALSE;
1844 #endif // wxUSE_REGEX/!wxUSE_REGEX
1845 }
1846
1847 // Count the number of chars
1848 int wxString::Freq(wxChar ch) const
1849 {
1850 int count = 0;
1851 int len = Len();
1852 for (int i = 0; i < len; i++)
1853 {
1854 if (GetChar(i) == ch)
1855 count ++;
1856 }
1857 return count;
1858 }
1859
1860 // convert to upper case, return the copy of the string
1861 wxString wxString::Upper() const
1862 { wxString s(*this); return s.MakeUpper(); }
1863
1864 // convert to lower case, return the copy of the string
1865 wxString wxString::Lower() const { wxString s(*this); return s.MakeLower(); }
1866
1867 int wxString::sprintf(const wxChar *pszFormat, ...)
1868 {
1869 va_list argptr;
1870 va_start(argptr, pszFormat);
1871 int iLen = PrintfV(pszFormat, argptr);
1872 va_end(argptr);
1873 return iLen;
1874 }
1875
1876 // ============================================================================
1877 // ArrayString
1878 // ============================================================================
1879
1880 #include "wx/arrstr.h"
1881
1882 #if !wxUSE_STL
1883
1884 // size increment = min(50% of current size, ARRAY_MAXSIZE_INCREMENT)
1885 #define ARRAY_MAXSIZE_INCREMENT 4096
1886
1887 #ifndef ARRAY_DEFAULT_INITIAL_SIZE // also defined in dynarray.h
1888 #define ARRAY_DEFAULT_INITIAL_SIZE (16)
1889 #endif
1890
1891 #define STRING(p) ((wxString *)(&(p)))
1892
1893 // ctor
1894 void wxArrayString::Init(bool autoSort)
1895 {
1896 m_nSize =
1897 m_nCount = 0;
1898 m_pItems = (wxChar **) NULL;
1899 m_autoSort = autoSort;
1900 }
1901
1902 // copy ctor
1903 wxArrayString::wxArrayString(const wxArrayString& src)
1904 {
1905 Init(src.m_autoSort);
1906
1907 *this = src;
1908 }
1909
1910 // assignment operator
1911 wxArrayString& wxArrayString::operator=(const wxArrayString& src)
1912 {
1913 if ( m_nSize > 0 )
1914 Clear();
1915
1916 Copy(src);
1917
1918 m_autoSort = src.m_autoSort;
1919
1920 return *this;
1921 }
1922
1923 void wxArrayString::Copy(const wxArrayString& src)
1924 {
1925 if ( src.m_nCount > ARRAY_DEFAULT_INITIAL_SIZE )
1926 Alloc(src.m_nCount);
1927
1928 for ( size_t n = 0; n < src.m_nCount; n++ )
1929 Add(src[n]);
1930 }
1931
1932 // grow the array
1933 void wxArrayString::Grow(size_t nIncrement)
1934 {
1935 // only do it if no more place
1936 if ( (m_nSize - m_nCount) < nIncrement ) {
1937 // if ARRAY_DEFAULT_INITIAL_SIZE were set to 0, the initially empty would
1938 // be never resized!
1939 #if ARRAY_DEFAULT_INITIAL_SIZE == 0
1940 #error "ARRAY_DEFAULT_INITIAL_SIZE must be > 0!"
1941 #endif
1942
1943 if ( m_nSize == 0 ) {
1944 // was empty, alloc some memory
1945 m_nSize = ARRAY_DEFAULT_INITIAL_SIZE;
1946 if (m_nSize < nIncrement)
1947 m_nSize = nIncrement;
1948 m_pItems = new wxChar *[m_nSize];
1949 }
1950 else {
1951 // otherwise when it's called for the first time, nIncrement would be 0
1952 // and the array would never be expanded
1953 // add 50% but not too much
1954 size_t ndefIncrement = m_nSize < ARRAY_DEFAULT_INITIAL_SIZE
1955 ? ARRAY_DEFAULT_INITIAL_SIZE : m_nSize >> 1;
1956 if ( ndefIncrement > ARRAY_MAXSIZE_INCREMENT )
1957 ndefIncrement = ARRAY_MAXSIZE_INCREMENT;
1958 if ( nIncrement < ndefIncrement )
1959 nIncrement = ndefIncrement;
1960 m_nSize += nIncrement;
1961 wxChar **pNew = new wxChar *[m_nSize];
1962
1963 // copy data to new location
1964 memcpy(pNew, m_pItems, m_nCount*sizeof(wxChar *));
1965
1966 // delete old memory (but do not release the strings!)
1967 wxDELETEA(m_pItems);
1968
1969 m_pItems = pNew;
1970 }
1971 }
1972 }
1973
1974 void wxArrayString::Free()
1975 {
1976 for ( size_t n = 0; n < m_nCount; n++ ) {
1977 STRING(m_pItems[n])->GetStringData()->Unlock();
1978 }
1979 }
1980
1981 // deletes all the strings from the list
1982 void wxArrayString::Empty()
1983 {
1984 Free();
1985
1986 m_nCount = 0;
1987 }
1988
1989 // as Empty, but also frees memory
1990 void wxArrayString::Clear()
1991 {
1992 Free();
1993
1994 m_nSize =
1995 m_nCount = 0;
1996
1997 wxDELETEA(m_pItems);
1998 }
1999
2000 // dtor
2001 wxArrayString::~wxArrayString()
2002 {
2003 Free();
2004
2005 wxDELETEA(m_pItems);
2006 }
2007
2008 void wxArrayString::reserve(size_t nSize)
2009 {
2010 Alloc(nSize);
2011 }
2012
2013 // pre-allocates memory (frees the previous data!)
2014 void wxArrayString::Alloc(size_t nSize)
2015 {
2016 // only if old buffer was not big enough
2017 if ( nSize > m_nSize ) {
2018 Free();
2019 wxDELETEA(m_pItems);
2020 m_pItems = new wxChar *[nSize];
2021 m_nSize = nSize;
2022 }
2023
2024 m_nCount = 0;
2025 }
2026
2027 // minimizes the memory usage by freeing unused memory
2028 void wxArrayString::Shrink()
2029 {
2030 // only do it if we have some memory to free
2031 if( m_nCount < m_nSize ) {
2032 // allocates exactly as much memory as we need
2033 wxChar **pNew = new wxChar *[m_nCount];
2034
2035 // copy data to new location
2036 memcpy(pNew, m_pItems, m_nCount*sizeof(wxChar *));
2037 delete [] m_pItems;
2038 m_pItems = pNew;
2039 }
2040 }
2041
2042 #if WXWIN_COMPATIBILITY_2_4
2043
2044 // return a wxString[] as required for some control ctors.
2045 wxString* wxArrayString::GetStringArray() const
2046 {
2047 wxString *array = 0;
2048
2049 if( m_nCount > 0 )
2050 {
2051 array = new wxString[m_nCount];
2052 for( size_t i = 0; i < m_nCount; i++ )
2053 array[i] = m_pItems[i];
2054 }
2055
2056 return array;
2057 }
2058
2059 #endif // WXWIN_COMPATIBILITY_2_4
2060
2061 // searches the array for an item (forward or backwards)
2062 int wxArrayString::Index(const wxChar *sz, bool bCase, bool bFromEnd) const
2063 {
2064 if ( m_autoSort ) {
2065 // use binary search in the sorted array
2066 wxASSERT_MSG( bCase && !bFromEnd,
2067 wxT("search parameters ignored for auto sorted array") );
2068
2069 size_t i,
2070 lo = 0,
2071 hi = m_nCount;
2072 int res;
2073 while ( lo < hi ) {
2074 i = (lo + hi)/2;
2075
2076 res = wxStrcmp(sz, m_pItems[i]);
2077 if ( res < 0 )
2078 hi = i;
2079 else if ( res > 0 )
2080 lo = i + 1;
2081 else
2082 return i;
2083 }
2084
2085 return wxNOT_FOUND;
2086 }
2087 else {
2088 // use linear search in unsorted array
2089 if ( bFromEnd ) {
2090 if ( m_nCount > 0 ) {
2091 size_t ui = m_nCount;
2092 do {
2093 if ( STRING(m_pItems[--ui])->IsSameAs(sz, bCase) )
2094 return ui;
2095 }
2096 while ( ui != 0 );
2097 }
2098 }
2099 else {
2100 for( size_t ui = 0; ui < m_nCount; ui++ ) {
2101 if( STRING(m_pItems[ui])->IsSameAs(sz, bCase) )
2102 return ui;
2103 }
2104 }
2105 }
2106
2107 return wxNOT_FOUND;
2108 }
2109
2110 // add item at the end
2111 size_t wxArrayString::Add(const wxString& str, size_t nInsert)
2112 {
2113 if ( m_autoSort ) {
2114 // insert the string at the correct position to keep the array sorted
2115 size_t i,
2116 lo = 0,
2117 hi = m_nCount;
2118 int res;
2119 while ( lo < hi ) {
2120 i = (lo + hi)/2;
2121
2122 res = wxStrcmp(str, m_pItems[i]);
2123 if ( res < 0 )
2124 hi = i;
2125 else if ( res > 0 )
2126 lo = i + 1;
2127 else {
2128 lo = hi = i;
2129 break;
2130 }
2131 }
2132
2133 wxASSERT_MSG( lo == hi, wxT("binary search broken") );
2134
2135 Insert(str, lo, nInsert);
2136
2137 return (size_t)lo;
2138 }
2139 else {
2140 wxASSERT( str.GetStringData()->IsValid() );
2141
2142 Grow(nInsert);
2143
2144 for (size_t i = 0; i < nInsert; i++)
2145 {
2146 // the string data must not be deleted!
2147 str.GetStringData()->Lock();
2148
2149 // just append
2150 m_pItems[m_nCount + i] = (wxChar *)str.c_str(); // const_cast
2151 }
2152 size_t ret = m_nCount;
2153 m_nCount += nInsert;
2154 return ret;
2155 }
2156 }
2157
2158 // add item at the given position
2159 void wxArrayString::Insert(const wxString& str, size_t nIndex, size_t nInsert)
2160 {
2161 wxASSERT( str.GetStringData()->IsValid() );
2162
2163 wxCHECK_RET( nIndex <= m_nCount, wxT("bad index in wxArrayString::Insert") );
2164 wxCHECK_RET( m_nCount <= m_nCount + nInsert,
2165 wxT("array size overflow in wxArrayString::Insert") );
2166
2167 Grow(nInsert);
2168
2169 memmove(&m_pItems[nIndex + nInsert], &m_pItems[nIndex],
2170 (m_nCount - nIndex)*sizeof(wxChar *));
2171
2172 for (size_t i = 0; i < nInsert; i++)
2173 {
2174 str.GetStringData()->Lock();
2175 m_pItems[nIndex + i] = (wxChar *)str.c_str();
2176 }
2177 m_nCount += nInsert;
2178 }
2179
2180 // expand the array
2181 void wxArrayString::SetCount(size_t count)
2182 {
2183 Alloc(count);
2184
2185 wxString s;
2186 while ( m_nCount < count )
2187 m_pItems[m_nCount++] = (wxChar *)s.c_str();
2188 }
2189
2190 // removes item from array (by index)
2191 void wxArrayString::RemoveAt(size_t nIndex, size_t nRemove)
2192 {
2193 wxCHECK_RET( nIndex < m_nCount, wxT("bad index in wxArrayString::Remove") );
2194 wxCHECK_RET( nIndex + nRemove <= m_nCount,
2195 wxT("removing too many elements in wxArrayString::Remove") );
2196
2197 // release our lock
2198 for (size_t i = 0; i < nRemove; i++)
2199 Item(nIndex + i).GetStringData()->Unlock();
2200
2201 memmove(&m_pItems[nIndex], &m_pItems[nIndex + nRemove],
2202 (m_nCount - nIndex - nRemove)*sizeof(wxChar *));
2203 m_nCount -= nRemove;
2204 }
2205
2206 // removes item from array (by value)
2207 void wxArrayString::Remove(const wxChar *sz)
2208 {
2209 int iIndex = Index(sz);
2210
2211 wxCHECK_RET( iIndex != wxNOT_FOUND,
2212 wxT("removing inexistent element in wxArrayString::Remove") );
2213
2214 RemoveAt(iIndex);
2215 }
2216
2217 void wxArrayString::assign(const_iterator first, const_iterator last)
2218 {
2219 reserve(last - first);
2220 for(; first != last; ++first)
2221 push_back(*first);
2222 }
2223
2224 // ----------------------------------------------------------------------------
2225 // sorting
2226 // ----------------------------------------------------------------------------
2227
2228 // we can only sort one array at a time with the quick-sort based
2229 // implementation
2230 #if wxUSE_THREADS
2231 // need a critical section to protect access to gs_compareFunction and
2232 // gs_sortAscending variables
2233 static wxCriticalSection *gs_critsectStringSort = NULL;
2234
2235 // call this before the value of the global sort vars is changed/after
2236 // you're finished with them
2237 #define START_SORT() wxASSERT( !gs_critsectStringSort ); \
2238 gs_critsectStringSort = new wxCriticalSection; \
2239 gs_critsectStringSort->Enter()
2240 #define END_SORT() gs_critsectStringSort->Leave(); \
2241 delete gs_critsectStringSort; \
2242 gs_critsectStringSort = NULL
2243 #else // !threads
2244 #define START_SORT()
2245 #define END_SORT()
2246 #endif // wxUSE_THREADS
2247
2248 // function to use for string comparaison
2249 static wxArrayString::CompareFunction gs_compareFunction = NULL;
2250
2251 // if we don't use the compare function, this flag tells us if we sort the
2252 // array in ascending or descending order
2253 static bool gs_sortAscending = TRUE;
2254
2255 // function which is called by quick sort
2256 extern "C" int wxC_CALLING_CONV // LINKAGEMODE
2257 wxStringCompareFunction(const void *first, const void *second)
2258 {
2259 wxString *strFirst = (wxString *)first;
2260 wxString *strSecond = (wxString *)second;
2261
2262 if ( gs_compareFunction ) {
2263 return gs_compareFunction(*strFirst, *strSecond);
2264 }
2265 else {
2266 // maybe we should use wxStrcoll
2267 int result = wxStrcmp(strFirst->c_str(), strSecond->c_str());
2268
2269 return gs_sortAscending ? result : -result;
2270 }
2271 }
2272
2273 // sort array elements using passed comparaison function
2274 void wxArrayString::Sort(CompareFunction compareFunction)
2275 {
2276 START_SORT();
2277
2278 wxASSERT( !gs_compareFunction ); // must have been reset to NULL
2279 gs_compareFunction = compareFunction;
2280
2281 DoSort();
2282
2283 // reset it to NULL so that Sort(bool) will work the next time
2284 gs_compareFunction = NULL;
2285
2286 END_SORT();
2287 }
2288
2289 typedef int (wxC_CALLING_CONV * wxStringCompareFn)(const void *first, const void *second);
2290
2291 void wxArrayString::Sort(CompareFunction2 compareFunction)
2292 {
2293 qsort(m_pItems, m_nCount, sizeof(wxChar *), (wxStringCompareFn)compareFunction);
2294 }
2295
2296 void wxArrayString::Sort(bool reverseOrder)
2297 {
2298 Sort(reverseOrder ? wxStringSortDescending : wxStringSortAscending);
2299 }
2300
2301 void wxArrayString::DoSort()
2302 {
2303 wxCHECK_RET( !m_autoSort, wxT("can't use this method with sorted arrays") );
2304
2305 // just sort the pointers using qsort() - of course it only works because
2306 // wxString() *is* a pointer to its data
2307 qsort(m_pItems, m_nCount, sizeof(wxChar *), wxStringCompareFunction);
2308 }
2309
2310 bool wxArrayString::operator==(const wxArrayString& a) const
2311 {
2312 if ( m_nCount != a.m_nCount )
2313 return FALSE;
2314
2315 for ( size_t n = 0; n < m_nCount; n++ )
2316 {
2317 if ( Item(n) != a[n] )
2318 return FALSE;
2319 }
2320
2321 return TRUE;
2322 }
2323
2324 #endif // !wxUSE_STL
2325
2326 int wxStringSortAscending(wxString* s1, wxString* s2)
2327 {
2328 return wxStrcmp(s1->c_str(), s2->c_str());
2329 }
2330
2331 int wxStringSortDescending(wxString* s1, wxString* s2)
2332 {
2333 return -wxStrcmp(s1->c_str(), s2->c_str());
2334 }