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