1///////////////////////////////////////////////////////////////////////////// 2// Name: src/common/string.cpp 3// Purpose: wxString class 4// Author: Vadim Zeitlin, Ryan Norton 5// Modified by: 6// Created: 29/01/98 7// RCS-ID: $Id: string.cpp 63008 2009-12-28 20:01:39Z VZ $ 8// Copyright: (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr> 9// (c) 2004 Ryan Norton <wxprojects@comcast.net> 10// Licence: wxWindows licence 11///////////////////////////////////////////////////////////////////////////// 12 13/* 14 * About ref counting: 15 * 1) all empty strings use g_strEmpty, nRefs = -1 (set in Init()) 16 * 2) AllocBuffer() sets nRefs to 1, Lock() increments it by one 17 * 3) Unlock() decrements nRefs and frees memory if it goes to 0 18 */ 19 20// =========================================================================== 21// headers, declarations, constants 22// =========================================================================== 23 24// For compilers that support precompilation, includes "wx.h". 25#include "wx/wxprec.h" 26 27#ifdef __BORLANDC__ 28 #pragma hdrstop 29#endif 30 31#ifndef WX_PRECOMP 32 #include "wx/string.h" 33 #include "wx/intl.h" 34 #include "wx/thread.h" 35#endif 36 37#include <ctype.h> 38 39#ifndef __WXWINCE__ 40 #include <errno.h> 41#endif 42 43#include <string.h> 44#include <stdlib.h> 45 46#ifdef __SALFORDC__ 47 #include <clib.h> 48#endif 49 50// allocating extra space for each string consumes more memory but speeds up 51// the concatenation operations (nLen is the current string's length) 52// NB: EXTRA_ALLOC must be >= 0! 53#define EXTRA_ALLOC (19 - nLen % 16) 54 55// --------------------------------------------------------------------------- 56// static class variables definition 57// --------------------------------------------------------------------------- 58 59#if !wxUSE_STL 60 //According to STL _must_ be a -1 size_t 61 const size_t wxStringBase::npos = (size_t) -1; 62#endif 63 64// ---------------------------------------------------------------------------- 65// static data 66// ---------------------------------------------------------------------------- 67 68#if wxUSE_STL 69 70extern const wxChar WXDLLIMPEXP_BASE *wxEmptyString = _T(""); 71 72#else 73 74// for an empty string, GetStringData() will return this address: this 75// structure has the same layout as wxStringData and it's data() method will 76// return the empty string (dummy pointer) 77static const struct 78{ 79 wxStringData data; 80 wxChar dummy; 81} g_strEmpty = { {-1, 0, 0}, wxT('\0') }; 82 83// empty C style string: points to 'string data' byte of g_strEmpty 84extern const wxChar WXDLLIMPEXP_BASE *wxEmptyString = &g_strEmpty.dummy; 85 86#endif 87 88// ---------------------------------------------------------------------------- 89// global functions 90// ---------------------------------------------------------------------------- 91 92#if wxUSE_STD_IOSTREAM 93 94#include <iostream> 95 96wxSTD ostream& operator<<(wxSTD ostream& os, const wxString& str) 97{ 98#ifdef __BORLANDC__ 99 os << str.mb_str(); 100#else 101 os << str.c_str(); 102#endif 103 return os; 104} 105 106#endif // wxUSE_STD_IOSTREAM 107 108// ---------------------------------------------------------------------------- 109// private classes 110// ---------------------------------------------------------------------------- 111 112// this small class is used to gather statistics for performance tuning 113//#define WXSTRING_STATISTICS 114#ifdef WXSTRING_STATISTICS 115 class Averager 116 { 117 public: 118 Averager(const wxChar *sz) { m_sz = sz; m_nTotal = m_nCount = 0; } 119 ~Averager() 120 { wxPrintf("wxString: average %s = %f\n", m_sz, ((float)m_nTotal)/m_nCount); } 121 122 void Add(size_t n) { m_nTotal += n; m_nCount++; } 123 124 private: 125 size_t m_nCount, m_nTotal; 126 const wxChar *m_sz; 127 } g_averageLength("allocation size"), 128 g_averageSummandLength("summand length"), 129 g_averageConcatHit("hit probability in concat"), 130 g_averageInitialLength("initial string length"); 131 132 #define STATISTICS_ADD(av, val) g_average##av.Add(val) 133#else 134 #define STATISTICS_ADD(av, val) 135#endif // WXSTRING_STATISTICS 136 137#if !wxUSE_STL 138 139// =========================================================================== 140// wxStringData class deallocation 141// =========================================================================== 142 143#if defined(__VISUALC__) && defined(_MT) && !defined(_DLL) 144# pragma message (__FILE__ ": building with Multithreaded non DLL runtime has a performance impact on wxString!") 145void wxStringData::Free() 146{ 147 free(this); 148} 149#endif 150 151// =========================================================================== 152// wxStringBase 153// =========================================================================== 154 155// takes nLength elements of psz starting at nPos 156void wxStringBase::InitWith(const wxChar *psz, size_t nPos, size_t nLength) 157{ 158 Init(); 159 160 // if the length is not given, assume the string to be NUL terminated 161 if ( nLength == npos ) { 162 wxASSERT_MSG( nPos <= wxStrlen(psz), _T("index out of bounds") ); 163 164 nLength = wxStrlen(psz + nPos); 165 } 166 167 STATISTICS_ADD(InitialLength, nLength); 168 169 if ( nLength > 0 ) { 170 // trailing '\0' is written in AllocBuffer() 171 if ( !AllocBuffer(nLength) ) { 172 wxFAIL_MSG( _T("out of memory in wxStringBase::InitWith") ); 173 return; 174 } 175 wxTmemcpy(m_pchData, psz + nPos, nLength); 176 } 177} 178 179// poor man's iterators are "void *" pointers 180wxStringBase::wxStringBase(const void *pStart, const void *pEnd) 181{ 182 if ( pEnd >= pStart ) 183 { 184 InitWith((const wxChar *)pStart, 0, 185 (const wxChar *)pEnd - (const wxChar *)pStart); 186 } 187 else 188 { 189 wxFAIL_MSG( _T("pStart is not before pEnd") ); 190 Init(); 191 } 192} 193 194wxStringBase::wxStringBase(size_type n, wxChar ch) 195{ 196 Init(); 197 append(n, ch); 198} 199 200// --------------------------------------------------------------------------- 201// memory allocation 202// --------------------------------------------------------------------------- 203 204// allocates memory needed to store a C string of length nLen 205bool wxStringBase::AllocBuffer(size_t nLen) 206{ 207 // allocating 0 sized buffer doesn't make sense, all empty strings should 208 // reuse g_strEmpty 209 wxASSERT( nLen > 0 ); 210 211 // make sure that we don't overflow 212 wxCHECK( nLen < (INT_MAX / sizeof(wxChar)) - 213 (sizeof(wxStringData) + EXTRA_ALLOC + 1), false ); 214 215 STATISTICS_ADD(Length, nLen); 216 217 // allocate memory: 218 // 1) one extra character for '\0' termination 219 // 2) sizeof(wxStringData) for housekeeping info 220 wxStringData* pData = (wxStringData*) 221 malloc(sizeof(wxStringData) + (nLen + EXTRA_ALLOC + 1)*sizeof(wxChar)); 222 223 if ( pData == NULL ) { 224 // allocation failures are handled by the caller 225 return false; 226 } 227 228 pData->nRefs = 1; 229 pData->nDataLength = nLen; 230 pData->nAllocLength = nLen + EXTRA_ALLOC; 231 m_pchData = pData->data(); // data starts after wxStringData 232 m_pchData[nLen] = wxT('\0'); 233 return true; 234} 235 236// must be called before changing this string 237bool wxStringBase::CopyBeforeWrite() 238{ 239 wxStringData* pData = GetStringData(); 240 241 if ( pData->IsShared() ) { 242 pData->Unlock(); // memory not freed because shared 243 size_t nLen = pData->nDataLength; 244 if ( !AllocBuffer(nLen) ) { 245 // allocation failures are handled by the caller 246 return false; 247 } 248 wxTmemcpy(m_pchData, pData->data(), nLen); 249 } 250 251 wxASSERT( !GetStringData()->IsShared() ); // we must be the only owner 252 253 return true; 254} 255 256// must be called before replacing contents of this string 257bool wxStringBase::AllocBeforeWrite(size_t nLen) 258{ 259 wxASSERT( nLen != 0 ); // doesn't make any sense 260 261 // must not share string and must have enough space 262 wxStringData* pData = GetStringData(); 263 if ( pData->IsShared() || pData->IsEmpty() ) { 264 // can't work with old buffer, get new one 265 pData->Unlock(); 266 if ( !AllocBuffer(nLen) ) { 267 // allocation failures are handled by the caller 268 return false; 269 } 270 } 271 else { 272 if ( nLen > pData->nAllocLength ) { 273 // realloc the buffer instead of calling malloc() again, this is more 274 // efficient 275 STATISTICS_ADD(Length, nLen); 276 277 nLen += EXTRA_ALLOC; 278 279 pData = (wxStringData*) 280 realloc(pData, sizeof(wxStringData) + (nLen + 1)*sizeof(wxChar)); 281 282 if ( pData == NULL ) { 283 // allocation failures are handled by the caller 284 // keep previous data since reallocation failed 285 return false; 286 } 287 288 pData->nAllocLength = nLen; 289 m_pchData = pData->data(); 290 } 291 } 292 293 wxASSERT( !GetStringData()->IsShared() ); // we must be the only owner 294 295 // it doesn't really matter what the string length is as it's going to be 296 // overwritten later but, for extra safety, set it to 0 for now as we may 297 // have some junk in m_pchData 298 GetStringData()->nDataLength = 0; 299 300 return true; 301} 302 303wxStringBase& wxStringBase::append(size_t n, wxChar ch) 304{ 305 size_type len = length(); 306 307 if ( !Alloc(len + n) || !CopyBeforeWrite() ) { 308 wxFAIL_MSG( _T("out of memory in wxStringBase::append") ); 309 } 310 GetStringData()->nDataLength = len + n; 311 m_pchData[len + n] = '\0'; 312 for ( size_t i = 0; i < n; ++i ) 313 m_pchData[len + i] = ch; 314 return *this; 315} 316 317void wxStringBase::resize(size_t nSize, wxChar ch) 318{ 319 size_t len = length(); 320 321 if ( nSize < len ) 322 { 323 erase(begin() + nSize, end()); 324 } 325 else if ( nSize > len ) 326 { 327 append(nSize - len, ch); 328 } 329 //else: we have exactly the specified length, nothing to do 330} 331 332// allocate enough memory for nLen characters 333bool wxStringBase::Alloc(size_t nLen) 334{ 335 wxStringData *pData = GetStringData(); 336 if ( pData->nAllocLength <= nLen ) { 337 if ( pData->IsEmpty() ) { 338 nLen += EXTRA_ALLOC; 339 340 pData = (wxStringData *) 341 malloc(sizeof(wxStringData) + (nLen + 1)*sizeof(wxChar)); 342 343 if ( pData == NULL ) { 344 // allocation failure handled by caller 345 return false; 346 } 347 348 pData->nRefs = 1; 349 pData->nDataLength = 0; 350 pData->nAllocLength = nLen; 351 m_pchData = pData->data(); // data starts after wxStringData 352 m_pchData[0u] = wxT('\0'); 353 } 354 else if ( pData->IsShared() ) { 355 pData->Unlock(); // memory not freed because shared 356 size_t nOldLen = pData->nDataLength; 357 if ( !AllocBuffer(nLen) ) { 358 // allocation failure handled by caller 359 return false; 360 } 361 // +1 to copy the terminator, too 362 memcpy(m_pchData, pData->data(), (nOldLen+1)*sizeof(wxChar)); 363 GetStringData()->nDataLength = nOldLen; 364 } 365 else { 366 nLen += EXTRA_ALLOC; 367 368 pData = (wxStringData *) 369 realloc(pData, sizeof(wxStringData) + (nLen + 1)*sizeof(wxChar)); 370 371 if ( pData == NULL ) { 372 // allocation failure handled by caller 373 // keep previous data since reallocation failed 374 return false; 375 } 376 377 // it's not important if the pointer changed or not (the check for this 378 // is not faster than assigning to m_pchData in all cases) 379 pData->nAllocLength = nLen; 380 m_pchData = pData->data(); 381 } 382 } 383 //else: we've already got enough 384 return true; 385} 386 387wxStringBase::iterator wxStringBase::begin() 388{ 389 if (length() > 0) 390 CopyBeforeWrite(); 391 return m_pchData; 392} 393 394wxStringBase::iterator wxStringBase::end() 395{ 396 if (length() > 0) 397 CopyBeforeWrite(); 398 return m_pchData + length(); 399} 400 401wxStringBase::iterator wxStringBase::erase(iterator it) 402{ 403 size_type idx = it - begin(); 404 erase(idx, 1); 405 return begin() + idx; 406} 407 408wxStringBase& wxStringBase::erase(size_t nStart, size_t nLen) 409{ 410 wxASSERT(nStart <= length()); 411 size_t strLen = length() - nStart; 412 // delete nLen or up to the end of the string characters 413 nLen = strLen < nLen ? strLen : nLen; 414 wxString strTmp(c_str(), nStart); 415 strTmp.append(c_str() + nStart + nLen, length() - nStart - nLen); 416 417 swap(strTmp); 418 return *this; 419} 420 421wxStringBase& wxStringBase::insert(size_t nPos, const wxChar *sz, size_t n) 422{ 423 wxASSERT( nPos <= length() ); 424 425 if ( n == npos ) n = wxStrlen(sz); 426 if ( n == 0 ) return *this; 427 428 if ( !Alloc(length() + n) || !CopyBeforeWrite() ) { 429 wxFAIL_MSG( _T("out of memory in wxStringBase::insert") ); 430 } 431 432 memmove(m_pchData + nPos + n, m_pchData + nPos, 433 (length() - nPos) * sizeof(wxChar)); 434 memcpy(m_pchData + nPos, sz, n * sizeof(wxChar)); 435 GetStringData()->nDataLength = length() + n; 436 m_pchData[length()] = '\0'; 437 438 return *this; 439} 440 441void wxStringBase::swap(wxStringBase& str) 442{ 443 wxChar* tmp = str.m_pchData; 444 str.m_pchData = m_pchData; 445 m_pchData = tmp; 446} 447 448size_t wxStringBase::find(const wxStringBase& str, size_t nStart) const 449{ 450 // deal with the special case of empty string first 451 const size_t nLen = length(); 452 const size_t nLenOther = str.length(); 453 454 if ( !nLenOther ) 455 { 456 // empty string is a substring of anything 457 return 0; 458 } 459 460 if ( !nLen ) 461 { 462 // the other string is non empty so can't be our substring 463 return npos; 464 } 465 466 wxASSERT( str.GetStringData()->IsValid() ); 467 wxASSERT( nStart <= nLen ); 468 469 const wxChar * const other = str.c_str(); 470 471 // anchor 472 const wxChar* p = (const wxChar*)wxTmemchr(c_str() + nStart, 473 *other, 474 nLen - nStart); 475 476 if ( !p ) 477 return npos; 478 479 while ( p - c_str() + nLenOther <= nLen && wxTmemcmp(p, other, nLenOther) ) 480 { 481 p++; 482 483 // anchor again 484 p = (const wxChar*)wxTmemchr(p, *other, nLen - (p - c_str())); 485 486 if ( !p ) 487 return npos; 488 } 489 490 return p - c_str() + nLenOther <= nLen ? p - c_str() : npos; 491} 492 493size_t wxStringBase::find(const wxChar* sz, size_t nStart, size_t n) const 494{ 495 return find(wxStringBase(sz, n), nStart); 496} 497 498size_t wxStringBase::find(wxChar ch, size_t nStart) const 499{ 500 wxASSERT( nStart <= length() ); 501 502 const wxChar *p = (const wxChar*)wxTmemchr(c_str() + nStart, ch, length() - nStart); 503 504 return p == NULL ? npos : p - c_str(); 505} 506 507size_t wxStringBase::rfind(const wxStringBase& str, size_t nStart) const 508{ 509 wxASSERT( str.GetStringData()->IsValid() ); 510 wxASSERT( nStart == npos || nStart <= length() ); 511 512 if ( length() >= str.length() ) 513 { 514 // avoids a corner case later 515 if ( length() == 0 && str.length() == 0 ) 516 return 0; 517 518 // "top" is the point where search starts from 519 size_t top = length() - str.length(); 520 521 if ( nStart == npos ) 522 nStart = length() - 1; 523 if ( nStart < top ) 524 top = nStart; 525 526 const wxChar *cursor = c_str() + top; 527 do 528 { 529 if ( wxTmemcmp(cursor, str.c_str(), 530 str.length()) == 0 ) 531 { 532 return cursor - c_str(); 533 } 534 } while ( cursor-- > c_str() ); 535 } 536 537 return npos; 538} 539 540size_t wxStringBase::rfind(const wxChar* sz, size_t nStart, size_t n) const 541{ 542 return rfind(wxStringBase(sz, n), nStart); 543} 544 545size_t wxStringBase::rfind(wxChar ch, size_t nStart) const 546{ 547 if ( nStart == npos ) 548 { 549 nStart = length(); 550 } 551 else 552 { 553 wxASSERT( nStart <= length() ); 554 } 555 556 const wxChar *actual; 557 for ( actual = c_str() + ( nStart == npos ? length() : nStart + 1 ); 558 actual > c_str(); --actual ) 559 { 560 if ( *(actual - 1) == ch ) 561 return (actual - 1) - c_str(); 562 } 563 564 return npos; 565} 566 567size_t wxStringBase::find_first_of(const wxChar* sz, size_t nStart) const 568{ 569 wxASSERT(nStart <= length()); 570 571 size_t len = wxStrlen(sz); 572 573 size_t i; 574 for(i = nStart; i < this->length(); ++i) 575 { 576 if (wxTmemchr(sz, *(c_str() + i), len)) 577 break; 578 } 579 580 if(i == this->length()) 581 return npos; 582 else 583 return i; 584} 585 586size_t wxStringBase::find_first_of(const wxChar* sz, size_t nStart, 587 size_t n) const 588{ 589 return find_first_of(wxStringBase(sz, n), nStart); 590} 591 592size_t wxStringBase::find_last_of(const wxChar* sz, size_t nStart) const 593{ 594 if ( nStart == npos ) 595 { 596 nStart = length() - 1; 597 } 598 else 599 { 600 wxASSERT_MSG( nStart <= length(), 601 _T("invalid index in find_last_of()") ); 602 } 603 604 size_t len = wxStrlen(sz); 605 606 for ( const wxChar *p = c_str() + nStart; p >= c_str(); --p ) 607 { 608 if ( wxTmemchr(sz, *p, len) ) 609 return p - c_str(); 610 } 611 612 return npos; 613} 614 615size_t wxStringBase::find_last_of(const wxChar* sz, size_t nStart, 616 size_t n) const 617{ 618 return find_last_of(wxStringBase(sz, n), nStart); 619} 620 621size_t wxStringBase::find_first_not_of(const wxChar* sz, size_t nStart) const 622{ 623 if ( nStart == npos ) 624 { 625 nStart = length(); 626 } 627 else 628 { 629 wxASSERT( nStart <= length() ); 630 } 631 632 size_t len = wxStrlen(sz); 633 634 size_t i; 635 for(i = nStart; i < this->length(); ++i) 636 { 637 if (!wxTmemchr(sz, *(c_str() + i), len)) 638 break; 639 } 640 641 if(i == this->length()) 642 return npos; 643 else 644 return i; 645} 646 647size_t wxStringBase::find_first_not_of(const wxChar* sz, size_t nStart, 648 size_t n) const 649{ 650 return find_first_not_of(wxStringBase(sz, n), nStart); 651} 652 653size_t wxStringBase::find_first_not_of(wxChar ch, size_t nStart) const 654{ 655 wxASSERT( nStart <= length() ); 656 657 for ( const wxChar *p = c_str() + nStart; *p; p++ ) 658 { 659 if ( *p != ch ) 660 return p - c_str(); 661 } 662 663 return npos; 664} 665 666size_t wxStringBase::find_last_not_of(const wxChar* sz, size_t nStart) const 667{ 668 if ( nStart == npos ) 669 { 670 nStart = length() - 1; 671 } 672 else 673 { 674 wxASSERT( nStart <= length() ); 675 } 676 677 size_t len = wxStrlen(sz); 678 679 for ( const wxChar *p = c_str() + nStart; p >= c_str(); --p ) 680 { 681 if ( !wxTmemchr(sz, *p,len) ) 682 return p - c_str(); 683 } 684 685 return npos; 686} 687 688size_t wxStringBase::find_last_not_of(const wxChar* sz, size_t nStart, 689 size_t n) const 690{ 691 return find_last_not_of(wxStringBase(sz, n), nStart); 692} 693 694size_t wxStringBase::find_last_not_of(wxChar ch, size_t nStart) const 695{ 696 if ( nStart == npos ) 697 { 698 nStart = length() - 1; 699 } 700 else 701 { 702 wxASSERT( nStart <= length() ); 703 } 704 705 for ( const wxChar *p = c_str() + nStart; p >= c_str(); --p ) 706 { 707 if ( *p != ch ) 708 return p - c_str(); 709 } 710 711 return npos; 712} 713 714wxStringBase& wxStringBase::replace(size_t nStart, size_t nLen, 715 const wxChar *sz) 716{ 717 wxASSERT_MSG( nStart <= length(), 718 _T("index out of bounds in wxStringBase::replace") ); 719 size_t strLen = length() - nStart; 720 nLen = strLen < nLen ? strLen : nLen; 721 722 wxStringBase strTmp; 723 strTmp.reserve(length()); // micro optimisation to avoid multiple mem allocs 724 725 //This is kind of inefficient, but its pretty good considering... 726 //we don't want to use character access operators here because on STL 727 //it will freeze the reference count of strTmp, which means a deep copy 728 //at the end when swap is called 729 // 730 //Also, we can't use append with the full character pointer and must 731 //do it manually because this string can contain null characters 732 for(size_t i1 = 0; i1 < nStart; ++i1) 733 strTmp.append(1, this->c_str()[i1]); 734 735 //its safe to do the full version here because 736 //sz must be a normal c string 737 strTmp.append(sz); 738 739 for(size_t i2 = nStart + nLen; i2 < length(); ++i2) 740 strTmp.append(1, this->c_str()[i2]); 741 742 swap(strTmp); 743 return *this; 744} 745 746wxStringBase& wxStringBase::replace(size_t nStart, size_t nLen, 747 size_t nCount, wxChar ch) 748{ 749 return replace(nStart, nLen, wxStringBase(nCount, ch).c_str()); 750} 751 752wxStringBase& wxStringBase::replace(size_t nStart, size_t nLen, 753 const wxStringBase& str, 754 size_t nStart2, size_t nLen2) 755{ 756 return replace(nStart, nLen, str.substr(nStart2, nLen2)); 757} 758 759wxStringBase& wxStringBase::replace(size_t nStart, size_t nLen, 760 const wxChar* sz, size_t nCount) 761{ 762 return replace(nStart, nLen, wxStringBase(sz, nCount).c_str()); 763} 764 765wxStringBase wxStringBase::substr(size_t nStart, size_t nLen) const 766{ 767 if ( nLen == npos ) 768 nLen = length() - nStart; 769 return wxStringBase(*this, nStart, nLen); 770} 771 772// assigns one string to another 773wxStringBase& wxStringBase::operator=(const wxStringBase& stringSrc) 774{ 775 wxASSERT( stringSrc.GetStringData()->IsValid() ); 776 777 // don't copy string over itself 778 if ( m_pchData != stringSrc.m_pchData ) { 779 if ( stringSrc.GetStringData()->IsEmpty() ) { 780 Reinit(); 781 } 782 else { 783 // adjust references 784 GetStringData()->Unlock(); 785 m_pchData = stringSrc.m_pchData; 786 GetStringData()->Lock(); 787 } 788 } 789 790 return *this; 791} 792 793// assigns a single character 794wxStringBase& wxStringBase::operator=(wxChar ch) 795{ 796 if ( !AssignCopy(1, &ch) ) { 797 wxFAIL_MSG( _T("out of memory in wxStringBase::operator=(wxChar)") ); 798 } 799 return *this; 800} 801 802// assigns C string 803wxStringBase& wxStringBase::operator=(const wxChar *psz) 804{ 805 if ( !AssignCopy(wxStrlen(psz), psz) ) { 806 wxFAIL_MSG( _T("out of memory in wxStringBase::operator=(const wxChar *)") ); 807 } 808 return *this; 809} 810 811// helper function: does real copy 812bool wxStringBase::AssignCopy(size_t nSrcLen, const wxChar *pszSrcData) 813{ 814 if ( nSrcLen == 0 ) { 815 Reinit(); 816 } 817 else { 818 if ( !AllocBeforeWrite(nSrcLen) ) { 819 // allocation failure handled by caller 820 return false; 821 } 822 823 // use memmove() and not memcpy() here as we might be copying from our own 824 // buffer in case of assignment such as "s = s.c_str()" (see #11294) 825 memmove(m_pchData, pszSrcData, nSrcLen*sizeof(wxChar)); 826 827 GetStringData()->nDataLength = nSrcLen; 828 m_pchData[nSrcLen] = wxT('\0'); 829 } 830 return true; 831} 832 833// --------------------------------------------------------------------------- 834// string concatenation 835// --------------------------------------------------------------------------- 836 837// add something to this string 838bool wxStringBase::ConcatSelf(size_t nSrcLen, const wxChar *pszSrcData, 839 size_t nMaxLen) 840{ 841 STATISTICS_ADD(SummandLength, nSrcLen); 842 843 nSrcLen = nSrcLen < nMaxLen ? nSrcLen : nMaxLen; 844 845 // concatenating an empty string is a NOP 846 if ( nSrcLen > 0 ) { 847 wxStringData *pData = GetStringData(); 848 size_t nLen = pData->nDataLength; 849 size_t nNewLen = nLen + nSrcLen; 850 851 // take special care when appending part of this string to itself: the code 852 // below reallocates our buffer and this invalidates pszSrcData pointer so 853 // we have to copy it in another temporary string in this case (but avoid 854 // doing this unnecessarily) 855 if ( pszSrcData >= m_pchData && pszSrcData < m_pchData + nLen ) 856 { 857 wxStringBase tmp(pszSrcData, nSrcLen); 858 return ConcatSelf(nSrcLen, tmp.m_pchData, nSrcLen); 859 } 860 861 // alloc new buffer if current is too small 862 if ( pData->IsShared() ) { 863 STATISTICS_ADD(ConcatHit, 0); 864 865 // we have to allocate another buffer 866 wxStringData* pOldData = GetStringData(); 867 if ( !AllocBuffer(nNewLen) ) { 868 // allocation failure handled by caller 869 return false; 870 } 871 memcpy(m_pchData, pOldData->data(), nLen*sizeof(wxChar)); 872 pOldData->Unlock(); 873 } 874 else if ( nNewLen > pData->nAllocLength ) { 875 STATISTICS_ADD(ConcatHit, 0); 876 877 reserve(nNewLen); 878 // we have to grow the buffer 879 if ( capacity() < nNewLen ) { 880 // allocation failure handled by caller 881 return false; 882 } 883 } 884 else { 885 STATISTICS_ADD(ConcatHit, 1); 886 887 // the buffer is already big enough 888 } 889 890 // should be enough space 891 wxASSERT( nNewLen <= GetStringData()->nAllocLength ); 892 893 // fast concatenation - all is done in our buffer 894 memcpy(m_pchData + nLen, pszSrcData, nSrcLen*sizeof(wxChar)); 895 896 m_pchData[nNewLen] = wxT('\0'); // put terminating '\0' 897 GetStringData()->nDataLength = nNewLen; // and fix the length 898 } 899 //else: the string to append was empty 900 return true; 901} 902 903// --------------------------------------------------------------------------- 904// simple sub-string extraction 905// --------------------------------------------------------------------------- 906 907// helper function: clone the data attached to this string 908bool wxStringBase::AllocCopy(wxString& dest, int nCopyLen, int nCopyIndex) const 909{ 910 if ( nCopyLen == 0 ) { 911 dest.Init(); 912 } 913 else { 914 if ( !dest.AllocBuffer(nCopyLen) ) { 915 // allocation failure handled by caller 916 return false; 917 } 918 memcpy(dest.m_pchData, m_pchData + nCopyIndex, nCopyLen*sizeof(wxChar)); 919 } 920 return true; 921} 922 923#endif // !wxUSE_STL 924 925#if !wxUSE_STL || !defined(HAVE_STD_STRING_COMPARE) 926 927#if !wxUSE_STL 928 #define STRINGCLASS wxStringBase 929#else 930 #define STRINGCLASS wxString 931#endif 932 933static inline int wxDoCmp(const wxChar* s1, size_t l1, 934 const wxChar* s2, size_t l2) 935{ 936 if( l1 == l2 ) 937 return wxTmemcmp(s1, s2, l1); 938 else if( l1 < l2 ) 939 { 940 int ret = wxTmemcmp(s1, s2, l1); 941 return ret == 0 ? -1 : ret; 942 } 943 else 944 { 945 int ret = wxTmemcmp(s1, s2, l2); 946 return ret == 0 ? +1 : ret; 947 } 948} 949 950int STRINGCLASS::compare(const wxStringBase& str) const 951{ 952 return ::wxDoCmp(data(), length(), str.data(), str.length()); 953} 954 955int STRINGCLASS::compare(size_t nStart, size_t nLen, 956 const wxStringBase& str) const 957{ 958 wxASSERT(nStart <= length()); 959 size_type strLen = length() - nStart; 960 nLen = strLen < nLen ? strLen : nLen; 961 return ::wxDoCmp(data() + nStart, nLen, str.data(), str.length()); 962} 963 964int STRINGCLASS::compare(size_t nStart, size_t nLen, 965 const wxStringBase& str, 966 size_t nStart2, size_t nLen2) const 967{ 968 wxASSERT(nStart <= length()); 969 wxASSERT(nStart2 <= str.length()); 970 size_type strLen = length() - nStart, 971 strLen2 = str.length() - nStart2; 972 nLen = strLen < nLen ? strLen : nLen; 973 nLen2 = strLen2 < nLen2 ? strLen2 : nLen2; 974 return ::wxDoCmp(data() + nStart, nLen, str.data() + nStart2, nLen2); 975} 976 977int STRINGCLASS::compare(const wxChar* sz) const 978{ 979 size_t nLen = wxStrlen(sz); 980 return ::wxDoCmp(data(), length(), sz, nLen); 981} 982 983int STRINGCLASS::compare(size_t nStart, size_t nLen, 984 const wxChar* sz, size_t nCount) const 985{ 986 wxASSERT(nStart <= length()); 987 size_type strLen = length() - nStart; 988 nLen = strLen < nLen ? strLen : nLen; 989 if( nCount == npos ) 990 nCount = wxStrlen(sz); 991 992 return ::wxDoCmp(data() + nStart, nLen, sz, nCount); 993} 994 995#undef STRINGCLASS 996 997#endif // !wxUSE_STL || !defined(HAVE_STD_STRING_COMPARE) 998 999// =========================================================================== 1000// wxString class core 1001// =========================================================================== 1002 1003// --------------------------------------------------------------------------- 1004// construction and conversion 1005// --------------------------------------------------------------------------- 1006 1007#if wxUSE_UNICODE 1008 1009// from multibyte string 1010wxString::wxString(const char *psz, const wxMBConv& conv, size_t nLength) 1011{ 1012 // anything to do? 1013 if ( psz && nLength != 0 ) 1014 { 1015 if ( nLength == npos ) 1016 { 1017 nLength = wxNO_LEN; 1018 } 1019 1020 size_t nLenWide; 1021 wxWCharBuffer wbuf = conv.cMB2WC(psz, nLength, &nLenWide); 1022 1023 if ( nLenWide ) 1024 assign(wbuf, nLenWide); 1025 } 1026} 1027 1028//Convert wxString in Unicode mode to a multi-byte string 1029const wxCharBuffer wxString::mb_str(const wxMBConv& conv) const 1030{ 1031 return conv.cWC2MB(c_str(), length() + 1 /* size, not length */, NULL); 1032} 1033 1034#else // ANSI 1035 1036#if wxUSE_WCHAR_T 1037 1038// from wide string 1039wxString::wxString(const wchar_t *pwz, const wxMBConv& conv, size_t nLength) 1040{ 1041 // anything to do? 1042 if ( pwz && nLength != 0 ) 1043 { 1044 if ( nLength == npos ) 1045 { 1046 nLength = wxNO_LEN; 1047 } 1048 1049 size_t nLenMB; 1050 wxCharBuffer buf = conv.cWC2MB(pwz, nLength, &nLenMB); 1051 1052 if ( nLenMB ) 1053 assign(buf, nLenMB); 1054 } 1055} 1056 1057//Converts this string to a wide character string if unicode 1058//mode is not enabled and wxUSE_WCHAR_T is enabled 1059const wxWCharBuffer wxString::wc_str(const wxMBConv& conv) const 1060{ 1061 return conv.cMB2WC(c_str(), length() + 1 /* size, not length */, NULL); 1062} 1063 1064#endif // wxUSE_WCHAR_T 1065 1066#endif // Unicode/ANSI 1067 1068// shrink to minimal size (releasing extra memory) 1069bool wxString::Shrink() 1070{ 1071 wxString tmp(begin(), end()); 1072 swap(tmp); 1073 return tmp.length() == length(); 1074} 1075 1076#if !wxUSE_STL 1077// get the pointer to writable buffer of (at least) nLen bytes 1078wxChar *wxString::GetWriteBuf(size_t nLen) 1079{ 1080 if ( !AllocBeforeWrite(nLen) ) { 1081 // allocation failure handled by caller 1082 return NULL; 1083 } 1084 1085 wxASSERT( GetStringData()->nRefs == 1 ); 1086 GetStringData()->Validate(false); 1087 1088 return m_pchData; 1089} 1090 1091// put string back in a reasonable state after GetWriteBuf 1092void wxString::UngetWriteBuf() 1093{ 1094 UngetWriteBuf(wxStrlen(m_pchData)); 1095} 1096 1097void wxString::UngetWriteBuf(size_t nLen) 1098{ 1099 wxStringData * const pData = GetStringData(); 1100 1101 wxASSERT_MSG( nLen < pData->nAllocLength, _T("buffer overrun") ); 1102 1103 // the strings we store are always NUL-terminated 1104 pData->data()[nLen] = _T('\0'); 1105 pData->nDataLength = nLen; 1106 pData->Validate(true); 1107} 1108#endif // !wxUSE_STL 1109 1110// --------------------------------------------------------------------------- 1111// data access 1112// --------------------------------------------------------------------------- 1113 1114// all functions are inline in string.h 1115 1116// --------------------------------------------------------------------------- 1117// assignment operators 1118// --------------------------------------------------------------------------- 1119 1120#if !wxUSE_UNICODE 1121 1122// same as 'signed char' variant 1123wxString& wxString::operator=(const unsigned char* psz) 1124{ 1125 *this = (const char *)psz; 1126 return *this; 1127} 1128 1129#if wxUSE_WCHAR_T 1130wxString& wxString::operator=(const wchar_t *pwz) 1131{ 1132 wxString str(pwz); 1133 swap(str); 1134 return *this; 1135} 1136#endif 1137 1138#endif 1139 1140/* 1141 * concatenation functions come in 5 flavours: 1142 * string + string 1143 * char + string and string + char 1144 * C str + string and string + C str 1145 */ 1146 1147wxString operator+(const wxString& str1, const wxString& str2) 1148{ 1149#if !wxUSE_STL 1150 wxASSERT( str1.GetStringData()->IsValid() ); 1151 wxASSERT( str2.GetStringData()->IsValid() ); 1152#endif 1153 1154 wxString s = str1; 1155 s += str2; 1156 1157 return s; 1158} 1159 1160wxString operator+(const wxString& str, wxChar ch) 1161{ 1162#if !wxUSE_STL 1163 wxASSERT( str.GetStringData()->IsValid() ); 1164#endif 1165 1166 wxString s = str; 1167 s += ch; 1168 1169 return s; 1170} 1171 1172wxString operator+(wxChar ch, const wxString& str) 1173{ 1174#if !wxUSE_STL 1175 wxASSERT( str.GetStringData()->IsValid() ); 1176#endif 1177 1178 wxString s = ch; 1179 s += str; 1180 1181 return s; 1182} 1183 1184wxString operator+(const wxString& str, const wxChar *psz) 1185{ 1186#if !wxUSE_STL 1187 wxASSERT( str.GetStringData()->IsValid() ); 1188#endif 1189 1190 wxString s; 1191 if ( !s.Alloc(wxStrlen(psz) + str.length()) ) { 1192 wxFAIL_MSG( _T("out of memory in wxString::operator+") ); 1193 } 1194 s += str; 1195 s += psz; 1196 1197 return s; 1198} 1199 1200wxString operator+(const wxChar *psz, const wxString& str) 1201{ 1202#if !wxUSE_STL 1203 wxASSERT( str.GetStringData()->IsValid() ); 1204#endif 1205 1206 wxString s; 1207 if ( !s.Alloc(wxStrlen(psz) + str.length()) ) { 1208 wxFAIL_MSG( _T("out of memory in wxString::operator+") ); 1209 } 1210 s = psz; 1211 s += str; 1212 1213 return s; 1214} 1215 1216// =========================================================================== 1217// other common string functions 1218// =========================================================================== 1219 1220int wxString::Cmp(const wxString& s) const 1221{ 1222 return compare(s); 1223} 1224 1225int wxString::Cmp(const wxChar* psz) const 1226{ 1227 return compare(psz); 1228} 1229 1230static inline int wxDoCmpNoCase(const wxChar* s1, size_t l1, 1231 const wxChar* s2, size_t l2) 1232{ 1233 size_t i; 1234 1235 if( l1 == l2 ) 1236 { 1237 for(i = 0; i < l1; ++i) 1238 { 1239 if(wxTolower(s1[i]) != wxTolower(s2[i])) 1240 break; 1241 } 1242 return i == l1 ? 0 : wxTolower(s1[i]) < wxTolower(s2[i]) ? -1 : 1; 1243 } 1244 else if( l1 < l2 ) 1245 { 1246 for(i = 0; i < l1; ++i) 1247 { 1248 if(wxTolower(s1[i]) != wxTolower(s2[i])) 1249 break; 1250 } 1251 return i == l1 ? -1 : wxTolower(s1[i]) < wxTolower(s2[i]) ? -1 : 1; 1252 } 1253 else 1254 { 1255 for(i = 0; i < l2; ++i) 1256 { 1257 if(wxTolower(s1[i]) != wxTolower(s2[i])) 1258 break; 1259 } 1260 return i == l2 ? 1 : wxTolower(s1[i]) < wxTolower(s2[i]) ? -1 : 1; 1261 } 1262} 1263 1264int wxString::CmpNoCase(const wxString& s) const 1265{ 1266 return wxDoCmpNoCase(data(), length(), s.data(), s.length()); 1267} 1268 1269int wxString::CmpNoCase(const wxChar* psz) const 1270{ 1271 int nLen = wxStrlen(psz); 1272 1273 return wxDoCmpNoCase(data(), length(), psz, nLen); 1274} 1275 1276 1277#if wxUSE_UNICODE 1278 1279#ifdef __MWERKS__ 1280#ifndef __SCHAR_MAX__ 1281#define __SCHAR_MAX__ 127 1282#endif 1283#endif 1284 1285wxString wxString::FromAscii(const char *ascii) 1286{ 1287 if (!ascii) 1288 return wxEmptyString; 1289 1290 size_t len = strlen( ascii ); 1291 wxString res; 1292 1293 if ( len ) 1294 { 1295 wxStringBuffer buf(res, len); 1296 1297 wchar_t *dest = buf; 1298 1299 for ( ;; ) 1300 { 1301 if ( (*dest++ = (wchar_t)(unsigned char)*ascii++) == L'\0' ) 1302 break; 1303 } 1304 } 1305 1306 return res; 1307} 1308 1309wxString wxString::FromAscii(const char ascii) 1310{ 1311 // What do we do with '\0' ? 1312 1313 wxString res; 1314 res += (wchar_t)(unsigned char) ascii; 1315 1316 return res; 1317} 1318 1319const wxCharBuffer wxString::ToAscii() const 1320{ 1321 // this will allocate enough space for the terminating NUL too 1322 wxCharBuffer buffer(length()); 1323 1324 1325 char *dest = buffer.data(); 1326 1327 const wchar_t *pwc = c_str(); 1328 for ( ;; ) 1329 { 1330 *dest++ = (char)(*pwc > SCHAR_MAX ? wxT('_') : *pwc); 1331 1332 // the output string can't have embedded NULs anyhow, so we can safely 1333 // stop at first of them even if we do have any 1334 if ( !*pwc++ ) 1335 break; 1336 } 1337 1338 return buffer; 1339} 1340 1341#endif // Unicode 1342 1343// extract string of length nCount starting at nFirst 1344wxString wxString::Mid(size_t nFirst, size_t nCount) const 1345{ 1346 size_t nLen = length(); 1347 1348 // default value of nCount is npos and means "till the end" 1349 if ( nCount == npos ) 1350 { 1351 nCount = nLen - nFirst; 1352 } 1353 1354 // out-of-bounds requests return sensible things 1355 if ( nFirst + nCount > nLen ) 1356 { 1357 nCount = nLen - nFirst; 1358 } 1359 1360 if ( nFirst > nLen ) 1361 { 1362 // AllocCopy() will return empty string 1363 return wxEmptyString; 1364 } 1365 1366 wxString dest(*this, nFirst, nCount); 1367 if ( dest.length() != nCount ) 1368 { 1369 wxFAIL_MSG( _T("out of memory in wxString::Mid") ); 1370 } 1371 1372 return dest; 1373} 1374 1375// check that the string starts with prefix and return the rest of the string 1376// in the provided pointer if it is not NULL, otherwise return false 1377bool wxString::StartsWith(const wxChar *prefix, wxString *rest) const 1378{ 1379 wxASSERT_MSG( prefix, _T("invalid parameter in wxString::StartsWith") ); 1380 1381 // first check if the beginning of the string matches the prefix: note 1382 // that we don't have to check that we don't run out of this string as 1383 // when we reach the terminating NUL, either prefix string ends too (and 1384 // then it's ok) or we break out of the loop because there is no match 1385 const wxChar *p = c_str(); 1386 while ( *prefix ) 1387 { 1388 if ( *prefix++ != *p++ ) 1389 { 1390 // no match 1391 return false; 1392 } 1393 } 1394 1395 if ( rest ) 1396 { 1397 // put the rest of the string into provided pointer 1398 *rest = p; 1399 } 1400 1401 return true; 1402} 1403 1404 1405// check that the string ends with suffix and return the rest of it in the 1406// provided pointer if it is not NULL, otherwise return false 1407bool wxString::EndsWith(const wxChar *suffix, wxString *rest) const 1408{ 1409 wxASSERT_MSG( suffix, _T("invalid parameter in wxString::EndssWith") ); 1410 1411 int start = length() - wxStrlen(suffix); 1412 if ( start < 0 || wxStrcmp(c_str() + start, suffix) != 0 ) 1413 return false; 1414 1415 if ( rest ) 1416 { 1417 // put the rest of the string into provided pointer 1418 rest->assign(*this, 0, start); 1419 } 1420 1421 return true; 1422} 1423 1424 1425// extract nCount last (rightmost) characters 1426wxString wxString::Right(size_t nCount) const 1427{ 1428 if ( nCount > length() ) 1429 nCount = length(); 1430 1431 wxString dest(*this, length() - nCount, nCount); 1432 if ( dest.length() != nCount ) { 1433 wxFAIL_MSG( _T("out of memory in wxString::Right") ); 1434 } 1435 return dest; 1436} 1437 1438// get all characters after the last occurence of ch 1439// (returns the whole string if ch not found) 1440wxString wxString::AfterLast(wxChar ch) const 1441{ 1442 wxString str; 1443 int iPos = Find(ch, true); 1444 if ( iPos == wxNOT_FOUND ) 1445 str = *this; 1446 else 1447 str = c_str() + iPos + 1; 1448 1449 return str; 1450} 1451 1452// extract nCount first (leftmost) characters 1453wxString wxString::Left(size_t nCount) const 1454{ 1455 if ( nCount > length() ) 1456 nCount = length(); 1457 1458 wxString dest(*this, 0, nCount); 1459 if ( dest.length() != nCount ) { 1460 wxFAIL_MSG( _T("out of memory in wxString::Left") ); 1461 } 1462 return dest; 1463} 1464 1465// get all characters before the first occurence of ch 1466// (returns the whole string if ch not found) 1467wxString wxString::BeforeFirst(wxChar ch) const 1468{ 1469 int iPos = Find(ch); 1470 if ( iPos == wxNOT_FOUND ) iPos = length(); 1471 return wxString(*this, 0, iPos); 1472} 1473 1474/// get all characters before the last occurence of ch 1475/// (returns empty string if ch not found) 1476wxString wxString::BeforeLast(wxChar ch) const 1477{ 1478 wxString str; 1479 int iPos = Find(ch, true); 1480 if ( iPos != wxNOT_FOUND && iPos != 0 ) 1481 str = wxString(c_str(), iPos); 1482 1483 return str; 1484} 1485 1486/// get all characters after the first occurence of ch 1487/// (returns empty string if ch not found) 1488wxString wxString::AfterFirst(wxChar ch) const 1489{ 1490 wxString str; 1491 int iPos = Find(ch); 1492 if ( iPos != wxNOT_FOUND ) 1493 str = c_str() + iPos + 1; 1494 1495 return str; 1496} 1497 1498// replace first (or all) occurences of some substring with another one 1499size_t 1500wxString::Replace(const wxChar *szOld, const wxChar *szNew, bool bReplaceAll) 1501{ 1502 // if we tried to replace an empty string we'd enter an infinite loop below 1503 wxCHECK_MSG( szOld && *szOld && szNew, 0, 1504 _T("wxString::Replace(): invalid parameter") ); 1505 1506 size_t uiCount = 0; // count of replacements made 1507 1508 // optimize the special common case of replacing one character with another 1509 // one 1510 if ( szOld[1] == '\0' && (szNew[0] != '\0' && szNew[1] == '\0') ) 1511 { 1512 // this loop is the simplified version of the one below 1513 for ( size_t pos = 0; ; ) 1514 { 1515 pos = find(*szOld, pos); 1516 if ( pos == npos ) 1517 break; 1518 1519 (*this)[pos++] = *szNew; 1520 1521 uiCount++; 1522 1523 if ( !bReplaceAll ) 1524 break; 1525 } 1526 } 1527 else // general case 1528 { 1529 const size_t uiOldLen = wxStrlen(szOld); 1530 const size_t uiNewLen = wxStrlen(szNew); 1531 1532 for ( size_t pos = 0; ; ) 1533 { 1534 pos = find(szOld, pos); 1535 if ( pos == npos ) 1536 break; 1537 1538 // replace this occurrence of the old string with the new one 1539 replace(pos, uiOldLen, szNew, uiNewLen); 1540 1541 // move past the string that was replaced 1542 pos += uiNewLen; 1543 1544 // increase replace count 1545 uiCount++; 1546 1547 // stop now? 1548 if ( !bReplaceAll ) 1549 break; 1550 } 1551 } 1552 1553 return uiCount; 1554} 1555 1556bool wxString::IsAscii() const 1557{ 1558 const wxChar *s = (const wxChar*) *this; 1559 while(*s){ 1560 if(!isascii(*s)) return(false); 1561 s++; 1562 } 1563 return(true); 1564} 1565 1566bool wxString::IsWord() const 1567{ 1568 const wxChar *s = (const wxChar*) *this; 1569 while(*s){ 1570 if(!wxIsalpha(*s)) return(false); 1571 s++; 1572 } 1573 return(true); 1574} 1575 1576bool wxString::IsNumber() const 1577{ 1578 const wxChar *s = (const wxChar*) *this; 1579 if (wxStrlen(s)) 1580 if ((s[0] == wxT('-')) || (s[0] == wxT('+'))) s++; 1581 while(*s){ 1582 if(!wxIsdigit(*s)) return(false); 1583 s++; 1584 } 1585 return(true); 1586} 1587 1588wxString wxString::Strip(stripType w) const 1589{ 1590 wxString s = *this; 1591 if ( w & leading ) s.Trim(false); 1592 if ( w & trailing ) s.Trim(true); 1593 return s; 1594} 1595 1596// --------------------------------------------------------------------------- 1597// case conversion 1598// --------------------------------------------------------------------------- 1599 1600wxString& wxString::MakeUpper() 1601{ 1602 for ( iterator it = begin(), en = end(); it != en; ++it ) 1603 *it = (wxChar)wxToupper(*it); 1604 1605 return *this; 1606} 1607 1608wxString& wxString::MakeLower() 1609{ 1610 for ( iterator it = begin(), en = end(); it != en; ++it ) 1611 *it = (wxChar)wxTolower(*it); 1612 1613 return *this; 1614} 1615 1616// --------------------------------------------------------------------------- 1617// trimming and padding 1618// --------------------------------------------------------------------------- 1619 1620// some compilers (VC++ 6.0 not to name them) return true for a call to 1621// isspace('\xEA') in the C locale which seems to be broken to me, but we have 1622// to live with this by checking that the character is a 7 bit one - even if 1623// this may fail to detect some spaces (I don't know if Unicode doesn't have 1624// space-like symbols somewhere except in the first 128 chars), it is arguably 1625// still better than trimming away accented letters 1626inline int wxSafeIsspace(wxChar ch) { return (ch < 127) && wxIsspace(ch); } 1627 1628// trims spaces (in the sense of isspace) from left or right side 1629wxString& wxString::Trim(bool bFromRight) 1630{ 1631 // first check if we're going to modify the string at all 1632 if ( !empty() && 1633 ( 1634 (bFromRight && wxSafeIsspace(GetChar(length() - 1))) || 1635 (!bFromRight && wxSafeIsspace(GetChar(0u))) 1636 ) 1637 ) 1638 { 1639 if ( bFromRight ) 1640 { 1641 // find last non-space character 1642 reverse_iterator psz = rbegin(); 1643 while ( (psz != rend()) && wxSafeIsspace(*psz) ) 1644 psz++; 1645 1646 // truncate at trailing space start 1647 erase(psz.base(), end()); 1648 } 1649 else 1650 { 1651 // find first non-space character 1652 iterator psz = begin(); 1653 while ( (psz != end()) && wxSafeIsspace(*psz) ) 1654 psz++; 1655 1656 // fix up data and length 1657 erase(begin(), psz); 1658 } 1659 } 1660 1661 return *this; 1662} 1663 1664// adds nCount characters chPad to the string from either side 1665wxString& wxString::Pad(size_t nCount, wxChar chPad, bool bFromRight) 1666{ 1667 wxString s(chPad, nCount); 1668 1669 if ( bFromRight ) 1670 *this += s; 1671 else 1672 { 1673 s += *this; 1674 swap(s); 1675 } 1676 1677 return *this; 1678} 1679 1680// truncate the string 1681wxString& wxString::Truncate(size_t uiLen) 1682{ 1683 if ( uiLen < length() ) 1684 { 1685 erase(begin() + uiLen, end()); 1686 } 1687 //else: nothing to do, string is already short enough 1688 1689 return *this; 1690} 1691 1692// --------------------------------------------------------------------------- 1693// finding (return wxNOT_FOUND if not found and index otherwise) 1694// --------------------------------------------------------------------------- 1695 1696// find a character 1697int wxString::Find(wxChar ch, bool bFromEnd) const 1698{ 1699 size_type idx = bFromEnd ? find_last_of(ch) : find_first_of(ch); 1700 1701 return (idx == npos) ? wxNOT_FOUND : (int)idx; 1702} 1703 1704// find a sub-string (like strstr) 1705int wxString::Find(const wxChar *pszSub) const 1706{ 1707 size_type idx = find(pszSub); 1708 1709 return (idx == npos) ? wxNOT_FOUND : (int)idx; 1710} 1711 1712// ---------------------------------------------------------------------------- 1713// conversion to numbers 1714// ---------------------------------------------------------------------------- 1715 1716// the implementation of all the functions below is exactly the same so factor 1717// it out 1718 1719template <typename T, typename F> 1720bool wxStringToIntType(const wxChar *start, 1721 T *val, 1722 int base, 1723 F func) 1724{ 1725 wxCHECK_MSG( val, false, _T("NULL output pointer") ); 1726 wxASSERT_MSG( !base || (base > 1 && base <= 36), _T("invalid base") ); 1727 1728#ifndef __WXWINCE__ 1729 errno = 0; 1730#endif 1731 1732 wxChar *end; 1733 *val = (*func)(start, &end, base); 1734 1735 // return true only if scan was stopped by the terminating NUL and if the 1736 // string was not empty to start with and no under/overflow occurred 1737 return !*end && (end != start) 1738#ifndef __WXWINCE__ 1739 && (errno != ERANGE) 1740#endif 1741 ; 1742} 1743 1744bool wxString::ToLong(long *val, int base) const 1745{ 1746 return wxStringToIntType(c_str(), val, base, wxStrtol); 1747} 1748 1749bool wxString::ToULong(unsigned long *val, int base) const 1750{ 1751 return wxStringToIntType(c_str(), val, base, wxStrtoul); 1752} 1753 1754bool wxString::ToLongLong(wxLongLong_t *val, int base) const 1755{ 1756#ifdef wxHAS_STRTOLL 1757 return wxStringToIntType(c_str(), val, base, wxStrtoll); 1758#else 1759 // TODO: implement this ourselves 1760 wxUnusedVar(val); 1761 wxUnusedVar(base); 1762 return false; 1763#endif // wxHAS_STRTOLL 1764} 1765 1766bool wxString::ToULongLong(wxULongLong_t *val, int base) const 1767{ 1768#ifdef wxHAS_STRTOLL 1769 return wxStringToIntType(c_str(), val, base, wxStrtoull); 1770#else 1771 // TODO: implement this ourselves 1772 wxUnusedVar(val); 1773 wxUnusedVar(base); 1774 return false; 1775#endif 1776} 1777 1778bool wxString::ToDouble(double *val) const 1779{ 1780 wxCHECK_MSG( val, false, _T("NULL pointer in wxString::ToDouble") ); 1781 1782#ifndef __WXWINCE__ 1783 errno = 0; 1784#endif 1785 1786 const wxChar *start = c_str(); 1787 wxChar *end; 1788 *val = wxStrtod(start, &end); 1789 1790 // return true only if scan was stopped by the terminating NUL and if the 1791 // string was not empty to start with and no under/overflow occurred 1792 return !*end && (end != start) 1793#ifndef __WXWINCE__ 1794 && (errno != ERANGE) 1795#endif 1796 ; 1797} 1798 1799// --------------------------------------------------------------------------- 1800// formatted output 1801// --------------------------------------------------------------------------- 1802 1803/* static */ 1804wxString wxString::Format(const wxChar *pszFormat, ...) 1805{ 1806 va_list argptr; 1807 va_start(argptr, pszFormat); 1808 1809 wxString s; 1810 s.PrintfV(pszFormat, argptr); 1811 1812 va_end(argptr); 1813 1814 return s; 1815} 1816 1817/* static */ 1818wxString wxString::FormatV(const wxChar *pszFormat, va_list argptr) 1819{ 1820 wxString s; 1821 s.PrintfV(pszFormat, argptr); 1822 return s; 1823} 1824 1825int wxString::Printf(const wxChar *pszFormat, ...) 1826{ 1827 va_list argptr; 1828 va_start(argptr, pszFormat); 1829 1830 int iLen = PrintfV(pszFormat, argptr); 1831 1832 va_end(argptr); 1833 1834 return iLen; 1835} 1836 1837/* 1838 Uses wxVsnprintf and places the result into the this string. 1839 1840 In ANSI build, wxVsnprintf is effectively vsnprintf but in Unicode build 1841 it is vswprintf. Due to a discrepancy between vsnprintf and vswprintf in 1842 the ISO C99 (and thus SUSv3) standard the return value for the case of 1843 an undersized buffer is inconsistent. For conforming vsnprintf 1844 implementations the function must return the number of characters that 1845 would have been printed had the buffer been large enough. For conforming 1846 vswprintf implementations the function must return a negative number 1847 and set errno. 1848 1849 What vswprintf sets errno to is undefined but Darwin seems to set it to 1850 EOVERFLOW. The only expected errno are EILSEQ and EINVAL. Both of 1851 those are defined in the standard and backed up by several conformance 1852 statements. Note that ENOMEM mentioned in the manual page does not 1853 apply to swprintf, only wprintf and fwprintf. 1854 1855 Official manual page: 1856 http://www.opengroup.org/onlinepubs/009695399/functions/swprintf.html 1857 1858 Some conformance statements (AIX, Solaris): 1859 http://www.opengroup.org/csq/view.mhtml?RID=ibm%2FSD1%2F3 1860 http://www.theopengroup.org/csq/view.mhtml?norationale=1&noreferences=1&RID=Fujitsu%2FSE2%2F10 1861 1862 Since EILSEQ and EINVAL are rather common but EOVERFLOW is not and since 1863 EILSEQ and EINVAL are specifically defined to mean the error is other than 1864 an undersized buffer and no other errno are defined we treat those two 1865 as meaning hard errors and everything else gets the old behavior which 1866 is to keep looping and increasing buffer size until the function succeeds. 1867 1868 In practice it's impossible to determine before compilation which behavior 1869 may be used. The vswprintf function may have vsnprintf-like behavior or 1870 vice-versa. Behavior detected on one release can theoretically change 1871 with an updated release. Not to mention that configure testing for it 1872 would require the test to be run on the host system, not the build system 1873 which makes cross compilation difficult. Therefore, we make no assumptions 1874 about behavior and try our best to handle every known case, including the 1875 case where wxVsnprintf returns a negative number and fails to set errno. 1876 1877 There is yet one more non-standard implementation and that is our own. 1878 Fortunately, that can be detected at compile-time. 1879 1880 On top of all that, ISO C99 explicitly defines snprintf to write a null 1881 character to the last position of the specified buffer. That would be at 1882 at the given buffer size minus 1. It is supposed to do this even if it 1883 turns out that the buffer is sized too small. 1884 1885 Darwin (tested on 10.5) follows the C99 behavior exactly. 1886 1887 Glibc 2.6 almost follows the C99 behavior except vswprintf never sets 1888 errno even when it fails. However, it only seems to ever fail due 1889 to an undersized buffer. 1890*/ 1891int wxString::PrintfV(const wxChar* pszFormat, va_list argptr) 1892{ 1893 int size = 1024; 1894 1895 for ( ;; ) 1896 { 1897 // Allocate 1 more character than we tell wxVsnprintf about 1898 // just in case it is buggy. 1899 // FIXME: I have a feeling that the underlying function was not buggy 1900 // and I suspect it was to fix the buf[size] = '\0' line below 1901 wxStringBuffer tmp(*this, size + 1); 1902 wxChar *buf = tmp; 1903 1904 if ( !buf ) 1905 { 1906 // out of memory 1907 return -1; 1908 } 1909 1910 // wxVsnprintf() may modify the original arg pointer, so pass it 1911 // only a copy 1912 va_list argptrcopy; 1913 wxVaCopy(argptrcopy, argptr); 1914 1915#ifndef __WXWINCE__ 1916 // Set errno to 0 to make it determinate if wxVsnprintf fails to set it. 1917 errno = 0; 1918#endif 1919 int len = wxVsnprintf(buf, size, pszFormat, argptrcopy); 1920 va_end(argptrcopy); 1921 1922 // some implementations of vsnprintf() don't NUL terminate 1923 // the string if there is not enough space for it so 1924 // always do it manually 1925 // FIXME: This really seems to be the wrong and would be an off-by-one 1926 // bug except the code above allocates an extra character. 1927 buf[size] = _T('\0'); 1928 1929 // vsnprintf() may return either -1 (traditional Unix behaviour) or the 1930 // total number of characters which would have been written if the 1931 // buffer were large enough (newer standards such as Unix98) 1932 if ( len < 0 ) 1933 { 1934#if wxUSE_WXVSNPRINTF 1935 // we know that our own implementation of wxVsnprintf() returns -1 1936 // only for a format error - thus there's something wrong with 1937 // the user's format string 1938 return -1; 1939#else // assume that system version only returns error if not enough space 1940#if !defined(__WXWINCE__) && (!defined(__OS2__) || defined(__INNOTEK_LIBC__)) 1941 if( (errno == EILSEQ) || (errno == EINVAL) ) 1942 // If errno was set to one of the two well-known hard errors 1943 // then fail immediately to avoid an infinite loop. 1944 return -1; 1945 else 1946#endif // __WXWINCE__ 1947 // still not enough, as we don't know how much we need, double the 1948 // current size of the buffer 1949 size *= 2; 1950#endif // wxUSE_WXVSNPRINTF/!wxUSE_WXVSNPRINTF 1951 } 1952 else if ( len >= size ) 1953 { 1954#if wxUSE_WXVSNPRINTF 1955 // we know that our own implementation of wxVsnprintf() returns 1956 // size+1 when there's not enough space but that's not the size 1957 // of the required buffer! 1958 size *= 2; // so we just double the current size of the buffer 1959#else 1960 // some vsnprintf() implementations NUL-terminate the buffer and 1961 // some don't in len == size case, to be safe always add 1 1962 // FIXME: I don't quite understand this comment. The vsnprintf 1963 // function is specifically defined to return the number of 1964 // characters printed not including the null terminator. 1965 // So OF COURSE you need to add 1 to get the right buffer size. 1966 // The following line is definitely correct, no question. 1967 size = len + 1; 1968#endif 1969 } 1970 else // ok, there was enough space 1971 { 1972 break; 1973 } 1974 } 1975 1976 // we could have overshot 1977 Shrink(); 1978 1979 return length(); 1980} 1981 1982// ---------------------------------------------------------------------------- 1983// misc other operations 1984// ---------------------------------------------------------------------------- 1985 1986// returns true if the string matches the pattern which may contain '*' and 1987// '?' metacharacters (as usual, '?' matches any character and '*' any number 1988// of them) 1989bool wxString::Matches(const wxChar *pszMask) const 1990{ 1991 // I disable this code as it doesn't seem to be faster (in fact, it seems 1992 // to be much slower) than the old, hand-written code below and using it 1993 // here requires always linking with libregex even if the user code doesn't 1994 // use it 1995#if 0 // wxUSE_REGEX 1996 // first translate the shell-like mask into a regex 1997 wxString pattern; 1998 pattern.reserve(wxStrlen(pszMask)); 1999 2000 pattern += _T('^'); 2001 while ( *pszMask ) 2002 { 2003 switch ( *pszMask ) 2004 { 2005 case _T('?'): 2006 pattern += _T('.'); 2007 break; 2008 2009 case _T('*'): 2010 pattern += _T(".*"); 2011 break; 2012 2013 case _T('^'): 2014 case _T('.'): 2015 case _T('$'): 2016 case _T('('): 2017 case _T(')'): 2018 case _T('|'): 2019 case _T('+'): 2020 case _T('\\'): 2021 // these characters are special in a RE, quote them 2022 // (however note that we don't quote '[' and ']' to allow 2023 // using them for Unix shell like matching) 2024 pattern += _T('\\'); 2025 // fall through 2026 2027 default: 2028 pattern += *pszMask; 2029 } 2030 2031 pszMask++; 2032 } 2033 pattern += _T('$'); 2034 2035 // and now use it 2036 return wxRegEx(pattern, wxRE_NOSUB | wxRE_EXTENDED).Matches(c_str()); 2037#else // !wxUSE_REGEX 2038 // TODO: this is, of course, awfully inefficient... 2039 2040 // the char currently being checked 2041 const wxChar *pszTxt = c_str(); 2042 2043 // the last location where '*' matched 2044 const wxChar *pszLastStarInText = NULL; 2045 const wxChar *pszLastStarInMask = NULL; 2046 2047match: 2048 for ( ; *pszMask != wxT('\0'); pszMask++, pszTxt++ ) { 2049 switch ( *pszMask ) { 2050 case wxT('?'): 2051 if ( *pszTxt == wxT('\0') ) 2052 return false; 2053 2054 // pszTxt and pszMask will be incremented in the loop statement 2055 2056 break; 2057 2058 case wxT('*'): 2059 { 2060 // remember where we started to be able to backtrack later 2061 pszLastStarInText = pszTxt; 2062 pszLastStarInMask = pszMask; 2063 2064 // ignore special chars immediately following this one 2065 // (should this be an error?) 2066 while ( *pszMask == wxT('*') || *pszMask == wxT('?') ) 2067 pszMask++; 2068 2069 // if there is nothing more, match 2070 if ( *pszMask == wxT('\0') ) 2071 return true; 2072 2073 // are there any other metacharacters in the mask? 2074 size_t uiLenMask; 2075 const wxChar *pEndMask = wxStrpbrk(pszMask, wxT("*?")); 2076 2077 if ( pEndMask != NULL ) { 2078 // we have to match the string between two metachars 2079 uiLenMask = pEndMask - pszMask; 2080 } 2081 else { 2082 // we have to match the remainder of the string 2083 uiLenMask = wxStrlen(pszMask); 2084 } 2085 2086 wxString strToMatch(pszMask, uiLenMask); 2087 const wxChar* pMatch = wxStrstr(pszTxt, strToMatch); 2088 if ( pMatch == NULL ) 2089 return false; 2090 2091 // -1 to compensate "++" in the loop 2092 pszTxt = pMatch + uiLenMask - 1; 2093 pszMask += uiLenMask - 1; 2094 } 2095 break; 2096 2097 default: 2098 if ( *pszMask != *pszTxt ) 2099 return false; 2100 break; 2101 } 2102 } 2103 2104 // match only if nothing left 2105 if ( *pszTxt == wxT('\0') ) 2106 return true; 2107 2108 // if we failed to match, backtrack if we can 2109 if ( pszLastStarInText ) { 2110 pszTxt = pszLastStarInText + 1; 2111 pszMask = pszLastStarInMask; 2112 2113 pszLastStarInText = NULL; 2114 2115 // don't bother resetting pszLastStarInMask, it's unnecessary 2116 2117 goto match; 2118 } 2119 2120 return false; 2121#endif // wxUSE_REGEX/!wxUSE_REGEX 2122} 2123 2124// Count the number of chars 2125int wxString::Freq(wxChar ch) const 2126{ 2127 int count = 0; 2128 int len = length(); 2129 for (int i = 0; i < len; i++) 2130 { 2131 if (GetChar(i) == ch) 2132 count ++; 2133 } 2134 return count; 2135} 2136 2137// convert to upper case, return the copy of the string 2138wxString wxString::Upper() const 2139{ wxString s(*this); return s.MakeUpper(); } 2140 2141// convert to lower case, return the copy of the string 2142wxString wxString::Lower() const { wxString s(*this); return s.MakeLower(); } 2143 2144int wxString::sprintf(const wxChar *pszFormat, ...) 2145 { 2146 va_list argptr; 2147 va_start(argptr, pszFormat); 2148 int iLen = PrintfV(pszFormat, argptr); 2149 va_end(argptr); 2150 return iLen; 2151 } 2152 2153// ============================================================================ 2154// ArrayString 2155// ============================================================================ 2156 2157#include "wx/arrstr.h" 2158 2159wxArrayString::wxArrayString(size_t sz, const wxChar** a) 2160{ 2161#if !wxUSE_STL 2162 Init(false); 2163#endif 2164 for (size_t i=0; i < sz; i++) 2165 Add(a[i]); 2166} 2167 2168wxArrayString::wxArrayString(size_t sz, const wxString* a) 2169{ 2170#if !wxUSE_STL 2171 Init(false); 2172#endif 2173 for (size_t i=0; i < sz; i++) 2174 Add(a[i]); 2175} 2176 2177#if !wxUSE_STL 2178 2179// size increment = min(50% of current size, ARRAY_MAXSIZE_INCREMENT) 2180#define ARRAY_MAXSIZE_INCREMENT 4096 2181 2182#ifndef ARRAY_DEFAULT_INITIAL_SIZE // also defined in dynarray.h 2183#define ARRAY_DEFAULT_INITIAL_SIZE (16) 2184#endif 2185 2186#define STRING(p) ((wxString *)(&(p))) 2187 2188// ctor 2189void wxArrayString::Init(bool autoSort) 2190{ 2191 m_nSize = 2192 m_nCount = 0; 2193 m_pItems = (wxChar **) NULL; 2194 m_autoSort = autoSort; 2195} 2196 2197// copy ctor 2198wxArrayString::wxArrayString(const wxArrayString& src) 2199{ 2200 Init(src.m_autoSort); 2201 2202 *this = src; 2203} 2204 2205// assignment operator 2206wxArrayString& wxArrayString::operator=(const wxArrayString& src) 2207{ 2208 if ( m_nSize > 0 ) 2209 Clear(); 2210 2211 Copy(src); 2212 2213 m_autoSort = src.m_autoSort; 2214 2215 return *this; 2216} 2217 2218void wxArrayString::Copy(const wxArrayString& src) 2219{ 2220 if ( src.m_nCount > ARRAY_DEFAULT_INITIAL_SIZE ) 2221 Alloc(src.m_nCount); 2222 2223 for ( size_t n = 0; n < src.m_nCount; n++ ) 2224 Add(src[n]); 2225} 2226 2227// grow the array 2228void wxArrayString::Grow(size_t nIncrement) 2229{ 2230 // only do it if no more place 2231 if ( (m_nSize - m_nCount) < nIncrement ) { 2232 // if ARRAY_DEFAULT_INITIAL_SIZE were set to 0, the initially empty would 2233 // be never resized! 2234 #if ARRAY_DEFAULT_INITIAL_SIZE == 0 2235 #error "ARRAY_DEFAULT_INITIAL_SIZE must be > 0!" 2236 #endif 2237 2238 if ( m_nSize == 0 ) { 2239 // was empty, alloc some memory 2240 m_nSize = ARRAY_DEFAULT_INITIAL_SIZE; 2241 if (m_nSize < nIncrement) 2242 m_nSize = nIncrement; 2243 m_pItems = new wxChar *[m_nSize]; 2244 } 2245 else { 2246 // otherwise when it's called for the first time, nIncrement would be 0 2247 // and the array would never be expanded 2248 // add 50% but not too much 2249 size_t ndefIncrement = m_nSize < ARRAY_DEFAULT_INITIAL_SIZE 2250 ? ARRAY_DEFAULT_INITIAL_SIZE : m_nSize >> 1; 2251 if ( ndefIncrement > ARRAY_MAXSIZE_INCREMENT ) 2252 ndefIncrement = ARRAY_MAXSIZE_INCREMENT; 2253 if ( nIncrement < ndefIncrement ) 2254 nIncrement = ndefIncrement; 2255 m_nSize += nIncrement; 2256 wxChar **pNew = new wxChar *[m_nSize]; 2257 2258 // copy data to new location 2259 memcpy(pNew, m_pItems, m_nCount*sizeof(wxChar *)); 2260 2261 // delete old memory (but do not release the strings!) 2262 wxDELETEA(m_pItems); 2263 2264 m_pItems = pNew; 2265 } 2266 } 2267} 2268 2269void wxArrayString::Free() 2270{ 2271 for ( size_t n = 0; n < m_nCount; n++ ) { 2272 STRING(m_pItems[n])->GetStringData()->Unlock(); 2273 } 2274} 2275 2276// deletes all the strings from the list 2277void wxArrayString::Empty() 2278{ 2279 Free(); 2280 2281 m_nCount = 0; 2282} 2283 2284// as Empty, but also frees memory 2285void wxArrayString::Clear() 2286{ 2287 Free(); 2288 2289 m_nSize = 2290 m_nCount = 0; 2291 2292 wxDELETEA(m_pItems); 2293} 2294 2295// dtor 2296wxArrayString::~wxArrayString() 2297{ 2298 Free(); 2299 2300 wxDELETEA(m_pItems); 2301} 2302 2303void wxArrayString::reserve(size_t nSize) 2304{ 2305 Alloc(nSize); 2306} 2307 2308// pre-allocates memory (frees the previous data!) 2309void wxArrayString::Alloc(size_t nSize) 2310{ 2311 // only if old buffer was not big enough 2312 if ( nSize > m_nSize ) { 2313 wxChar **pNew = new wxChar *[nSize]; 2314 if ( !pNew ) 2315 return; 2316 2317 memcpy(pNew, m_pItems, m_nCount*sizeof(wxChar *)); 2318 delete [] m_pItems; 2319 2320 m_pItems = pNew; 2321 m_nSize = nSize; 2322 } 2323} 2324 2325// minimizes the memory usage by freeing unused memory 2326void wxArrayString::Shrink() 2327{ 2328 // only do it if we have some memory to free 2329 if( m_nCount < m_nSize ) { 2330 // allocates exactly as much memory as we need 2331 wxChar **pNew = new wxChar *[m_nCount]; 2332 2333 // copy data to new location 2334 memcpy(pNew, m_pItems, m_nCount*sizeof(wxChar *)); 2335 delete [] m_pItems; 2336 m_pItems = pNew; 2337 m_nSize = m_nCount; 2338 } 2339} 2340 2341#if WXWIN_COMPATIBILITY_2_4 2342 2343// return a wxString[] as required for some control ctors. 2344wxString* wxArrayString::GetStringArray() const 2345{ 2346 wxString *array = 0; 2347 2348 if( m_nCount > 0 ) 2349 { 2350 array = new wxString[m_nCount]; 2351 for( size_t i = 0; i < m_nCount; i++ ) 2352 array[i] = m_pItems[i]; 2353 } 2354 2355 return array; 2356} 2357 2358void wxArrayString::Remove(size_t nIndex, size_t nRemove) 2359{ 2360 RemoveAt(nIndex, nRemove); 2361} 2362 2363#endif // WXWIN_COMPATIBILITY_2_4 2364 2365// searches the array for an item (forward or backwards) 2366int wxArrayString::Index(const wxChar *sz, bool bCase, bool bFromEnd) const 2367{ 2368 if ( m_autoSort ) { 2369 // use binary search in the sorted array 2370 wxASSERT_MSG( bCase && !bFromEnd, 2371 wxT("search parameters ignored for auto sorted array") ); 2372 2373 size_t i, 2374 lo = 0, 2375 hi = m_nCount; 2376 int res; 2377 while ( lo < hi ) { 2378 i = (lo + hi)/2; 2379 2380 res = wxStrcmp(sz, m_pItems[i]); 2381 if ( res < 0 ) 2382 hi = i; 2383 else if ( res > 0 ) 2384 lo = i + 1; 2385 else 2386 return i; 2387 } 2388 2389 return wxNOT_FOUND; 2390 } 2391 else { 2392 // use linear search in unsorted array 2393 if ( bFromEnd ) { 2394 if ( m_nCount > 0 ) { 2395 size_t ui = m_nCount; 2396 do { 2397 if ( STRING(m_pItems[--ui])->IsSameAs(sz, bCase) ) 2398 return ui; 2399 } 2400 while ( ui != 0 ); 2401 } 2402 } 2403 else { 2404 for( size_t ui = 0; ui < m_nCount; ui++ ) { 2405 if( STRING(m_pItems[ui])->IsSameAs(sz, bCase) ) 2406 return ui; 2407 } 2408 } 2409 } 2410 2411 return wxNOT_FOUND; 2412} 2413 2414// add item at the end 2415size_t wxArrayString::Add(const wxString& str, size_t nInsert) 2416{ 2417 if ( m_autoSort ) { 2418 // insert the string at the correct position to keep the array sorted 2419 size_t i, 2420 lo = 0, 2421 hi = m_nCount; 2422 int res; 2423 while ( lo < hi ) { 2424 i = (lo + hi)/2; 2425 2426 res = str.Cmp(m_pItems[i]); 2427 if ( res < 0 ) 2428 hi = i; 2429 else if ( res > 0 ) 2430 lo = i + 1; 2431 else { 2432 lo = hi = i; 2433 break; 2434 } 2435 } 2436 2437 wxASSERT_MSG( lo == hi, wxT("binary search broken") ); 2438 2439 Insert(str, lo, nInsert); 2440 2441 return (size_t)lo; 2442 } 2443 else { 2444 wxASSERT( str.GetStringData()->IsValid() ); 2445 2446 Grow(nInsert); 2447 2448 for (size_t i = 0; i < nInsert; i++) 2449 { 2450 // the string data must not be deleted! 2451 str.GetStringData()->Lock(); 2452 2453 // just append 2454 m_pItems[m_nCount + i] = (wxChar *)str.c_str(); // const_cast 2455 } 2456 size_t ret = m_nCount; 2457 m_nCount += nInsert; 2458 return ret; 2459 } 2460} 2461 2462// add item at the given position 2463void wxArrayString::Insert(const wxString& str, size_t nIndex, size_t nInsert) 2464{ 2465 wxASSERT( str.GetStringData()->IsValid() ); 2466 2467 wxCHECK_RET( nIndex <= m_nCount, wxT("bad index in wxArrayString::Insert") ); 2468 wxCHECK_RET( m_nCount <= m_nCount + nInsert, 2469 wxT("array size overflow in wxArrayString::Insert") ); 2470 2471 Grow(nInsert); 2472 2473 memmove(&m_pItems[nIndex + nInsert], &m_pItems[nIndex], 2474 (m_nCount - nIndex)*sizeof(wxChar *)); 2475 2476 for (size_t i = 0; i < nInsert; i++) 2477 { 2478 str.GetStringData()->Lock(); 2479 m_pItems[nIndex + i] = (wxChar *)str.c_str(); 2480 } 2481 m_nCount += nInsert; 2482} 2483 2484// range insert (STL 23.2.4.3) 2485void 2486wxArrayString::insert(iterator it, const_iterator first, const_iterator last) 2487{ 2488 const int idx = it - begin(); 2489 2490 // grow it once 2491 Grow(last - first); 2492 2493 // reset "it" since it can change inside Grow() 2494 it = begin() + idx; 2495 2496 while ( first != last ) 2497 { 2498 it = insert(it, *first); 2499 2500 // insert returns an iterator to the last element inserted but we need 2501 // insert the next after this one, that is before the next one 2502 ++it; 2503 2504 ++first; 2505 } 2506} 2507 2508// expand the array 2509void wxArrayString::SetCount(size_t count) 2510{ 2511 Alloc(count); 2512 2513 wxString s; 2514 while ( m_nCount < count ) 2515 m_pItems[m_nCount++] = (wxChar *)s.c_str(); 2516} 2517 2518// removes item from array (by index) 2519void wxArrayString::RemoveAt(size_t nIndex, size_t nRemove) 2520{ 2521 wxCHECK_RET( nIndex < m_nCount, wxT("bad index in wxArrayString::Remove") ); 2522 wxCHECK_RET( nIndex + nRemove <= m_nCount, 2523 wxT("removing too many elements in wxArrayString::Remove") ); 2524 2525 // release our lock 2526 for (size_t i = 0; i < nRemove; i++) 2527 Item(nIndex + i).GetStringData()->Unlock(); 2528 2529 memmove(&m_pItems[nIndex], &m_pItems[nIndex + nRemove], 2530 (m_nCount - nIndex - nRemove)*sizeof(wxChar *)); 2531 m_nCount -= nRemove; 2532} 2533 2534// removes item from array (by value) 2535void wxArrayString::Remove(const wxChar *sz) 2536{ 2537 int iIndex = Index(sz); 2538 2539 wxCHECK_RET( iIndex != wxNOT_FOUND, 2540 wxT("removing inexistent element in wxArrayString::Remove") ); 2541 2542 RemoveAt(iIndex); 2543} 2544 2545void wxArrayString::assign(const_iterator first, const_iterator last) 2546{ 2547 reserve(last - first); 2548 for(; first != last; ++first) 2549 push_back(*first); 2550} 2551 2552// ---------------------------------------------------------------------------- 2553// sorting 2554// ---------------------------------------------------------------------------- 2555 2556// we can only sort one array at a time with the quick-sort based 2557// implementation 2558#if wxUSE_THREADS 2559 // need a critical section to protect access to gs_compareFunction and 2560 // gs_sortAscending variables 2561 static wxCriticalSection gs_critsectStringSort; 2562#endif // wxUSE_THREADS 2563 2564// function to use for string comparaison 2565static wxArrayString::CompareFunction gs_compareFunction = NULL; 2566 2567// if we don't use the compare function, this flag tells us if we sort the 2568// array in ascending or descending order 2569static bool gs_sortAscending = true; 2570 2571// function which is called by quick sort 2572extern "C" int wxC_CALLING_CONV // LINKAGEMODE 2573wxStringCompareFunction(const void *first, const void *second) 2574{ 2575 wxString *strFirst = (wxString *)first; 2576 wxString *strSecond = (wxString *)second; 2577 2578 if ( gs_compareFunction ) { 2579 return gs_compareFunction(*strFirst, *strSecond); 2580 } 2581 else { 2582 // maybe we should use wxStrcoll 2583 int result = strFirst->Cmp(*strSecond); 2584 2585 return gs_sortAscending ? result : -result; 2586 } 2587} 2588 2589// sort array elements using passed comparaison function 2590void wxArrayString::Sort(CompareFunction compareFunction) 2591{ 2592 wxCRIT_SECT_LOCKER(lockCmpFunc, gs_critsectStringSort); 2593 2594 wxASSERT( !gs_compareFunction ); // must have been reset to NULL 2595 gs_compareFunction = compareFunction; 2596 2597 DoSort(); 2598 2599 // reset it to NULL so that Sort(bool) will work the next time 2600 gs_compareFunction = NULL; 2601} 2602 2603extern "C" 2604{ 2605 typedef int (wxC_CALLING_CONV * wxStringCompareFn)(const void *first, 2606 const void *second); 2607} 2608 2609void wxArrayString::Sort(CompareFunction2 compareFunction) 2610{ 2611 qsort(m_pItems, m_nCount, sizeof(wxChar *), (wxStringCompareFn)compareFunction); 2612} 2613 2614void wxArrayString::Sort(bool reverseOrder) 2615{ 2616 Sort(reverseOrder ? wxStringSortDescending : wxStringSortAscending); 2617} 2618 2619void wxArrayString::DoSort() 2620{ 2621 wxCHECK_RET( !m_autoSort, wxT("can't use this method with sorted arrays") ); 2622 2623 // just sort the pointers using qsort() - of course it only works because 2624 // wxString() *is* a pointer to its data 2625 qsort(m_pItems, m_nCount, sizeof(wxChar *), wxStringCompareFunction); 2626} 2627 2628bool wxArrayString::operator==(const wxArrayString& a) const 2629{ 2630 if ( m_nCount != a.m_nCount ) 2631 return false; 2632 2633 for ( size_t n = 0; n < m_nCount; n++ ) 2634 { 2635 if ( Item(n) != a[n] ) 2636 return false; 2637 } 2638 2639 return true; 2640} 2641 2642#endif // !wxUSE_STL 2643 2644int wxCMPFUNC_CONV wxStringSortAscending(wxString* s1, wxString* s2) 2645{ 2646 return s1->Cmp(*s2); 2647} 2648 2649int wxCMPFUNC_CONV wxStringSortDescending(wxString* s1, wxString* s2) 2650{ 2651 return -s1->Cmp(*s2); 2652} 2653 2654wxString* wxCArrayString::Release() 2655{ 2656 wxString *r = GetStrings(); 2657 m_strings = NULL; 2658 return r; 2659} 2660