/[pcsx2_0.9.7]/trunk/3rdparty/wxWidgets/src/common/string.cpp
ViewVC logotype

Annotation of /trunk/3rdparty/wxWidgets/src/common/string.cpp

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.22