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