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: string.cpp 63008 2009-12-28 20:01:39Z VZ $
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
operator <<(wxSTD ostream & os,const wxString & str)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:
Averager(const wxChar * sz)118 Averager(const wxChar *sz) { m_sz = sz; m_nTotal = m_nCount = 0; }
~Averager()119 ~Averager()
120 { wxPrintf("wxString: average %s = %f\n", m_sz, ((float)m_nTotal)/m_nCount); }
121
Add(size_t n)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!")
Free()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
InitWith(const wxChar * psz,size_t nPos,size_t nLength)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
wxStringBase(const void * pStart,const void * pEnd)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
wxStringBase(size_type n,wxChar ch)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
AllocBuffer(size_t 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 wxCHECK( nLen < (INT_MAX / sizeof(wxChar)) -
213 (sizeof(wxStringData) + EXTRA_ALLOC + 1), false );
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
CopyBeforeWrite()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
AllocBeforeWrite(size_t nLen)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
append(size_t n,wxChar ch)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
resize(size_t nSize,wxChar ch)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
Alloc(size_t nLen)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
begin()387 wxStringBase::iterator wxStringBase::begin()
388 {
389 if (length() > 0)
390 CopyBeforeWrite();
391 return m_pchData;
392 }
393
end()394 wxStringBase::iterator wxStringBase::end()
395 {
396 if (length() > 0)
397 CopyBeforeWrite();
398 return m_pchData + length();
399 }
400
erase(iterator it)401 wxStringBase::iterator wxStringBase::erase(iterator it)
402 {
403 size_type idx = it - begin();
404 erase(idx, 1);
405 return begin() + idx;
406 }
407
erase(size_t nStart,size_t nLen)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
insert(size_t nPos,const wxChar * sz,size_t n)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
swap(wxStringBase & str)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
find(const wxStringBase & str,size_t nStart) const448 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
find(const wxChar * sz,size_t nStart,size_t n) const493 size_t wxStringBase::find(const wxChar* sz, size_t nStart, size_t n) const
494 {
495 return find(wxStringBase(sz, n), nStart);
496 }
497
find(wxChar ch,size_t nStart) const498 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
rfind(const wxStringBase & str,size_t nStart) const507 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
rfind(const wxChar * sz,size_t nStart,size_t n) const540 size_t wxStringBase::rfind(const wxChar* sz, size_t nStart, size_t n) const
541 {
542 return rfind(wxStringBase(sz, n), nStart);
543 }
544
rfind(wxChar ch,size_t nStart) const545 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
find_first_of(const wxChar * sz,size_t nStart) const567 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
find_first_of(const wxChar * sz,size_t nStart,size_t n) const586 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
find_last_of(const wxChar * sz,size_t nStart) const592 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
find_last_of(const wxChar * sz,size_t nStart,size_t n) const615 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
find_first_not_of(const wxChar * sz,size_t nStart) const621 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
find_first_not_of(const wxChar * sz,size_t nStart,size_t n) const647 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
find_first_not_of(wxChar ch,size_t nStart) const653 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
find_last_not_of(const wxChar * sz,size_t nStart) const666 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
find_last_not_of(const wxChar * sz,size_t nStart,size_t n) const688 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
find_last_not_of(wxChar ch,size_t nStart) const694 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
replace(size_t nStart,size_t nLen,const wxChar * sz)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
replace(size_t nStart,size_t nLen,size_t nCount,wxChar ch)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
replace(size_t nStart,size_t nLen,const wxStringBase & str,size_t nStart2,size_t nLen2)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
replace(size_t nStart,size_t nLen,const wxChar * sz,size_t nCount)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
substr(size_t nStart,size_t nLen) const765 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
operator =(const wxStringBase & stringSrc)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
operator =(wxChar ch)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
operator =(const wxChar * psz)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
AssignCopy(size_t nSrcLen,const wxChar * pszSrcData)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
823 // use memmove() and not memcpy() here as we might be copying from our own
824 // buffer in case of assignment such as "s = s.c_str()" (see #11294)
825 memmove(m_pchData, pszSrcData, nSrcLen*sizeof(wxChar));
826
827 GetStringData()->nDataLength = nSrcLen;
828 m_pchData[nSrcLen] = wxT('\0');
829 }
830 return true;
831 }
832
833 // ---------------------------------------------------------------------------
834 // string concatenation
835 // ---------------------------------------------------------------------------
836
837 // add something to this string
ConcatSelf(size_t nSrcLen,const wxChar * pszSrcData,size_t nMaxLen)838 bool wxStringBase::ConcatSelf(size_t nSrcLen, const wxChar *pszSrcData,
839 size_t nMaxLen)
840 {
841 STATISTICS_ADD(SummandLength, nSrcLen);
842
843 nSrcLen = nSrcLen < nMaxLen ? nSrcLen : nMaxLen;
844
845 // concatenating an empty string is a NOP
846 if ( nSrcLen > 0 ) {
847 wxStringData *pData = GetStringData();
848 size_t nLen = pData->nDataLength;
849 size_t nNewLen = nLen + nSrcLen;
850
851 // take special care when appending part of this string to itself: the code
852 // below reallocates our buffer and this invalidates pszSrcData pointer so
853 // we have to copy it in another temporary string in this case (but avoid
854 // doing this unnecessarily)
855 if ( pszSrcData >= m_pchData && pszSrcData < m_pchData + nLen )
856 {
857 wxStringBase tmp(pszSrcData, nSrcLen);
858 return ConcatSelf(nSrcLen, tmp.m_pchData, nSrcLen);
859 }
860
861 // alloc new buffer if current is too small
862 if ( pData->IsShared() ) {
863 STATISTICS_ADD(ConcatHit, 0);
864
865 // we have to allocate another buffer
866 wxStringData* pOldData = GetStringData();
867 if ( !AllocBuffer(nNewLen) ) {
868 // allocation failure handled by caller
869 return false;
870 }
871 memcpy(m_pchData, pOldData->data(), nLen*sizeof(wxChar));
872 pOldData->Unlock();
873 }
874 else if ( nNewLen > pData->nAllocLength ) {
875 STATISTICS_ADD(ConcatHit, 0);
876
877 reserve(nNewLen);
878 // we have to grow the buffer
879 if ( capacity() < nNewLen ) {
880 // allocation failure handled by caller
881 return false;
882 }
883 }
884 else {
885 STATISTICS_ADD(ConcatHit, 1);
886
887 // the buffer is already big enough
888 }
889
890 // should be enough space
891 wxASSERT( nNewLen <= GetStringData()->nAllocLength );
892
893 // fast concatenation - all is done in our buffer
894 memcpy(m_pchData + nLen, pszSrcData, nSrcLen*sizeof(wxChar));
895
896 m_pchData[nNewLen] = wxT('\0'); // put terminating '\0'
897 GetStringData()->nDataLength = nNewLen; // and fix the length
898 }
899 //else: the string to append was empty
900 return true;
901 }
902
903 // ---------------------------------------------------------------------------
904 // simple sub-string extraction
905 // ---------------------------------------------------------------------------
906
907 // helper function: clone the data attached to this string
AllocCopy(wxString & dest,int nCopyLen,int nCopyIndex) const908 bool wxStringBase::AllocCopy(wxString& dest, int nCopyLen, int nCopyIndex) const
909 {
910 if ( nCopyLen == 0 ) {
911 dest.Init();
912 }
913 else {
914 if ( !dest.AllocBuffer(nCopyLen) ) {
915 // allocation failure handled by caller
916 return false;
917 }
918 memcpy(dest.m_pchData, m_pchData + nCopyIndex, nCopyLen*sizeof(wxChar));
919 }
920 return true;
921 }
922
923 #endif // !wxUSE_STL
924
925 #if !wxUSE_STL || !defined(HAVE_STD_STRING_COMPARE)
926
927 #if !wxUSE_STL
928 #define STRINGCLASS wxStringBase
929 #else
930 #define STRINGCLASS wxString
931 #endif
932
wxDoCmp(const wxChar * s1,size_t l1,const wxChar * s2,size_t l2)933 static inline int wxDoCmp(const wxChar* s1, size_t l1,
934 const wxChar* s2, size_t l2)
935 {
936 if( l1 == l2 )
937 return wxTmemcmp(s1, s2, l1);
938 else if( l1 < l2 )
939 {
940 int ret = wxTmemcmp(s1, s2, l1);
941 return ret == 0 ? -1 : ret;
942 }
943 else
944 {
945 int ret = wxTmemcmp(s1, s2, l2);
946 return ret == 0 ? +1 : ret;
947 }
948 }
949
compare(const wxStringBase & str) const950 int STRINGCLASS::compare(const wxStringBase& str) const
951 {
952 return ::wxDoCmp(data(), length(), str.data(), str.length());
953 }
954
compare(size_t nStart,size_t nLen,const wxStringBase & str) const955 int STRINGCLASS::compare(size_t nStart, size_t nLen,
956 const wxStringBase& str) const
957 {
958 wxASSERT(nStart <= length());
959 size_type strLen = length() - nStart;
960 nLen = strLen < nLen ? strLen : nLen;
961 return ::wxDoCmp(data() + nStart, nLen, str.data(), str.length());
962 }
963
compare(size_t nStart,size_t nLen,const wxStringBase & str,size_t nStart2,size_t nLen2) const964 int STRINGCLASS::compare(size_t nStart, size_t nLen,
965 const wxStringBase& str,
966 size_t nStart2, size_t nLen2) const
967 {
968 wxASSERT(nStart <= length());
969 wxASSERT(nStart2 <= str.length());
970 size_type strLen = length() - nStart,
971 strLen2 = str.length() - nStart2;
972 nLen = strLen < nLen ? strLen : nLen;
973 nLen2 = strLen2 < nLen2 ? strLen2 : nLen2;
974 return ::wxDoCmp(data() + nStart, nLen, str.data() + nStart2, nLen2);
975 }
976
compare(const wxChar * sz) const977 int STRINGCLASS::compare(const wxChar* sz) const
978 {
979 size_t nLen = wxStrlen(sz);
980 return ::wxDoCmp(data(), length(), sz, nLen);
981 }
982
compare(size_t nStart,size_t nLen,const wxChar * sz,size_t nCount) const983 int STRINGCLASS::compare(size_t nStart, size_t nLen,
984 const wxChar* sz, size_t nCount) const
985 {
986 wxASSERT(nStart <= length());
987 size_type strLen = length() - nStart;
988 nLen = strLen < nLen ? strLen : nLen;
989 if( nCount == npos )
990 nCount = wxStrlen(sz);
991
992 return ::wxDoCmp(data() + nStart, nLen, sz, nCount);
993 }
994
995 #undef STRINGCLASS
996
997 #endif // !wxUSE_STL || !defined(HAVE_STD_STRING_COMPARE)
998
999 // ===========================================================================
1000 // wxString class core
1001 // ===========================================================================
1002
1003 // ---------------------------------------------------------------------------
1004 // construction and conversion
1005 // ---------------------------------------------------------------------------
1006
1007 #if wxUSE_UNICODE
1008
1009 // from multibyte string
wxString(const char * psz,const wxMBConv & conv,size_t nLength)1010 wxString::wxString(const char *psz, const wxMBConv& conv, size_t nLength)
1011 {
1012 // anything to do?
1013 if ( psz && nLength != 0 )
1014 {
1015 if ( nLength == npos )
1016 {
1017 nLength = wxNO_LEN;
1018 }
1019
1020 size_t nLenWide;
1021 wxWCharBuffer wbuf = conv.cMB2WC(psz, nLength, &nLenWide);
1022
1023 if ( nLenWide )
1024 assign(wbuf, nLenWide);
1025 }
1026 }
1027
1028 //Convert wxString in Unicode mode to a multi-byte string
mb_str(const wxMBConv & conv) const1029 const wxCharBuffer wxString::mb_str(const wxMBConv& conv) const
1030 {
1031 return conv.cWC2MB(c_str(), length() + 1 /* size, not length */, NULL);
1032 }
1033
1034 #else // ANSI
1035
1036 #if wxUSE_WCHAR_T
1037
1038 // from wide string
wxString(const wchar_t * pwz,const wxMBConv & conv,size_t nLength)1039 wxString::wxString(const wchar_t *pwz, const wxMBConv& conv, size_t nLength)
1040 {
1041 // anything to do?
1042 if ( pwz && nLength != 0 )
1043 {
1044 if ( nLength == npos )
1045 {
1046 nLength = wxNO_LEN;
1047 }
1048
1049 size_t nLenMB;
1050 wxCharBuffer buf = conv.cWC2MB(pwz, nLength, &nLenMB);
1051
1052 if ( nLenMB )
1053 assign(buf, nLenMB);
1054 }
1055 }
1056
1057 //Converts this string to a wide character string if unicode
1058 //mode is not enabled and wxUSE_WCHAR_T is enabled
wc_str(const wxMBConv & conv) const1059 const wxWCharBuffer wxString::wc_str(const wxMBConv& conv) const
1060 {
1061 return conv.cMB2WC(c_str(), length() + 1 /* size, not length */, NULL);
1062 }
1063
1064 #endif // wxUSE_WCHAR_T
1065
1066 #endif // Unicode/ANSI
1067
1068 // shrink to minimal size (releasing extra memory)
Shrink()1069 bool wxString::Shrink()
1070 {
1071 wxString tmp(begin(), end());
1072 swap(tmp);
1073 return tmp.length() == length();
1074 }
1075
1076 #if !wxUSE_STL
1077 // get the pointer to writable buffer of (at least) nLen bytes
GetWriteBuf(size_t nLen)1078 wxChar *wxString::GetWriteBuf(size_t nLen)
1079 {
1080 if ( !AllocBeforeWrite(nLen) ) {
1081 // allocation failure handled by caller
1082 return NULL;
1083 }
1084
1085 wxASSERT( GetStringData()->nRefs == 1 );
1086 GetStringData()->Validate(false);
1087
1088 return m_pchData;
1089 }
1090
1091 // put string back in a reasonable state after GetWriteBuf
UngetWriteBuf()1092 void wxString::UngetWriteBuf()
1093 {
1094 UngetWriteBuf(wxStrlen(m_pchData));
1095 }
1096
UngetWriteBuf(size_t nLen)1097 void wxString::UngetWriteBuf(size_t nLen)
1098 {
1099 wxStringData * const pData = GetStringData();
1100
1101 wxASSERT_MSG( nLen < pData->nAllocLength, _T("buffer overrun") );
1102
1103 // the strings we store are always NUL-terminated
1104 pData->data()[nLen] = _T('\0');
1105 pData->nDataLength = nLen;
1106 pData->Validate(true);
1107 }
1108 #endif // !wxUSE_STL
1109
1110 // ---------------------------------------------------------------------------
1111 // data access
1112 // ---------------------------------------------------------------------------
1113
1114 // all functions are inline in string.h
1115
1116 // ---------------------------------------------------------------------------
1117 // assignment operators
1118 // ---------------------------------------------------------------------------
1119
1120 #if !wxUSE_UNICODE
1121
1122 // same as 'signed char' variant
operator =(const unsigned char * psz)1123 wxString& wxString::operator=(const unsigned char* psz)
1124 {
1125 *this = (const char *)psz;
1126 return *this;
1127 }
1128
1129 #if wxUSE_WCHAR_T
operator =(const wchar_t * pwz)1130 wxString& wxString::operator=(const wchar_t *pwz)
1131 {
1132 wxString str(pwz);
1133 swap(str);
1134 return *this;
1135 }
1136 #endif
1137
1138 #endif
1139
1140 /*
1141 * concatenation functions come in 5 flavours:
1142 * string + string
1143 * char + string and string + char
1144 * C str + string and string + C str
1145 */
1146
operator +(const wxString & str1,const wxString & str2)1147 wxString operator+(const wxString& str1, const wxString& str2)
1148 {
1149 #if !wxUSE_STL
1150 wxASSERT( str1.GetStringData()->IsValid() );
1151 wxASSERT( str2.GetStringData()->IsValid() );
1152 #endif
1153
1154 wxString s = str1;
1155 s += str2;
1156
1157 return s;
1158 }
1159
operator +(const wxString & str,wxChar ch)1160 wxString operator+(const wxString& str, wxChar ch)
1161 {
1162 #if !wxUSE_STL
1163 wxASSERT( str.GetStringData()->IsValid() );
1164 #endif
1165
1166 wxString s = str;
1167 s += ch;
1168
1169 return s;
1170 }
1171
operator +(wxChar ch,const wxString & str)1172 wxString operator+(wxChar ch, const wxString& str)
1173 {
1174 #if !wxUSE_STL
1175 wxASSERT( str.GetStringData()->IsValid() );
1176 #endif
1177
1178 wxString s = ch;
1179 s += str;
1180
1181 return s;
1182 }
1183
operator +(const wxString & str,const wxChar * psz)1184 wxString operator+(const wxString& str, const wxChar *psz)
1185 {
1186 #if !wxUSE_STL
1187 wxASSERT( str.GetStringData()->IsValid() );
1188 #endif
1189
1190 wxString s;
1191 if ( !s.Alloc(wxStrlen(psz) + str.length()) ) {
1192 wxFAIL_MSG( _T("out of memory in wxString::operator+") );
1193 }
1194 s += str;
1195 s += psz;
1196
1197 return s;
1198 }
1199
operator +(const wxChar * psz,const wxString & str)1200 wxString operator+(const wxChar *psz, const wxString& str)
1201 {
1202 #if !wxUSE_STL
1203 wxASSERT( str.GetStringData()->IsValid() );
1204 #endif
1205
1206 wxString s;
1207 if ( !s.Alloc(wxStrlen(psz) + str.length()) ) {
1208 wxFAIL_MSG( _T("out of memory in wxString::operator+") );
1209 }
1210 s = psz;
1211 s += str;
1212
1213 return s;
1214 }
1215
1216 // ===========================================================================
1217 // other common string functions
1218 // ===========================================================================
1219
Cmp(const wxString & s) const1220 int wxString::Cmp(const wxString& s) const
1221 {
1222 return compare(s);
1223 }
1224
Cmp(const wxChar * psz) const1225 int wxString::Cmp(const wxChar* psz) const
1226 {
1227 return compare(psz);
1228 }
1229
wxDoCmpNoCase(const wxChar * s1,size_t l1,const wxChar * s2,size_t l2)1230 static inline int wxDoCmpNoCase(const wxChar* s1, size_t l1,
1231 const wxChar* s2, size_t l2)
1232 {
1233 size_t i;
1234
1235 if( l1 == l2 )
1236 {
1237 for(i = 0; i < l1; ++i)
1238 {
1239 if(wxTolower(s1[i]) != wxTolower(s2[i]))
1240 break;
1241 }
1242 return i == l1 ? 0 : wxTolower(s1[i]) < wxTolower(s2[i]) ? -1 : 1;
1243 }
1244 else if( l1 < l2 )
1245 {
1246 for(i = 0; i < l1; ++i)
1247 {
1248 if(wxTolower(s1[i]) != wxTolower(s2[i]))
1249 break;
1250 }
1251 return i == l1 ? -1 : wxTolower(s1[i]) < wxTolower(s2[i]) ? -1 : 1;
1252 }
1253 else
1254 {
1255 for(i = 0; i < l2; ++i)
1256 {
1257 if(wxTolower(s1[i]) != wxTolower(s2[i]))
1258 break;
1259 }
1260 return i == l2 ? 1 : wxTolower(s1[i]) < wxTolower(s2[i]) ? -1 : 1;
1261 }
1262 }
1263
CmpNoCase(const wxString & s) const1264 int wxString::CmpNoCase(const wxString& s) const
1265 {
1266 return wxDoCmpNoCase(data(), length(), s.data(), s.length());
1267 }
1268
CmpNoCase(const wxChar * psz) const1269 int wxString::CmpNoCase(const wxChar* psz) const
1270 {
1271 int nLen = wxStrlen(psz);
1272
1273 return wxDoCmpNoCase(data(), length(), psz, nLen);
1274 }
1275
1276
1277 #if wxUSE_UNICODE
1278
1279 #ifdef __MWERKS__
1280 #ifndef __SCHAR_MAX__
1281 #define __SCHAR_MAX__ 127
1282 #endif
1283 #endif
1284
FromAscii(const char * ascii)1285 wxString wxString::FromAscii(const char *ascii)
1286 {
1287 if (!ascii)
1288 return wxEmptyString;
1289
1290 size_t len = strlen( ascii );
1291 wxString res;
1292
1293 if ( len )
1294 {
1295 wxStringBuffer buf(res, len);
1296
1297 wchar_t *dest = buf;
1298
1299 for ( ;; )
1300 {
1301 if ( (*dest++ = (wchar_t)(unsigned char)*ascii++) == L'\0' )
1302 break;
1303 }
1304 }
1305
1306 return res;
1307 }
1308
FromAscii(const char ascii)1309 wxString wxString::FromAscii(const char ascii)
1310 {
1311 // What do we do with '\0' ?
1312
1313 wxString res;
1314 res += (wchar_t)(unsigned char) ascii;
1315
1316 return res;
1317 }
1318
ToAscii() const1319 const wxCharBuffer wxString::ToAscii() const
1320 {
1321 // this will allocate enough space for the terminating NUL too
1322 wxCharBuffer buffer(length());
1323
1324
1325 char *dest = buffer.data();
1326
1327 const wchar_t *pwc = c_str();
1328 for ( ;; )
1329 {
1330 *dest++ = (char)(*pwc > SCHAR_MAX ? wxT('_') : *pwc);
1331
1332 // the output string can't have embedded NULs anyhow, so we can safely
1333 // stop at first of them even if we do have any
1334 if ( !*pwc++ )
1335 break;
1336 }
1337
1338 return buffer;
1339 }
1340
1341 #endif // Unicode
1342
1343 // extract string of length nCount starting at nFirst
Mid(size_t nFirst,size_t nCount) const1344 wxString wxString::Mid(size_t nFirst, size_t nCount) const
1345 {
1346 size_t nLen = length();
1347
1348 // default value of nCount is npos and means "till the end"
1349 if ( nCount == npos )
1350 {
1351 nCount = nLen - nFirst;
1352 }
1353
1354 // out-of-bounds requests return sensible things
1355 if ( nFirst + nCount > nLen )
1356 {
1357 nCount = nLen - nFirst;
1358 }
1359
1360 if ( nFirst > nLen )
1361 {
1362 // AllocCopy() will return empty string
1363 return wxEmptyString;
1364 }
1365
1366 wxString dest(*this, nFirst, nCount);
1367 if ( dest.length() != nCount )
1368 {
1369 wxFAIL_MSG( _T("out of memory in wxString::Mid") );
1370 }
1371
1372 return dest;
1373 }
1374
1375 // check that the string starts with prefix and return the rest of the string
1376 // in the provided pointer if it is not NULL, otherwise return false
StartsWith(const wxChar * prefix,wxString * rest) const1377 bool wxString::StartsWith(const wxChar *prefix, wxString *rest) const
1378 {
1379 wxASSERT_MSG( prefix, _T("invalid parameter in wxString::StartsWith") );
1380
1381 // first check if the beginning of the string matches the prefix: note
1382 // that we don't have to check that we don't run out of this string as
1383 // when we reach the terminating NUL, either prefix string ends too (and
1384 // then it's ok) or we break out of the loop because there is no match
1385 const wxChar *p = c_str();
1386 while ( *prefix )
1387 {
1388 if ( *prefix++ != *p++ )
1389 {
1390 // no match
1391 return false;
1392 }
1393 }
1394
1395 if ( rest )
1396 {
1397 // put the rest of the string into provided pointer
1398 *rest = p;
1399 }
1400
1401 return true;
1402 }
1403
1404
1405 // check that the string ends with suffix and return the rest of it in the
1406 // provided pointer if it is not NULL, otherwise return false
EndsWith(const wxChar * suffix,wxString * rest) const1407 bool wxString::EndsWith(const wxChar *suffix, wxString *rest) const
1408 {
1409 wxASSERT_MSG( suffix, _T("invalid parameter in wxString::EndssWith") );
1410
1411 int start = length() - wxStrlen(suffix);
1412 if ( start < 0 || wxStrcmp(c_str() + start, suffix) != 0 )
1413 return false;
1414
1415 if ( rest )
1416 {
1417 // put the rest of the string into provided pointer
1418 rest->assign(*this, 0, start);
1419 }
1420
1421 return true;
1422 }
1423
1424
1425 // extract nCount last (rightmost) characters
Right(size_t nCount) const1426 wxString wxString::Right(size_t nCount) const
1427 {
1428 if ( nCount > length() )
1429 nCount = length();
1430
1431 wxString dest(*this, length() - nCount, nCount);
1432 if ( dest.length() != nCount ) {
1433 wxFAIL_MSG( _T("out of memory in wxString::Right") );
1434 }
1435 return dest;
1436 }
1437
1438 // get all characters after the last occurence of ch
1439 // (returns the whole string if ch not found)
AfterLast(wxChar ch) const1440 wxString wxString::AfterLast(wxChar ch) const
1441 {
1442 wxString str;
1443 int iPos = Find(ch, true);
1444 if ( iPos == wxNOT_FOUND )
1445 str = *this;
1446 else
1447 str = c_str() + iPos + 1;
1448
1449 return str;
1450 }
1451
1452 // extract nCount first (leftmost) characters
Left(size_t nCount) const1453 wxString wxString::Left(size_t nCount) const
1454 {
1455 if ( nCount > length() )
1456 nCount = length();
1457
1458 wxString dest(*this, 0, nCount);
1459 if ( dest.length() != nCount ) {
1460 wxFAIL_MSG( _T("out of memory in wxString::Left") );
1461 }
1462 return dest;
1463 }
1464
1465 // get all characters before the first occurence of ch
1466 // (returns the whole string if ch not found)
BeforeFirst(wxChar ch) const1467 wxString wxString::BeforeFirst(wxChar ch) const
1468 {
1469 int iPos = Find(ch);
1470 if ( iPos == wxNOT_FOUND ) iPos = length();
1471 return wxString(*this, 0, iPos);
1472 }
1473
1474 /// get all characters before the last occurence of ch
1475 /// (returns empty string if ch not found)
BeforeLast(wxChar ch) const1476 wxString wxString::BeforeLast(wxChar ch) const
1477 {
1478 wxString str;
1479 int iPos = Find(ch, true);
1480 if ( iPos != wxNOT_FOUND && iPos != 0 )
1481 str = wxString(c_str(), iPos);
1482
1483 return str;
1484 }
1485
1486 /// get all characters after the first occurence of ch
1487 /// (returns empty string if ch not found)
AfterFirst(wxChar ch) const1488 wxString wxString::AfterFirst(wxChar ch) const
1489 {
1490 wxString str;
1491 int iPos = Find(ch);
1492 if ( iPos != wxNOT_FOUND )
1493 str = c_str() + iPos + 1;
1494
1495 return str;
1496 }
1497
1498 // replace first (or all) occurences of some substring with another one
1499 size_t
Replace(const wxChar * szOld,const wxChar * szNew,bool bReplaceAll)1500 wxString::Replace(const wxChar *szOld, const wxChar *szNew, bool bReplaceAll)
1501 {
1502 // if we tried to replace an empty string we'd enter an infinite loop below
1503 wxCHECK_MSG( szOld && *szOld && szNew, 0,
1504 _T("wxString::Replace(): invalid parameter") );
1505
1506 size_t uiCount = 0; // count of replacements made
1507
1508 // optimize the special common case of replacing one character with another
1509 // one
1510 if ( szOld[1] == '\0' && (szNew[0] != '\0' && szNew[1] == '\0') )
1511 {
1512 // this loop is the simplified version of the one below
1513 for ( size_t pos = 0; ; )
1514 {
1515 pos = find(*szOld, pos);
1516 if ( pos == npos )
1517 break;
1518
1519 (*this)[pos++] = *szNew;
1520
1521 uiCount++;
1522
1523 if ( !bReplaceAll )
1524 break;
1525 }
1526 }
1527 else // general case
1528 {
1529 const size_t uiOldLen = wxStrlen(szOld);
1530 const size_t uiNewLen = wxStrlen(szNew);
1531
1532 for ( size_t pos = 0; ; )
1533 {
1534 pos = find(szOld, pos);
1535 if ( pos == npos )
1536 break;
1537
1538 // replace this occurrence of the old string with the new one
1539 replace(pos, uiOldLen, szNew, uiNewLen);
1540
1541 // move past the string that was replaced
1542 pos += uiNewLen;
1543
1544 // increase replace count
1545 uiCount++;
1546
1547 // stop now?
1548 if ( !bReplaceAll )
1549 break;
1550 }
1551 }
1552
1553 return uiCount;
1554 }
1555
IsAscii() const1556 bool wxString::IsAscii() const
1557 {
1558 const wxChar *s = (const wxChar*) *this;
1559 while(*s){
1560 if(!isascii(*s)) return(false);
1561 s++;
1562 }
1563 return(true);
1564 }
1565
IsWord() const1566 bool wxString::IsWord() const
1567 {
1568 const wxChar *s = (const wxChar*) *this;
1569 while(*s){
1570 if(!wxIsalpha(*s)) return(false);
1571 s++;
1572 }
1573 return(true);
1574 }
1575
IsNumber() const1576 bool wxString::IsNumber() const
1577 {
1578 const wxChar *s = (const wxChar*) *this;
1579 if (wxStrlen(s))
1580 if ((s[0] == wxT('-')) || (s[0] == wxT('+'))) s++;
1581 while(*s){
1582 if(!wxIsdigit(*s)) return(false);
1583 s++;
1584 }
1585 return(true);
1586 }
1587
Strip(stripType w) const1588 wxString wxString::Strip(stripType w) const
1589 {
1590 wxString s = *this;
1591 if ( w & leading ) s.Trim(false);
1592 if ( w & trailing ) s.Trim(true);
1593 return s;
1594 }
1595
1596 // ---------------------------------------------------------------------------
1597 // case conversion
1598 // ---------------------------------------------------------------------------
1599
MakeUpper()1600 wxString& wxString::MakeUpper()
1601 {
1602 for ( iterator it = begin(), en = end(); it != en; ++it )
1603 *it = (wxChar)wxToupper(*it);
1604
1605 return *this;
1606 }
1607
MakeLower()1608 wxString& wxString::MakeLower()
1609 {
1610 for ( iterator it = begin(), en = end(); it != en; ++it )
1611 *it = (wxChar)wxTolower(*it);
1612
1613 return *this;
1614 }
1615
1616 // ---------------------------------------------------------------------------
1617 // trimming and padding
1618 // ---------------------------------------------------------------------------
1619
1620 // some compilers (VC++ 6.0 not to name them) return true for a call to
1621 // isspace('\xEA') in the C locale which seems to be broken to me, but we have
1622 // to live with this by checking that the character is a 7 bit one - even if
1623 // this may fail to detect some spaces (I don't know if Unicode doesn't have
1624 // space-like symbols somewhere except in the first 128 chars), it is arguably
1625 // still better than trimming away accented letters
wxSafeIsspace(wxChar ch)1626 inline int wxSafeIsspace(wxChar ch) { return (ch < 127) && wxIsspace(ch); }
1627
1628 // trims spaces (in the sense of isspace) from left or right side
Trim(bool bFromRight)1629 wxString& wxString::Trim(bool bFromRight)
1630 {
1631 // first check if we're going to modify the string at all
1632 if ( !empty() &&
1633 (
1634 (bFromRight && wxSafeIsspace(GetChar(length() - 1))) ||
1635 (!bFromRight && wxSafeIsspace(GetChar(0u)))
1636 )
1637 )
1638 {
1639 if ( bFromRight )
1640 {
1641 // find last non-space character
1642 reverse_iterator psz = rbegin();
1643 while ( (psz != rend()) && wxSafeIsspace(*psz) )
1644 psz++;
1645
1646 // truncate at trailing space start
1647 erase(psz.base(), end());
1648 }
1649 else
1650 {
1651 // find first non-space character
1652 iterator psz = begin();
1653 while ( (psz != end()) && wxSafeIsspace(*psz) )
1654 psz++;
1655
1656 // fix up data and length
1657 erase(begin(), psz);
1658 }
1659 }
1660
1661 return *this;
1662 }
1663
1664 // adds nCount characters chPad to the string from either side
Pad(size_t nCount,wxChar chPad,bool bFromRight)1665 wxString& wxString::Pad(size_t nCount, wxChar chPad, bool bFromRight)
1666 {
1667 wxString s(chPad, nCount);
1668
1669 if ( bFromRight )
1670 *this += s;
1671 else
1672 {
1673 s += *this;
1674 swap(s);
1675 }
1676
1677 return *this;
1678 }
1679
1680 // truncate the string
Truncate(size_t uiLen)1681 wxString& wxString::Truncate(size_t uiLen)
1682 {
1683 if ( uiLen < length() )
1684 {
1685 erase(begin() + uiLen, end());
1686 }
1687 //else: nothing to do, string is already short enough
1688
1689 return *this;
1690 }
1691
1692 // ---------------------------------------------------------------------------
1693 // finding (return wxNOT_FOUND if not found and index otherwise)
1694 // ---------------------------------------------------------------------------
1695
1696 // find a character
Find(wxChar ch,bool bFromEnd) const1697 int wxString::Find(wxChar ch, bool bFromEnd) const
1698 {
1699 size_type idx = bFromEnd ? find_last_of(ch) : find_first_of(ch);
1700
1701 return (idx == npos) ? wxNOT_FOUND : (int)idx;
1702 }
1703
1704 // find a sub-string (like strstr)
Find(const wxChar * pszSub) const1705 int wxString::Find(const wxChar *pszSub) const
1706 {
1707 size_type idx = find(pszSub);
1708
1709 return (idx == npos) ? wxNOT_FOUND : (int)idx;
1710 }
1711
1712 // ----------------------------------------------------------------------------
1713 // conversion to numbers
1714 // ----------------------------------------------------------------------------
1715
1716 // the implementation of all the functions below is exactly the same so factor
1717 // it out
1718
1719 template <typename T, typename F>
wxStringToIntType(const wxChar * start,T * val,int base,F func)1720 bool wxStringToIntType(const wxChar *start,
1721 T *val,
1722 int base,
1723 F func)
1724 {
1725 wxCHECK_MSG( val, false, _T("NULL output pointer") );
1726 wxASSERT_MSG( !base || (base > 1 && base <= 36), _T("invalid base") );
1727
1728 #ifndef __WXWINCE__
1729 errno = 0;
1730 #endif
1731
1732 wxChar *end;
1733 *val = (*func)(start, &end, base);
1734
1735 // return true only if scan was stopped by the terminating NUL and if the
1736 // string was not empty to start with and no under/overflow occurred
1737 return !*end && (end != start)
1738 #ifndef __WXWINCE__
1739 && (errno != ERANGE)
1740 #endif
1741 ;
1742 }
1743
ToLong(long * val,int base) const1744 bool wxString::ToLong(long *val, int base) const
1745 {
1746 return wxStringToIntType(c_str(), val, base, wxStrtol);
1747 }
1748
ToULong(unsigned long * val,int base) const1749 bool wxString::ToULong(unsigned long *val, int base) const
1750 {
1751 return wxStringToIntType(c_str(), val, base, wxStrtoul);
1752 }
1753
ToLongLong(wxLongLong_t * val,int base) const1754 bool wxString::ToLongLong(wxLongLong_t *val, int base) const
1755 {
1756 #ifdef wxHAS_STRTOLL
1757 return wxStringToIntType(c_str(), val, base, wxStrtoll);
1758 #else
1759 // TODO: implement this ourselves
1760 wxUnusedVar(val);
1761 wxUnusedVar(base);
1762 return false;
1763 #endif // wxHAS_STRTOLL
1764 }
1765
ToULongLong(wxULongLong_t * val,int base) const1766 bool wxString::ToULongLong(wxULongLong_t *val, int base) const
1767 {
1768 #ifdef wxHAS_STRTOLL
1769 return wxStringToIntType(c_str(), val, base, wxStrtoull);
1770 #else
1771 // TODO: implement this ourselves
1772 wxUnusedVar(val);
1773 wxUnusedVar(base);
1774 return false;
1775 #endif
1776 }
1777
ToDouble(double * val) const1778 bool wxString::ToDouble(double *val) const
1779 {
1780 wxCHECK_MSG( val, false, _T("NULL pointer in wxString::ToDouble") );
1781
1782 #ifndef __WXWINCE__
1783 errno = 0;
1784 #endif
1785
1786 const wxChar *start = c_str();
1787 wxChar *end;
1788 *val = wxStrtod(start, &end);
1789
1790 // return true only if scan was stopped by the terminating NUL and if the
1791 // string was not empty to start with and no under/overflow occurred
1792 return !*end && (end != start)
1793 #ifndef __WXWINCE__
1794 && (errno != ERANGE)
1795 #endif
1796 ;
1797 }
1798
1799 // ---------------------------------------------------------------------------
1800 // formatted output
1801 // ---------------------------------------------------------------------------
1802
1803 /* static */
Format(const wxChar * pszFormat,...)1804 wxString wxString::Format(const wxChar *pszFormat, ...)
1805 {
1806 va_list argptr;
1807 va_start(argptr, pszFormat);
1808
1809 wxString s;
1810 s.PrintfV(pszFormat, argptr);
1811
1812 va_end(argptr);
1813
1814 return s;
1815 }
1816
1817 /* static */
FormatV(const wxChar * pszFormat,va_list argptr)1818 wxString wxString::FormatV(const wxChar *pszFormat, va_list argptr)
1819 {
1820 wxString s;
1821 s.PrintfV(pszFormat, argptr);
1822 return s;
1823 }
1824
Printf(const wxChar * pszFormat,...)1825 int wxString::Printf(const wxChar *pszFormat, ...)
1826 {
1827 va_list argptr;
1828 va_start(argptr, pszFormat);
1829
1830 int iLen = PrintfV(pszFormat, argptr);
1831
1832 va_end(argptr);
1833
1834 return iLen;
1835 }
1836
1837 /*
1838 Uses wxVsnprintf and places the result into the this string.
1839
1840 In ANSI build, wxVsnprintf is effectively vsnprintf but in Unicode build
1841 it is vswprintf. Due to a discrepancy between vsnprintf and vswprintf in
1842 the ISO C99 (and thus SUSv3) standard the return value for the case of
1843 an undersized buffer is inconsistent. For conforming vsnprintf
1844 implementations the function must return the number of characters that
1845 would have been printed had the buffer been large enough. For conforming
1846 vswprintf implementations the function must return a negative number
1847 and set errno.
1848
1849 What vswprintf sets errno to is undefined but Darwin seems to set it to
1850 EOVERFLOW. The only expected errno are EILSEQ and EINVAL. Both of
1851 those are defined in the standard and backed up by several conformance
1852 statements. Note that ENOMEM mentioned in the manual page does not
1853 apply to swprintf, only wprintf and fwprintf.
1854
1855 Official manual page:
1856 http://www.opengroup.org/onlinepubs/009695399/functions/swprintf.html
1857
1858 Some conformance statements (AIX, Solaris):
1859 http://www.opengroup.org/csq/view.mhtml?RID=ibm%2FSD1%2F3
1860 http://www.theopengroup.org/csq/view.mhtml?norationale=1&noreferences=1&RID=Fujitsu%2FSE2%2F10
1861
1862 Since EILSEQ and EINVAL are rather common but EOVERFLOW is not and since
1863 EILSEQ and EINVAL are specifically defined to mean the error is other than
1864 an undersized buffer and no other errno are defined we treat those two
1865 as meaning hard errors and everything else gets the old behavior which
1866 is to keep looping and increasing buffer size until the function succeeds.
1867
1868 In practice it's impossible to determine before compilation which behavior
1869 may be used. The vswprintf function may have vsnprintf-like behavior or
1870 vice-versa. Behavior detected on one release can theoretically change
1871 with an updated release. Not to mention that configure testing for it
1872 would require the test to be run on the host system, not the build system
1873 which makes cross compilation difficult. Therefore, we make no assumptions
1874 about behavior and try our best to handle every known case, including the
1875 case where wxVsnprintf returns a negative number and fails to set errno.
1876
1877 There is yet one more non-standard implementation and that is our own.
1878 Fortunately, that can be detected at compile-time.
1879
1880 On top of all that, ISO C99 explicitly defines snprintf to write a null
1881 character to the last position of the specified buffer. That would be at
1882 at the given buffer size minus 1. It is supposed to do this even if it
1883 turns out that the buffer is sized too small.
1884
1885 Darwin (tested on 10.5) follows the C99 behavior exactly.
1886
1887 Glibc 2.6 almost follows the C99 behavior except vswprintf never sets
1888 errno even when it fails. However, it only seems to ever fail due
1889 to an undersized buffer.
1890 */
PrintfV(const wxChar * pszFormat,va_list argptr)1891 int wxString::PrintfV(const wxChar* pszFormat, va_list argptr)
1892 {
1893 int size = 1024;
1894
1895 for ( ;; )
1896 {
1897 // Allocate 1 more character than we tell wxVsnprintf about
1898 // just in case it is buggy.
1899 // FIXME: I have a feeling that the underlying function was not buggy
1900 // and I suspect it was to fix the buf[size] = '\0' line below
1901 wxStringBuffer tmp(*this, size + 1);
1902 wxChar *buf = tmp;
1903
1904 if ( !buf )
1905 {
1906 // out of memory
1907 return -1;
1908 }
1909
1910 // wxVsnprintf() may modify the original arg pointer, so pass it
1911 // only a copy
1912 va_list argptrcopy;
1913 wxVaCopy(argptrcopy, argptr);
1914
1915 #ifndef __WXWINCE__
1916 // Set errno to 0 to make it determinate if wxVsnprintf fails to set it.
1917 errno = 0;
1918 #endif
1919 int len = wxVsnprintf(buf, size, pszFormat, argptrcopy);
1920 va_end(argptrcopy);
1921
1922 // some implementations of vsnprintf() don't NUL terminate
1923 // the string if there is not enough space for it so
1924 // always do it manually
1925 // FIXME: This really seems to be the wrong and would be an off-by-one
1926 // bug except the code above allocates an extra character.
1927 buf[size] = _T('\0');
1928
1929 // vsnprintf() may return either -1 (traditional Unix behaviour) or the
1930 // total number of characters which would have been written if the
1931 // buffer were large enough (newer standards such as Unix98)
1932 if ( len < 0 )
1933 {
1934 #if wxUSE_WXVSNPRINTF
1935 // we know that our own implementation of wxVsnprintf() returns -1
1936 // only for a format error - thus there's something wrong with
1937 // the user's format string
1938 return -1;
1939 #else // assume that system version only returns error if not enough space
1940 #if !defined(__WXWINCE__) && (!defined(__OS2__) || defined(__INNOTEK_LIBC__))
1941 if( (errno == EILSEQ) || (errno == EINVAL) )
1942 // If errno was set to one of the two well-known hard errors
1943 // then fail immediately to avoid an infinite loop.
1944 return -1;
1945 else
1946 #endif // __WXWINCE__
1947 // still not enough, as we don't know how much we need, double the
1948 // current size of the buffer
1949 size *= 2;
1950 #endif // wxUSE_WXVSNPRINTF/!wxUSE_WXVSNPRINTF
1951 }
1952 else if ( len >= size )
1953 {
1954 #if wxUSE_WXVSNPRINTF
1955 // we know that our own implementation of wxVsnprintf() returns
1956 // size+1 when there's not enough space but that's not the size
1957 // of the required buffer!
1958 size *= 2; // so we just double the current size of the buffer
1959 #else
1960 // some vsnprintf() implementations NUL-terminate the buffer and
1961 // some don't in len == size case, to be safe always add 1
1962 // FIXME: I don't quite understand this comment. The vsnprintf
1963 // function is specifically defined to return the number of
1964 // characters printed not including the null terminator.
1965 // So OF COURSE you need to add 1 to get the right buffer size.
1966 // The following line is definitely correct, no question.
1967 size = len + 1;
1968 #endif
1969 }
1970 else // ok, there was enough space
1971 {
1972 break;
1973 }
1974 }
1975
1976 // we could have overshot
1977 Shrink();
1978
1979 return length();
1980 }
1981
1982 // ----------------------------------------------------------------------------
1983 // misc other operations
1984 // ----------------------------------------------------------------------------
1985
1986 // returns true if the string matches the pattern which may contain '*' and
1987 // '?' metacharacters (as usual, '?' matches any character and '*' any number
1988 // of them)
Matches(const wxChar * pszMask) const1989 bool wxString::Matches(const wxChar *pszMask) const
1990 {
1991 // I disable this code as it doesn't seem to be faster (in fact, it seems
1992 // to be much slower) than the old, hand-written code below and using it
1993 // here requires always linking with libregex even if the user code doesn't
1994 // use it
1995 #if 0 // wxUSE_REGEX
1996 // first translate the shell-like mask into a regex
1997 wxString pattern;
1998 pattern.reserve(wxStrlen(pszMask));
1999
2000 pattern += _T('^');
2001 while ( *pszMask )
2002 {
2003 switch ( *pszMask )
2004 {
2005 case _T('?'):
2006 pattern += _T('.');
2007 break;
2008
2009 case _T('*'):
2010 pattern += _T(".*");
2011 break;
2012
2013 case _T('^'):
2014 case _T('.'):
2015 case _T('$'):
2016 case _T('('):
2017 case _T(')'):
2018 case _T('|'):
2019 case _T('+'):
2020 case _T('\\'):
2021 // these characters are special in a RE, quote them
2022 // (however note that we don't quote '[' and ']' to allow
2023 // using them for Unix shell like matching)
2024 pattern += _T('\\');
2025 // fall through
2026
2027 default:
2028 pattern += *pszMask;
2029 }
2030
2031 pszMask++;
2032 }
2033 pattern += _T('$');
2034
2035 // and now use it
2036 return wxRegEx(pattern, wxRE_NOSUB | wxRE_EXTENDED).Matches(c_str());
2037 #else // !wxUSE_REGEX
2038 // TODO: this is, of course, awfully inefficient...
2039
2040 // the char currently being checked
2041 const wxChar *pszTxt = c_str();
2042
2043 // the last location where '*' matched
2044 const wxChar *pszLastStarInText = NULL;
2045 const wxChar *pszLastStarInMask = NULL;
2046
2047 match:
2048 for ( ; *pszMask != wxT('\0'); pszMask++, pszTxt++ ) {
2049 switch ( *pszMask ) {
2050 case wxT('?'):
2051 if ( *pszTxt == wxT('\0') )
2052 return false;
2053
2054 // pszTxt and pszMask will be incremented in the loop statement
2055
2056 break;
2057
2058 case wxT('*'):
2059 {
2060 // remember where we started to be able to backtrack later
2061 pszLastStarInText = pszTxt;
2062 pszLastStarInMask = pszMask;
2063
2064 // ignore special chars immediately following this one
2065 // (should this be an error?)
2066 while ( *pszMask == wxT('*') || *pszMask == wxT('?') )
2067 pszMask++;
2068
2069 // if there is nothing more, match
2070 if ( *pszMask == wxT('\0') )
2071 return true;
2072
2073 // are there any other metacharacters in the mask?
2074 size_t uiLenMask;
2075 const wxChar *pEndMask = wxStrpbrk(pszMask, wxT("*?"));
2076
2077 if ( pEndMask != NULL ) {
2078 // we have to match the string between two metachars
2079 uiLenMask = pEndMask - pszMask;
2080 }
2081 else {
2082 // we have to match the remainder of the string
2083 uiLenMask = wxStrlen(pszMask);
2084 }
2085
2086 wxString strToMatch(pszMask, uiLenMask);
2087 const wxChar* pMatch = wxStrstr(pszTxt, strToMatch);
2088 if ( pMatch == NULL )
2089 return false;
2090
2091 // -1 to compensate "++" in the loop
2092 pszTxt = pMatch + uiLenMask - 1;
2093 pszMask += uiLenMask - 1;
2094 }
2095 break;
2096
2097 default:
2098 if ( *pszMask != *pszTxt )
2099 return false;
2100 break;
2101 }
2102 }
2103
2104 // match only if nothing left
2105 if ( *pszTxt == wxT('\0') )
2106 return true;
2107
2108 // if we failed to match, backtrack if we can
2109 if ( pszLastStarInText ) {
2110 pszTxt = pszLastStarInText + 1;
2111 pszMask = pszLastStarInMask;
2112
2113 pszLastStarInText = NULL;
2114
2115 // don't bother resetting pszLastStarInMask, it's unnecessary
2116
2117 goto match;
2118 }
2119
2120 return false;
2121 #endif // wxUSE_REGEX/!wxUSE_REGEX
2122 }
2123
2124 // Count the number of chars
Freq(wxChar ch) const2125 int wxString::Freq(wxChar ch) const
2126 {
2127 int count = 0;
2128 int len = length();
2129 for (int i = 0; i < len; i++)
2130 {
2131 if (GetChar(i) == ch)
2132 count ++;
2133 }
2134 return count;
2135 }
2136
2137 // convert to upper case, return the copy of the string
Upper() const2138 wxString wxString::Upper() const
2139 { wxString s(*this); return s.MakeUpper(); }
2140
2141 // convert to lower case, return the copy of the string
Lower() const2142 wxString wxString::Lower() const { wxString s(*this); return s.MakeLower(); }
2143
sprintf(const wxChar * pszFormat,...)2144 int wxString::sprintf(const wxChar *pszFormat, ...)
2145 {
2146 va_list argptr;
2147 va_start(argptr, pszFormat);
2148 int iLen = PrintfV(pszFormat, argptr);
2149 va_end(argptr);
2150 return iLen;
2151 }
2152
2153 // ============================================================================
2154 // ArrayString
2155 // ============================================================================
2156
2157 #include "wx/arrstr.h"
2158
wxArrayString(size_t sz,const wxChar ** a)2159 wxArrayString::wxArrayString(size_t sz, const wxChar** a)
2160 {
2161 #if !wxUSE_STL
2162 Init(false);
2163 #endif
2164 for (size_t i=0; i < sz; i++)
2165 Add(a[i]);
2166 }
2167
wxArrayString(size_t sz,const wxString * a)2168 wxArrayString::wxArrayString(size_t sz, const wxString* a)
2169 {
2170 #if !wxUSE_STL
2171 Init(false);
2172 #endif
2173 for (size_t i=0; i < sz; i++)
2174 Add(a[i]);
2175 }
2176
2177 #if !wxUSE_STL
2178
2179 // size increment = min(50% of current size, ARRAY_MAXSIZE_INCREMENT)
2180 #define ARRAY_MAXSIZE_INCREMENT 4096
2181
2182 #ifndef ARRAY_DEFAULT_INITIAL_SIZE // also defined in dynarray.h
2183 #define ARRAY_DEFAULT_INITIAL_SIZE (16)
2184 #endif
2185
2186 #define STRING(p) ((wxString *)(&(p)))
2187
2188 // ctor
Init(bool autoSort)2189 void wxArrayString::Init(bool autoSort)
2190 {
2191 m_nSize =
2192 m_nCount = 0;
2193 m_pItems = (wxChar **) NULL;
2194 m_autoSort = autoSort;
2195 }
2196
2197 // copy ctor
wxArrayString(const wxArrayString & src)2198 wxArrayString::wxArrayString(const wxArrayString& src)
2199 {
2200 Init(src.m_autoSort);
2201
2202 *this = src;
2203 }
2204
2205 // assignment operator
operator =(const wxArrayString & src)2206 wxArrayString& wxArrayString::operator=(const wxArrayString& src)
2207 {
2208 if ( m_nSize > 0 )
2209 Clear();
2210
2211 Copy(src);
2212
2213 m_autoSort = src.m_autoSort;
2214
2215 return *this;
2216 }
2217
Copy(const wxArrayString & src)2218 void wxArrayString::Copy(const wxArrayString& src)
2219 {
2220 if ( src.m_nCount > ARRAY_DEFAULT_INITIAL_SIZE )
2221 Alloc(src.m_nCount);
2222
2223 for ( size_t n = 0; n < src.m_nCount; n++ )
2224 Add(src[n]);
2225 }
2226
2227 // grow the array
Grow(size_t nIncrement)2228 void wxArrayString::Grow(size_t nIncrement)
2229 {
2230 // only do it if no more place
2231 if ( (m_nSize - m_nCount) < nIncrement ) {
2232 // if ARRAY_DEFAULT_INITIAL_SIZE were set to 0, the initially empty would
2233 // be never resized!
2234 #if ARRAY_DEFAULT_INITIAL_SIZE == 0
2235 #error "ARRAY_DEFAULT_INITIAL_SIZE must be > 0!"
2236 #endif
2237
2238 if ( m_nSize == 0 ) {
2239 // was empty, alloc some memory
2240 m_nSize = ARRAY_DEFAULT_INITIAL_SIZE;
2241 if (m_nSize < nIncrement)
2242 m_nSize = nIncrement;
2243 m_pItems = new wxChar *[m_nSize];
2244 }
2245 else {
2246 // otherwise when it's called for the first time, nIncrement would be 0
2247 // and the array would never be expanded
2248 // add 50% but not too much
2249 size_t ndefIncrement = m_nSize < ARRAY_DEFAULT_INITIAL_SIZE
2250 ? ARRAY_DEFAULT_INITIAL_SIZE : m_nSize >> 1;
2251 if ( ndefIncrement > ARRAY_MAXSIZE_INCREMENT )
2252 ndefIncrement = ARRAY_MAXSIZE_INCREMENT;
2253 if ( nIncrement < ndefIncrement )
2254 nIncrement = ndefIncrement;
2255 m_nSize += nIncrement;
2256 wxChar **pNew = new wxChar *[m_nSize];
2257
2258 // copy data to new location
2259 memcpy(pNew, m_pItems, m_nCount*sizeof(wxChar *));
2260
2261 // delete old memory (but do not release the strings!)
2262 wxDELETEA(m_pItems);
2263
2264 m_pItems = pNew;
2265 }
2266 }
2267 }
2268
Free()2269 void wxArrayString::Free()
2270 {
2271 for ( size_t n = 0; n < m_nCount; n++ ) {
2272 STRING(m_pItems[n])->GetStringData()->Unlock();
2273 }
2274 }
2275
2276 // deletes all the strings from the list
Empty()2277 void wxArrayString::Empty()
2278 {
2279 Free();
2280
2281 m_nCount = 0;
2282 }
2283
2284 // as Empty, but also frees memory
Clear()2285 void wxArrayString::Clear()
2286 {
2287 Free();
2288
2289 m_nSize =
2290 m_nCount = 0;
2291
2292 wxDELETEA(m_pItems);
2293 }
2294
2295 // dtor
~wxArrayString()2296 wxArrayString::~wxArrayString()
2297 {
2298 Free();
2299
2300 wxDELETEA(m_pItems);
2301 }
2302
reserve(size_t nSize)2303 void wxArrayString::reserve(size_t nSize)
2304 {
2305 Alloc(nSize);
2306 }
2307
2308 // pre-allocates memory (frees the previous data!)
Alloc(size_t nSize)2309 void wxArrayString::Alloc(size_t nSize)
2310 {
2311 // only if old buffer was not big enough
2312 if ( nSize > m_nSize ) {
2313 wxChar **pNew = new wxChar *[nSize];
2314 if ( !pNew )
2315 return;
2316
2317 memcpy(pNew, m_pItems, m_nCount*sizeof(wxChar *));
2318 delete [] m_pItems;
2319
2320 m_pItems = pNew;
2321 m_nSize = nSize;
2322 }
2323 }
2324
2325 // minimizes the memory usage by freeing unused memory
Shrink()2326 void wxArrayString::Shrink()
2327 {
2328 // only do it if we have some memory to free
2329 if( m_nCount < m_nSize ) {
2330 // allocates exactly as much memory as we need
2331 wxChar **pNew = new wxChar *[m_nCount];
2332
2333 // copy data to new location
2334 memcpy(pNew, m_pItems, m_nCount*sizeof(wxChar *));
2335 delete [] m_pItems;
2336 m_pItems = pNew;
2337 m_nSize = m_nCount;
2338 }
2339 }
2340
2341 #if WXWIN_COMPATIBILITY_2_4
2342
2343 // return a wxString[] as required for some control ctors.
GetStringArray() const2344 wxString* wxArrayString::GetStringArray() const
2345 {
2346 wxString *array = 0;
2347
2348 if( m_nCount > 0 )
2349 {
2350 array = new wxString[m_nCount];
2351 for( size_t i = 0; i < m_nCount; i++ )
2352 array[i] = m_pItems[i];
2353 }
2354
2355 return array;
2356 }
2357
Remove(size_t nIndex,size_t nRemove)2358 void wxArrayString::Remove(size_t nIndex, size_t nRemove)
2359 {
2360 RemoveAt(nIndex, nRemove);
2361 }
2362
2363 #endif // WXWIN_COMPATIBILITY_2_4
2364
2365 // searches the array for an item (forward or backwards)
Index(const wxChar * sz,bool bCase,bool bFromEnd) const2366 int wxArrayString::Index(const wxChar *sz, bool bCase, bool bFromEnd) const
2367 {
2368 if ( m_autoSort ) {
2369 // use binary search in the sorted array
2370 wxASSERT_MSG( bCase && !bFromEnd,
2371 wxT("search parameters ignored for auto sorted array") );
2372
2373 size_t i,
2374 lo = 0,
2375 hi = m_nCount;
2376 int res;
2377 while ( lo < hi ) {
2378 i = (lo + hi)/2;
2379
2380 res = wxStrcmp(sz, m_pItems[i]);
2381 if ( res < 0 )
2382 hi = i;
2383 else if ( res > 0 )
2384 lo = i + 1;
2385 else
2386 return i;
2387 }
2388
2389 return wxNOT_FOUND;
2390 }
2391 else {
2392 // use linear search in unsorted array
2393 if ( bFromEnd ) {
2394 if ( m_nCount > 0 ) {
2395 size_t ui = m_nCount;
2396 do {
2397 if ( STRING(m_pItems[--ui])->IsSameAs(sz, bCase) )
2398 return ui;
2399 }
2400 while ( ui != 0 );
2401 }
2402 }
2403 else {
2404 for( size_t ui = 0; ui < m_nCount; ui++ ) {
2405 if( STRING(m_pItems[ui])->IsSameAs(sz, bCase) )
2406 return ui;
2407 }
2408 }
2409 }
2410
2411 return wxNOT_FOUND;
2412 }
2413
2414 // add item at the end
Add(const wxString & str,size_t nInsert)2415 size_t wxArrayString::Add(const wxString& str, size_t nInsert)
2416 {
2417 if ( m_autoSort ) {
2418 // insert the string at the correct position to keep the array sorted
2419 size_t i,
2420 lo = 0,
2421 hi = m_nCount;
2422 int res;
2423 while ( lo < hi ) {
2424 i = (lo + hi)/2;
2425
2426 res = str.Cmp(m_pItems[i]);
2427 if ( res < 0 )
2428 hi = i;
2429 else if ( res > 0 )
2430 lo = i + 1;
2431 else {
2432 lo = hi = i;
2433 break;
2434 }
2435 }
2436
2437 wxASSERT_MSG( lo == hi, wxT("binary search broken") );
2438
2439 Insert(str, lo, nInsert);
2440
2441 return (size_t)lo;
2442 }
2443 else {
2444 wxASSERT( str.GetStringData()->IsValid() );
2445
2446 Grow(nInsert);
2447
2448 for (size_t i = 0; i < nInsert; i++)
2449 {
2450 // the string data must not be deleted!
2451 str.GetStringData()->Lock();
2452
2453 // just append
2454 m_pItems[m_nCount + i] = (wxChar *)str.c_str(); // const_cast
2455 }
2456 size_t ret = m_nCount;
2457 m_nCount += nInsert;
2458 return ret;
2459 }
2460 }
2461
2462 // add item at the given position
Insert(const wxString & str,size_t nIndex,size_t nInsert)2463 void wxArrayString::Insert(const wxString& str, size_t nIndex, size_t nInsert)
2464 {
2465 wxASSERT( str.GetStringData()->IsValid() );
2466
2467 wxCHECK_RET( nIndex <= m_nCount, wxT("bad index in wxArrayString::Insert") );
2468 wxCHECK_RET( m_nCount <= m_nCount + nInsert,
2469 wxT("array size overflow in wxArrayString::Insert") );
2470
2471 Grow(nInsert);
2472
2473 memmove(&m_pItems[nIndex + nInsert], &m_pItems[nIndex],
2474 (m_nCount - nIndex)*sizeof(wxChar *));
2475
2476 for (size_t i = 0; i < nInsert; i++)
2477 {
2478 str.GetStringData()->Lock();
2479 m_pItems[nIndex + i] = (wxChar *)str.c_str();
2480 }
2481 m_nCount += nInsert;
2482 }
2483
2484 // range insert (STL 23.2.4.3)
2485 void
insert(iterator it,const_iterator first,const_iterator last)2486 wxArrayString::insert(iterator it, const_iterator first, const_iterator last)
2487 {
2488 const int idx = it - begin();
2489
2490 // grow it once
2491 Grow(last - first);
2492
2493 // reset "it" since it can change inside Grow()
2494 it = begin() + idx;
2495
2496 while ( first != last )
2497 {
2498 it = insert(it, *first);
2499
2500 // insert returns an iterator to the last element inserted but we need
2501 // insert the next after this one, that is before the next one
2502 ++it;
2503
2504 ++first;
2505 }
2506 }
2507
2508 // expand the array
SetCount(size_t count)2509 void wxArrayString::SetCount(size_t count)
2510 {
2511 Alloc(count);
2512
2513 wxString s;
2514 while ( m_nCount < count )
2515 m_pItems[m_nCount++] = (wxChar *)s.c_str();
2516 }
2517
2518 // removes item from array (by index)
RemoveAt(size_t nIndex,size_t nRemove)2519 void wxArrayString::RemoveAt(size_t nIndex, size_t nRemove)
2520 {
2521 wxCHECK_RET( nIndex < m_nCount, wxT("bad index in wxArrayString::Remove") );
2522 wxCHECK_RET( nIndex + nRemove <= m_nCount,
2523 wxT("removing too many elements in wxArrayString::Remove") );
2524
2525 // release our lock
2526 for (size_t i = 0; i < nRemove; i++)
2527 Item(nIndex + i).GetStringData()->Unlock();
2528
2529 memmove(&m_pItems[nIndex], &m_pItems[nIndex + nRemove],
2530 (m_nCount - nIndex - nRemove)*sizeof(wxChar *));
2531 m_nCount -= nRemove;
2532 }
2533
2534 // removes item from array (by value)
Remove(const wxChar * sz)2535 void wxArrayString::Remove(const wxChar *sz)
2536 {
2537 int iIndex = Index(sz);
2538
2539 wxCHECK_RET( iIndex != wxNOT_FOUND,
2540 wxT("removing inexistent element in wxArrayString::Remove") );
2541
2542 RemoveAt(iIndex);
2543 }
2544
assign(const_iterator first,const_iterator last)2545 void wxArrayString::assign(const_iterator first, const_iterator last)
2546 {
2547 reserve(last - first);
2548 for(; first != last; ++first)
2549 push_back(*first);
2550 }
2551
2552 // ----------------------------------------------------------------------------
2553 // sorting
2554 // ----------------------------------------------------------------------------
2555
2556 // we can only sort one array at a time with the quick-sort based
2557 // implementation
2558 #if wxUSE_THREADS
2559 // need a critical section to protect access to gs_compareFunction and
2560 // gs_sortAscending variables
2561 static wxCriticalSection gs_critsectStringSort;
2562 #endif // wxUSE_THREADS
2563
2564 // function to use for string comparaison
2565 static wxArrayString::CompareFunction gs_compareFunction = NULL;
2566
2567 // if we don't use the compare function, this flag tells us if we sort the
2568 // array in ascending or descending order
2569 static bool gs_sortAscending = true;
2570
2571 // function which is called by quick sort
2572 extern "C" int wxC_CALLING_CONV // LINKAGEMODE
wxStringCompareFunction(const void * first,const void * second)2573 wxStringCompareFunction(const void *first, const void *second)
2574 {
2575 wxString *strFirst = (wxString *)first;
2576 wxString *strSecond = (wxString *)second;
2577
2578 if ( gs_compareFunction ) {
2579 return gs_compareFunction(*strFirst, *strSecond);
2580 }
2581 else {
2582 // maybe we should use wxStrcoll
2583 int result = strFirst->Cmp(*strSecond);
2584
2585 return gs_sortAscending ? result : -result;
2586 }
2587 }
2588
2589 // sort array elements using passed comparaison function
Sort(CompareFunction compareFunction)2590 void wxArrayString::Sort(CompareFunction compareFunction)
2591 {
2592 wxCRIT_SECT_LOCKER(lockCmpFunc, gs_critsectStringSort);
2593
2594 wxASSERT( !gs_compareFunction ); // must have been reset to NULL
2595 gs_compareFunction = compareFunction;
2596
2597 DoSort();
2598
2599 // reset it to NULL so that Sort(bool) will work the next time
2600 gs_compareFunction = NULL;
2601 }
2602
2603 extern "C"
2604 {
2605 typedef int (wxC_CALLING_CONV * wxStringCompareFn)(const void *first,
2606 const void *second);
2607 }
2608
Sort(CompareFunction2 compareFunction)2609 void wxArrayString::Sort(CompareFunction2 compareFunction)
2610 {
2611 qsort(m_pItems, m_nCount, sizeof(wxChar *), (wxStringCompareFn)compareFunction);
2612 }
2613
Sort(bool reverseOrder)2614 void wxArrayString::Sort(bool reverseOrder)
2615 {
2616 Sort(reverseOrder ? wxStringSortDescending : wxStringSortAscending);
2617 }
2618
DoSort()2619 void wxArrayString::DoSort()
2620 {
2621 wxCHECK_RET( !m_autoSort, wxT("can't use this method with sorted arrays") );
2622
2623 // just sort the pointers using qsort() - of course it only works because
2624 // wxString() *is* a pointer to its data
2625 qsort(m_pItems, m_nCount, sizeof(wxChar *), wxStringCompareFunction);
2626 }
2627
operator ==(const wxArrayString & a) const2628 bool wxArrayString::operator==(const wxArrayString& a) const
2629 {
2630 if ( m_nCount != a.m_nCount )
2631 return false;
2632
2633 for ( size_t n = 0; n < m_nCount; n++ )
2634 {
2635 if ( Item(n) != a[n] )
2636 return false;
2637 }
2638
2639 return true;
2640 }
2641
2642 #endif // !wxUSE_STL
2643
wxStringSortAscending(wxString * s1,wxString * s2)2644 int wxCMPFUNC_CONV wxStringSortAscending(wxString* s1, wxString* s2)
2645 {
2646 return s1->Cmp(*s2);
2647 }
2648
wxStringSortDescending(wxString * s1,wxString * s2)2649 int wxCMPFUNC_CONV wxStringSortDescending(wxString* s1, wxString* s2)
2650 {
2651 return -s1->Cmp(*s2);
2652 }
2653
Release()2654 wxString* wxCArrayString::Release()
2655 {
2656 wxString *r = GetStrings();
2657 m_strings = NULL;
2658 return r;
2659 }
2660