]> git.saurik.com Git - wxWidgets.git/blobdiff - include/wx/strvararg.h
support SDK < 10.6, fixes #14902
[wxWidgets.git] / include / wx / strvararg.h
index 29b4ae041bfa3b037ee2e5a99d308fb5715780f1..8f2d16551ecc25c592cd497274ef276b1d149699 100644 (file)
 #include "wx/buffer.h"
 #include "wx/unichar.h"
 
 #include "wx/buffer.h"
 #include "wx/unichar.h"
 
+#if defined(HAVE_TYPE_TRAITS)
+    #include <type_traits>
+#elif defined(HAVE_TR1_TYPE_TRAITS)
+    #ifdef __VISUALC__
+        #include <type_traits>
+    #else
+        #include <tr1/type_traits>
+    #endif
+#endif
+
 class WXDLLIMPEXP_FWD_BASE wxCStrData;
 class WXDLLIMPEXP_FWD_BASE wxString;
 
 class WXDLLIMPEXP_FWD_BASE wxCStrData;
 class WXDLLIMPEXP_FWD_BASE wxString;
 
@@ -140,12 +150,46 @@ public:
     wxFormatString(const wxScopedWCharBuffer& str)
         : m_wchar(str), m_str(NULL), m_cstr(NULL) {}
 
     wxFormatString(const wxScopedWCharBuffer& str)
         : m_wchar(str), m_str(NULL), m_cstr(NULL) {}
 
-
+    // Possible argument types. These are or-combinable for wxASSERT_ARG_TYPE
+    // convenience. Some of the values are or-combined with another value, this
+    // expresses "supertypes" for use with wxASSERT_ARG_TYPE masks. For example,
+    // a char* string is also a pointer and an integer is also a char.
     enum ArgumentType
     {
     enum ArgumentType
     {
-        Arg_Char,    // character as char
+        Arg_Char        = 0x0001,    // character as char %c
+        Arg_Pointer     = 0x0002,    // %p
+        Arg_String      = 0x0004 | Arg_Pointer, // any form of string (%s and %p too)
+
+        Arg_Int         = 0x0008 | Arg_Char, // (ints can be used with %c)
+#if SIZEOF_INT == SIZEOF_LONG
+        Arg_LongInt     = Arg_Int,
+#else
+        Arg_LongInt     = 0x0010,
+#endif
+#if defined(SIZEOF_LONG_LONG) && SIZEOF_LONG_LONG == SIZEOF_LONG
+        Arg_LongLongInt = Arg_LongInt,
+#elif defined(wxLongLong_t)
+        Arg_LongLongInt = 0x0020,
+#endif
+
+        Arg_Double      = 0x0040,
+        Arg_LongDouble  = 0x0080,
+
+#if defined(wxSIZE_T_IS_UINT)
+        Arg_Size_t      = Arg_Int,
+#elif defined(wxSIZE_T_IS_ULONG)
+        Arg_Size_t      = Arg_LongInt,
+#elif defined(SIZEOF_LONG_LONG) && SIZEOF_SIZE_T == SIZEOF_LONG_LONG
+        Arg_Size_t      = Arg_LongLongInt,
+#else
+        Arg_Size_t      = 0x0100,
+#endif
+
+        Arg_IntPtr      = 0x0200,    // %n -- store # of chars written
+        Arg_ShortIntPtr = 0x0400,
+        Arg_LongIntPtr  = 0x0800,
 
 
-        Arg_Other    // something else, for example int for %d
+        Arg_Unknown     = 0x8000     // unrecognized specifier (likely error)
     };
 
     // returns the type of format specifier for n-th variadic argument (this is
     };
 
     // returns the type of format specifier for n-th variadic argument (this is
@@ -163,7 +207,7 @@ public:
         { return const_cast<wxFormatString*>(this)->AsChar(); }
 private:
     // InputAsChar() returns the value passed to ctor, only converted
         { return const_cast<wxFormatString*>(this)->AsChar(); }
 private:
     // InputAsChar() returns the value passed to ctor, only converted
-    // to char, while AsChar() takes the the string returned by InputAsChar()
+    // to char, while AsChar() takes the string returned by InputAsChar()
     // and does format string conversion on it as well (and similarly for
     // ..AsWChar() below)
     const char* InputAsChar();
     // and does format string conversion on it as well (and similarly for
     // ..AsWChar() below)
     const char* InputAsChar();
@@ -260,6 +304,137 @@ struct wxFormatStringArgumentFinder<wxWCharBuffer>
 // wxArgNormalizer*<T> converters
 // ----------------------------------------------------------------------------
 
 // wxArgNormalizer*<T> converters
 // ----------------------------------------------------------------------------
 
+#if wxDEBUG_LEVEL
+    // Check that the format specifier for index-th argument in 'fmt' has
+    // the correct type (one of wxFormatString::Arg_XXX or-combination in
+    // 'expected_mask').
+    #define wxASSERT_ARG_TYPE(fmt, index, expected_mask)                    \
+        wxSTATEMENT_MACRO_BEGIN                                             \
+            if ( !fmt )                                                     \
+                break;                                                      \
+            const int argtype = fmt->GetArgumentType(index);                \
+            wxASSERT_MSG( (argtype & (expected_mask)) == argtype,           \
+                          "format specifier doesn't match argument type" ); \
+        wxSTATEMENT_MACRO_END
+#else
+    // Just define it to suppress "unused parameter" warnings for the
+    // parameters which we don't use otherwise
+    #define wxASSERT_ARG_TYPE(fmt, index, expected_mask)                      \
+        wxUnusedVar(fmt);                                                     \
+        wxUnusedVar(index)
+#endif // wxDEBUG_LEVEL/!wxDEBUG_LEVEL
+
+
+#if defined(HAVE_TYPE_TRAITS) || defined(HAVE_TR1_TYPE_TRAITS)
+
+// Note: this type is misnamed, so that the error message is easier to
+// understand (no error happens for enums, because the IsEnum=true case is
+// specialized).
+template<bool IsEnum>
+struct wxFormatStringSpecifierNonPodType {};
+
+template<>
+struct wxFormatStringSpecifierNonPodType<true>
+{
+    enum { value = wxFormatString::Arg_Int };
+};
+
+template<typename T>
+struct wxFormatStringSpecifier
+{
+#ifdef HAVE_TYPE_TRAITS
+    typedef std::is_enum<T> is_enum;
+#elif defined HAVE_TR1_TYPE_TRAITS
+    typedef std::tr1::is_enum<T> is_enum;
+#endif
+    enum { value = wxFormatStringSpecifierNonPodType<is_enum::value>::value };
+};
+
+#else // !HAVE_(TR1_)TYPE_TRAITS
+
+template<typename T>
+struct wxFormatStringSpecifier
+{
+    // We can't detect enums without is_enum, so the only thing we can
+    // do is to accept unknown types. However, the only acceptable unknown
+    // types still are enums, which are promoted to ints, so return Arg_Int
+    // here. This will at least catch passing of non-POD types through ... at
+    // runtime.
+    //
+    // Furthermore, if the compiler doesn't have partial template
+    // specialization, we didn't cover pointers either.
+#ifdef HAVE_PARTIAL_SPECIALIZATION
+    enum { value = wxFormatString::Arg_Int };
+#else
+    enum { value = wxFormatString::Arg_Int | wxFormatString::Arg_Pointer };
+#endif
+};
+
+#endif // HAVE_TR1_TYPE_TRAITS/!HAVE_TR1_TYPE_TRAITS
+
+
+#ifdef HAVE_PARTIAL_SPECIALIZATION
+template<typename T>
+struct wxFormatStringSpecifier<T*>
+{
+    enum { value = wxFormatString::Arg_Pointer };
+};
+
+template<typename T>
+struct wxFormatStringSpecifier<const T*>
+{
+    enum { value = wxFormatString::Arg_Pointer };
+};
+#endif // !HAVE_PARTIAL_SPECIALIZATION
+
+
+#define wxFORMAT_STRING_SPECIFIER(T, arg)                                   \
+    template<> struct wxFormatStringSpecifier<T>                            \
+    {                                                                       \
+        enum { value = arg };                                               \
+    };
+
+wxFORMAT_STRING_SPECIFIER(bool, wxFormatString::Arg_Int)
+wxFORMAT_STRING_SPECIFIER(int, wxFormatString::Arg_Int)
+wxFORMAT_STRING_SPECIFIER(unsigned int, wxFormatString::Arg_Int)
+wxFORMAT_STRING_SPECIFIER(short int, wxFormatString::Arg_Int)
+wxFORMAT_STRING_SPECIFIER(short unsigned int, wxFormatString::Arg_Int)
+wxFORMAT_STRING_SPECIFIER(long int, wxFormatString::Arg_LongInt)
+wxFORMAT_STRING_SPECIFIER(long unsigned int, wxFormatString::Arg_LongInt)
+#ifdef wxLongLong_t
+wxFORMAT_STRING_SPECIFIER(wxLongLong_t, wxFormatString::Arg_LongLongInt)
+wxFORMAT_STRING_SPECIFIER(wxULongLong_t, wxFormatString::Arg_LongLongInt)
+#endif
+wxFORMAT_STRING_SPECIFIER(float, wxFormatString::Arg_Double)
+wxFORMAT_STRING_SPECIFIER(double, wxFormatString::Arg_Double)
+wxFORMAT_STRING_SPECIFIER(long double, wxFormatString::Arg_LongDouble)
+
+#if wxWCHAR_T_IS_REAL_TYPE
+wxFORMAT_STRING_SPECIFIER(wchar_t, wxFormatString::Arg_Char | wxFormatString::Arg_Int)
+#endif
+
+#if !wxUSE_UNICODE
+wxFORMAT_STRING_SPECIFIER(char, wxFormatString::Arg_Char | wxFormatString::Arg_Int)
+wxFORMAT_STRING_SPECIFIER(signed char, wxFormatString::Arg_Char | wxFormatString::Arg_Int)
+wxFORMAT_STRING_SPECIFIER(unsigned char, wxFormatString::Arg_Char | wxFormatString::Arg_Int)
+#endif
+
+wxFORMAT_STRING_SPECIFIER(char*, wxFormatString::Arg_String)
+wxFORMAT_STRING_SPECIFIER(unsigned char*, wxFormatString::Arg_String)
+wxFORMAT_STRING_SPECIFIER(signed char*, wxFormatString::Arg_String)
+wxFORMAT_STRING_SPECIFIER(const char*, wxFormatString::Arg_String)
+wxFORMAT_STRING_SPECIFIER(const unsigned char*, wxFormatString::Arg_String)
+wxFORMAT_STRING_SPECIFIER(const signed char*, wxFormatString::Arg_String)
+wxFORMAT_STRING_SPECIFIER(wchar_t*, wxFormatString::Arg_String)
+wxFORMAT_STRING_SPECIFIER(const wchar_t*, wxFormatString::Arg_String)
+
+wxFORMAT_STRING_SPECIFIER(int*, wxFormatString::Arg_IntPtr | wxFormatString::Arg_Pointer)
+wxFORMAT_STRING_SPECIFIER(short int*, wxFormatString::Arg_ShortIntPtr | wxFormatString::Arg_Pointer)
+wxFORMAT_STRING_SPECIFIER(long int*, wxFormatString::Arg_LongIntPtr | wxFormatString::Arg_Pointer)
+
+#undef wxFORMAT_STRING_SPECIFIER
+
+
 // Converts an argument passed to wxPrint etc. into standard form expected,
 // by wxXXX functions, e.g. all strings (wxString, char*, wchar_t*) are
 // converted into wchar_t* or char* depending on the build.
 // Converts an argument passed to wxPrint etc. into standard form expected,
 // by wxXXX functions, e.g. all strings (wxString, char*, wchar_t*) are
 // converted into wchar_t* or char* depending on the build.
@@ -271,8 +446,11 @@ struct wxArgNormalizer
     // use format string and 'index' is index of 'value' in variadic arguments
     // list (starting at 1)
     wxArgNormalizer(T value,
     // use format string and 'index' is index of 'value' in variadic arguments
     // list (starting at 1)
     wxArgNormalizer(T value,
-                    const wxFormatString *WXUNUSED(fmt), unsigned WXUNUSED(index))
-        : m_value(value) {}
+                    const wxFormatString *fmt, unsigned index)
+        : m_value(value)
+    {
+        wxASSERT_ARG_TYPE( fmt, index, wxFormatStringSpecifier<T>::value );
+    }
 
     // Returns the value in a form that can be safely passed to real vararg
     // functions. In case of strings, this is char* in ANSI build and wchar_t*
 
     // Returns the value in a form that can be safely passed to real vararg
     // functions. In case of strings, this is char* in ANSI build and wchar_t*
@@ -326,9 +504,12 @@ struct wxArgNormalizerWithBuffer
 
     wxArgNormalizerWithBuffer() {}
     wxArgNormalizerWithBuffer(const CharBuffer& buf,
 
     wxArgNormalizerWithBuffer() {}
     wxArgNormalizerWithBuffer(const CharBuffer& buf,
-                              const wxFormatString *WXUNUSED(fmt),
-                              unsigned WXUNUSED(index))
-        : m_value(buf) {}
+                              const wxFormatString *fmt,
+                              unsigned index)
+        : m_value(buf)
+    {
+        wxASSERT_ARG_TYPE( fmt, index, wxFormatString::Arg_String );
+    }
 
     const CharType *get() const { return m_value; }
 
 
     const CharType *get() const { return m_value; }
 
@@ -340,9 +521,12 @@ template<>
 struct WXDLLIMPEXP_BASE wxArgNormalizerNative<const wxString&>
 {
     wxArgNormalizerNative(const wxString& s,
 struct WXDLLIMPEXP_BASE wxArgNormalizerNative<const wxString&>
 {
     wxArgNormalizerNative(const wxString& s,
-                          const wxFormatString *WXUNUSED(fmt),
-                          unsigned WXUNUSED(index))
-        : m_value(s) {}
+                          const wxFormatString *fmt,
+                          unsigned index)
+        : m_value(s)
+    {
+        wxASSERT_ARG_TYPE( fmt, index, wxFormatString::Arg_String );
+    }
 
     const wxStringCharType *get() const;
 
 
     const wxStringCharType *get() const;
 
@@ -354,9 +538,12 @@ template<>
 struct WXDLLIMPEXP_BASE wxArgNormalizerNative<const wxCStrData&>
 {
     wxArgNormalizerNative(const wxCStrData& value,
 struct WXDLLIMPEXP_BASE wxArgNormalizerNative<const wxCStrData&>
 {
     wxArgNormalizerNative(const wxCStrData& value,
-                          const wxFormatString *WXUNUSED(fmt),
-                          unsigned WXUNUSED(index))
-        : m_value(value) {}
+                          const wxFormatString *fmt,
+                          unsigned index)
+        : m_value(value)
+    {
+        wxASSERT_ARG_TYPE( fmt, index, wxFormatString::Arg_String );
+    }
 
     const wxStringCharType *get() const;
 
 
     const wxStringCharType *get() const;
 
@@ -412,9 +599,11 @@ struct wxArgNormalizerUtf8<const char*>
     : public wxArgNormalizerWithBuffer<char>
 {
     wxArgNormalizerUtf8(const char* s,
     : public wxArgNormalizerWithBuffer<char>
 {
     wxArgNormalizerUtf8(const char* s,
-                        const wxFormatString *WXUNUSED(fmt),
-                        unsigned WXUNUSED(index))
+                        const wxFormatString *fmt,
+                        unsigned index)
     {
     {
+        wxASSERT_ARG_TYPE( fmt, index, wxFormatString::Arg_String );
+
         if ( wxLocaleIsUtf8 )
         {
             m_value = wxScopedCharBuffer::CreateNonOwned(s);
         if ( wxLocaleIsUtf8 )
         {
             m_value = wxScopedCharBuffer::CreateNonOwned(s);
@@ -577,6 +766,9 @@ struct wxArgNormalizerNarrowChar
     wxArgNormalizerNarrowChar(T value,
                               const wxFormatString *fmt, unsigned index)
     {
     wxArgNormalizerNarrowChar(T value,
                               const wxFormatString *fmt, unsigned index)
     {
+        wxASSERT_ARG_TYPE( fmt, index,
+                           wxFormatString::Arg_Char | wxFormatString::Arg_Int );
+
         // FIXME-UTF8: which one is better default in absence of fmt string
         //             (i.e. when used like e.g. Foo("foo", "bar", 'c', NULL)?
         if ( !fmt || fmt->GetArgumentType(index) == wxFormatString::Arg_Char )
         // FIXME-UTF8: which one is better default in absence of fmt string
         //             (i.e. when used like e.g. Foo("foo", "bar", 'c', NULL)?
         if ( !fmt || fmt->GetArgumentType(index) == wxFormatString::Arg_Char )
@@ -607,6 +799,15 @@ struct wxArgNormalizer<unsigned char>
         : wxArgNormalizerNarrowChar<unsigned char>(value, fmt, index) {}
 };
 
         : wxArgNormalizerNarrowChar<unsigned char>(value, fmt, index) {}
 };
 
+template<>
+struct wxArgNormalizer<signed char>
+    : public wxArgNormalizerNarrowChar<signed char>
+{
+    wxArgNormalizer(signed char value,
+                    const wxFormatString *fmt, unsigned index)
+        : wxArgNormalizerNarrowChar<signed char>(value, fmt, index) {}
+};
+
 #endif // wxUSE_UNICODE
 
 // convert references:
 #endif // wxUSE_UNICODE
 
 // convert references:
@@ -617,11 +818,14 @@ WX_ARG_NORMALIZER_FORWARD(const wchar_t&, wchar_t);
 
 WX_ARG_NORMALIZER_FORWARD(const char&, char);
 WX_ARG_NORMALIZER_FORWARD(const unsigned char&, unsigned char);
 
 WX_ARG_NORMALIZER_FORWARD(const char&, char);
 WX_ARG_NORMALIZER_FORWARD(const unsigned char&, unsigned char);
+WX_ARG_NORMALIZER_FORWARD(const signed char&, signed char);
 
 
 #undef WX_ARG_NORMALIZER_FORWARD
 #undef _WX_ARG_NORMALIZER_FORWARD_IMPL
 
 
 
 #undef WX_ARG_NORMALIZER_FORWARD
 #undef _WX_ARG_NORMALIZER_FORWARD_IMPL
 
+// NB: Don't #undef wxASSERT_ARG_TYPE here as it's also used in wx/longlong.h.
+
 // ----------------------------------------------------------------------------
 // WX_VA_ARG_STRING
 // ----------------------------------------------------------------------------
 // ----------------------------------------------------------------------------
 // WX_VA_ARG_STRING
 // ----------------------------------------------------------------------------