]> git.saurik.com Git - wxWidgets.git/blame - src/common/string.cpp
wxFileConfig uses sorted arrays (big performance improvement)
[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
35#include "wx/defs.h"
36#include "wx/string.h"
37#endif
38
39#include <ctype.h>
40#include <string.h>
41#include <stdlib.h>
42
43#ifdef WXSTRING_IS_WXOBJECT
44 IMPLEMENT_DYNAMIC_CLASS(wxString, wxObject)
45#endif //WXSTRING_IS_WXOBJECT
46
47// ---------------------------------------------------------------------------
48// static class variables definition
49// ---------------------------------------------------------------------------
50
51#ifdef STD_STRING_COMPATIBILITY
52 const size_t wxString::npos = STRING_MAXLEN;
53#endif
54
55// ===========================================================================
56// static class data, special inlines
57// ===========================================================================
58
59// for an empty string, GetStringData() will return this address
60static int g_strEmpty[] = { -1, // ref count (locked)
61 0, // current length
62 0, // allocated memory
63 0 }; // string data
c801d85f
KB
64// empty C style string: points to 'string data' byte of g_strEmpty
65extern const char *g_szNul = (const char *)(&g_strEmpty[3]);
66
67// ===========================================================================
68// global functions
69// ===========================================================================
70
71#ifdef STD_STRING_COMPATIBILITY
72
73// MS Visual C++ version 5.0 provides the new STL headers as well as the old
74// iostream ones.
75//
76// ATTN: you can _not_ use both of these in the same program!
77#if 0 // def _MSC_VER
78 #include <iostream>
79 #define NAMESPACE std::
80#else
81 #include <iostream.h>
82 #define NAMESPACE
83#endif //Visual C++
84
85NAMESPACE istream& operator>>(NAMESPACE istream& is, wxString& WXUNUSED(str))
86{
87#if 0
88 int w = is.width(0);
89 if ( is.ipfx(0) ) {
90 NAMESPACE streambuf *sb = is.rdbuf();
91 str.erase();
92 while ( true ) {
93 int ch = sb->sbumpc ();
94 if ( ch == EOF ) {
95 is.setstate(NAMESPACE ios::eofbit);
96 break;
97 }
98 else if ( isspace(ch) ) {
99 sb->sungetc();
100 break;
101 }
dd1eaa89 102
c801d85f
KB
103 str += ch;
104 if ( --w == 1 )
105 break;
106 }
107 }
108
109 is.isfx();
110 if ( str.length() == 0 )
111 is.setstate(NAMESPACE ios::failbit);
112#endif
113 return is;
114}
115
116#endif //std::string compatibility
117
118// ===========================================================================
119// wxString class core
120// ===========================================================================
121
122// ---------------------------------------------------------------------------
123// construction
124// ---------------------------------------------------------------------------
125
126// construct an empty string
127wxString::wxString()
128{
129 Init();
130}
131
132// copy constructor
133wxString::wxString(const wxString& stringSrc)
134{
135 wxASSERT( stringSrc.GetStringData()->IsValid() );
136
137 if ( stringSrc.IsEmpty() ) {
138 // nothing to do for an empty string
139 Init();
140 }
141 else {
142 m_pchData = stringSrc.m_pchData; // share same data
143 GetStringData()->Lock(); // => one more copy
144 }
145}
146
147// constructs string of <nLength> copies of character <ch>
148wxString::wxString(char ch, size_t nLength)
149{
150 Init();
151
152 if ( nLength > 0 ) {
153 AllocBuffer(nLength);
f1da2f03 154
c801d85f
KB
155 wxASSERT( sizeof(char) == 1 ); // can't use memset if not
156
157 memset(m_pchData, ch, nLength);
158 }
159}
160
161// takes nLength elements of psz starting at nPos
162void wxString::InitWith(const char *psz, size_t nPos, size_t nLength)
163{
164 Init();
165
166 wxASSERT( nPos <= Strlen(psz) );
167
168 if ( nLength == STRING_MAXLEN )
169 nLength = Strlen(psz + nPos);
170
171 if ( nLength > 0 ) {
172 // trailing '\0' is written in AllocBuffer()
173 AllocBuffer(nLength);
174 memcpy(m_pchData, psz + nPos, nLength*sizeof(char));
175 }
176}
dd1eaa89 177
c801d85f
KB
178// take first nLength characters of C string psz
179// (default value of STRING_MAXLEN means take all the string)
180wxString::wxString(const char *psz, size_t nLength)
181{
182 InitWith(psz, 0, nLength);
183}
184
185// the same as previous constructor, but for compilers using unsigned char
186wxString::wxString(const unsigned char* psz, size_t nLength)
187{
188 InitWith((const char *)psz, 0, nLength);
dd1eaa89
VZ
189}
190
c801d85f
KB
191#ifdef STD_STRING_COMPATIBILITY
192
193// ctor from a substring
097c080b 194wxString::wxString(const wxString& str, size_t nPos, size_t nLen)
c801d85f 195{
097c080b
VZ
196 wxASSERT( str.GetStringData()->IsValid() );
197
198 InitWith(str.c_str(), nPos, nLen == npos ? 0 : nLen);
c801d85f
KB
199}
200
201// poor man's iterators are "void *" pointers
202wxString::wxString(const void *pStart, const void *pEnd)
203{
dd1eaa89 204 InitWith((const char *)pStart, 0,
c801d85f
KB
205 (const char *)pEnd - (const char *)pStart);
206}
207
208#endif //std::string compatibility
209
210// from wide string
211wxString::wxString(const wchar_t *pwz)
212{
213 // first get necessary size
214 size_t nLen = wcstombs(NULL, pwz, 0);
215
216 // empty?
217 if ( nLen != 0 ) {
218 AllocBuffer(nLen);
219 wcstombs(m_pchData, pwz, nLen);
220 }
221 else {
222 Init();
223 }
224}
225
226// ---------------------------------------------------------------------------
227// memory allocation
228// ---------------------------------------------------------------------------
229
230// allocates memory needed to store a C string of length nLen
231void wxString::AllocBuffer(size_t nLen)
232{
233 wxASSERT( nLen > 0 ); //
234 wxASSERT( nLen <= INT_MAX-1 ); // max size (enough room for 1 extra)
235
236 // allocate memory:
237 // 1) one extra character for '\0' termination
238 // 2) sizeof(wxStringData) for housekeeping info
dd1eaa89
VZ
239 wxStringData* pData = (wxStringData*)malloc(sizeof(wxStringData) +
240 (nLen + 1)*sizeof(char));
c801d85f
KB
241 pData->nRefs = 1;
242 pData->data()[nLen] = '\0';
243 pData->nDataLength = nLen;
244 pData->nAllocLength = nLen;
245 m_pchData = pData->data(); // data starts after wxStringData
246}
247
c801d85f
KB
248// must be called before changing this string
249void wxString::CopyBeforeWrite()
250{
251 wxStringData* pData = GetStringData();
252
253 if ( pData->IsShared() ) {
254 pData->Unlock(); // memory not freed because shared
255 AllocBuffer(pData->nDataLength);
256 memcpy(m_pchData, pData->data(), (pData->nDataLength + 1)*sizeof(char));
257 }
258
259 wxASSERT( !pData->IsShared() ); // we must be the only owner
260}
261
262// must be called before replacing contents of this string
263void wxString::AllocBeforeWrite(size_t nLen)
264{
265 wxASSERT( nLen != 0 ); // doesn't make any sense
266
267 // must not share string and must have enough space
f1da2f03 268 register wxStringData* pData = GetStringData();
c801d85f
KB
269 if ( pData->IsShared() || (nLen > pData->nAllocLength) ) {
270 // can't work with old buffer, get new one
271 pData->Unlock();
272 AllocBuffer(nLen);
273 }
274
f1da2f03 275 wxASSERT( !GetStringData()->IsShared() ); // we must be the only owner
c801d85f
KB
276}
277
dd1eaa89
VZ
278// allocate enough memory for nLen characters
279void wxString::Alloc(uint nLen)
280{
281 wxStringData *pData = GetStringData();
282 if ( pData->nAllocLength <= nLen ) {
283 if ( pData->IsEmpty() )
284 AllocBuffer(nLen);
285 else {
286 wxStringData *p = (wxStringData *)
287 realloc(pData, sizeof(wxStringData) + (nLen + 1)*sizeof(char));
288 if ( p != NULL && p != pData ) {
289 // the call succeeded but the pointer changed
290 pData->Unlock();
291 free(pData);
292
293 p->nRefs = 1;
294 p->nAllocLength = nLen;
295 m_pchData = p->data();
296 }
297 //else: do nothing: either the call failed or the pointer is unchanged
298 }
299 }
300 //else: we've already got enough
301}
302
303// shrink to minimal size (releasing extra memory)
304void wxString::Shrink()
305{
306 wxStringData *pData = GetStringData();
307 void *p = realloc(pData, sizeof(wxStringData) +
308 (pData->nDataLength + 1)*sizeof(char));
309 if ( p == NULL ) // huh? can't unallocate memory? unlikely but possible.
310 return;
311 wxASSERT( p == pData ); // we're decrementing the size - block shouldn't move!
312}
313
c801d85f 314// get the pointer to writable buffer of (at least) nLen bytes
dd1eaa89 315char *wxString::GetWriteBuf(uint nLen)
c801d85f
KB
316{
317 AllocBeforeWrite(nLen);
097c080b
VZ
318
319 wxASSERT( GetStringData()->nRefs == 1 );
320 GetStringData()->Validate(FALSE);
321
c801d85f
KB
322 return m_pchData;
323}
324
097c080b
VZ
325// put string back in a reasonable state after GetWriteBuf
326void wxString::UngetWriteBuf()
327{
328 GetStringData()->nDataLength = strlen(m_pchData);
329 GetStringData()->Validate(TRUE);
330}
331
c801d85f
KB
332// dtor frees memory if no other strings use it
333wxString::~wxString()
334{
335 GetStringData()->Unlock();
336}
337
338// ---------------------------------------------------------------------------
339// data access
340// ---------------------------------------------------------------------------
341
342// all functions are inline in string.h
343
344// ---------------------------------------------------------------------------
345// assignment operators
346// ---------------------------------------------------------------------------
347
dd1eaa89 348// helper function: does real copy
c801d85f
KB
349void wxString::AssignCopy(size_t nSrcLen, const char *pszSrcData)
350{
351 if ( nSrcLen == 0 ) {
352 Reinit();
353 }
354 else {
355 AllocBeforeWrite(nSrcLen);
356 memcpy(m_pchData, pszSrcData, nSrcLen*sizeof(char));
357 GetStringData()->nDataLength = nSrcLen;
358 m_pchData[nSrcLen] = '\0';
359 }
360}
361
362// assigns one string to another
363wxString& wxString::operator=(const wxString& stringSrc)
364{
097c080b
VZ
365 wxASSERT( stringSrc.GetStringData()->IsValid() );
366
c801d85f
KB
367 // don't copy string over itself
368 if ( m_pchData != stringSrc.m_pchData ) {
369 if ( stringSrc.GetStringData()->IsEmpty() ) {
370 Reinit();
371 }
372 else {
373 // adjust references
374 GetStringData()->Unlock();
375 m_pchData = stringSrc.m_pchData;
376 GetStringData()->Lock();
377 }
378 }
379
380 return *this;
381}
382
383// assigns a single character
384wxString& wxString::operator=(char ch)
385{
386 AssignCopy(1, &ch);
387 return *this;
388}
389
390// assigns C string
391wxString& wxString::operator=(const char *psz)
392{
393 AssignCopy(Strlen(psz), psz);
394 return *this;
395}
396
397// same as 'signed char' variant
398wxString& wxString::operator=(const unsigned char* psz)
399{
400 *this = (const char *)psz;
401 return *this;
402}
403
404wxString& wxString::operator=(const wchar_t *pwz)
405{
406 wxString str(pwz);
407 *this = str;
408 return *this;
409}
410
411// ---------------------------------------------------------------------------
412// string concatenation
413// ---------------------------------------------------------------------------
414
415// concatenate two sources
416// NB: assume that 'this' is a new wxString object
417void wxString::ConcatCopy(int nSrc1Len, const char *pszSrc1Data,
dd1eaa89 418 int nSrc2Len, const char *pszSrc2Data)
c801d85f
KB
419{
420 int nNewLen = nSrc1Len + nSrc2Len;
421 if ( nNewLen != 0 )
422 {
423 AllocBuffer(nNewLen);
424 memcpy(m_pchData, pszSrc1Data, nSrc1Len*sizeof(char));
425 memcpy(m_pchData + nSrc1Len, pszSrc2Data, nSrc2Len*sizeof(char));
426 }
427}
428
429// add something to this string
430void wxString::ConcatSelf(int nSrcLen, const char *pszSrcData)
431{
432 // concatenating an empty string is a NOP
433 if ( nSrcLen != 0 ) {
434 register wxStringData *pData = GetStringData();
435
436 // alloc new buffer if current is too small
dd1eaa89 437 if ( pData->IsShared() ||
c801d85f
KB
438 pData->nDataLength + nSrcLen > pData->nAllocLength ) {
439 // we have to grow the buffer, use the ConcatCopy routine
440 // (which will allocate memory)
441 wxStringData* pOldData = GetStringData();
442 ConcatCopy(pOldData->nDataLength, m_pchData, nSrcLen, pszSrcData);
443 pOldData->Unlock();
444 }
445 else {
446 // fast concatenation when buffer big enough
447 memcpy(m_pchData + pData->nDataLength, pszSrcData, nSrcLen*sizeof(char));
448 pData->nDataLength += nSrcLen;
449
450 // should be enough space
451 wxASSERT( pData->nDataLength <= pData->nAllocLength );
452
453 m_pchData[pData->nDataLength] = '\0'; // put terminating '\0'
454 }
455 }
456}
457
458/*
c801d85f
KB
459 * concatenation functions come in 5 flavours:
460 * string + string
461 * char + string and string + char
462 * C str + string and string + C str
463 */
464
465wxString operator+(const wxString& string1, const wxString& string2)
466{
097c080b
VZ
467 wxASSERT( string1.GetStringData()->IsValid() );
468 wxASSERT( string2.GetStringData()->IsValid() );
469
c801d85f
KB
470 wxString s;
471 s.ConcatCopy(string1.GetStringData()->nDataLength, string1.m_pchData,
472 string2.GetStringData()->nDataLength, string2.m_pchData);
473 return s;
474}
475
476wxString operator+(const wxString& string1, char ch)
477{
097c080b
VZ
478 wxASSERT( string1.GetStringData()->IsValid() );
479
c801d85f
KB
480 wxString s;
481 s.ConcatCopy(string1.GetStringData()->nDataLength, string1.m_pchData, 1, &ch);
482 return s;
483}
484
485wxString operator+(char ch, const wxString& string)
486{
097c080b
VZ
487 wxASSERT( string.GetStringData()->IsValid() );
488
c801d85f
KB
489 wxString s;
490 s.ConcatCopy(1, &ch, string.GetStringData()->nDataLength, string.m_pchData);
491 return s;
492}
493
494wxString operator+(const wxString& string, const char *psz)
495{
097c080b
VZ
496 wxASSERT( string.GetStringData()->IsValid() );
497
c801d85f
KB
498 wxString s;
499 s.ConcatCopy(string.GetStringData()->nDataLength, string.m_pchData,
500 Strlen(psz), psz);
501 return s;
502}
503
504wxString operator+(const char *psz, const wxString& string)
505{
097c080b
VZ
506 wxASSERT( string.GetStringData()->IsValid() );
507
c801d85f
KB
508 wxString s;
509 s.ConcatCopy(Strlen(psz), psz,
510 string.GetStringData()->nDataLength, string.m_pchData);
511 return s;
512}
513
514// ===========================================================================
515// other common string functions
516// ===========================================================================
517
518// ---------------------------------------------------------------------------
519// simple sub-string extraction
520// ---------------------------------------------------------------------------
521
522// helper function: clone the data attached to this string
523void wxString::AllocCopy(wxString& dest, int nCopyLen, int nCopyIndex) const
524{
525 if ( nCopyLen == 0 )
526 {
527 dest.Init();
528 }
529 else
530 {
531 dest.AllocBuffer(nCopyLen);
532 memcpy(dest.m_pchData, m_pchData + nCopyIndex, nCopyLen*sizeof(char));
533 }
534}
535
536// extract string of length nCount starting at nFirst
537// default value of nCount is 0 and means "till the end"
538wxString wxString::Mid(size_t nFirst, size_t nCount) const
539{
540 // out-of-bounds requests return sensible things
541 if ( nCount == 0 )
542 nCount = GetStringData()->nDataLength - nFirst;
543
544 if ( nFirst + nCount > (size_t)GetStringData()->nDataLength )
545 nCount = GetStringData()->nDataLength - nFirst;
546 if ( nFirst > (size_t)GetStringData()->nDataLength )
547 nCount = 0;
548
549 wxString dest;
550 AllocCopy(dest, nCount, nFirst);
551 return dest;
552}
553
554// extract nCount last (rightmost) characters
555wxString wxString::Right(size_t nCount) const
556{
557 if ( nCount > (size_t)GetStringData()->nDataLength )
558 nCount = GetStringData()->nDataLength;
559
560 wxString dest;
561 AllocCopy(dest, nCount, GetStringData()->nDataLength - nCount);
562 return dest;
563}
564
565// get all characters after the last occurence of ch
566// (returns the whole string if ch not found)
567wxString wxString::Right(char ch) const
568{
569 wxString str;
570 int iPos = Find(ch, TRUE);
571 if ( iPos == NOT_FOUND )
572 str = *this;
573 else
c8cfb486 574 str = c_str() + iPos + 1;
c801d85f
KB
575
576 return str;
577}
578
579// extract nCount first (leftmost) characters
580wxString wxString::Left(size_t nCount) const
581{
582 if ( nCount > (size_t)GetStringData()->nDataLength )
583 nCount = GetStringData()->nDataLength;
584
585 wxString dest;
586 AllocCopy(dest, nCount, 0);
587 return dest;
588}
589
590// get all characters before the first occurence of ch
591// (returns the whole string if ch not found)
592wxString wxString::Left(char ch) const
593{
594 wxString str;
595 for ( const char *pc = m_pchData; *pc != '\0' && *pc != ch; pc++ )
596 str += *pc;
597
598 return str;
599}
600
601/// get all characters before the last occurence of ch
602/// (returns empty string if ch not found)
603wxString wxString::Before(char ch) const
604{
605 wxString str;
606 int iPos = Find(ch, TRUE);
607 if ( iPos != NOT_FOUND && iPos != 0 )
d1c9bbf6 608 str = wxString(c_str(), iPos);
c801d85f
KB
609
610 return str;
611}
612
613/// get all characters after the first occurence of ch
614/// (returns empty string if ch not found)
615wxString wxString::After(char ch) const
616{
617 wxString str;
618 int iPos = Find(ch);
619 if ( iPos != NOT_FOUND )
620 str = c_str() + iPos + 1;
621
622 return str;
623}
624
625// replace first (or all) occurences of some substring with another one
626uint wxString::Replace(const char *szOld, const char *szNew, bool bReplaceAll)
627{
628 uint uiCount = 0; // count of replacements made
629
630 uint uiOldLen = Strlen(szOld);
631
632 wxString strTemp;
633 const char *pCurrent = m_pchData;
dd1eaa89 634 const char *pSubstr;
c801d85f
KB
635 while ( *pCurrent != '\0' ) {
636 pSubstr = strstr(pCurrent, szOld);
637 if ( pSubstr == NULL ) {
638 // strTemp is unused if no replacements were made, so avoid the copy
639 if ( uiCount == 0 )
640 return 0;
641
642 strTemp += pCurrent; // copy the rest
643 break; // exit the loop
644 }
645 else {
646 // take chars before match
647 strTemp.ConcatSelf(pSubstr - pCurrent, pCurrent);
648 strTemp += szNew;
649 pCurrent = pSubstr + uiOldLen; // restart after match
650
651 uiCount++;
652
653 // stop now?
654 if ( !bReplaceAll ) {
655 strTemp += pCurrent; // copy the rest
656 break; // exit the loop
657 }
658 }
659 }
660
661 // only done if there were replacements, otherwise would have returned above
662 *this = strTemp;
663
664 return uiCount;
665}
666
667bool wxString::IsAscii() const
668{
669 const char *s = (const char*) *this;
670 while(*s){
671 if(!isascii(*s)) return(FALSE);
672 s++;
673 }
674 return(TRUE);
675}
dd1eaa89 676
c801d85f
KB
677bool wxString::IsWord() const
678{
679 const char *s = (const char*) *this;
680 while(*s){
681 if(!isalpha(*s)) return(FALSE);
682 s++;
683 }
684 return(TRUE);
685}
dd1eaa89 686
c801d85f
KB
687bool wxString::IsNumber() const
688{
689 const char *s = (const char*) *this;
690 while(*s){
691 if(!isdigit(*s)) return(FALSE);
692 s++;
693 }
694 return(TRUE);
695}
696
c801d85f
KB
697wxString wxString::Strip(stripType w) const
698{
699 wxString s = *this;
700 if ( w & leading ) s.Trim(FALSE);
701 if ( w & trailing ) s.Trim(TRUE);
702 return s;
703}
704
c801d85f
KB
705// ---------------------------------------------------------------------------
706// case conversion
707// ---------------------------------------------------------------------------
708
709wxString& wxString::MakeUpper()
710{
711 CopyBeforeWrite();
712
713 for ( char *p = m_pchData; *p; p++ )
714 *p = (char)toupper(*p);
715
716 return *this;
717}
718
719wxString& wxString::MakeLower()
720{
721 CopyBeforeWrite();
dd1eaa89 722
c801d85f
KB
723 for ( char *p = m_pchData; *p; p++ )
724 *p = (char)tolower(*p);
725
726 return *this;
727}
728
729// ---------------------------------------------------------------------------
730// trimming and padding
731// ---------------------------------------------------------------------------
732
733// trims spaces (in the sense of isspace) from left or right side
734wxString& wxString::Trim(bool bFromRight)
735{
736 CopyBeforeWrite();
737
738 if ( bFromRight )
739 {
740 // find last non-space character
741 char *psz = m_pchData + GetStringData()->nDataLength - 1;
742 while ( isspace(*psz) && (psz >= m_pchData) )
743 psz--;
744
745 // truncate at trailing space start
746 *++psz = '\0';
747 GetStringData()->nDataLength = psz - m_pchData;
748 }
749 else
750 {
751 // find first non-space character
752 const char *psz = m_pchData;
753 while ( isspace(*psz) )
754 psz++;
755
756 // fix up data and length
757 int nDataLength = GetStringData()->nDataLength - (psz - m_pchData);
758 memmove(m_pchData, psz, (nDataLength + 1)*sizeof(char));
759 GetStringData()->nDataLength = nDataLength;
760 }
761
762 return *this;
763}
764
765// adds nCount characters chPad to the string from either side
766wxString& wxString::Pad(size_t nCount, char chPad, bool bFromRight)
767{
768 wxString s(chPad, nCount);
769
770 if ( bFromRight )
771 *this += s;
772 else
773 {
774 s += *this;
775 *this = s;
776 }
777
778 return *this;
779}
780
781// truncate the string
782wxString& wxString::Truncate(size_t uiLen)
783{
784 *(m_pchData + uiLen) = '\0';
785 GetStringData()->nDataLength = uiLen;
786
787 return *this;
788}
789
790// ---------------------------------------------------------------------------
791// finding (return NOT_FOUND if not found and index otherwise)
792// ---------------------------------------------------------------------------
793
794// find a character
795int wxString::Find(char ch, bool bFromEnd) const
796{
797 const char *psz = bFromEnd ? strrchr(m_pchData, ch) : strchr(m_pchData, ch);
798
799 return (psz == NULL) ? NOT_FOUND : psz - m_pchData;
800}
801
802// find a sub-string (like strstr)
803int wxString::Find(const char *pszSub) const
804{
805 const char *psz = strstr(m_pchData, pszSub);
806
807 return (psz == NULL) ? NOT_FOUND : psz - m_pchData;
808}
809
810// ---------------------------------------------------------------------------
9efd3367 811// formatted output
c801d85f
KB
812// ---------------------------------------------------------------------------
813int wxString::Printf(const char *pszFormat, ...)
814{
815 va_list argptr;
816 va_start(argptr, pszFormat);
817
818 int iLen = PrintfV(pszFormat, argptr);
819
820 va_end(argptr);
821
822 return iLen;
823}
824
825int wxString::PrintfV(const char* pszFormat, va_list argptr)
826{
9efd3367 827 static char s_szScratch[1024];
c801d85f
KB
828
829 int iLen = vsprintf(s_szScratch, pszFormat, argptr);
830 AllocBeforeWrite(iLen);
831 strcpy(m_pchData, s_szScratch);
832
833 return iLen;
834}
835
f0edd824 836#if 0
607d9061
JS
837int wxString::Scanf(const char *pszFormat, ...) const
838{
839 va_list argptr;
840 va_start(argptr, pszFormat);
841
842 int iLen = ScanfV(pszFormat, argptr);
843
844 va_end(argptr);
845
846 return iLen;
847}
848
849int wxString::ScanfV(const char *pszFormat, va_list argptr) const
850{
2049ba38 851#ifdef __WXMSW__
607d9061
JS
852 wxMessageBox("ScanfV not implemented");
853 return 0;
854#else
855 return vsscanf(c_str(), pszFormat, argptr);
856#endif
857}
f0edd824 858#endif
607d9061 859
097c080b
VZ
860// ----------------------------------------------------------------------------
861// misc other operations
862// ----------------------------------------------------------------------------
863bool wxString::Matches(const char *pszMask) const
864{
865 // check char by char
866 const char *pszTxt;
867 for ( pszTxt = c_str(); *pszMask != '\0'; pszMask++, pszTxt++ ) {
868 switch ( *pszMask ) {
869 case '?':
870 if ( *pszTxt == '\0' )
871 return FALSE;
872
873 pszTxt++;
874 pszMask++;
875 break;
876
877 case '*':
878 {
879 // ignore special chars immediately following this one
880 while ( *pszMask == '*' || *pszMask == '?' )
881 pszMask++;
882
883 // if there is nothing more, match
884 if ( *pszMask == '\0' )
885 return TRUE;
886
887 // are there any other metacharacters in the mask?
888 uint uiLenMask;
889 const char *pEndMask = strpbrk(pszMask, "*?");
890
891 if ( pEndMask != NULL ) {
892 // we have to match the string between two metachars
893 uiLenMask = pEndMask - pszMask;
894 }
895 else {
896 // we have to match the remainder of the string
897 uiLenMask = strlen(pszMask);
898 }
899
900 wxString strToMatch(pszMask, uiLenMask);
901 const char* pMatch = strstr(pszTxt, strToMatch);
902 if ( pMatch == NULL )
903 return FALSE;
904
905 // -1 to compensate "++" in the loop
906 pszTxt = pMatch + uiLenMask - 1;
907 pszMask += uiLenMask - 1;
908 }
909 break;
910
911 default:
912 if ( *pszMask != *pszTxt )
913 return FALSE;
914 break;
915 }
916 }
917
918 // match only if nothing left
919 return *pszTxt == '\0';
920}
921
c801d85f
KB
922// ---------------------------------------------------------------------------
923// standard C++ library string functions
924// ---------------------------------------------------------------------------
925#ifdef STD_STRING_COMPATIBILITY
926
927wxString& wxString::insert(size_t nPos, const wxString& str)
928{
097c080b 929 wxASSERT( str.GetStringData()->IsValid() );
c801d85f
KB
930 wxASSERT( nPos <= Len() );
931
932 wxString strTmp;
68919656 933 char *pc = strTmp.GetWriteBuf(Len() + str.Len());
c801d85f
KB
934 strncpy(pc, c_str(), nPos);
935 strcpy(pc + nPos, str);
936 strcpy(pc + nPos + str.Len(), c_str() + nPos);
abc79986 937 strTmp.UngetWriteBuf();
c801d85f 938 *this = strTmp;
dd1eaa89
VZ
939
940 return *this;
c801d85f
KB
941}
942
943size_t wxString::find(const wxString& str, size_t nStart) const
944{
097c080b 945 wxASSERT( str.GetStringData()->IsValid() );
c801d85f
KB
946 wxASSERT( nStart <= Len() );
947
948 const char *p = strstr(c_str() + nStart, str);
dd1eaa89 949
c801d85f
KB
950 return p == NULL ? npos : p - c_str();
951}
952
f0b3249b
JS
953// VC++ 1.5 can't cope with the default argument in the header.
954#if ! (defined(_MSC_VER) && !defined(__WIN32__))
c801d85f
KB
955size_t wxString::find(const char* sz, size_t nStart, size_t n) const
956{
957 return find(wxString(sz, n == npos ? 0 : n), nStart);
958}
f0b3249b 959#endif
dd1eaa89 960
c801d85f
KB
961size_t wxString::find(char ch, size_t nStart) const
962{
963 wxASSERT( nStart <= Len() );
964
965 const char *p = strchr(c_str() + nStart, ch);
dd1eaa89 966
c801d85f
KB
967 return p == NULL ? npos : p - c_str();
968}
969
970size_t wxString::rfind(const wxString& str, size_t nStart) const
971{
097c080b 972 wxASSERT( str.GetStringData()->IsValid() );
c801d85f
KB
973 wxASSERT( nStart <= Len() );
974
975 // # could be quicker than that
976 const char *p = c_str() + (nStart == npos ? Len() : nStart);
977 while ( p >= c_str() + str.Len() ) {
978 if ( strncmp(p - str.Len(), str, str.Len()) == 0 )
979 return p - str.Len() - c_str();
980 p--;
981 }
dd1eaa89 982
c801d85f
KB
983 return npos;
984}
dd1eaa89 985
f0b3249b
JS
986// VC++ 1.5 can't cope with the default argument in the header.
987#if ! (defined(_MSC_VER) && !defined(__WIN32__))
c801d85f
KB
988size_t wxString::rfind(const char* sz, size_t nStart, size_t n) const
989{
990 return rfind(wxString(sz, n == npos ? 0 : n), nStart);
991}
992
993size_t wxString::rfind(char ch, size_t nStart) const
994{
995 wxASSERT( nStart <= Len() );
996
997 const char *p = strrchr(c_str() + nStart, ch);
dd1eaa89 998
c801d85f
KB
999 return p == NULL ? npos : p - c_str();
1000}
f0b3249b 1001#endif
c801d85f
KB
1002
1003wxString wxString::substr(size_t nStart, size_t nLen) const
1004{
1005 // npos means 'take all'
1006 if ( nLen == npos )
1007 nLen = 0;
1008
1009 wxASSERT( nStart + nLen <= Len() );
1010
1011 return wxString(c_str() + nStart, nLen == npos ? 0 : nLen);
1012}
1013
1014wxString& wxString::erase(size_t nStart, size_t nLen)
1015{
1016 wxString strTmp(c_str(), nStart);
1017 if ( nLen != npos ) {
1018 wxASSERT( nStart + nLen <= Len() );
1019
1020 strTmp.append(c_str() + nStart + nLen);
1021 }
1022
1023 *this = strTmp;
1024 return *this;
1025}
1026
1027wxString& wxString::replace(size_t nStart, size_t nLen, const char *sz)
1028{
1029 wxASSERT( nStart + nLen <= Strlen(sz) );
1030
1031 wxString strTmp;
1032 if ( nStart != 0 )
1033 strTmp.append(c_str(), nStart);
1034 strTmp += sz;
1035 strTmp.append(c_str() + nStart + nLen);
dd1eaa89 1036
c801d85f
KB
1037 *this = strTmp;
1038 return *this;
1039}
1040
1041wxString& wxString::replace(size_t nStart, size_t nLen, size_t nCount, char ch)
1042{
1043 return replace(nStart, nLen, wxString(ch, nCount));
1044}
1045
dd1eaa89 1046wxString& wxString::replace(size_t nStart, size_t nLen,
097c080b 1047 const wxString& str, size_t nStart2, size_t nLen2)
c801d85f
KB
1048{
1049 return replace(nStart, nLen, str.substr(nStart2, nLen2));
1050}
1051
dd1eaa89 1052wxString& wxString::replace(size_t nStart, size_t nLen,
c801d85f
KB
1053 const char* sz, size_t nCount)
1054{
1055 return replace(nStart, nLen, wxString(sz, nCount));
1056}
1057
1058#endif //std::string compatibility
1059
1060// ============================================================================
1061// ArrayString
1062// ============================================================================
1063
1064// size increment = max(50% of current size, ARRAY_MAXSIZE_INCREMENT)
1065#define ARRAY_MAXSIZE_INCREMENT 4096
1066#ifndef ARRAY_DEFAULT_INITIAL_SIZE // also defined in dynarray.h
1067 #define ARRAY_DEFAULT_INITIAL_SIZE (16)
1068#endif
1069
1070#define STRING(p) ((wxString *)(&(p)))
1071
1072// ctor
1073wxArrayString::wxArrayString()
1074{
1075 m_nSize =
1076 m_nCount = 0;
1077 m_pItems = NULL;
1078}
1079
1080// copy ctor
1081wxArrayString::wxArrayString(const wxArrayString& src)
1082{
1083 m_nSize = src.m_nSize;
1084 m_nCount = src.m_nCount;
1085
1086 if ( m_nSize != 0 )
1087 m_pItems = new char *[m_nSize];
1088 else
1089 m_pItems = NULL;
1090
1091 if ( m_nCount != 0 )
1092 memcpy(m_pItems, src.m_pItems, m_nCount*sizeof(char *));
1093}
1094
1095// copy operator
1096wxArrayString& wxArrayString::operator=(const wxArrayString& src)
1097{
1098 DELETEA(m_pItems);
1099
1100 m_nSize = src.m_nSize;
1101 m_nCount = src.m_nCount;
1102
1103 if ( m_nSize != 0 )
dd1eaa89 1104 m_pItems = new char *[m_nCount];
c801d85f
KB
1105 else
1106 m_pItems = NULL;
1107
1108 if ( m_nCount != 0 )
1109 memcpy(m_pItems, src.m_pItems, m_nCount*sizeof(char *));
1110
1111 return *this;
1112}
1113
1114// grow the array
1115void wxArrayString::Grow()
1116{
1117 // only do it if no more place
1118 if( m_nCount == m_nSize ) {
1119 if( m_nSize == 0 ) {
1120 // was empty, alloc some memory
1121 m_nSize = ARRAY_DEFAULT_INITIAL_SIZE;
1122 m_pItems = new char *[m_nSize];
1123 }
1124 else {
1125 // add 50% but not too much
1126 size_t nIncrement = m_nSize >> 1;
1127 if ( nIncrement > ARRAY_MAXSIZE_INCREMENT )
1128 nIncrement = ARRAY_MAXSIZE_INCREMENT;
1129 m_nSize += nIncrement;
1130 char **pNew = new char *[m_nSize];
1131
1132 // copy data to new location
1133 memcpy(pNew, m_pItems, m_nCount*sizeof(char *));
1134
1135 // delete old memory (but do not release the strings!)
1136 DELETEA(m_pItems);
1137
1138 m_pItems = pNew;
1139 }
1140 }
1141}
1142
1143void wxArrayString::Free()
1144{
1145 for ( size_t n = 0; n < m_nCount; n++ ) {
1146 STRING(m_pItems[n])->GetStringData()->Unlock();
1147 }
1148}
1149
1150// deletes all the strings from the list
1151void wxArrayString::Empty()
1152{
1153 Free();
1154
1155 m_nCount = 0;
1156}
1157
1158// as Empty, but also frees memory
1159void wxArrayString::Clear()
1160{
1161 Free();
1162
dd1eaa89 1163 m_nSize =
c801d85f
KB
1164 m_nCount = 0;
1165
1166 DELETEA(m_pItems);
1167 m_pItems = NULL;
1168}
1169
1170// dtor
1171wxArrayString::~wxArrayString()
1172{
1173 Free();
1174
1175 DELETEA(m_pItems);
1176}
1177
1178// pre-allocates memory (frees the previous data!)
1179void wxArrayString::Alloc(size_t nSize)
1180{
1181 wxASSERT( nSize > 0 );
1182
1183 // only if old buffer was not big enough
1184 if ( nSize > m_nSize ) {
1185 Free();
1186 DELETEA(m_pItems);
1187 m_pItems = new char *[nSize];
1188 m_nSize = nSize;
1189 }
1190
1191 m_nCount = 0;
1192}
1193
1194// searches the array for an item (forward or backwards)
1195
9efd3367 1196// Robert Roebling (changed to bool from bool)
c801d85f
KB
1197
1198int wxArrayString::Index(const char *sz, bool bCase, bool bFromEnd) const
1199{
1200 if ( bFromEnd ) {
1201 if ( m_nCount > 0 ) {
1202 uint ui = m_nCount;
1203 do {
1204 if ( STRING(m_pItems[--ui])->IsSameAs(sz, bCase) )
1205 return ui;
1206 }
1207 while ( ui != 0 );
1208 }
1209 }
1210 else {
1211 for( uint ui = 0; ui < m_nCount; ui++ ) {
1212 if( STRING(m_pItems[ui])->IsSameAs(sz, bCase) )
1213 return ui;
1214 }
1215 }
1216
1217 return NOT_FOUND;
1218}
1219
1220// add item at the end
097c080b 1221void wxArrayString::Add(const wxString& str)
c801d85f 1222{
097c080b
VZ
1223 wxASSERT( str.GetStringData()->IsValid() );
1224
c801d85f
KB
1225 Grow();
1226
1227 // the string data must not be deleted!
097c080b
VZ
1228 str.GetStringData()->Lock();
1229 m_pItems[m_nCount++] = (char *)str.c_str();
c801d85f
KB
1230}
1231
1232// add item at the given position
097c080b 1233void wxArrayString::Insert(const wxString& str, size_t nIndex)
c801d85f 1234{
097c080b
VZ
1235 wxASSERT( str.GetStringData()->IsValid() );
1236
9efd3367 1237 wxCHECK_RET( nIndex <= m_nCount, "bad index in wxArrayString::Insert" );
c801d85f
KB
1238
1239 Grow();
1240
dd1eaa89 1241 memmove(&m_pItems[nIndex + 1], &m_pItems[nIndex],
c801d85f
KB
1242 (m_nCount - nIndex)*sizeof(char *));
1243
097c080b
VZ
1244 str.GetStringData()->Lock();
1245 m_pItems[nIndex] = (char *)str.c_str();
c801d85f
KB
1246
1247 m_nCount++;
1248}
1249
1250// removes item from array (by index)
1251void wxArrayString::Remove(size_t nIndex)
1252{
9efd3367 1253 wxCHECK_RET( nIndex <= m_nCount, "bad index in wxArrayString::Remove" );
c801d85f
KB
1254
1255 // release our lock
1256 Item(nIndex).GetStringData()->Unlock();
1257
dd1eaa89 1258 memmove(&m_pItems[nIndex], &m_pItems[nIndex + 1],
c801d85f
KB
1259 (m_nCount - nIndex - 1)*sizeof(char *));
1260 m_nCount--;
1261}
1262
1263// removes item from array (by value)
1264void wxArrayString::Remove(const char *sz)
1265{
1266 int iIndex = Index(sz);
1267
9efd3367
VZ
1268 wxCHECK_RET( iIndex != NOT_FOUND,
1269 "removing inexistent element in wxArrayString::Remove" );
c801d85f
KB
1270
1271 Remove((size_t)iIndex);
1272}
1273
1274// sort array elements using passed comparaison function
1275
c801d85f
KB
1276void wxArrayString::Sort(bool bCase, bool bReverse)
1277{
1278 //@@@@ TO DO
1279 //qsort(m_pItems, m_nCount, sizeof(char *), fCmp);
1280}