]> git.saurik.com Git - wxWidgets.git/blame - src/common/string.cpp
compilation fix for 2.8 compat disabled
[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
ce3ed50d 38#ifdef __SALFORDC__
8898456d 39 #include <clib.h>
ce3ed50d
JS
40#endif
41
8116a0c5 42#include "wx/hashmap.h"
8f93a29f
VS
43
44// string handling functions used by wxString:
45#if wxUSE_UNICODE_UTF8
46 #define wxStringMemcpy memcpy
47 #define wxStringMemcmp memcmp
48 #define wxStringMemchr memchr
49 #define wxStringStrlen strlen
50#else
51 #define wxStringMemcpy wxTmemcpy
52 #define wxStringMemcmp wxTmemcmp
a7ea63e2
VS
53 #define wxStringMemchr wxTmemchr
54 #define wxStringStrlen wxStrlen
55#endif
8f93a29f 56
e87b7833 57
a7ea63e2
VS
58// ---------------------------------------------------------------------------
59// static class variables definition
60// ---------------------------------------------------------------------------
e87b7833 61
a7ea63e2
VS
62//According to STL _must_ be a -1 size_t
63const size_t wxString::npos = (size_t) -1;
8f93a29f 64
a7ea63e2
VS
65// ----------------------------------------------------------------------------
66// global functions
67// ----------------------------------------------------------------------------
e87b7833 68
a7ea63e2 69#if wxUSE_STD_IOSTREAM
8f93a29f 70
a7ea63e2 71#include <iostream>
8f93a29f 72
a7ea63e2 73wxSTD ostream& operator<<(wxSTD ostream& os, const wxCStrData& str)
8f93a29f 74{
04abe4bc 75// FIXME-UTF8: always, not only if wxUSE_UNICODE
a7ea63e2 76#if wxUSE_UNICODE && !defined(__BORLANDC__)
681e4412 77 return os << (const wchar_t*)str.AsWCharBuf();
a7ea63e2 78#else
681e4412 79 return os << (const char*)str.AsCharBuf();
a7ea63e2 80#endif
8f93a29f
VS
81}
82
04abe4bc
VS
83wxSTD ostream& operator<<(wxSTD ostream& os, const wxString& str)
84{
85 return os << str.c_str();
86}
87
88wxSTD ostream& operator<<(wxSTD ostream& os, const wxCharBuffer& str)
89{
90 return os << str.data();
91}
92
93#ifndef __BORLANDC__
94wxSTD ostream& operator<<(wxSTD ostream& os, const wxWCharBuffer& str)
95{
96 return os << str.data();
97}
98#endif
99
a7ea63e2 100#endif // wxUSE_STD_IOSTREAM
e87b7833 101
81727065
VS
102// ===========================================================================
103// wxString class core
104// ===========================================================================
105
106#if wxUSE_UNICODE_UTF8
107
81727065
VS
108void wxString::PosLenToImpl(size_t pos, size_t len,
109 size_t *implPos, size_t *implLen) const
110{
111 if ( pos == npos )
112 *implPos = npos;
113 else
114 {
115 const_iterator i = begin() + pos;
cf9a878b 116 *implPos = wxStringImpl::const_iterator(i.impl()) - m_impl.begin();
81727065
VS
117 if ( len == npos )
118 *implLen = npos;
119 else
120 {
121 // too large length is interpreted as "to the end of the string"
122 // FIXME-UTF8: verify this is the case in std::string, assert
123 // otherwise
124 if ( pos + len > length() )
125 len = length() - pos;
126
cf9a878b 127 *implLen = (i + len).impl() - i.impl();
81727065
VS
128 }
129 }
130}
131
132#endif // wxUSE_UNICODE_UTF8
133
11aac4ba
VS
134// ----------------------------------------------------------------------------
135// wxCStrData converted strings caching
136// ----------------------------------------------------------------------------
137
132276cf
VS
138// FIXME-UTF8: temporarily disabled because it doesn't work with global
139// string objects; re-enable after fixing this bug and benchmarking
140// performance to see if using a hash is a good idea at all
141#if 0
142
11aac4ba
VS
143// For backward compatibility reasons, it must be possible to assign the value
144// returned by wxString::c_str() to a char* or wchar_t* variable and work with
145// it. Returning wxCharBuffer from (const char*)c_str() wouldn't do the trick,
146// because the memory would be freed immediately, but it has to be valid as long
147// as the string is not modified, so that code like this still works:
148//
149// const wxChar *s = str.c_str();
150// while ( s ) { ... }
151
152// FIXME-UTF8: not thread safe!
153// FIXME-UTF8: we currently clear the cached conversion only when the string is
154// destroyed, but we should do it when the string is modified, to
155// keep memory usage down
156// FIXME-UTF8: we do the conversion every time As[W]Char() is called, but if we
157// invalidated the cache on every change, we could keep the previous
158// conversion
159// FIXME-UTF8: add tracing of usage of these two methods - new code is supposed
160// to use mb_str() or wc_str() instead of (const [w]char*)c_str()
161
162template<typename T>
163static inline void DeleteStringFromConversionCache(T& hash, const wxString *s)
164{
6c4ebcda 165 typename T::iterator i = hash.find(wxConstCast(s, wxString));
11aac4ba
VS
166 if ( i != hash.end() )
167 {
168 free(i->second);
169 hash.erase(i);
170 }
171}
172
173#if wxUSE_UNICODE
6c4ebcda
VS
174// NB: non-STL implementation doesn't compile with "const wxString*" key type,
175// so we have to use wxString* here and const-cast when used
11aac4ba
VS
176WX_DECLARE_HASH_MAP(wxString*, char*, wxPointerHash, wxPointerEqual,
177 wxStringCharConversionCache);
178static wxStringCharConversionCache gs_stringsCharCache;
179
180const char* wxCStrData::AsChar() const
181{
182 // remove previously cache value, if any (see FIXMEs above):
183 DeleteStringFromConversionCache(gs_stringsCharCache, m_str);
184
185 // convert the string and keep it:
6c4ebcda
VS
186 const char *s = gs_stringsCharCache[wxConstCast(m_str, wxString)] =
187 m_str->mb_str().release();
11aac4ba
VS
188
189 return s + m_offset;
190}
191#endif // wxUSE_UNICODE
192
193#if !wxUSE_UNICODE_WCHAR
194WX_DECLARE_HASH_MAP(wxString*, wchar_t*, wxPointerHash, wxPointerEqual,
195 wxStringWCharConversionCache);
196static wxStringWCharConversionCache gs_stringsWCharCache;
197
198const wchar_t* wxCStrData::AsWChar() const
199{
200 // remove previously cache value, if any (see FIXMEs above):
201 DeleteStringFromConversionCache(gs_stringsWCharCache, m_str);
202
203 // convert the string and keep it:
6c4ebcda
VS
204 const wchar_t *s = gs_stringsWCharCache[wxConstCast(m_str, wxString)] =
205 m_str->wc_str().release();
11aac4ba
VS
206
207 return s + m_offset;
208}
209#endif // !wxUSE_UNICODE_WCHAR
210
11aac4ba
VS
211wxString::~wxString()
212{
213#if wxUSE_UNICODE
214 // FIXME-UTF8: do this only if locale is not UTF8 if wxUSE_UNICODE_UTF8
215 DeleteStringFromConversionCache(gs_stringsCharCache, this);
216#endif
217#if !wxUSE_UNICODE_WCHAR
218 DeleteStringFromConversionCache(gs_stringsWCharCache, this);
219#endif
220}
132276cf
VS
221#endif
222
223#if wxUSE_UNICODE
224const char* wxCStrData::AsChar() const
225{
226 wxString *str = wxConstCast(m_str, wxString);
05f32fc3
VS
227
228 // convert the string:
229 wxCharBuffer buf(str->mb_str());
230
231 // FIXME-UTF8: do the conversion in-place in the existing buffer
232 if ( str->m_convertedToChar &&
233 strlen(buf) == strlen(str->m_convertedToChar) )
234 {
235 // keep the same buffer for as long as possible, so that several calls
236 // to c_str() in a row still work:
237 strcpy(str->m_convertedToChar, buf);
238 }
239 else
240 {
241 str->m_convertedToChar = buf.release();
242 }
243
244 // and keep it:
132276cf
VS
245 return str->m_convertedToChar + m_offset;
246}
247#endif // wxUSE_UNICODE
248
249#if !wxUSE_UNICODE_WCHAR
250const wchar_t* wxCStrData::AsWChar() const
251{
252 wxString *str = wxConstCast(m_str, wxString);
05f32fc3
VS
253
254 // convert the string:
255 wxWCharBuffer buf(str->wc_str());
256
257 // FIXME-UTF8: do the conversion in-place in the existing buffer
258 if ( str->m_convertedToWChar &&
259 wxWcslen(buf) == wxWcslen(str->m_convertedToWChar) )
260 {
261 // keep the same buffer for as long as possible, so that several calls
262 // to c_str() in a row still work:
263 memcpy(str->m_convertedToWChar, buf, sizeof(wchar_t) * wxWcslen(buf));
264 }
265 else
266 {
267 str->m_convertedToWChar = buf.release();
268 }
269
270 // and keep it:
132276cf
VS
271 return str->m_convertedToWChar + m_offset;
272}
273#endif // !wxUSE_UNICODE_WCHAR
274
275// ===========================================================================
276// wxString class core
277// ===========================================================================
278
279// ---------------------------------------------------------------------------
280// construction and conversion
281// ---------------------------------------------------------------------------
11aac4ba 282
81727065 283#if wxUSE_UNICODE_WCHAR
8f93a29f
VS
284/* static */
285wxString::SubstrBufFromMB wxString::ConvertStr(const char *psz, size_t nLength,
04abe4bc 286 const wxMBConv& conv)
8f93a29f
VS
287{
288 // anything to do?
289 if ( !psz || nLength == 0 )
81727065 290 return SubstrBufFromMB(L"", 0);
8f93a29f
VS
291
292 if ( nLength == npos )
293 nLength = wxNO_LEN;
294
295 size_t wcLen;
296 wxWCharBuffer wcBuf(conv.cMB2WC(psz, nLength, &wcLen));
297 if ( !wcLen )
81727065 298 return SubstrBufFromMB(_T(""), 0);
8f93a29f
VS
299 else
300 return SubstrBufFromMB(wcBuf, wcLen);
301}
81727065
VS
302#endif // wxUSE_UNICODE_WCHAR
303
304#if wxUSE_UNICODE_UTF8
305/* static */
306wxString::SubstrBufFromMB wxString::ConvertStr(const char *psz, size_t nLength,
307 const wxMBConv& conv)
308{
309 // FIXME-UTF8: return as-is without copying under UTF8 locale, return
310 // converted string under other locales - needs wxCharBuffer
311 // changes
312
313 // anything to do?
314 if ( !psz || nLength == 0 )
315 return SubstrBufFromMB("", 0);
316
317 if ( nLength == npos )
318 nLength = wxNO_LEN;
319
320 // first convert to wide string:
321 size_t wcLen;
322 wxWCharBuffer wcBuf(conv.cMB2WC(psz, nLength, &wcLen));
323 if ( !wcLen )
324 return SubstrBufFromMB("", 0);
325
326 // and then to UTF-8:
327 SubstrBufFromMB buf(ConvertStr(wcBuf, wcLen, wxConvUTF8));
328 // widechar -> UTF-8 conversion isn't supposed to ever fail:
329 wxASSERT_MSG( buf.data, _T("conversion to UTF-8 failed") );
330
331 return buf;
332}
333#endif // wxUSE_UNICODE_UTF8
334
335#if wxUSE_UNICODE_UTF8 || !wxUSE_UNICODE
8f93a29f
VS
336/* static */
337wxString::SubstrBufFromWC wxString::ConvertStr(const wchar_t *pwz, size_t nLength,
04abe4bc 338 const wxMBConv& conv)
8f93a29f
VS
339{
340 // anything to do?
341 if ( !pwz || nLength == 0 )
81727065 342 return SubstrBufFromWC("", 0);
8f93a29f
VS
343
344 if ( nLength == npos )
345 nLength = wxNO_LEN;
346
347 size_t mbLen;
348 wxCharBuffer mbBuf(conv.cWC2MB(pwz, nLength, &mbLen));
349 if ( !mbLen )
81727065 350 return SubstrBufFromWC("", 0);
8f93a29f
VS
351 else
352 return SubstrBufFromWC(mbBuf, mbLen);
353}
81727065 354#endif // wxUSE_UNICODE_UTF8 || !wxUSE_UNICODE
8f93a29f
VS
355
356
81727065 357#if wxUSE_UNICODE_WCHAR
e87b7833 358
06386448 359//Convert wxString in Unicode mode to a multi-byte string
830f8f11 360const wxCharBuffer wxString::mb_str(const wxMBConv& conv) const
265d5cce 361{
81727065 362 return conv.cWC2MB(wx_str(), length() + 1 /* size, not length */, NULL);
e87b7833
MB
363}
364
81727065 365#elif wxUSE_UNICODE_UTF8
e87b7833 366
81727065
VS
367const wxWCharBuffer wxString::wc_str() const
368{
369 return wxConvUTF8.cMB2WC(m_impl.c_str(),
370 m_impl.length() + 1 /* size, not length */,
371 NULL);
372}
373
374const wxCharBuffer wxString::mb_str(const wxMBConv& conv) const
375{
376 // FIXME-UTF8: optimize the case when conv==wxConvUTF8 or wxConvLibc
377 // under UTF8 locale
378 // FIXME-UTF8: use wc_str() here once we have buffers with length
379
380 size_t wcLen;
381 wxWCharBuffer wcBuf(
382 wxConvUTF8.cMB2WC(m_impl.c_str(),
383 m_impl.length() + 1 /* size, not length */,
384 &wcLen));
385 if ( !wcLen )
386 return wxCharBuffer("");
387
388 return conv.cWC2MB(wcBuf, wcLen, NULL);
389}
390
391#else // ANSI
eec47cc6 392
7663d0d4 393//Converts this string to a wide character string if unicode
06386448 394//mode is not enabled and wxUSE_WCHAR_T is enabled
830f8f11 395const wxWCharBuffer wxString::wc_str(const wxMBConv& conv) const
265d5cce 396{
81727065 397 return conv.cMB2WC(wx_str(), length() + 1 /* size, not length */, NULL);
265d5cce 398}
7663d0d4 399
e87b7833
MB
400#endif // Unicode/ANSI
401
402// shrink to minimal size (releasing extra memory)
403bool wxString::Shrink()
404{
405 wxString tmp(begin(), end());
406 swap(tmp);
407 return tmp.length() == length();
408}
409
d8a4b666 410// deprecated compatibility code:
a7ea63e2 411#if WXWIN_COMPATIBILITY_2_8 && !wxUSE_STL_BASED_WXSTRING && !wxUSE_UNICODE_UTF8
c87a0bc8 412wxStringCharType *wxString::GetWriteBuf(size_t nLen)
d8a4b666
VS
413{
414 return DoGetWriteBuf(nLen);
415}
416
417void wxString::UngetWriteBuf()
418{
419 DoUngetWriteBuf();
420}
421
422void wxString::UngetWriteBuf(size_t nLen)
423{
424 DoUngetWriteBuf(nLen);
425}
a7ea63e2 426#endif // WXWIN_COMPATIBILITY_2_8 && !wxUSE_STL_BASED_WXSTRING && !wxUSE_UNICODE_UTF8
e87b7833 427
d8a4b666 428
e87b7833
MB
429// ---------------------------------------------------------------------------
430// data access
431// ---------------------------------------------------------------------------
432
433// all functions are inline in string.h
434
435// ---------------------------------------------------------------------------
e8f59039 436// concatenation operators
e87b7833
MB
437// ---------------------------------------------------------------------------
438
c801d85f 439/*
c801d85f
KB
440 * concatenation functions come in 5 flavours:
441 * string + string
442 * char + string and string + char
443 * C str + string and string + C str
444 */
445
b1801e0e 446wxString operator+(const wxString& str1, const wxString& str2)
c801d85f 447{
992527a5 448#if !wxUSE_STL_BASED_WXSTRING
8f93a29f
VS
449 wxASSERT( str1.IsValid() );
450 wxASSERT( str2.IsValid() );
e87b7833 451#endif
097c080b 452
3458e408
WS
453 wxString s = str1;
454 s += str2;
3168a13f 455
3458e408 456 return s;
c801d85f
KB
457}
458
c9f78968 459wxString operator+(const wxString& str, wxUniChar ch)
c801d85f 460{
992527a5 461#if !wxUSE_STL_BASED_WXSTRING
8f93a29f 462 wxASSERT( str.IsValid() );
e87b7833 463#endif
3168a13f 464
3458e408
WS
465 wxString s = str;
466 s += ch;
097c080b 467
3458e408 468 return s;
c801d85f
KB
469}
470
c9f78968 471wxString operator+(wxUniChar ch, const wxString& str)
c801d85f 472{
992527a5 473#if !wxUSE_STL_BASED_WXSTRING
8f93a29f 474 wxASSERT( str.IsValid() );
e87b7833 475#endif
097c080b 476
3458e408
WS
477 wxString s = ch;
478 s += str;
3168a13f 479
3458e408 480 return s;
c801d85f
KB
481}
482
8f93a29f 483wxString operator+(const wxString& str, const char *psz)
c801d85f 484{
992527a5 485#if !wxUSE_STL_BASED_WXSTRING
8f93a29f 486 wxASSERT( str.IsValid() );
e87b7833 487#endif
097c080b 488
3458e408 489 wxString s;
8f93a29f 490 if ( !s.Alloc(strlen(psz) + str.length()) ) {
3458e408
WS
491 wxFAIL_MSG( _T("out of memory in wxString::operator+") );
492 }
493 s += str;
494 s += psz;
3168a13f 495
3458e408 496 return s;
c801d85f
KB
497}
498
8f93a29f 499wxString operator+(const wxString& str, const wchar_t *pwz)
c801d85f 500{
992527a5 501#if !wxUSE_STL_BASED_WXSTRING
8f93a29f
VS
502 wxASSERT( str.IsValid() );
503#endif
504
505 wxString s;
506 if ( !s.Alloc(wxWcslen(pwz) + str.length()) ) {
507 wxFAIL_MSG( _T("out of memory in wxString::operator+") );
508 }
509 s += str;
510 s += pwz;
511
512 return s;
513}
514
515wxString operator+(const char *psz, const wxString& str)
516{
a7ea63e2
VS
517#if !wxUSE_STL_BASED_WXSTRING
518 wxASSERT( str.IsValid() );
519#endif
520
521 wxString s;
522 if ( !s.Alloc(strlen(psz) + str.length()) ) {
523 wxFAIL_MSG( _T("out of memory in wxString::operator+") );
524 }
525 s = psz;
526 s += str;
527
528 return s;
529}
530
531wxString operator+(const wchar_t *pwz, const wxString& str)
532{
533#if !wxUSE_STL_BASED_WXSTRING
534 wxASSERT( str.IsValid() );
535#endif
536
537 wxString s;
538 if ( !s.Alloc(wxWcslen(pwz) + str.length()) ) {
539 wxFAIL_MSG( _T("out of memory in wxString::operator+") );
540 }
541 s = pwz;
542 s += str;
543
544 return s;
545}
546
547// ---------------------------------------------------------------------------
548// string comparison
549// ---------------------------------------------------------------------------
550
551#ifdef HAVE_STD_STRING_COMPARE
552
553// NB: Comparison code (both if HAVE_STD_STRING_COMPARE and if not) works with
554// UTF-8 encoded strings too, thanks to UTF-8's design which allows us to
555// sort strings in characters code point order by sorting the byte sequence
556// in byte values order (i.e. what strcmp() and memcmp() do).
557
558int wxString::compare(const wxString& str) const
559{
560 return m_impl.compare(str.m_impl);
561}
562
563int wxString::compare(size_t nStart, size_t nLen,
564 const wxString& str) const
565{
566 size_t pos, len;
567 PosLenToImpl(nStart, nLen, &pos, &len);
568 return m_impl.compare(pos, len, str.m_impl);
569}
570
571int wxString::compare(size_t nStart, size_t nLen,
572 const wxString& str,
573 size_t nStart2, size_t nLen2) const
574{
575 size_t pos, len;
576 PosLenToImpl(nStart, nLen, &pos, &len);
577
578 size_t pos2, len2;
579 str.PosLenToImpl(nStart2, nLen2, &pos2, &len2);
580
581 return m_impl.compare(pos, len, str.m_impl, pos2, len2);
582}
583
584int wxString::compare(const char* sz) const
585{
586 return m_impl.compare(ImplStr(sz));
587}
588
589int wxString::compare(const wchar_t* sz) const
590{
591 return m_impl.compare(ImplStr(sz));
592}
593
594int wxString::compare(size_t nStart, size_t nLen,
595 const char* sz, size_t nCount) const
596{
597 size_t pos, len;
598 PosLenToImpl(nStart, nLen, &pos, &len);
599
600 SubstrBufFromMB str(ImplStr(sz, nCount));
601
602 return m_impl.compare(pos, len, str.data, str.len);
603}
604
605int wxString::compare(size_t nStart, size_t nLen,
606 const wchar_t* sz, size_t nCount) const
607{
608 size_t pos, len;
609 PosLenToImpl(nStart, nLen, &pos, &len);
610
611 SubstrBufFromWC str(ImplStr(sz, nCount));
612
613 return m_impl.compare(pos, len, str.data, str.len);
614}
615
616#else // !HAVE_STD_STRING_COMPARE
617
618static inline int wxDoCmp(const wxStringCharType* s1, size_t l1,
619 const wxStringCharType* s2, size_t l2)
620{
621 if( l1 == l2 )
622 return wxStringMemcmp(s1, s2, l1);
623 else if( l1 < l2 )
624 {
625 int ret = wxStringMemcmp(s1, s2, l1);
626 return ret == 0 ? -1 : ret;
627 }
628 else
629 {
630 int ret = wxStringMemcmp(s1, s2, l2);
631 return ret == 0 ? +1 : ret;
632 }
633}
634
635int wxString::compare(const wxString& str) const
636{
637 return ::wxDoCmp(m_impl.data(), m_impl.length(),
638 str.m_impl.data(), str.m_impl.length());
639}
640
641int wxString::compare(size_t nStart, size_t nLen,
642 const wxString& str) const
643{
644 wxASSERT(nStart <= length());
645 size_type strLen = length() - nStart;
646 nLen = strLen < nLen ? strLen : nLen;
647
648 size_t pos, len;
649 PosLenToImpl(nStart, nLen, &pos, &len);
650
651 return ::wxDoCmp(m_impl.data() + pos, len,
652 str.m_impl.data(), str.m_impl.length());
653}
654
655int wxString::compare(size_t nStart, size_t nLen,
656 const wxString& str,
657 size_t nStart2, size_t nLen2) const
658{
659 wxASSERT(nStart <= length());
660 wxASSERT(nStart2 <= str.length());
661 size_type strLen = length() - nStart,
662 strLen2 = str.length() - nStart2;
663 nLen = strLen < nLen ? strLen : nLen;
664 nLen2 = strLen2 < nLen2 ? strLen2 : nLen2;
665
666 size_t pos, len;
667 PosLenToImpl(nStart, nLen, &pos, &len);
668 size_t pos2, len2;
669 str.PosLenToImpl(nStart2, nLen2, &pos2, &len2);
670
671 return ::wxDoCmp(m_impl.data() + pos, len,
672 str.m_impl.data() + pos2, len2);
673}
674
675int wxString::compare(const char* sz) const
676{
677 SubstrBufFromMB str(ImplStr(sz, npos));
678 if ( str.len == npos )
679 str.len = wxStringStrlen(str.data);
680 return ::wxDoCmp(m_impl.data(), m_impl.length(), str.data, str.len);
681}
682
683int wxString::compare(const wchar_t* sz) const
684{
685 SubstrBufFromWC str(ImplStr(sz, npos));
686 if ( str.len == npos )
687 str.len = wxStringStrlen(str.data);
688 return ::wxDoCmp(m_impl.data(), m_impl.length(), str.data, str.len);
689}
690
691int wxString::compare(size_t nStart, size_t nLen,
692 const char* sz, size_t nCount) const
693{
694 wxASSERT(nStart <= length());
695 size_type strLen = length() - nStart;
696 nLen = strLen < nLen ? strLen : nLen;
097c080b 697
a7ea63e2
VS
698 size_t pos, len;
699 PosLenToImpl(nStart, nLen, &pos, &len);
3168a13f 700
a7ea63e2
VS
701 SubstrBufFromMB str(ImplStr(sz, nCount));
702 if ( str.len == npos )
703 str.len = wxStringStrlen(str.data);
704
705 return ::wxDoCmp(m_impl.data() + pos, len, str.data, str.len);
c801d85f
KB
706}
707
a7ea63e2
VS
708int wxString::compare(size_t nStart, size_t nLen,
709 const wchar_t* sz, size_t nCount) const
8f93a29f 710{
a7ea63e2
VS
711 wxASSERT(nStart <= length());
712 size_type strLen = length() - nStart;
713 nLen = strLen < nLen ? strLen : nLen;
8f93a29f 714
a7ea63e2
VS
715 size_t pos, len;
716 PosLenToImpl(nStart, nLen, &pos, &len);
8f93a29f 717
a7ea63e2
VS
718 SubstrBufFromWC str(ImplStr(sz, nCount));
719 if ( str.len == npos )
720 str.len = wxStringStrlen(str.data);
721
722 return ::wxDoCmp(m_impl.data() + pos, len, str.data, str.len);
8f93a29f
VS
723}
724
a7ea63e2
VS
725#endif // HAVE_STD_STRING_COMPARE/!HAVE_STD_STRING_COMPARE
726
727
8f93a29f
VS
728// ---------------------------------------------------------------------------
729// find_{first,last}_[not]_of functions
730// ---------------------------------------------------------------------------
731
732#if !wxUSE_STL_BASED_WXSTRING || wxUSE_UNICODE_UTF8
c801d85f 733
8f93a29f
VS
734// NB: All these functions are implemented with the argument being wxChar*,
735// i.e. widechar string in any Unicode build, even though native string
736// representation is char* in the UTF-8 build. This is because we couldn't
737// use memchr() to determine if a character is in a set encoded as UTF-8.
738
739size_t wxString::find_first_of(const wxChar* sz, size_t nStart) const
dcb68102 740{
8f93a29f 741 return find_first_of(sz, nStart, wxStrlen(sz));
dcb68102
RN
742}
743
8f93a29f 744size_t wxString::find_first_not_of(const wxChar* sz, size_t nStart) const
dcb68102 745{
8f93a29f 746 return find_first_not_of(sz, nStart, wxStrlen(sz));
dcb68102
RN
747}
748
8f93a29f 749size_t wxString::find_first_of(const wxChar* sz, size_t nStart, size_t n) const
dcb68102 750{
8f93a29f 751 wxASSERT_MSG( nStart <= length(), _T("invalid index") );
dcb68102 752
8f93a29f
VS
753 size_t idx = nStart;
754 for ( const_iterator i = begin() + nStart; i != end(); ++idx, ++i )
dcb68102 755 {
8f93a29f
VS
756 if ( wxTmemchr(sz, *i, n) )
757 return idx;
dcb68102 758 }
8f93a29f
VS
759
760 return npos;
761}
762
763size_t wxString::find_first_not_of(const wxChar* sz, size_t nStart, size_t n) const
764{
765 wxASSERT_MSG( nStart <= length(), _T("invalid index") );
766
767 size_t idx = nStart;
768 for ( const_iterator i = begin() + nStart; i != end(); ++idx, ++i )
dcb68102 769 {
8f93a29f
VS
770 if ( !wxTmemchr(sz, *i, n) )
771 return idx;
772 }
773
774 return npos;
775}
776
777
778size_t wxString::find_last_of(const wxChar* sz, size_t nStart) const
779{
780 return find_last_of(sz, nStart, wxStrlen(sz));
781}
782
783size_t wxString::find_last_not_of(const wxChar* sz, size_t nStart) const
784{
785 return find_last_not_of(sz, nStart, wxStrlen(sz));
786}
787
788size_t wxString::find_last_of(const wxChar* sz, size_t nStart, size_t n) const
789{
790 size_t len = length();
791
792 if ( nStart == npos )
793 {
794 nStart = len - 1;
dcb68102 795 }
2c09fb3b 796 else
dcb68102 797 {
8f93a29f 798 wxASSERT_MSG( nStart <= len, _T("invalid index") );
dcb68102 799 }
8f93a29f
VS
800
801 size_t idx = nStart;
802 for ( const_reverse_iterator i = rbegin() + (len - nStart - 1);
803 i != rend(); --idx, ++i )
804 {
805 if ( wxTmemchr(sz, *i, n) )
806 return idx;
807 }
808
809 return npos;
dcb68102
RN
810}
811
8f93a29f 812size_t wxString::find_last_not_of(const wxChar* sz, size_t nStart, size_t n) const
dcb68102 813{
8f93a29f
VS
814 size_t len = length();
815
816 if ( nStart == npos )
817 {
818 nStart = len - 1;
819 }
820 else
821 {
822 wxASSERT_MSG( nStart <= len, _T("invalid index") );
823 }
824
825 size_t idx = nStart;
826 for ( const_reverse_iterator i = rbegin() + (len - nStart - 1);
827 i != rend(); --idx, ++i )
828 {
829 if ( !wxTmemchr(sz, *i, n) )
830 return idx;
831 }
832
833 return npos;
dcb68102
RN
834}
835
8f93a29f 836size_t wxString::find_first_not_of(wxUniChar ch, size_t nStart) const
dcb68102 837{
8f93a29f
VS
838 wxASSERT_MSG( nStart <= length(), _T("invalid index") );
839
840 size_t idx = nStart;
841 for ( const_iterator i = begin() + nStart; i != end(); ++idx, ++i )
842 {
843 if ( *i != ch )
844 return idx;
845 }
846
847 return npos;
848}
849
850size_t wxString::find_last_not_of(wxUniChar ch, size_t nStart) const
851{
852 size_t len = length();
853
854 if ( nStart == npos )
855 {
856 nStart = len - 1;
857 }
858 else
859 {
860 wxASSERT_MSG( nStart <= len, _T("invalid index") );
861 }
862
863 size_t idx = nStart;
864 for ( const_reverse_iterator i = rbegin() + (len - nStart - 1);
865 i != rend(); --idx, ++i )
866 {
867 if ( *i != ch )
868 return idx;
869 }
870
871 return npos;
872}
873
874// the functions above were implemented for wchar_t* arguments in Unicode
875// build and char* in ANSI build; below are implementations for the other
876// version:
877#if wxUSE_UNICODE
878 #define wxOtherCharType char
879 #define STRCONV (const wxChar*)wxConvLibc.cMB2WC
880#else
881 #define wxOtherCharType wchar_t
882 #define STRCONV (const wxChar*)wxConvLibc.cWC2MB
883#endif
884
885size_t wxString::find_first_of(const wxOtherCharType* sz, size_t nStart) const
886 { return find_first_of(STRCONV(sz), nStart); }
887
888size_t wxString::find_first_of(const wxOtherCharType* sz, size_t nStart,
889 size_t n) const
890 { return find_first_of(STRCONV(sz, n, NULL), nStart, n); }
891size_t wxString::find_last_of(const wxOtherCharType* sz, size_t nStart) const
892 { return find_last_of(STRCONV(sz), nStart); }
893size_t wxString::find_last_of(const wxOtherCharType* sz, size_t nStart,
894 size_t n) const
895 { return find_last_of(STRCONV(sz, n, NULL), nStart, n); }
896size_t wxString::find_first_not_of(const wxOtherCharType* sz, size_t nStart) const
897 { return find_first_not_of(STRCONV(sz), nStart); }
898size_t wxString::find_first_not_of(const wxOtherCharType* sz, size_t nStart,
899 size_t n) const
900 { return find_first_not_of(STRCONV(sz, n, NULL), nStart, n); }
901size_t wxString::find_last_not_of(const wxOtherCharType* sz, size_t nStart) const
902 { return find_last_not_of(STRCONV(sz), nStart); }
903size_t wxString::find_last_not_of(const wxOtherCharType* sz, size_t nStart,
904 size_t n) const
905 { return find_last_not_of(STRCONV(sz, n, NULL), nStart, n); }
906
907#undef wxOtherCharType
908#undef STRCONV
909
910#endif // !wxUSE_STL_BASED_WXSTRING || wxUSE_UNICODE_UTF8
911
912// ===========================================================================
913// other common string functions
914// ===========================================================================
915
916int wxString::CmpNoCase(const wxString& s) const
917{
918 // FIXME-UTF8: use wxUniChar::ToLower/ToUpper once added
919
920 size_t idx = 0;
921 const_iterator i1 = begin();
922 const_iterator end1 = end();
923 const_iterator i2 = s.begin();
924 const_iterator end2 = s.end();
925
926 for ( ; i1 != end1 && i2 != end2; ++idx, ++i1, ++i2 )
927 {
928 wxUniChar lower1 = (wxChar)wxTolower(*i1);
929 wxUniChar lower2 = (wxChar)wxTolower(*i2);
930 if ( lower1 != lower2 )
931 return lower1 < lower2 ? -1 : 1;
932 }
933
934 size_t len1 = length();
935 size_t len2 = s.length();
dcb68102 936
8f93a29f
VS
937 if ( len1 < len2 )
938 return -1;
939 else if ( len1 > len2 )
940 return 1;
941 return 0;
dcb68102
RN
942}
943
944
b1ac3b56 945#if wxUSE_UNICODE
e015c2a3 946
cf6bedce
SC
947#ifdef __MWERKS__
948#ifndef __SCHAR_MAX__
949#define __SCHAR_MAX__ 127
950#endif
951#endif
952
e015c2a3 953wxString wxString::FromAscii(const char *ascii)
b1ac3b56
RR
954{
955 if (!ascii)
956 return wxEmptyString;
e015c2a3 957
c1eada83 958 size_t len = strlen(ascii);
b1ac3b56 959 wxString res;
e015c2a3
VZ
960
961 if ( len )
962 {
c1eada83
VS
963 wxImplStringBuffer buf(res, len);
964 wxStringCharType *dest = buf;
e015c2a3
VZ
965
966 for ( ;; )
967 {
c1eada83
VS
968 unsigned char c = (unsigned char)*ascii++;
969 wxASSERT_MSG( c < 0x80,
970 _T("Non-ASCII value passed to FromAscii().") );
971
972 *dest++ = (wchar_t)c;
973
974 if ( c == '\0' )
975 break;
e015c2a3
VZ
976 }
977 }
978
b1ac3b56
RR
979 return res;
980}
981
2b5f62a0
VZ
982wxString wxString::FromAscii(const char ascii)
983{
984 // What do we do with '\0' ?
985
c1eada83 986 unsigned char c = (unsigned char)ascii;
8760bc65 987
c1eada83
VS
988 wxASSERT_MSG( c < 0x80, _T("Non-ASCII value passed to FromAscii().") );
989
990 // NB: the cast to wchar_t causes interpretation of 'ascii' as Latin1 value
991 return wxString(wxUniChar((wchar_t)c));
2b5f62a0
VZ
992}
993
b1ac3b56
RR
994const wxCharBuffer wxString::ToAscii() const
995{
e015c2a3
VZ
996 // this will allocate enough space for the terminating NUL too
997 wxCharBuffer buffer(length());
6e394fc6 998 char *dest = buffer.data();
e015c2a3 999
c1eada83 1000 for ( const_iterator i = begin(); i != end(); ++i )
b1ac3b56 1001 {
c1eada83
VS
1002 wxUniChar c(*i);
1003 // FIXME-UTF8: unify substituted char ('_') with wxUniChar ('?')
1004 *dest++ = c.IsAscii() ? (char)c : '_';
e015c2a3
VZ
1005
1006 // the output string can't have embedded NULs anyhow, so we can safely
1007 // stop at first of them even if we do have any
c1eada83 1008 if ( !c )
e015c2a3 1009 break;
b1ac3b56 1010 }
e015c2a3 1011
b1ac3b56
RR
1012 return buffer;
1013}
e015c2a3 1014
c1eada83 1015#endif // wxUSE_UNICODE
b1ac3b56 1016
c801d85f 1017// extract string of length nCount starting at nFirst
c801d85f
KB
1018wxString wxString::Mid(size_t nFirst, size_t nCount) const
1019{
73f507f5 1020 size_t nLen = length();
30d9011f 1021
73f507f5
WS
1022 // default value of nCount is npos and means "till the end"
1023 if ( nCount == npos )
1024 {
1025 nCount = nLen - nFirst;
1026 }
30d9011f 1027
73f507f5
WS
1028 // out-of-bounds requests return sensible things
1029 if ( nFirst + nCount > nLen )
1030 {
1031 nCount = nLen - nFirst;
1032 }
c801d85f 1033
73f507f5
WS
1034 if ( nFirst > nLen )
1035 {
1036 // AllocCopy() will return empty string
1037 return wxEmptyString;
1038 }
c801d85f 1039
73f507f5
WS
1040 wxString dest(*this, nFirst, nCount);
1041 if ( dest.length() != nCount )
1042 {
1043 wxFAIL_MSG( _T("out of memory in wxString::Mid") );
1044 }
30d9011f 1045
73f507f5 1046 return dest;
c801d85f
KB
1047}
1048
e87b7833 1049// check that the string starts with prefix and return the rest of the string
d775fa82 1050// in the provided pointer if it is not NULL, otherwise return false
f6bcfd97
BP
1051bool wxString::StartsWith(const wxChar *prefix, wxString *rest) const
1052{
1053 wxASSERT_MSG( prefix, _T("invalid parameter in wxString::StartsWith") );
1054
1055 // first check if the beginning of the string matches the prefix: note
1056 // that we don't have to check that we don't run out of this string as
1057 // when we reach the terminating NUL, either prefix string ends too (and
1058 // then it's ok) or we break out of the loop because there is no match
1059 const wxChar *p = c_str();
1060 while ( *prefix )
1061 {
1062 if ( *prefix++ != *p++ )
1063 {
1064 // no match
d775fa82 1065 return false;
f6bcfd97
BP
1066 }
1067 }
1068
1069 if ( rest )
1070 {
1071 // put the rest of the string into provided pointer
1072 *rest = p;
1073 }
1074
d775fa82 1075 return true;
f6bcfd97
BP
1076}
1077
3affcd07
VZ
1078
1079// check that the string ends with suffix and return the rest of it in the
1080// provided pointer if it is not NULL, otherwise return false
1081bool wxString::EndsWith(const wxChar *suffix, wxString *rest) const
1082{
1083 wxASSERT_MSG( suffix, _T("invalid parameter in wxString::EndssWith") );
1084
1085 int start = length() - wxStrlen(suffix);
81727065
VS
1086
1087 if ( start < 0 || compare(start, npos, suffix) != 0 )
3affcd07
VZ
1088 return false;
1089
1090 if ( rest )
1091 {
1092 // put the rest of the string into provided pointer
1093 rest->assign(*this, 0, start);
1094 }
1095
1096 return true;
1097}
1098
1099
c801d85f
KB
1100// extract nCount last (rightmost) characters
1101wxString wxString::Right(size_t nCount) const
1102{
e87b7833
MB
1103 if ( nCount > length() )
1104 nCount = length();
c801d85f 1105
e87b7833
MB
1106 wxString dest(*this, length() - nCount, nCount);
1107 if ( dest.length() != nCount ) {
b1801e0e
GD
1108 wxFAIL_MSG( _T("out of memory in wxString::Right") );
1109 }
c801d85f
KB
1110 return dest;
1111}
1112
1113// get all characters after the last occurence of ch
1114// (returns the whole string if ch not found)
c9f78968 1115wxString wxString::AfterLast(wxUniChar ch) const
c801d85f
KB
1116{
1117 wxString str;
d775fa82 1118 int iPos = Find(ch, true);
3c67202d 1119 if ( iPos == wxNOT_FOUND )
c801d85f
KB
1120 str = *this;
1121 else
c9f78968 1122 str = wx_str() + iPos + 1;
c801d85f
KB
1123
1124 return str;
1125}
1126
1127// extract nCount first (leftmost) characters
1128wxString wxString::Left(size_t nCount) const
1129{
e87b7833
MB
1130 if ( nCount > length() )
1131 nCount = length();
c801d85f 1132
e87b7833
MB
1133 wxString dest(*this, 0, nCount);
1134 if ( dest.length() != nCount ) {
b1801e0e
GD
1135 wxFAIL_MSG( _T("out of memory in wxString::Left") );
1136 }
c801d85f
KB
1137 return dest;
1138}
1139
1140// get all characters before the first occurence of ch
1141// (returns the whole string if ch not found)
c9f78968 1142wxString wxString::BeforeFirst(wxUniChar ch) const
c801d85f 1143{
e87b7833
MB
1144 int iPos = Find(ch);
1145 if ( iPos == wxNOT_FOUND ) iPos = length();
1146 return wxString(*this, 0, iPos);
c801d85f
KB
1147}
1148
1149/// get all characters before the last occurence of ch
1150/// (returns empty string if ch not found)
c9f78968 1151wxString wxString::BeforeLast(wxUniChar ch) const
c801d85f
KB
1152{
1153 wxString str;
d775fa82 1154 int iPos = Find(ch, true);
3c67202d 1155 if ( iPos != wxNOT_FOUND && iPos != 0 )
d1c9bbf6 1156 str = wxString(c_str(), iPos);
c801d85f
KB
1157
1158 return str;
1159}
1160
1161/// get all characters after the first occurence of ch
1162/// (returns empty string if ch not found)
c9f78968 1163wxString wxString::AfterFirst(wxUniChar ch) const
c801d85f
KB
1164{
1165 wxString str;
1166 int iPos = Find(ch);
3c67202d 1167 if ( iPos != wxNOT_FOUND )
c9f78968 1168 str = wx_str() + iPos + 1;
c801d85f
KB
1169
1170 return str;
1171}
1172
1173// replace first (or all) occurences of some substring with another one
8a540c88
VS
1174size_t wxString::Replace(const wxString& strOld,
1175 const wxString& strNew, bool bReplaceAll)
c801d85f 1176{
a8f1f1b2 1177 // if we tried to replace an empty string we'd enter an infinite loop below
8a540c88 1178 wxCHECK_MSG( !strOld.empty(), 0,
a8f1f1b2
VZ
1179 _T("wxString::Replace(): invalid parameter") );
1180
510bb748 1181 size_t uiCount = 0; // count of replacements made
c801d85f 1182
8a540c88
VS
1183 size_t uiOldLen = strOld.length();
1184 size_t uiNewLen = strNew.length();
c801d85f 1185
510bb748 1186 size_t dwPos = 0;
c801d85f 1187
8a540c88 1188 while ( (*this)[dwPos] != wxT('\0') )
510bb748
RN
1189 {
1190 //DO NOT USE STRSTR HERE
1191 //this string can contain embedded null characters,
1192 //so strstr will function incorrectly
8a540c88 1193 dwPos = find(strOld, dwPos);
ad5bb7d6 1194 if ( dwPos == npos )
510bb748 1195 break; // exit the loop
ad5bb7d6 1196 else
510bb748
RN
1197 {
1198 //replace this occurance of the old string with the new one
8a540c88 1199 replace(dwPos, uiOldLen, strNew, uiNewLen);
510bb748 1200
2df0258e
RN
1201 //move up pos past the string that was replaced
1202 dwPos += uiNewLen;
510bb748
RN
1203
1204 //increase replace count
1205 ++uiCount;
ad5bb7d6 1206
510bb748 1207 // stop now?
ad5bb7d6 1208 if ( !bReplaceAll )
510bb748
RN
1209 break; // exit the loop
1210 }
c801d85f 1211 }
c801d85f 1212
510bb748 1213 return uiCount;
c801d85f
KB
1214}
1215
1216bool wxString::IsAscii() const
1217{
a4a44612
VS
1218 for ( const_iterator i = begin(); i != end(); ++i )
1219 {
1220 if ( !(*i).IsAscii() )
1221 return false;
1222 }
1223
1224 return true;
c801d85f 1225}
dd1eaa89 1226
c801d85f
KB
1227bool wxString::IsWord() const
1228{
a4a44612
VS
1229 for ( const_iterator i = begin(); i != end(); ++i )
1230 {
1231 if ( !wxIsalpha(*i) )
1232 return false;
1233 }
1234
1235 return true;
c801d85f 1236}
dd1eaa89 1237
c801d85f
KB
1238bool wxString::IsNumber() const
1239{
a4a44612
VS
1240 if ( empty() )
1241 return true;
1242
1243 const_iterator i = begin();
1244
1245 if ( *i == _T('-') || *i == _T('+') )
1246 ++i;
1247
1248 for ( ; i != end(); ++i )
1249 {
1250 if ( !wxIsdigit(*i) )
1251 return false;
1252 }
1253
1254 return true;
c801d85f
KB
1255}
1256
c801d85f
KB
1257wxString wxString::Strip(stripType w) const
1258{
1259 wxString s = *this;
d775fa82
WS
1260 if ( w & leading ) s.Trim(false);
1261 if ( w & trailing ) s.Trim(true);
c801d85f
KB
1262 return s;
1263}
1264
c801d85f
KB
1265// ---------------------------------------------------------------------------
1266// case conversion
1267// ---------------------------------------------------------------------------
1268
1269wxString& wxString::MakeUpper()
1270{
e87b7833
MB
1271 for ( iterator it = begin(), en = end(); it != en; ++it )
1272 *it = (wxChar)wxToupper(*it);
c801d85f
KB
1273
1274 return *this;
1275}
1276
1277wxString& wxString::MakeLower()
1278{
e87b7833
MB
1279 for ( iterator it = begin(), en = end(); it != en; ++it )
1280 *it = (wxChar)wxTolower(*it);
c801d85f
KB
1281
1282 return *this;
1283}
1284
1285// ---------------------------------------------------------------------------
1286// trimming and padding
1287// ---------------------------------------------------------------------------
1288
d775fa82 1289// some compilers (VC++ 6.0 not to name them) return true for a call to
576c608d
VZ
1290