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