]> git.saurik.com Git - wxWidgets.git/blob - src/common/string.cpp
Unicode needs the 'experimental' printf, so define it if wxUSE_UNICODE
[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 #include "wx/intl.h"
38 #if wxUSE_THREADS
39 #include <wx/thread.h>
40 #endif
41 #endif
42
43 #include <ctype.h>
44 #include <string.h>
45 #include <stdlib.h>
46
47 #ifdef __SALFORDC__
48 #include <clib.h>
49 #endif
50
51 #if wxUSE_WCSRTOMBS
52 #include <wchar.h> // for wcsrtombs(), see comments where it's used
53 #endif // GNU
54
55 #ifdef WXSTRING_IS_WXOBJECT
56 IMPLEMENT_DYNAMIC_CLASS(wxString, wxObject)
57 #endif //WXSTRING_IS_WXOBJECT
58
59 #if wxUSE_UNICODE
60 #undef wxUSE_EXPERIMENTAL_PRINTF
61 #define wxUSE_EXPERIMENTAL_PRINTF 1
62 #endif
63
64 // allocating extra space for each string consumes more memory but speeds up
65 // the concatenation operations (nLen is the current string's length)
66 // NB: EXTRA_ALLOC must be >= 0!
67 #define EXTRA_ALLOC (19 - nLen % 16)
68
69 // ---------------------------------------------------------------------------
70 // static class variables definition
71 // ---------------------------------------------------------------------------
72
73 #ifdef wxSTD_STRING_COMPATIBILITY
74 const size_t wxString::npos = wxSTRING_MAXLEN;
75 #endif // wxSTD_STRING_COMPATIBILITY
76
77 // ----------------------------------------------------------------------------
78 // static data
79 // ----------------------------------------------------------------------------
80
81 // for an empty string, GetStringData() will return this address: this
82 // structure has the same layout as wxStringData and it's data() method will
83 // return the empty string (dummy pointer)
84 static const struct
85 {
86 wxStringData data;
87 wxChar dummy;
88 } g_strEmpty = { {-1, 0, 0}, _T('\0') };
89
90 // empty C style string: points to 'string data' byte of g_strEmpty
91 extern const wxChar WXDLLEXPORT *g_szNul = &g_strEmpty.dummy;
92
93 // ----------------------------------------------------------------------------
94 // conditional compilation
95 // ----------------------------------------------------------------------------
96
97 // we want to find out if the current platform supports vsnprintf()-like
98 // function: for Unix this is done with configure, for Windows we test the
99 // compiler explicitly.
100 #ifdef __WXMSW__
101 #ifdef __VISUALC__
102 #define wxVsnprintf _vsnprintf
103 #endif
104 #else // !Windows
105 #ifdef HAVE_VSNPRINTF
106 #define wxVsnprintf vsnprintf
107 #endif
108 #endif // Windows/!Windows
109
110 #ifndef wxVsnprintf
111 // in this case we'll use vsprintf() (which is ANSI and thus should be
112 // always available), but it's unsafe because it doesn't check for buffer
113 // size - so give a warning
114 #define wxVsnprintf(buffer,len,format,argptr) vsprintf(buffer,format, argptr)
115
116 #if defined(__VISUALC__)
117 #pragma message("Using sprintf() because no snprintf()-like function defined")
118 #elif defined(__GNUG__) && !defined(__UNIX__)
119 #warning "Using sprintf() because no snprintf()-like function defined"
120 #elif defined(__MWERKS__)
121 #warning "Using sprintf() because no snprintf()-like function defined"
122 #endif //compiler
123 #endif // no vsnprintf
124
125 #ifdef _AIX
126 // AIX has vsnprintf, but there's no prototype in the system headers.
127 extern "C" int vsnprintf(char* str, size_t n, const char* format, va_list ap);
128 #endif
129
130 // ----------------------------------------------------------------------------
131 // global functions
132 // ----------------------------------------------------------------------------
133
134 #ifdef wxSTD_STRING_COMPATIBILITY
135
136 // MS Visual C++ version 5.0 provides the new STL headers as well as the old
137 // iostream ones.
138 //
139 // ATTN: you can _not_ use both of these in the same program!
140
141 istream& operator>>(istream& is, wxString& WXUNUSED(str))
142 {
143 #if 0
144 int w = is.width(0);
145 if ( is.ipfx(0) ) {
146 streambuf *sb = is.rdbuf();
147 str.erase();
148 while ( true ) {
149 int ch = sb->sbumpc ();
150 if ( ch == EOF ) {
151 is.setstate(ios::eofbit);
152 break;
153 }
154 else if ( isspace(ch) ) {
155 sb->sungetc();
156 break;
157 }
158
159 str += ch;
160 if ( --w == 1 )
161 break;
162 }
163 }
164
165 is.isfx();
166 if ( str.length() == 0 )
167 is.setstate(ios::failbit);
168 #endif
169 return is;
170 }
171
172 #endif //std::string compatibility
173
174 // ----------------------------------------------------------------------------
175 // private classes
176 // ----------------------------------------------------------------------------
177
178 // this small class is used to gather statistics for performance tuning
179 //#define WXSTRING_STATISTICS
180 #ifdef WXSTRING_STATISTICS
181 class Averager
182 {
183 public:
184 Averager(const char *sz) { m_sz = sz; m_nTotal = m_nCount = 0; }
185 ~Averager()
186 { printf("wxString: average %s = %f\n", m_sz, ((float)m_nTotal)/m_nCount); }
187
188 void Add(size_t n) { m_nTotal += n; m_nCount++; }
189
190 private:
191 size_t m_nCount, m_nTotal;
192 const char *m_sz;
193 } g_averageLength("allocation size"),
194 g_averageSummandLength("summand length"),
195 g_averageConcatHit("hit probability in concat"),
196 g_averageInitialLength("initial string length");
197
198 #define STATISTICS_ADD(av, val) g_average##av.Add(val)
199 #else
200 #define STATISTICS_ADD(av, val)
201 #endif // WXSTRING_STATISTICS
202
203 // ===========================================================================
204 // wxString class core
205 // ===========================================================================
206
207 // ---------------------------------------------------------------------------
208 // construction
209 // ---------------------------------------------------------------------------
210
211 // constructs string of <nLength> copies of character <ch>
212 wxString::wxString(wxChar ch, size_t nLength)
213 {
214 Init();
215
216 if ( nLength > 0 ) {
217 AllocBuffer(nLength);
218
219 #if wxUSE_UNICODE
220 // memset only works on char
221 for (size_t n=0; n<nLength; n++) m_pchData[n] = ch;
222 #else
223 memset(m_pchData, ch, nLength);
224 #endif
225 }
226 }
227
228 // takes nLength elements of psz starting at nPos
229 void wxString::InitWith(const wxChar *psz, size_t nPos, size_t nLength)
230 {
231 Init();
232
233 wxASSERT( nPos <= wxStrlen(psz) );
234
235 if ( nLength == wxSTRING_MAXLEN )
236 nLength = wxStrlen(psz + nPos);
237
238 STATISTICS_ADD(InitialLength, nLength);
239
240 if ( nLength > 0 ) {
241 // trailing '\0' is written in AllocBuffer()
242 AllocBuffer(nLength);
243 memcpy(m_pchData, psz + nPos, nLength*sizeof(wxChar));
244 }
245 }
246
247 #ifdef wxSTD_STRING_COMPATIBILITY
248
249 // poor man's iterators are "void *" pointers
250 wxString::wxString(const void *pStart, const void *pEnd)
251 {
252 InitWith((const wxChar *)pStart, 0,
253 (const wxChar *)pEnd - (const wxChar *)pStart);
254 }
255
256 #endif //std::string compatibility
257
258 #if wxUSE_UNICODE
259
260 // from multibyte string
261 wxString::wxString(const char *psz, wxMBConv& conv, size_t nLength)
262 {
263 // first get necessary size
264 size_t nLen = psz ? conv.MB2WC((wchar_t *) NULL, psz, 0) : 0;
265
266 // nLength is number of *Unicode* characters here!
267 if ((nLen != (size_t)-1) && (nLen > nLength))
268 nLen = nLength;
269
270 // empty?
271 if ( (nLen != 0) && (nLen != (size_t)-1) ) {
272 AllocBuffer(nLen);
273 conv.MB2WC(m_pchData, psz, nLen);
274 }
275 else {
276 Init();
277 }
278 }
279
280 #else
281
282 #if wxUSE_WCHAR_T
283 // from wide string
284 wxString::wxString(const wchar_t *pwz)
285 {
286 // first get necessary size
287 size_t nLen = pwz ? wxWC2MB((char *) NULL, pwz, 0) : 0;
288
289 // empty?
290 if ( (nLen != 0) && (nLen != (size_t)-1) ) {
291 AllocBuffer(nLen);
292 wxWC2MB(m_pchData, pwz, nLen);
293 }
294 else {
295 Init();
296 }
297 }
298 #endif
299
300 #endif
301
302 // ---------------------------------------------------------------------------
303 // memory allocation
304 // ---------------------------------------------------------------------------
305
306 // allocates memory needed to store a C string of length nLen
307 void wxString::AllocBuffer(size_t nLen)
308 {
309 wxASSERT( nLen > 0 ); //
310 wxASSERT( nLen <= INT_MAX-1 ); // max size (enough room for 1 extra)
311
312 STATISTICS_ADD(Length, nLen);
313
314 // allocate memory:
315 // 1) one extra character for '\0' termination
316 // 2) sizeof(wxStringData) for housekeeping info
317 wxStringData* pData = (wxStringData*)
318 malloc(sizeof(wxStringData) + (nLen + EXTRA_ALLOC + 1)*sizeof(wxChar));
319 pData->nRefs = 1;
320 pData->nDataLength = nLen;
321 pData->nAllocLength = nLen + EXTRA_ALLOC;
322 m_pchData = pData->data(); // data starts after wxStringData
323 m_pchData[nLen] = _T('\0');
324 }
325
326 // must be called before changing this string
327 void wxString::CopyBeforeWrite()
328 {
329 wxStringData* pData = GetStringData();
330
331 if ( pData->IsShared() ) {
332 pData->Unlock(); // memory not freed because shared
333 size_t nLen = pData->nDataLength;
334 AllocBuffer(nLen);
335 memcpy(m_pchData, pData->data(), nLen*sizeof(wxChar));
336 }
337
338 wxASSERT( !GetStringData()->IsShared() ); // we must be the only owner
339 }
340
341 // must be called before replacing contents of this string
342 void wxString::AllocBeforeWrite(size_t nLen)
343 {
344 wxASSERT( nLen != 0 ); // doesn't make any sense
345
346 // must not share string and must have enough space
347 wxStringData* pData = GetStringData();
348 if ( pData->IsShared() || (nLen > pData->nAllocLength) ) {
349 // can't work with old buffer, get new one
350 pData->Unlock();
351 AllocBuffer(nLen);
352 }
353 else {
354 // update the string length
355 pData->nDataLength = nLen;
356 }
357
358 wxASSERT( !GetStringData()->IsShared() ); // we must be the only owner
359 }
360
361 // allocate enough memory for nLen characters
362 void wxString::Alloc(size_t nLen)
363 {
364 wxStringData *pData = GetStringData();
365 if ( pData->nAllocLength <= nLen ) {
366 if ( pData->IsEmpty() ) {
367 nLen += EXTRA_ALLOC;
368
369 wxStringData* pData = (wxStringData*)
370 malloc(sizeof(wxStringData) + (nLen + 1)*sizeof(wxChar));
371 pData->nRefs = 1;
372 pData->nDataLength = 0;
373 pData->nAllocLength = nLen;
374 m_pchData = pData->data(); // data starts after wxStringData
375 m_pchData[0u] = _T('\0');
376 }
377 else if ( pData->IsShared() ) {
378 pData->Unlock(); // memory not freed because shared
379 size_t nOldLen = pData->nDataLength;
380 AllocBuffer(nLen);
381 memcpy(m_pchData, pData->data(), nOldLen*sizeof(wxChar));
382 }
383 else {
384 nLen += EXTRA_ALLOC;
385
386 wxStringData *p = (wxStringData *)
387 realloc(pData, sizeof(wxStringData) + (nLen + 1)*sizeof(wxChar));
388
389 if ( p == NULL ) {
390 // @@@ what to do on memory error?
391 return;
392 }
393
394 // it's not important if the pointer changed or not (the check for this
395 // is not faster than assigning to m_pchData in all cases)
396 p->nAllocLength = nLen;
397 m_pchData = p->data();
398 }
399 }
400 //else: we've already got enough
401 }
402
403 // shrink to minimal size (releasing extra memory)
404 void wxString::Shrink()
405 {
406 wxStringData *pData = GetStringData();
407
408 // this variable is unused in release build, so avoid the compiler warning by
409 // just not declaring it
410 #ifdef __WXDEBUG__
411 void *p =
412 #endif
413 realloc(pData, sizeof(wxStringData) + (pData->nDataLength + 1)*sizeof(wxChar));
414
415 wxASSERT( p != NULL ); // can't free memory?
416 wxASSERT( p == pData ); // we're decrementing the size - block shouldn't move!
417 }
418
419 // get the pointer to writable buffer of (at least) nLen bytes
420 wxChar *wxString::GetWriteBuf(size_t nLen)
421 {
422 AllocBeforeWrite(nLen);
423
424 wxASSERT( GetStringData()->nRefs == 1 );
425 GetStringData()->Validate(FALSE);
426
427 return m_pchData;
428 }
429
430 // put string back in a reasonable state after GetWriteBuf
431 void wxString::UngetWriteBuf()
432 {
433 GetStringData()->nDataLength = wxStrlen(m_pchData);
434 GetStringData()->Validate(TRUE);
435 }
436
437 // ---------------------------------------------------------------------------
438 // data access
439 // ---------------------------------------------------------------------------
440
441 // all functions are inline in string.h
442
443 // ---------------------------------------------------------------------------
444 // assignment operators
445 // ---------------------------------------------------------------------------
446
447 // helper function: does real copy
448 void wxString::AssignCopy(size_t nSrcLen, const wxChar *pszSrcData)
449 {
450 if ( nSrcLen == 0 ) {
451 Reinit();
452 }
453 else {
454 AllocBeforeWrite(nSrcLen);
455 memcpy(m_pchData, pszSrcData, nSrcLen*sizeof(wxChar));
456 GetStringData()->nDataLength = nSrcLen;
457 m_pchData[nSrcLen] = _T('\0');
458 }
459 }
460
461 // assigns one string to another
462 wxString& wxString::operator=(const wxString& stringSrc)
463 {
464 wxASSERT( stringSrc.GetStringData()->IsValid() );
465
466 // don't copy string over itself
467 if ( m_pchData != stringSrc.m_pchData ) {
468 if ( stringSrc.GetStringData()->IsEmpty() ) {
469 Reinit();
470 }
471 else {
472 // adjust references
473 GetStringData()->Unlock();
474 m_pchData = stringSrc.m_pchData;
475 GetStringData()->Lock();
476 }
477 }
478
479 return *this;
480 }
481
482 // assigns a single character
483 wxString& wxString::operator=(wxChar ch)
484 {
485 AssignCopy(1, &ch);
486 return *this;
487 }
488
489 // assigns C string
490 wxString& wxString::operator=(const wxChar *psz)
491 {
492 AssignCopy(wxStrlen(psz), psz);
493 return *this;
494 }
495
496 #if !wxUSE_UNICODE
497
498 // same as 'signed char' variant
499 wxString& wxString::operator=(const unsigned char* psz)
500 {
501 *this = (const char *)psz;
502 return *this;
503 }
504
505 #if wxUSE_WCHAR_T
506 wxString& wxString::operator=(const wchar_t *pwz)
507 {
508 wxString str(pwz);
509 *this = str;
510 return *this;
511 }
512 #endif
513
514 #endif
515
516 // ---------------------------------------------------------------------------
517 // string concatenation
518 // ---------------------------------------------------------------------------
519
520 // add something to this string
521 void wxString::ConcatSelf(int nSrcLen, const wxChar *pszSrcData)
522 {
523 STATISTICS_ADD(SummandLength, nSrcLen);
524
525 // concatenating an empty string is a NOP
526 if ( nSrcLen > 0 ) {
527 wxStringData *pData = GetStringData();
528 size_t nLen = pData->nDataLength;
529 size_t nNewLen = nLen + nSrcLen;
530
531 // alloc new buffer if current is too small
532 if ( pData->IsShared() ) {
533 STATISTICS_ADD(ConcatHit, 0);
534
535 // we have to allocate another buffer
536 wxStringData* pOldData = GetStringData();
537 AllocBuffer(nNewLen);
538 memcpy(m_pchData, pOldData->data(), nLen*sizeof(wxChar));
539 pOldData->Unlock();
540 }
541 else if ( nNewLen > pData->nAllocLength ) {
542 STATISTICS_ADD(ConcatHit, 0);
543
544 // we have to grow the buffer
545 Alloc(nNewLen);
546 }
547 else {
548 STATISTICS_ADD(ConcatHit, 1);
549
550 // the buffer is already big enough
551 }
552
553 // should be enough space
554 wxASSERT( nNewLen <= GetStringData()->nAllocLength );
555
556 // fast concatenation - all is done in our buffer
557 memcpy(m_pchData + nLen, pszSrcData, nSrcLen*sizeof(wxChar));
558
559 m_pchData[nNewLen] = _T('\0'); // put terminating '\0'
560 GetStringData()->nDataLength = nNewLen; // and fix the length
561 }
562 //else: the string to append was empty
563 }
564
565 /*
566 * concatenation functions come in 5 flavours:
567 * string + string
568 * char + string and string + char
569 * C str + string and string + C str
570 */
571
572 wxString operator+(const wxString& string1, const wxString& string2)
573 {
574 wxASSERT( string1.GetStringData()->IsValid() );
575 wxASSERT( string2.GetStringData()->IsValid() );
576
577 wxString s = string1;
578 s += string2;
579
580 return s;
581 }
582
583 wxString operator+(const wxString& string, wxChar ch)
584 {
585 wxASSERT( string.GetStringData()->IsValid() );
586
587 wxString s = string;
588 s += ch;
589
590 return s;
591 }
592
593 wxString operator+(wxChar ch, const wxString& string)
594 {
595 wxASSERT( string.GetStringData()->IsValid() );
596
597 wxString s = ch;
598 s += string;
599
600 return s;
601 }
602
603 wxString operator+(const wxString& string, const wxChar *psz)
604 {
605 wxASSERT( string.GetStringData()->IsValid() );
606
607 wxString s;
608 s.Alloc(wxStrlen(psz) + string.Len());
609 s = string;
610 s += psz;
611
612 return s;
613 }
614
615 wxString operator+(const wxChar *psz, const wxString& string)
616 {
617 wxASSERT( string.GetStringData()->IsValid() );
618
619 wxString s;
620 s.Alloc(wxStrlen(psz) + string.Len());
621 s = psz;
622 s += string;
623
624 return s;
625 }
626
627 // ===========================================================================
628 // other common string functions
629 // ===========================================================================
630
631 // ---------------------------------------------------------------------------
632 // simple sub-string extraction
633 // ---------------------------------------------------------------------------
634
635 // helper function: clone the data attached to this string
636 void wxString::AllocCopy(wxString& dest, int nCopyLen, int nCopyIndex) const
637 {
638 if ( nCopyLen == 0 ) {
639 dest.Init();
640 }
641 else {
642 dest.AllocBuffer(nCopyLen);
643 memcpy(dest.m_pchData, m_pchData + nCopyIndex, nCopyLen*sizeof(wxChar));
644 }
645 }
646
647 // extract string of length nCount starting at nFirst
648 wxString wxString::Mid(size_t nFirst, size_t nCount) const
649 {
650 wxStringData *pData = GetStringData();
651 size_t nLen = pData->nDataLength;
652
653 // default value of nCount is wxSTRING_MAXLEN and means "till the end"
654 if ( nCount == wxSTRING_MAXLEN )
655 {
656 nCount = nLen - nFirst;
657 }
658
659 // out-of-bounds requests return sensible things
660 if ( nFirst + nCount > nLen )
661 {
662 nCount = nLen - nFirst;
663 }
664
665 if ( nFirst > nLen )
666 {
667 // AllocCopy() will return empty string
668 nCount = 0;
669 }
670
671 wxString dest;
672 AllocCopy(dest, nCount, nFirst);
673
674 return dest;
675 }
676
677 // extract nCount last (rightmost) characters
678 wxString wxString::Right(size_t nCount) const
679 {
680 if ( nCount > (size_t)GetStringData()->nDataLength )
681 nCount = GetStringData()->nDataLength;
682
683 wxString dest;
684 AllocCopy(dest, nCount, GetStringData()->nDataLength - nCount);
685 return dest;
686 }
687
688 // get all characters after the last occurence of ch
689 // (returns the whole string if ch not found)
690 wxString wxString::AfterLast(wxChar ch) const
691 {
692 wxString str;
693 int iPos = Find(ch, TRUE);
694 if ( iPos == wxNOT_FOUND )
695 str = *this;
696 else
697 str = c_str() + iPos + 1;
698
699 return str;
700 }
701
702 // extract nCount first (leftmost) characters
703 wxString wxString::Left(size_t nCount) const
704 {
705 if ( nCount > (size_t)GetStringData()->nDataLength )
706 nCount = GetStringData()->nDataLength;
707
708 wxString dest;
709 AllocCopy(dest, nCount, 0);
710 return dest;
711 }
712
713 // get all characters before the first occurence of ch
714 // (returns the whole string if ch not found)
715 wxString wxString::BeforeFirst(wxChar ch) const
716 {
717 wxString str;
718 for ( const wxChar *pc = m_pchData; *pc != _T('\0') && *pc != ch; pc++ )
719 str += *pc;
720
721 return str;
722 }
723
724 /// get all characters before the last occurence of ch
725 /// (returns empty string if ch not found)
726 wxString wxString::BeforeLast(wxChar ch) const
727 {
728 wxString str;
729 int iPos = Find(ch, TRUE);
730 if ( iPos != wxNOT_FOUND && iPos != 0 )
731 str = wxString(c_str(), iPos);
732
733 return str;
734 }
735
736 /// get all characters after the first occurence of ch
737 /// (returns empty string if ch not found)
738 wxString wxString::AfterFirst(wxChar ch) const
739 {
740 wxString str;
741 int iPos = Find(ch);
742 if ( iPos != wxNOT_FOUND )
743 str = c_str() + iPos + 1;
744
745 return str;
746 }
747
748 // replace first (or all) occurences of some substring with another one
749 size_t wxString::Replace(const wxChar *szOld, const wxChar *szNew, bool bReplaceAll)
750 {
751 size_t uiCount = 0; // count of replacements made
752
753 size_t uiOldLen = wxStrlen(szOld);
754
755 wxString strTemp;
756 const wxChar *pCurrent = m_pchData;
757 const wxChar *pSubstr;
758 while ( *pCurrent != _T('\0') ) {
759 pSubstr = wxStrstr(pCurrent, szOld);
760 if ( pSubstr == NULL ) {
761 // strTemp is unused if no replacements were made, so avoid the copy
762 if ( uiCount == 0 )
763 return 0;
764
765 strTemp += pCurrent; // copy the rest
766 break; // exit the loop
767 }
768 else {
769 // take chars before match
770 strTemp.ConcatSelf(pSubstr - pCurrent, pCurrent);
771 strTemp += szNew;
772 pCurrent = pSubstr + uiOldLen; // restart after match
773
774 uiCount++;
775
776 // stop now?
777 if ( !bReplaceAll ) {
778 strTemp += pCurrent; // copy the rest
779 break; // exit the loop
780 }
781 }
782 }
783
784 // only done if there were replacements, otherwise would have returned above
785 *this = strTemp;
786
787 return uiCount;
788 }
789
790 bool wxString::IsAscii() const
791 {
792 const wxChar *s = (const wxChar*) *this;
793 while(*s){
794 if(!isascii(*s)) return(FALSE);
795 s++;
796 }
797 return(TRUE);
798 }
799
800 bool wxString::IsWord() const
801 {
802 const wxChar *s = (const wxChar*) *this;
803 while(*s){
804 if(!wxIsalpha(*s)) return(FALSE);
805 s++;
806 }
807 return(TRUE);
808 }
809
810 bool wxString::IsNumber() const
811 {
812 const wxChar *s = (const wxChar*) *this;
813 while(*s){
814 if(!wxIsdigit(*s)) return(FALSE);
815 s++;
816 }
817 return(TRUE);
818 }
819
820 wxString wxString::Strip(stripType w) const
821 {
822 wxString s = *this;
823 if ( w & leading ) s.Trim(FALSE);
824 if ( w & trailing ) s.Trim(TRUE);
825 return s;
826 }
827
828 // ---------------------------------------------------------------------------
829 // case conversion
830 // ---------------------------------------------------------------------------
831
832 wxString& wxString::MakeUpper()
833 {
834 CopyBeforeWrite();
835
836 for ( wxChar *p = m_pchData; *p; p++ )
837 *p = (wxChar)wxToupper(*p);
838
839 return *this;
840 }
841
842 wxString& wxString::MakeLower()
843 {
844 CopyBeforeWrite();
845
846 for ( wxChar *p = m_pchData; *p; p++ )
847 *p = (wxChar)wxTolower(*p);
848
849 return *this;
850 }
851
852 // ---------------------------------------------------------------------------
853 // trimming and padding
854 // ---------------------------------------------------------------------------
855
856 // trims spaces (in the sense of isspace) from left or right side
857 wxString& wxString::Trim(bool bFromRight)
858 {
859 // first check if we're going to modify the string at all
860 if ( !IsEmpty() &&
861 (
862 (bFromRight && wxIsspace(GetChar(Len() - 1))) ||
863 (!bFromRight && wxIsspace(GetChar(0u)))
864 )
865 )
866 {
867 // ok, there is at least one space to trim
868 CopyBeforeWrite();
869
870 if ( bFromRight )
871 {
872 // find last non-space character
873 wxChar *psz = m_pchData + GetStringData()->nDataLength - 1;
874 while ( wxIsspace(*psz) && (psz >= m_pchData) )
875 psz--;
876
877 // truncate at trailing space start
878 *++psz = _T('\0');
879 GetStringData()->nDataLength = psz - m_pchData;
880 }
881 else
882 {
883 // find first non-space character
884 const wxChar *psz = m_pchData;
885 while ( wxIsspace(*psz) )
886 psz++;
887
888 // fix up data and length
889 int nDataLength = GetStringData()->nDataLength - (psz - (const wxChar*) m_pchData);
890 memmove(m_pchData, psz, (nDataLength + 1)*sizeof(wxChar));
891 GetStringData()->nDataLength = nDataLength;
892 }
893 }
894
895 return *this;
896 }
897
898 // adds nCount characters chPad to the string from either side
899 wxString& wxString::Pad(size_t nCount, wxChar chPad, bool bFromRight)
900 {
901 wxString s(chPad, nCount);
902
903 if ( bFromRight )
904 *this += s;
905 else
906 {
907 s += *this;
908 *this = s;
909 }
910
911 return *this;
912 }
913
914 // truncate the string
915 wxString& wxString::Truncate(size_t uiLen)
916 {
917 if ( uiLen < Len() ) {
918 CopyBeforeWrite();
919
920 *(m_pchData + uiLen) = _T('\0');
921 GetStringData()->nDataLength = uiLen;
922 }
923 //else: nothing to do, string is already short enough
924
925 return *this;
926 }
927
928 // ---------------------------------------------------------------------------
929 // finding (return wxNOT_FOUND if not found and index otherwise)
930 // ---------------------------------------------------------------------------
931
932 // find a character
933 int wxString::Find(wxChar ch, bool bFromEnd) const
934 {
935 const wxChar *psz = bFromEnd ? wxStrrchr(m_pchData, ch) : wxStrchr(m_pchData, ch);
936
937 return (psz == NULL) ? wxNOT_FOUND : psz - (const wxChar*) m_pchData;
938 }
939
940 // find a sub-string (like strstr)
941 int wxString::Find(const wxChar *pszSub) const
942 {
943 const wxChar *psz = wxStrstr(m_pchData, pszSub);
944
945 return (psz == NULL) ? wxNOT_FOUND : psz - (const wxChar*) m_pchData;
946 }
947
948 // ---------------------------------------------------------------------------
949 // stream-like operators
950 // ---------------------------------------------------------------------------
951 wxString& wxString::operator<<(int i)
952 {
953 wxString res;
954 res.Printf(_T("%d"), i);
955
956 return (*this) << res;
957 }
958
959 wxString& wxString::operator<<(float f)
960 {
961 wxString res;
962 res.Printf(_T("%f"), f);
963
964 return (*this) << res;
965 }
966
967 wxString& wxString::operator<<(double d)
968 {
969 wxString res;
970 res.Printf(_T("%g"), d);
971
972 return (*this) << res;
973 }
974
975 // ---------------------------------------------------------------------------
976 // formatted output
977 // ---------------------------------------------------------------------------
978 int wxString::Printf(const wxChar *pszFormat, ...)
979 {
980 va_list argptr;
981 va_start(argptr, pszFormat);
982
983 int iLen = PrintfV(pszFormat, argptr);
984
985 va_end(argptr);
986
987 return iLen;
988 }
989
990 int wxString::PrintfV(const wxChar* pszFormat, va_list argptr)
991 {
992 // static buffer to avoid dynamic memory allocation each time
993 char s_szScratch[1024]; // using static buffer causes internal compiler err
994 #if 0
995 #if wxUSE_THREADS
996 // protect the static buffer
997 static wxCriticalSection critsect;
998 wxCriticalSectionLocker lock(critsect);
999 #endif
1000 #endif
1001
1002 #if wxUSE_EXPERIMENTAL_PRINTF
1003 // the new implementation
1004
1005 Reinit();
1006 for (size_t n = 0; pszFormat[n]; n++)
1007 if (pszFormat[n] == _T('%')) {
1008 static char s_szFlags[256] = "%";
1009 size_t flagofs = 1;
1010 bool adj_left = FALSE, in_prec = FALSE,
1011 prec_dot = FALSE, done = FALSE;
1012 int ilen = 0;
1013 size_t min_width = 0, max_width = wxSTRING_MAXLEN;
1014 do {
1015 #define CHECK_PREC if (in_prec && !prec_dot) { s_szFlags[flagofs++] = '.'; prec_dot = TRUE; }
1016 switch (pszFormat[++n]) {
1017 case _T('\0'):
1018 done = TRUE;
1019 break;
1020 case _T('%'):
1021 *this += _T('%');
1022 done = TRUE;
1023 break;
1024 case _T('#'):
1025 case _T('0'):
1026 case _T(' '):
1027 case _T('+'):
1028 case _T('\''):
1029 CHECK_PREC
1030 s_szFlags[flagofs++] = pszFormat[n];
1031 break;
1032 case _T('-'):
1033 CHECK_PREC
1034 adj_left = TRUE;
1035 s_szFlags[flagofs++] = pszFormat[n];
1036 break;
1037 case _T('.'):
1038 CHECK_PREC
1039 in_prec = TRUE;
1040 prec_dot = FALSE;
1041 max_width = 0;
1042 // dot will be auto-added to s_szFlags if non-negative number follows
1043 break;
1044 case _T('h'):
1045 ilen = -1;
1046 CHECK_PREC
1047 s_szFlags[flagofs++] = pszFormat[n];
1048 break;
1049 case _T('l'):
1050 ilen = 1;
1051 CHECK_PREC
1052 s_szFlags[flagofs++] = pszFormat[n];
1053 break;
1054 case _T('q'):
1055 case _T('L'):
1056 ilen = 2;
1057 CHECK_PREC
1058 s_szFlags[flagofs++] = pszFormat[n];
1059 break;
1060 case _T('Z'):
1061 ilen = 3;
1062 CHECK_PREC
1063 s_szFlags[flagofs++] = pszFormat[n];
1064 break;
1065 case _T('*'):
1066 {
1067 int len = va_arg(argptr, int);
1068 if (in_prec) {
1069 if (len<0) break;
1070 CHECK_PREC
1071 max_width = len;
1072 } else {
1073 if (len<0) {
1074 adj_left = !adj_left;
1075 s_szFlags[flagofs++] = '-';
1076 len = -len;
1077 }
1078 min_width = len;
1079 }
1080 flagofs += ::sprintf(s_szFlags+flagofs,"%d",len);
1081 }
1082 break;
1083 case _T('1'): case _T('2'): case _T('3'):
1084 case _T('4'): case _T('5'): case _T('6'):
1085 case _T('7'): case _T('8'): case _T('9'):
1086 {
1087 int len = 0;
1088 CHECK_PREC
1089 while ((pszFormat[n]>=_T('0')) && (pszFormat[n]<=_T('9'))) {
1090 s_szFlags[flagofs++] = pszFormat[n];
1091 len = len*10 + (pszFormat[n] - _T('0'));
1092 n++;
1093 }
1094 if (in_prec) max_width = len;
1095 else min_width = len;
1096 n--; // the main loop pre-increments n again
1097 }
1098 break;
1099 case _T('d'):
1100 case _T('i'):
1101 case _T('o'):
1102 case _T('u'):
1103 case _T('x'):
1104 case _T('X'):
1105 CHECK_PREC
1106 s_szFlags[flagofs++] = pszFormat[n];
1107 s_szFlags[flagofs] = '\0';
1108 if (ilen == 0 ) {
1109 int val = va_arg(argptr, int);
1110 ::sprintf(s_szScratch, s_szFlags, val);
1111 }
1112 else if (ilen == -1) {
1113 short int val = va_arg(argptr, short int);
1114 ::sprintf(s_szScratch, s_szFlags, val);
1115 }
1116 else if (ilen == 1) {
1117 long int val = va_arg(argptr, long int);
1118 ::sprintf(s_szScratch, s_szFlags, val);
1119 }
1120 else if (ilen == 2) {
1121 #if SIZEOF_LONG_LONG
1122 long long int val = va_arg(argptr, long long int);
1123 ::sprintf(s_szScratch, s_szFlags, val);
1124 #else
1125 long int val = va_arg(argptr, long int);
1126 ::sprintf(s_szScratch, s_szFlags, val);
1127 #endif
1128 }
1129 else if (ilen == 3) {
1130 size_t val = va_arg(argptr, size_t);
1131 ::sprintf(s_szScratch, s_szFlags, val);
1132 }
1133 *this += wxString(s_szScratch);
1134 done = TRUE;
1135 break;
1136 case _T('e'):
1137 case _T('E'):
1138 case _T('f'):
1139 case _T('g'):
1140 case _T('G'):
1141 CHECK_PREC
1142 s_szFlags[flagofs++] = pszFormat[n];
1143 s_szFlags[flagofs] = '\0';
1144 if (ilen == 2) {
1145 long double val = va_arg(argptr, long double);
1146 ::sprintf(s_szScratch, s_szFlags, val);
1147 } else {
1148 double val = va_arg(argptr, double);
1149 ::sprintf(s_szScratch, s_szFlags, val);
1150 }
1151 *this += wxString(s_szScratch);
1152 done = TRUE;
1153 break;
1154 case _T('p'):
1155 {
1156 void *val = va_arg(argptr, void *);
1157 CHECK_PREC
1158 s_szFlags[flagofs++] = pszFormat[n];
1159 s_szFlags[flagofs] = '\0';
1160 ::sprintf(s_szScratch, s_szFlags, val);
1161 *this += wxString(s_szScratch);
1162 done = TRUE;
1163 }
1164 break;
1165 case _T('c'):
1166 {
1167 wxChar val = va_arg(argptr, int);
1168 // we don't need to honor padding here, do we?
1169 *this += val;
1170 done = TRUE;
1171 }
1172 break;
1173 case _T('s'):
1174 if (ilen == -1) {
1175 // wx extension: we'll let %hs mean non-Unicode strings
1176 char *val = va_arg(argptr, char *);
1177 #if wxUSE_UNICODE
1178 // ASCII->Unicode constructor handles max_width right
1179 wxString s(val, wxConvLibc, max_width);
1180 #else
1181 size_t len = wxSTRING_MAXLEN;
1182 if (val) {
1183 for (len = 0; val[len] && (len<max_width); len++);
1184 } else val = _T("(null)");
1185 wxString s(val, len);
1186 #endif
1187 if (s.Len() < min_width)
1188 s.Pad(min_width - s.Len(), _T(' '), adj_left);
1189 *this += s;
1190 } else {
1191 wxChar *val = va_arg(argptr, wxChar *);
1192 size_t len = wxSTRING_MAXLEN;
1193 if (val) {
1194 for (len = 0; val[len] && (len<max_width); len++);
1195 } else val = _T("(null)");
1196 wxString s(val, len);
1197 if (s.Len() < min_width)
1198 s.Pad(min_width - s.Len(), _T(' '), adj_left);
1199 *this += s;
1200 }
1201 done = TRUE;
1202 break;
1203 case _T('n'):
1204 if (ilen == 0) {
1205 int *val = va_arg(argptr, int *);
1206 *val = Len();
1207 }
1208 else if (ilen == -1) {
1209 short int *val = va_arg(argptr, short int *);
1210 *val = Len();
1211 }
1212 else if (ilen >= 1) {
1213 long int *val = va_arg(argptr, long int *);
1214 *val = Len();
1215 }
1216 done = TRUE;
1217 break;
1218 default:
1219 if (wxIsalpha(pszFormat[n]))
1220 // probably some flag not taken care of here yet
1221 s_szFlags[flagofs++] = pszFormat[n];
1222 else {
1223 // bad format
1224 *this += _T('%'); // just to pass the glibc tst-printf.c
1225 n--;
1226 done = TRUE;
1227 }
1228 break;
1229 }
1230 #undef CHECK_PREC
1231 } while (!done);
1232 } else *this += pszFormat[n];
1233
1234 #else
1235 // NB: wxVsnprintf() may return either less than the buffer size or -1 if there
1236 // is not enough place depending on implementation
1237 int iLen = wxVsnprintf(s_szScratch, WXSIZEOF(s_szScratch), pszFormat, argptr);
1238 char *buffer;
1239 if ( iLen < (int)WXSIZEOF(s_szScratch) ) {
1240 buffer = s_szScratch;
1241 }
1242 else {
1243 int size = WXSIZEOF(s_szScratch) * 2;
1244 buffer = (char *)malloc(size);
1245 while ( buffer != NULL ) {
1246 iLen = wxVsnprintf(buffer, WXSIZEOF(s_szScratch), pszFormat, argptr);
1247 if ( iLen < size ) {
1248 // ok, there was enough space
1249 break;
1250 }
1251
1252 // still not enough, double it again
1253 buffer = (char *)realloc(buffer, size *= 2);
1254 }
1255
1256 if ( !buffer ) {
1257 // out of memory
1258 return -1;
1259 }
1260 }
1261
1262 wxString s(buffer);
1263 *this = s;
1264
1265 if ( buffer != s_szScratch )
1266 free(buffer);
1267 #endif
1268
1269 return Len();
1270 }
1271
1272 // ----------------------------------------------------------------------------
1273 // misc other operations
1274 // ----------------------------------------------------------------------------
1275 bool wxString::Matches(const wxChar *pszMask) const
1276 {
1277 // check char by char
1278 const wxChar *pszTxt;
1279 for ( pszTxt = c_str(); *pszMask != _T('\0'); pszMask++, pszTxt++ ) {
1280 switch ( *pszMask ) {
1281 case _T('?'):
1282 if ( *pszTxt == _T('\0') )
1283 return FALSE;
1284
1285 pszTxt++;
1286 pszMask++;
1287 break;
1288
1289 case _T('*'):
1290 {
1291 // ignore special chars immediately following this one
1292 while ( *pszMask == _T('*') || *pszMask == _T('?') )
1293 pszMask++;
1294
1295 // if there is nothing more, match
1296 if ( *pszMask == _T('\0') )
1297 return TRUE;
1298
1299 // are there any other metacharacters in the mask?
1300 size_t uiLenMask;
1301 const wxChar *pEndMask = wxStrpbrk(pszMask, _T("*?"));
1302
1303 if ( pEndMask != NULL ) {
1304 // we have to match the string between two metachars
1305 uiLenMask = pEndMask - pszMask;
1306 }
1307 else {
1308 // we have to match the remainder of the string
1309 uiLenMask = wxStrlen(pszMask);
1310 }
1311
1312 wxString strToMatch(pszMask, uiLenMask);
1313 const wxChar* pMatch = wxStrstr(pszTxt, strToMatch);
1314 if ( pMatch == NULL )
1315 return FALSE;
1316
1317 // -1 to compensate "++" in the loop
1318 pszTxt = pMatch + uiLenMask - 1;
1319 pszMask += uiLenMask - 1;
1320 }
1321 break;
1322
1323 default:
1324 if ( *pszMask != *pszTxt )
1325 return FALSE;
1326 break;
1327 }
1328 }
1329
1330 // match only if nothing left
1331 return *pszTxt == _T('\0');
1332 }
1333
1334 // Count the number of chars
1335 int wxString::Freq(wxChar ch) const
1336 {
1337 int count = 0;
1338 int len = Len();
1339 for (int i = 0; i < len; i++)
1340 {
1341 if (GetChar(i) == ch)
1342 count ++;
1343 }
1344 return count;
1345 }
1346
1347 // convert to upper case, return the copy of the string
1348 wxString wxString::Upper() const
1349 { wxString s(*this); return s.MakeUpper(); }
1350
1351 // convert to lower case, return the copy of the string
1352 wxString wxString::Lower() const { wxString s(*this); return s.MakeLower(); }
1353
1354 int wxString::sprintf(const wxChar *pszFormat, ...)
1355 {
1356 va_list argptr;
1357 va_start(argptr, pszFormat);
1358 int iLen = PrintfV(pszFormat, argptr);
1359 va_end(argptr);
1360 return iLen;
1361 }
1362
1363 // ---------------------------------------------------------------------------
1364 // standard C++ library string functions
1365 // ---------------------------------------------------------------------------
1366 #ifdef wxSTD_STRING_COMPATIBILITY
1367
1368 wxString& wxString::insert(size_t nPos, const wxString& str)
1369 {
1370 wxASSERT( str.GetStringData()->IsValid() );
1371 wxASSERT( nPos <= Len() );
1372
1373 if ( !str.IsEmpty() ) {
1374 wxString strTmp;
1375 wxChar *pc = strTmp.GetWriteBuf(Len() + str.Len());
1376 wxStrncpy(pc, c_str(), nPos);
1377 wxStrcpy(pc + nPos, str);
1378 wxStrcpy(pc + nPos + str.Len(), c_str() + nPos);
1379 strTmp.UngetWriteBuf();
1380 *this = strTmp;
1381 }
1382
1383 return *this;
1384 }
1385
1386 size_t wxString::find(const wxString& str, size_t nStart) const
1387 {
1388 wxASSERT( str.GetStringData()->IsValid() );
1389 wxASSERT( nStart <= Len() );
1390
1391 const wxChar *p = wxStrstr(c_str() + nStart, str);
1392
1393 return p == NULL ? npos : p - c_str();
1394 }
1395
1396 // VC++ 1.5 can't cope with the default argument in the header.
1397 #if !defined(__VISUALC__) || defined(__WIN32__)
1398 size_t wxString::find(const wxChar* sz, size_t nStart, size_t n) const
1399 {
1400 return find(wxString(sz, n == npos ? 0 : n), nStart);
1401 }
1402 #endif // VC++ 1.5
1403
1404 // Gives a duplicate symbol (presumably a case-insensitivity problem)
1405 #if !defined(__BORLANDC__)
1406 size_t wxString::find(wxChar ch, size_t nStart) const
1407 {
1408 wxASSERT( nStart <= Len() );
1409
1410 const wxChar *p = wxStrchr(c_str() + nStart, ch);
1411
1412 return p == NULL ? npos : p - c_str();
1413 }
1414 #endif
1415
1416 size_t wxString::rfind(const wxString& str, size_t nStart) const
1417 {
1418 wxASSERT( str.GetStringData()->IsValid() );
1419 wxASSERT( nStart <= Len() );
1420
1421 // TODO could be made much quicker than that
1422 const wxChar *p = c_str() + (nStart == npos ? Len() : nStart);
1423 while ( p >= c_str() + str.Len() ) {
1424 if ( wxStrncmp(p - str.Len(), str, str.Len()) == 0 )
1425 return p - str.Len() - c_str();
1426 p--;
1427 }
1428
1429 return npos;
1430 }
1431
1432 // VC++ 1.5 can't cope with the default argument in the header.
1433 #if !defined(__VISUALC__) || defined(__WIN32__)
1434 size_t wxString::rfind(const wxChar* sz, size_t nStart, size_t n) const
1435 {
1436 return rfind(wxString(sz, n == npos ? 0 : n), nStart);
1437 }
1438
1439 size_t wxString::rfind(wxChar ch, size_t nStart) const
1440 {
1441 if ( nStart == npos )
1442 {
1443 nStart = Len();
1444 }
1445 else
1446 {
1447 wxASSERT( nStart <= Len() );
1448 }
1449
1450 const wxChar *p = wxStrrchr(c_str(), ch);
1451
1452 if ( p == NULL )
1453 return npos;
1454
1455 size_t result = p - c_str();
1456 return ( result > nStart ) ? npos : result;
1457 }
1458 #endif // VC++ 1.5
1459
1460 size_t wxString::find_first_of(const wxChar* sz, size_t nStart) const
1461 {
1462 const wxChar *start = c_str() + nStart;
1463 const wxChar *firstOf = wxStrpbrk(start, sz);
1464 if ( firstOf )
1465 return firstOf - start;
1466 else
1467 return npos;
1468 }
1469
1470 size_t wxString::find_last_of(const wxChar* sz, size_t nStart) const
1471 {
1472 if ( nStart == npos )
1473 {
1474 nStart = Len();
1475 }
1476 else
1477 {
1478 wxASSERT( nStart <= Len() );
1479 }
1480
1481 for ( const wxChar *p = c_str() + length() - 1; p >= c_str(); p-- )
1482 {
1483 if ( wxStrchr(sz, *p) )
1484 return p - c_str();
1485 }
1486
1487 return npos;
1488 }
1489
1490 size_t wxString::find_first_not_of(const wxChar* sz, size_t nStart) const
1491 {
1492 if ( nStart == npos )
1493 {
1494 nStart = Len();
1495 }
1496 else
1497 {
1498 wxASSERT( nStart <= Len() );
1499 }
1500
1501 size_t nAccept = wxStrspn(c_str() + nStart, sz);
1502 if ( nAccept >= length() - nStart )
1503 return npos;
1504 else
1505 return nAccept;
1506 }
1507
1508 size_t wxString::find_first_not_of(wxChar ch, size_t nStart) const
1509 {
1510 wxASSERT( nStart <= Len() );
1511
1512 for ( const wxChar *p = c_str() + nStart; *p; p++ )
1513 {
1514 if ( *p != ch )
1515 return p - c_str();
1516 }
1517
1518 return npos;
1519 }
1520
1521 size_t wxString::find_last_not_of(const wxChar* sz, size_t nStart) const
1522 {
1523 if ( nStart == npos )
1524 {
1525 nStart = Len();
1526 }
1527 else
1528 {
1529 wxASSERT( nStart <= Len() );
1530 }
1531
1532 for ( const wxChar *p = c_str() + nStart - 1; p >= c_str(); p-- )
1533 {
1534 if ( !wxStrchr(sz, *p) )
1535 return p - c_str();
1536 }
1537
1538 return npos;
1539 }
1540
1541 size_t wxString::find_last_not_of(wxChar ch, size_t nStart) const
1542 {
1543 if ( nStart == npos )
1544 {
1545 nStart = Len();
1546 }
1547 else
1548 {
1549 wxASSERT( nStart <= Len() );
1550 }
1551
1552 for ( const wxChar *p = c_str() + nStart - 1; p >= c_str(); p-- )
1553 {
1554 if ( *p != ch )
1555 return p - c_str();
1556 }
1557
1558 return npos;
1559 }
1560
1561 wxString wxString::substr(size_t nStart, size_t nLen) const
1562 {
1563 // npos means 'take all'
1564 if ( nLen == npos )
1565 nLen = 0;
1566
1567 wxASSERT( nStart + nLen <= Len() );
1568
1569 return wxString(c_str() + nStart, nLen == npos ? 0 : nLen);
1570 }
1571
1572 wxString& wxString::erase(size_t nStart, size_t nLen)
1573 {
1574 wxString strTmp(c_str(), nStart);
1575 if ( nLen != npos ) {
1576 wxASSERT( nStart + nLen <= Len() );
1577
1578 strTmp.append(c_str() + nStart + nLen);
1579 }
1580
1581 *this = strTmp;
1582 return *this;
1583 }
1584
1585 wxString& wxString::replace(size_t nStart, size_t nLen, const wxChar *sz)
1586 {
1587 wxASSERT( nStart + nLen <= wxStrlen(sz) );
1588
1589 wxString strTmp;
1590 if ( nStart != 0 )
1591 strTmp.append(c_str(), nStart);
1592 strTmp += sz;
1593 strTmp.append(c_str() + nStart + nLen);
1594
1595 *this = strTmp;
1596 return *this;
1597 }
1598
1599 wxString& wxString::replace(size_t nStart, size_t nLen, size_t nCount, wxChar ch)
1600 {
1601 return replace(nStart, nLen, wxString(ch, nCount));
1602 }
1603
1604 wxString& wxString::replace(size_t nStart, size_t nLen,
1605 const wxString& str, size_t nStart2, size_t nLen2)
1606 {
1607 return replace(nStart, nLen, str.substr(nStart2, nLen2));
1608 }
1609
1610 wxString& wxString::replace(size_t nStart, size_t nLen,
1611 const wxChar* sz, size_t nCount)
1612 {
1613 return replace(nStart, nLen, wxString(sz, nCount));
1614 }
1615
1616 #endif //std::string compatibility
1617
1618 // ============================================================================
1619 // ArrayString
1620 // ============================================================================
1621
1622 // size increment = max(50% of current size, ARRAY_MAXSIZE_INCREMENT)
1623 #define ARRAY_MAXSIZE_INCREMENT 4096
1624 #ifndef ARRAY_DEFAULT_INITIAL_SIZE // also defined in dynarray.h
1625 #define ARRAY_DEFAULT_INITIAL_SIZE (16)
1626 #endif
1627
1628 #define STRING(p) ((wxString *)(&(p)))
1629
1630 // ctor
1631 wxArrayString::wxArrayString()
1632 {
1633 m_nSize =
1634 m_nCount = 0;
1635 m_pItems = (wxChar **) NULL;
1636 }
1637
1638 // copy ctor
1639 wxArrayString::wxArrayString(const wxArrayString& src)
1640 {
1641 m_nSize =
1642 m_nCount = 0;
1643 m_pItems = (wxChar **) NULL;
1644
1645 *this = src;
1646 }
1647
1648 // assignment operator
1649 wxArrayString& wxArrayString::operator=(const wxArrayString& src)
1650 {
1651 if ( m_nSize > 0 )
1652 Clear();
1653
1654 if ( src.m_nCount > ARRAY_DEFAULT_INITIAL_SIZE )
1655 Alloc(src.m_nCount);
1656
1657 // we can't just copy the pointers here because otherwise we would share
1658 // the strings with another array
1659 for ( size_t n = 0; n < src.m_nCount; n++ )
1660 Add(src[n]);
1661
1662 if ( m_nCount != 0 )
1663 memcpy(m_pItems, src.m_pItems, m_nCount*sizeof(wxChar *));
1664
1665 return *this;
1666 }
1667
1668 // grow the array
1669 void wxArrayString::Grow()
1670 {
1671 // only do it if no more place
1672 if( m_nCount == m_nSize ) {
1673 if( m_nSize == 0 ) {
1674 // was empty, alloc some memory
1675 m_nSize = ARRAY_DEFAULT_INITIAL_SIZE;
1676 m_pItems = new wxChar *[m_nSize];
1677 }
1678 else {
1679 // otherwise when it's called for the first time, nIncrement would be 0
1680 // and the array would never be expanded
1681 wxASSERT( ARRAY_DEFAULT_INITIAL_SIZE != 0 );
1682
1683 // add 50% but not too much
1684 size_t nIncrement = m_nSize < ARRAY_DEFAULT_INITIAL_SIZE
1685 ? ARRAY_DEFAULT_INITIAL_SIZE : m_nSize >> 1;
1686 if ( nIncrement > ARRAY_MAXSIZE_INCREMENT )
1687 nIncrement = ARRAY_MAXSIZE_INCREMENT;
1688 m_nSize += nIncrement;
1689 wxChar **pNew = new wxChar *[m_nSize];
1690
1691 // copy data to new location
1692 memcpy(pNew, m_pItems, m_nCount*sizeof(wxChar *));
1693
1694 // delete old memory (but do not release the strings!)
1695 wxDELETEA(m_pItems);
1696
1697 m_pItems = pNew;
1698 }
1699 }
1700 }
1701
1702 void wxArrayString::Free()
1703 {
1704 for ( size_t n = 0; n < m_nCount; n++ ) {
1705 STRING(m_pItems[n])->GetStringData()->Unlock();
1706 }
1707 }
1708
1709 // deletes all the strings from the list
1710 void wxArrayString::Empty()
1711 {
1712 Free();
1713
1714 m_nCount = 0;
1715 }
1716
1717 // as Empty, but also frees memory
1718 void wxArrayString::Clear()
1719 {
1720 Free();
1721
1722 m_nSize =
1723 m_nCount = 0;
1724
1725 wxDELETEA(m_pItems);
1726 }
1727
1728 // dtor
1729 wxArrayString::~wxArrayString()
1730 {
1731 Free();
1732
1733 wxDELETEA(m_pItems);
1734 }
1735
1736 // pre-allocates memory (frees the previous data!)
1737 void wxArrayString::Alloc(size_t nSize)
1738 {
1739 wxASSERT( nSize > 0 );
1740
1741 // only if old buffer was not big enough
1742 if ( nSize > m_nSize ) {
1743 Free();
1744 wxDELETEA(m_pItems);
1745 m_pItems = new wxChar *[nSize];
1746 m_nSize = nSize;
1747 }
1748
1749 m_nCount = 0;
1750 }
1751
1752 // minimizes the memory usage by freeing unused memory
1753 void wxArrayString::Shrink()
1754 {
1755 // only do it if we have some memory to free
1756 if( m_nCount < m_nSize ) {
1757 // allocates exactly as much memory as we need
1758 wxChar **pNew = new wxChar *[m_nCount];
1759
1760 // copy data to new location
1761 memcpy(pNew, m_pItems, m_nCount*sizeof(wxChar *));
1762 delete [] m_pItems;
1763 m_pItems = pNew;
1764 }
1765 }
1766
1767 // searches the array for an item (forward or backwards)
1768 int wxArrayString::Index(const wxChar *sz, bool bCase, bool bFromEnd) const
1769 {
1770 if ( bFromEnd ) {
1771 if ( m_nCount > 0 ) {
1772 size_t ui = m_nCount;
1773 do {
1774 if ( STRING(m_pItems[--ui])->IsSameAs(sz, bCase) )
1775 return ui;
1776 }
1777 while ( ui != 0 );
1778 }
1779 }
1780 else {
1781 for( size_t ui = 0; ui < m_nCount; ui++ ) {
1782 if( STRING(m_pItems[ui])->IsSameAs(sz, bCase) )
1783 return ui;
1784 }
1785 }
1786
1787 return wxNOT_FOUND;
1788 }
1789
1790 // add item at the end
1791 void wxArrayString::Add(const wxString& str)
1792 {
1793 wxASSERT( str.GetStringData()->IsValid() );
1794
1795 Grow();
1796
1797 // the string data must not be deleted!
1798 str.GetStringData()->Lock();
1799 m_pItems[m_nCount++] = (wxChar *)str.c_str();
1800 }
1801
1802 // add item at the given position
1803 void wxArrayString::Insert(const wxString& str, size_t nIndex)
1804 {
1805 wxASSERT( str.GetStringData()->IsValid() );
1806
1807 wxCHECK_RET( nIndex <= m_nCount, _("bad index in wxArrayString::Insert") );
1808
1809 Grow();
1810
1811 memmove(&m_pItems[nIndex + 1], &m_pItems[nIndex],
1812 (m_nCount - nIndex)*sizeof(wxChar *));
1813
1814 str.GetStringData()->Lock();
1815 m_pItems[nIndex] = (wxChar *)str.c_str();
1816
1817 m_nCount++;
1818 }
1819
1820 // removes item from array (by index)
1821 void wxArrayString::Remove(size_t nIndex)
1822 {
1823 wxCHECK_RET( nIndex <= m_nCount, _("bad index in wxArrayString::Remove") );
1824
1825 // release our lock
1826 Item(nIndex).GetStringData()->Unlock();
1827
1828 memmove(&m_pItems[nIndex], &m_pItems[nIndex + 1],
1829 (m_nCount - nIndex - 1)*sizeof(wxChar *));
1830 m_nCount--;
1831 }
1832
1833 // removes item from array (by value)
1834 void wxArrayString::Remove(const wxChar *sz)
1835 {
1836 int iIndex = Index(sz);
1837
1838 wxCHECK_RET( iIndex != wxNOT_FOUND,
1839 _("removing inexistent element in wxArrayString::Remove") );
1840
1841 Remove(iIndex);
1842 }
1843
1844 // ----------------------------------------------------------------------------
1845 // sorting
1846 // ----------------------------------------------------------------------------
1847
1848 // we can only sort one array at a time with the quick-sort based
1849 // implementation
1850 #if wxUSE_THREADS
1851 // need a critical section to protect access to gs_compareFunction and
1852 // gs_sortAscending variables
1853 static wxCriticalSection *gs_critsectStringSort = NULL;
1854
1855 // call this before the value of the global sort vars is changed/after
1856 // you're finished with them
1857 #define START_SORT() wxASSERT( !gs_critsectStringSort ); \
1858 gs_critsectStringSort = new wxCriticalSection; \
1859 gs_critsectStringSort->Enter()
1860 #define END_SORT() gs_critsectStringSort->Leave(); \
1861 delete gs_critsectStringSort; \
1862 gs_critsectStringSort = NULL
1863 #else // !threads
1864 #define START_SORT()
1865 #define END_SORT()
1866 #endif // wxUSE_THREADS
1867
1868 // function to use for string comparaison
1869 static wxArrayString::CompareFunction gs_compareFunction = NULL;
1870
1871 // if we don't use the compare function, this flag tells us if we sort the
1872 // array in ascending or descending order
1873 static bool gs_sortAscending = TRUE;
1874
1875 // function which is called by quick sort
1876 static int wxStringCompareFunction(const void *first, const void *second)
1877 {
1878 wxString *strFirst = (wxString *)first;
1879 wxString *strSecond = (wxString *)second;
1880
1881 if ( gs_compareFunction ) {
1882 return gs_compareFunction(*strFirst, *strSecond);
1883 }
1884 else {
1885 // maybe we should use wxStrcoll
1886 int result = wxStrcmp(strFirst->c_str(), strSecond->c_str());
1887
1888 return gs_sortAscending ? result : -result;
1889 }
1890 }
1891
1892 // sort array elements using passed comparaison function
1893 void wxArrayString::Sort(CompareFunction compareFunction)
1894 {
1895 START_SORT();
1896
1897 wxASSERT( !gs_compareFunction ); // must have been reset to NULL
1898 gs_compareFunction = compareFunction;
1899
1900 DoSort();
1901
1902 END_SORT();
1903 }
1904
1905 void wxArrayString::Sort(bool reverseOrder)
1906 {
1907 START_SORT();
1908
1909 wxASSERT( !gs_compareFunction ); // must have been reset to NULL
1910 gs_sortAscending = !reverseOrder;
1911
1912 DoSort();
1913
1914 END_SORT();
1915 }
1916
1917 void wxArrayString::DoSort()
1918 {
1919 // just sort the pointers using qsort() - of course it only works because
1920 // wxString() *is* a pointer to its data
1921 qsort(m_pItems, m_nCount, sizeof(wxChar *), wxStringCompareFunction);
1922 }
1923
1924 // ============================================================================
1925 // MBConv
1926 // ============================================================================
1927
1928 WXDLLEXPORT_DATA(wxMBConv *) wxConvCurrent = &wxConvLibc;
1929 #if !wxUSE_WCHAR_T
1930 WXDLLEXPORT_DATA(wxMBConv) wxConvLibc, wxConvFile;
1931 #endif
1932
1933 #if wxUSE_WCHAR_T
1934
1935 // ----------------------------------------------------------------------------
1936 // standard libc conversion
1937 // ----------------------------------------------------------------------------
1938
1939 WXDLLEXPORT_DATA(wxMBConv) wxConvLibc;
1940
1941 size_t wxMBConv::MB2WC(wchar_t *buf, const char *psz, size_t n) const
1942 {
1943 return wxMB2WC(buf, psz, n);
1944 }
1945
1946 size_t wxMBConv::WC2MB(char *buf, const wchar_t *psz, size_t n) const
1947 {
1948 return wxWC2MB(buf, psz, n);
1949 }
1950
1951 // ----------------------------------------------------------------------------
1952 // standard file conversion
1953 // ----------------------------------------------------------------------------
1954
1955 WXDLLEXPORT_DATA(wxMBConvFile) wxConvFile;
1956
1957 // just use the libc conversion for now
1958 size_t wxMBConvFile::MB2WC(wchar_t *buf, const char *psz, size_t n) const
1959 {
1960 return wxMB2WC(buf, psz, n);
1961 }
1962
1963 size_t wxMBConvFile::WC2MB(char *buf, const wchar_t *psz, size_t n) const
1964 {
1965 return wxWC2MB(buf, psz, n);
1966 }
1967
1968 // ----------------------------------------------------------------------------
1969 // standard gdk conversion
1970 // ----------------------------------------------------------------------------
1971
1972 #ifdef __WXGTK12__
1973 WXDLLEXPORT_DATA(wxMBConvGdk) wxConvGdk;
1974
1975 #include <gdk/gdk.h>
1976
1977 size_t wxMBConvGdk::MB2WC(wchar_t *buf, const char *psz, size_t n) const
1978 {
1979 if (buf) {
1980 return gdk_mbstowcs((GdkWChar *)buf, psz, n);
1981 } else {
1982 GdkWChar *nbuf = new GdkWChar[n=strlen(psz)];
1983 size_t len = gdk_mbstowcs(nbuf, psz, n);
1984 delete [] nbuf;
1985 return len;
1986 }
1987 }
1988
1989 size_t wxMBConvGdk::WC2MB(char *buf, const wchar_t *psz, size_t n) const
1990 {
1991 char *mbstr = gdk_wcstombs((GdkWChar *)psz);
1992 size_t len = mbstr ? strlen(mbstr) : 0;
1993 if (buf) {
1994 if (len > n) len = n;
1995 memcpy(buf, psz, len);
1996 if (len < n) buf[len] = 0;
1997 }
1998 return len;
1999 }
2000 #endif // GTK > 1.0
2001
2002 // ----------------------------------------------------------------------------
2003 // UTF-7
2004 // ----------------------------------------------------------------------------
2005
2006 WXDLLEXPORT_DATA(wxMBConvUTF7) wxConvUTF7;
2007
2008 #if 0
2009 static char utf7_setD[]="ABCDEFGHIJKLMNOPQRSTUVWXYZ"
2010 "abcdefghijklmnopqrstuvwxyz"
2011 "0123456789'(),-./:?";
2012 static char utf7_setO[]="!\"#$%&*;<=>@[]^_`{|}";
2013 static char utf7_setB[]="ABCDEFGHIJKLMNOPQRSTUVWXYZ"
2014 "abcdefghijklmnopqrstuvwxyz"
2015 "0123456789+/";
2016 #endif
2017
2018 // TODO: write actual implementations of UTF-7 here
2019 size_t wxMBConvUTF7::MB2WC(wchar_t * WXUNUSED(buf),
2020 const char * WXUNUSED(psz),
2021 size_t WXUNUSED(n)) const
2022 {
2023 return 0;
2024 }
2025
2026 size_t wxMBConvUTF7::WC2MB(char * WXUNUSED(buf),
2027 const wchar_t * WXUNUSED(psz),
2028 size_t WXUNUSED(n)) const
2029 {
2030 return 0;
2031 }
2032
2033 // ----------------------------------------------------------------------------
2034 // UTF-8
2035 // ----------------------------------------------------------------------------
2036
2037 WXDLLEXPORT_DATA(wxMBConvUTF8) wxConvUTF8;
2038
2039 static unsigned long utf8_max[]={0x7f,0x7ff,0xffff,0x1fffff,0x3ffffff,0x7fffffff,0xffffffff};
2040
2041 size_t wxMBConvUTF8::MB2WC(wchar_t *buf, const char *psz, size_t n) const
2042 {
2043 size_t len = 0;
2044
2045 while (*psz && ((!buf) || (len<n))) {
2046 unsigned char cc=*psz++, fc=cc;
2047 unsigned cnt;
2048 for (cnt=0; fc&0x80; cnt++) fc<<=1;
2049 if (!cnt) {
2050 // plain ASCII char
2051 if (buf) *buf++=cc;
2052 len++;
2053 } else {
2054 cnt--;
2055 if (!cnt) {
2056 // invalid UTF-8 sequence
2057 return (size_t)-1;
2058 } else {
2059 unsigned ocnt=cnt-1;
2060 unsigned long res=cc&(0x3f>>cnt);
2061 while (cnt--) {
2062 cc = *psz++;
2063 if ((cc&0xC0)!=0x80) {
2064 // invalid UTF-8 sequence
2065 return (size_t)-1;
2066 }
2067 res=(res<<6)|(cc&0x3f);
2068 }
2069 if (res<=utf8_max[ocnt]) {
2070 // illegal UTF-8 encoding
2071 return (size_t)-1;
2072 }
2073 if (buf) *buf++=res;
2074 len++;
2075 }
2076 }
2077 }
2078 if (buf && (len<n)) *buf = 0;
2079 return len;
2080 }
2081
2082 size_t wxMBConvUTF8::WC2MB(char *buf, const wchar_t *psz, size_t n) const
2083 {
2084 size_t len = 0;
2085
2086 while (*psz && ((!buf) || (len<n))) {
2087 unsigned long cc=(*psz++)&0x7fffffff;
2088 unsigned cnt;
2089 for (cnt=0; cc>utf8_max[cnt]; cnt++);
2090 if (!cnt) {
2091 // plain ASCII char
2092 if (buf) *buf++=cc;
2093 len++;
2094 } else {
2095 len+=cnt+1;
2096 if (buf) {
2097 *buf++=(-128>>cnt)|((cc>>(cnt*6))&(0x3f>>cnt));
2098 while (cnt--)
2099 *buf++=0x80|((cc>>(cnt*6))&0x3f);
2100 }
2101 }
2102 }
2103 if (buf && (len<n)) *buf = 0;
2104 return len;
2105 }
2106
2107 // ----------------------------------------------------------------------------
2108 // specified character set
2109 // ----------------------------------------------------------------------------
2110
2111 class wxCharacterSet
2112 {
2113 public:
2114 wxArrayString names;
2115 wchar_t *data;
2116 };
2117
2118 #ifndef WX_PRECOMP
2119 #include "wx/dynarray.h"
2120 #include "wx/filefn.h"
2121 #include "wx/textfile.h"
2122 #include "wx/tokenzr.h"
2123 #include "wx/utils.h"
2124 #endif
2125
2126 WX_DECLARE_OBJARRAY(wxCharacterSet, wxCSArray);
2127 #include "wx/arrimpl.cpp"
2128 WX_DEFINE_OBJARRAY(wxCSArray);
2129
2130 static wxCSArray wxCharsets;
2131
2132 static void wxLoadCharacterSets(void)
2133 {
2134 static bool already_loaded = FALSE;
2135
2136 if (already_loaded) return;
2137
2138 already_loaded = TRUE;
2139 #if defined(__UNIX__) && wxUSE_TEXTFILE
2140 // search through files in /usr/share/i18n/charmaps
2141 wxString fname;
2142 for (fname = ::wxFindFirstFile(_T("/usr/share/i18n/charmaps/*"));
2143 !fname.IsEmpty();
2144 fname = ::wxFindNextFile()) {
2145 wxTextFile cmap(fname);
2146 if (cmap.Open()) {
2147 wxCharacterSet *cset = new wxCharacterSet;
2148 wxString comchar,escchar;
2149 bool in_charset = FALSE;
2150
2151 // wxFprintf(stderr,_T("Loaded: %s\n"),fname.c_str());
2152
2153 wxString line;
2154 for (line = cmap.GetFirstLine();
2155 !cmap.Eof();
2156 line = cmap.GetNextLine()) {
2157 // wxFprintf(stderr,_T("line contents: %s\n"),line.c_str());
2158 wxStringTokenizer token(line);
2159 wxString cmd = token.GetNextToken();
2160 if (cmd == comchar) {
2161 if (token.GetNextToken() == _T("alias"))
2162 cset->names.Add(token.GetNextToken());
2163 }
2164 else if (cmd == _T("<code_set_name>"))
2165 cset->names.Add(token.GetNextToken());
2166 else if (cmd == _T("<comment_char>"))
2167 comchar = token.GetNextToken();
2168 else if (cmd == _T("<escape_char>"))
2169 escchar = token.GetNextToken();
2170 else if (cmd == _T("<mb_cur_min>")) {
2171 delete cset;
2172 cset = (wxCharacterSet *) NULL;
2173 break; // we don't support multibyte charsets ourselves (yet)
2174 }
2175 else if (cmd == _T("CHARMAP")) {
2176 cset->data = (wchar_t *)calloc(256, sizeof(wchar_t));
2177 in_charset = TRUE;
2178 }
2179 else if (cmd == _T("END")) {
2180 if (token.GetNextToken() == _T("CHARMAP"))
2181 in_charset = FALSE;
2182 }
2183 else if (in_charset) {
2184 // format: <NUL> /x00 <U0000> NULL (NUL)
2185 // <A> /x41 <U0041> LATIN CAPITAL LETTER A
2186 wxString hex = token.GetNextToken();
2187 // skip whitespace (why doesn't wxStringTokenizer do this?)
2188 while (wxIsEmpty(hex) && token.HasMoreTokens()) hex = token.GetNextToken();
2189 wxString uni = token.GetNextToken();
2190 // skip whitespace again
2191 while (wxIsEmpty(uni) && token.HasMoreTokens()) uni = token.GetNextToken();
2192
2193 if ((hex.Len() > 2) && (hex.GetChar(0) == escchar) && (hex.GetChar(1) == _T('x')) &&
2194 (uni.Left(2) == _T("<U"))) {
2195 hex.MakeUpper(); uni.MakeUpper();
2196 int pos = ::wxHexToDec(hex.Mid(2,2));
2197 if (pos>=0) {
2198 unsigned long uni1 = ::wxHexToDec(uni.Mid(2,2));
2199 unsigned long uni2 = ::wxHexToDec(uni.Mid(4,2));
2200 cset->data[pos] = (uni1 << 16) | uni2;
2201 // wxFprintf(stderr,_T("char %02x mapped to %04x (%c)\n"),pos,cset->data[pos],cset->data[pos]);
2202 }
2203 }
2204 }
2205 }
2206 if (cset) {
2207 cset->names.Shrink();
2208 wxCharsets.Add(cset);
2209 }
2210 }
2211 }
2212 #endif
2213 wxCharsets.Shrink();
2214 }
2215
2216 static wxCharacterSet *wxFindCharacterSet(const wxChar *charset)
2217 {
2218 if (!charset) return (wxCharacterSet *)NULL;
2219 wxLoadCharacterSets();
2220 for (size_t n=0; n<wxCharsets.GetCount(); n++)
2221 if (wxCharsets[n].names.Index(charset) != wxNOT_FOUND)
2222 return &(wxCharsets[n]);
2223 return (wxCharacterSet *)NULL;
2224 }
2225
2226 WXDLLEXPORT_DATA(wxCSConv) wxConvLocal((const wxChar *)NULL);
2227
2228 wxCSConv::wxCSConv(const wxChar *charset)
2229 {
2230 m_name = (wxChar *) NULL;
2231 m_cset = (wxCharacterSet *) NULL;
2232 m_deferred = TRUE;
2233 SetName(charset);
2234 }
2235
2236 wxCSConv::~wxCSConv()
2237 {
2238 if (m_name) free(m_name);
2239 }
2240
2241 void wxCSConv::SetName(const wxChar *charset)
2242 {
2243 if (charset) {
2244 #ifdef __UNIX__
2245 // first, convert the character set name to standard form
2246 wxString codeset;
2247 if (wxString(charset,3).CmpNoCase(_T("ISO")) == 0) {
2248 // make sure it's represented in the standard form: ISO_8859-1
2249 codeset = _T("ISO_");
2250 charset += 3;
2251 if ((*charset == _T('-')) || (*charset == _T('_'))) charset++;
2252 if (wxStrlen(charset)>4) {
2253 if (wxString(charset,4) == _T("8859")) {
2254 codeset << _T("8859-");
2255 if (*charset == _T('-')) charset++;
2256 }
2257 }
2258 }
2259 codeset << charset;
2260 codeset.MakeUpper();
2261 m_name = wxStrdup(codeset.c_str());
2262 m_deferred = TRUE;
2263 #endif
2264 }
2265 }
2266
2267 void wxCSConv::LoadNow()
2268 {
2269 // wxPrintf(_T("Conversion request\n"));
2270 if (m_deferred) {
2271 if (!m_name) {
2272 #ifdef __UNIX__
2273 wxChar *lang = wxGetenv(_T("LANG"));
2274 wxChar *dot = lang ? wxStrchr(lang, _T('.')) : (wxChar *)NULL;
2275 if (dot) SetName(dot+1);
2276 #endif
2277 }
2278 m_cset = wxFindCharacterSet(m_name);
2279 m_deferred = FALSE;
2280 }
2281 }
2282
2283 size_t wxCSConv::MB2WC(wchar_t *buf, const char *psz, size_t n) const
2284 {
2285 ((wxCSConv *)this)->LoadNow(); // discard constness
2286 if (buf) {
2287 if (m_cset) {
2288 for (size_t c=0; c<n; c++)
2289 buf[c] = m_cset->data[(unsigned char)(psz[c])];
2290 } else {
2291 // latin-1 (direct)
2292 for (size_t c=0; c<n; c++)
2293 buf[c] = (unsigned char)(psz[c]);
2294 }
2295 return n;
2296 }
2297 return strlen(psz);
2298 }
2299
2300 size_t wxCSConv::WC2MB(char *buf, const wchar_t *psz, size_t n) const
2301 {
2302 ((wxCSConv *)this)->LoadNow(); // discard constness
2303 if (buf) {
2304 if (m_cset) {
2305 for (size_t c=0; c<n; c++) {
2306 size_t n;
2307 for (n=0; (n<256) && (m_cset->data[n] != psz[c]); n++);
2308 buf[c] = (n>0xff) ? '?' : n;
2309 }
2310 } else {
2311 // latin-1 (direct)
2312 for (size_t c=0; c<n; c++)
2313 buf[c] = (psz[c]>0xff) ? '?' : psz[c];
2314 }
2315 return n;
2316 }
2317 return wcslen(psz);
2318 }
2319
2320 #endif//wxUSE_WCHAR_T
2321
2322 #if wxUSE_WCHAR_T
2323 const wxWCharBuffer wxMBConv::cMB2WC(const char *psz) const
2324 {
2325 if (psz) {
2326 size_t nLen = MB2WC((wchar_t *) NULL, psz, 0);
2327 wxWCharBuffer buf(nLen);
2328 MB2WC(WCSTRINGCAST buf, psz, nLen);
2329 return buf;
2330 } else return wxWCharBuffer((wchar_t *) NULL);
2331 }
2332
2333 const wxCharBuffer wxMBConv::cWC2MB(const wchar_t *psz) const
2334 {
2335 if (psz) {
2336 size_t nLen = WC2MB((char *) NULL, psz, 0);
2337 wxCharBuffer buf(nLen);
2338 WC2MB(MBSTRINGCAST buf, psz, nLen);
2339 return buf;
2340 } else return wxCharBuffer((char *) NULL);
2341 }
2342
2343 #endif//wxUSE_WCHAR_T
2344