X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/3c024cc22f19fa0d809dbfe3050257998def6e78..f5419957e5794f2d10f4e125f77b2c2e2cd222d6:/src/common/string.cpp diff --git a/src/common/string.cpp b/src/common/string.cpp index 1bcf9bff83..749a952b34 100644 --- a/src/common/string.cpp +++ b/src/common/string.cpp @@ -41,6 +41,16 @@ #include #include +// This probably isn't right, what should it be Vadim? +// Otherwise we end up with no wxVsprintf defined. +#ifdef __WXMOTIF__ +#define HAVE_VPRINTF +#endif + +#ifdef wxUSE_WCSRTOMBS + #include // for wcsrtombs(), see comments where it's used +#endif // GNU + #ifdef WXSTRING_IS_WXOBJECT IMPLEMENT_DYNAMIC_CLASS(wxString, wxObject) #endif //WXSTRING_IS_WXOBJECT @@ -74,6 +84,31 @@ static const struct // empty C style string: points to 'string data' byte of g_strEmpty extern const char *g_szNul = &g_strEmpty.dummy; +// ---------------------------------------------------------------------------- +// conditional compilation +// ---------------------------------------------------------------------------- + +// we want to find out if the current platform supports vsnprintf()-like +// function: for Unix this is done with configure, for Windows we test the +// compiler explicitly. +#ifdef __WXMSW__ + #ifdef _MSC_VER + #define wxVsprintf _vsnprintf + #endif +#else // !Windows + #ifdef HAVE_VSNPRINTF + #define wxVsprintf vsnprintf + #endif +#endif // Windows/!Windows + +#ifndef wxVsprintf + // in this case we'll use vsprintf() (which is ANSI and thus should be + // always available), but it's unsafe because it doesn't check for buffer + // size - so give a warning + #define wxVsprintf(buffer,len,format,argptr) vsprintf(buffer,format, argptr) + #pragma message("Using sprintf() because no snprintf()-like function defined") +#endif + // ---------------------------------------------------------------------------- // global functions // ---------------------------------------------------------------------------- @@ -84,13 +119,34 @@ extern const char *g_szNul = &g_strEmpty.dummy; // iostream ones. // // ATTN: you can _not_ use both of these in the same program! -#if 0 // def _MSC_VER - #include - #define NAMESPACE std:: +#if wxUSE_IOSTREAMH +#include +#define NAMESPACE +#else +#include +# ifdef _MSC_VER + using namespace std; +# endif +// for msvc (bcc50+ also) you don't need these NAMESPACE defines, +// using namespace std; takes care of that. +#define NAMESPACE std:: +#endif + +#ifdef __WXMSW__ + #ifdef _MSC_VER + #define wxVsprintf _vsnprintf + #endif #else - #include - #define NAMESPACE -#endif //Visual C++ + #if defined ( HAVE_VSNPRINTF ) + #define wxVsprintf vsnprintf + #endif +#endif + +#ifndef wxVsprintf + // vsprintf() is ANSI so we can always use it, but it's unsafe! + #define wxVsprintf(buffer,len,format,argptr) vsprintf(buffer,format, argptr) + #pragma message("Using sprintf() because no snprintf()-like function defined") +#endif NAMESPACE istream& operator>>(NAMESPACE istream& is, wxString& WXUNUSED(str)) { @@ -136,7 +192,7 @@ NAMESPACE istream& operator>>(NAMESPACE istream& is, wxString& WXUNUSED(str)) { public: Averager(const char *sz) { m_sz = sz; m_nTotal = m_nCount = 0; } - ~Averager() + ~Averager() { printf("wxString: average %s = %f\n", m_sz, ((float)m_nTotal)/m_nCount); } void Add(size_t n) { m_nTotal += n; m_nCount++; } @@ -216,7 +272,17 @@ wxString::wxString(const void *pStart, const void *pEnd) wxString::wxString(const wchar_t *pwz) { // first get necessary size + + // NB: GNU libc5 wcstombs() is completely broken, don't use it (it doesn't + // honor the 3rd parameter, thus it will happily crash here). +#ifdef wxUSE_WCSRTOMBS + // don't know if it's really needed (or if we can pass NULL), but better safe + // than quick + mbstate_t mbstate; + size_t nLen = wcsrtombs((char *) NULL, &pwz, 0, &mbstate); +#else // !GNU libc size_t nLen = wcstombs((char *) NULL, pwz, 0); +#endif // GNU // empty? if ( nLen != 0 ) { @@ -441,43 +507,44 @@ void wxString::ConcatSelf(int nSrcLen, const char *pszSrcData) { STATISTICS_ADD(SummandLength, nSrcLen); - // concatenating an empty string is a NOP, but it happens quite rarely, - // so we don't waste our time checking for it - // if ( nSrcLen > 0 ) - wxStringData *pData = GetStringData(); - size_t nLen = pData->nDataLength; - size_t nNewLen = nLen + nSrcLen; + // concatenating an empty string is a NOP + if ( nSrcLen > 0 ) { + wxStringData *pData = GetStringData(); + size_t nLen = pData->nDataLength; + size_t nNewLen = nLen + nSrcLen; - // alloc new buffer if current is too small - if ( pData->IsShared() ) { - STATISTICS_ADD(ConcatHit, 0); + // alloc new buffer if current is too small + if ( pData->IsShared() ) { + STATISTICS_ADD(ConcatHit, 0); - // we have to allocate another buffer - wxStringData* pOldData = GetStringData(); - AllocBuffer(nNewLen); - memcpy(m_pchData, pOldData->data(), nLen*sizeof(char)); - pOldData->Unlock(); - } - else if ( nNewLen > pData->nAllocLength ) { - STATISTICS_ADD(ConcatHit, 0); + // we have to allocate another buffer + wxStringData* pOldData = GetStringData(); + AllocBuffer(nNewLen); + memcpy(m_pchData, pOldData->data(), nLen*sizeof(char)); + pOldData->Unlock(); + } + else if ( nNewLen > pData->nAllocLength ) { + STATISTICS_ADD(ConcatHit, 0); - // we have to grow the buffer - Alloc(nNewLen); - } - else { - STATISTICS_ADD(ConcatHit, 1); + // we have to grow the buffer + Alloc(nNewLen); + } + else { + STATISTICS_ADD(ConcatHit, 1); - // the buffer is already big enough - } + // the buffer is already big enough + } - // should be enough space - wxASSERT( nNewLen <= GetStringData()->nAllocLength ); + // should be enough space + wxASSERT( nNewLen <= GetStringData()->nAllocLength ); - // fast concatenation - all is done in our buffer - memcpy(m_pchData + nLen, pszSrcData, nSrcLen*sizeof(char)); + // fast concatenation - all is done in our buffer + memcpy(m_pchData + nLen, pszSrcData, nSrcLen*sizeof(char)); - m_pchData[nNewLen] = '\0'; // put terminating '\0' - GetStringData()->nDataLength = nNewLen; // and fix the length + m_pchData[nNewLen] = '\0'; // put terminating '\0' + GetStringData()->nDataLength = nNewLen; // and fix the length + } + //else: the string to append was empty } /* @@ -563,20 +630,32 @@ void wxString::AllocCopy(wxString& dest, int nCopyLen, int nCopyIndex) const } // extract string of length nCount starting at nFirst -// default value of nCount is 0 and means "till the end" wxString wxString::Mid(size_t nFirst, size_t nCount) const { + wxStringData *pData = GetStringData(); + size_t nLen = pData->nDataLength; + + // default value of nCount is STRING_MAXLEN and means "till the end" + if ( nCount == STRING_MAXLEN ) + { + nCount = nLen - nFirst; + } + // out-of-bounds requests return sensible things - if ( nCount == 0 ) - nCount = GetStringData()->nDataLength - nFirst; + if ( nFirst + nCount > nLen ) + { + nCount = nLen - nFirst; + } - if ( nFirst + nCount > (size_t)GetStringData()->nDataLength ) - nCount = GetStringData()->nDataLength - nFirst; - if ( nFirst > (size_t)GetStringData()->nDataLength ) + if ( nFirst > nLen ) + { + // AllocCopy() will return empty string nCount = 0; + } wxString dest; AllocCopy(dest, nCount, nFirst); + return dest; } @@ -762,30 +841,40 @@ wxString& wxString::MakeLower() // trims spaces (in the sense of isspace) from left or right side wxString& wxString::Trim(bool bFromRight) { - CopyBeforeWrite(); - - if ( bFromRight ) - { - // find last non-space character - char *psz = m_pchData + GetStringData()->nDataLength - 1; - while ( isspace(*psz) && (psz >= m_pchData) ) - psz--; - - // truncate at trailing space start - *++psz = '\0'; - GetStringData()->nDataLength = psz - m_pchData; - } - else + // first check if we're going to modify the string at all + if ( !IsEmpty() && + ( + (bFromRight && isspace(GetChar(Len() - 1))) || + (!bFromRight && isspace(GetChar(0u))) + ) + ) { - // find first non-space character - const char *psz = m_pchData; - while ( isspace(*psz) ) - psz++; - - // fix up data and length - int nDataLength = GetStringData()->nDataLength - (psz - m_pchData); - memmove(m_pchData, psz, (nDataLength + 1)*sizeof(char)); - GetStringData()->nDataLength = nDataLength; + // ok, there is at least one space to trim + CopyBeforeWrite(); + + if ( bFromRight ) + { + // find last non-space character + char *psz = m_pchData + GetStringData()->nDataLength - 1; + while ( isspace(*psz) && (psz >= m_pchData) ) + psz--; + + // truncate at trailing space start + *++psz = '\0'; + GetStringData()->nDataLength = psz - m_pchData; + } + else + { + // find first non-space character + const char *psz = m_pchData; + while ( isspace(*psz) ) + psz++; + + // fix up data and length + int nDataLength = GetStringData()->nDataLength - (psz - m_pchData); + memmove(m_pchData, psz, (nDataLength + 1)*sizeof(char)); + GetStringData()->nDataLength = nDataLength; + } } return *this; @@ -836,6 +925,33 @@ int wxString::Find(const char *pszSub) const return (psz == NULL) ? NOT_FOUND : psz - m_pchData; } +// --------------------------------------------------------------------------- +// stream-like operators +// --------------------------------------------------------------------------- +wxString& wxString::operator<<(int i) +{ + wxString res; + res.Printf("%d", i); + + return (*this) << res; +} + +wxString& wxString::operator<<(float f) +{ + wxString res; + res.Printf("%f", f); + + return (*this) << res; +} + +wxString& wxString::operator<<(double d) +{ + wxString res; + res.Printf("%g", d); + + return (*this) << res; +} + // --------------------------------------------------------------------------- // formatted output // --------------------------------------------------------------------------- @@ -853,11 +969,41 @@ int wxString::Printf(const char *pszFormat, ...) int wxString::PrintfV(const char* pszFormat, va_list argptr) { + // static buffer to avoid dynamic memory allocation each time static char s_szScratch[1024]; - int iLen = vsprintf(s_szScratch, pszFormat, argptr); + // NB: wxVsprintf() may return either less than the buffer size or -1 if there + // is not enough place depending on implementation + int iLen = wxVsprintf(s_szScratch, WXSIZEOF(s_szScratch), pszFormat, argptr); + char *buffer; + if ( iLen < (int)WXSIZEOF(s_szScratch) ) { + buffer = s_szScratch; + } + else { + int size = WXSIZEOF(s_szScratch) * 2; + buffer = (char *)malloc(size); + while ( buffer != NULL ) { + iLen = wxVsprintf(buffer, WXSIZEOF(s_szScratch), pszFormat, argptr); + if ( iLen < size ) { + // ok, there was enough space + break; + } + + // still not enough, double it again + buffer = (char *)realloc(buffer, size *= 2); + } + + if ( !buffer ) { + // out of memory + return -1; + } + } + AllocBeforeWrite(iLen); - strcpy(m_pchData, s_szScratch); + strcpy(m_pchData, buffer); + + if ( buffer != s_szScratch ) + free(buffer); return iLen; }