X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/2523e9b70044baa92a1c63ffdfe179c28ad53536..69659fd770f615210efac4b4fa741b3ad6223616:/src/common/wxprintf.cpp diff --git a/src/common/wxprintf.cpp b/src/common/wxprintf.cpp index 4aed1cad1f..ee415e8bac 100644 --- a/src/common/wxprintf.cpp +++ b/src/common/wxprintf.cpp @@ -20,7 +20,7 @@ #pragma hdrstop #endif -#include "wx/wxchar.h" +#include "wx/crt.h" #include @@ -44,7 +44,8 @@ using namespace std ; // special test mode: define all functions below even if we don't really need // them to be able to test them #ifdef wxTEST_PRINTF - #undef wxVsnprintf_ + #undef wxCRT_VsnprintfW + #undef wxCRT_VsnprintfA #endif // ---------------------------------------------------------------------------- @@ -53,13 +54,13 @@ using namespace std ; // (very useful for i18n purposes) // ---------------------------------------------------------------------------- -#if !defined(wxVsnprintf_) +// ---------------------------------------------------------------------------- +// common code for both ANSI and Unicode versions +// ---------------------------------------------------------------------------- -#if !wxUSE_WXVSNPRINTF - #error wxUSE_WXVSNPRINTF must be 1 if our wxVsnprintf_ is used -#endif +#if !defined(wxCRT_VsnprintfW) || !defined(wxCRT_VsnprintfA) -// wxUSE_STRUTILS says our wxVsnprintf_ implementation to use or not to +// wxUSE_STRUTILS says our wxCRT_VsnprintfW implementation to use or not to // use wxStrlen and wxStrncpy functions over one-char processing loops. // // Some benchmarking revealed that wxUSE_STRUTILS == 1 has the following @@ -99,7 +100,10 @@ using namespace std ; #define SYSTEM_SPRINTF_IS_UNSAFE #endif -// the conversion specifiers accepted by wxVsnprintf_ +namespace +{ + +// the conversion specifiers accepted by wxCRT_VsnprintfW enum wxPrintfArgType { wxPAT_INVALID = -1, @@ -126,7 +130,7 @@ enum wxPrintfArgType { wxPAT_NLONGINT // %ln }; -// an argument passed to wxVsnprintf_ +// an argument passed to wxCRT_VsnprintfW typedef union { int pad_int; // %d, %i, %o, %u, %x, %X long int pad_longint; // %ld, etc @@ -150,11 +154,28 @@ typedef union { long int *pad_nlongint; // %ln } wxPrintfArg; +// helper for converting string into either char* or wchar_t* dependening +// on the type of wxPrintfConvSpec instantiation: +template struct wxPrintfStringHelper {}; + +template<> struct wxPrintfStringHelper +{ + typedef const wxWX2MBbuf ConvertedType; + static ConvertedType Convert(const wxString& s) { return s.mb_str(); } +}; + +template<> struct wxPrintfStringHelper +{ + typedef const wxWX2WCbuf ConvertedType; + static ConvertedType Convert(const wxString& s) { return s.wc_str(); } +}; + // Contains parsed data relative to a conversion specifier given to -// wxVsnprintf_ and parsed from the format string +// wxCRT_VsnprintfW and parsed from the format string // NOTE: in C++ there is almost no difference between struct & classes thus // there is no performance gain by using a struct here... +template class wxPrintfConvSpec { public: @@ -176,18 +197,18 @@ public: // pointer to the '%' of this conversion specifier in the format string // NOTE: this points somewhere in the string given to the Parse() function - // it's task of the caller ensure that memory is still valid ! - const wxChar *m_pArgPos; + const CharType *m_pArgPos; // pointer to the last character of this conversion specifier in the // format string // NOTE: this points somewhere in the string given to the Parse() function - // it's task of the caller ensure that memory is still valid ! - const wxChar *m_pArgEnd; + const CharType *m_pArgEnd; // a little buffer where formatting flags like #+\.hlqLZ are stored by Parse() // for use in Process() // NB: even if this buffer is used only for numeric conversion specifiers and - // thus could be safely declared as a char[] buffer, we want it to be wxChar + // thus could be safely declared as a char[] buffer, we want it to be wchar_t // so that in Unicode builds we can avoid to convert its contents to Unicode // chars when copying it in user's buffer. char m_szFlags[wxMAX_SVNPRINTF_FLAGBUFFER_LEN]; @@ -196,19 +217,19 @@ public: public: // we don't declare this as a constructor otherwise it would be called - // automatically and we don't want this: to be optimized, wxVsnprintf_ + // automatically and we don't want this: to be optimized, wxCRT_VsnprintfW // calls this function only on really-used instances of this class. void Init(); // Parses the first conversion specifier in the given string, which must // begin with a '%'. Returns false if the first '%' does not introduce a // (valid) conversion specifier and thus should be ignored. - bool Parse(const wxChar *format); + bool Parse(const CharType *format); // Process this conversion specifier and puts the result in the given // buffer. Returns the number of characters written in 'buf' or -1 if // there's not enough space. - int Process(wxChar *buf, size_t lenMax, wxPrintfArg *p, size_t written); + int Process(CharType *buf, size_t lenMax, wxPrintfArg *p, size_t written); // Loads the argument of this conversion specifier from given va_list. bool LoadArg(wxPrintfArg *p, va_list &argptr); @@ -218,7 +239,8 @@ private: void ReplaceAsteriskWith(int w); }; -void wxPrintfConvSpec::Init() +template +void wxPrintfConvSpec::Init() { m_nMinWidth = 0; m_nMaxWidth = 0xFFFF; @@ -232,7 +254,8 @@ void wxPrintfConvSpec::Init() m_szFlags[0] = '%'; } -bool wxPrintfConvSpec::Parse(const wxChar *format) +template +bool wxPrintfConvSpec::Parse(const CharType *format) { bool done = false; @@ -254,7 +277,7 @@ bool wxPrintfConvSpec::Parse(const wxChar *format) } // what follows '%'? - const wxChar ch = *(++m_pArgEnd); + const CharType ch = *(++m_pArgEnd); switch ( ch ) { case wxT('\0'): @@ -362,8 +385,8 @@ bool wxPrintfConvSpec::Parse(const wxChar *format) { int len = 0; CHECK_PREC - while ( (*m_pArgEnd >= wxT('0')) && - (*m_pArgEnd <= wxT('9')) ) + while ( (*m_pArgEnd >= CharType('0')) && + (*m_pArgEnd <= CharType('9')) ) { m_szFlags[flagofs++] = char(*m_pArgEnd); len = len*10 + (*m_pArgEnd - wxT('0')); @@ -528,8 +551,8 @@ bool wxPrintfConvSpec::Parse(const wxChar *format) return true; // parsing was successful } - -void wxPrintfConvSpec::ReplaceAsteriskWith(int width) +template +void wxPrintfConvSpec::ReplaceAsteriskWith(int width) { char temp[wxMAX_SVNPRINTF_FLAGBUFFER_LEN]; @@ -556,7 +579,8 @@ void wxPrintfConvSpec::ReplaceAsteriskWith(int width) strcpy(pwidth+offset, temp); } -bool wxPrintfConvSpec::LoadArg(wxPrintfArg *p, va_list &argptr) +template +bool wxPrintfConvSpec::LoadArg(wxPrintfArg *p, va_list &argptr) { // did the '*' width/precision specifier was used ? if (m_nMaxWidth == -1) @@ -637,7 +661,8 @@ bool wxPrintfConvSpec::LoadArg(wxPrintfArg *p, va_list &argptr) return true; // loading was successful } -int wxPrintfConvSpec::Process(wxChar *buf, size_t lenMax, wxPrintfArg *p, size_t written) +template +int wxPrintfConvSpec::Process(CharType *buf, size_t lenMax, wxPrintfArg *p, size_t written) { // buffer to avoid dynamic memory allocation each time for small strings; // note that this buffer is used only to hold results of number formatting, @@ -688,32 +713,13 @@ int wxPrintfConvSpec::Process(wxChar *buf, size_t lenMax, wxPrintfArg *p, size_t case wxPAT_CHAR: case wxPAT_WCHAR: { - wxChar val = -#if wxUSE_UNICODE - p->pad_wchar; - + wxUniChar ch; if (m_type == wxPAT_CHAR) - { - // user passed a character explicitely indicated as ANSI... - const char buf[2] = { p->pad_char, 0 }; - val = wxString(buf, wxConvLibc)[0u]; + ch = p->pad_char; + else // m_type == wxPAT_WCHAR + ch = p->pad_wchar; - //wprintf(L"converting ANSI=>Unicode"); // for debug - } -#else - p->pad_char; - -#if wxUSE_WCHAR_T - if (m_type == wxPAT_WCHAR) - { - // user passed a character explicitely indicated as Unicode... - const wchar_t buf[2] = { p->pad_wchar, 0 }; - val = wxString(buf, wxConvLibc)[0u]; - - //printf("converting Unicode=>ANSI"); // for debug - } -#endif -#endif + CharType val = ch; size_t i; @@ -738,9 +744,12 @@ int wxPrintfConvSpec::Process(wxChar *buf, size_t lenMax, wxPrintfArg *p, size_t if ( !arg.IsValid() && m_nMaxWidth >= 6 ) s = wxT("(null)"); + typename wxPrintfStringHelper::ConvertedType strbuf( + wxPrintfStringHelper::Convert(s)); + // at this point we are sure that m_nMaxWidth is positive or // null (see top of wxPrintfConvSpec::LoadArg) - int len = wxMin((unsigned int)m_nMaxWidth, s.length()); + int len = wxMin((unsigned int)m_nMaxWidth, wxStrlen(strbuf)); int i; @@ -750,19 +759,9 @@ int wxPrintfConvSpec::Process(wxChar *buf, size_t lenMax, wxPrintfArg *p, size_t APPEND_CH(_T(' ')); } -#if wxUSE_STRUTILS len = wxMin((unsigned int)len, lenMax-lenCur); - #if wxUSE_UNICODE // FIXME-UTF8 - wxStrncpy(buf+lenCur, s.wc_str(), len); - #else - wxStrncpy(buf+lenCur, s.mb_str(), len); - #endif + wxStrncpy(buf+lenCur, strbuf, len); lenCur += len; -#else - wxString::const_iterator end = s.begin() + len; - for (wxString::const_iterator j = s.begin(); j != end; ++j) - APPEND_CH(*j); -#endif if (m_bAlignLeft) { @@ -803,54 +802,22 @@ int wxPrintfConvSpec::Process(wxChar *buf, size_t lenMax, wxPrintfArg *p, size_t case wxPAT_DOUBLE: case wxPAT_POINTER: wxASSERT(lenScratch < wxMAX_SVNPRINTF_SCRATCHBUFFER_LEN); -#if !wxUSE_UNICODE + // NB: 1) we can compare lenMax (for CharType*, i.e. possibly + // wchar_t*) with lenScratch (char*) because this code is + // formatting integers and that will have the same length + // even in UTF-8 (the only case when char* length may be + // more than wchar_t* length of the same string) + // 2) wxStrncpy converts the 2nd argument to 1st argument's + // type transparently if their types differ, so this code + // works for both instantiations + if (lenMax < lenScratch) { - if (lenMax < lenScratch) - { - // fill output buffer and then return -1 - wxStrncpy(buf, szScratch, lenMax); - return -1; - } - wxStrncpy(buf, szScratch, lenScratch); - lenCur += lenScratch; + // fill output buffer and then return -1 + wxStrncpy(buf, szScratch, lenMax); + return -1; } -#else - { - // Copy the char scratch to the wide output. This requires - // conversion, but we can optimise by making use of the fact - // that we are formatting numbers, this should mean only 7-bit - // ascii characters are involved. - wxChar *bufptr = buf; - const wxChar *bufend = buf + lenMax; - const char *scratchptr = szScratch; - - // Simply copy each char to a wxChar, stopping on the first - // null or non-ascii byte. Checking '(signed char)*scratchptr - // > 0' is an extra optimisation over '*scratchptr != 0 && - // isascii(*scratchptr)', though it assumes signed char is - // 8-bit 2 complement. - while ((signed char)*scratchptr > 0 && bufptr != bufend) - *bufptr++ = *scratchptr++; - - if (bufptr == bufend) - return -1; - - lenCur += bufptr - buf; - - // check if the loop stopped on a non-ascii char, if yes then - // fall back to wxMB2WX - if (*scratchptr) - { - size_t len = wxMB2WX(bufptr, scratchptr, bufend - bufptr); - - if (len && len != (size_t)(-1)) - if (bufptr[len - 1]) - return -1; - else - lenCur += len; - } - } -#endif + wxStrncpy(buf, szScratch, lenScratch); + lenCur += lenScratch; break; default: @@ -863,12 +830,12 @@ int wxPrintfConvSpec::Process(wxChar *buf, size_t lenMax, wxPrintfArg *p, size_t // Copy chars from source to dest converting '%%' to '%'. Takes at most maxIn // chars from source and write at most outMax chars to dest, returns the // number of chars actually written. Does not treat null specially. -// +template static int wxCopyStrWithPercents( size_t maxOut, - wxChar *dest, + CharType *dest, size_t maxIn, - const wxChar *source) + const CharType *source) { size_t written = 0; @@ -894,19 +861,20 @@ static int wxCopyStrWithPercents( return written; } -int WXDLLEXPORT wxVsnprintf_(wxChar *buf, size_t lenMax, - const wxChar *format, va_list argptr) +template +static int wxDoVsnprintf(CharType *buf, size_t lenMax, + const CharType *format, va_list argptr) { // useful for debugging, to understand if we are really using this function // rather than the system implementation #if 0 - wprintf(L"Using wxVsnprintf_\n"); + wprintf(L"Using wxCRT_VsnprintfW\n"); #endif // required memory: - wxPrintfConvSpec arg[wxMAX_SVNPRINTF_ARGUMENTS]; + wxPrintfConvSpec arg[wxMAX_SVNPRINTF_ARGUMENTS]; wxPrintfArg argdata[wxMAX_SVNPRINTF_ARGUMENTS]; - wxPrintfConvSpec *pspec[wxMAX_SVNPRINTF_ARGUMENTS] = { NULL }; + wxPrintfConvSpec *pspec[wxMAX_SVNPRINTF_ARGUMENTS] = { NULL }; size_t i; @@ -914,7 +882,7 @@ int WXDLLEXPORT wxVsnprintf_(wxChar *buf, size_t lenMax, size_t lenCur = 0; size_t nargs = 0; - const wxChar *toparse = format; + const CharType *toparse = format; // parse the format string bool posarg_present = false, nonposarg_present = false; @@ -928,7 +896,7 @@ int WXDLLEXPORT wxVsnprintf_(wxChar *buf, size_t lenMax, if (arg[nargs].Parse(toparse)) { // ...yes it is - wxPrintfConvSpec *current = &arg[nargs]; + wxPrintfConvSpec *current = &arg[nargs]; // make toparse point to the end of this specifier toparse = current->m_pArgEnd; @@ -1053,10 +1021,54 @@ int WXDLLEXPORT wxVsnprintf_(wxChar *buf, size_t lenMax, #undef APPEND_CH #undef CHECK_PREC -#else // wxVsnprintf_ is defined +} // anonymous namespace + +#endif // !defined(wxCRT_VsnprintfW) || !defined(wxCRT_VsnprintfA) + +// ---------------------------------------------------------------------------- +// wxCRT_VsnprintfW +// ---------------------------------------------------------------------------- + +#if !defined(wxCRT_VsnprintfW) + +#if !wxUSE_WXVSNPRINTFW + #error "wxUSE_WXVSNPRINTFW must be 1 if our wxCRT_VsnprintfW is used" +#endif + +int wxCRT_VsnprintfW(wchar_t *buf, size_t len, + const wchar_t *format, va_list argptr) +{ + return wxDoVsnprintf(buf, len, format, argptr); +} + +#else // wxCRT_VsnprintfW is defined + +#if wxUSE_WXVSNPRINTFW + #error "wxUSE_WXVSNPRINTFW must be 0 if our wxCRT_VsnprintfW is not used" +#endif + +#endif // !wxCRT_VsnprintfW + +// ---------------------------------------------------------------------------- +// wxCRT_VsnprintfA +// ---------------------------------------------------------------------------- + +#ifndef wxCRT_VsnprintfA + +#if !wxUSE_WXVSNPRINTFA + #error "wxUSE_WXVSNPRINTFA must be 1 if our wxCRT_VsnprintfA is used" +#endif + +int wxCRT_VsnprintfA(char *buf, size_t len, + const char *format, va_list argptr) +{ + return wxDoVsnprintf(buf, len, format, argptr); +} + +#else // wxCRT_VsnprintfA is defined -#if wxUSE_WXVSNPRINTF - #error wxUSE_WXVSNPRINTF must be 0 if our wxVsnprintf_ is not used +#if wxUSE_WXVSNPRINTFA + #error "wxUSE_WXVSNPRINTFA must be 0 if our wxCRT_VsnprintfA is not used" #endif -#endif // !wxVsnprintf_ +#endif // !wxCRT_VsnprintfA