+/* safe version of strlen() (returns 0 if passed NULL pointer) */
+// NB: these are defined in wxcrtbase.h, see the comment there
+// inline size_t wxStrlen(const char *s) { return s ? strlen(s) : 0; }
+// inline size_t wxStrlen(const wchar_t *s) { return s ? wxCRT_Strlen_(s) : 0; }
+inline size_t wxStrlen(const wxCharBuffer& s) { return wxStrlen(s.data()); }
+inline size_t wxStrlen(const wxWCharBuffer& s) { return wxStrlen(s.data()); }
+inline size_t wxStrlen(const wxString& s) { return s.length(); }
+inline size_t wxStrlen(const wxCStrData& s) { return s.AsString().length(); }
+
+// NB: these are defined in wxcrtbase.h, see the comment there
+// inline char* wxStrdup(const char *s) { return wxStrdupA(s); }
+// inline wchar_t* wxStrdup(const wchar_t *s) { return wxStrdupW(s); }
+inline char* wxStrdup(const wxCharBuffer& s) { return wxStrdup(s.data()); }
+inline wchar_t* wxStrdup(const wxWCharBuffer& s) { return wxStrdup(s.data()); }
+inline char* wxStrdup(const wxString& s) { return wxStrdup(s.mb_str()); }
+inline char* wxStrdup(const wxCStrData& s) { return wxStrdup(s.AsCharBuf()); }
+
+inline char *wxStrcpy(char *dest, const char *src)
+ { return wxCRT_StrcpyA(dest, src); }
+inline wchar_t *wxStrcpy(wchar_t *dest, const wchar_t *src)
+ { return wxCRT_StrcpyW(dest, src); }
+inline char *wxStrcpy(char *dest, const wxString& src)
+ { return wxCRT_StrcpyA(dest, src.mb_str()); }
+inline char *wxStrcpy(char *dest, const wxCStrData& src)
+ { return wxCRT_StrcpyA(dest, src.AsCharBuf()); }
+inline char *wxStrcpy(char *dest, const wxCharBuffer& src)
+ { return wxCRT_StrcpyA(dest, src.data()); }
+inline wchar_t *wxStrcpy(wchar_t *dest, const wxString& src)
+ { return wxCRT_StrcpyW(dest, src.wc_str()); }
+inline wchar_t *wxStrcpy(wchar_t *dest, const wxCStrData& src)
+ { return wxCRT_StrcpyW(dest, src.AsWCharBuf()); }
+inline wchar_t *wxStrcpy(wchar_t *dest, const wxWCharBuffer& src)
+ { return wxCRT_StrcpyW(dest, src.data()); }
+inline char *wxStrcpy(char *dest, const wchar_t *src)
+ { return wxCRT_StrcpyA(dest, wxConvLibc.cWC2MB(src)); }
+inline wchar_t *wxStrcpy(wchar_t *dest, const char *src)
+ { return wxCRT_StrcpyW(dest, wxConvLibc.cMB2WC(src)); }
+
+inline char *wxStrncpy(char *dest, const char *src, size_t n)
+ { return wxCRT_StrncpyA(dest, src, n); }
+inline wchar_t *wxStrncpy(wchar_t *dest, const wchar_t *src, size_t n)
+ { return wxCRT_StrncpyW(dest, src, n); }
+inline char *wxStrncpy(char *dest, const wxString& src, size_t n)
+ { return wxCRT_StrncpyA(dest, src.mb_str(), n); }
+inline char *wxStrncpy(char *dest, const wxCStrData& src, size_t n)
+ { return wxCRT_StrncpyA(dest, src.AsCharBuf(), n); }
+inline char *wxStrncpy(char *dest, const wxCharBuffer& src, size_t n)
+ { return wxCRT_StrncpyA(dest, src.data(), n); }
+inline wchar_t *wxStrncpy(wchar_t *dest, const wxString& src, size_t n)
+ { return wxCRT_StrncpyW(dest, src.wc_str(), n); }
+inline wchar_t *wxStrncpy(wchar_t *dest, const wxCStrData& src, size_t n)
+ { return wxCRT_StrncpyW(dest, src.AsWCharBuf(), n); }
+inline wchar_t *wxStrncpy(wchar_t *dest, const wxWCharBuffer& src, size_t n)
+ { return wxCRT_StrncpyW(dest, src.data(), n); }
+inline char *wxStrncpy(char *dest, const wchar_t *src, size_t n)
+ { return wxCRT_StrncpyA(dest, wxConvLibc.cWC2MB(src), n); }
+inline wchar_t *wxStrncpy(wchar_t *dest, const char *src, size_t n)
+ { return wxCRT_StrncpyW(dest, wxConvLibc.cMB2WC(src), n); }
+
+inline char *wxStrcat(char *dest, const char *src)
+ { return wxCRT_StrcatA(dest, src); }
+inline wchar_t *wxStrcat(wchar_t *dest, const wchar_t *src)
+ { return wxCRT_StrcatW(dest, src); }
+inline char *wxStrcat(char *dest, const wxString& src)
+ { return wxCRT_StrcatA(dest, src.mb_str()); }
+inline char *wxStrcat(char *dest, const wxCStrData& src)
+ { return wxCRT_StrcatA(dest, src.AsCharBuf()); }
+inline char *wxStrcat(char *dest, const wxCharBuffer& src)
+ { return wxCRT_StrcatA(dest, src.data()); }
+inline wchar_t *wxStrcat(wchar_t *dest, const wxString& src)
+ { return wxCRT_StrcatW(dest, src.wc_str()); }
+inline wchar_t *wxStrcat(wchar_t *dest, const wxCStrData& src)
+ { return wxCRT_StrcatW(dest, src.AsWCharBuf()); }
+inline wchar_t *wxStrcat(wchar_t *dest, const wxWCharBuffer& src)
+ { return wxCRT_StrcatW(dest, src.data()); }
+inline char *wxStrcat(char *dest, const wchar_t *src)
+ { return wxCRT_StrcatA(dest, wxConvLibc.cWC2MB(src)); }
+inline wchar_t *wxStrcat(wchar_t *dest, const char *src)
+ { return wxCRT_StrcatW(dest, wxConvLibc.cMB2WC(src)); }
+
+inline char *wxStrncat(char *dest, const char *src, size_t n)
+ { return wxCRT_StrncatA(dest, src, n); }
+inline wchar_t *wxStrncat(wchar_t *dest, const wchar_t *src, size_t n)
+ { return wxCRT_StrncatW(dest, src, n); }
+inline char *wxStrncat(char *dest, const wxString& src, size_t n)
+ { return wxCRT_StrncatA(dest, src.mb_str(), n); }
+inline char *wxStrncat(char *dest, const wxCStrData& src, size_t n)
+ { return wxCRT_StrncatA(dest, src.AsCharBuf(), n); }
+inline char *wxStrncat(char *dest, const wxCharBuffer& src, size_t n)
+ { return wxCRT_StrncatA(dest, src.data(), n); }
+inline wchar_t *wxStrncat(wchar_t *dest, const wxString& src, size_t n)
+ { return wxCRT_StrncatW(dest, src.wc_str(), n); }
+inline wchar_t *wxStrncat(wchar_t *dest, const wxCStrData& src, size_t n)
+ { return wxCRT_StrncatW(dest, src.AsWCharBuf(), n); }
+inline wchar_t *wxStrncat(wchar_t *dest, const wxWCharBuffer& src, size_t n)
+ { return wxCRT_StrncatW(dest, src.data(), n); }
+inline char *wxStrncat(char *dest, const wchar_t *src, size_t n)
+ { return wxCRT_StrncatA(dest, wxConvLibc.cWC2MB(src), n); }
+inline wchar_t *wxStrncat(wchar_t *dest, const char *src, size_t n)
+ { return wxCRT_StrncatW(dest, wxConvLibc.cMB2WC(src), n); }
+
+
+#define WX_STR_DECL(name, T1, T2) name(T1 s1, T2 s2)
+#define WX_STR_CALL(func, a1, a2) func(a1, a2)
+
+// This macro defines string function for all possible variants of arguments,
+// except for those taking wxString or wxCStrData as second argument.
+// Parameters:
+// rettype - return type
+// name - name of the (overloaded) function to define
+// crtA - function to call for char* versions (takes two arguments)
+// crtW - ditto for wchar_t* function
+// forString - function to call when the *first* argument is wxString;
+// the second argument can be any string type, so this is
+// typically a template
+#define WX_STR_FUNC_NO_INVERT(rettype, name, crtA, crtW, forString) \
+ inline rettype WX_STR_DECL(name, const char *, const char *) \
+ { return WX_STR_CALL(crtA, s1, s2); } \
+ inline rettype WX_STR_DECL(name, const char *, const wchar_t *) \
+ { return WX_STR_CALL(forString, wxString(s1), wxString(s2)); } \
+ inline rettype WX_STR_DECL(name, const char *, const wxCharBuffer&) \
+ { return WX_STR_CALL(crtA, s1, s2.data()); } \
+ inline rettype WX_STR_DECL(name, const char *, const wxWCharBuffer&) \
+ { return WX_STR_CALL(forString, wxString(s1), s2.data()); } \
+ \
+ inline rettype WX_STR_DECL(name, const wchar_t *, const wchar_t *) \
+ { return WX_STR_CALL(crtW, s1, s2); } \
+ inline rettype WX_STR_DECL(name, const wchar_t *, const char *) \
+ { return WX_STR_CALL(forString, wxString(s1), wxString(s2)); } \
+ inline rettype WX_STR_DECL(name, const wchar_t *, const wxWCharBuffer&) \
+ { return WX_STR_CALL(crtW, s1, s2.data()); } \
+ inline rettype WX_STR_DECL(name, const wchar_t *, const wxCharBuffer&) \
+ { return WX_STR_CALL(forString, wxString(s1), s2.data()); } \
+ \
+ inline rettype WX_STR_DECL(name, const wxCharBuffer&, const char *) \
+ { return WX_STR_CALL(crtA, s1.data(), s2); } \
+ inline rettype WX_STR_DECL(name, const wxCharBuffer&, const wchar_t *) \
+ { return WX_STR_CALL(forString, wxString(s1), wxString(s2)); } \
+ inline rettype WX_STR_DECL(name, const wxCharBuffer&, const wxCharBuffer&)\
+ { return WX_STR_CALL(crtA, s1.data(), s2.data()); } \
+ inline int WX_STR_DECL(name, const wxCharBuffer&, const wxWCharBuffer&) \
+ { return WX_STR_CALL(forString, wxString(s1), wxString(s2)); } \
+ \
+ inline rettype WX_STR_DECL(name, const wxWCharBuffer&, const wchar_t *) \
+ { return WX_STR_CALL(crtW, s1.data(), s2); } \
+ inline rettype WX_STR_DECL(name, const wxWCharBuffer&, const char *) \
+ { return WX_STR_CALL(forString, wxString(s1), wxString(s2)); } \
+ inline int WX_STR_DECL(name, const wxWCharBuffer&, const wxWCharBuffer&) \
+ { return WX_STR_CALL(crtW, s1.data(), s2.data()); } \
+ inline int WX_STR_DECL(name, const wxWCharBuffer&, const wxCharBuffer&) \
+ { return WX_STR_CALL(forString, wxString(s1), wxString(s2)); } \
+ \
+ inline rettype WX_STR_DECL(name, const wxString&, const char*) \
+ { return WX_STR_CALL(forString, s1, s2); } \
+ inline rettype WX_STR_DECL(name, const wxString&, const wchar_t*) \
+ { return WX_STR_CALL(forString, s1, s2); } \
+ inline rettype WX_STR_DECL(name, const wxString&, const wxCharBuffer&) \
+ { return WX_STR_CALL(forString, s1, s2); } \
+ inline rettype WX_STR_DECL(name, const wxString&, const wxWCharBuffer&) \
+ { return WX_STR_CALL(forString, s1, s2); } \
+ inline rettype WX_STR_DECL(name, const wxString&, const wxString&) \
+ { return WX_STR_CALL(forString, s1, s2); } \
+ inline rettype WX_STR_DECL(name, const wxString&, const wxCStrData&) \
+ { return WX_STR_CALL(forString, s1, s2); } \
+ \
+ inline rettype WX_STR_DECL(name, const wxCStrData&, const char*) \
+ { return WX_STR_CALL(forString, s1.AsString(), s2); } \
+ inline rettype WX_STR_DECL(name, const wxCStrData&, const wchar_t*) \
+ { return WX_STR_CALL(forString, s1.AsString(), s2); } \
+ inline rettype WX_STR_DECL(name, const wxCStrData&, const wxCharBuffer&) \
+ { return WX_STR_CALL(forString, s1.AsString(), s2); } \
+ inline rettype WX_STR_DECL(name, const wxCStrData&, const wxWCharBuffer&) \
+ { return WX_STR_CALL(forString, s1.AsString(), s2); } \
+ inline rettype WX_STR_DECL(name, const wxCStrData&, const wxString&) \
+ { return WX_STR_CALL(forString, s1.AsString(), s2); } \
+ inline rettype WX_STR_DECL(name, const wxCStrData&, const wxCStrData&) \
+ { return WX_STR_CALL(forString, s1.AsString(), s2); }
+
+// This defines strcmp-like function, i.e. one returning the result of
+// comparison; see WX_STR_FUNC_NO_INVERT for explanation of the arguments
+#define WX_STRCMP_FUNC(name, crtA, crtW, forString) \
+ WX_STR_FUNC_NO_INVERT(int, name, crtA, crtW, forString) \
+ \
+ inline int WX_STR_DECL(name, const char *, const wxCStrData&) \
+ { return -WX_STR_CALL(forString, s2.AsString(), s1); } \
+ inline int WX_STR_DECL(name, const char *, const wxString&) \
+ { return -WX_STR_CALL(forString, s2, s1); } \
+ \
+ inline int WX_STR_DECL(name, const wchar_t *, const wxCStrData&) \
+ { return -WX_STR_CALL(forString, s2.AsString(), s1); } \
+ inline int WX_STR_DECL(name, const wchar_t *, const wxString&) \
+ { return -WX_STR_CALL(forString, s2, s1); } \
+ \
+ inline int WX_STR_DECL(name, const wxCharBuffer&, const wxCStrData&) \
+ { return -WX_STR_CALL(forString, s2.AsString(), s1.data()); } \
+ inline int WX_STR_DECL(name, const wxCharBuffer&, const wxString&) \
+ { return -WX_STR_CALL(forString, s2, s1.data()); } \
+ \
+ inline int WX_STR_DECL(name, const wxWCharBuffer&, const wxCStrData&) \
+ { return -WX_STR_CALL(forString, s2.AsString(), s1.data()); } \
+ inline int WX_STR_DECL(name, const wxWCharBuffer&, const wxString&) \
+ { return -WX_STR_CALL(forString, s2, s1.data()); }
+
+
+// This defines a string function that is *not* strcmp-like, i.e. doesn't
+// return the result of comparison and so if the second argument is a string,
+// it has to be converted to char* or wchar_t*
+#define WX_STR_FUNC(rettype, name, crtA, crtW, forString) \
+ WX_STR_FUNC_NO_INVERT(rettype, name, crtA, crtW, forString) \
+ \
+ inline rettype WX_STR_DECL(name, const char *, const wxCStrData&) \
+ { return WX_STR_CALL(crtA, s1, s2.AsCharBuf()); } \
+ inline rettype WX_STR_DECL(name, const char *, const wxString&) \
+ { return WX_STR_CALL(crtA, s1, s2.mb_str()); } \
+ \
+ inline rettype WX_STR_DECL(name, const wchar_t *, const wxCStrData&) \
+ { return WX_STR_CALL(crtW, s1, s2.AsWCharBuf()); } \
+ inline rettype WX_STR_DECL(name, const wchar_t *, const wxString&) \
+ { return WX_STR_CALL(crtW, s1, s2.wc_str()); } \
+ \
+ inline rettype WX_STR_DECL(name, const wxCharBuffer&, const wxCStrData&) \
+ { return WX_STR_CALL(crtA, s1.data(), s2.AsCharBuf()); } \
+ inline rettype WX_STR_DECL(name, const wxCharBuffer&, const wxString&) \
+ { return WX_STR_CALL(crtA, s1.data(), s2.mb_str()); } \
+ \
+ inline rettype WX_STR_DECL(name, const wxWCharBuffer&, const wxCStrData&) \
+ { return WX_STR_CALL(crtW, s1.data(), s2.AsWCharBuf()); } \
+ inline rettype WX_STR_DECL(name, const wxWCharBuffer&, const wxString&) \
+ { return WX_STR_CALL(crtW, s1.data(), s2.wc_str()); }
+
+template<typename T>
+inline int wxStrcmp_String(const wxString& s1, const T& s2)
+ { return s1.compare(s2); }
+WX_STRCMP_FUNC(wxStrcmp, wxCRT_StrcmpA, wxCRT_StrcmpW, wxStrcmp_String)
+
+template<typename T>
+inline int wxStricmp_String(const wxString& s1, const T& s2)
+ { return s1.CmpNoCase(s2); }
+WX_STRCMP_FUNC(wxStricmp, wxCRT_StricmpA, wxCRT_StricmpW, wxStricmp_String)
+
+
+// GCC 3.3 and other compilers have a bug that causes it to fail compilation if
+// the template's implementation uses overloaded function declared later (see
+// the wxStrcoll() call in wxStrcoll_String<T>()), so we have to
+// forward-declare the template and implement it below WX_STRCMP_FUNC. OTOH,
+// this fails to compile with VC6, so don't do it for VC.
+#if !defined(__VISUALC__)
+template<typename T>
+inline int wxStrcoll_String(const wxString& s1, const T& s2);
+WX_STRCMP_FUNC(wxStrcoll, wxCRT_StrcollA, wxCRT_StrcollW, wxStrcoll_String)
+#endif // !__VISUALC__
+
+template<typename T>
+inline int wxStrcoll_String(const wxString& s1, const T& s2)
+{
+#if wxUSE_UNICODE
+ // NB: strcoll() doesn't work correctly on UTF-8 strings, so we have to use
+ // wc_str() even if wxUSE_UNICODE_UTF8; the (const wchar_t*) cast is
+ // there just as optimization to avoid going through
+ // wxStrcoll<wxWCharBuffer>:
+ return wxStrcoll((const wchar_t*)s1.wc_str(), s2);
+#else
+ return wxStrcoll((const char*)s1.mb_str(), s2);