fix crash in ~wxString with global wxString objects: temporarily move conversion...
[wxWidgets.git] / src / common / string.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/string.cpp
3 // Purpose: wxString class
4 // Author: Vadim Zeitlin, Ryan Norton
5 // Modified by:
6 // Created: 29/01/98
7 // RCS-ID: $Id$
8 // Copyright: (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
9 // (c) 2004 Ryan Norton <wxprojects@comcast.net>
10 // Licence: wxWindows licence
11 /////////////////////////////////////////////////////////////////////////////
12
13 /*
14 * About ref counting:
15 * 1) all empty strings use g_strEmpty, nRefs = -1 (set in Init())
16 * 2) AllocBuffer() sets nRefs to 1, Lock() increments it by one
17 * 3) Unlock() decrements nRefs and frees memory if it goes to 0
18 */
19
20 // ===========================================================================
21 // headers, declarations, constants
22 // ===========================================================================
23
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
26
27 #ifdef __BORLANDC__
28 #pragma hdrstop
29 #endif
30
31 #ifndef WX_PRECOMP
32 #include "wx/string.h"
33 #endif
34
35 #include <ctype.h>
36
37 #ifndef __WXWINCE__
38 #include <errno.h>
39 #endif
40
41 #include <string.h>
42 #include <stdlib.h>
43
44 #ifdef __SALFORDC__
45 #include <clib.h>
46 #endif
47
48 #include <wx/hashmap.h>
49
50 // string handling functions used by wxString:
51 #if wxUSE_UNICODE_UTF8
52 #define wxStringMemcpy memcpy
53 #define wxStringMemcmp memcmp
54 #define wxStringMemchr memchr
55 #define wxStringStrlen strlen
56 #else
57 #define wxStringMemcpy wxTmemcpy
58 #define wxStringMemcmp wxTmemcmp
59 #define wxStringMemchr wxTmemchr
60 #define wxStringStrlen wxStrlen
61 #endif
62
63
64 // ---------------------------------------------------------------------------
65 // static class variables definition
66 // ---------------------------------------------------------------------------
67
68 //According to STL _must_ be a -1 size_t
69 const size_t wxString::npos = (size_t) -1;
70
71 // ----------------------------------------------------------------------------
72 // global functions
73 // ----------------------------------------------------------------------------
74
75 #if wxUSE_STD_IOSTREAM
76
77 #include <iostream>
78
79 wxSTD ostream& operator<<(wxSTD ostream& os, const wxCStrData& str)
80 {
81 // FIXME-UTF8: always, not only if wxUSE_UNICODE
82 #if wxUSE_UNICODE && !defined(__BORLANDC__)
83 return os << str.AsWChar();
84 #else
85 return os << str.AsChar();
86 #endif
87 }
88
89 wxSTD ostream& operator<<(wxSTD ostream& os, const wxString& str)
90 {
91 return os << str.c_str();
92 }
93
94 wxSTD ostream& operator<<(wxSTD ostream& os, const wxCharBuffer& str)
95 {
96 return os << str.data();
97 }
98
99 #ifndef __BORLANDC__
100 wxSTD ostream& operator<<(wxSTD ostream& os, const wxWCharBuffer& str)
101 {
102 return os << str.data();
103 }
104 #endif
105
106 #endif // wxUSE_STD_IOSTREAM
107
108 // ----------------------------------------------------------------------------
109 // wxCStrData converted strings caching
110 // ----------------------------------------------------------------------------
111
112 // FIXME-UTF8: temporarily disabled because it doesn't work with global
113 // string objects; re-enable after fixing this bug and benchmarking
114 // performance to see if using a hash is a good idea at all
115 #if 0
116
117 // For backward compatibility reasons, it must be possible to assign the value
118 // returned by wxString::c_str() to a char* or wchar_t* variable and work with
119 // it. Returning wxCharBuffer from (const char*)c_str() wouldn't do the trick,
120 // because the memory would be freed immediately, but it has to be valid as long
121 // as the string is not modified, so that code like this still works:
122 //
123 // const wxChar *s = str.c_str();
124 // while ( s ) { ... }
125
126 // FIXME-UTF8: not thread safe!
127 // FIXME-UTF8: we currently clear the cached conversion only when the string is
128 // destroyed, but we should do it when the string is modified, to
129 // keep memory usage down
130 // FIXME-UTF8: we do the conversion every time As[W]Char() is called, but if we
131 // invalidated the cache on every change, we could keep the previous
132 // conversion
133 // FIXME-UTF8: add tracing of usage of these two methods - new code is supposed
134 // to use mb_str() or wc_str() instead of (const [w]char*)c_str()
135
136 template<typename T>
137 static inline void DeleteStringFromConversionCache(T& hash, const wxString *s)
138 {
139 typename T::iterator i = hash.find(wxConstCast(s, wxString));
140 if ( i != hash.end() )
141 {
142 free(i->second);
143 hash.erase(i);
144 }
145 }
146
147 #if wxUSE_UNICODE
148 // NB: non-STL implementation doesn't compile with "const wxString*" key type,
149 // so we have to use wxString* here and const-cast when used
150 WX_DECLARE_HASH_MAP(wxString*, char*, wxPointerHash, wxPointerEqual,
151 wxStringCharConversionCache);
152 static wxStringCharConversionCache gs_stringsCharCache;
153
154 const char* wxCStrData::AsChar() const
155 {
156 // remove previously cache value, if any (see FIXMEs above):
157 DeleteStringFromConversionCache(gs_stringsCharCache, m_str);
158
159 // convert the string and keep it:
160 const char *s = gs_stringsCharCache[wxConstCast(m_str, wxString)] =
161 m_str->mb_str().release();
162
163 return s + m_offset;
164 }
165 #endif // wxUSE_UNICODE
166
167 #if !wxUSE_UNICODE_WCHAR
168 WX_DECLARE_HASH_MAP(wxString*, wchar_t*, wxPointerHash, wxPointerEqual,
169 wxStringWCharConversionCache);
170 static wxStringWCharConversionCache gs_stringsWCharCache;
171
172 const wchar_t* wxCStrData::AsWChar() const
173 {
174 // remove previously cache value, if any (see FIXMEs above):
175 DeleteStringFromConversionCache(gs_stringsWCharCache, m_str);
176
177 // convert the string and keep it:
178 const wchar_t *s = gs_stringsWCharCache[wxConstCast(m_str, wxString)] =
179 m_str->wc_str().release();
180
181 return s + m_offset;
182 }
183 #endif // !wxUSE_UNICODE_WCHAR
184
185 wxString::~wxString()
186 {
187 #if wxUSE_UNICODE
188 // FIXME-UTF8: do this only if locale is not UTF8 if wxUSE_UNICODE_UTF8
189 DeleteStringFromConversionCache(gs_stringsCharCache, this);
190 #endif
191 #if !wxUSE_UNICODE_WCHAR
192 DeleteStringFromConversionCache(gs_stringsWCharCache, this);
193 #endif
194 }
195 #endif
196
197 #if wxUSE_UNICODE
198 const char* wxCStrData::AsChar() const
199 {
200 wxString *str = wxConstCast(m_str, wxString);
201 // convert the string and keep it:
202 str->m_convertedToChar = str->mb_str().release();
203 return str->m_convertedToChar + m_offset;
204 }
205 #endif // wxUSE_UNICODE
206
207 #if !wxUSE_UNICODE_WCHAR
208 const wchar_t* wxCStrData::AsWChar() const
209 {
210 wxString *str = wxConstCast(m_str, wxString);
211 // convert the string and keep it:
212 str->m_convertedToWChar = str->wc_str().release();
213 return str->m_convertedToWChar + m_offset;
214 }
215 #endif // !wxUSE_UNICODE_WCHAR
216
217 // ===========================================================================
218 // wxString class core
219 // ===========================================================================
220
221 // ---------------------------------------------------------------------------
222 // construction and conversion
223 // ---------------------------------------------------------------------------
224
225 #if wxUSE_UNICODE
226 /* static */
227 wxString::SubstrBufFromMB wxString::ConvertStr(const char *psz, size_t nLength,
228 const wxMBConv& conv)
229 {
230 // anything to do?
231 if ( !psz || nLength == 0 )
232 return SubstrBufFromMB();
233
234 if ( nLength == npos )
235 nLength = wxNO_LEN;
236
237 size_t wcLen;
238 wxWCharBuffer wcBuf(conv.cMB2WC(psz, nLength, &wcLen));
239 if ( !wcLen )
240 return SubstrBufFromMB();
241 else
242 return SubstrBufFromMB(wcBuf, wcLen);
243 }
244 #else
245 /* static */
246 wxString::SubstrBufFromWC wxString::ConvertStr(const wchar_t *pwz, size_t nLength,
247 const wxMBConv& conv)
248 {
249 // anything to do?
250 if ( !pwz || nLength == 0 )
251 return SubstrBufFromWC();
252
253 if ( nLength == npos )
254 nLength = wxNO_LEN;
255
256 size_t mbLen;
257 wxCharBuffer mbBuf(conv.cWC2MB(pwz, nLength, &mbLen));
258 if ( !mbLen )
259 return SubstrBufFromWC();
260 else
261 return SubstrBufFromWC(mbBuf, mbLen);
262 }
263 #endif
264
265
266 #if wxUSE_UNICODE
267
268 //Convert wxString in Unicode mode to a multi-byte string
269 const wxCharBuffer wxString::mb_str(const wxMBConv& conv) const
270 {
271 return conv.cWC2MB(c_str(), length() + 1 /* size, not length */, NULL);
272 }
273
274 #else // ANSI
275
276 #if wxUSE_WCHAR_T
277
278 //Converts this string to a wide character string if unicode
279 //mode is not enabled and wxUSE_WCHAR_T is enabled
280 const wxWCharBuffer wxString::wc_str(const wxMBConv& conv) const
281 {
282 return conv.cMB2WC(c_str(), length() + 1 /* size, not length */, NULL);
283 }
284
285 #endif // wxUSE_WCHAR_T
286
287 #endif // Unicode/ANSI
288
289 // shrink to minimal size (releasing extra memory)
290 bool wxString::Shrink()
291 {
292 wxString tmp(begin(), end());
293 swap(tmp);
294 return tmp.length() == length();
295 }
296
297 // deprecated compatibility code:
298 #if WXWIN_COMPATIBILITY_2_8 && !wxUSE_STL_BASED_WXSTRING && !wxUSE_UNICODE_UTF8
299 wxChar *wxString::GetWriteBuf(size_t nLen)
300 {
301 return DoGetWriteBuf(nLen);
302 }
303
304 void wxString::UngetWriteBuf()
305 {
306 DoUngetWriteBuf();
307 }
308
309 void wxString::UngetWriteBuf(size_t nLen)
310 {
311 DoUngetWriteBuf(nLen);
312 }
313 #endif // WXWIN_COMPATIBILITY_2_8 && !wxUSE_STL_BASED_WXSTRING && !wxUSE_UNICODE_UTF8
314
315
316 // ---------------------------------------------------------------------------
317 // data access
318 // ---------------------------------------------------------------------------
319
320 // all functions are inline in string.h
321
322 // ---------------------------------------------------------------------------
323 // concatenation operators
324 // ---------------------------------------------------------------------------
325
326 /*
327 * concatenation functions come in 5 flavours:
328 * string + string
329 * char + string and string + char
330 * C str + string and string + C str
331 */
332
333 wxString operator+(const wxString& str1, const wxString& str2)
334 {
335 #if !wxUSE_STL_BASED_WXSTRING
336 wxASSERT( str1.IsValid() );
337 wxASSERT( str2.IsValid() );
338 #endif
339
340 wxString s = str1;
341 s += str2;
342
343 return s;
344 }
345
346 wxString operator+(const wxString& str, wxUniChar ch)
347 {
348 #if !wxUSE_STL_BASED_WXSTRING
349 wxASSERT( str.IsValid() );
350 #endif
351
352 wxString s = str;
353 s += ch;
354
355 return s;
356 }
357
358 wxString operator+(wxUniChar ch, const wxString& str)
359 {
360 #if !wxUSE_STL_BASED_WXSTRING
361 wxASSERT( str.IsValid() );
362 #endif
363
364 wxString s = ch;
365 s += str;
366
367 return s;
368 }
369
370 wxString operator+(const wxString& str, const char *psz)
371 {
372 #if !wxUSE_STL_BASED_WXSTRING
373 wxASSERT( str.IsValid() );
374 #endif
375
376 wxString s;
377 if ( !s.Alloc(strlen(psz) + str.length()) ) {
378 wxFAIL_MSG( _T("out of memory in wxString::operator+") );
379 }
380 s += str;
381 s += psz;
382
383 return s;
384 }
385
386 wxString operator+(const wxString& str, const wchar_t *pwz)
387 {
388 #if !wxUSE_STL_BASED_WXSTRING
389 wxASSERT( str.IsValid() );
390 #endif
391
392 wxString s;
393 if ( !s.Alloc(wxWcslen(pwz) + str.length()) ) {
394 wxFAIL_MSG( _T("out of memory in wxString::operator+") );
395 }
396 s += str;
397 s += pwz;
398
399 return s;
400 }
401
402 wxString operator+(const char *psz, const wxString& str)
403 {
404 #if !wxUSE_STL_BASED_WXSTRING
405 wxASSERT( str.IsValid() );
406 #endif
407
408 wxString s;
409 if ( !s.Alloc(strlen(psz) + str.length()) ) {
410 wxFAIL_MSG( _T("out of memory in wxString::operator+") );
411 }
412 s = psz;
413 s += str;
414
415 return s;
416 }
417
418 wxString operator+(const wchar_t *pwz, const wxString& str)
419 {
420 #if !wxUSE_STL_BASED_WXSTRING
421 wxASSERT( str.IsValid() );
422 #endif
423
424 wxString s;
425 if ( !s.Alloc(wxWcslen(pwz) + str.length()) ) {
426 wxFAIL_MSG( _T("out of memory in wxString::operator+") );
427 }
428 s = pwz;
429 s += str;
430
431 return s;
432 }
433
434 // ---------------------------------------------------------------------------
435 // string comparison
436 // ---------------------------------------------------------------------------
437
438 #ifdef HAVE_STD_STRING_COMPARE
439
440 // NB: Comparison code (both if HAVE_STD_STRING_COMPARE and if not) works with
441 // UTF-8 encoded strings too, thanks to UTF-8's design which allows us to
442 // sort strings in characters code point order by sorting the byte sequence
443 // in byte values order (i.e. what strcmp() and memcmp() do).
444
445 int wxString::compare(const wxString& str) const
446 {
447 return m_impl.compare(str.m_impl);
448 }
449
450 int wxString::compare(size_t nStart, size_t nLen,
451 const wxString& str) const
452 {
453 size_t pos, len;
454 PosLenToImpl(nStart, nLen, &pos, &len);
455 return m_impl.compare(pos, len, str.m_impl);
456 }
457
458 int wxString::compare(size_t nStart, size_t nLen,
459 const wxString& str,
460 size_t nStart2, size_t nLen2) const
461 {
462 size_t pos, len;
463 PosLenToImpl(nStart, nLen, &pos, &len);
464
465 size_t pos2, len2;
466 str.PosLenToImpl(nStart2, nLen2, &pos2, &len2);
467
468 return m_impl.compare(pos, len, str.m_impl, pos2, len2);
469 }
470
471 int wxString::compare(const char* sz) const
472 {
473 return m_impl.compare(ImplStr(sz));
474 }
475
476 int wxString::compare(const wchar_t* sz) const
477 {
478 return m_impl.compare(ImplStr(sz));
479 }
480
481 int wxString::compare(size_t nStart, size_t nLen,
482 const char* sz, size_t nCount) const
483 {
484 size_t pos, len;
485 PosLenToImpl(nStart, nLen, &pos, &len);
486
487 SubstrBufFromMB str(ImplStr(sz, nCount));
488
489 return m_impl.compare(pos, len, str.data, str.len);
490 }
491
492 int wxString::compare(size_t nStart, size_t nLen,
493 const wchar_t* sz, size_t nCount) const
494 {
495 size_t pos, len;
496 PosLenToImpl(nStart, nLen, &pos, &len);
497
498 SubstrBufFromWC str(ImplStr(sz, nCount));
499
500 return m_impl.compare(pos, len, str.data, str.len);
501 }
502
503 #else // !HAVE_STD_STRING_COMPARE
504
505 static inline int wxDoCmp(const wxStringCharType* s1, size_t l1,
506 const wxStringCharType* s2, size_t l2)
507 {
508 if( l1 == l2 )
509 return wxStringMemcmp(s1, s2, l1);
510 else if( l1 < l2 )
511 {
512 int ret = wxStringMemcmp(s1, s2, l1);
513 return ret == 0 ? -1 : ret;
514 }
515 else
516 {
517 int ret = wxStringMemcmp(s1, s2, l2);
518 return ret == 0 ? +1 : ret;
519 }
520 }
521
522 int wxString::compare(const wxString& str) const
523 {
524 return ::wxDoCmp(m_impl.data(), m_impl.length(),
525 str.m_impl.data(), str.m_impl.length());
526 }
527
528 int wxString::compare(size_t nStart, size_t nLen,
529 const wxString& str) const
530 {
531 wxASSERT(nStart <= length());
532 size_type strLen = length() - nStart;
533 nLen = strLen < nLen ? strLen : nLen;
534
535 size_t pos, len;
536 PosLenToImpl(nStart, nLen, &pos, &len);
537
538 return ::wxDoCmp(m_impl.data() + pos, len,
539 str.m_impl.data(), str.m_impl.length());
540 }
541
542 int wxString::compare(size_t nStart, size_t nLen,
543 const wxString& str,
544 size_t nStart2, size_t nLen2) const
545 {
546 wxASSERT(nStart <= length());
547 wxASSERT(nStart2 <= str.length());
548 size_type strLen = length() - nStart,
549 strLen2 = str.length() - nStart2;
550 nLen = strLen < nLen ? strLen : nLen;
551 nLen2 = strLen2 < nLen2 ? strLen2 : nLen2;
552
553 size_t pos, len;
554 PosLenToImpl(nStart, nLen, &pos, &len);
555 size_t pos2, len2;
556 str.PosLenToImpl(nStart2, nLen2, &pos2, &len2);
557
558 return ::wxDoCmp(m_impl.data() + pos, len,
559 str.m_impl.data() + pos2, len2);
560 }
561
562 int wxString::compare(const char* sz) const
563 {
564 SubstrBufFromMB str(ImplStr(sz, npos));
565 if ( str.len == npos )
566 str.len = wxStringStrlen(str.data);
567 return ::wxDoCmp(m_impl.data(), m_impl.length(), str.data, str.len);
568 }
569
570 int wxString::compare(const wchar_t* sz) const
571 {
572 SubstrBufFromWC str(ImplStr(sz, npos));
573 if ( str.len == npos )
574 str.len = wxStringStrlen(str.data);
575 return ::wxDoCmp(m_impl.data(), m_impl.length(), str.data, str.len);
576 }
577
578 int wxString::compare(size_t nStart, size_t nLen,
579 const char* sz, size_t nCount) const
580 {
581 wxASSERT(nStart <= length());
582 size_type strLen = length() - nStart;
583 nLen = strLen < nLen ? strLen : nLen;
584
585 size_t pos, len;
586 PosLenToImpl(nStart, nLen, &pos, &len);
587
588 SubstrBufFromMB str(ImplStr(sz, nCount));
589 if ( str.len == npos )
590 str.len = wxStringStrlen(str.data);
591
592 return ::wxDoCmp(m_impl.data() + pos, len, str.data, str.len);
593 }
594
595 int wxString::compare(size_t nStart, size_t nLen,
596 const wchar_t* sz, size_t nCount) const
597 {
598 wxASSERT(nStart <= length());
599 size_type strLen = length() - nStart;
600 nLen = strLen < nLen ? strLen : nLen;
601
602 size_t pos, len;
603 PosLenToImpl(nStart, nLen, &pos, &len);
604
605 SubstrBufFromWC str(ImplStr(sz, nCount));
606 if ( str.len == npos )
607 str.len = wxStringStrlen(str.data);
608
609 return ::wxDoCmp(m_impl.data() + pos, len, str.data, str.len);
610 }
611
612 #endif // HAVE_STD_STRING_COMPARE/!HAVE_STD_STRING_COMPARE
613
614
615 // ---------------------------------------------------------------------------
616 // find_{first,last}_[not]_of functions
617 // ---------------------------------------------------------------------------
618
619 #if !wxUSE_STL_BASED_WXSTRING || wxUSE_UNICODE_UTF8
620
621 // NB: All these functions are implemented with the argument being wxChar*,
622 // i.e. widechar string in any Unicode build, even though native string
623 // representation is char* in the UTF-8 build. This is because we couldn't
624 // use memchr() to determine if a character is in a set encoded as UTF-8.
625
626 size_t wxString::find_first_of(const wxChar* sz, size_t nStart) const
627 {
628 return find_first_of(sz, nStart, wxStrlen(sz));
629 }
630
631 size_t wxString::find_first_not_of(const wxChar* sz, size_t nStart) const
632 {
633 return find_first_not_of(sz, nStart, wxStrlen(sz));
634 }
635
636 size_t wxString::find_first_of(const wxChar* sz, size_t nStart, size_t n) const
637 {
638 wxASSERT_MSG( nStart <= length(), _T("invalid index") );
639
640 size_t idx = nStart;
641 for ( const_iterator i = begin() + nStart; i != end(); ++idx, ++i )
642 {
643 if ( wxTmemchr(sz, *i, n) )
644 return idx;
645 }
646
647 return npos;
648 }
649
650 size_t wxString::find_first_not_of(const wxChar* sz, size_t nStart, size_t n) const
651 {
652 wxASSERT_MSG( nStart <= length(), _T("invalid index") );
653
654 size_t idx = nStart;
655 for ( const_iterator i = begin() + nStart; i != end(); ++idx, ++i )
656 {
657 if ( !wxTmemchr(sz, *i, n) )
658 return idx;
659 }
660
661 return npos;
662 }
663
664
665 size_t wxString::find_last_of(const wxChar* sz, size_t nStart) const
666 {
667 return find_last_of(sz, nStart, wxStrlen(sz));
668 }
669
670 size_t wxString::find_last_not_of(const wxChar* sz, size_t nStart) const
671 {
672 return find_last_not_of(sz, nStart, wxStrlen(sz));
673 }
674
675 size_t wxString::find_last_of(const wxChar* sz, size_t nStart, size_t n) const
676 {
677 size_t len = length();
678
679 if ( nStart == npos )
680 {
681 nStart = len - 1;
682 }
683 else
684 {
685 wxASSERT_MSG( nStart <= len, _T("invalid index") );
686 }
687
688 size_t idx = nStart;
689 for ( const_reverse_iterator i = rbegin() + (len - nStart - 1);
690 i != rend(); --idx, ++i )
691 {
692 if ( wxTmemchr(sz, *i, n) )
693 return idx;
694 }
695
696 return npos;
697 }
698
699 size_t wxString::find_last_not_of(const wxChar* sz, size_t nStart, size_t n) const
700 {
701 size_t len = length();
702
703 if ( nStart == npos )
704 {
705 nStart = len - 1;
706 }
707 else
708 {
709 wxASSERT_MSG( nStart <= len, _T("invalid index") );
710 }
711
712 size_t idx = nStart;
713 for ( const_reverse_iterator i = rbegin() + (len - nStart - 1);
714 i != rend(); --idx, ++i )
715 {
716 if ( !wxTmemchr(sz, *i, n) )
717 return idx;
718 }
719
720 return npos;
721 }
722
723 size_t wxString::find_first_not_of(wxUniChar ch, size_t nStart) const
724 {
725 wxASSERT_MSG( nStart <= length(), _T("invalid index") );
726
727 size_t idx = nStart;
728 for ( const_iterator i = begin() + nStart; i != end(); ++idx, ++i )
729 {
730 if ( *i != ch )
731 return idx;
732 }
733
734 return npos;
735 }
736
737 size_t wxString::find_last_not_of(wxUniChar ch, size_t nStart) const
738 {
739 size_t len = length();
740
741 if ( nStart == npos )
742 {
743 nStart = len - 1;
744 }
745 else
746 {
747 wxASSERT_MSG( nStart <= len, _T("invalid index") );
748 }
749
750 size_t idx = nStart;
751 for ( const_reverse_iterator i = rbegin() + (len - nStart - 1);
752 i != rend(); --idx, ++i )
753 {
754 if ( *i != ch )
755 return idx;
756 }
757
758 return npos;
759 }
760
761 // the functions above were implemented for wchar_t* arguments in Unicode
762 // build and char* in ANSI build; below are implementations for the other
763 // version:
764 #if wxUSE_UNICODE
765 #define wxOtherCharType char
766 #define STRCONV (const wxChar*)wxConvLibc.cMB2WC
767 #else
768 #define wxOtherCharType wchar_t
769 #define STRCONV (const wxChar*)wxConvLibc.cWC2MB
770 #endif
771
772 size_t wxString::find_first_of(const wxOtherCharType* sz, size_t nStart) const
773 { return find_first_of(STRCONV(sz), nStart); }
774
775 size_t wxString::find_first_of(const wxOtherCharType* sz, size_t nStart,
776 size_t n) const
777 { return find_first_of(STRCONV(sz, n, NULL), nStart, n); }
778 size_t wxString::find_last_of(const wxOtherCharType* sz, size_t nStart) const
779 { return find_last_of(STRCONV(sz), nStart); }
780 size_t wxString::find_last_of(const wxOtherCharType* sz, size_t nStart,
781 size_t n) const
782 { return find_last_of(STRCONV(sz, n, NULL), nStart, n); }
783 size_t wxString::find_first_not_of(const wxOtherCharType* sz, size_t nStart) const
784 { return find_first_not_of(STRCONV(sz), nStart); }
785 size_t wxString::find_first_not_of(const wxOtherCharType* sz, size_t nStart,
786 size_t n) const
787 { return find_first_not_of(STRCONV(sz, n, NULL), nStart, n); }
788 size_t wxString::find_last_not_of(const wxOtherCharType* sz, size_t nStart) const
789 { return find_last_not_of(STRCONV(sz), nStart); }
790 size_t wxString::find_last_not_of(const wxOtherCharType* sz, size_t nStart,
791 size_t n) const
792 { return find_last_not_of(STRCONV(sz, n, NULL), nStart, n); }
793
794 #undef wxOtherCharType
795 #undef STRCONV
796
797 #endif // !wxUSE_STL_BASED_WXSTRING || wxUSE_UNICODE_UTF8
798
799 // ===========================================================================
800 // other common string functions
801 // ===========================================================================
802
803 int wxString::CmpNoCase(const wxString& s) const
804 {
805 // FIXME-UTF8: use wxUniChar::ToLower/ToUpper once added
806
807 size_t idx = 0;
808 const_iterator i1 = begin();
809 const_iterator end1 = end();
810 const_iterator i2 = s.begin();
811 const_iterator end2 = s.end();
812
813 for ( ; i1 != end1 && i2 != end2; ++idx, ++i1, ++i2 )
814 {
815 wxUniChar lower1 = (wxChar)wxTolower(*i1);
816 wxUniChar lower2 = (wxChar)wxTolower(*i2);
817 if ( lower1 != lower2 )
818 return lower1 < lower2 ? -1 : 1;
819 }
820
821 size_t len1 = length();
822 size_t len2 = s.length();
823
824 if ( len1 < len2 )
825 return -1;
826 else if ( len1 > len2 )
827 return 1;
828 return 0;
829 }
830
831
832 #if wxUSE_UNICODE
833
834 #ifdef __MWERKS__
835 #ifndef __SCHAR_MAX__
836 #define __SCHAR_MAX__ 127
837 #endif
838 #endif
839
840 wxString wxString::FromAscii(const char *ascii)
841 {
842 if (!ascii)
843 return wxEmptyString;
844
845 size_t len = strlen( ascii );
846 wxString res;
847
848 if ( len )
849 {
850 wxStringBuffer buf(res, len);
851
852 wchar_t *dest = buf;
853
854 for ( ;; )
855 {
856 if ( (*dest++ = (wchar_t)(unsigned char)*ascii++) == L'\0' )
857 break;
858 }
859 }
860
861 return res;
862 }
863
864 wxString wxString::FromAscii(const char ascii)
865 {
866 // What do we do with '\0' ?
867
868 wxString res;
869 res += (wchar_t)(unsigned char) ascii;
870
871 return res;
872 }
873
874 const wxCharBuffer wxString::ToAscii() const
875 {
876 // this will allocate enough space for the terminating NUL too
877 wxCharBuffer buffer(length());
878
879
880 char *dest = buffer.data();
881
882 const wchar_t *pwc = c_str();
883 for ( ;; )
884 {
885 *dest++ = (char)(*pwc > SCHAR_MAX ? wxT('_') : *pwc);
886
887 // the output string can't have embedded NULs anyhow, so we can safely
888 // stop at first of them even if we do have any
889 if ( !*pwc++ )
890 break;
891 }
892
893 return buffer;
894 }
895
896 #endif // Unicode
897
898 // extract string of length nCount starting at nFirst
899 wxString wxString::Mid(size_t nFirst, size_t nCount) const
900 {
901 size_t nLen = length();
902
903 // default value of nCount is npos and means "till the end"
904 if ( nCount == npos )
905 {
906 nCount = nLen - nFirst;
907 }
908
909 // out-of-bounds requests return sensible things
910 if ( nFirst + nCount > nLen )
911 {
912 nCount = nLen - nFirst;
913 }
914
915 if ( nFirst > nLen )
916 {
917 // AllocCopy() will return empty string
918 return wxEmptyString;
919 }
920
921 wxString dest(*this, nFirst, nCount);
922 if ( dest.length() != nCount )
923 {
924 wxFAIL_MSG( _T("out of memory in wxString::Mid") );
925 }
926
927 return dest;
928 }
929
930 // check that the string starts with prefix and return the rest of the string
931 // in the provided pointer if it is not NULL, otherwise return false
932 bool wxString::StartsWith(const wxChar *prefix, wxString *rest) const
933 {
934 wxASSERT_MSG( prefix, _T("invalid parameter in wxString::StartsWith") );
935
936 // first check if the beginning of the string matches the prefix: note
937 // that we don't have to check that we don't run out of this string as
938 // when we reach the terminating NUL, either prefix string ends too (and
939 // then it's ok) or we break out of the loop because there is no match
940 const wxChar *p = c_str();
941 while ( *prefix )
942 {
943 if ( *prefix++ != *p++ )
944 {
945 // no match
946 return false;
947 }
948 }
949
950 if ( rest )
951 {
952 // put the rest of the string into provided pointer
953 *rest = p;
954 }
955
956 return true;
957 }
958
959
960 // check that the string ends with suffix and return the rest of it in the
961 // provided pointer if it is not NULL, otherwise return false
962 bool wxString::EndsWith(const wxChar *suffix, wxString *rest) const
963 {
964 wxASSERT_MSG( suffix, _T("invalid parameter in wxString::EndssWith") );
965
966 int start = length() - wxStrlen(suffix);
967 if ( start < 0 || wxStrcmp(wx_str() + start, suffix) != 0 )
968 return false;
969
970 if ( rest )
971 {
972 // put the rest of the string into provided pointer
973 rest->assign(*this, 0, start);
974 }
975
976 return true;
977 }
978
979
980 // extract nCount last (rightmost) characters
981 wxString wxString::Right(size_t nCount) const
982 {
983 if ( nCount > length() )
984 nCount = length();
985
986 wxString dest(*this, length() - nCount, nCount);
987 if ( dest.length() != nCount ) {
988 wxFAIL_MSG( _T("out of memory in wxString::Right") );
989 }
990 return dest;
991 }
992
993 // get all characters after the last occurence of ch
994 // (returns the whole string if ch not found)
995 wxString wxString::AfterLast(wxUniChar ch) const
996 {
997 wxString str;
998 int iPos = Find(ch, true);
999 if ( iPos == wxNOT_FOUND )
1000 str = *this;
1001 else
1002 str = wx_str() + iPos + 1;
1003
1004 return str;
1005 }
1006
1007 // extract nCount first (leftmost) characters
1008 wxString wxString::Left(size_t nCount) const
1009 {
1010 if ( nCount > length() )
1011 nCount = length();
1012
1013 wxString dest(*this, 0, nCount);
1014 if ( dest.length() != nCount ) {
1015 wxFAIL_MSG( _T("out of memory in wxString::Left") );
1016 }
1017 return dest;
1018 }
1019
1020 // get all characters before the first occurence of ch
1021 // (returns the whole string if ch not found)
1022 wxString wxString::BeforeFirst(wxUniChar ch) const
1023 {
1024 int iPos = Find(ch);
1025 if ( iPos == wxNOT_FOUND ) iPos = length();
1026 return wxString(*this, 0, iPos);
1027 }
1028
1029 /// get all characters before the last occurence of ch
1030 /// (returns empty string if ch not found)
1031 wxString wxString::BeforeLast(wxUniChar ch) const
1032 {
1033 wxString str;
1034 int iPos = Find(ch, true);
1035 if ( iPos != wxNOT_FOUND && iPos != 0 )
1036 str = wxString(c_str(), iPos);
1037
1038 return str;
1039 }
1040
1041 /// get all characters after the first occurence of ch
1042 /// (returns empty string if ch not found)
1043 wxString wxString::AfterFirst(wxUniChar ch) const
1044 {
1045 wxString str;
1046 int iPos = Find(ch);
1047 if ( iPos != wxNOT_FOUND )
1048 str = wx_str() + iPos + 1;
1049
1050 return str;
1051 }
1052
1053 // replace first (or all) occurences of some substring with another one
1054 size_t wxString::Replace(const wxString& strOld,
1055 const wxString& strNew, bool bReplaceAll)
1056 {
1057 // if we tried to replace an empty string we'd enter an infinite loop below
1058 wxCHECK_MSG( !strOld.empty(), 0,
1059 _T("wxString::Replace(): invalid parameter") );
1060
1061 size_t uiCount = 0; // count of replacements made
1062
1063 size_t uiOldLen = strOld.length();
1064 size_t uiNewLen = strNew.length();
1065
1066 size_t dwPos = 0;
1067
1068 while ( (*this)[dwPos] != wxT('\0') )
1069 {
1070 //DO NOT USE STRSTR HERE
1071 //this string can contain embedded null characters,
1072 //so strstr will function incorrectly
1073 dwPos = find(strOld, dwPos);
1074 if ( dwPos == npos )
1075 break; // exit the loop
1076 else
1077 {
1078 //replace this occurance of the old string with the new one
1079 replace(dwPos, uiOldLen, strNew, uiNewLen);
1080
1081 //move up pos past the string that was replaced
1082 dwPos += uiNewLen;
1083
1084 //increase replace count
1085 ++uiCount;
1086
1087 // stop now?
1088 if ( !bReplaceAll )
1089 break; // exit the loop
1090 }
1091 }
1092
1093 return uiCount;
1094 }
1095
1096 bool wxString::IsAscii() const
1097 {
1098 const wxChar *s = (const wxChar*) *this;
1099 while(*s){
1100 if(!isascii(*s)) return(false);
1101 s++;
1102 }
1103 return(true);
1104 }
1105
1106 bool wxString::IsWord() const
1107 {
1108 const wxChar *s = (const wxChar*) *this;
1109 while(*s){
1110 if(!wxIsalpha(*s)) return(false);
1111 s++;
1112 }
1113 return(true);
1114 }
1115
1116 bool wxString::IsNumber() const
1117 {
1118 const wxChar *s = (const wxChar*) *this;
1119 if (wxStrlen(s))
1120 if ((s[0] == wxT('-')) || (s[0] == wxT('+'))) s++;
1121 while(*s){
1122 if(!wxIsdigit(*s)) return(false);
1123 s++;
1124 }
1125 return(true);
1126 }
1127
1128 wxString wxString::Strip(stripType w) const
1129 {
1130 wxString s = *this;
1131 if ( w & leading ) s.Trim(false);
1132 if ( w & trailing ) s.Trim(true);
1133 return s;
1134 }
1135
1136 // ---------------------------------------------------------------------------
1137 // case conversion
1138 // ---------------------------------------------------------------------------
1139
1140 wxString& wxString::MakeUpper()
1141 {
1142 for ( iterator it = begin(), en = end(); it != en; ++it )
1143 *it = (wxChar)wxToupper(*it);
1144
1145 return *this;
1146 }
1147
1148 wxString& wxString::MakeLower()
1149 {
1150 for ( iterator it = begin(), en = end(); it != en; ++it )
1151 *it = (wxChar)wxTolower(*it);
1152
1153 return *this;
1154 }
1155
1156 // ---------------------------------------------------------------------------
1157 // trimming and padding
1158 // ---------------------------------------------------------------------------
1159
1160 // some compilers (VC++ 6.0 not to name them) return true for a call to
1161 // isspace('ê') in the C locale which seems to be broken to me, but we have to
1162 // live with this by checking that the character is a 7 bit one - even if this
1163 // may fail to detect some spaces (I don't know if Unicode doesn't have
1164 // space-like symbols somewhere except in the first 128 chars), it is arguably
1165 // still better than trimming away accented letters
1166 inline int wxSafeIsspace(wxChar ch) { return (ch < 127) && wxIsspace(ch); }
1167
1168 // trims spaces (in the sense of isspace) from left or right side
1169 wxString& wxString::Trim(bool bFromRight)
1170 {
1171 // first check if we're going to modify the string at all
1172 if ( !empty() &&
1173 (
1174 (bFromRight && wxSafeIsspace(GetChar(length() - 1))) ||
1175 (!bFromRight && wxSafeIsspace(GetChar(0u)))
1176 )
1177 )
1178 {
1179 if ( bFromRight )
1180 {
1181 // find last non-space character
1182 reverse_iterator psz = rbegin();
1183 while ( (psz != rend()) && wxSafeIsspace(*psz) )
1184 psz++;
1185
1186 // truncate at trailing space start
1187 erase(psz.base(), end());
1188 }
1189 else
1190 {
1191 // find first non-space character
1192 iterator psz = begin();
1193 while ( (psz != end()) && wxSafeIsspace(*psz) )
1194 psz++;
1195
1196 // fix up data and length
1197 erase(begin(), psz);
1198 }
1199 }
1200
1201 return *this;
1202 }
1203
1204 // adds nCount characters chPad to the string from either side
1205 wxString& wxString::Pad(size_t nCount, wxUniChar chPad, bool bFromRight)
1206 {
1207 wxString s(chPad, nCount);
1208
1209 if ( bFromRight )
1210 *this += s;
1211 else
1212 {
1213 s += *this;
1214 swap(s);
1215 }
1216
1217 return *this;
1218 }
1219
1220 // truncate the string
1221 wxString& wxString::Truncate(size_t uiLen)
1222 {
1223 if ( uiLen < length() )
1224 {
1225 erase(begin() + uiLen, end());
1226 }
1227 //else: nothing to do, string is already short enough
1228
1229 return *this;
1230 }
1231
1232 // ---------------------------------------------------------------------------
1233 // finding (return wxNOT_FOUND if not found and index otherwise)
1234 // ---------------------------------------------------------------------------
1235
1236 // find a character
1237 int wxString::Find(wxUniChar ch, bool bFromEnd) const
1238 {
1239 size_type idx = bFromEnd ? find_last_of(ch) : find_first_of(ch);
1240
1241 return (idx == npos) ? wxNOT_FOUND : (int)idx;
1242 }
1243
1244 // ----------------------------------------------------------------------------
1245 // conversion to numbers
1246 // ----------------------------------------------------------------------------
1247
1248 // the implementation of all the functions below is exactly the same so factor
1249 // it out
1250
1251 template <typename T, typename F>
1252 bool wxStringToIntType(const wxChar *start,
1253 T *val,
1254 int base,
1255 F func)
1256 {
1257 wxCHECK_MSG( val, false, _T("NULL output pointer") );
1258 wxASSERT_MSG( !base || (base > 1 && base <= 36), _T("invalid base") );
1259
1260 #ifndef __WXWINCE__
1261 errno = 0;
1262 #endif
1263
1264 wxChar *end;
1265 *val = (*func)(start, &end, base);
1266
1267 // return true only if scan was stopped by the terminating NUL and if the
1268 // string was not empty to start with and no under/overflow occurred
1269 return !*end && (end != start)
1270 #ifndef __WXWINCE__
1271 && (errno != ERANGE)
1272 #endif
1273 ;
1274 }
1275
1276 bool wxString::ToLong(long *val, int base) const
1277 {
1278 return wxStringToIntType((const wxChar*)c_str(), val, base, wxStrtol);
1279 }
1280
1281 bool wxString::ToULong(unsigned long *val, int base) const
1282 {
1283 return wxStringToIntType((const wxChar*)c_str(), val, base, wxStrtoul);
1284 }
1285
1286 bool wxString::ToLongLong(wxLongLong_t *val, int base) const
1287 {
1288 #ifdef wxHAS_STRTOLL
1289 return wxStringToIntType((const wxChar*)c_str(), val, base, wxStrtoll);
1290 #else
1291 // TODO: implement this ourselves
1292 wxUnusedVar(val);
1293 wxUnusedVar(base);
1294 return false;
1295 #endif // wxHAS_STRTOLL
1296 }
1297
1298 bool wxString::ToULongLong(wxULongLong_t *val, int base) const
1299 {
1300 #ifdef wxHAS_STRTOLL
1301 return wxStringToIntType((const wxChar*)c_str(), val, base, wxStrtoull);
1302 #else
1303 // TODO: implement this ourselves
1304 wxUnusedVar(val);
1305 wxUnusedVar(base);
1306 return false;
1307 #endif
1308 }
1309
1310 bool wxString::ToDouble(double *val) const
1311 {
1312 wxCHECK_MSG( val, false, _T("NULL pointer in wxString::ToDouble") );
1313
1314 #ifndef __WXWINCE__
1315 errno = 0;
1316 #endif
1317
1318 const wxChar *start = c_str();
1319 wxChar *end;
1320 *val = wxStrtod(start, &end);
1321
1322 // return true only if scan was stopped by the terminating NUL and if the
1323 // string was not empty to start with and no under/overflow occurred
1324 return !*end && (end != start)
1325 #ifndef __WXWINCE__
1326 && (errno != ERANGE)
1327 #endif
1328 ;
1329 }
1330
1331 // ---------------------------------------------------------------------------
1332 // formatted output
1333 // ---------------------------------------------------------------------------
1334
1335 /* static */
1336 #ifdef wxNEEDS_WXSTRING_PRINTF_MIXIN
1337 wxString wxStringPrintfMixinBase::DoFormat(const wxChar *format, ...)
1338 #else
1339 wxString wxString::DoFormat(const wxChar *format, ...)
1340 #endif
1341 {
1342 va_list argptr;
1343 va_start(argptr, format);
1344
1345 wxString s;
1346 s.PrintfV(format, argptr);
1347
1348 va_end(argptr);
1349
1350 return s;
1351 }
1352
1353 /* static */
1354 wxString wxString::FormatV(const wxString& format, va_list argptr)
1355 {
1356 wxString s;
1357 s.PrintfV(format, argptr);
1358 return s;
1359 }
1360
1361 #ifdef wxNEEDS_WXSTRING_PRINTF_MIXIN
1362 int wxStringPrintfMixinBase::DoPrintf(const wxChar *format, ...)
1363 #else
1364 int wxString::DoPrintf(const wxChar *format, ...)
1365 #endif
1366 {
1367 va_list argptr;
1368 va_start(argptr, format);
1369
1370 #ifdef wxNEEDS_WXSTRING_PRINTF_MIXIN
1371 // get a pointer to the wxString instance; we have to use dynamic_cast<>
1372 // because it's the only cast that works safely for downcasting when
1373 // multiple inheritance is used:
1374 wxString *str = static_cast<wxString*>(this);
1375 #else
1376 wxString *str = this;
1377 #endif
1378
1379 int iLen = str->PrintfV(format, argptr);
1380
1381 va_end(argptr);
1382
1383 return iLen;
1384 }
1385
1386 int wxString::PrintfV(const wxString& format, va_list argptr)
1387 {
1388 int size = 1024;
1389
1390 for ( ;; )
1391 {
1392 wxStringBuffer tmp(*this, size + 1);
1393 wxChar *buf = tmp;
1394
1395 if ( !buf )
1396 {
1397 // out of memory
1398 return -1;
1399 }
1400
1401 // wxVsnprintf() may modify the original arg pointer, so pass it
1402 // only a copy
1403 va_list argptrcopy;
1404 wxVaCopy(argptrcopy, argptr);
1405 int len = wxVsnprintf(buf, size, format, argptrcopy);
1406 va_end(argptrcopy);
1407
1408 // some implementations of vsnprintf() don't NUL terminate
1409 // the string if there is not enough space for it so
1410 // always do it manually
1411 buf[size] = _T('\0');
1412
1413 // vsnprintf() may return either -1 (traditional Unix behaviour) or the
1414 // total number of characters which would have been written if the
1415 // buffer were large enough (newer standards such as Unix98)
1416 if ( len < 0 )
1417 {
1418 #if wxUSE_WXVSNPRINTF
1419 // we know that our own implementation of wxVsnprintf() returns -1
1420 // only for a format error - thus there's something wrong with
1421 // the user's format string
1422 return -1;
1423 #else // assume that system version only returns error if not enough space
1424 // still not enough, as we don't know how much we need, double the
1425 // current size of the buffer
1426 size *= 2;
1427 #endif // wxUSE_WXVSNPRINTF/!wxUSE_WXVSNPRINTF
1428 }
1429 else if ( len >= size )
1430 {
1431 #if wxUSE_WXVSNPRINTF
1432 // we know that our own implementation of wxVsnprintf() returns
1433 // size+1 when there's not enough space but that's not the size
1434 // of the required buffer!
1435 size *= 2; // so we just double the current size of the buffer
1436 #else
1437 // some vsnprintf() implementations NUL-terminate the buffer and
1438 // some don't in len == size case, to be safe always add 1
1439 size = len + 1;
1440 #endif
1441 }
1442 else // ok, there was enough space
1443 {
1444 break;
1445 }
1446 }
1447
1448 // we could have overshot
1449 Shrink();
1450
1451 return length();
1452 }
1453
1454 // ----------------------------------------------------------------------------
1455 // misc other operations
1456 // ----------------------------------------------------------------------------
1457
1458 // returns true if the string matches the pattern which may contain '*' and
1459 // '?' metacharacters (as usual, '?' matches any character and '*' any number
1460 // of them)
1461 bool wxString::Matches(const wxString& mask) const
1462 {
1463 // I disable this code as it doesn't seem to be faster (in fact, it seems
1464 // to be much slower) than the old, hand-written code below and using it
1465 // here requires always linking with libregex even if the user code doesn't
1466 // use it
1467 #if 0 // wxUSE_REGEX
1468 // first translate the shell-like mask into a regex
1469 wxString pattern;
1470 pattern.reserve(wxStrlen(pszMask));
1471
1472 pattern += _T('^');
1473 while ( *pszMask )
1474 {
1475 switch ( *pszMask )
1476 {
1477 case _T('?'):
1478 pattern += _T('.');
1479 break;
1480
1481 case _T('*'):
1482 pattern += _T(".*");
1483 break;
1484
1485 case _T('^'):
1486 case _T('.'):
1487 case _T('$'):
1488 case _T('('):
1489 case _T(')'):
1490 case _T('|'):
1491 case _T('+'):
1492 case _T('\\'):
1493 // these characters are special in a RE, quote them
1494 // (however note that we don't quote '[' and ']' to allow
1495 // using them for Unix shell like matching)
1496 pattern += _T('\\');
1497 // fall through
1498
1499 default:
1500 pattern += *pszMask;
1501 }
1502
1503 pszMask++;
1504 }
1505 pattern += _T('$');
1506
1507 // and now use it
1508 return wxRegEx(pattern, wxRE_NOSUB | wxRE_EXTENDED).Matches(c_str());
1509 #else // !wxUSE_REGEX
1510 // TODO: this is, of course, awfully inefficient...
1511
1512 // FIXME-UTF8: implement using iterators, remove #if
1513 #if wxUSE_UNICODE_UTF8
1514 wxWCharBuffer maskBuf = mask.wc_str();
1515 wxWCharBuffer txtBuf = wc_str();
1516 const wxChar *pszMask = maskBuf.data();
1517 const wxChar *pszTxt = txtBuf.data();
1518 #else
1519 const wxChar *pszMask = mask.wx_str();
1520 // the char currently being checked
1521 const wxChar *pszTxt = wx_str();
1522 #endif
1523
1524 // the last location where '*' matched
1525 const wxChar *pszLastStarInText = NULL;
1526 const wxChar *pszLastStarInMask = NULL;
1527
1528 match:
1529 for ( ; *pszMask != wxT('\0'); pszMask++, pszTxt++ ) {
1530 switch ( *pszMask ) {
1531 case wxT('?'):
1532 if ( *pszTxt == wxT('\0') )
1533 return false;
1534
1535 // pszTxt and pszMask will be incremented in the loop statement
1536
1537 break;
1538
1539 case wxT('*'):
1540 {
1541 // remember where we started to be able to backtrack later
1542 pszLastStarInText = pszTxt;
1543 pszLastStarInMask = pszMask;
1544
1545 // ignore special chars immediately following this one
1546 // (should this be an error?)
1547 while ( *pszMask == wxT('*') || *pszMask == wxT('?') )
1548 pszMask++;
1549
1550 // if there is nothing more, match
1551 if ( *pszMask == wxT('\0') )
1552 return true;
1553
1554 // are there any other metacharacters in the mask?
1555 size_t uiLenMask;
1556 const wxChar *pEndMask = wxStrpbrk(pszMask, wxT("*?"));
1557
1558 if ( pEndMask != NULL ) {
1559 // we have to match the string between two metachars
1560 uiLenMask = pEndMask - pszMask;
1561 }
1562 else {
1563 // we have to match the remainder of the string
1564 uiLenMask = wxStrlen(pszMask);
1565 }
1566
1567 wxString strToMatch(pszMask, uiLenMask);
1568 const wxChar* pMatch = wxStrstr(pszTxt, strToMatch);
1569 if ( pMatch == NULL )
1570 return false;
1571
1572 // -1 to compensate "++" in the loop
1573 pszTxt = pMatch + uiLenMask - 1;
1574 pszMask += uiLenMask - 1;
1575 }
1576 break;
1577
1578 default:
1579 if ( *pszMask != *pszTxt )
1580 return false;
1581 break;
1582 }
1583 }
1584
1585 // match only if nothing left
1586 if ( *pszTxt == wxT('\0') )
1587 return true;
1588
1589 // if we failed to match, backtrack if we can
1590 if ( pszLastStarInText ) {
1591 pszTxt = pszLastStarInText + 1;
1592 pszMask = pszLastStarInMask;
1593
1594 pszLastStarInText = NULL;
1595
1596 // don't bother resetting pszLastStarInMask, it's unnecessary
1597
1598 goto match;
1599 }
1600
1601 return false;
1602 #endif // wxUSE_REGEX/!wxUSE_REGEX
1603 }
1604
1605 // Count the number of chars
1606 int wxString::Freq(wxUniChar ch) const
1607 {
1608 int count = 0;
1609 for ( const_iterator i = begin(); i != end(); ++i )
1610 {
1611 if ( *i == ch )
1612 count ++;
1613 }
1614 return count;
1615 }
1616
1617 // convert to upper case, return the copy of the string
1618 wxString wxString::Upper() const
1619 { wxString s(*this); return s.MakeUpper(); }
1620
1621 // convert to lower case, return the copy of the string
1622 wxString wxString::Lower() const { wxString s(*this); return s.MakeLower(); }