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