// Purpose: macros for implementing type-safe vararg passing of strings
// Author: Vaclav Slavik
// Created: 2007-02-19
-// RCS-ID: $Id$
// Copyright: (c) 2007 REA Elektronik GmbH
// Licence: wxWindows licence
///////////////////////////////////////////////////////////////////////////////
#include "wx/strvararg.h"
#include "wx/string.h"
#include "wx/crt.h"
+#include "wx/private/wxprintf.h"
// ============================================================================
// implementation
}
#if wxUSE_UNICODE_UTF8 && !wxUSE_UTF8_LOCALE_ONLY
-wxArgNormalizerWchar<const wxString&>::wxArgNormalizerWchar(const wxString& s)
- : wxArgNormalizerWithBuffer<wchar_t>(s.wc_str())
+wxArgNormalizerWchar<const wxString&>::wxArgNormalizerWchar(
+ const wxString& s,
+ const wxFormatString *fmt, unsigned index)
+ : wxArgNormalizerWithBuffer<wchar_t>(s.wc_str(), fmt, index)
{
}
-wxArgNormalizerWchar<const wxCStrData&>::wxArgNormalizerWchar(const wxCStrData& s)
- : wxArgNormalizerWithBuffer<wchar_t>(s.AsWCharBuf())
+wxArgNormalizerWchar<const wxCStrData&>::wxArgNormalizerWchar(
+ const wxCStrData& s,
+ const wxFormatString *fmt, unsigned index)
+ : wxArgNormalizerWithBuffer<wchar_t>(s.AsWCharBuf(), fmt, index)
{
}
#endif // wxUSE_UNICODE_UTF8 && !wxUSE_UTF8_LOCALE_ONLY
return wxEmptyString;
#if wxUSE_UTF8_LOCALE_ONLY
- return wxString(wx_reinterpret_cast(const char*, m_ptr));
+ return wxString(reinterpret_cast<const char*>(m_ptr));
#else
#if wxUSE_UNICODE_UTF8
if ( wxLocaleIsUtf8 )
- return wxString(wx_reinterpret_cast(const char*, m_ptr));
+ return wxString(reinterpret_cast<const char*>(m_ptr));
else
#endif
- return wxString(wx_reinterpret_cast(const wxChar*, m_ptr));
+ return wxString(reinterpret_cast<const wxChar*>(m_ptr));
#endif // !wxUSE_UTF8_LOCALE_ONLY
}
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
m_nCopied = 0;
}
- wxCharTypeBuffer<CharType> Convert(const CharType *format)
+ wxScopedCharTypeBuffer<CharType> 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);
// 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<T>, 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;
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:
// format
if ( m_fmtOrig )
{
- return wxCharTypeBuffer<CharType>::CreateNonOwned(m_fmtOrig);
+ return wxScopedCharTypeBuffer<CharType>::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;
}
}
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)++);
}
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<wchar_t>
};
#endif // !wxUSE_UTF8_LOCALE_ONLY
+#endif // __WINDOWS__/!__WINDOWS__
+
#if wxUSE_UNICODE_UTF8
class wxPrintfFormatConverterUtf8 : public wxFormatConverterBase<char>
{
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<char>
{
}
};
-const wxWCharBuffer wxScanfConvertFormatW(const wchar_t *format)
+const wxScopedWCharBuffer wxScanfConvertFormatW(const wchar_t *format)
{
return wxScanfFormatConverterWchar().Convert(format);
}
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<typename CharType>
+wxFormatString::ArgumentType DoGetArgumentType(const CharType *format,
+ unsigned n)
+{
+ wxCHECK_MSG( format, wxFormatString::Arg_Unknown,
+ "empty format string not allowed here" );
+
+ wxPrintfConvSpecParser<CharType> 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;
+}