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