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