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