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