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