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