X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/50e27899137071a7379e0bcca3ced4097d982e5b..8fdbcf4de8eeff67ccfaf3deec833d203f112629:/src/common/strvararg.cpp?ds=sidebyside diff --git a/src/common/strvararg.cpp b/src/common/strvararg.cpp index 34cac3ca1d..656359a6b2 100644 --- a/src/common/strvararg.cpp +++ b/src/common/strvararg.cpp @@ -25,6 +25,8 @@ #include "wx/strvararg.h" #include "wx/string.h" +#include "wx/crt.h" +#include "wx/private/wxprintf.h" // ============================================================================ // implementation @@ -45,13 +47,17 @@ const wxStringCharType *wxArgNormalizerNative::get() const } #if wxUSE_UNICODE_UTF8 && !wxUSE_UTF8_LOCALE_ONLY -wxArgNormalizerWchar::wxArgNormalizerWchar(const wxString& s) - : wxArgNormalizerWithBuffer(s.wc_str()) +wxArgNormalizerWchar::wxArgNormalizerWchar( + const wxString& s, + const wxFormatString *fmt, unsigned index) + : wxArgNormalizerWithBuffer(s.wc_str(), fmt, index) { } -wxArgNormalizerWchar::wxArgNormalizerWchar(const wxCStrData& s) - : wxArgNormalizerWithBuffer(s.AsWCharBuf()) +wxArgNormalizerWchar::wxArgNormalizerWchar( + const wxCStrData& s, + const wxFormatString *fmt, unsigned index) + : wxArgNormalizerWithBuffer(s.AsWCharBuf(), fmt, index) { } #endif // wxUSE_UNICODE_UTF8 && !wxUSE_UTF8_LOCALE_ONLY @@ -66,14 +72,14 @@ wxString wxArgNormalizedString::GetString() const return wxEmptyString; #if wxUSE_UTF8_LOCALE_ONLY - return wxString(wx_reinterpret_cast(const char*, m_ptr)); + return wxString(reinterpret_cast(m_ptr)); #else #if wxUSE_UNICODE_UTF8 if ( wxLocaleIsUtf8 ) - return wxString(wx_reinterpret_cast(const char*, m_ptr)); + return wxString(reinterpret_cast(m_ptr)); else #endif - return wxString(wx_reinterpret_cast(const wxChar*, m_ptr)); + return wxString(reinterpret_cast(m_ptr)); #endif // !wxUSE_UTF8_LOCALE_ONLY } @@ -127,10 +133,6 @@ wxArgNormalizedString::operator wxString() const And, of course, the same should be done for %c as well. - 4) Finally, in UTF-8 build when calling ANSI printf() function, we need to - translate %c to %s, because not every Unicode character can be - represented by a char. - wxScanf() family of functions is simpler, because we don't normalize their variadic arguments and we only have to handle 2) above and only for widechar @@ -150,30 +152,43 @@ public: m_nCopied = 0; } - wxCharTypeBuffer Convert(const CharType *format) + wxScopedCharTypeBuffer Convert(const CharType *format) { // this is reset to NULL if we modify the format string m_fmtOrig = format; while ( *format ) { - if ( CopyFmtChar(*format++) == _T('%') ) + if ( CopyFmtChar(*format++) == wxT('%') ) { +#if wxUSE_PRINTF_POS_PARAMS + if ( *format >= '0' && *format <= '9' ) + { + SkipDigits(&format); + if ( *format == '$' ) + { + // It was a positional argument specification. + CopyFmtChar(*format++); + } + //else: it was a width specification, nothing else to do. + } +#endif // wxUSE_PRINTF_POS_PARAMS + // skip any flags while ( IsFlagChar(*format) ) CopyFmtChar(*format++); // and possible width - if ( *format == _T('*') ) + if ( *format == wxT('*') ) CopyFmtChar(*format++); else SkipDigits(&format); // precision? - if ( *format == _T('.') ) + if ( *format == wxT('.') ) { CopyFmtChar(*format++); - if ( *format == _T('*') ) + if ( *format == wxT('*') ) CopyFmtChar(*format++); else SkipDigits(&format); @@ -209,16 +224,16 @@ public: // and finally we should have the type switch ( *format ) { - case _T('S'): - case _T('s'): + case wxT('S'): + case wxT('s'): // all strings were converted into the same form by // wxArgNormalizer, this form depends on the context // in which the value is used (scanf/printf/wprintf): HandleString(*format, size, outConv, outSize); break; - case _T('C'): - case _T('c'): + case wxT('C'): + case wxT('c'): HandleChar(*format, size, outConv, outSize); break; @@ -238,11 +253,11 @@ public: switch ( outSize ) { case Size_Long: - InsertFmtChar(_T('l')); + InsertFmtChar(wxT('l')); break; case Size_Short: - InsertFmtChar(_T('h')); + InsertFmtChar(wxT('h')); break; case Size_Default: @@ -261,12 +276,14 @@ public: // format if ( m_fmtOrig ) { - return wxCharTypeBuffer::CreateNonOwned(m_fmtOrig); + return wxScopedCharTypeBuffer::CreateNonOwned(m_fmtOrig); } else { - // NULL-terminate converted format string: - *m_fmtLast = 0; + // shrink converted format string to actual size (instead of + // over-sized allocation from CopyAllBefore()) and NUL-terminate + // it: + m_fmt.shrink(m_fmtLast - m_fmt.data()); return m_fmt; } } @@ -349,13 +366,13 @@ private: static bool IsFlagChar(CharType ch) { - return ch == _T('-') || ch == _T('+') || - ch == _T('0') || ch == _T(' ') || ch == _T('#'); + return ch == wxT('-') || ch == wxT('+') || + ch == wxT('0') || ch == wxT(' ') || ch == wxT('#'); } void SkipDigits(const CharType **ptpc) { - while ( **ptpc >= _T('0') && **ptpc <= _T('9') ) + while ( **ptpc >= wxT('0') && **ptpc <= wxT('9') ) CopyFmtChar(*(*ptpc)++); } @@ -371,9 +388,7 @@ private: size_t m_nCopied; }; - - -#ifdef __WINDOWS +#if defined(__WINDOWS__) && !defined(__CYGWIN__) // on Windows, we should use %s and %c regardless of the build: class wxPrintfFormatConverterWchar : public wxFormatConverterBase @@ -420,6 +435,8 @@ class wxPrintfFormatConverterWchar : public wxFormatConverterBase }; #endif // !wxUSE_UTF8_LOCALE_ONLY +#endif // __WINDOWS__/!__WINDOWS__ + #if wxUSE_UNICODE_UTF8 class wxPrintfFormatConverterUtf8 : public wxFormatConverterBase { @@ -435,15 +452,14 @@ class wxPrintfFormatConverterUtf8 : public wxFormatConverterBase SizeModifier WXUNUSED(size), CharType& outConv, SizeModifier& outSize) { - // added complication: %c should be translated to %s in UTF-8 build - outConv = 's'; - outSize = Size_Default; + // chars are represented using wchar_t in both builds, so this is + // the same as above + outConv = 'c'; + outSize = Size_Long; } }; #endif // wxUSE_UNICODE_UTF8 -#endif // __WINDOWS__/!__WINDOWS__ - #if !wxUSE_UNICODE // FIXME-UTF8: remove class wxPrintfFormatConverterANSI : public wxFormatConverterBase { @@ -517,7 +533,7 @@ class wxScanfFormatConverterWchar : public wxFormatConverterBase } }; -const wxWCharBuffer wxScanfConvertFormatW(const wchar_t *format) +const wxScopedWCharBuffer wxScanfConvertFormatW(const wchar_t *format) { return wxScanfFormatConverterWchar().Convert(format); } @@ -607,3 +623,107 @@ const wchar_t* wxFormatString::AsWChar() return m_convertedWChar.data(); } #endif // wxUSE_UNICODE && !wxUSE_UTF8_LOCALE_ONLY + +wxString wxFormatString::InputAsString() const +{ + if ( m_str ) + return *m_str; + if ( m_cstr ) + return m_cstr->AsString(); + if ( m_wchar ) + return wxString(m_wchar); + if ( m_char ) + return wxString(m_char); + + wxFAIL_MSG( "invalid wxFormatString - not initialized?" ); + return wxString(); +} + +// ---------------------------------------------------------------------------- +// wxFormatString::GetArgumentType() +// ---------------------------------------------------------------------------- + +namespace +{ + +template +wxFormatString::ArgumentType DoGetArgumentType(const CharType *format, + unsigned n) +{ + wxCHECK_MSG( format, wxFormatString::Arg_Unknown, + "empty format string not allowed here" ); + + wxPrintfConvSpecParser parser(format); + + wxCHECK_MSG( n <= parser.nargs, wxFormatString::Arg_Unknown, + "more arguments than format string specifiers?" ); + + wxCHECK_MSG( parser.pspec[n-1] != NULL, wxFormatString::Arg_Unknown, + "requested argument not found - invalid format string?" ); + + switch ( parser.pspec[n-1]->m_type ) + { + case wxPAT_CHAR: + case wxPAT_WCHAR: + return wxFormatString::Arg_Char; + + case wxPAT_PCHAR: + case wxPAT_PWCHAR: + return wxFormatString::Arg_String; + + case wxPAT_INT: + return wxFormatString::Arg_Int; + case wxPAT_LONGINT: + return wxFormatString::Arg_LongInt; +#ifdef wxLongLong_t + case wxPAT_LONGLONGINT: + return wxFormatString::Arg_LongLongInt; +#endif + case wxPAT_SIZET: + return wxFormatString::Arg_Size_t; + + case wxPAT_DOUBLE: + return wxFormatString::Arg_Double; + case wxPAT_LONGDOUBLE: + return wxFormatString::Arg_LongDouble; + + case wxPAT_POINTER: + return wxFormatString::Arg_Pointer; + + case wxPAT_NINT: + return wxFormatString::Arg_IntPtr; + case wxPAT_NSHORTINT: + return wxFormatString::Arg_ShortIntPtr; + case wxPAT_NLONGINT: + return wxFormatString::Arg_LongIntPtr; + + case wxPAT_STAR: + // "*" requires argument of type int + return wxFormatString::Arg_Int; + + case wxPAT_INVALID: + // (handled after the switch statement) + break; + } + + // silence warning + wxFAIL_MSG( "unexpected argument type" ); + return wxFormatString::Arg_Unknown; +} + +} // anonymous namespace + +wxFormatString::ArgumentType wxFormatString::GetArgumentType(unsigned n) const +{ + if ( m_char ) + return DoGetArgumentType(m_char.data(), n); + else if ( m_wchar ) + return DoGetArgumentType(m_wchar.data(), n); + else if ( m_str ) + return DoGetArgumentType(m_str->wx_str(), n); + else if ( m_cstr ) + return DoGetArgumentType(m_cstr->AsInternal(), n); + + wxFAIL_MSG( "unreachable code" ); + return Arg_Unknown; +}