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