]> git.saurik.com Git - wxWidgets.git/blob - src/common/string.cpp
EVT_TEXT_UPDATED bug fixed, text ctrl callbacks simplified
[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 #endif
39
40 #include <ctype.h>
41 #include <string.h>
42 #include <stdlib.h>
43
44 #ifdef __SALFORDC__
45 #include <clib.h>
46 #endif
47
48 #if wxUSE_WCSRTOMBS
49 #include <wchar.h> // for wcsrtombs(), see comments where it's used
50 #endif // GNU
51
52 #ifdef WXSTRING_IS_WXOBJECT
53 IMPLEMENT_DYNAMIC_CLASS(wxString, wxObject)
54 #endif //WXSTRING_IS_WXOBJECT
55
56 // allocating extra space for each string consumes more memory but speeds up
57 // the concatenation operations (nLen is the current string's length)
58 // NB: EXTRA_ALLOC must be >= 0!
59 #define EXTRA_ALLOC (19 - nLen % 16)
60
61 // ---------------------------------------------------------------------------
62 // static class variables definition
63 // ---------------------------------------------------------------------------
64
65 #ifdef wxSTD_STRING_COMPATIBILITY
66 const size_t wxString::npos = wxSTRING_MAXLEN;
67 #endif // wxSTD_STRING_COMPATIBILITY
68
69 // ----------------------------------------------------------------------------
70 // static data
71 // ----------------------------------------------------------------------------
72
73 // for an empty string, GetStringData() will return this address: this
74 // structure has the same layout as wxStringData and it's data() method will
75 // return the empty string (dummy pointer)
76 static const struct
77 {
78 wxStringData data;
79 char dummy;
80 } g_strEmpty = { {-1, 0, 0}, '\0' };
81
82 // empty C style string: points to 'string data' byte of g_strEmpty
83 extern const char WXDLLEXPORT *g_szNul = &g_strEmpty.dummy;
84
85 // ----------------------------------------------------------------------------
86 // conditional compilation
87 // ----------------------------------------------------------------------------
88
89 // we want to find out if the current platform supports vsnprintf()-like
90 // function: for Unix this is done with configure, for Windows we test the
91 // compiler explicitly.
92 #ifdef __WXMSW__
93 #ifdef __VISUALC__
94 #define wxVsprintf _vsnprintf
95 #endif
96 #else // !Windows
97 #ifdef HAVE_VSNPRINTF
98 #define wxVsprintf vsnprintf
99 #endif
100 #endif // Windows/!Windows
101
102 #ifndef wxVsprintf
103 // in this case we'll use vsprintf() (which is ANSI and thus should be
104 // always available), but it's unsafe because it doesn't check for buffer
105 // size - so give a warning
106 #define wxVsprintf(buffer,len,format,argptr) vsprintf(buffer,format, argptr)
107
108 #if defined(__VISUALC__)
109 #pragma message("Using sprintf() because no snprintf()-like function defined")
110 #elif defined(__GNUG__) && !defined(__UNIX__)
111 #warning "Using sprintf() because no snprintf()-like function defined"
112 #elif defined(__MWERKS__)
113 #warning "Using sprintf() because no snprintf()-like function defined"
114 #endif //compiler
115 #endif // no vsnprintf
116
117 #ifdef _AIX
118 // AIX has vsnprintf, but there's no prototype in the system headers.
119 extern "C" int vsnprintf(char* str, size_t n, const char* format, va_list ap);
120 #endif
121
122 // ----------------------------------------------------------------------------
123 // global functions
124 // ----------------------------------------------------------------------------
125
126 #ifdef wxSTD_STRING_COMPATIBILITY
127
128 // MS Visual C++ version 5.0 provides the new STL headers as well as the old
129 // iostream ones.
130 //
131 // ATTN: you can _not_ use both of these in the same program!
132
133 istream& operator>>(istream& is, wxString& WXUNUSED(str))
134 {
135 #if 0
136 int w = is.width(0);
137 if ( is.ipfx(0) ) {
138 streambuf *sb = is.rdbuf();
139 str.erase();
140 while ( true ) {
141 int ch = sb->sbumpc ();
142 if ( ch == EOF ) {
143 is.setstate(ios::eofbit);
144 break;
145 }
146 else if ( isspace(ch) ) {
147 sb->sungetc();
148 break;
149 }
150
151 str += ch;
152 if ( --w == 1 )
153 break;
154 }
155 }
156
157 is.isfx();
158 if ( str.length() == 0 )
159 is.setstate(ios::failbit);
160 #endif
161 return is;
162 }
163
164 #endif //std::string compatibility
165
166 // ----------------------------------------------------------------------------
167 // private classes
168 // ----------------------------------------------------------------------------
169
170 // this small class is used to gather statistics for performance tuning
171 //#define WXSTRING_STATISTICS
172 #ifdef WXSTRING_STATISTICS
173 class Averager
174 {
175 public:
176 Averager(const char *sz) { m_sz = sz; m_nTotal = m_nCount = 0; }
177 ~Averager()
178 { printf("wxString: average %s = %f\n", m_sz, ((float)m_nTotal)/m_nCount); }
179
180 void Add(size_t n) { m_nTotal += n; m_nCount++; }
181
182 private:
183 size_t m_nCount, m_nTotal;
184 const char *m_sz;
185 } g_averageLength("allocation size"),
186 g_averageSummandLength("summand length"),
187 g_averageConcatHit("hit probability in concat"),
188 g_averageInitialLength("initial string length");
189
190 #define STATISTICS_ADD(av, val) g_average##av.Add(val)
191 #else
192 #define STATISTICS_ADD(av, val)
193 #endif // WXSTRING_STATISTICS
194
195 // ===========================================================================
196 // wxString class core
197 // ===========================================================================
198
199 // ---------------------------------------------------------------------------
200 // construction
201 // ---------------------------------------------------------------------------
202
203 // constructs string of <nLength> copies of character <ch>
204 wxString::wxString(char ch, size_t nLength)
205 {
206 Init();
207
208 if ( nLength > 0 ) {
209 AllocBuffer(nLength);
210
211 wxASSERT( sizeof(char) == 1 ); // can't use memset if not
212
213 memset(m_pchData, ch, nLength);
214 }
215 }
216
217 // takes nLength elements of psz starting at nPos
218 void wxString::InitWith(const char *psz, size_t nPos, size_t nLength)
219 {
220 Init();
221
222 wxASSERT( nPos <= Strlen(psz) );
223
224 if ( nLength == wxSTRING_MAXLEN )
225 nLength = Strlen(psz + nPos);
226
227 STATISTICS_ADD(InitialLength, nLength);
228
229 if ( nLength > 0 ) {
230 // trailing '\0' is written in AllocBuffer()
231 AllocBuffer(nLength);
232 memcpy(m_pchData, psz + nPos, nLength*sizeof(char));
233 }
234 }
235
236 // the same as previous constructor, but for compilers using unsigned char
237 wxString::wxString(const unsigned char* psz, size_t nLength)
238 {
239 InitWith((const char *)psz, 0, nLength);
240 }
241
242 #ifdef wxSTD_STRING_COMPATIBILITY
243
244 // poor man's iterators are "void *" pointers
245 wxString::wxString(const void *pStart, const void *pEnd)
246 {
247 InitWith((const char *)pStart, 0,
248 (const char *)pEnd - (const char *)pStart);
249 }
250
251 #endif //std::string compatibility
252
253 // from wide string
254 wxString::wxString(const wchar_t *pwz)
255 {
256 // first get necessary size
257
258 // NB: GNU libc5 wcstombs() is completely broken, don't use it (it doesn't
259 // honor the 3rd parameter, thus it will happily crash here).
260 #if wxUSE_WCSRTOMBS
261 // don't know if it's really needed (or if we can pass NULL), but better safe
262 // than quick
263 mbstate_t mbstate;
264 size_t nLen = wcsrtombs((char *) NULL, &pwz, 0, &mbstate);
265 #else // !GNU libc
266 size_t nLen = wcstombs((char *) NULL, pwz, 0);
267 #endif // GNU
268
269 // empty?
270 if ( nLen != 0 ) {
271 AllocBuffer(nLen);
272 wcstombs(m_pchData, pwz, nLen);
273 }
274 else {
275 Init();
276 }
277 }
278
279 // ---------------------------------------------------------------------------
280 // memory allocation
281 // ---------------------------------------------------------------------------
282
283 // allocates memory needed to store a C string of length nLen
284 void wxString::AllocBuffer(size_t nLen)
285 {
286 wxASSERT( nLen > 0 ); //
287 wxASSERT( nLen <= INT_MAX-1 ); // max size (enough room for 1 extra)
288
289 STATISTICS_ADD(Length, nLen);
290
291 // allocate memory:
292 // 1) one extra character for '\0' termination
293 // 2) sizeof(wxStringData) for housekeeping info
294 wxStringData* pData = (wxStringData*)
295 malloc(sizeof(wxStringData) + (nLen + EXTRA_ALLOC + 1)*sizeof(char));
296 pData->nRefs = 1;
297 pData->nDataLength = nLen;
298 pData->nAllocLength = nLen + EXTRA_ALLOC;
299 m_pchData = pData->data(); // data starts after wxStringData
300 m_pchData[nLen] = '\0';
301 }
302
303 // must be called before changing this string
304 void wxString::CopyBeforeWrite()
305 {
306 wxStringData* pData = GetStringData();
307
308 if ( pData->IsShared() ) {
309 pData->Unlock(); // memory not freed because shared
310 size_t nLen = pData->nDataLength;
311 AllocBuffer(nLen);
312 memcpy(m_pchData, pData->data(), nLen*sizeof(char));
313 }
314
315 wxASSERT( !GetStringData()->IsShared() ); // we must be the only owner
316 }
317
318 // must be called before replacing contents of this string
319 void wxString::AllocBeforeWrite(size_t nLen)
320 {
321 wxASSERT( nLen != 0 ); // doesn't make any sense
322
323 // must not share string and must have enough space
324 wxStringData* pData = GetStringData();
325 if ( pData->IsShared() || (nLen > pData->nAllocLength) ) {
326 // can't work with old buffer, get new one
327 pData->Unlock();
328 AllocBuffer(nLen);
329 }
330 else {
331 // update the string length
332 pData->nDataLength = nLen;
333 }
334
335 wxASSERT( !GetStringData()->IsShared() ); // we must be the only owner
336 }
337
338 // allocate enough memory for nLen characters
339 void wxString::Alloc(size_t nLen)
340 {
341 wxStringData *pData = GetStringData();
342 if ( pData->nAllocLength <= nLen ) {
343 if ( pData->IsEmpty() ) {
344 nLen += EXTRA_ALLOC;
345
346 wxStringData* pData = (wxStringData*)
347 malloc(sizeof(wxStringData) + (nLen + 1)*sizeof(char));
348 pData->nRefs = 1;
349 pData->nDataLength = 0;
350 pData->nAllocLength = nLen;
351 m_pchData = pData->data(); // data starts after wxStringData
352 m_pchData[0u] = '\0';
353 }
354 else if ( pData->IsShared() ) {
355 pData->Unlock(); // memory not freed because shared
356 size_t nOldLen = pData->nDataLength;
357 AllocBuffer(nLen);
358 memcpy(m_pchData, pData->data(), nOldLen*sizeof(char));
359 }
360 else {
361 nLen += EXTRA_ALLOC;
362
363 wxStringData *p = (wxStringData *)
364 realloc(pData, sizeof(wxStringData) + (nLen + 1)*sizeof(char));
365
366 if ( p == NULL ) {
367 // @@@ what to do on memory error?
368 return;
369 }
370
371 // it's not important if the pointer changed or not (the check for this
372 // is not faster than assigning to m_pchData in all cases)
373 p->nAllocLength = nLen;
374 m_pchData = p->data();
375 }
376 }
377 //else: we've already got enough
378 }
379
380 // shrink to minimal size (releasing extra memory)
381 void wxString::Shrink()
382 {
383 wxStringData *pData = GetStringData();
384
385 // this variable is unused in release build, so avoid the compiler warning by
386 // just not declaring it
387 #ifdef __WXDEBUG__
388 void *p =
389 #endif
390 realloc(pData, sizeof(wxStringData) + (pData->nDataLength + 1)*sizeof(char));
391
392 wxASSERT( p != NULL ); // can't free memory?
393 wxASSERT( p == pData ); // we're decrementing the size - block shouldn't move!
394 }
395
396 // get the pointer to writable buffer of (at least) nLen bytes
397 char *wxString::GetWriteBuf(size_t nLen)
398 {
399 AllocBeforeWrite(nLen);
400
401 wxASSERT( GetStringData()->nRefs == 1 );
402 GetStringData()->Validate(FALSE);
403
404 return m_pchData;
405 }
406
407 // put string back in a reasonable state after GetWriteBuf
408 void wxString::UngetWriteBuf()
409 {
410 GetStringData()->nDataLength = strlen(m_pchData);
411 GetStringData()->Validate(TRUE);
412 }
413
414 // ---------------------------------------------------------------------------
415 // data access
416 // ---------------------------------------------------------------------------
417
418 // all functions are inline in string.h
419
420 // ---------------------------------------------------------------------------
421 // assignment operators
422 // ---------------------------------------------------------------------------
423
424 // helper function: does real copy
425 void wxString::AssignCopy(size_t nSrcLen, const char *pszSrcData)
426 {
427 if ( nSrcLen == 0 ) {
428 Reinit();
429 }
430 else {
431 AllocBeforeWrite(nSrcLen);
432 memcpy(m_pchData, pszSrcData, nSrcLen*sizeof(char));
433 GetStringData()->nDataLength = nSrcLen;
434 m_pchData[nSrcLen] = '\0';
435 }
436 }
437
438 // assigns one string to another
439 wxString& wxString::operator=(const wxString& stringSrc)
440 {
441 wxASSERT( stringSrc.GetStringData()->IsValid() );
442
443 // don't copy string over itself
444 if ( m_pchData != stringSrc.m_pchData ) {
445 if ( stringSrc.GetStringData()->IsEmpty() ) {
446 Reinit();
447 }
448 else {
449 // adjust references
450 GetStringData()->Unlock();
451 m_pchData = stringSrc.m_pchData;
452 GetStringData()->Lock();
453 }
454 }
455
456 return *this;
457 }
458
459 // assigns a single character
460 wxString& wxString::operator=(char ch)
461 {
462 AssignCopy(1, &ch);
463 return *this;
464 }
465
466 // assigns C string
467 wxString& wxString::operator=(const char *psz)
468 {
469 AssignCopy(Strlen(psz), psz);
470 return *this;
471 }
472
473 // same as 'signed char' variant
474 wxString& wxString::operator=(const unsigned char* psz)
475 {
476 *this = (const char *)psz;
477 return *this;
478 }
479
480 wxString& wxString::operator=(const wchar_t *pwz)
481 {
482 wxString str(pwz);
483 *this = str;
484 return *this;
485 }
486
487 // ---------------------------------------------------------------------------
488 // string concatenation
489 // ---------------------------------------------------------------------------
490
491 // add something to this string
492 void wxString::ConcatSelf(int nSrcLen, const char *pszSrcData)
493 {
494 STATISTICS_ADD(SummandLength, nSrcLen);
495
496 // concatenating an empty string is a NOP
497 if ( nSrcLen > 0 ) {
498 wxStringData *pData = GetStringData();
499 size_t nLen = pData->nDataLength;
500 size_t nNewLen = nLen + nSrcLen;
501
502 // alloc new buffer if current is too small
503 if ( pData->IsShared() ) {
504 STATISTICS_ADD(ConcatHit, 0);
505
506 // we have to allocate another buffer
507 wxStringData* pOldData = GetStringData();
508 AllocBuffer(nNewLen);
509 memcpy(m_pchData, pOldData->data(), nLen*sizeof(char));
510 pOldData->Unlock();
511 }
512 else if ( nNewLen > pData->nAllocLength ) {
513 STATISTICS_ADD(ConcatHit, 0);
514
515 // we have to grow the buffer
516 Alloc(nNewLen);
517 }
518 else {
519 STATISTICS_ADD(ConcatHit, 1);
520
521 // the buffer is already big enough
522 }
523
524 // should be enough space
525 wxASSERT( nNewLen <= GetStringData()->nAllocLength );
526
527 // fast concatenation - all is done in our buffer
528 memcpy(m_pchData + nLen, pszSrcData, nSrcLen*sizeof(char));
529
530 m_pchData[nNewLen] = '\0'; // put terminating '\0'
531 GetStringData()->nDataLength = nNewLen; // and fix the length
532 }
533 //else: the string to append was empty
534 }
535
536 /*
537 * concatenation functions come in 5 flavours:
538 * string + string
539 * char + string and string + char
540 * C str + string and string + C str
541 */
542
543 wxString operator+(const wxString& string1, const wxString& string2)
544 {
545 wxASSERT( string1.GetStringData()->IsValid() );
546 wxASSERT( string2.GetStringData()->IsValid() );
547
548 wxString s = string1;
549 s += string2;
550
551 return s;
552 }
553
554 wxString operator+(const wxString& string, char ch)
555 {
556 wxASSERT( string.GetStringData()->IsValid() );
557
558 wxString s = string;
559 s += ch;
560
561 return s;
562 }
563
564 wxString operator+(char ch, const wxString& string)
565 {
566 wxASSERT( string.GetStringData()->IsValid() );
567
568 wxString s = ch;
569 s += string;
570
571 return s;
572 }
573
574 wxString operator+(const wxString& string, const char *psz)
575 {
576 wxASSERT( string.GetStringData()->IsValid() );
577
578 wxString s;
579 s.Alloc(Strlen(psz) + string.Len());
580 s = string;
581 s += psz;
582
583 return s;
584 }
585
586 wxString operator+(const char *psz, const wxString& string)
587 {
588 wxASSERT( string.GetStringData()->IsValid() );
589
590 wxString s;
591 s.Alloc(Strlen(psz) + string.Len());
592 s = psz;
593 s += string;
594
595 return s;
596 }
597
598 // ===========================================================================
599 // other common string functions
600 // ===========================================================================
601
602 // ---------------------------------------------------------------------------
603 // simple sub-string extraction
604 // ---------------------------------------------------------------------------
605
606 // helper function: clone the data attached to this string
607 void wxString::AllocCopy(wxString& dest, int nCopyLen, int nCopyIndex) const
608 {
609 if ( nCopyLen == 0 ) {
610 dest.Init();
611 }
612 else {
613 dest.AllocBuffer(nCopyLen);
614 memcpy(dest.m_pchData, m_pchData + nCopyIndex, nCopyLen*sizeof(char));
615 }
616 }
617
618 // extract string of length nCount starting at nFirst
619 wxString wxString::Mid(size_t nFirst, size_t nCount) const
620 {
621 wxStringData *pData = GetStringData();
622 size_t nLen = pData->nDataLength;
623
624 // default value of nCount is wxSTRING_MAXLEN and means "till the end"
625 if ( nCount == wxSTRING_MAXLEN )
626 {
627 nCount = nLen - nFirst;
628 }
629
630 // out-of-bounds requests return sensible things
631 if ( nFirst + nCount > nLen )
632 {
633 nCount = nLen - nFirst;
634 }
635
636 if ( nFirst > nLen )
637 {
638 // AllocCopy() will return empty string
639 nCount = 0;
640 }
641
642 wxString dest;
643 AllocCopy(dest, nCount, nFirst);
644
645 return dest;
646 }
647
648 // extract nCount last (rightmost) characters
649 wxString wxString::Right(size_t nCount) const
650 {
651 if ( nCount > (size_t)GetStringData()->nDataLength )
652 nCount = GetStringData()->nDataLength;
653
654 wxString dest;
655 AllocCopy(dest, nCount, GetStringData()->nDataLength - nCount);
656 return dest;
657 }
658
659 // get all characters after the last occurence of ch
660 // (returns the whole string if ch not found)
661 wxString wxString::AfterLast(char ch) const
662 {
663 wxString str;
664 int iPos = Find(ch, TRUE);
665 if ( iPos == wxNOT_FOUND )
666 str = *this;
667 else
668 str = c_str() + iPos + 1;
669
670 return str;
671 }
672
673 // extract nCount first (leftmost) characters
674 wxString wxString::Left(size_t nCount) const
675 {
676 if ( nCount > (size_t)GetStringData()->nDataLength )
677 nCount = GetStringData()->nDataLength;
678
679 wxString dest;
680 AllocCopy(dest, nCount, 0);
681 return dest;
682 }
683
684 // get all characters before the first occurence of ch
685 // (returns the whole string if ch not found)
686 wxString wxString::BeforeFirst(char ch) const
687 {
688 wxString str;
689 for ( const char *pc = m_pchData; *pc != '\0' && *pc != ch; pc++ )
690 str += *pc;
691
692 return str;
693 }
694
695 /// get all characters before the last occurence of ch
696 /// (returns empty string if ch not found)
697 wxString wxString::BeforeLast(char ch) const
698 {
699 wxString str;
700 int iPos = Find(ch, TRUE);
701 if ( iPos != wxNOT_FOUND && iPos != 0 )
702 str = wxString(c_str(), iPos);
703
704 return str;
705 }
706
707 /// get all characters after the first occurence of ch
708 /// (returns empty string if ch not found)
709 wxString wxString::AfterFirst(char ch) const
710 {
711 wxString str;
712 int iPos = Find(ch);
713 if ( iPos != wxNOT_FOUND )
714 str = c_str() + iPos + 1;
715
716 return str;
717 }
718
719 // replace first (or all) occurences of some substring with another one
720 size_t wxString::Replace(const char *szOld, const char *szNew, bool bReplaceAll)
721 {
722 size_t uiCount = 0; // count of replacements made
723
724 size_t uiOldLen = Strlen(szOld);
725
726 wxString strTemp;
727 const char *pCurrent = m_pchData;
728 const char *pSubstr;
729 while ( *pCurrent != '\0' ) {
730 pSubstr = strstr(pCurrent, szOld);
731 if ( pSubstr == NULL ) {
732 // strTemp is unused if no replacements were made, so avoid the copy
733 if ( uiCount == 0 )
734 return 0;
735
736 strTemp += pCurrent; // copy the rest
737 break; // exit the loop
738 }
739 else {
740 // take chars before match
741 strTemp.ConcatSelf(pSubstr - pCurrent, pCurrent);
742 strTemp += szNew;
743 pCurrent = pSubstr + uiOldLen; // restart after match
744
745 uiCount++;
746
747 // stop now?
748 if ( !bReplaceAll ) {
749 strTemp += pCurrent; // copy the rest
750 break; // exit the loop
751 }
752 }
753 }
754
755 // only done if there were replacements, otherwise would have returned above
756 *this = strTemp;
757
758 return uiCount;
759 }
760
761 bool wxString::IsAscii() const
762 {
763 const char *s = (const char*) *this;
764 while(*s){
765 if(!isascii(*s)) return(FALSE);
766 s++;
767 }
768 return(TRUE);
769 }
770
771 bool wxString::IsWord() const
772 {
773 const char *s = (const char*) *this;
774 while(*s){
775 if(!isalpha(*s)) return(FALSE);
776 s++;
777 }
778 return(TRUE);
779 }
780
781 bool wxString::IsNumber() const
782 {
783 const char *s = (const char*) *this;
784 while(*s){
785 if(!isdigit(*s)) return(FALSE);
786 s++;
787 }
788 return(TRUE);
789 }
790
791 wxString wxString::Strip(stripType w) const
792 {
793 wxString s = *this;
794 if ( w & leading ) s.Trim(FALSE);
795 if ( w & trailing ) s.Trim(TRUE);
796 return s;
797 }
798
799 // ---------------------------------------------------------------------------
800 // case conversion
801 // ---------------------------------------------------------------------------
802
803 wxString& wxString::MakeUpper()
804 {
805 CopyBeforeWrite();
806
807 for ( char *p = m_pchData; *p; p++ )
808 *p = (char)toupper(*p);
809
810 return *this;
811 }
812
813 wxString& wxString::MakeLower()
814 {
815 CopyBeforeWrite();
816
817 for ( char *p = m_pchData; *p; p++ )
818 *p = (char)tolower(*p);
819
820 return *this;
821 }
822
823 // ---------------------------------------------------------------------------
824 // trimming and padding
825 // ---------------------------------------------------------------------------
826
827 // trims spaces (in the sense of isspace) from left or right side
828 wxString& wxString::Trim(bool bFromRight)
829 {
830 // first check if we're going to modify the string at all
831 if ( !IsEmpty() &&
832 (
833 (bFromRight && isspace(GetChar(Len() - 1))) ||
834 (!bFromRight && isspace(GetChar(0u)))
835 )
836 )
837 {
838 // ok, there is at least one space to trim
839 CopyBeforeWrite();
840
841 if ( bFromRight )
842 {
843 // find last non-space character
844 char *psz = m_pchData + GetStringData()->nDataLength - 1;
845 while ( isspace(*psz) && (psz >= m_pchData) )
846 psz--;
847
848 // truncate at trailing space start
849 *++psz = '\0';
850 GetStringData()->nDataLength = psz - m_pchData;
851 }
852 else
853 {
854 // find first non-space character
855 const char *psz = m_pchData;
856 while ( isspace(*psz) )
857 psz++;
858
859 // fix up data and length
860 int nDataLength = GetStringData()->nDataLength - (psz - (const char*) m_pchData);
861 memmove(m_pchData, psz, (nDataLength + 1)*sizeof(char));
862 GetStringData()->nDataLength = nDataLength;
863 }
864 }
865
866 return *this;
867 }
868
869 // adds nCount characters chPad to the string from either side
870 wxString& wxString::Pad(size_t nCount, char chPad, bool bFromRight)
871 {
872 wxString s(chPad, nCount);
873
874 if ( bFromRight )
875 *this += s;
876 else
877 {
878 s += *this;
879 *this = s;
880 }
881
882 return *this;
883 }
884
885 // truncate the string
886 wxString& wxString::Truncate(size_t uiLen)
887 {
888 if ( uiLen < Len() ) {
889 CopyBeforeWrite();
890
891 *(m_pchData + uiLen) = '\0';
892 GetStringData()->nDataLength = uiLen;
893 }
894 //else: nothing to do, string is already short enough
895
896 return *this;
897 }
898
899 // ---------------------------------------------------------------------------
900 // finding (return wxNOT_FOUND if not found and index otherwise)
901 // ---------------------------------------------------------------------------
902
903 // find a character
904 int wxString::Find(char ch, bool bFromEnd) const
905 {
906 const char *psz = bFromEnd ? strrchr(m_pchData, ch) : strchr(m_pchData, ch);
907
908 return (psz == NULL) ? wxNOT_FOUND : psz - (const char*) m_pchData;
909 }
910
911 // find a sub-string (like strstr)
912 int wxString::Find(const char *pszSub) const
913 {
914 const char *psz = strstr(m_pchData, pszSub);
915
916 return (psz == NULL) ? wxNOT_FOUND : psz - (const char*) m_pchData;
917 }
918
919 // ---------------------------------------------------------------------------
920 // stream-like operators
921 // ---------------------------------------------------------------------------
922 wxString& wxString::operator<<(int i)
923 {
924 wxString res;
925 res.Printf("%d", i);
926
927 return (*this) << res;
928 }
929
930 wxString& wxString::operator<<(float f)
931 {
932 wxString res;
933 res.Printf("%f", f);
934
935 return (*this) << res;
936 }
937
938 wxString& wxString::operator<<(double d)
939 {
940 wxString res;
941 res.Printf("%g", d);
942
943 return (*this) << res;
944 }
945
946 // ---------------------------------------------------------------------------
947 // formatted output
948 // ---------------------------------------------------------------------------
949 int wxString::Printf(const char *pszFormat, ...)
950 {
951 va_list argptr;
952 va_start(argptr, pszFormat);
953
954 int iLen = PrintfV(pszFormat, argptr);
955
956 va_end(argptr);
957
958 return iLen;
959 }
960
961 int wxString::PrintfV(const char* pszFormat, va_list argptr)
962 {
963 // static buffer to avoid dynamic memory allocation each time
964 static char s_szScratch[1024];
965
966 // NB: wxVsprintf() may return either less than the buffer size or -1 if there
967 // is not enough place depending on implementation
968 int iLen = wxVsprintf(s_szScratch, WXSIZEOF(s_szScratch), pszFormat, argptr);
969 char *buffer;
970 if ( iLen < (int)WXSIZEOF(s_szScratch) ) {
971 buffer = s_szScratch;
972 }
973 else {
974 int size = WXSIZEOF(s_szScratch) * 2;
975 buffer = (char *)malloc(size);
976 while ( buffer != NULL ) {
977 iLen = wxVsprintf(buffer, WXSIZEOF(s_szScratch), pszFormat, argptr);
978 if ( iLen < size ) {
979 // ok, there was enough space
980 break;
981 }
982
983 // still not enough, double it again
984 buffer = (char *)realloc(buffer, size *= 2);
985 }
986
987 if ( !buffer ) {
988 // out of memory
989 return -1;
990 }
991 }
992
993 AllocBeforeWrite(iLen);
994 strcpy(m_pchData, buffer);
995
996 if ( buffer != s_szScratch )
997 free(buffer);
998
999 return iLen;
1000 }
1001
1002 // ----------------------------------------------------------------------------
1003 // misc other operations
1004 // ----------------------------------------------------------------------------
1005 bool wxString::Matches(const char *pszMask) const
1006 {
1007 // check char by char
1008 const char *pszTxt;
1009 for ( pszTxt = c_str(); *pszMask != '\0'; pszMask++, pszTxt++ ) {
1010 switch ( *pszMask ) {
1011 case '?':
1012 if ( *pszTxt == '\0' )
1013 return FALSE;
1014
1015 pszTxt++;
1016 pszMask++;
1017 break;
1018
1019 case '*':
1020 {
1021 // ignore special chars immediately following this one
1022 while ( *pszMask == '*' || *pszMask == '?' )
1023 pszMask++;
1024
1025 // if there is nothing more, match
1026 if ( *pszMask == '\0' )
1027 return TRUE;
1028
1029 // are there any other metacharacters in the mask?
1030 size_t uiLenMask;
1031 const char *pEndMask = strpbrk(pszMask, "*?");
1032
1033 if ( pEndMask != NULL ) {
1034 // we have to match the string between two metachars
1035 uiLenMask = pEndMask - pszMask;
1036 }
1037 else {
1038 // we have to match the remainder of the string
1039 uiLenMask = strlen(pszMask);
1040 }
1041
1042 wxString strToMatch(pszMask, uiLenMask);
1043 const char* pMatch = strstr(pszTxt, strToMatch);
1044 if ( pMatch == NULL )
1045 return FALSE;
1046
1047 // -1 to compensate "++" in the loop
1048 pszTxt = pMatch + uiLenMask - 1;
1049 pszMask += uiLenMask - 1;
1050 }
1051 break;
1052
1053 default:
1054 if ( *pszMask != *pszTxt )
1055 return FALSE;
1056 break;
1057 }
1058 }
1059
1060 // match only if nothing left
1061 return *pszTxt == '\0';
1062 }
1063
1064 // Count the number of chars
1065 int wxString::Freq(char ch) const
1066 {
1067 int count = 0;
1068 int len = Len();
1069 for (int i = 0; i < len; i++)
1070 {
1071 if (GetChar(i) == ch)
1072 count ++;
1073 }
1074 return count;
1075 }
1076
1077 // convert to upper case, return the copy of the string
1078 wxString wxString::Upper() const
1079 { wxString s(*this); return s.MakeUpper(); }
1080
1081 // convert to lower case, return the copy of the string
1082 wxString wxString::Lower() const { wxString s(*this); return s.MakeLower(); }
1083
1084 int wxString::sprintf(const char *pszFormat, ...)
1085 {
1086 va_list argptr;
1087 va_start(argptr, pszFormat);
1088 int iLen = PrintfV(pszFormat, argptr);
1089 va_end(argptr);
1090 return iLen;
1091 }
1092
1093 // ---------------------------------------------------------------------------
1094 // standard C++ library string functions
1095 // ---------------------------------------------------------------------------
1096 #ifdef wxSTD_STRING_COMPATIBILITY
1097
1098 wxString& wxString::insert(size_t nPos, const wxString& str)
1099 {
1100 wxASSERT( str.GetStringData()->IsValid() );
1101 wxASSERT( nPos <= Len() );
1102
1103 if ( !str.IsEmpty() ) {
1104 wxString strTmp;
1105 char *pc = strTmp.GetWriteBuf(Len() + str.Len());
1106 strncpy(pc, c_str(), nPos);
1107 strcpy(pc + nPos, str);
1108 strcpy(pc + nPos + str.Len(), c_str() + nPos);
1109 strTmp.UngetWriteBuf();
1110 *this = strTmp;
1111 }
1112
1113 return *this;
1114 }
1115
1116 size_t wxString::find(const wxString& str, size_t nStart) const
1117 {
1118 wxASSERT( str.GetStringData()->IsValid() );
1119 wxASSERT( nStart <= Len() );
1120
1121 const char *p = strstr(c_str() + nStart, str);
1122
1123 return p == NULL ? npos : p - c_str();
1124 }
1125
1126 // VC++ 1.5 can't cope with the default argument in the header.
1127 #if !defined(__VISUALC__) || defined(__WIN32__)
1128 size_t wxString::find(const char* sz, size_t nStart, size_t n) const
1129 {
1130 return find(wxString(sz, n == npos ? 0 : n), nStart);
1131 }
1132 #endif // VC++ 1.5
1133
1134 // Gives a duplicate symbol (presumably a case-insensitivity problem)
1135 #if !defined(__BORLANDC__)
1136 size_t wxString::find(char ch, size_t nStart) const
1137 {
1138 wxASSERT( nStart <= Len() );
1139
1140 const char *p = strchr(c_str() + nStart, ch);
1141
1142 return p == NULL ? npos : p - c_str();
1143 }
1144 #endif
1145
1146 size_t wxString::rfind(const wxString& str, size_t nStart) const
1147 {
1148 wxASSERT( str.GetStringData()->IsValid() );
1149 wxASSERT( nStart <= Len() );
1150
1151 // # could be quicker than that
1152 const char *p = c_str() + (nStart == npos ? Len() : nStart);
1153 while ( p >= c_str() + str.Len() ) {
1154 if ( strncmp(p - str.Len(), str, str.Len()) == 0 )
1155 return p - str.Len() - c_str();
1156 p--;
1157 }
1158
1159 return npos;
1160 }
1161
1162 // VC++ 1.5 can't cope with the default argument in the header.
1163 #if !defined(__VISUALC__) || defined(__WIN32__)
1164 size_t wxString::rfind(const char* sz, size_t nStart, size_t n) const
1165 {
1166 return rfind(wxString(sz, n == npos ? 0 : n), nStart);
1167 }
1168
1169 size_t wxString::rfind(char ch, size_t nStart) const
1170 {
1171 wxASSERT( nStart <= Len() );
1172
1173 const char *p = strrchr(c_str() + nStart, ch);
1174
1175 return p == NULL ? npos : p - c_str();
1176 }
1177 #endif // VC++ 1.5
1178
1179 wxString wxString::substr(size_t nStart, size_t nLen) const
1180 {
1181 // npos means 'take all'
1182 if ( nLen == npos )
1183 nLen = 0;
1184
1185 wxASSERT( nStart + nLen <= Len() );
1186
1187 return wxString(c_str() + nStart, nLen == npos ? 0 : nLen);
1188 }
1189
1190 wxString& wxString::erase(size_t nStart, size_t nLen)
1191 {
1192 wxString strTmp(c_str(), nStart);
1193 if ( nLen != npos ) {
1194 wxASSERT( nStart + nLen <= Len() );
1195
1196 strTmp.append(c_str() + nStart + nLen);
1197 }
1198
1199 *this = strTmp;
1200 return *this;
1201 }
1202
1203 wxString& wxString::replace(size_t nStart, size_t nLen, const char *sz)
1204 {
1205 wxASSERT( nStart + nLen <= Strlen(sz) );
1206
1207 wxString strTmp;
1208 if ( nStart != 0 )
1209 strTmp.append(c_str(), nStart);
1210 strTmp += sz;
1211 strTmp.append(c_str() + nStart + nLen);
1212
1213 *this = strTmp;
1214 return *this;
1215 }
1216
1217 wxString& wxString::replace(size_t nStart, size_t nLen, size_t nCount, char ch)
1218 {
1219 return replace(nStart, nLen, wxString(ch, nCount));
1220 }
1221
1222 wxString& wxString::replace(size_t nStart, size_t nLen,
1223 const wxString& str, size_t nStart2, size_t nLen2)
1224 {
1225 return replace(nStart, nLen, str.substr(nStart2, nLen2));
1226 }
1227
1228 wxString& wxString::replace(size_t nStart, size_t nLen,
1229 const char* sz, size_t nCount)
1230 {
1231 return replace(nStart, nLen, wxString(sz, nCount));
1232 }
1233
1234 #endif //std::string compatibility
1235
1236 // ============================================================================
1237 // ArrayString
1238 // ============================================================================
1239
1240 // size increment = max(50% of current size, ARRAY_MAXSIZE_INCREMENT)
1241 #define ARRAY_MAXSIZE_INCREMENT 4096
1242 #ifndef ARRAY_DEFAULT_INITIAL_SIZE // also defined in dynarray.h
1243 #define ARRAY_DEFAULT_INITIAL_SIZE (16)
1244 #endif
1245
1246 #define STRING(p) ((wxString *)(&(p)))
1247
1248 // ctor
1249 wxArrayString::wxArrayString()
1250 {
1251 m_nSize =
1252 m_nCount = 0;
1253 m_pItems = (char **) NULL;
1254 }
1255
1256 // copy ctor
1257 wxArrayString::wxArrayString(const wxArrayString& src)
1258 {
1259 m_nSize =
1260 m_nCount = 0;
1261 m_pItems = (char **) NULL;
1262
1263 *this = src;
1264 }
1265
1266 // assignment operator
1267 wxArrayString& wxArrayString::operator=(const wxArrayString& src)
1268 {
1269 if ( m_nSize > 0 )
1270 Clear();
1271
1272 if ( src.m_nCount > ARRAY_DEFAULT_INITIAL_SIZE )
1273 Alloc(src.m_nCount);
1274
1275 // we can't just copy the pointers here because otherwise we would share
1276 // the strings with another array
1277 for ( size_t n = 0; n < src.m_nCount; n++ )
1278 Add(src[n]);
1279
1280 if ( m_nCount != 0 )
1281 memcpy(m_pItems, src.m_pItems, m_nCount*sizeof(char *));
1282
1283 return *this;
1284 }
1285
1286 // grow the array
1287 void wxArrayString::Grow()
1288 {
1289 // only do it if no more place
1290 if( m_nCount == m_nSize ) {
1291 if( m_nSize == 0 ) {
1292 // was empty, alloc some memory
1293 m_nSize = ARRAY_DEFAULT_INITIAL_SIZE;
1294 m_pItems = new char *[m_nSize];
1295 }
1296 else {
1297 // otherwise when it's called for the first time, nIncrement would be 0
1298 // and the array would never be expanded
1299 wxASSERT( ARRAY_DEFAULT_INITIAL_SIZE != 0 );
1300
1301 // add 50% but not too much
1302 size_t nIncrement = m_nSize < ARRAY_DEFAULT_INITIAL_SIZE
1303 ? ARRAY_DEFAULT_INITIAL_SIZE : m_nSize >> 1;
1304 if ( nIncrement > ARRAY_MAXSIZE_INCREMENT )
1305 nIncrement = ARRAY_MAXSIZE_INCREMENT;
1306 m_nSize += nIncrement;
1307 char **pNew = new char *[m_nSize];
1308
1309 // copy data to new location
1310 memcpy(pNew, m_pItems, m_nCount*sizeof(char *));
1311
1312 // delete old memory (but do not release the strings!)
1313 wxDELETEA(m_pItems);
1314
1315 m_pItems = pNew;
1316 }
1317 }
1318 }
1319
1320 void wxArrayString::Free()
1321 {
1322 for ( size_t n = 0; n < m_nCount; n++ ) {
1323 STRING(m_pItems[n])->GetStringData()->Unlock();
1324 }
1325 }
1326
1327 // deletes all the strings from the list
1328 void wxArrayString::Empty()
1329 {
1330 Free();
1331
1332 m_nCount = 0;
1333 }
1334
1335 // as Empty, but also frees memory
1336 void wxArrayString::Clear()
1337 {
1338 Free();
1339
1340 m_nSize =
1341 m_nCount = 0;
1342
1343 wxDELETEA(m_pItems);
1344 }
1345
1346 // dtor
1347 wxArrayString::~wxArrayString()
1348 {
1349 Free();
1350
1351 wxDELETEA(m_pItems);
1352 }
1353
1354 // pre-allocates memory (frees the previous data!)
1355 void wxArrayString::Alloc(size_t nSize)
1356 {
1357 wxASSERT( nSize > 0 );
1358
1359 // only if old buffer was not big enough
1360 if ( nSize > m_nSize ) {
1361 Free();
1362 wxDELETEA(m_pItems);
1363 m_pItems = new char *[nSize];
1364 m_nSize = nSize;
1365 }
1366
1367 m_nCount = 0;
1368 }
1369
1370 // searches the array for an item (forward or backwards)
1371 int wxArrayString::Index(const char *sz, bool bCase, bool bFromEnd) const
1372 {
1373 if ( bFromEnd ) {
1374 if ( m_nCount > 0 ) {
1375 size_t ui = m_nCount;
1376 do {
1377 if ( STRING(m_pItems[--ui])->IsSameAs(sz, bCase) )
1378 return ui;
1379 }
1380 while ( ui != 0 );
1381 }
1382 }
1383 else {
1384 for( size_t ui = 0; ui < m_nCount; ui++ ) {
1385 if( STRING(m_pItems[ui])->IsSameAs(sz, bCase) )
1386 return ui;
1387 }
1388 }
1389
1390 return wxNOT_FOUND;
1391 }
1392
1393 // add item at the end
1394 void wxArrayString::Add(const wxString& str)
1395 {
1396 wxASSERT( str.GetStringData()->IsValid() );
1397
1398 Grow();
1399
1400 // the string data must not be deleted!
1401 str.GetStringData()->Lock();
1402 m_pItems[m_nCount++] = (char *)str.c_str();
1403 }
1404
1405 // add item at the given position
1406 void wxArrayString::Insert(const wxString& str, size_t nIndex)
1407 {
1408 wxASSERT( str.GetStringData()->IsValid() );
1409
1410 wxCHECK_RET( nIndex <= m_nCount, ("bad index in wxArrayString::Insert") );
1411
1412 Grow();
1413
1414 memmove(&m_pItems[nIndex + 1], &m_pItems[nIndex],
1415 (m_nCount - nIndex)*sizeof(char *));
1416
1417 str.GetStringData()->Lock();
1418 m_pItems[nIndex] = (char *)str.c_str();
1419
1420 m_nCount++;
1421 }
1422
1423 // removes item from array (by index)
1424 void wxArrayString::Remove(size_t nIndex)
1425 {
1426 wxCHECK_RET( nIndex <= m_nCount, _("bad index in wxArrayString::Remove") );
1427
1428 // release our lock
1429 Item(nIndex).GetStringData()->Unlock();
1430
1431 memmove(&m_pItems[nIndex], &m_pItems[nIndex + 1],
1432 (m_nCount - nIndex - 1)*sizeof(char *));
1433 m_nCount--;
1434 }
1435
1436 // removes item from array (by value)
1437 void wxArrayString::Remove(const char *sz)
1438 {
1439 int iIndex = Index(sz);
1440
1441 wxCHECK_RET( iIndex != wxNOT_FOUND,
1442 _("removing inexistent element in wxArrayString::Remove") );
1443
1444 Remove(iIndex);
1445 }
1446
1447 // ----------------------------------------------------------------------------
1448 // sorting
1449 // ----------------------------------------------------------------------------
1450
1451 // we can only sort one array at a time with the quick-sort based
1452 // implementation
1453 #if wxUSE_THREADS
1454 #include <wx/thread.h>
1455
1456 // need a critical section to protect access to gs_compareFunction and
1457 // gs_sortAscending variables
1458 static wxCriticalSection *gs_critsectStringSort = NULL;
1459
1460 // call this before the value of the global sort vars is changed/after
1461 // you're finished with them
1462 #define START_SORT() wxASSERT( !gs_critsectStringSort ); \
1463 gs_critsectStringSort = new wxCriticalSection; \
1464 gs_critsectStringSort->Enter()
1465 #define END_SORT() gs_critsectStringSort->Leave(); \
1466 delete gs_critsectStringSort; \
1467 gs_critsectStringSort = NULL
1468 #else // !threads
1469 #define START_SORT()
1470 #define END_SORT()
1471 #endif // wxUSE_THREADS
1472
1473 // function to use for string comparaison
1474 static wxArrayString::CompareFunction gs_compareFunction = NULL;
1475
1476 // if we don't use the compare function, this flag tells us if we sort the
1477 // array in ascending or descending order
1478 static bool gs_sortAscending = TRUE;
1479
1480 // function which is called by quick sort
1481 static int wxStringCompareFunction(const void *first, const void *second)
1482 {
1483 wxString *strFirst = (wxString *)first;
1484 wxString *strSecond = (wxString *)second;
1485
1486 if ( gs_compareFunction ) {
1487 return gs_compareFunction(*strFirst, *strSecond);
1488 }
1489 else {
1490 int result = strcmp(strFirst->c_str(), strSecond->c_str());
1491
1492 return gs_sortAscending ? result : -result;
1493 }
1494 }
1495
1496 // sort array elements using passed comparaison function
1497 void wxArrayString::Sort(CompareFunction compareFunction)
1498 {
1499 START_SORT();
1500
1501 wxASSERT( !gs_compareFunction ); // must have been reset to NULL
1502 gs_compareFunction = compareFunction;
1503
1504 DoSort();
1505
1506 END_SORT();
1507 }
1508
1509 void wxArrayString::Sort(bool reverseOrder)
1510 {
1511 START_SORT();
1512
1513 wxASSERT( !gs_compareFunction ); // must have been reset to NULL
1514 gs_sortAscending = !reverseOrder;
1515
1516 DoSort();
1517
1518 END_SORT();
1519 }
1520
1521 void wxArrayString::DoSort()
1522 {
1523 // just sort the pointers using qsort() - of course it only works because
1524 // wxString() *is* a pointer to its data
1525 qsort(m_pItems, m_nCount, sizeof(char *), wxStringCompareFunction);
1526 }