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