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