]> git.saurik.com Git - wxWidgets.git/blob - src/common/string.cpp
set icons bundle, not single icon, for frames loaded from XRC
[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 // headers, declarations, constants
15 // ===========================================================================
16
17 // For compilers that support precompilation, includes "wx.h".
18 #include "wx/wxprec.h"
19
20 #ifdef __BORLANDC__
21 #pragma hdrstop
22 #endif
23
24 #ifndef WX_PRECOMP
25 #include "wx/string.h"
26 #include "wx/wxcrtvararg.h"
27 #endif
28
29 #include <ctype.h>
30
31 #ifndef __WXWINCE__
32 #include <errno.h>
33 #endif
34
35 #include <string.h>
36 #include <stdlib.h>
37
38 #include "wx/hashmap.h"
39 #include "wx/vector.h"
40 #include "wx/xlocale.h"
41
42 // string handling functions used by wxString:
43 #if wxUSE_UNICODE_UTF8
44 #define wxStringMemcpy memcpy
45 #define wxStringMemcmp memcmp
46 #define wxStringMemchr memchr
47 #define wxStringStrlen strlen
48 #else
49 #define wxStringMemcpy wxTmemcpy
50 #define wxStringMemcmp wxTmemcmp
51 #define wxStringMemchr wxTmemchr
52 #define wxStringStrlen wxStrlen
53 #endif
54
55 // ----------------------------------------------------------------------------
56 // global variables
57 // ----------------------------------------------------------------------------
58
59 namespace wxPrivate
60 {
61
62 static UntypedBufferData s_untypedNullData(NULL, 0);
63
64 UntypedBufferData * const untypedNullDataPtr = &s_untypedNullData;
65
66 } // namespace wxPrivate
67
68 // ---------------------------------------------------------------------------
69 // static class variables definition
70 // ---------------------------------------------------------------------------
71
72 //According to STL _must_ be a -1 size_t
73 const size_t wxString::npos = (size_t) -1;
74
75 #if wxUSE_STRING_POS_CACHE
76
77 #ifdef wxHAS_COMPILER_TLS
78
79 wxTLS_TYPE(wxString::Cache) wxString::ms_cache;
80
81 #else // !wxHAS_COMPILER_TLS
82
83 struct wxStrCacheInitializer
84 {
85 wxStrCacheInitializer()
86 {
87 // calling this function triggers s_cache initialization in it, and
88 // from now on it becomes safe to call from multiple threads
89 wxString::GetCache();
90 }
91 };
92
93 /*
94 wxString::Cache& wxString::GetCache()
95 {
96 static wxTLS_TYPE(Cache) s_cache;
97
98 return wxTLS_VALUE(s_cache);
99 }
100 */
101
102 static wxStrCacheInitializer gs_stringCacheInit;
103
104 #endif // wxHAS_COMPILER_TLS/!wxHAS_COMPILER_TLS
105
106 // gdb seems to be unable to display thread-local variables correctly, at least
107 // not my 6.4.98 version under amd64, so provide this debugging helper to do it
108 #if wxDEBUG_LEVEL >= 2
109
110 struct wxStrCacheDumper
111 {
112 static void ShowAll()
113 {
114 puts("*** wxString cache dump:");
115 for ( unsigned n = 0; n < wxString::Cache::SIZE; n++ )
116 {
117 const wxString::Cache::Element&
118 c = wxString::GetCacheBegin()[n];
119
120 printf("\t%u%s\t%p: pos=(%lu, %lu), len=%ld\n",
121 n,
122 n == wxString::LastUsedCacheElement() ? " [*]" : "",
123 c.str,
124 (unsigned long)c.pos,
125 (unsigned long)c.impl,
126 (long)c.len);
127 }
128 }
129 };
130
131 void wxDumpStrCache() { wxStrCacheDumper::ShowAll(); }
132
133 #endif // wxDEBUG_LEVEL >= 2
134
135 #ifdef wxPROFILE_STRING_CACHE
136
137 wxString::CacheStats wxString::ms_cacheStats;
138
139 struct wxStrCacheStatsDumper
140 {
141 ~wxStrCacheStatsDumper()
142 {
143 const wxString::CacheStats& stats = wxString::ms_cacheStats;
144
145 if ( stats.postot )
146 {
147 puts("*** wxString cache statistics:");
148 printf("\tTotal non-trivial calls to PosToImpl(): %u\n",
149 stats.postot);
150 printf("\tHits %u (of which %u not used) or %.2f%%\n",
151 stats.poshits,
152 stats.mishits,
153 100.*float(stats.poshits - stats.mishits)/stats.postot);
154 printf("\tAverage position requested: %.2f\n",
155 float(stats.sumpos) / stats.postot);
156 printf("\tAverage offset after cached hint: %.2f\n",
157 float(stats.sumofs) / stats.postot);
158 }
159
160 if ( stats.lentot )
161 {
162 printf("\tNumber of calls to length(): %u, hits=%.2f%%\n",
163 stats.lentot, 100.*float(stats.lenhits)/stats.lentot);
164 }
165 }
166 };
167
168 static wxStrCacheStatsDumper s_showCacheStats;
169
170 #endif // wxPROFILE_STRING_CACHE
171
172 #endif // wxUSE_STRING_POS_CACHE
173
174 // ----------------------------------------------------------------------------
175 // global functions
176 // ----------------------------------------------------------------------------
177
178 #if wxUSE_STD_IOSTREAM
179
180 #include <iostream>
181
182 wxSTD ostream& operator<<(wxSTD ostream& os, const wxCStrData& str)
183 {
184 #if wxUSE_UNICODE && !wxUSE_UNICODE_UTF8
185 const wxScopedCharBuffer buf(str.AsCharBuf());
186 if ( !buf )
187 os.clear(wxSTD ios_base::failbit);
188 else
189 os << buf.data();
190
191 return os;
192 #else
193 return os << str.AsInternal();
194 #endif
195 }
196
197 wxSTD ostream& operator<<(wxSTD ostream& os, const wxString& str)
198 {
199 return os << str.c_str();
200 }
201
202 wxSTD ostream& operator<<(wxSTD ostream& os, const wxScopedCharBuffer& str)
203 {
204 return os << str.data();
205 }
206
207 #ifndef __BORLANDC__
208 wxSTD ostream& operator<<(wxSTD ostream& os, const wxScopedWCharBuffer& str)
209 {
210 return os << str.data();
211 }
212 #endif
213
214 #if wxUSE_UNICODE && defined(HAVE_WOSTREAM)
215
216 wxSTD wostream& operator<<(wxSTD wostream& wos, const wxString& str)
217 {
218 return wos << str.wc_str();
219 }
220
221 wxSTD wostream& operator<<(wxSTD wostream& wos, const wxCStrData& str)
222 {
223 return wos << str.AsWChar();
224 }
225
226 wxSTD wostream& operator<<(wxSTD wostream& wos, const wxScopedWCharBuffer& str)
227 {
228 return wos << str.data();
229 }
230
231 #endif // wxUSE_UNICODE && defined(HAVE_WOSTREAM)
232
233 #endif // wxUSE_STD_IOSTREAM
234
235 // ===========================================================================
236 // wxString class core
237 // ===========================================================================
238
239 #if wxUSE_UNICODE_UTF8
240
241 void wxString::PosLenToImpl(size_t pos, size_t len,
242 size_t *implPos, size_t *implLen) const
243 {
244 if ( pos == npos )
245 {
246 *implPos = npos;
247 }
248 else // have valid start position
249 {
250 const const_iterator b = GetIterForNthChar(pos);
251 *implPos = wxStringImpl::const_iterator(b.impl()) - m_impl.begin();
252 if ( len == npos )
253 {
254 *implLen = npos;
255 }
256 else // have valid length too
257 {
258 // we need to handle the case of length specifying a substring
259 // going beyond the end of the string, just as std::string does
260 const const_iterator e(end());
261 const_iterator i(b);
262 while ( len && i <= e )
263 {
264 ++i;
265 --len;
266 }
267
268 *implLen = i.impl() - b.impl();
269 }
270 }
271 }
272
273 #endif // wxUSE_UNICODE_UTF8
274
275 // ----------------------------------------------------------------------------
276 // wxCStrData converted strings caching
277 // ----------------------------------------------------------------------------
278
279 // FIXME-UTF8: temporarily disabled because it doesn't work with global
280 // string objects; re-enable after fixing this bug and benchmarking
281 // performance to see if using a hash is a good idea at all
282 #if 0
283
284 // For backward compatibility reasons, it must be possible to assign the value
285 // returned by wxString::c_str() to a char* or wchar_t* variable and work with
286 // it. Returning wxCharBuffer from (const char*)c_str() wouldn't do the trick,
287 // because the memory would be freed immediately, but it has to be valid as long
288 // as the string is not modified, so that code like this still works:
289 //
290 // const wxChar *s = str.c_str();
291 // while ( s ) { ... }
292
293 // FIXME-UTF8: not thread safe!
294 // FIXME-UTF8: we currently clear the cached conversion only when the string is
295 // destroyed, but we should do it when the string is modified, to
296 // keep memory usage down
297 // FIXME-UTF8: we do the conversion every time As[W]Char() is called, but if we
298 // invalidated the cache on every change, we could keep the previous
299 // conversion
300 // FIXME-UTF8: add tracing of usage of these two methods - new code is supposed
301 // to use mb_str() or wc_str() instead of (const [w]char*)c_str()
302
303 template<typename T>
304 static inline void DeleteStringFromConversionCache(T& hash, const wxString *s)
305 {
306 typename T::iterator i = hash.find(wxConstCast(s, wxString));
307 if ( i != hash.end() )
308 {
309 free(i->second);
310 hash.erase(i);
311 }
312 }
313
314 #if wxUSE_UNICODE
315 // NB: non-STL implementation doesn't compile with "const wxString*" key type,
316 // so we have to use wxString* here and const-cast when used
317 WX_DECLARE_HASH_MAP(wxString*, char*, wxPointerHash, wxPointerEqual,
318 wxStringCharConversionCache);
319 static wxStringCharConversionCache gs_stringsCharCache;
320
321 const char* wxCStrData::AsChar() const
322 {
323 // remove previously cache value, if any (see FIXMEs above):
324 DeleteStringFromConversionCache(gs_stringsCharCache, m_str);
325
326 // convert the string and keep it:
327 const char *s = gs_stringsCharCache[wxConstCast(m_str, wxString)] =
328 m_str->mb_str().release();
329
330 return s + m_offset;
331 }
332 #endif // wxUSE_UNICODE
333
334 #if !wxUSE_UNICODE_WCHAR
335 WX_DECLARE_HASH_MAP(wxString*, wchar_t*, wxPointerHash, wxPointerEqual,
336 wxStringWCharConversionCache);
337 static wxStringWCharConversionCache gs_stringsWCharCache;
338
339 const wchar_t* wxCStrData::AsWChar() const
340 {
341 // remove previously cache value, if any (see FIXMEs above):
342 DeleteStringFromConversionCache(gs_stringsWCharCache, m_str);
343
344 // convert the string and keep it:
345 const wchar_t *s = gs_stringsWCharCache[wxConstCast(m_str, wxString)] =
346 m_str->wc_str().release();
347
348 return s + m_offset;
349 }
350 #endif // !wxUSE_UNICODE_WCHAR
351
352 wxString::~wxString()
353 {
354 #if wxUSE_UNICODE
355 // FIXME-UTF8: do this only if locale is not UTF8 if wxUSE_UNICODE_UTF8
356 DeleteStringFromConversionCache(gs_stringsCharCache, this);
357 #endif
358 #if !wxUSE_UNICODE_WCHAR
359 DeleteStringFromConversionCache(gs_stringsWCharCache, this);
360 #endif
361 }
362 #endif
363
364 #if wxUSE_UNICODE && !wxUSE_UTF8_LOCALE_ONLY
365 const char* wxCStrData::AsChar() const
366 {
367 #if wxUSE_UNICODE_UTF8
368 if ( wxLocaleIsUtf8 )
369 return AsInternal();
370 #endif
371 // under non-UTF8 locales, we have to convert the internal UTF-8
372 // representation using wxConvLibc and cache the result
373
374 wxString *str = wxConstCast(m_str, wxString);
375
376 // convert the string:
377 //
378 // FIXME-UTF8: we'd like to do the conversion in the existing buffer (if we
379 // have it) but it's unfortunately not obvious to implement
380 // because we don't know how big buffer do we need for the
381 // given string length (in case of multibyte encodings, e.g.
382 // ISO-2022-JP or UTF-8 when internal representation is wchar_t)
383 //
384 // One idea would be to store more than just m_convertedToChar
385 // in wxString: then we could record the length of the string
386 // which was converted the last time and try to reuse the same
387 // buffer if the current length is not greater than it (this
388 // could still fail because string could have been modified in
389 // place but it would work most of the time, so we'd do it and
390 // only allocate the new buffer if in-place conversion returned
391 // an error). We could also store a bit saying if the string
392 // was modified since the last conversion (and update it in all
393 // operation modifying the string, of course) to avoid unneeded
394 // consequential conversions. But both of these ideas require
395 // adding more fields to wxString and require profiling results
396 // to be sure that we really gain enough from them to justify
397 // doing it.
398 wxScopedCharBuffer buf(str->mb_str());
399
400 // if it failed, return empty string and not NULL to avoid crashes in code
401 // written with either wxWidgets 2 wxString or std::string behaviour in
402 // mind: neither of them ever returns NULL and so we shouldn't neither
403 if ( !buf )
404 return "";
405
406 if ( str->m_convertedToChar &&
407 strlen(buf) == strlen(str->m_convertedToChar) )
408 {
409 // keep the same buffer for as long as possible, so that several calls
410 // to c_str() in a row still work:
411 strcpy(str->m_convertedToChar, buf);
412 }
413 else
414 {
415 str->m_convertedToChar = buf.release();
416 }
417
418 // and keep it:
419 return str->m_convertedToChar + m_offset;
420 }
421 #endif // wxUSE_UNICODE && !wxUSE_UTF8_LOCALE_ONLY
422
423 #if !wxUSE_UNICODE_WCHAR
424 const wchar_t* wxCStrData::AsWChar() const
425 {
426 wxString *str = wxConstCast(m_str, wxString);
427
428 // convert the string:
429 wxScopedWCharBuffer buf(str->wc_str());
430
431 // notice that here, unlike above in AsChar(), conversion can't fail as our
432 // internal UTF-8 is always well-formed -- or the string was corrupted and
433 // all bets are off anyhow
434
435 // FIXME-UTF8: do the conversion in-place in the existing buffer
436 if ( str->m_convertedToWChar &&
437 wxWcslen(buf) == wxWcslen(str->m_convertedToWChar) )
438 {
439 // keep the same buffer for as long as possible, so that several calls
440 // to c_str() in a row still work:
441 memcpy(str->m_convertedToWChar, buf, sizeof(wchar_t) * wxWcslen(buf));
442 }
443 else
444 {
445 str->m_convertedToWChar = buf.release();
446 }
447
448 // and keep it:
449 return str->m_convertedToWChar + m_offset;
450 }
451 #endif // !wxUSE_UNICODE_WCHAR
452
453 // ===========================================================================
454 // wxString class core
455 // ===========================================================================
456
457 // ---------------------------------------------------------------------------
458 // construction and conversion
459 // ---------------------------------------------------------------------------
460
461 #if wxUSE_UNICODE_WCHAR
462 /* static */
463 wxString::SubstrBufFromMB wxString::ConvertStr(const char *psz, size_t nLength,
464 const wxMBConv& conv)
465 {
466 // anything to do?
467 if ( !psz || nLength == 0 )
468 return SubstrBufFromMB(wxWCharBuffer(L""), 0);
469
470 if ( nLength == npos )
471 nLength = wxNO_LEN;
472
473 size_t wcLen;
474 wxScopedWCharBuffer wcBuf(conv.cMB2WC(psz, nLength, &wcLen));
475 if ( !wcLen )
476 return SubstrBufFromMB(wxWCharBuffer(L""), 0);
477 else
478 return SubstrBufFromMB(wcBuf, wcLen);
479 }
480 #endif // wxUSE_UNICODE_WCHAR
481
482 #if wxUSE_UNICODE_UTF8
483 /* static */
484 wxString::SubstrBufFromMB wxString::ConvertStr(const char *psz, size_t nLength,
485 const wxMBConv& conv)
486 {
487 // anything to do?
488 if ( !psz || nLength == 0 )
489 return SubstrBufFromMB(wxCharBuffer(""), 0);
490
491 // if psz is already in UTF-8, we don't have to do the roundtrip to
492 // wchar_t* and back:
493 if ( conv.IsUTF8() )
494 {
495 // we need to validate the input because UTF8 iterators assume valid
496 // UTF-8 sequence and psz may be invalid:
497 if ( wxStringOperations::IsValidUtf8String(psz, nLength) )
498 {
499 // we must pass the real string length to SubstrBufFromMB ctor
500 if ( nLength == npos )
501 nLength = psz ? strlen(psz) : 0;
502 return SubstrBufFromMB(wxCharBuffer::CreateNonOwned(psz, nLength),
503 nLength);
504 }
505 // else: do the roundtrip through wchar_t*
506 }
507
508 if ( nLength == npos )
509 nLength = wxNO_LEN;
510
511 // first convert to wide string:
512 size_t wcLen;
513 wxScopedWCharBuffer wcBuf(conv.cMB2WC(psz, nLength, &wcLen));
514 if ( !wcLen )
515 return SubstrBufFromMB(wxCharBuffer(""), 0);
516
517 // and then to UTF-8:
518 SubstrBufFromMB buf(ConvertStr(wcBuf, wcLen, wxMBConvStrictUTF8()));
519 // widechar -> UTF-8 conversion isn't supposed to ever fail:
520 wxASSERT_MSG( buf.data, _T("conversion to UTF-8 failed") );
521
522 return buf;
523 }
524 #endif // wxUSE_UNICODE_UTF8
525
526 #if wxUSE_UNICODE_UTF8 || !wxUSE_UNICODE
527 /* static */
528 wxString::SubstrBufFromWC wxString::ConvertStr(const wchar_t *pwz, size_t nLength,
529 const wxMBConv& conv)
530 {
531 // anything to do?
532 if ( !pwz || nLength == 0 )
533 return SubstrBufFromWC(wxCharBuffer(""), 0);
534
535 if ( nLength == npos )
536 nLength = wxNO_LEN;
537
538 size_t mbLen;
539 wxScopedCharBuffer mbBuf(conv.cWC2MB(pwz, nLength, &mbLen));
540 if ( !mbLen )
541 return SubstrBufFromWC(wxCharBuffer(""), 0);
542 else
543 return SubstrBufFromWC(mbBuf, mbLen);
544 }
545 #endif // wxUSE_UNICODE_UTF8 || !wxUSE_UNICODE
546
547
548 #if wxUSE_UNICODE_WCHAR
549
550 //Convert wxString in Unicode mode to a multi-byte string
551 const wxScopedCharBuffer wxString::mb_str(const wxMBConv& conv) const
552 {
553 return conv.cWC2MB(wx_str(), length() + 1 /* size, not length */, NULL);
554 }
555
556 #elif wxUSE_UNICODE_UTF8
557
558 const wxScopedWCharBuffer wxString::wc_str() const
559 {
560 return wxMBConvStrictUTF8().cMB2WC
561 (
562 m_impl.c_str(),
563 m_impl.length() + 1, // size, not length
564 NULL
565 );
566 }
567
568 const wxScopedCharBuffer wxString::mb_str(const wxMBConv& conv) const
569 {
570 if ( conv.IsUTF8() )
571 return wxScopedCharBuffer::CreateNonOwned(m_impl.c_str(), m_impl.length());
572
573 // FIXME-UTF8: use wc_str() here once we have buffers with length
574
575 size_t wcLen;
576 wxScopedWCharBuffer wcBuf
577 (
578 wxMBConvStrictUTF8().cMB2WC
579 (
580 m_impl.c_str(),
581 m_impl.length() + 1, // size
582 &wcLen
583 )
584 );
585 if ( !wcLen )
586 return wxCharBuffer("");
587
588 return conv.cWC2MB(wcBuf, wcLen+1, NULL);
589 }
590
591 #else // ANSI
592
593 //Converts this string to a wide character string if unicode
594 //mode is not enabled and wxUSE_WCHAR_T is enabled
595 const wxScopedWCharBuffer wxString::wc_str(const wxMBConv& conv) const
596 {
597 return conv.cMB2WC(wx_str(), length() + 1 /* size, not length */, NULL);
598 }
599
600 #endif // Unicode/ANSI
601
602 // shrink to minimal size (releasing extra memory)
603 bool wxString::Shrink()
604 {
605 wxString tmp(begin(), end());
606 swap(tmp);
607 return tmp.length() == length();
608 }
609
610 // deprecated compatibility code:
611 #if WXWIN_COMPATIBILITY_2_8 && !wxUSE_STL_BASED_WXSTRING && !wxUSE_UNICODE_UTF8
612 wxStringCharType *wxString::GetWriteBuf(size_t nLen)
613 {
614 return DoGetWriteBuf(nLen);
615 }
616
617 void wxString::UngetWriteBuf()
618 {
619 DoUngetWriteBuf();
620 }
621
622 void wxString::UngetWriteBuf(size_t nLen)
623 {
624 DoUngetWriteBuf(nLen);
625 }
626 #endif // WXWIN_COMPATIBILITY_2_8 && !wxUSE_STL_BASED_WXSTRING && !wxUSE_UNICODE_UTF8
627
628
629 // ---------------------------------------------------------------------------
630 // data access
631 // ---------------------------------------------------------------------------
632
633 // all functions are inline in string.h
634
635 // ---------------------------------------------------------------------------
636 // concatenation operators
637 // ---------------------------------------------------------------------------
638
639 /*
640 * concatenation functions come in 5 flavours:
641 * string + string
642 * char + string and string + char
643 * C str + string and string + C str
644 */
645
646 wxString operator+(const wxString& str1, const wxString& str2)
647 {
648 #if !wxUSE_STL_BASED_WXSTRING
649 wxASSERT( str1.IsValid() );
650 wxASSERT( str2.IsValid() );
651 #endif
652
653 wxString s = str1;
654 s += str2;
655
656 return s;
657 }
658
659 wxString operator+(const wxString& str, wxUniChar ch)
660 {
661 #if !wxUSE_STL_BASED_WXSTRING
662 wxASSERT( str.IsValid() );
663 #endif
664
665 wxString s = str;
666 s += ch;
667
668 return s;
669 }
670
671 wxString operator+(wxUniChar ch, const wxString& str)
672 {
673 #if !wxUSE_STL_BASED_WXSTRING
674 wxASSERT( str.IsValid() );
675 #endif
676
677 wxString s = ch;
678 s += str;
679
680 return s;
681 }
682
683 wxString operator+(const wxString& str, const char *psz)
684 {
685 #if !wxUSE_STL_BASED_WXSTRING
686 wxASSERT( str.IsValid() );
687 #endif
688
689 wxString s;
690 if ( !s.Alloc(strlen(psz) + str.length()) ) {
691 wxFAIL_MSG( _T("out of memory in wxString::operator+") );
692 }
693 s += str;
694 s += psz;
695
696 return s;
697 }
698
699 wxString operator+(const wxString& str, const wchar_t *pwz)
700 {
701 #if !wxUSE_STL_BASED_WXSTRING
702 wxASSERT( str.IsValid() );
703 #endif
704
705 wxString s;
706 if ( !s.Alloc(wxWcslen(pwz) + str.length()) ) {
707 wxFAIL_MSG( _T("out of memory in wxString::operator+") );
708 }
709 s += str;
710 s += pwz;
711
712 return s;
713 }
714
715 wxString operator+(const char *psz, const wxString& str)
716 {
717 #if !wxUSE_STL_BASED_WXSTRING
718 wxASSERT( str.IsValid() );
719 #endif
720
721 wxString s;
722 if ( !s.Alloc(strlen(psz) + str.length()) ) {
723 wxFAIL_MSG( _T("out of memory in wxString::operator+") );
724 }
725 s = psz;
726 s += str;
727
728 return s;
729 }
730
731 wxString operator+(const wchar_t *pwz, const wxString& str)
732 {
733 #if !wxUSE_STL_BASED_WXSTRING
734 wxASSERT( str.IsValid() );
735 #endif
736
737 wxString s;
738 if ( !s.Alloc(wxWcslen(pwz) + str.length()) ) {
739 wxFAIL_MSG( _T("out of memory in wxString::operator+") );
740 }
741 s = pwz;
742 s += str;
743
744 return s;
745 }
746
747 // ---------------------------------------------------------------------------
748 // string comparison
749 // ---------------------------------------------------------------------------
750
751 bool wxString::IsSameAs(wxUniChar c, bool compareWithCase) const
752 {
753 return (length() == 1) && (compareWithCase ? GetChar(0u) == c
754 : wxToupper(GetChar(0u)) == wxToupper(c));
755 }
756
757 #ifdef HAVE_STD_STRING_COMPARE
758
759 // NB: Comparison code (both if HAVE_STD_STRING_COMPARE and if not) works with
760 // UTF-8 encoded strings too, thanks to UTF-8's design which allows us to
761 // sort strings in characters code point order by sorting the byte sequence
762 // in byte values order (i.e. what strcmp() and memcmp() do).
763
764 int wxString::compare(const wxString& str) const
765 {
766 return m_impl.compare(str.m_impl);
767 }
768
769 int wxString::compare(size_t nStart, size_t nLen,
770 const wxString& str) const
771 {
772 size_t pos, len;
773 PosLenToImpl(nStart, nLen, &pos, &len);
774 return m_impl.compare(pos, len, str.m_impl);
775 }
776
777 int wxString::compare(size_t nStart, size_t nLen,
778 const wxString& str,
779 size_t nStart2, size_t nLen2) const
780 {
781 size_t pos, len;
782 PosLenToImpl(nStart, nLen, &pos, &len);
783
784 size_t pos2, len2;
785 str.PosLenToImpl(nStart2, nLen2, &pos2, &len2);
786
787 return m_impl.compare(pos, len, str.m_impl, pos2, len2);
788 }
789
790 int wxString::compare(const char* sz) const
791 {
792 return m_impl.compare(ImplStr(sz));
793 }
794
795 int wxString::compare(const wchar_t* sz) const
796 {
797 return m_impl.compare(ImplStr(sz));
798 }
799
800 int wxString::compare(size_t nStart, size_t nLen,
801 const char* sz, size_t nCount) const
802 {
803 size_t pos, len;
804 PosLenToImpl(nStart, nLen, &pos, &len);
805
806 SubstrBufFromMB str(ImplStr(sz, nCount));
807
808 return m_impl.compare(pos, len, str.data, str.len);
809 }
810
811 int wxString::compare(size_t nStart, size_t nLen,
812 const wchar_t* sz, size_t nCount) const
813 {
814 size_t pos, len;
815 PosLenToImpl(nStart, nLen, &pos, &len);
816
817 SubstrBufFromWC str(ImplStr(sz, nCount));
818
819 return m_impl.compare(pos, len, str.data, str.len);
820 }
821
822 #else // !HAVE_STD_STRING_COMPARE
823
824 static inline int wxDoCmp(const wxStringCharType* s1, size_t l1,
825 const wxStringCharType* s2, size_t l2)
826 {
827 if( l1 == l2 )
828 return wxStringMemcmp(s1, s2, l1);
829 else if( l1 < l2 )
830 {
831 int ret = wxStringMemcmp(s1, s2, l1);
832 return ret == 0 ? -1 : ret;
833 }
834 else
835 {
836 int ret = wxStringMemcmp(s1, s2, l2);
837 return ret == 0 ? +1 : ret;
838 }
839 }
840
841 int wxString::compare(const wxString& str) const
842 {
843 return ::wxDoCmp(m_impl.data(), m_impl.length(),
844 str.m_impl.data(), str.m_impl.length());
845 }
846
847 int wxString::compare(size_t nStart, size_t nLen,
848 const wxString& str) const
849 {
850 wxASSERT(nStart <= length());
851 size_type strLen = length() - nStart;
852 nLen = strLen < nLen ? strLen : nLen;
853
854 size_t pos, len;
855 PosLenToImpl(nStart, nLen, &pos, &len);
856
857 return ::wxDoCmp(m_impl.data() + pos, len,
858 str.m_impl.data(), str.m_impl.length());
859 }
860
861 int wxString::compare(size_t nStart, size_t nLen,
862 const wxString& str,
863 size_t nStart2, size_t nLen2) const
864 {
865 wxASSERT(nStart <= length());
866 wxASSERT(nStart2 <= str.length());
867 size_type strLen = length() - nStart,
868 strLen2 = str.length() - nStart2;
869 nLen = strLen < nLen ? strLen : nLen;
870 nLen2 = strLen2 < nLen2 ? strLen2 : nLen2;
871
872 size_t pos, len;
873 PosLenToImpl(nStart, nLen, &pos, &len);
874 size_t pos2, len2;
875 str.PosLenToImpl(nStart2, nLen2, &pos2, &len2);
876
877 return ::wxDoCmp(m_impl.data() + pos, len,
878 str.m_impl.data() + pos2, len2);
879 }
880
881 int wxString::compare(const char* sz) const
882 {
883 SubstrBufFromMB str(ImplStr(sz, npos));
884 if ( str.len == npos )
885 str.len = wxStringStrlen(str.data);
886 return ::wxDoCmp(m_impl.data(), m_impl.length(), str.data, str.len);
887 }
888
889 int wxString::compare(const wchar_t* sz) const
890 {
891 SubstrBufFromWC str(ImplStr(sz, npos));
892 if ( str.len == npos )
893 str.len = wxStringStrlen(str.data);
894 return ::wxDoCmp(m_impl.data(), m_impl.length(), str.data, str.len);
895 }
896
897 int wxString::compare(size_t nStart, size_t nLen,
898 const char* sz, size_t nCount) const
899 {
900 wxASSERT(nStart <= length());
901 size_type strLen = length() - nStart;
902 nLen = strLen < nLen ? strLen : nLen;
903
904 size_t pos, len;
905 PosLenToImpl(nStart, nLen, &pos, &len);
906
907 SubstrBufFromMB str(ImplStr(sz, nCount));
908 if ( str.len == npos )
909 str.len = wxStringStrlen(str.data);
910
911 return ::wxDoCmp(m_impl.data() + pos, len, str.data, str.len);
912 }
913
914 int wxString::compare(size_t nStart, size_t nLen,
915 const wchar_t* sz, size_t nCount) const
916 {
917 wxASSERT(nStart <= length());
918 size_type strLen = length() - nStart;
919 nLen = strLen < nLen ? strLen : nLen;
920
921 size_t pos, len;
922 PosLenToImpl(nStart, nLen, &pos, &len);
923
924 SubstrBufFromWC str(ImplStr(sz, nCount));
925 if ( str.len == npos )
926 str.len = wxStringStrlen(str.data);
927
928 return ::wxDoCmp(m_impl.data() + pos, len, str.data, str.len);
929 }
930
931 #endif // HAVE_STD_STRING_COMPARE/!HAVE_STD_STRING_COMPARE
932
933
934 // ---------------------------------------------------------------------------
935 // find_{first,last}_[not]_of functions
936 // ---------------------------------------------------------------------------
937
938 #if !wxUSE_STL_BASED_WXSTRING || wxUSE_UNICODE_UTF8
939
940 // NB: All these functions are implemented with the argument being wxChar*,
941 // i.e. widechar string in any Unicode build, even though native string
942 // representation is char* in the UTF-8 build. This is because we couldn't
943 // use memchr() to determine if a character is in a set encoded as UTF-8.
944
945 size_t wxString::find_first_of(const wxChar* sz, size_t nStart) const
946 {
947 return find_first_of(sz, nStart, wxStrlen(sz));
948 }
949
950 size_t wxString::find_first_not_of(const wxChar* sz, size_t nStart) const
951 {
952 return find_first_not_of(sz, nStart, wxStrlen(sz));
953 }
954
955 size_t wxString::find_first_of(const wxChar* sz, size_t nStart, size_t n) const
956 {
957 wxASSERT_MSG( nStart <= length(), _T("invalid index") );
958
959 size_t idx = nStart;
960 for ( const_iterator i = begin() + nStart; i != end(); ++idx, ++i )
961 {
962 if ( wxTmemchr(sz, *i, n) )
963 return idx;
964 }
965
966 return npos;
967 }
968
969 size_t wxString::find_first_not_of(const wxChar* sz, size_t nStart, size_t n) const
970 {
971 wxASSERT_MSG( nStart <= length(), _T("invalid index") );
972
973 size_t idx = nStart;
974 for ( const_iterator i = begin() + nStart; i != end(); ++idx, ++i )
975 {
976 if ( !wxTmemchr(sz, *i, n) )
977 return idx;
978 }
979
980 return npos;
981 }
982
983
984 size_t wxString::find_last_of(const wxChar* sz, size_t nStart) const
985 {
986 return find_last_of(sz, nStart, wxStrlen(sz));
987 }
988
989 size_t wxString::find_last_not_of(const wxChar* sz, size_t nStart) const
990 {
991 return find_last_not_of(sz, nStart, wxStrlen(sz));
992 }
993
994 size_t wxString::find_last_of(const wxChar* sz, size_t nStart, size_t n) const
995 {
996 size_t len = length();
997
998 if ( nStart == npos )
999 {
1000 nStart = len - 1;
1001 }
1002 else
1003 {
1004 wxASSERT_MSG( nStart <= len, _T("invalid index") );
1005 }
1006
1007 size_t idx = nStart;
1008 for ( const_reverse_iterator i = rbegin() + (len - nStart - 1);
1009 i != rend(); --idx, ++i )
1010 {
1011 if ( wxTmemchr(sz, *i, n) )
1012 return idx;
1013 }
1014
1015 return npos;
1016 }
1017
1018 size_t wxString::find_last_not_of(const wxChar* sz, size_t nStart, size_t n) const
1019 {
1020 size_t len = length();
1021
1022 if ( nStart == npos )
1023 {
1024 nStart = len - 1;
1025 }
1026 else
1027 {
1028 wxASSERT_MSG( nStart <= len, _T("invalid index") );
1029 }
1030
1031 size_t idx = nStart;
1032 for ( const_reverse_iterator i = rbegin() + (len - nStart - 1);
1033 i != rend(); --idx, ++i )
1034 {
1035 if ( !wxTmemchr(sz, *i, n) )
1036 return idx;
1037 }
1038
1039 return npos;
1040 }
1041
1042 size_t wxString::find_first_not_of(wxUniChar ch, size_t nStart) const
1043 {
1044 wxASSERT_MSG( nStart <= length(), _T("invalid index") );
1045
1046 size_t idx = nStart;
1047 for ( const_iterator i = begin() + nStart; i != end(); ++idx, ++i )
1048 {
1049 if ( *i != ch )
1050 return idx;
1051 }
1052
1053 return npos;
1054 }
1055
1056 size_t wxString::find_last_not_of(wxUniChar ch, size_t nStart) const
1057 {
1058 size_t len = length();
1059
1060 if ( nStart == npos )
1061 {
1062 nStart = len - 1;
1063 }
1064 else
1065 {
1066 wxASSERT_MSG( nStart <= len, _T("invalid index") );
1067 }
1068
1069 size_t idx = nStart;
1070 for ( const_reverse_iterator i = rbegin() + (len - nStart - 1);
1071 i != rend(); --idx, ++i )
1072 {
1073 if ( *i != ch )
1074 return idx;
1075 }
1076
1077 return npos;
1078 }
1079
1080 // the functions above were implemented for wchar_t* arguments in Unicode
1081 // build and char* in ANSI build; below are implementations for the other
1082 // version:
1083 #if wxUSE_UNICODE
1084 #define wxOtherCharType char
1085 #define STRCONV (const wxChar*)wxConvLibc.cMB2WC
1086 #else
1087 #define wxOtherCharType wchar_t
1088 #define STRCONV (const wxChar*)wxConvLibc.cWC2MB
1089 #endif
1090
1091 size_t wxString::find_first_of(const wxOtherCharType* sz, size_t nStart) const
1092 { return find_first_of(STRCONV(sz), nStart); }
1093
1094 size_t wxString::find_first_of(const wxOtherCharType* sz, size_t nStart,
1095 size_t n) const
1096 { return find_first_of(STRCONV(sz, n, NULL), nStart, n); }
1097 size_t wxString::find_last_of(const wxOtherCharType* sz, size_t nStart) const
1098 { return find_last_of(STRCONV(sz), nStart); }
1099 size_t wxString::find_last_of(const wxOtherCharType* sz, size_t nStart,
1100 size_t n) const
1101 { return find_last_of(STRCONV(sz, n, NULL), nStart, n); }
1102 size_t wxString::find_first_not_of(const wxOtherCharType* sz, size_t nStart) const
1103 { return find_first_not_of(STRCONV(sz), nStart); }
1104 size_t wxString::find_first_not_of(const wxOtherCharType* sz, size_t nStart,
1105 size_t n) const
1106 { return find_first_not_of(STRCONV(sz, n, NULL), nStart, n); }
1107 size_t wxString::find_last_not_of(const wxOtherCharType* sz, size_t nStart) const
1108 { return find_last_not_of(STRCONV(sz), nStart); }
1109 size_t wxString::find_last_not_of(const wxOtherCharType* sz, size_t nStart,
1110 size_t n) const
1111 { return find_last_not_of(STRCONV(sz, n, NULL), nStart, n); }
1112
1113 #undef wxOtherCharType
1114 #undef STRCONV
1115
1116 #endif // !wxUSE_STL_BASED_WXSTRING || wxUSE_UNICODE_UTF8
1117
1118 // ===========================================================================
1119 // other common string functions
1120 // ===========================================================================
1121
1122 int wxString::CmpNoCase(const wxString& s) const
1123 {
1124 #if wxUSE_UNICODE_UTF8
1125 // FIXME-UTF8: use wxUniChar::ToLower/ToUpper once added
1126
1127 const_iterator i1 = begin();
1128 const_iterator end1 = end();
1129 const_iterator i2 = s.begin();
1130 const_iterator end2 = s.end();
1131
1132 for ( ; i1 != end1 && i2 != end2; ++i1, ++i2 )
1133 {
1134 wxUniChar lower1 = (wxChar)wxTolower(*i1);
1135 wxUniChar lower2 = (wxChar)wxTolower(*i2);
1136 if ( lower1 != lower2 )
1137 return lower1 < lower2 ? -1 : 1;
1138 }
1139
1140 size_t len1 = length();
1141 size_t len2 = s.length();
1142
1143 if ( len1 < len2 )
1144 return -1;
1145 else if ( len1 > len2 )
1146 return 1;
1147 return 0;
1148 #else // wxUSE_UNICODE_WCHAR or ANSI
1149 return wxStricmp(m_impl.c_str(), s.m_impl.c_str());
1150 #endif
1151 }
1152
1153
1154 #if wxUSE_UNICODE
1155
1156 #ifdef __MWERKS__
1157 #ifndef __SCHAR_MAX__
1158 #define __SCHAR_MAX__ 127
1159 #endif
1160 #endif
1161
1162 wxString wxString::FromAscii(const char *ascii, size_t len)
1163 {
1164 if (!ascii || len == 0)
1165 return wxEmptyString;
1166
1167 wxString res;
1168
1169 {
1170 wxStringInternalBuffer buf(res, len);
1171 wxStringCharType *dest = buf;
1172
1173 for ( ; len > 0; --len )
1174 {
1175 unsigned char c = (unsigned char)*ascii++;
1176 wxASSERT_MSG( c < 0x80,
1177 _T("Non-ASCII value passed to FromAscii().") );
1178
1179 *dest++ = (wchar_t)c;
1180 }
1181 }
1182
1183 return res;
1184 }
1185
1186 wxString wxString::FromAscii(const char *ascii)
1187 {
1188 return FromAscii(ascii, wxStrlen(ascii));
1189 }
1190
1191 wxString wxString::FromAscii(char ascii)
1192 {
1193 // What do we do with '\0' ?
1194
1195 unsigned char c = (unsigned char)ascii;
1196
1197 wxASSERT_MSG( c < 0x80, _T("Non-ASCII value passed to FromAscii().") );
1198
1199 // NB: the cast to wchar_t causes interpretation of 'ascii' as Latin1 value
1200 return wxString(wxUniChar((wchar_t)c));
1201 }
1202
1203 const wxScopedCharBuffer wxString::ToAscii() const
1204 {
1205 // this will allocate enough space for the terminating NUL too
1206 wxCharBuffer buffer(length());
1207 char *dest = buffer.data();
1208
1209 for ( const_iterator i = begin(); i != end(); ++i )
1210 {
1211 wxUniChar c(*i);
1212 // FIXME-UTF8: unify substituted char ('_') with wxUniChar ('?')
1213 *dest++ = c.IsAscii() ? (char)c : '_';
1214
1215 // the output string can't have embedded NULs anyhow, so we can safely
1216 // stop at first of them even if we do have any
1217 if ( !c )
1218 break;
1219 }
1220
1221 return buffer;
1222 }
1223
1224 #endif // wxUSE_UNICODE
1225
1226 // extract string of length nCount starting at nFirst
1227 wxString wxString::Mid(size_t nFirst, size_t nCount) const
1228 {
1229 size_t nLen = length();
1230
1231 // default value of nCount is npos and means "till the end"
1232 if ( nCount == npos )
1233 {
1234 nCount = nLen - nFirst;
1235 }
1236
1237 // out-of-bounds requests return sensible things
1238 if ( nFirst + nCount > nLen )
1239 {
1240 nCount = nLen - nFirst;
1241 }
1242
1243 if ( nFirst > nLen )
1244 {
1245 // AllocCopy() will return empty string
1246 return wxEmptyString;
1247 }
1248
1249 wxString dest(*this, nFirst, nCount);
1250 if ( dest.length() != nCount )
1251 {
1252 wxFAIL_MSG( _T("out of memory in wxString::Mid") );
1253 }
1254
1255 return dest;
1256 }
1257
1258 // check that the string starts with prefix and return the rest of the string
1259 // in the provided pointer if it is not NULL, otherwise return false
1260 bool wxString::StartsWith(const wxString& prefix, wxString *rest) const
1261 {
1262 if ( compare(0, prefix.length(), prefix) != 0 )
1263 return false;
1264
1265 if ( rest )
1266 {
1267 // put the rest of the string into provided pointer
1268 rest->assign(*this, prefix.length(), npos);
1269 }
1270
1271 return true;
1272 }
1273
1274
1275 // check that the string ends with suffix and return the rest of it in the
1276 // provided pointer if it is not NULL, otherwise return false
1277 bool wxString::EndsWith(const wxString& suffix, wxString *rest) const
1278 {
1279 int start = length() - suffix.length();
1280
1281 if ( start < 0 || compare(start, npos, suffix) != 0 )
1282 return false;
1283
1284 if ( rest )
1285 {
1286 // put the rest of the string into provided pointer
1287 rest->assign(*this, 0, start);
1288 }
1289
1290 return true;
1291 }
1292
1293
1294 // extract nCount last (rightmost) characters
1295 wxString wxString::Right(size_t nCount) const
1296 {
1297 if ( nCount > length() )
1298 nCount = length();
1299
1300 wxString dest(*this, length() - nCount, nCount);
1301 if ( dest.length() != nCount ) {
1302 wxFAIL_MSG( _T("out of memory in wxString::Right") );
1303 }
1304 return dest;
1305 }
1306
1307 // get all characters after the last occurrence of ch
1308 // (returns the whole string if ch not found)
1309 wxString wxString::AfterLast(wxUniChar ch) const
1310 {
1311 wxString str;
1312 int iPos = Find(ch, true);
1313 if ( iPos == wxNOT_FOUND )
1314 str = *this;
1315 else
1316 str.assign(*this, iPos + 1, npos);
1317
1318 return str;
1319 }
1320
1321 // extract nCount first (leftmost) characters
1322 wxString wxString::Left(size_t nCount) const
1323 {
1324 if ( nCount > length() )
1325 nCount = length();
1326
1327 wxString dest(*this, 0, nCount);
1328 if ( dest.length() != nCount ) {
1329 wxFAIL_MSG( _T("out of memory in wxString::Left") );
1330 }
1331 return dest;
1332 }
1333
1334 // get all characters before the first occurrence of ch
1335 // (returns the whole string if ch not found)
1336 wxString wxString::BeforeFirst(wxUniChar ch) const
1337 {
1338 int iPos = Find(ch);
1339 if ( iPos == wxNOT_FOUND )
1340 iPos = length();
1341 return wxString(*this, 0, iPos);
1342 }
1343
1344 /// get all characters before the last occurrence of ch
1345 /// (returns empty string if ch not found)
1346 wxString wxString::BeforeLast(wxUniChar ch) const
1347 {
1348 wxString str;
1349 int iPos = Find(ch, true);
1350 if ( iPos != wxNOT_FOUND && iPos != 0 )
1351 str = wxString(c_str(), iPos);
1352
1353 return str;
1354 }
1355
1356 /// get all characters after the first occurrence of ch
1357 /// (returns empty string if ch not found)
1358 wxString wxString::AfterFirst(wxUniChar ch) const
1359 {
1360 wxString str;
1361 int iPos = Find(ch);
1362 if ( iPos != wxNOT_FOUND )
1363 str.assign(*this, iPos + 1, npos);
1364
1365 return str;
1366 }
1367
1368 // replace first (or all) occurrences of some substring with another one
1369 size_t wxString::Replace(const wxString& strOld,
1370 const wxString& strNew, bool bReplaceAll)
1371 {
1372 // if we tried to replace an empty string we'd enter an infinite loop below
1373 wxCHECK_MSG( !strOld.empty(), 0,
1374 _T("wxString::Replace(): invalid parameter") );
1375
1376 wxSTRING_INVALIDATE_CACHE();
1377
1378 size_t uiCount = 0; // count of replacements made
1379
1380 // optimize the special common case: replacement of one character by
1381 // another one (in UTF-8 case we can only do this for ASCII characters)
1382 //
1383 // benchmarks show that this special version is around 3 times faster
1384 // (depending on the proportion of matching characters and UTF-8/wchar_t
1385 // build)
1386 if ( strOld.m_impl.length() == 1 && strNew.m_impl.length() == 1 )
1387 {
1388 const wxStringCharType chOld = strOld.m_impl[0],
1389 chNew = strNew.m_impl[0];
1390
1391 // this loop is the simplified version of the one below
1392 for ( size_t pos = 0; ; )
1393 {
1394 pos = m_impl.find(chOld, pos);
1395 if ( pos == npos )
1396 break;
1397
1398 m_impl[pos++] = chNew;
1399
1400 uiCount++;
1401
1402 if ( !bReplaceAll )
1403 break;
1404 }
1405 }
1406 else if ( !bReplaceAll)
1407 {
1408 size_t pos = m_impl.find(strOld, 0);
1409 if ( pos != npos )
1410 {
1411 m_impl.replace(pos, strOld.m_impl.length(), strNew.m_impl);
1412 uiCount = 1;
1413 }
1414 }
1415 else // replace all occurrences
1416 {
1417 const size_t uiOldLen = strOld.m_impl.length();
1418 const size_t uiNewLen = strNew.m_impl.length();
1419
1420 // first scan the string to find all positions at which the replacement
1421 // should be made
1422 wxVector<size_t> replacePositions;
1423
1424 size_t pos;
1425 for ( pos = m_impl.find(strOld.m_impl, 0);
1426 pos != npos;
1427 pos = m_impl.find(strOld.m_impl, pos + uiOldLen))
1428 {
1429 replacePositions.push_back(pos);
1430 ++uiCount;
1431 }
1432
1433 if ( !uiCount )
1434 return 0;
1435
1436 // allocate enough memory for the whole new string
1437 wxString tmp;
1438 tmp.m_impl.reserve(m_impl.length() + uiCount*(uiNewLen - uiOldLen));
1439
1440 // copy this string to tmp doing replacements on the fly
1441 size_t replNum = 0;
1442 for ( pos = 0; replNum < uiCount; replNum++ )
1443 {
1444 const size_t nextReplPos = replacePositions[replNum];
1445
1446 if ( pos != nextReplPos )
1447 {
1448 tmp.m_impl.append(m_impl, pos, nextReplPos - pos);
1449 }
1450
1451 tmp.m_impl.append(strNew.m_impl);
1452 pos = nextReplPos + uiOldLen;
1453 }
1454
1455 if ( pos != m_impl.length() )
1456 {
1457 // append the rest of the string unchanged
1458 tmp.m_impl.append(m_impl, pos, m_impl.length() - pos);
1459 }
1460
1461 swap(tmp);
1462 }
1463
1464 return uiCount;
1465 }
1466
1467 bool wxString::IsAscii() const
1468 {
1469 for ( const_iterator i = begin(); i != end(); ++i )
1470 {
1471 if ( !(*i).IsAscii() )
1472 return false;
1473 }
1474
1475 return true;
1476 }
1477
1478 bool wxString::IsWord() const
1479 {
1480 for ( const_iterator i = begin(); i != end(); ++i )
1481 {
1482 if ( !wxIsalpha(*i) )
1483 return false;
1484 }
1485
1486 return true;
1487 }
1488
1489 bool wxString::IsNumber() const
1490 {
1491 if ( empty() )
1492 return true;
1493
1494 const_iterator i = begin();
1495
1496 if ( *i == _T('-') || *i == _T('+') )
1497 ++i;
1498
1499 for ( ; i != end(); ++i )
1500 {
1501 if ( !wxIsdigit(*i) )
1502 return false;
1503 }
1504
1505 return true;
1506 }
1507
1508 wxString wxString::Strip(stripType w) const
1509 {
1510 wxString s = *this;
1511 if ( w & leading ) s.Trim(false);
1512 if ( w & trailing ) s.Trim(true);
1513 return s;
1514 }
1515
1516 // ---------------------------------------------------------------------------
1517 // case conversion
1518 // ---------------------------------------------------------------------------
1519
1520 wxString& wxString::MakeUpper()
1521 {
1522 for ( iterator it = begin(), en = end(); it != en; ++it )
1523 *it = (wxChar)wxToupper(*it);
1524
1525 return *this;
1526 }
1527
1528 wxString& wxString::MakeLower()
1529 {
1530 for ( iterator it = begin(), en = end(); it != en; ++it )
1531 *it = (wxChar)wxTolower(*it);
1532
1533 return *this;
1534 }
1535
1536 wxString& wxString::MakeCapitalized()
1537 {
1538 const iterator en = end();
1539 iterator it = begin();
1540 if ( it != en )
1541 {
1542 *it = (wxChar)wxToupper(*it);
1543 for ( ++it; it != en; ++it )
1544 *it = (wxChar)wxTolower(*it);
1545 }
1546
1547 return *this;
1548 }
1549
1550 // ---------------------------------------------------------------------------
1551 // trimming and padding
1552 // ---------------------------------------------------------------------------
1553
1554 // some compilers (VC++ 6.0 not to name them) return true for a call to
1555 // isspace('\xEA') in the C locale which seems to be broken to me, but we have
1556 // to live with this by checking that the character is a 7 bit one - even if
1557 // this may fail to detect some spaces (I don't know if Unicode doesn't have
1558 // space-like symbols somewhere except in the first 128 chars), it is arguably
1559 // still better than trimming away accented letters
1560 inline int wxSafeIsspace(wxChar ch) { return (ch < 127) && wxIsspace(ch); }
1561
1562 // trims spaces (in the sense of isspace) from left or right side
1563 wxString& wxString::Trim(bool bFromRight)
1564 {
1565 // first check if we're going to modify the string at all
1566 if ( !empty() &&
1567 (
1568 (bFromRight && wxSafeIsspace(GetChar(length() - 1))) ||
1569 (!bFromRight && wxSafeIsspace(GetChar(0u)))
1570 )
1571 )
1572 {
1573 if ( bFromRight )
1574 {
1575 // find last non-space character
1576 reverse_iterator psz = rbegin();
1577 while ( (psz != rend()) && wxSafeIsspace(*psz) )
1578 ++psz;
1579
1580 // truncate at trailing space start
1581 erase(psz.base(), end());
1582 }
1583 else
1584 {
1585 // find first non-space character
1586 iterator psz = begin();
1587 while ( (psz != end()) && wxSafeIsspace(*psz) )
1588 ++psz;
1589
1590 // fix up data and length
1591 erase(begin(), psz);
1592 }
1593 }
1594
1595 return *this;
1596 }
1597
1598 // adds nCount characters chPad to the string from either side
1599 wxString& wxString::Pad(size_t nCount, wxUniChar chPad, bool bFromRight)
1600 {
1601 wxString s(chPad, nCount);
1602
1603 if ( bFromRight )
1604 *this += s;
1605 else
1606 {
1607 s += *this;
1608 swap(s);
1609 }
1610
1611 return *this;
1612 }
1613
1614 // truncate the string
1615 wxString& wxString::Truncate(size_t uiLen)
1616 {
1617 if ( uiLen < length() )
1618 {
1619 erase(begin() + uiLen, end());
1620 }
1621 //else: nothing to do, string is already short enough
1622
1623 return *this;
1624 }
1625
1626 // ---------------------------------------------------------------------------
1627 // finding (return wxNOT_FOUND if not found and index otherwise)
1628 // ---------------------------------------------------------------------------
1629
1630 // find a character
1631 int wxString::Find(wxUniChar ch, bool bFromEnd) const
1632 {
1633 size_type idx = bFromEnd ? find_last_of(ch) : find_first_of(ch);
1634
1635 return (idx == npos) ? wxNOT_FOUND : (int)idx;
1636 }
1637
1638 // ----------------------------------------------------------------------------
1639 // conversion to numbers
1640 // ----------------------------------------------------------------------------
1641
1642 // The implementation of all the functions below is exactly the same so factor
1643 // it out. Note that number extraction works correctly on UTF-8 strings, so
1644 // we can use wxStringCharType and wx_str() for maximum efficiency.
1645
1646 #ifndef __WXWINCE__
1647 #define DO_IF_NOT_WINCE(x) x
1648 #else
1649 #define DO_IF_NOT_WINCE(x)
1650 #endif
1651
1652 #define WX_STRING_TO_X_TYPE_START \
1653 wxCHECK_MSG( pVal, false, _T("NULL output pointer") ); \
1654 DO_IF_NOT_WINCE( errno = 0; ) \
1655 const wxStringCharType *start = wx_str(); \
1656 wxStringCharType *end;
1657
1658 #define WX_STRING_TO_X_TYPE_END \
1659 /* return true only if scan was stopped by the terminating NUL and */ \
1660 /* if the string was not empty to start with and no under/overflow */ \
1661 /* occurred: */ \
1662 if ( *end || end == start DO_IF_NOT_WINCE(|| errno == ERANGE) ) \
1663 return false; \
1664 *pVal = val; \
1665 return true;
1666
1667 bool wxString::ToLong(long *pVal, int base) const
1668 {
1669 wxASSERT_MSG( !base || (base > 1 && base <= 36), _T("invalid base") );
1670
1671 WX_STRING_TO_X_TYPE_START
1672 long val = wxStrtol(start, &end, base);
1673 WX_STRING_TO_X_TYPE_END
1674 }
1675
1676 bool wxString::ToULong(unsigned long *pVal, int base) const
1677 {
1678 wxASSERT_MSG( !base || (base > 1 && base <= 36), _T("invalid base") );
1679
1680 WX_STRING_TO_X_TYPE_START
1681 unsigned long val = wxStrtoul(start, &end, base);
1682 WX_STRING_TO_X_TYPE_END
1683 }
1684
1685 bool wxString::ToLongLong(wxLongLong_t *pVal, int base) const
1686 {
1687 wxASSERT_MSG( !base || (base > 1 && base <= 36), _T("invalid base") );
1688
1689 WX_STRING_TO_X_TYPE_START
1690 wxLongLong_t val = wxStrtoll(start, &end, base);
1691 WX_STRING_TO_X_TYPE_END
1692 }
1693
1694 bool wxString::ToULongLong(wxULongLong_t *pVal, int base) const
1695 {
1696 wxASSERT_MSG( !base || (base > 1 && base <= 36), _T("invalid base") );
1697
1698 WX_STRING_TO_X_TYPE_START
1699 wxULongLong_t val = wxStrtoull(start, &end, base);
1700 WX_STRING_TO_X_TYPE_END
1701 }
1702
1703 bool wxString::ToDouble(double *pVal) const
1704 {
1705 WX_STRING_TO_X_TYPE_START
1706 double val = wxStrtod(start, &end);
1707 WX_STRING_TO_X_TYPE_END
1708 }
1709
1710 #if wxUSE_XLOCALE
1711
1712 bool wxString::ToCLong(long *pVal, int base) const
1713 {
1714 wxASSERT_MSG( !base || (base > 1 && base <= 36), _T("invalid base") );
1715
1716 WX_STRING_TO_X_TYPE_START
1717 #if wxUSE_UNICODE_UTF8 || !wxUSE_UNICODE
1718 long val = wxStrtol_lA(start, &end, base, wxCLocale);
1719 #else
1720 long val = wxStrtol_l(start, &end, base, wxCLocale);
1721 #endif
1722 WX_STRING_TO_X_TYPE_END
1723 }
1724
1725 bool wxString::ToCULong(unsigned long *pVal, int base) const
1726 {
1727 wxASSERT_MSG( !base || (base > 1 && base <= 36), _T("invalid base") );
1728
1729 WX_STRING_TO_X_TYPE_START
1730 #if wxUSE_UNICODE_UTF8 || !wxUSE_UNICODE
1731 unsigned long val = wxStrtoul_lA(start, &end, base, wxCLocale);
1732 #else
1733 unsigned long val = wxStrtoul_l(start, &end, base, wxCLocale);
1734 #endif
1735 WX_STRING_TO_X_TYPE_END
1736 }
1737
1738 bool wxString::ToCDouble(double *pVal) const
1739 {
1740 WX_STRING_TO_X_TYPE_START
1741 #if wxUSE_UNICODE_UTF8 || !wxUSE_UNICODE
1742 double val = wxStrtod_lA(start, &end, wxCLocale);
1743 #else
1744 double val = wxStrtod_l(start, &end, wxCLocale);
1745 #endif
1746 WX_STRING_TO_X_TYPE_END
1747 }
1748
1749 #endif // wxUSE_XLOCALE
1750
1751 // ---------------------------------------------------------------------------
1752 // formatted output
1753 // ---------------------------------------------------------------------------
1754
1755 #if !wxUSE_UTF8_LOCALE_ONLY
1756 /* static */
1757 #ifdef wxNEEDS_WXSTRING_PRINTF_MIXIN
1758 wxString wxStringPrintfMixinBase::DoFormatWchar(const wxChar *format, ...)
1759 #else
1760 wxString wxString::DoFormatWchar(const wxChar *format, ...)
1761 #endif
1762 {
1763 va_list argptr;
1764 va_start(argptr, format);
1765
1766 wxString s;
1767 s.PrintfV(format, argptr);
1768
1769 va_end(argptr);
1770
1771 return s;
1772 }
1773 #endif // !wxUSE_UTF8_LOCALE_ONLY
1774
1775 #if wxUSE_UNICODE_UTF8
1776 /* static */
1777 wxString wxString::DoFormatUtf8(const char *format, ...)
1778 {
1779 va_list argptr;
1780 va_start(argptr, format);
1781
1782 wxString s;
1783 s.PrintfV(format, argptr);
1784
1785 va_end(argptr);
1786
1787 return s;
1788 }
1789 #endif // wxUSE_UNICODE_UTF8
1790
1791 /* static */
1792 wxString wxString::FormatV(const wxString& format, va_list argptr)
1793 {
1794 wxString s;
1795 s.PrintfV(format, argptr);
1796 return s;
1797 }
1798
1799 #if !wxUSE_UTF8_LOCALE_ONLY
1800 #ifdef wxNEEDS_WXSTRING_PRINTF_MIXIN
1801 int wxStringPrintfMixinBase::DoPrintfWchar(const wxChar *format, ...)
1802 #else
1803 int wxString::DoPrintfWchar(const wxChar *format, ...)
1804 #endif
1805 {
1806 va_list argptr;
1807 va_start(argptr, format);
1808
1809 #ifdef wxNEEDS_WXSTRING_PRINTF_MIXIN
1810 // get a pointer to the wxString instance; we have to use dynamic_cast<>
1811 // because it's the only cast that works safely for downcasting when
1812 // multiple inheritance is used:
1813 wxString *str = static_cast<wxString*>(this);
1814 #else
1815 wxString *str = this;
1816 #endif
1817
1818 int iLen = str->PrintfV(format, argptr);
1819
1820 va_end(argptr);
1821
1822 return iLen;
1823 }
1824 #endif // !wxUSE_UTF8_LOCALE_ONLY
1825
1826 #if wxUSE_UNICODE_UTF8
1827 int wxString::DoPrintfUtf8(const char *format, ...)
1828 {
1829 va_list argptr;
1830 va_start(argptr, format);
1831
1832 int iLen = PrintfV(format, argptr);
1833
1834 va_end(argptr);
1835
1836 return iLen;
1837 }
1838 #endif // wxUSE_UNICODE_UTF8
1839
1840 /*
1841 Uses wxVsnprintf and places the result into the this string.
1842
1843 In ANSI build, wxVsnprintf is effectively vsnprintf but in Unicode build
1844 it is vswprintf. Due to a discrepancy between vsnprintf and vswprintf in
1845 the ISO C99 (and thus SUSv3) standard the return value for the case of
1846 an undersized buffer is inconsistent. For conforming vsnprintf
1847 implementations the function must return the number of characters that
1848 would have been printed had the buffer been large enough. For conforming
1849 vswprintf implementations the function must return a negative number
1850 and set errno.
1851
1852 What vswprintf sets errno to is undefined but Darwin seems to set it to
1853 EOVERFLOW. The only expected errno are EILSEQ and EINVAL. Both of
1854 those are defined in the standard and backed up by several conformance
1855 statements. Note that ENOMEM mentioned in the manual page does not
1856 apply to swprintf, only wprintf and fwprintf.
1857
1858 Official manual page:
1859 http://www.opengroup.org/onlinepubs/009695399/functions/swprintf.html
1860
1861 Some conformance statements (AIX, Solaris):
1862 http://www.opengroup.org/csq/view.mhtml?RID=ibm%2FSD1%2F3
1863 http://www.theopengroup.org/csq/view.mhtml?norationale=1&noreferences=1&RID=Fujitsu%2FSE2%2F10
1864
1865 Since EILSEQ and EINVAL are rather common but EOVERFLOW is not and since
1866 EILSEQ and EINVAL are specifically defined to mean the error is other than
1867 an undersized buffer and no other errno are defined we treat those two
1868 as meaning hard errors and everything else gets the old behavior which
1869 is to keep looping and increasing buffer size until the function succeeds.
1870
1871 In practice it's impossible to determine before compilation which behavior
1872 may be used. The vswprintf function may have vsnprintf-like behavior or
1873 vice-versa. Behavior detected on one release can theoretically change
1874 with an updated release. Not to mention that configure testing for it
1875 would require the test to be run on the host system, not the build system
1876 which makes cross compilation difficult. Therefore, we make no assumptions
1877 about behavior and try our best to handle every known case, including the
1878 case where wxVsnprintf returns a negative number and fails to set errno.
1879
1880 There is yet one more non-standard implementation and that is our own.
1881 Fortunately, that can be detected at compile-time.
1882
1883 On top of all that, ISO C99 explicitly defines snprintf to write a null
1884 character to the last position of the specified buffer. That would be at
1885 at the given buffer size minus 1. It is supposed to do this even if it
1886 turns out that the buffer is sized too small.
1887
1888 Darwin (tested on 10.5) follows the C99 behavior exactly.
1889
1890 Glibc 2.6 almost follows the C99 behavior except vswprintf never sets
1891 errno even when it fails. However, it only seems to ever fail due
1892 to an undersized buffer.
1893 */
1894 #if wxUSE_UNICODE_UTF8
1895 template<typename BufferType>
1896 #else
1897 // we only need one version in non-UTF8 builds and at least two Windows
1898 // compilers have problems with this function template, so use just one
1899 // normal function here
1900 #endif
1901 static int DoStringPrintfV(wxString& str,
1902 const wxString& format, va_list argptr)
1903 {
1904 int size = 1024;
1905
1906 for ( ;; )
1907 {
1908 #if wxUSE_UNICODE_UTF8
1909 BufferType tmp(str, size + 1);
1910 typename BufferType::CharType *buf = tmp;
1911 #else
1912 wxStringBuffer tmp(str, size + 1);
1913 wxChar *buf = tmp;
1914 #endif
1915
1916 if ( !buf )
1917 {
1918 // out of memory
1919
1920 // in UTF-8 build, leaving uninitialized junk in the buffer
1921 // could result in invalid non-empty UTF-8 string, so just
1922 // reset the string to empty on failure:
1923 buf[0] = '\0';
1924 return -1;
1925 }
1926
1927 // wxVsnprintf() may modify the original arg pointer, so pass it
1928 // only a copy
1929 va_list argptrcopy;
1930 wxVaCopy(argptrcopy, argptr);
1931
1932 #ifndef __WXWINCE__
1933 // Set errno to 0 to make it determinate if wxVsnprintf fails to set it.
1934 errno = 0;
1935 #endif
1936 int len = wxVsnprintf(buf, size, format, argptrcopy);
1937 va_end(argptrcopy);
1938
1939 // some implementations of vsnprintf() don't NUL terminate
1940 // the string if there is not enough space for it so
1941 // always do it manually
1942 // FIXME: This really seems to be the wrong and would be an off-by-one
1943 // bug except the code above allocates an extra character.
1944 buf[size] = _T('\0');
1945
1946 // vsnprintf() may return either -1 (traditional Unix behaviour) or the
1947 // total number of characters which would have been written if the
1948 // buffer were large enough (newer standards such as Unix98)
1949 if ( len < 0 )
1950 {
1951 // NB: wxVsnprintf() may call either wxCRT_VsnprintfW or
1952 // wxCRT_VsnprintfA in UTF-8 build; wxUSE_WXVSNPRINTF
1953 // is true if *both* of them use our own implementation,
1954 // otherwise we can't be sure
1955 #if wxUSE_WXVSNPRINTF
1956 // we know that our own implementation of wxVsnprintf() returns -1
1957 // only for a format error - thus there's something wrong with
1958 // the user's format string
1959 buf[0] = '\0';
1960 return -1;
1961 #else // possibly using system version
1962 // assume it only returns error if there is not enough space, but
1963 // as we don't know how much we need, double the current size of
1964 // the buffer
1965 #ifndef __WXWINCE__
1966 if( (errno == EILSEQ) || (errno == EINVAL) )
1967 // If errno was set to one of the two well-known hard errors
1968 // then fail immediately to avoid an infinite loop.
1969 return -1;
1970 else
1971 #endif // __WXWINCE__
1972 // still not enough, as we don't know how much we need, double the
1973 // current size of the buffer
1974 size *= 2;
1975 #endif // wxUSE_WXVSNPRINTF/!wxUSE_WXVSNPRINTF
1976 }
1977 else if ( len >= size )
1978 {
1979 #if wxUSE_WXVSNPRINTF
1980 // we know that our own implementation of wxVsnprintf() returns
1981 // size+1 when there's not enough space but that's not the size
1982 // of the required buffer!
1983 size *= 2; // so we just double the current size of the buffer
1984 #else
1985 // some vsnprintf() implementations NUL-terminate the buffer and
1986 // some don't in len == size case, to be safe always add 1
1987 // FIXME: I don't quite understand this comment. The vsnprintf
1988 // function is specifically defined to return the number of
1989 // characters printed not including the null terminator.
1990 // So OF COURSE you need to add 1 to get the right buffer size.
1991 // The following line is definitely correct, no question.
1992 size = len + 1;
1993 #endif
1994 }
1995 else // ok, there was enough space
1996 {
1997 break;
1998 }
1999 }
2000
2001 // we could have overshot
2002 str.Shrink();
2003
2004 return str.length();
2005 }
2006
2007 int wxString::PrintfV(const wxString& format, va_list argptr)
2008 {
2009 #if wxUSE_UNICODE_UTF8
2010 #if wxUSE_STL_BASED_WXSTRING
2011 typedef wxStringTypeBuffer<char> Utf8Buffer;
2012 #else
2013 typedef wxStringInternalBuffer Utf8Buffer;
2014 #endif
2015 #endif
2016
2017 #if wxUSE_UTF8_LOCALE_ONLY
2018 return DoStringPrintfV<Utf8Buffer>(*this, format, argptr);
2019 #else
2020 #if wxUSE_UNICODE_UTF8
2021 if ( wxLocaleIsUtf8 )
2022 return DoStringPrintfV<Utf8Buffer>(*this, format, argptr);
2023 else
2024 // wxChar* version
2025 return DoStringPrintfV<wxStringBuffer>(*this, format, argptr);
2026 #else
2027 return DoStringPrintfV(*this, format, argptr);
2028 #endif // UTF8/WCHAR
2029 #endif
2030 }
2031
2032 // ----------------------------------------------------------------------------
2033 // misc other operations
2034 // ----------------------------------------------------------------------------
2035
2036 // returns true if the string matches the pattern which may contain '*' and
2037 // '?' metacharacters (as usual, '?' matches any character and '*' any number
2038 // of them)
2039 bool wxString::Matches(const wxString& mask) const
2040 {
2041 // I disable this code as it doesn't seem to be faster (in fact, it seems
2042 // to be much slower) than the old, hand-written code below and using it
2043 // here requires always linking with libregex even if the user code doesn't
2044 // use it
2045 #if 0 // wxUSE_REGEX
2046 // first translate the shell-like mask into a regex
2047 wxString pattern;
2048 pattern.reserve(wxStrlen(pszMask));
2049
2050 pattern += _T('^');
2051 while ( *pszMask )
2052 {
2053 switch ( *pszMask )
2054 {
2055 case _T('?'):
2056 pattern += _T('.');
2057 break;
2058
2059 case _T('*'):
2060 pattern += _T(".*");
2061 break;
2062
2063 case _T('^'):
2064 case _T('.'):
2065 case _T('$'):
2066 case _T('('):
2067 case _T(')'):
2068 case _T('|'):
2069 case _T('+'):
2070 case _T('\\'):
2071 // these characters are special in a RE, quote them
2072 // (however note that we don't quote '[' and ']' to allow
2073 // using them for Unix shell like matching)
2074 pattern += _T('\\');
2075 // fall through
2076
2077 default:
2078 pattern += *pszMask;
2079 }
2080
2081 pszMask++;
2082 }
2083 pattern += _T('$');
2084
2085 // and now use it
2086 return wxRegEx(pattern, wxRE_NOSUB | wxRE_EXTENDED).Matches(c_str());
2087 #else // !wxUSE_REGEX
2088 // TODO: this is, of course, awfully inefficient...
2089
2090 // FIXME-UTF8: implement using iterators, remove #if
2091 #if wxUSE_UNICODE_UTF8
2092 const wxScopedWCharBuffer maskBuf = mask.wc_str();
2093 const wxScopedWCharBuffer txtBuf = wc_str();
2094 const wxChar *pszMask = maskBuf.data();
2095 const wxChar *pszTxt = txtBuf.data();
2096 #else
2097 const wxChar *pszMask = mask.wx_str();
2098 // the char currently being checked
2099 const wxChar *pszTxt = wx_str();
2100 #endif
2101
2102 // the last location where '*' matched
2103 const wxChar *pszLastStarInText = NULL;
2104 const wxChar *pszLastStarInMask = NULL;
2105
2106 match:
2107 for ( ; *pszMask != wxT('\0'); pszMask++, pszTxt++ ) {
2108 switch ( *pszMask ) {
2109 case wxT('?'):
2110 if ( *pszTxt == wxT('\0') )
2111 return false;
2112
2113 // pszTxt and pszMask will be incremented in the loop statement
2114
2115 break;
2116
2117 case wxT('*'):
2118 {
2119 // remember where we started to be able to backtrack later
2120 pszLastStarInText = pszTxt;
2121 pszLastStarInMask = pszMask;
2122
2123 // ignore special chars immediately following this one
2124 // (should this be an error?)
2125 while ( *pszMask == wxT('*') || *pszMask == wxT('?') )
2126 pszMask++;
2127
2128 // if there is nothing more, match
2129 if ( *pszMask == wxT('\0') )
2130 return true;
2131
2132 // are there any other metacharacters in the mask?
2133 size_t uiLenMask;
2134 const wxChar *pEndMask = wxStrpbrk(pszMask, wxT("*?"));
2135
2136 if ( pEndMask != NULL ) {
2137 // we have to match the string between two metachars
2138 uiLenMask = pEndMask - pszMask;
2139 }
2140 else {
2141 // we have to match the remainder of the string
2142 uiLenMask = wxStrlen(pszMask);
2143 }
2144
2145 wxString strToMatch(pszMask, uiLenMask);
2146 const wxChar* pMatch = wxStrstr(pszTxt, strToMatch);
2147 if ( pMatch == NULL )
2148 return false;
2149
2150 // -1 to compensate "++" in the loop
2151 pszTxt = pMatch + uiLenMask - 1;
2152 pszMask += uiLenMask - 1;
2153 }
2154 break;
2155
2156 default:
2157 if ( *pszMask != *pszTxt )
2158 return false;
2159 break;
2160 }
2161 }
2162
2163 // match only if nothing left
2164 if ( *pszTxt == wxT('\0') )
2165 return true;
2166
2167 // if we failed to match, backtrack if we can
2168 if ( pszLastStarInText ) {
2169 pszTxt = pszLastStarInText + 1;
2170 pszMask = pszLastStarInMask;
2171
2172 pszLastStarInText = NULL;
2173
2174 // don't bother resetting pszLastStarInMask, it's unnecessary
2175
2176 goto match;
2177 }
2178
2179 return false;
2180 #endif // wxUSE_REGEX/!wxUSE_REGEX
2181 }
2182
2183 // Count the number of chars
2184 int wxString::Freq(wxUniChar ch) const
2185 {
2186 int count = 0;
2187 for ( const_iterator i = begin(); i != end(); ++i )
2188 {
2189 if ( *i == ch )
2190 count ++;
2191 }
2192 return count;
2193 }
2194