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