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