]> git.saurik.com Git - wxWidgets.git/blame - src/common/string.cpp
Corrected dangerous cast.
[wxWidgets.git] / src / common / string.cpp
CommitLineData
c801d85f
KB
1/////////////////////////////////////////////////////////////////////////////
2// Name: string.cpp
3// Purpose: wxString class
4// Author: Vadim Zeitlin
5// Modified by:
6// Created: 29/01/98
7// RCS-ID: $Id$
8// Copyright: (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
dd1eaa89 9// Licence: wxWindows license
c801d85f
KB
10/////////////////////////////////////////////////////////////////////////////
11
12#ifdef __GNUG__
30b21f9a 13 #pragma implementation "string.h"
c801d85f
KB
14#endif
15
16/*
17 * About ref counting:
18 * 1) all empty strings use g_strEmpty, nRefs = -1 (set in Init())
19 * 2) AllocBuffer() sets nRefs to 1, Lock() increments it by one
20 * 3) Unlock() decrements nRefs and frees memory if it goes to 0
21 */
22
23// ===========================================================================
24// headers, declarations, constants
25// ===========================================================================
26
27// For compilers that support precompilation, includes "wx.h".
28#include "wx/wxprec.h"
29
30#ifdef __BORLANDC__
30b21f9a 31 #pragma hdrstop
c801d85f
KB
32#endif
33
34#ifndef WX_PRECOMP
3c024cc2
VZ
35 #include "wx/defs.h"
36 #include "wx/string.h"
37 #include "wx/intl.h"
3096bd2f 38 #include "wx/thread.h"
6b769f3d 39#endif
c801d85f
KB
40
41#include <ctype.h>
42#include <string.h>
43#include <stdlib.h>
44
ce3ed50d 45#ifdef __SALFORDC__
30b21f9a 46 #include <clib.h>
ce3ed50d
JS
47#endif
48
ec2ba3aa 49#if wxUSE_UNICODE
5737d05f 50 #undef wxUSE_EXPERIMENTAL_PRINTF
a59c124d
RR
51 #ifndef wvsnprintf
52 #define wxUSE_EXPERIMENTAL_PRINTF 1
53 #endif
ec2ba3aa
OK
54#endif
55
3168a13f
VZ
56// allocating extra space for each string consumes more memory but speeds up
57// the concatenation operations (nLen is the current string's length)
77ca46e7
VZ
58// NB: EXTRA_ALLOC must be >= 0!
59#define EXTRA_ALLOC (19 - nLen % 16)
3168a13f 60
c801d85f
KB
61// ---------------------------------------------------------------------------
62// static class variables definition
63// ---------------------------------------------------------------------------
64
75ad8feb
DW
65#if defined(__VISAGECPP__) && __IBMCPP__ >= 400
66// must define this static for VA or else you get multiply defined symbols
67// everywhere
68const unsigned int wxSTRING_MAXLEN = UINT_MAX - 100;
69#endif // Visual Age
70
8de2e39c 71#ifdef wxSTD_STRING_COMPATIBILITY
566b84d2 72 const size_t wxString::npos = wxSTRING_MAXLEN;
8de2e39c 73#endif // wxSTD_STRING_COMPATIBILITY
c801d85f 74
3168a13f
VZ
75// ----------------------------------------------------------------------------
76// static data
77// ----------------------------------------------------------------------------
c801d85f 78
3c024cc2
VZ
79// for an empty string, GetStringData() will return this address: this
80// structure has the same layout as wxStringData and it's data() method will
81// return the empty string (dummy pointer)
82static const struct
83{
84 wxStringData data;
2bb67b80 85 wxChar dummy;
223d09f6 86} g_strEmpty = { {-1, 0, 0}, wxT('\0') };
3c024cc2 87
c801d85f 88// empty C style string: points to 'string data' byte of g_strEmpty
e90c1d2a 89extern const wxChar WXDLLEXPORT *wxEmptyString = &g_strEmpty.dummy;
c801d85f 90
89b892a2
VZ
91// ----------------------------------------------------------------------------
92// conditional compilation
93// ----------------------------------------------------------------------------
94
dcf924a3
RR
95#if !defined(__WXSW__) && wxUSE_UNICODE
96 #ifdef wxUSE_EXPERIMENTAL_PRINTF
97 #undef wxUSE_EXPERIMENTAL_PRINTF
98 #endif
99 #define wxUSE_EXPERIMENTAL_PRINTF 1
100#endif
101
89b892a2
VZ
102// we want to find out if the current platform supports vsnprintf()-like
103// function: for Unix this is done with configure, for Windows we test the
104// compiler explicitly.
378b05f7
VZ
105//
106// FIXME currently, this is only for ANSI (!Unicode) strings, so we call this
107// function wxVsnprintfA (A for ANSI), should also find one for Unicode
108// strings in Unicode build
89b892a2 109#ifdef __WXMSW__
012286eb 110 #if defined(__VISUALC__) || (defined(__MINGW32__) && wxUSE_NORLANDER_HEADERS)
378b05f7 111 #define wxVsnprintfA _vsnprintf
89b892a2 112 #endif
03e11df5
GD
113#elif defined(__WXMAC__)
114 #define wxVsnprintfA vsnprintf
89b892a2
VZ
115#else // !Windows
116 #ifdef HAVE_VSNPRINTF
378b05f7 117 #define wxVsnprintfA vsnprintf
89b892a2
VZ
118 #endif
119#endif // Windows/!Windows
120
378b05f7 121#ifndef wxVsnprintfA
89b892a2
VZ
122 // in this case we'll use vsprintf() (which is ANSI and thus should be
123 // always available), but it's unsafe because it doesn't check for buffer
124 // size - so give a warning
378b05f7 125 #define wxVsnprintfA(buf, len, format, arg) vsprintf(buf, format, arg)
566b84d2 126
57493f9f
VZ
127 #if defined(__VISUALC__)
128 #pragma message("Using sprintf() because no snprintf()-like function defined")
03e11df5 129 #elif defined(__GNUG__)
378b05f7 130 #warning "Using sprintf() because no snprintf()-like function defined"
57493f9f 131 #endif //compiler
3f4a0c5b 132#endif // no vsnprintf
89b892a2 133
783fab59 134#if defined(_AIX)
227b5cd7
VZ
135 // AIX has vsnprintf, but there's no prototype in the system headers.
136 extern "C" int vsnprintf(char* str, size_t n, const char* format, va_list ap);
137#endif
138
3168a13f 139// ----------------------------------------------------------------------------
c801d85f 140// global functions
3168a13f 141// ----------------------------------------------------------------------------
c801d85f 142
a533f5c1 143#if defined(wxSTD_STRING_COMPATIBILITY) && wxUSE_STD_IOSTREAM
c801d85f
KB
144
145// MS Visual C++ version 5.0 provides the new STL headers as well as the old
146// iostream ones.
147//
148// ATTN: you can _not_ use both of these in the same program!
a38b83c3 149
dd107c50 150wxSTD istream& operator>>(wxSTD istream& is, wxString& WXUNUSED(str))
c801d85f
KB
151{
152#if 0
153 int w = is.width(0);
154 if ( is.ipfx(0) ) {
3f4a0c5b 155 streambuf *sb = is.rdbuf();
c801d85f
KB
156 str.erase();
157 while ( true ) {
158 int ch = sb->sbumpc ();
159 if ( ch == EOF ) {
3f4a0c5b 160 is.setstate(ios::eofbit);
c801d85f
KB
161 break;
162 }
163 else if ( isspace(ch) ) {
164 sb->sungetc();
165 break;
166 }
dd1eaa89 167
c801d85f
KB
168 str += ch;
169 if ( --w == 1 )
170 break;
171 }
172 }
173
174 is.isfx();
175 if ( str.length() == 0 )
3f4a0c5b 176 is.setstate(ios::failbit);
c801d85f
KB
177#endif
178 return is;
179}
180
dd107c50 181wxSTD ostream& operator<<(wxSTD ostream& os, const wxString& str)
825ba8f0
SB
182{
183 os << str.c_str();
184 return os;
185}
186
c801d85f
KB
187#endif //std::string compatibility
188
a59c124d
RR
189#ifndef wxVsnprintf
190int WXDLLEXPORT wxVsnprintf(wxChar *buf, size_t len,
191 const wxChar *format, va_list argptr)
378b05f7
VZ
192{
193#if wxUSE_UNICODE
378b05f7
VZ
194 wxString s;
195 int iLen = s.PrintfV(format, argptr);
196 if ( iLen != -1 )
197 {
7f017c64
VZ
198 wxStrncpy(buf, s.c_str(), len);
199 buf[len-1] = wxT('\0');
378b05f7
VZ
200 }
201
202 return iLen;
203#else // ANSI
b568d04f
VZ
204 // vsnprintf() will not terminate the string with '\0' if there is not
205 // enough place, but we want the string to always be NUL terminated
206 int rc = wxVsnprintfA(buf, len - 1, format, argptr);
2f02cb89
VZ
207 if ( rc == -1 )
208 {
209 buf[len] = 0;
210 }
b568d04f
VZ
211
212 return rc;
378b05f7
VZ
213#endif // Unicode/ANSI
214}
a59c124d
RR
215#else
216// GNU libc 2.2 only has for wxVsnprintf for Unicode called vswprintf
217// so we imitate wxVsprintf using it.
218int WXDLLEXPORT wxVsprintf(wxChar *buf,
219 const wxChar *format,
220 va_list argptr)
221{
222 return vswprintf( buf, 10000, format, argptr );
223}
224#endif
378b05f7 225
a59c124d
RR
226#ifndef wxSnprintf
227int WXDLLEXPORT wxSnprintf(wxChar *buf, size_t len,
228 const wxChar *format, ...)
378b05f7
VZ
229{
230 va_list argptr;
231 va_start(argptr, format);
232
233 int iLen = wxVsnprintf(buf, len, format, argptr);
234
235 va_end(argptr);
236
237 return iLen;
238}
a59c124d
RR
239#else
240// GNU libc 2.2 only has for wxSnprintf for Unicode called swprintf
241// so we imitate wxSprintf using it.
242int WXDLLEXPORT wxSprintf(wxChar *buf,
243 const wxChar *format,
244 ...) ATTRIBUTE_PRINTF_2
245{
246 va_list argptr;
247 va_start(argptr, format);
248
249 int iLen = swprintf(buf, 10000, format, argptr);
250
251 va_end(argptr);
252
253 return iLen;
254}
255#endif
378b05f7 256
3168a13f
VZ
257// ----------------------------------------------------------------------------
258// private classes
259// ----------------------------------------------------------------------------
260
261// this small class is used to gather statistics for performance tuning
262//#define WXSTRING_STATISTICS
263#ifdef WXSTRING_STATISTICS
264 class Averager
265 {
266 public:
267 Averager(const char *sz) { m_sz = sz; m_nTotal = m_nCount = 0; }
2c3b684c 268 ~Averager()
3168a13f
VZ
269 { printf("wxString: average %s = %f\n", m_sz, ((float)m_nTotal)/m_nCount); }
270
c86f1403 271 void Add(size_t n) { m_nTotal += n; m_nCount++; }
3168a13f
VZ
272
273 private:
c86f1403 274 size_t m_nCount, m_nTotal;
3168a13f
VZ
275 const char *m_sz;
276 } g_averageLength("allocation size"),
277 g_averageSummandLength("summand length"),
278 g_averageConcatHit("hit probability in concat"),
279 g_averageInitialLength("initial string length");
280
281 #define STATISTICS_ADD(av, val) g_average##av.Add(val)
282#else
283 #define STATISTICS_ADD(av, val)
284#endif // WXSTRING_STATISTICS
285
c801d85f
KB
286// ===========================================================================
287// wxString class core
288// ===========================================================================
289
290// ---------------------------------------------------------------------------
291// construction
292// ---------------------------------------------------------------------------
293
c801d85f 294// constructs string of <nLength> copies of character <ch>
2bb67b80 295wxString::wxString(wxChar ch, size_t nLength)
c801d85f
KB
296{
297 Init();
298
299 if ( nLength > 0 ) {
b1801e0e
GD
300 if ( !AllocBuffer(nLength) ) {
301 wxFAIL_MSG( _T("out of memory in wxString::wxString") );
302 return;
303 }
f1da2f03 304
2bb67b80
OK
305#if wxUSE_UNICODE
306 // memset only works on char
307 for (size_t n=0; n<nLength; n++) m_pchData[n] = ch;
308#else
c801d85f 309 memset(m_pchData, ch, nLength);
2bb67b80 310#endif
c801d85f
KB
311 }
312}
313
314// takes nLength elements of psz starting at nPos
2bb67b80 315void wxString::InitWith(const wxChar *psz, size_t nPos, size_t nLength)
c801d85f
KB
316{
317 Init();
318
f6bcfd97
BP
319 // if the length is not given, assume the string to be NUL terminated
320 if ( nLength == wxSTRING_MAXLEN ) {
321 wxASSERT_MSG( nPos <= wxStrlen(psz), _T("index out of bounds") );
c801d85f 322
f6bcfd97
BP
323 nLength = wxStrlen(psz + nPos);
324 }
6c68273f 325
3168a13f
VZ
326 STATISTICS_ADD(InitialLength, nLength);
327
c801d85f
KB
328 if ( nLength > 0 ) {
329 // trailing '\0' is written in AllocBuffer()
b1801e0e
GD
330 if ( !AllocBuffer(nLength) ) {
331 wxFAIL_MSG( _T("out of memory in wxString::InitWith") );
332 return;
333 }
2bb67b80 334 memcpy(m_pchData, psz + nPos, nLength*sizeof(wxChar));
c801d85f
KB
335 }
336}
dd1eaa89 337
8de2e39c 338#ifdef wxSTD_STRING_COMPATIBILITY
c801d85f 339
c801d85f
KB
340// poor man's iterators are "void *" pointers
341wxString::wxString(const void *pStart, const void *pEnd)
342{
2bb67b80
OK
343 InitWith((const wxChar *)pStart, 0,
344 (const wxChar *)pEnd - (const wxChar *)pStart);
c801d85f
KB
345}
346
347#endif //std::string compatibility
348
2bb67b80
OK
349#if wxUSE_UNICODE
350
351// from multibyte string
cf2f341a 352wxString::wxString(const char *psz, wxMBConv& conv, size_t nLength)
2bb67b80
OK
353{
354 // first get necessary size
435595e0 355 size_t nLen = psz ? conv.MB2WC((wchar_t *) NULL, psz, 0) : 0;
2bb67b80
OK
356
357 // nLength is number of *Unicode* characters here!
eea4f86a 358 if ((nLen != (size_t)-1) && (nLen > nLength))
2bb67b80
OK
359 nLen = nLength;
360
361 // empty?
eea4f86a 362 if ( (nLen != 0) && (nLen != (size_t)-1) ) {
b1801e0e
GD
363 if ( !AllocBuffer(nLen) ) {
364 wxFAIL_MSG( _T("out of memory in wxString::wxString") );
365 return;
366 }
2bb67b80
OK
367 conv.MB2WC(m_pchData, psz, nLen);
368 }
369 else {
370 Init();
371 }
372}
373
e90c1d2a 374#else // ANSI
2bb67b80 375
0f3e3e0c 376#if wxUSE_WCHAR_T
c801d85f 377// from wide string
1c2e6a28 378wxString::wxString(const wchar_t *pwz, wxMBConv& conv, size_t nLength)
c801d85f
KB
379{
380 // first get necessary size
1c2e6a28
VS
381 size_t nLen = 0;
382 if (pwz)
383 {
384 if (nLength == wxSTRING_MAXLEN)
385 nLen = conv.WC2MB((char *) NULL, pwz, 0);
386 else
387 nLen = nLength;
388 }
c801d85f
KB
389
390 // empty?
eea4f86a 391 if ( (nLen != 0) && (nLen != (size_t)-1) ) {
b1801e0e
GD
392 if ( !AllocBuffer(nLen) ) {
393 wxFAIL_MSG( _T("out of memory in wxString::wxString") );
394 return;
395 }
f6bcfd97 396 conv.WC2MB(m_pchData, pwz, nLen);
c801d85f
KB
397 }
398 else {
399 Init();
400 }
401}
e90c1d2a 402#endif // wxUSE_WCHAR_T
c801d85f 403
e90c1d2a 404#endif // Unicode/ANSI
2bb67b80 405
c801d85f
KB
406// ---------------------------------------------------------------------------
407// memory allocation
408// ---------------------------------------------------------------------------
409
410// allocates memory needed to store a C string of length nLen
b1801e0e 411bool wxString::AllocBuffer(size_t nLen)
c801d85f 412{
13111b2a
VZ
413 // allocating 0 sized buffer doesn't make sense, all empty strings should
414 // reuse g_strEmpty
415 wxASSERT( nLen > 0 );
416
417 // make sure that we don't overflow
418 wxASSERT( nLen < (INT_MAX / sizeof(wxChar)) -
419 (sizeof(wxStringData) + EXTRA_ALLOC + 1) );
c801d85f 420
3168a13f
VZ
421 STATISTICS_ADD(Length, nLen);
422
c801d85f
KB
423 // allocate memory:
424 // 1) one extra character for '\0' termination
425 // 2) sizeof(wxStringData) for housekeeping info
3168a13f 426 wxStringData* pData = (wxStringData*)
2bb67b80 427 malloc(sizeof(wxStringData) + (nLen + EXTRA_ALLOC + 1)*sizeof(wxChar));
b1801e0e
GD
428
429 if ( pData == NULL ) {
430 // allocation failures are handled by the caller
431 return FALSE;
432 }
433
c801d85f 434 pData->nRefs = 1;
c801d85f 435 pData->nDataLength = nLen;
3168a13f 436 pData->nAllocLength = nLen + EXTRA_ALLOC;
c801d85f 437 m_pchData = pData->data(); // data starts after wxStringData
223d09f6 438 m_pchData[nLen] = wxT('\0');
b1801e0e 439 return TRUE;
c801d85f
KB
440}
441
c801d85f 442// must be called before changing this string
b1801e0e 443bool wxString::CopyBeforeWrite()
c801d85f
KB
444{
445 wxStringData* pData = GetStringData();
446
447 if ( pData->IsShared() ) {
448 pData->Unlock(); // memory not freed because shared
c86f1403 449 size_t nLen = pData->nDataLength;
b1801e0e
GD
450 if ( !AllocBuffer(nLen) ) {
451 // allocation failures are handled by the caller
452 return FALSE;
453 }
2bb67b80 454 memcpy(m_pchData, pData->data(), nLen*sizeof(wxChar));
c801d85f
KB
455 }
456
3bbb630a 457 wxASSERT( !GetStringData()->IsShared() ); // we must be the only owner
b1801e0e
GD
458
459 return TRUE;
c801d85f
KB
460}
461
462// must be called before replacing contents of this string
b1801e0e 463bool wxString::AllocBeforeWrite(size_t nLen)
c801d85f
KB
464{
465 wxASSERT( nLen != 0 ); // doesn't make any sense
466
467 // must not share string and must have enough space
3168a13f 468 wxStringData* pData = GetStringData();
fbf0c83d 469 if ( pData->IsShared() || pData->IsEmpty() ) {
c801d85f
KB
470 // can't work with old buffer, get new one
471 pData->Unlock();
b1801e0e
GD
472 if ( !AllocBuffer(nLen) ) {
473 // allocation failures are handled by the caller
474 return FALSE;
475 }
c801d85f 476 }
471aebdd 477 else {
fbf0c83d
VZ
478 if ( nLen > pData->nAllocLength ) {
479 // realloc the buffer instead of calling malloc() again, this is more
480 // efficient
481 STATISTICS_ADD(Length, nLen);
482
483 nLen += EXTRA_ALLOC;
484
fbf0c83d
VZ
485 pData = (wxStringData*)
486 realloc(pData, sizeof(wxStringData) + (nLen + 1)*sizeof(wxChar));
b1801e0e
GD
487
488 if ( pData == NULL ) {
489 // allocation failures are handled by the caller
490 // keep previous data since reallocation failed
491 return FALSE;
fbf0c83d
VZ
492 }
493
494 pData->nAllocLength = nLen;
495 m_pchData = pData->data();
496 }
497
498 // now we have enough space, just update the string length
471aebdd
VZ
499 pData->nDataLength = nLen;
500 }
c801d85f 501
f1da2f03 502 wxASSERT( !GetStringData()->IsShared() ); // we must be the only owner
b1801e0e
GD
503
504 return TRUE;
c801d85f
KB
505}
506
dd1eaa89 507// allocate enough memory for nLen characters
b1801e0e 508bool wxString::Alloc(size_t nLen)
dd1eaa89
VZ
509{
510 wxStringData *pData = GetStringData();
511 if ( pData->nAllocLength <= nLen ) {
9fbd8b8d
VZ
512 if ( pData->IsEmpty() ) {
513 nLen += EXTRA_ALLOC;
514
515 wxStringData* pData = (wxStringData*)
b1801e0e
GD
516 malloc(sizeof(wxStringData) + (nLen + 1)*sizeof(wxChar));
517
518 if ( pData == NULL ) {
519 // allocation failure handled by caller
520 return FALSE;
521 }
522
9fbd8b8d
VZ
523 pData->nRefs = 1;
524 pData->nDataLength = 0;
525 pData->nAllocLength = nLen;
526 m_pchData = pData->data(); // data starts after wxStringData
223d09f6 527 m_pchData[0u] = wxT('\0');
9fbd8b8d 528 }
3168a13f
VZ
529 else if ( pData->IsShared() ) {
530 pData->Unlock(); // memory not freed because shared
c86f1403 531 size_t nOldLen = pData->nDataLength;
b1801e0e
GD
532 if ( !AllocBuffer(nLen) ) {
533 // allocation failure handled by caller
534 return FALSE;
535 }
2bb67b80 536 memcpy(m_pchData, pData->data(), nOldLen*sizeof(wxChar));
3168a13f 537 }
dd1eaa89 538 else {
3168a13f
VZ
539 nLen += EXTRA_ALLOC;
540
b1801e0e 541 pData = (wxStringData *)
2bb67b80 542 realloc(pData, sizeof(wxStringData) + (nLen + 1)*sizeof(wxChar));
3168a13f 543
b1801e0e
GD
544 if ( pData == NULL ) {
545 // allocation failure handled by caller
546 // keep previous data since reallocation failed
547 return FALSE;
dd1eaa89 548 }
3168a13f
VZ
549
550 // it's not important if the pointer changed or not (the check for this
551 // is not faster than assigning to m_pchData in all cases)
b1801e0e
GD
552 pData->nAllocLength = nLen;
553 m_pchData = pData->data();
dd1eaa89
VZ
554 }
555 }
556 //else: we've already got enough
b1801e0e 557 return TRUE;
dd1eaa89
VZ
558}
559
560// shrink to minimal size (releasing extra memory)
b1801e0e 561bool wxString::Shrink()
dd1eaa89
VZ
562{
563 wxStringData *pData = GetStringData();
3bbb630a 564
337a0010
VZ
565 size_t nLen = pData->nDataLength;
566 void *p = realloc(pData, sizeof(wxStringData) + (nLen + 1)*sizeof(wxChar));
567
b1801e0e
GD
568 if ( p == NULL) {
569 wxFAIL_MSG( _T("out of memory reallocating wxString data") );
570 // keep previous data since reallocation failed
571 return FALSE;
572 }
337a0010
VZ
573
574 if ( p != pData )
575 {
576 // contrary to what one might believe, some realloc() implementation do
577 // move the memory block even when its size is reduced
578 pData = (wxStringData *)p;
3bbb630a 579
337a0010
VZ
580 m_pchData = pData->data();
581 }
fbf0c83d 582
337a0010 583 pData->nAllocLength = nLen;
b1801e0e
GD
584
585 return TRUE;
dd1eaa89
VZ
586}
587
c801d85f 588// get the pointer to writable buffer of (at least) nLen bytes
2bb67b80 589wxChar *wxString::GetWriteBuf(size_t nLen)
c801d85f 590{
b1801e0e
GD
591 if ( !AllocBeforeWrite(nLen) ) {
592 // allocation failure handled by caller
593 return NULL;
594 }
097c080b
VZ
595
596 wxASSERT( GetStringData()->nRefs == 1 );
597 GetStringData()->Validate(FALSE);
598
c801d85f
KB
599 return m_pchData;
600}
601
097c080b
VZ
602// put string back in a reasonable state after GetWriteBuf
603void wxString::UngetWriteBuf()
604{
2bb67b80 605 GetStringData()->nDataLength = wxStrlen(m_pchData);
097c080b
VZ
606 GetStringData()->Validate(TRUE);
607}
608
8f06a017
RD
609void wxString::UngetWriteBuf(size_t nLen)
610{
611 GetStringData()->nDataLength = nLen;
612 GetStringData()->Validate(TRUE);
613}
614
c801d85f
KB
615// ---------------------------------------------------------------------------
616// data access
617// ---------------------------------------------------------------------------
618
619// all functions are inline in string.h
620
621// ---------------------------------------------------------------------------
622// assignment operators
623// ---------------------------------------------------------------------------
624
dd1eaa89 625// helper function: does real copy
b1801e0e 626bool wxString::AssignCopy(size_t nSrcLen, const wxChar *pszSrcData)
c801d85f
KB
627{
628 if ( nSrcLen == 0 ) {
629 Reinit();
630 }
631 else {
b1801e0e
GD
632 if ( !AllocBeforeWrite(nSrcLen) ) {
633 // allocation failure handled by caller
634 return FALSE;
635 }
2bb67b80 636 memcpy(m_pchData, pszSrcData, nSrcLen*sizeof(wxChar));
c801d85f 637 GetStringData()->nDataLength = nSrcLen;
223d09f6 638 m_pchData[nSrcLen] = wxT('\0');
c801d85f 639 }
b1801e0e 640 return TRUE;
c801d85f
KB
641}
642
643// assigns one string to another
644wxString& wxString::operator=(const wxString& stringSrc)
645{
097c080b
VZ
646 wxASSERT( stringSrc.GetStringData()->IsValid() );
647
c801d85f
KB
648 // don't copy string over itself
649 if ( m_pchData != stringSrc.m_pchData ) {
650 if ( stringSrc.GetStringData()->IsEmpty() ) {
651 Reinit();
652 }
653 else {
654 // adjust references
655 GetStringData()->Unlock();
656 m_pchData = stringSrc.m_pchData;
657 GetStringData()->Lock();
658 }
659 }
660
661 return *this;
662}
663
664// assigns a single character
2bb67b80 665wxString& wxString::operator=(wxChar ch)
c801d85f 666{
b1801e0e
GD
667 if ( !AssignCopy(1, &ch) ) {
668 wxFAIL_MSG( _T("out of memory in wxString::operator=(wxChar)") );
669 }
c801d85f
KB
670 return *this;
671}
672
a3291804 673
c801d85f 674// assigns C string
2bb67b80 675wxString& wxString::operator=(const wxChar *psz)
c801d85f 676{
b1801e0e
GD
677 if ( !AssignCopy(wxStrlen(psz), psz) ) {
678 wxFAIL_MSG( _T("out of memory in wxString::operator=(const wxChar *)") );
679 }
c801d85f
KB
680 return *this;
681}
682
2bb67b80
OK
683#if !wxUSE_UNICODE
684
c801d85f
KB
685// same as 'signed char' variant
686wxString& wxString::operator=(const unsigned char* psz)
687{
688 *this = (const char *)psz;
689 return *this;
690}
691
0f3e3e0c 692#if wxUSE_WCHAR_T
c801d85f
KB
693wxString& wxString::operator=(const wchar_t *pwz)
694{
695 wxString str(pwz);
696 *this = str;
697 return *this;
698}
0f3e3e0c 699#endif
c801d85f 700
2bb67b80
OK
701#endif
702
c801d85f
KB
703// ---------------------------------------------------------------------------
704// string concatenation
705// ---------------------------------------------------------------------------
706
c801d85f 707// add something to this string
b1801e0e 708bool wxString::ConcatSelf(int nSrcLen, const wxChar *pszSrcData)
c801d85f 709{
3168a13f 710 STATISTICS_ADD(SummandLength, nSrcLen);
c801d85f 711
05488905
VZ
712 // concatenating an empty string is a NOP
713 if ( nSrcLen > 0 ) {
714 wxStringData *pData = GetStringData();
715 size_t nLen = pData->nDataLength;
716 size_t nNewLen = nLen + nSrcLen;
c801d85f 717
05488905
VZ
718 // alloc new buffer if current is too small
719 if ( pData->IsShared() ) {
720 STATISTICS_ADD(ConcatHit, 0);
3168a13f 721
05488905
VZ
722 // we have to allocate another buffer
723 wxStringData* pOldData = GetStringData();
b1801e0e
GD
724 if ( !AllocBuffer(nNewLen) ) {
725 // allocation failure handled by caller
726 return FALSE;
727 }
2bb67b80 728 memcpy(m_pchData, pOldData->data(), nLen*sizeof(wxChar));
05488905
VZ
729 pOldData->Unlock();
730 }
731 else if ( nNewLen > pData->nAllocLength ) {
732 STATISTICS_ADD(ConcatHit, 0);
3168a13f 733
05488905 734 // we have to grow the buffer
b1801e0e
GD
735 if ( !Alloc(nNewLen) ) {
736 // allocation failure handled by caller
737 return FALSE;
738 }
05488905
VZ
739 }
740 else {
741 STATISTICS_ADD(ConcatHit, 1);
3168a13f 742
05488905
VZ
743 // the buffer is already big enough
744 }
3168a13f 745
05488905
VZ
746 // should be enough space
747 wxASSERT( nNewLen <= GetStringData()->nAllocLength );
3168a13f 748
05488905 749 // fast concatenation - all is done in our buffer
2bb67b80 750 memcpy(m_pchData + nLen, pszSrcData, nSrcLen*sizeof(wxChar));
3168a13f 751
223d09f6 752 m_pchData[nNewLen] = wxT('\0'); // put terminating '\0'
05488905
VZ
753 GetStringData()->nDataLength = nNewLen; // and fix the length
754 }
755 //else: the string to append was empty
b1801e0e 756 return TRUE;
c801d85f
KB
757}
758
759/*
c801d85f
KB
760 * concatenation functions come in 5 flavours:
761 * string + string
762 * char + string and string + char
763 * C str + string and string + C str
764 */
765
b1801e0e 766wxString operator+(const wxString& str1, const wxString& str2)
c801d85f 767{
b1801e0e
GD
768 wxASSERT( str1.GetStringData()->IsValid() );
769 wxASSERT( str2.GetStringData()->IsValid() );
097c080b 770
b1801e0e
GD
771 wxString s = str1;
772 s += str2;
3168a13f 773
c801d85f
KB
774 return s;
775}
776
b1801e0e 777wxString operator+(const wxString& str, wxChar ch)
c801d85f 778{
b1801e0e 779 wxASSERT( str.GetStringData()->IsValid() );
3168a13f 780
b1801e0e 781 wxString s = str;
3168a13f 782 s += ch;
097c080b 783
c801d85f
KB
784 return s;
785}
786
b1801e0e 787wxString operator+(wxChar ch, const wxString& str)
c801d85f 788{
b1801e0e 789 wxASSERT( str.GetStringData()->IsValid() );
097c080b 790
3168a13f 791 wxString s = ch;
b1801e0e 792 s += str;
3168a13f 793
c801d85f
KB
794 return s;
795}
796
b1801e0e 797wxString operator+(const wxString& str, const wxChar *psz)
c801d85f 798{
b1801e0e 799 wxASSERT( str.GetStringData()->IsValid() );
097c080b 800
c801d85f 801 wxString s;
b1801e0e
GD
802 if ( !s.Alloc(wxStrlen(psz) + str.Len()) ) {
803 wxFAIL_MSG( _T("out of memory in wxString::operator+") );
804 }
805 s = str;
3168a13f
VZ
806 s += psz;
807
c801d85f
KB
808 return s;
809}
810
b1801e0e 811wxString operator+(const wxChar *psz, const wxString& str)
c801d85f 812{
b1801e0e 813 wxASSERT( str.GetStringData()->IsValid() );
097c080b 814
c801d85f 815 wxString s;
b1801e0e
GD
816 if ( !s.Alloc(wxStrlen(psz) + str.Len()) ) {
817 wxFAIL_MSG( _T("out of memory in wxString::operator+") );
818 }
3168a13f 819 s = psz;
b1801e0e 820 s += str;
3168a13f 821
c801d85f
KB
822 return s;
823}
824
825// ===========================================================================
826// other common string functions
827// ===========================================================================
828
b1ac3b56
RR
829#if wxUSE_UNICODE
830wxString wxString::FromAscii( char *ascii )
831{
832 if (!ascii)
833 return wxEmptyString;
834
835 size_t len = strlen( ascii );
836 wxString res;
837 res.AllocBuffer( len );
838 wchar_t *dest = (wchar_t*)(const wchar_t*) res.c_str();
839
840 for (size_t i = 0; i < len+1; i++)
841 dest[i] = (wchar_t) ascii[i];
842
843 return res;
844}
845
846const wxCharBuffer wxString::ToAscii() const
847{
848 if (IsNull())
849 return wxCharBuffer( (const char*)NULL );
850
851 size_t len = Len();
852 wxCharBuffer buffer( len ); // allocates len+1
853
854 char *dest = (char*)(const char*) buffer;
855
856 for (size_t i = 0; i < len+1; i++)
857 {
858 if (m_pchData[i] > 127)
859 dest[i] = '_';
860 else
861 dest[i] = (char) m_pchData[i];
862 }
863
864 return buffer;
865}
866#endif
867
c801d85f
KB
868// ---------------------------------------------------------------------------
869// simple sub-string extraction
870// ---------------------------------------------------------------------------
871
872// helper function: clone the data attached to this string
b1801e0e 873bool wxString::AllocCopy(wxString& dest, int nCopyLen, int nCopyIndex) const
c801d85f 874{
3168a13f 875 if ( nCopyLen == 0 ) {
c801d85f
KB
876 dest.Init();
877 }
3168a13f 878 else {
b1801e0e
GD
879 if ( !dest.AllocBuffer(nCopyLen) ) {
880 // allocation failure handled by caller
881 return FALSE;
882 }
2bb67b80 883 memcpy(dest.m_pchData, m_pchData + nCopyIndex, nCopyLen*sizeof(wxChar));
c801d85f 884 }
b1801e0e 885 return TRUE;
c801d85f
KB
886}
887
888// extract string of length nCount starting at nFirst
c801d85f
KB
889wxString wxString::Mid(size_t nFirst, size_t nCount) const
890{
30d9011f
VZ
891 wxStringData *pData = GetStringData();
892 size_t nLen = pData->nDataLength;
893
566b84d2
VZ
894 // default value of nCount is wxSTRING_MAXLEN and means "till the end"
895 if ( nCount == wxSTRING_MAXLEN )
30d9011f
VZ
896 {
897 nCount = nLen - nFirst;
898 }
899
c801d85f 900 // out-of-bounds requests return sensible things
30d9011f
VZ
901 if ( nFirst + nCount > nLen )
902 {
903 nCount = nLen - nFirst;
904 }
c801d85f 905
30d9011f
VZ
906 if ( nFirst > nLen )
907 {
908 // AllocCopy() will return empty string
c801d85f 909 nCount = 0;
30d9011f 910 }
c801d85f
KB
911
912 wxString dest;
b1801e0e
GD
913 if ( !AllocCopy(dest, nCount, nFirst) ) {
914 wxFAIL_MSG( _T("out of memory in wxString::Mid") );
915 }
30d9011f 916
c801d85f
KB
917 return dest;
918}
919
f6bcfd97
BP
920// check that the tring starts with prefix and return the rest of the string
921// in the provided pointer if it is not NULL, otherwise return FALSE
922bool wxString::StartsWith(const wxChar *prefix, wxString *rest) const
923{
924 wxASSERT_MSG( prefix, _T("invalid parameter in wxString::StartsWith") );
925
926 // first check if the beginning of the string matches the prefix: note
927 // that we don't have to check that we don't run out of this string as
928 // when we reach the terminating NUL, either prefix string ends too (and
929 // then it's ok) or we break out of the loop because there is no match
930 const wxChar *p = c_str();
931 while ( *prefix )
932 {
933 if ( *prefix++ != *p++ )
934 {
935 // no match
936 return FALSE;
937 }
938 }
939
940 if ( rest )
941 {
942 // put the rest of the string into provided pointer
943 *rest = p;
944 }
945
946 return TRUE;
947}
948
c801d85f
KB
949// extract nCount last (rightmost) characters
950wxString wxString::Right(size_t nCount) const
951{
952 if ( nCount > (size_t)GetStringData()->nDataLength )
953 nCount = GetStringData()->nDataLength;
954
955 wxString dest;
b1801e0e
GD
956 if ( !AllocCopy(dest, nCount, GetStringData()->nDataLength - nCount) ) {
957 wxFAIL_MSG( _T("out of memory in wxString::Right") );
958 }
c801d85f
KB
959 return dest;
960}
961
962// get all characters after the last occurence of ch
963// (returns the whole string if ch not found)
2bb67b80 964wxString wxString::AfterLast(wxChar ch) const
c801d85f
KB
965{
966 wxString str;
967 int iPos = Find(ch, TRUE);
3c67202d 968 if ( iPos == wxNOT_FOUND )
c801d85f
KB
969 str = *this;
970 else
c8cfb486 971 str = c_str() + iPos + 1;
c801d85f
KB
972
973 return str;
974}
975
976// extract nCount first (leftmost) characters
977wxString wxString::Left(size_t nCount) const
978{
979 if ( nCount > (size_t)GetStringData()->nDataLength )
980 nCount = GetStringData()->nDataLength;
981
982 wxString dest;
b1801e0e
GD
983 if ( !AllocCopy(dest, nCount, 0) ) {
984 wxFAIL_MSG( _T("out of memory in wxString::Left") );
985 }
c801d85f
KB
986 return dest;
987}
988
989// get all characters before the first occurence of ch
990// (returns the whole string if ch not found)
2bb67b80 991wxString wxString::BeforeFirst(wxChar ch) const
c801d85f
KB
992{
993 wxString str;
223d09f6 994 for ( const wxChar *pc = m_pchData; *pc != wxT('\0') && *pc != ch; pc++ )
c801d85f
KB
995 str += *pc;
996
997 return str;
998}
999
1000/// get all characters before the last occurence of ch
1001/// (returns empty string if ch not found)
2bb67b80 1002wxString wxString::BeforeLast(wxChar ch) const
c801d85f
KB
1003{
1004 wxString str;
1005 int iPos = Find(ch, TRUE);
3c67202d 1006 if ( iPos != wxNOT_FOUND && iPos != 0 )
d1c9bbf6 1007 str = wxString(c_str(), iPos);
c801d85f
KB
1008
1009 return str;
1010}
1011
1012/// get all characters after the first occurence of ch
1013/// (returns empty string if ch not found)
2bb67b80 1014wxString wxString::AfterFirst(wxChar ch) const
c801d85f
KB
1015{
1016 wxString str;
1017 int iPos = Find(ch);
3c67202d 1018 if ( iPos != wxNOT_FOUND )
c801d85f
KB
1019 str = c_str() + iPos + 1;
1020
1021 return str;
1022}
1023
1024// replace first (or all) occurences of some substring with another one
2bb67b80 1025size_t wxString::Replace(const wxChar *szOld, const wxChar *szNew, bool bReplaceAll)
c801d85f 1026{
c86f1403 1027 size_t uiCount = 0; // count of replacements made
c801d85f 1028
2bb67b80 1029 size_t uiOldLen = wxStrlen(szOld);
c801d85f
KB
1030
1031 wxString strTemp;
2bb67b80
OK
1032 const wxChar *pCurrent = m_pchData;
1033 const wxChar *pSubstr;
223d09f6 1034 while ( *pCurrent != wxT('\0') ) {
2bb67b80 1035 pSubstr = wxStrstr(pCurrent, szOld);
c801d85f
KB
1036 if ( pSubstr == NULL ) {
1037 // strTemp is unused if no replacements were made, so avoid the copy
1038 if ( uiCount == 0 )
1039 return 0;
1040
1041 strTemp += pCurrent; // copy the rest
1042 break; // exit the loop
1043 }
1044 else {
1045 // take chars before match
b1801e0e
GD
1046 if ( !strTemp.ConcatSelf(pSubstr - pCurrent, pCurrent) ) {
1047 wxFAIL_MSG( _T("out of memory in wxString::Replace") );
1048 return 0;
1049 }
c801d85f
KB
1050 strTemp += szNew;
1051 pCurrent = pSubstr + uiOldLen; // restart after match
1052
1053 uiCount++;
1054
1055 // stop now?
1056 if ( !bReplaceAll ) {
1057 strTemp += pCurrent; // copy the rest
1058 break; // exit the loop
1059 }
1060 }
1061 }
1062
1063 // only done if there were replacements, otherwise would have returned above
1064 *this = strTemp;
1065
1066 return uiCount;
1067}
1068
1069bool wxString::IsAscii() const
1070{
2bb67b80 1071 const wxChar *s = (const wxChar*) *this;
c801d85f
KB
1072 while(*s){
1073 if(!isascii(*s)) return(FALSE);
1074 s++;
1075 }
1076 return(TRUE);
1077}
dd1eaa89 1078
c801d85f
KB
1079bool wxString::IsWord() const
1080{
2bb67b80 1081 const wxChar *s = (const wxChar*) *this;
c801d85f 1082 while(*s){
2bb67b80 1083 if(!wxIsalpha(*s)) return(FALSE);
c801d85f
KB
1084 s++;
1085 }
1086 return(TRUE);
1087}
dd1eaa89 1088
c801d85f
KB
1089bool wxString::IsNumber() const
1090{
2bb67b80 1091 const wxChar *s = (const wxChar*) *this;
2f74ed28
GT
1092 if (wxStrlen(s))
1093 if ((s[0] == '-') || (s[0] == '+')) s++;
c801d85f 1094 while(*s){
2bb67b80 1095 if(!wxIsdigit(*s)) return(FALSE);
c801d85f
KB
1096 s++;
1097 }
1098 return(TRUE);
1099}
1100
c801d85f
KB
1101wxString wxString::Strip(stripType w) const
1102{
1103 wxString s = *this;
1104 if ( w & leading ) s.Trim(FALSE);
1105 if ( w & trailing ) s.Trim(TRUE);
1106 return s;
1107}
1108
c801d85f
KB
1109// ---------------------------------------------------------------------------
1110// case conversion
1111// ---------------------------------------------------------------------------
1112
1113wxString& wxString::MakeUpper()
1114{
b1801e0e
GD
1115 if ( !CopyBeforeWrite() ) {
1116 wxFAIL_MSG( _T("out of memory in wxString::MakeUpper") );
1117 return *this;
1118 }
1119
2bb67b80
OK
1120 for ( wxChar *p = m_pchData; *p; p++ )
1121 *p = (wxChar)wxToupper(*p);
c801d85f
KB
1122
1123 return *this;
1124}
1125
1126wxString& wxString::MakeLower()
1127{
b1801e0e
GD
1128 if ( !CopyBeforeWrite() ) {
1129 wxFAIL_MSG( _T("out of memory in wxString::MakeLower") );
1130 return *this;
1131 }
dd1eaa89 1132
2bb67b80
OK
1133 for ( wxChar *p = m_pchData; *p; p++ )
1134 *p = (wxChar)wxTolower(*p);
c801d85f
KB
1135
1136 return *this;
1137}
1138
1139// ---------------------------------------------------------------------------
1140// trimming and padding
1141// ---------------------------------------------------------------------------
1142
576c608d
VZ
1143// some compilers (VC++ 6.0 not to name them) return TRUE for a call to
1144