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