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