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