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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 31 - (show annotations) (download)
Tue Sep 7 03:24:11 2010 UTC (10 years, 2 months ago) by william
File size: 70020 byte(s)
committing r3113 initial commit again...
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 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