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