]> git.saurik.com Git - wxWidgets.git/blame - src/common/string.cpp
dlopen fixes
[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"
c801d85f
KB
38#endif
39
40#include <ctype.h>
41#include <string.h>
42#include <stdlib.h>
43
ce3ed50d 44#ifdef __SALFORDC__
30b21f9a 45 #include <clib.h>
ce3ed50d
JS
46#endif
47
ede25f5b 48#if wxUSE_WCSRTOMBS
fb4e5803
VZ
49 #include <wchar.h> // for wcsrtombs(), see comments where it's used
50#endif // GNU
51
c801d85f
KB
52#ifdef WXSTRING_IS_WXOBJECT
53 IMPLEMENT_DYNAMIC_CLASS(wxString, wxObject)
54#endif //WXSTRING_IS_WXOBJECT
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
8de2e39c 65#ifdef wxSTD_STRING_COMPATIBILITY
566b84d2 66 const size_t wxString::npos = wxSTRING_MAXLEN;
8de2e39c 67#endif // wxSTD_STRING_COMPATIBILITY
c801d85f 68
3168a13f
VZ
69// ----------------------------------------------------------------------------
70// static data
71// ----------------------------------------------------------------------------
c801d85f 72
3c024cc2
VZ
73// for an empty string, GetStringData() will return this address: this
74// structure has the same layout as wxStringData and it's data() method will
75// return the empty string (dummy pointer)
76static const struct
77{
78 wxStringData data;
79 char dummy;
80} g_strEmpty = { {-1, 0, 0}, '\0' };
81
c801d85f 82// empty C style string: points to 'string data' byte of g_strEmpty
ba681060 83extern const char WXDLLEXPORT *g_szNul = &g_strEmpty.dummy;
c801d85f 84
89b892a2
VZ
85// ----------------------------------------------------------------------------
86// conditional compilation
87// ----------------------------------------------------------------------------
88
89// we want to find out if the current platform supports vsnprintf()-like
90// function: for Unix this is done with configure, for Windows we test the
91// compiler explicitly.
92#ifdef __WXMSW__
3f4a0c5b 93 #ifdef __VISUALC__
89b892a2
VZ
94 #define wxVsprintf _vsnprintf
95 #endif
96#else // !Windows
97 #ifdef HAVE_VSNPRINTF
98 #define wxVsprintf vsnprintf
99 #endif
100#endif // Windows/!Windows
101
102#ifndef wxVsprintf
103 // in this case we'll use vsprintf() (which is ANSI and thus should be
104 // always available), but it's unsafe because it doesn't check for buffer
105 // size - so give a warning
106 #define wxVsprintf(buffer,len,format,argptr) vsprintf(buffer,format, argptr)
566b84d2 107#if defined(__VISUALC__)
89b892a2 108 #pragma message("Using sprintf() because no snprintf()-like function defined")
566b84d2
VZ
109#elif defined(__GNUG__)
110 #warning "Using sprintf() because no snprintf()-like function defined"
c3deb08b
JS
111#elif defined(__MWERKS__)
112 #warning "Using sprintf() because no snprintf()-like function defined"
dbda9e86
JS
113#elif defined(__WATCOMC__)
114 // No warning
115#elif defined(__BORLANDC__)
116 // No warning
566b84d2
VZ
117#elif defined(__SUNCC__)
118 // nothing -- I don't know about "#warning" for Sun's CC
64716cd7
VZ
119#elif defined(__DECCXX)
120 // nothing
566b84d2
VZ
121#else
122 // change this to some analogue of '#warning' for your compiler
123 #error "Using sprintf() because no snprintf()-like function defined"
124#endif //compiler
125
3f4a0c5b 126#endif // no vsnprintf
89b892a2 127
3168a13f 128// ----------------------------------------------------------------------------
c801d85f 129// global functions
3168a13f 130// ----------------------------------------------------------------------------
c801d85f 131
8de2e39c 132#ifdef wxSTD_STRING_COMPATIBILITY
c801d85f
KB
133
134// MS Visual C++ version 5.0 provides the new STL headers as well as the old
135// iostream ones.
136//
137// ATTN: you can _not_ use both of these in the same program!
a38b83c3 138
3f4a0c5b 139istream& operator>>(istream& is, wxString& WXUNUSED(str))
c801d85f
KB
140{
141#if 0
142 int w = is.width(0);
143 if ( is.ipfx(0) ) {
3f4a0c5b 144 streambuf *sb = is.rdbuf();
c801d85f
KB
145 str.erase();
146 while ( true ) {
147 int ch = sb->sbumpc ();
148 if ( ch == EOF ) {
3f4a0c5b 149 is.setstate(ios::eofbit);
c801d85f
KB
150 break;
151 }
152 else if ( isspace(ch) ) {
153 sb->sungetc();
154 break;
155 }
dd1eaa89 156
c801d85f
KB
157 str += ch;
158 if ( --w == 1 )
159 break;
160 }
161 }
162
163 is.isfx();
164 if ( str.length() == 0 )
3f4a0c5b 165 is.setstate(ios::failbit);
c801d85f
KB
166#endif
167 return is;
168}
169
170#endif //std::string compatibility
171
3168a13f
VZ
172// ----------------------------------------------------------------------------
173// private classes
174// ----------------------------------------------------------------------------
175
176// this small class is used to gather statistics for performance tuning
177//#define WXSTRING_STATISTICS
178#ifdef WXSTRING_STATISTICS
179 class Averager
180 {
181 public:
182 Averager(const char *sz) { m_sz = sz; m_nTotal = m_nCount = 0; }
2c3b684c 183 ~Averager()
3168a13f
VZ
184 { printf("wxString: average %s = %f\n", m_sz, ((float)m_nTotal)/m_nCount); }
185
c86f1403 186 void Add(size_t n) { m_nTotal += n; m_nCount++; }
3168a13f
VZ
187
188 private:
c86f1403 189 size_t m_nCount, m_nTotal;
3168a13f
VZ
190 const char *m_sz;
191 } g_averageLength("allocation size"),
192 g_averageSummandLength("summand length"),
193 g_averageConcatHit("hit probability in concat"),
194 g_averageInitialLength("initial string length");
195
196 #define STATISTICS_ADD(av, val) g_average##av.Add(val)
197#else
198 #define STATISTICS_ADD(av, val)
199#endif // WXSTRING_STATISTICS
200
c801d85f
KB
201// ===========================================================================
202// wxString class core
203// ===========================================================================
204
205// ---------------------------------------------------------------------------
206// construction
207// ---------------------------------------------------------------------------
208
c801d85f
KB
209// constructs string of <nLength> copies of character <ch>
210wxString::wxString(char ch, size_t nLength)
211{
212 Init();
213
214 if ( nLength > 0 ) {
215 AllocBuffer(nLength);
f1da2f03 216
c801d85f
KB
217 wxASSERT( sizeof(char) == 1 ); // can't use memset if not
218
219 memset(m_pchData, ch, nLength);
220 }
221}
222
223// takes nLength elements of psz starting at nPos
224void wxString::InitWith(const char *psz, size_t nPos, size_t nLength)
225{
226 Init();
227
228 wxASSERT( nPos <= Strlen(psz) );
229
566b84d2 230 if ( nLength == wxSTRING_MAXLEN )
c801d85f
KB
231 nLength = Strlen(psz + nPos);
232
3168a13f
VZ
233 STATISTICS_ADD(InitialLength, nLength);
234
c801d85f
KB
235 if ( nLength > 0 ) {
236 // trailing '\0' is written in AllocBuffer()
237 AllocBuffer(nLength);
238 memcpy(m_pchData, psz + nPos, nLength*sizeof(char));
239 }
240}
dd1eaa89 241
c801d85f
KB
242// the same as previous constructor, but for compilers using unsigned char
243wxString::wxString(const unsigned char* psz, size_t nLength)
244{
245 InitWith((const char *)psz, 0, nLength);
dd1eaa89
VZ
246}
247
8de2e39c 248#ifdef wxSTD_STRING_COMPATIBILITY
c801d85f 249
c801d85f
KB
250// poor man's iterators are "void *" pointers
251wxString::wxString(const void *pStart, const void *pEnd)
252{
dd1eaa89 253 InitWith((const char *)pStart, 0,
c801d85f
KB
254 (const char *)pEnd - (const char *)pStart);
255}
256
257#endif //std::string compatibility
258
259// from wide string
260wxString::wxString(const wchar_t *pwz)
261{
262 // first get necessary size
fb4e5803
VZ
263
264 // NB: GNU libc5 wcstombs() is completely broken, don't use it (it doesn't
265 // honor the 3rd parameter, thus it will happily crash here).
ede25f5b 266#if wxUSE_WCSRTOMBS
fb4e5803
VZ
267 // don't know if it's really needed (or if we can pass NULL), but better safe
268 // than quick
269 mbstate_t mbstate;
270 size_t nLen = wcsrtombs((char *) NULL, &pwz, 0, &mbstate);
271#else // !GNU libc
c67daf87 272 size_t nLen = wcstombs((char *) NULL, pwz, 0);
fb4e5803 273#endif // GNU
c801d85f
KB
274
275 // empty?
276 if ( nLen != 0 ) {
277 AllocBuffer(nLen);
278 wcstombs(m_pchData, pwz, nLen);
279 }
280 else {
281 Init();
282 }
283}
284
285// ---------------------------------------------------------------------------
286// memory allocation
287// ---------------------------------------------------------------------------
288
289// allocates memory needed to store a C string of length nLen
290void wxString::AllocBuffer(size_t nLen)
291{
292 wxASSERT( nLen > 0 ); //
293 wxASSERT( nLen <= INT_MAX-1 ); // max size (enough room for 1 extra)
294
3168a13f
VZ
295 STATISTICS_ADD(Length, nLen);
296
c801d85f
KB
297 // allocate memory:
298 // 1) one extra character for '\0' termination
299 // 2) sizeof(wxStringData) for housekeeping info
3168a13f
VZ
300 wxStringData* pData = (wxStringData*)
301 malloc(sizeof(wxStringData) + (nLen + EXTRA_ALLOC + 1)*sizeof(char));
c801d85f 302 pData->nRefs = 1;
c801d85f 303 pData->nDataLength = nLen;
3168a13f 304 pData->nAllocLength = nLen + EXTRA_ALLOC;
c801d85f 305 m_pchData = pData->data(); // data starts after wxStringData
3168a13f 306 m_pchData[nLen] = '\0';
c801d85f
KB
307}
308
c801d85f
KB
309// must be called before changing this string
310void wxString::CopyBeforeWrite()
311{
312 wxStringData* pData = GetStringData();
313
314 if ( pData->IsShared() ) {
315 pData->Unlock(); // memory not freed because shared
c86f1403 316 size_t nLen = pData->nDataLength;
3168a13f
VZ
317 AllocBuffer(nLen);
318 memcpy(m_pchData, pData->data(), nLen*sizeof(char));
c801d85f
KB
319 }
320
3bbb630a 321 wxASSERT( !GetStringData()->IsShared() ); // we must be the only owner
c801d85f
KB
322}
323
324// must be called before replacing contents of this string
325void wxString::AllocBeforeWrite(size_t nLen)
326{
327 wxASSERT( nLen != 0 ); // doesn't make any sense
328
329 // must not share string and must have enough space
3168a13f 330 wxStringData* pData = GetStringData();
c801d85f
KB
331 if ( pData->IsShared() || (nLen > pData->nAllocLength) ) {
332 // can't work with old buffer, get new one
333 pData->Unlock();
334 AllocBuffer(nLen);
335 }
471aebdd
VZ
336 else {
337 // update the string length
338 pData->nDataLength = nLen;
339 }
c801d85f 340
f1da2f03 341 wxASSERT( !GetStringData()->IsShared() ); // we must be the only owner
c801d85f
KB
342}
343
dd1eaa89 344// allocate enough memory for nLen characters
c86f1403 345void wxString::Alloc(size_t nLen)
dd1eaa89
VZ
346{
347 wxStringData *pData = GetStringData();
348 if ( pData->nAllocLength <= nLen ) {
9fbd8b8d
VZ
349 if ( pData->IsEmpty() ) {
350 nLen += EXTRA_ALLOC;
351
352 wxStringData* pData = (wxStringData*)
353 malloc(sizeof(wxStringData) + (nLen + 1)*sizeof(char));
354 pData->nRefs = 1;
355 pData->nDataLength = 0;
356 pData->nAllocLength = nLen;
357 m_pchData = pData->data(); // data starts after wxStringData
358 m_pchData[0u] = '\0';
359 }
3168a13f
VZ
360 else if ( pData->IsShared() ) {
361 pData->Unlock(); // memory not freed because shared
c86f1403 362 size_t nOldLen = pData->nDataLength;
3168a13f 363 AllocBuffer(nLen);
9fbd8b8d 364 memcpy(m_pchData, pData->data(), nOldLen*sizeof(char));
3168a13f 365 }
dd1eaa89 366 else {
3168a13f
VZ
367 nLen += EXTRA_ALLOC;
368
dd1eaa89
VZ
369 wxStringData *p = (wxStringData *)
370 realloc(pData, sizeof(wxStringData) + (nLen + 1)*sizeof(char));
3168a13f
VZ
371
372 if ( p == NULL ) {
373 // @@@ what to do on memory error?
374 return;
dd1eaa89 375 }
3168a13f
VZ
376
377 // it's not important if the pointer changed or not (the check for this
378 // is not faster than assigning to m_pchData in all cases)
379 p->nAllocLength = nLen;
380 m_pchData = p->data();
dd1eaa89
VZ
381 }
382 }
383 //else: we've already got enough
384}
385
386// shrink to minimal size (releasing extra memory)
387void wxString::Shrink()
388{
389 wxStringData *pData = GetStringData();
3bbb630a
VZ
390
391 // this variable is unused in release build, so avoid the compiler warning by
392 // just not declaring it
393#ifdef __WXDEBUG__
394 void *p =
395#endif
396 realloc(pData, sizeof(wxStringData) + (pData->nDataLength + 1)*sizeof(char));
397
3168a13f 398 wxASSERT( p != NULL ); // can't free memory?
dd1eaa89
VZ
399 wxASSERT( p == pData ); // we're decrementing the size - block shouldn't move!
400}
401
c801d85f 402// get the pointer to writable buffer of (at least) nLen bytes
c86f1403 403char *wxString::GetWriteBuf(size_t nLen)
c801d85f
KB
404{
405 AllocBeforeWrite(nLen);
097c080b
VZ
406
407 wxASSERT( GetStringData()->nRefs == 1 );
408 GetStringData()->Validate(FALSE);
409
c801d85f
KB
410 return m_pchData;
411}
412
097c080b
VZ
413// put string back in a reasonable state after GetWriteBuf
414void wxString::UngetWriteBuf()
415{
416 GetStringData()->nDataLength = strlen(m_pchData);
417 GetStringData()->Validate(TRUE);
418}
419
c801d85f
KB
420// ---------------------------------------------------------------------------
421// data access
422// ---------------------------------------------------------------------------
423
424// all functions are inline in string.h
425
426// ---------------------------------------------------------------------------
427// assignment operators
428// ---------------------------------------------------------------------------
429
dd1eaa89 430// helper function: does real copy
c801d85f
KB
431void wxString::AssignCopy(size_t nSrcLen, const char *pszSrcData)
432{
433 if ( nSrcLen == 0 ) {
434 Reinit();
435 }
436 else {
437 AllocBeforeWrite(nSrcLen);
438 memcpy(m_pchData, pszSrcData, nSrcLen*sizeof(char));
439 GetStringData()->nDataLength = nSrcLen;
440 m_pchData[nSrcLen] = '\0';
441 }
442}
443
444// assigns one string to another
445wxString& wxString::operator=(const wxString& stringSrc)
446{
097c080b
VZ
447 wxASSERT( stringSrc.GetStringData()->IsValid() );
448
c801d85f
KB
449 // don't copy string over itself
450 if ( m_pchData != stringSrc.m_pchData ) {
451 if ( stringSrc.GetStringData()->IsEmpty() ) {
452 Reinit();
453 }
454 else {
455 // adjust references
456 GetStringData()->Unlock();
457 m_pchData = stringSrc.m_pchData;
458 GetStringData()->Lock();
459 }
460 }
461
462 return *this;
463}
464
465// assigns a single character
466wxString& wxString::operator=(char ch)
467{
468 AssignCopy(1, &ch);
469 return *this;
470}
471
472// assigns C string
473wxString& wxString::operator=(const char *psz)
474{
475 AssignCopy(Strlen(psz), psz);
476 return *this;
477}
478
479// same as 'signed char' variant
480wxString& wxString::operator=(const unsigned char* psz)
481{
482 *this = (const char *)psz;
483 return *this;
484}
485
486wxString& wxString::operator=(const wchar_t *pwz)
487{
488 wxString str(pwz);
489 *this = str;
490 return *this;
491}
492
493// ---------------------------------------------------------------------------
494// string concatenation
495// ---------------------------------------------------------------------------
496
c801d85f
KB
497// add something to this string
498void wxString::ConcatSelf(int nSrcLen, const char *pszSrcData)
499{
3168a13f 500 STATISTICS_ADD(SummandLength, nSrcLen);
c801d85f 501
05488905
VZ
502 // concatenating an empty string is a NOP
503 if ( nSrcLen > 0 ) {
504 wxStringData *pData = GetStringData();
505 size_t nLen = pData->nDataLength;
506 size_t nNewLen = nLen + nSrcLen;
c801d85f 507
05488905
VZ
508 // alloc new buffer if current is too small
509 if ( pData->IsShared() ) {
510 STATISTICS_ADD(ConcatHit, 0);
3168a13f 511
05488905
VZ
512 // we have to allocate another buffer
513 wxStringData* pOldData = GetStringData();
514 AllocBuffer(nNewLen);
515 memcpy(m_pchData, pOldData->data(), nLen*sizeof(char));
516 pOldData->Unlock();
517 }
518 else if ( nNewLen > pData->nAllocLength ) {
519 STATISTICS_ADD(ConcatHit, 0);
3168a13f 520
05488905
VZ
521 // we have to grow the buffer
522 Alloc(nNewLen);
523 }
524 else {
525 STATISTICS_ADD(ConcatHit, 1);
3168a13f 526
05488905
VZ
527 // the buffer is already big enough
528 }
3168a13f 529
05488905
VZ
530 // should be enough space
531 wxASSERT( nNewLen <= GetStringData()->nAllocLength );
3168a13f 532
05488905
VZ
533 // fast concatenation - all is done in our buffer
534 memcpy(m_pchData + nLen, pszSrcData, nSrcLen*sizeof(char));
3168a13f 535
05488905
VZ
536 m_pchData[nNewLen] = '\0'; // put terminating '\0'
537 GetStringData()->nDataLength = nNewLen; // and fix the length
538 }
539 //else: the string to append was empty
c801d85f
KB
540}
541
542/*
c801d85f
KB
543 * concatenation functions come in 5 flavours:
544 * string + string
545 * char + string and string + char
546 * C str + string and string + C str
547 */
548
549wxString operator+(const wxString& string1, const wxString& string2)
550{
097c080b
VZ
551 wxASSERT( string1.GetStringData()->IsValid() );
552 wxASSERT( string2.GetStringData()->IsValid() );
553
3168a13f
VZ
554 wxString s = string1;
555 s += string2;
556
c801d85f
KB
557 return s;
558}
559
3168a13f 560wxString operator+(const wxString& string, char ch)
c801d85f 561{
3168a13f
VZ
562 wxASSERT( string.GetStringData()->IsValid() );
563
564 wxString s = string;
565 s += ch;
097c080b 566
c801d85f
KB
567 return s;
568}
569
570wxString operator+(char ch, const wxString& string)
571{
097c080b
VZ
572 wxASSERT( string.GetStringData()->IsValid() );
573
3168a13f
VZ
574 wxString s = ch;
575 s += string;
576
c801d85f
KB
577 return s;
578}
579
580wxString operator+(const wxString& string, const char *psz)
581{
097c080b
VZ
582 wxASSERT( string.GetStringData()->IsValid() );
583
c801d85f 584 wxString s;
3168a13f
VZ
585 s.Alloc(Strlen(psz) + string.Len());
586 s = string;
587 s += psz;
588
c801d85f
KB
589 return s;
590}
591
592wxString operator+(const char *psz, const wxString& string)
593{
097c080b
VZ
594 wxASSERT( string.GetStringData()->IsValid() );
595
c801d85f 596 wxString s;
3168a13f
VZ
597 s.Alloc(Strlen(psz) + string.Len());
598 s = psz;
599 s += string;
600
c801d85f
KB
601 return s;
602}
603
604// ===========================================================================
605// other common string functions
606// ===========================================================================
607
608// ---------------------------------------------------------------------------
609// simple sub-string extraction
610// ---------------------------------------------------------------------------
611
612// helper function: clone the data attached to this string
613void wxString::AllocCopy(wxString& dest, int nCopyLen, int nCopyIndex) const
614{
3168a13f 615 if ( nCopyLen == 0 ) {
c801d85f
KB
616 dest.Init();
617 }
3168a13f 618 else {
c801d85f
KB
619 dest.AllocBuffer(nCopyLen);
620 memcpy(dest.m_pchData, m_pchData + nCopyIndex, nCopyLen*sizeof(char));
621 }
622}
623
624// extract string of length nCount starting at nFirst
c801d85f
KB
625wxString wxString::Mid(size_t nFirst, size_t nCount) const
626{
30d9011f
VZ
627 wxStringData *pData = GetStringData();
628 size_t nLen = pData->nDataLength;
629
566b84d2
VZ
630 // default value of nCount is wxSTRING_MAXLEN and means "till the end"
631 if ( nCount == wxSTRING_MAXLEN )
30d9011f
VZ
632 {
633 nCount = nLen - nFirst;
634 }
635
c801d85f 636 // out-of-bounds requests return sensible things
30d9011f
VZ
637 if ( nFirst + nCount > nLen )
638 {
639 nCount = nLen - nFirst;
640 }
c801d85f 641
30d9011f
VZ
642 if ( nFirst > nLen )
643 {
644 // AllocCopy() will return empty string
c801d85f 645 nCount = 0;
30d9011f 646 }
c801d85f
KB
647
648 wxString dest;
649 AllocCopy(dest, nCount, nFirst);
30d9011f 650
c801d85f
KB
651 return dest;
652}
653
654// extract nCount last (rightmost) characters
655wxString wxString::Right(size_t nCount) const
656{
657 if ( nCount > (size_t)GetStringData()->nDataLength )
658 nCount = GetStringData()->nDataLength;
659
660 wxString dest;
661 AllocCopy(dest, nCount, GetStringData()->nDataLength - nCount);
662 return dest;
663}
664
665// get all characters after the last occurence of ch
666// (returns the whole string if ch not found)
3c67202d 667wxString wxString::AfterLast(char ch) const
c801d85f
KB
668{
669 wxString str;
670 int iPos = Find(ch, TRUE);
3c67202d 671 if ( iPos == wxNOT_FOUND )
c801d85f
KB
672 str = *this;
673 else
c8cfb486 674 str = c_str() + iPos + 1;
c801d85f
KB
675
676 return str;
677}
678
679// extract nCount first (leftmost) characters
680wxString wxString::Left(size_t nCount) const
681{
682 if ( nCount > (size_t)GetStringData()->nDataLength )
683 nCount = GetStringData()->nDataLength;
684
685 wxString dest;
686 AllocCopy(dest, nCount, 0);
687 return dest;
688}
689
690// get all characters before the first occurence of ch
691// (returns the whole string if ch not found)
3c67202d 692wxString wxString::BeforeFirst(char ch) const
c801d85f
KB
693{
694 wxString str;
695 for ( const char *pc = m_pchData; *pc != '\0' && *pc != ch; pc++ )
696 str += *pc;
697
698 return str;
699}
700
701/// get all characters before the last occurence of ch
702/// (returns empty string if ch not found)
3c67202d 703wxString wxString::BeforeLast(char ch) const
c801d85f
KB
704{
705 wxString str;
706 int iPos = Find(ch, TRUE);
3c67202d 707 if ( iPos != wxNOT_FOUND && iPos != 0 )
d1c9bbf6 708 str = wxString(c_str(), iPos);
c801d85f
KB
709
710 return str;
711}
712
713/// get all characters after the first occurence of ch
714/// (returns empty string if ch not found)
3c67202d 715wxString wxString::AfterFirst(char ch) const
c801d85f
KB
716{
717 wxString str;
718 int iPos = Find(ch);
3c67202d 719 if ( iPos != wxNOT_FOUND )
c801d85f
KB
720 str = c_str() + iPos + 1;
721
722 return str;
723}
724
725// replace first (or all) occurences of some substring with another one
c86f1403 726size_t wxString::Replace(const char *szOld, const char *szNew, bool bReplaceAll)
c801d85f 727{
c86f1403 728 size_t uiCount = 0; // count of replacements made
c801d85f 729
c86f1403 730 size_t uiOldLen = Strlen(szOld);
c801d85f
KB
731
732 wxString strTemp;
733 const char *pCurrent = m_pchData;
dd1eaa89 734 const char *pSubstr;
c801d85f
KB
735 while ( *pCurrent != '\0' ) {
736 pSubstr = strstr(pCurrent, szOld);
737 if ( pSubstr == NULL ) {
738 // strTemp is unused if no replacements were made, so avoid the copy
739 if ( uiCount == 0 )
740 return 0;
741
742 strTemp += pCurrent; // copy the rest
743 break; // exit the loop
744 }
745 else {
746 // take chars before match
747 strTemp.ConcatSelf(pSubstr - pCurrent, pCurrent);
748 strTemp += szNew;
749 pCurrent = pSubstr + uiOldLen; // restart after match
750
751 uiCount++;
752
753 // stop now?
754 if ( !bReplaceAll ) {
755 strTemp += pCurrent; // copy the rest
756 break; // exit the loop
757 }
758 }
759 }
760
761 // only done if there were replacements, otherwise would have returned above
762 *this = strTemp;
763
764 return uiCount;
765}
766
767bool wxString::IsAscii() const
768{
769 const char *s = (const char*) *this;
770 while(*s){
771 if(!isascii(*s)) return(FALSE);
772 s++;
773 }
774 return(TRUE);
775}
dd1eaa89 776
c801d85f
KB
777bool wxString::IsWord() const
778{
779 const char *s = (const char*) *this;
780 while(*s){
781 if(!isalpha(*s)) return(FALSE);
782 s++;
783 }
784 return(TRUE);
785}
dd1eaa89 786
c801d85f
KB
787bool wxString::IsNumber() const
788{
789 const char *s = (const char*) *this;
790 while(*s){
791 if(!isdigit(*s)) return(FALSE);
792 s++;
793 }
794 return(TRUE);
795}
796
c801d85f
KB
797wxString wxString::Strip(stripType w) const
798{
799 wxString s = *this;
800 if ( w & leading ) s.Trim(FALSE);
801 if ( w & trailing ) s.Trim(TRUE);
802 return s;
803}
804
c801d85f
KB
805// ---------------------------------------------------------------------------
806// case conversion
807// ---------------------------------------------------------------------------
808
809wxString& wxString::MakeUpper()
810{
811 CopyBeforeWrite();
812
813 for ( char *p = m_pchData; *p; p++ )
814 *p = (char)toupper(*p);
815
816 return *this;
817}
818
819wxString& wxString::MakeLower()
820{
821 CopyBeforeWrite();
dd1eaa89 822
c801d85f
KB
823 for ( char *p = m_pchData; *p; p++ )
824 *p = (char)tolower(*p);
825
826 return *this;
827}
828
829// ---------------------------------------------------------------------------
830// trimming and padding
831// ---------------------------------------------------------------------------
832
833// trims spaces (in the sense of isspace) from left or right side
834wxString& wxString::Trim(bool bFromRight)
835{
2c3b684c
VZ
836 // first check if we're going to modify the string at all
837 if ( !IsEmpty() &&
838 (
839 (bFromRight && isspace(GetChar(Len() - 1))) ||
840 (!bFromRight && isspace(GetChar(0u)))
841 )
842 )
c801d85f 843 {
2c3b684c
VZ
844 // ok, there is at least one space to trim
845 CopyBeforeWrite();
846
847 if ( bFromRight )
848 {
849 // find last non-space character
850 char *psz = m_pchData + GetStringData()->nDataLength - 1;
851 while ( isspace(*psz) && (psz >= m_pchData) )
852 psz--;
853
854 // truncate at trailing space start
855 *++psz = '\0';
856 GetStringData()->nDataLength = psz - m_pchData;
857 }
858 else
859 {
860 // find first non-space character
861 const char *psz = m_pchData;
862 while ( isspace(*psz) )
863 psz++;
864
865 // fix up data and length
ce3ed50d 866 int nDataLength = GetStringData()->nDataLength - (psz - (const char*) m_pchData);
2c3b684c
VZ
867 memmove(m_pchData, psz, (nDataLength + 1)*sizeof(char));
868 GetStringData()->nDataLength = nDataLength;
869 }
c801d85f
KB
870 }
871
872 return *this;
873}
874
875// adds nCount characters chPad to the string from either side
876wxString& wxString::Pad(size_t nCount, char chPad, bool bFromRight)
877{
878 wxString s(chPad, nCount);
879
880 if ( bFromRight )
881 *this += s;
882 else
883 {
884 s += *this;
885 *this = s;
886 }
887
888 return *this;
889}
890
891// truncate the string
892wxString& wxString::Truncate(size_t uiLen)
893{
79a773ba
VZ
894 if ( uiLen < Len() ) {
895 CopyBeforeWrite();
896
897 *(m_pchData + uiLen) = '\0';
898 GetStringData()->nDataLength = uiLen;
899 }
900 //else: nothing to do, string is already short enough
c801d85f
KB
901
902 return *this;
903}
904
905// ---------------------------------------------------------------------------
3c67202d 906// finding (return wxNOT_FOUND if not found and index otherwise)
c801d85f
KB
907// ---------------------------------------------------------------------------
908
909// find a character
910int wxString::Find(char ch, bool bFromEnd) const
911{
912 const char *psz = bFromEnd ? strrchr(m_pchData, ch) : strchr(m_pchData, ch);
913
ce3ed50d 914 return (psz == NULL) ? wxNOT_FOUND : psz - (const char*) m_pchData;
c801d85f
KB
915}
916
917// find a sub-string (like strstr)
918int wxString::Find(const char *pszSub) const
919{
920 const char *psz = strstr(m_pchData, pszSub);
921
ce3ed50d 922 return (psz == NULL) ? wxNOT_FOUND : psz - (const char*) m_pchData;
c801d85f
KB
923}
924
7be07660
VZ
925// ---------------------------------------------------------------------------
926// stream-like operators
927// ---------------------------------------------------------------------------
928wxString& wxString::operator<<(int i)
929{
930 wxString res;
931 res.Printf("%d", i);
932
933 return (*this) << res;
934}
935
936wxString& wxString::operator<<(float f)
937{
938 wxString res;
939 res.Printf("%f", f);
940
941 return (*this) << res;
942}
943
944wxString& wxString::operator<<(double d)
945{
946 wxString res;
947 res.Printf("%g", d);
948
949 return (*this) << res;
950}
951
c801d85f 952// ---------------------------------------------------------------------------
9efd3367 953// formatted output
c801d85f
KB
954// ---------------------------------------------------------------------------
955int wxString::Printf(const char *pszFormat, ...)
956{
957 va_list argptr;
958 va_start(argptr, pszFormat);
959
960 int iLen = PrintfV(pszFormat, argptr);
961
962 va_end(argptr);
963
964 return iLen;
965}
966
967int wxString::PrintfV(const char* pszFormat, va_list argptr)
968{
7be07660 969 // static buffer to avoid dynamic memory allocation each time
9efd3367 970 static char s_szScratch[1024];
c801d85f 971
89b892a2
VZ
972 // NB: wxVsprintf() may return either less than the buffer size or -1 if there
973 // is not enough place depending on implementation
7be07660
VZ
974 int iLen = wxVsprintf(s_szScratch, WXSIZEOF(s_szScratch), pszFormat, argptr);
975 char *buffer;
89b892a2 976 if ( iLen < (int)WXSIZEOF(s_szScratch) ) {
7be07660
VZ
977 buffer = s_szScratch;
978 }
979 else {
980 int size = WXSIZEOF(s_szScratch) * 2;
981 buffer = (char *)malloc(size);
982 while ( buffer != NULL ) {
983 iLen = wxVsprintf(buffer, WXSIZEOF(s_szScratch), pszFormat, argptr);
984 if ( iLen < size ) {
985 // ok, there was enough space
986 break;
987 }
988
989 // still not enough, double it again
990 buffer = (char *)realloc(buffer, size *= 2);
991 }
992
993 if ( !buffer ) {
994 // out of memory
995 return -1;
996 }
997 }
998
c801d85f 999 AllocBeforeWrite(iLen);
7be07660
VZ
1000 strcpy(m_pchData, buffer);
1001
1002 if ( buffer != s_szScratch )
1003 free(buffer);
c801d85f
KB
1004
1005 return iLen;
1006}
1007
097c080b
VZ
1008// ----------------------------------------------------------------------------
1009// misc other operations
1010// ----------------------------------------------------------------------------
1011bool wxString::Matches(const char *pszMask) const
1012{
1013 // check char by char
1014 const char *pszTxt;
1015 for ( pszTxt = c_str(); *pszMask != '\0'; pszMask++, pszTxt++ ) {
1016 switch ( *pszMask ) {
1017 case '?':
1018 if ( *pszTxt == '\0' )
1019 return FALSE;
1020
1021 pszTxt++;
1022 pszMask++;
1023 break;
1024
1025 case '*':
1026 {
1027 // ignore special chars immediately following this one
1028 while ( *pszMask == '*' || *pszMask == '?' )
1029 pszMask++;
1030
1031 // if there is nothing more, match
1032 if ( *pszMask == '\0' )
1033 return TRUE;
1034
1035 // are there any other metacharacters in the mask?
c86f1403 1036 size_t uiLenMask;
097c080b
VZ
1037 const char *pEndMask = strpbrk(pszMask, "*?");
1038
1039 if ( pEndMask != NULL ) {
1040 // we have to match the string between two metachars
1041 uiLenMask = pEndMask - pszMask;
1042 }
1043 else {
1044 // we have to match the remainder of the string
1045 uiLenMask = strlen(pszMask);
1046 }
1047
1048 wxString strToMatch(pszMask, uiLenMask);
1049 const char* pMatch = strstr(pszTxt, strToMatch);
1050 if ( pMatch == NULL )
1051 return FALSE;
1052
1053 // -1 to compensate "++" in the loop
1054 pszTxt = pMatch + uiLenMask - 1;
1055 pszMask += uiLenMask - 1;
1056 }
1057 break;
1058
1059 default:
1060 if ( *pszMask != *pszTxt )
1061 return FALSE;
1062 break;
1063 }
1064 }
1065
1066 // match only if nothing left
1067 return *pszTxt == '\0';
1068}
1069
1fc5dd6f
JS
1070// Count the number of chars
1071int wxString::Freq(char ch) const
1072{
1073 int count = 0;
1074 int len = Len();
1075 for (int i = 0; i < len; i++)
1076 {
1077 if (GetChar(i) == ch)
1078 count ++;
1079 }
1080 return count;
1081}
1082
03ab016d
JS
1083// convert to upper case, return the copy of the string
1084wxString wxString::Upper() const
1085{ wxString s(*this); return s.MakeUpper(); }
1086
1087// convert to lower case, return the copy of the string
1088wxString wxString::Lower() const { wxString s(*this); return s.MakeLower(); }
1089
8870c26e
JS
1090int wxString::sprintf(const char *pszFormat, ...)
1091 {
1092 va_list argptr;
1093 va_start(argptr, pszFormat);
1094 int iLen = PrintfV(pszFormat, argptr);
1095 va_end(argptr);
1096 return iLen;
1097 }
1098
c801d85f
KB
1099// ---------------------------------------------------------------------------
1100// standard C++ library string functions
1101// ---------------------------------------------------------------------------
8de2e39c 1102#ifdef wxSTD_STRING_COMPATIBILITY
c801d85f
KB
1103
1104wxString& wxString::insert(size_t nPos, const wxString& str)
1105{
097c080b 1106 wxASSERT( str.GetStringData()->IsValid() );
c801d85f
KB
1107 wxASSERT( nPos <= Len() );
1108
cb6780ff
VZ
1109 if ( !str.IsEmpty() ) {
1110 wxString strTmp;
1111 char *pc = strTmp.GetWriteBuf(Len() + str.Len());
1112 strncpy(pc, c_str(), nPos);
1113 strcpy(pc + nPos, str);
1114 strcpy(pc + nPos + str.Len(), c_str() + nPos);
1115 strTmp.UngetWriteBuf();
1116 *this = strTmp;
1117 }
dd1eaa89
VZ
1118
1119 return *this;
c801d85f
KB
1120}
1121
1122size_t wxString::find(const wxString& str, size_t nStart) const
1123{
097c080b 1124 wxASSERT( str.GetStringData()->IsValid() );
c801d85f
KB
1125 wxASSERT( nStart <= Len() );
1126
1127 const char *p = strstr(c_str() + nStart, str);
dd1eaa89 1128
c801d85f
KB
1129 return p == NULL ? npos : p - c_str();
1130}
1131
f0b3249b 1132// VC++ 1.5 can't cope with the default argument in the header.
3f4a0c5b 1133#if !defined(__VISUALC__) || defined(__WIN32__)
c801d85f
KB
1134size_t wxString::find(const char* sz, size_t nStart, size_t n) const
1135{
1136 return find(wxString(sz, n == npos ? 0 : n), nStart);
1137}
3f4a0c5b 1138#endif // VC++ 1.5
dd1eaa89 1139
62448488
JS
1140// Gives a duplicate symbol (presumably a case-insensitivity problem)
1141#if !defined(__BORLANDC__)
c801d85f
KB
1142size_t wxString::find(char ch, size_t nStart) const
1143{
1144 wxASSERT( nStart <= Len() );
1145
1146 const char *p = strchr(c_str() + nStart, ch);
dd1eaa89 1147
c801d85f
KB
1148 return p == NULL ? npos : p - c_str();
1149}
62448488 1150#endif
c801d85f
KB
1151
1152size_t wxString::rfind(const wxString& str, size_t nStart) const
1153{
097c080b 1154 wxASSERT( str.GetStringData()->IsValid() );
c801d85f
KB
1155 wxASSERT( nStart <= Len() );
1156
1157 // # could be quicker than that
1158 const char *p = c_str() + (nStart == npos ? Len() : nStart);
1159 while ( p >= c_str() + str.Len() ) {
1160 if ( strncmp(p - str.Len(), str, str.Len()) == 0 )
1161 return p - str.Len() - c_str();
1162 p--;
1163 }
dd1eaa89 1164
c801d85f
KB
1165 return npos;
1166}
dd1eaa89 1167
f0b3249b 1168// VC++ 1.5 can't cope with the default argument in the header.
3f4a0c5b 1169#if !defined(__VISUALC__) || defined(__WIN32__)
c801d85f
KB
1170size_t wxString::rfind(const char* sz, size_t nStart, size_t n) const
1171{
1172 return rfind(wxString(sz, n == npos ? 0 : n), nStart);
1173}
1174
1175size_t wxString::rfind(char ch, size_t nStart) const
1176{
1177 wxASSERT( nStart <= Len() );
1178
1179 const char *p = strrchr(c_str() + nStart, ch);
dd1eaa89 1180
c801d85f
KB
1181 return p == NULL ? npos : p - c_str();
1182}
3f4a0c5b 1183#endif // VC++ 1.5
c801d85f
KB
1184
1185wxString wxString::substr(size_t nStart, size_t nLen) const
1186{
1187 // npos means 'take all'
1188 if ( nLen == npos )
1189 nLen = 0;
1190
1191 wxASSERT( nStart + nLen <= Len() );
1192
1193 return wxString(c_str() + nStart, nLen == npos ? 0 : nLen);
1194}
1195
1196wxString& wxString::erase(size_t nStart, size_t nLen)
1197{
1198 wxString strTmp(c_str(), nStart);
1199 if ( nLen != npos ) {
1200 wxASSERT( nStart + nLen <= Len() );
1201
1202 strTmp.append(c_str() + nStart + nLen);
1203 }
1204
1205 *this = strTmp;
1206 return *this;
1207}
1208
1209wxString& wxString::replace(size_t nStart, size_t nLen, const char *sz)
1210{
1211 wxASSERT( nStart + nLen <= Strlen(sz) );
1212
1213 wxString strTmp;
1214 if ( nStart != 0 )
1215 strTmp.append(c_str(), nStart);
1216 strTmp += sz;
1217 strTmp.append(c_str() + nStart + nLen);
dd1eaa89 1218
c801d85f
KB
1219 *this = strTmp;
1220 return *this;
1221}
1222
1223wxString& wxString::replace(size_t nStart, size_t nLen, size_t nCount, char ch)
1224{
1225 return replace(nStart, nLen, wxString(ch, nCount));
1226}
1227
dd1eaa89 1228wxString& wxString::replace(size_t nStart, size_t nLen,
097c080b 1229 const wxString& str, size_t nStart2, size_t nLen2)
c801d85f
KB
1230{
1231 return replace(nStart, nLen, str.substr(nStart2, nLen2));
1232}
1233
dd1eaa89 1234wxString& wxString::replace(size_t nStart, size_t nLen,
c801d85f
KB
1235 const char* sz, size_t nCount)
1236{
1237 return replace(nStart, nLen, wxString(sz, nCount));
1238}
1239
1240#endif //std::string compatibility
1241
1242// ============================================================================
1243// ArrayString
1244// ============================================================================
1245
1246// size increment = max(50% of current size, ARRAY_MAXSIZE_INCREMENT)
1247#define ARRAY_MAXSIZE_INCREMENT 4096
1248#ifndef ARRAY_DEFAULT_INITIAL_SIZE // also defined in dynarray.h
1249 #define ARRAY_DEFAULT_INITIAL_SIZE (16)
1250#endif
1251
1252#define STRING(p) ((wxString *)(&(p)))
1253
1254// ctor
1255wxArrayString::wxArrayString()
1256{
1257 m_nSize =
1258 m_nCount = 0;
c67daf87 1259 m_pItems = (char **) NULL;
c801d85f
KB
1260}
1261
1262// copy ctor
1263wxArrayString::wxArrayString(const wxArrayString& src)
1264{
3bbb630a
VZ
1265 m_nSize =
1266 m_nCount = 0;
c67daf87 1267 m_pItems = (char **) NULL;
c801d85f 1268
4d14b524 1269 *this = src;
c801d85f
KB
1270}
1271
4d14b524 1272// assignment operator
c801d85f
KB
1273wxArrayString& wxArrayString::operator=(const wxArrayString& src)
1274{
d93f63db
VZ
1275 if ( m_nSize > 0 )
1276 Clear();
c801d85f 1277
4d14b524
VZ
1278 if ( src.m_nCount > ARRAY_DEFAULT_INITIAL_SIZE )
1279 Alloc(src.m_nCount);
c801d85f 1280
4d14b524
VZ
1281 // we can't just copy the pointers here because otherwise we would share
1282 // the strings with another array
c86f1403 1283 for ( size_t n = 0; n < src.m_nCount; n++ )
4d14b524 1284 Add(src[n]);
c801d85f 1285
3bbb630a
VZ
1286 if ( m_nCount != 0 )
1287 memcpy(m_pItems, src.m_pItems, m_nCount*sizeof(char *));
1288
c801d85f
KB
1289 return *this;
1290}
1291
1292// grow the array
1293void wxArrayString::Grow()
1294{
1295 // only do it if no more place
1296 if( m_nCount == m_nSize ) {
1297 if( m_nSize == 0 ) {
1298 // was empty, alloc some memory
1299 m_nSize = ARRAY_DEFAULT_INITIAL_SIZE;
1300 m_pItems = new char *[m_nSize];
1301 }
1302 else {
3bbb630a
VZ
1303 // otherwise when it's called for the first time, nIncrement would be 0
1304 // and the array would never be expanded
1305 wxASSERT( ARRAY_DEFAULT_INITIAL_SIZE != 0 );
1306
c801d85f 1307 // add 50% but not too much
3bbb630a 1308 size_t nIncrement = m_nSize < ARRAY_DEFAULT_INITIAL_SIZE
4d14b524 1309 ? ARRAY_DEFAULT_INITIAL_SIZE : m_nSize >> 1;
c801d85f
KB
1310 if ( nIncrement > ARRAY_MAXSIZE_INCREMENT )
1311 nIncrement = ARRAY_MAXSIZE_INCREMENT;
1312 m_nSize += nIncrement;
1313 char **pNew = new char *[m_nSize];
1314
1315 // copy data to new location
1316 memcpy(pNew, m_pItems, m_nCount*sizeof(char *));
1317
1318 // delete old memory (but do not release the strings!)
a3622daa 1319 wxDELETEA(m_pItems);
c801d85f
KB
1320
1321 m_pItems = pNew;
1322 }
1323 }
1324}
1325
1326void wxArrayString::Free()
1327{
1328 for ( size_t n = 0; n < m_nCount; n++ ) {
1329 STRING(m_pItems[n])->GetStringData()->Unlock();
1330 }
1331}
1332
1333// deletes all the strings from the list
1334void wxArrayString::Empty()
1335{
1336 Free();
1337
1338 m_nCount = 0;
1339}
1340
1341// as Empty, but also frees memory
1342void wxArrayString::Clear()
1343{
1344 Free();
1345
dd1eaa89 1346 m_nSize =
c801d85f
KB
1347 m_nCount = 0;
1348
a3622daa 1349 wxDELETEA(m_pItems);
c801d85f
KB
1350}
1351
1352// dtor
1353wxArrayString::~wxArrayString()
1354{
1355 Free();
1356
a3622daa 1357 wxDELETEA(m_pItems);
c801d85f
KB
1358}
1359
1360// pre-allocates memory (frees the previous data!)
1361void wxArrayString::Alloc(size_t nSize)
1362{
1363 wxASSERT( nSize > 0 );
1364
1365 // only if old buffer was not big enough
1366 if ( nSize > m_nSize ) {
1367 Free();
a3622daa 1368 wxDELETEA(m_pItems);
c801d85f
KB
1369 m_pItems = new char *[nSize];
1370 m_nSize = nSize;
1371 }
1372
1373 m_nCount = 0;
1374}
1375
1376// searches the array for an item (forward or backwards)
c801d85f
KB
1377int wxArrayString::Index(const char *sz, bool bCase, bool bFromEnd) const
1378{
1379 if ( bFromEnd ) {
1380 if ( m_nCount > 0 ) {
c86f1403 1381 size_t ui = m_nCount;
c801d85f
KB
1382 do {
1383 if ( STRING(m_pItems[--ui])->IsSameAs(sz, bCase) )
1384 return ui;
1385 }
1386 while ( ui != 0 );
1387 }
1388 }
1389 else {
c86f1403 1390 for( size_t ui = 0; ui < m_nCount; ui++ ) {
c801d85f
KB
1391 if( STRING(m_pItems[ui])->IsSameAs(sz, bCase) )
1392 return ui;
1393 }
1394 }
1395
3c67202d 1396 return wxNOT_FOUND;
c801d85f
KB
1397}
1398
1399// add item at the end
097c080b 1400void wxArrayString::Add(const wxString& str)
c801d85f 1401{
097c080b
VZ
1402 wxASSERT( str.GetStringData()->IsValid() );
1403
c801d85f
KB
1404 Grow();
1405
1406 // the string data must not be deleted!
097c080b
VZ
1407 str.GetStringData()->Lock();
1408 m_pItems[m_nCount++] = (char *)str.c_str();
c801d85f
KB
1409}
1410
1411// add item at the given position
097c080b 1412void wxArrayString::Insert(const wxString& str, size_t nIndex)
c801d85f 1413{
097c080b
VZ
1414 wxASSERT( str.GetStringData()->IsValid() );
1415
1a5a8367 1416 wxCHECK_RET( nIndex <= m_nCount, ("bad index in wxArrayString::Insert") );
c801d85f
KB
1417
1418 Grow();
1419
dd1eaa89 1420 memmove(&m_pItems[nIndex + 1], &m_pItems[nIndex],
c801d85f
KB
1421 (m_nCount - nIndex)*sizeof(char *));
1422
097c080b
VZ
1423 str.GetStringData()->Lock();
1424 m_pItems[nIndex] = (char *)str.c_str();
c801d85f
KB
1425
1426 m_nCount++;
1427}
1428
1429// removes item from array (by index)
1430void wxArrayString::Remove(size_t nIndex)
1431{
1a5a8367 1432 wxCHECK_RET( nIndex <= m_nCount, _("bad index in wxArrayString::Remove") );
c801d85f
KB
1433
1434 // release our lock
1435 Item(nIndex).GetStringData()->Unlock();
1436
dd1eaa89 1437 memmove(&m_pItems[nIndex], &m_pItems[nIndex + 1],
c801d85f
KB
1438 (m_nCount - nIndex - 1)*sizeof(char *));
1439 m_nCount--;
1440}
1441
1442// removes item from array (by value)
1443void wxArrayString::Remove(const char *sz)
1444{
1445 int iIndex = Index(sz);
1446
3c67202d 1447 wxCHECK_RET( iIndex != wxNOT_FOUND,
1a5a8367 1448 _("removing inexistent element in wxArrayString::Remove") );
c801d85f 1449
c86f1403 1450 Remove(iIndex);
c801d85f
KB
1451}
1452
30b21f9a
VZ
1453// ----------------------------------------------------------------------------
1454// sorting
1455// ----------------------------------------------------------------------------
1456
1457// we can only sort one array at a time with the quick-sort based
1458// implementation
1459#if wxUSE_THREADS
1460 #include <wx/thread.h>
1461
1462 // need a critical section to protect access to gs_compareFunction and
1463 // gs_sortAscending variables
1464 static wxCriticalSection gs_critsectStringSort;
1465
1466 // call this before the value of the global sort vars is changed/after
1467 // you're finished with them
1468 #define START_SORT() gs_critsectStringSort.Enter()
1469 #define END_SORT() gs_critsectStringSort.Leave()
1470#else // !threads
1471 #define START_SORT()
1472 #define END_SORT()
1473#endif // wxUSE_THREADS
1474
1475// function to use for string comparaison
1476static wxArrayString::CompareFunction gs_compareFunction = NULL;
1477
1478// if we don't use the compare function, this flag tells us if we sort the
1479// array in ascending or descending order
1480static bool gs_sortAscending = TRUE;
1481
1482// function which is called by quick sort
1483static int wxStringCompareFunction(const void *first, const void *second)
1484{
1485 wxString *strFirst = (wxString *)first;
1486 wxString *strSecond = (wxString *)second;
1487
64716cd7 1488 if ( gs_compareFunction ) {
30b21f9a 1489 return gs_compareFunction(*strFirst, *strSecond);
64716cd7 1490 }
30b21f9a
VZ
1491 else {
1492 int result = strcmp(strFirst->c_str(), strSecond->c_str());
1493
1494 return gs_sortAscending ? result : -result;
1495 }
1496}
1497
c801d85f 1498// sort array elements using passed comparaison function
30b21f9a
VZ
1499void wxArrayString::Sort(CompareFunction compareFunction)
1500{
1501 START_SORT();
1502
1503 wxASSERT( !gs_compareFunction ); // must have been reset to NULL
1504 gs_compareFunction = compareFunction;
1505
1506 DoSort();
1507
1508 END_SORT();
1509}
1510
1511void wxArrayString::Sort(bool reverseOrder)
1512{
1513 START_SORT();
1514
1515 wxASSERT( !gs_compareFunction ); // must have been reset to NULL
1516 gs_sortAscending = !reverseOrder;
1517
1518 DoSort();
1519
1520 END_SORT();
1521}
c801d85f 1522
30b21f9a 1523void wxArrayString::DoSort()
c801d85f 1524{
30b21f9a
VZ
1525 // just sort the pointers using qsort() - of course it only works because
1526 // wxString() *is* a pointer to its data
1527 qsort(m_pItems, m_nCount, sizeof(char *), wxStringCompareFunction);
c801d85f 1528}