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