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