#pragma hdrstop
#endif
-#include "wx/wxchar.h"
+#include "wx/crt.h"
#include <string.h>
// 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
// ----------------------------------------------------------------------------
// (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
#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,
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
long int *pad_nlongint; // %ln
} wxPrintfArg;
+// helper for converting string into either char* or wchar_t* dependening
+// on the type of wxPrintfConvSpec<T> instantiation:
+template<typename CharType> struct wxPrintfStringHelper {};
+
+template<> struct wxPrintfStringHelper<char>
+{
+ typedef const wxWX2MBbuf ConvertedType;
+ static ConvertedType Convert(const wxString& s) { return s.mb_str(); }
+};
+
+template<> struct wxPrintfStringHelper<wchar_t>
+{
+ 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<typename CharType>
class wxPrintfConvSpec
{
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];
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);
void ReplaceAsteriskWith(int w);
};
-void wxPrintfConvSpec::Init()
+template<typename CharType>
+void wxPrintfConvSpec<CharType>::Init()
{
m_nMinWidth = 0;
m_nMaxWidth = 0xFFFF;
m_szFlags[0] = '%';
}
-bool wxPrintfConvSpec::Parse(const wxChar *format)
+template<typename CharType>
+bool wxPrintfConvSpec<CharType>::Parse(const CharType *format)
{
bool done = false;
}
// what follows '%'?
- const wxChar ch = *(++m_pArgEnd);
+ const CharType ch = *(++m_pArgEnd);
switch ( ch )
{
case wxT('\0'):
{
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'));
return true; // parsing was successful
}
-
-void wxPrintfConvSpec::ReplaceAsteriskWith(int width)
+template<typename CharType>
+void wxPrintfConvSpec<CharType>::ReplaceAsteriskWith(int width)
{
char temp[wxMAX_SVNPRINTF_FLAGBUFFER_LEN];
strcpy(pwidth+offset, temp);
}
-bool wxPrintfConvSpec::LoadArg(wxPrintfArg *p, va_list &argptr)
+template<typename CharType>
+bool wxPrintfConvSpec<CharType>::LoadArg(wxPrintfArg *p, va_list &argptr)
{
// did the '*' width/precision specifier was used ?
if (m_nMaxWidth == -1)
return true; // loading was successful
}
-int wxPrintfConvSpec::Process(wxChar *buf, size_t lenMax, wxPrintfArg *p, size_t written)
+template<typename CharType>
+int wxPrintfConvSpec<CharType>::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,
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;
if ( !arg.IsValid() && m_nMaxWidth >= 6 )
s = wxT("(null)");
+ typename wxPrintfStringHelper<CharType>::ConvertedType strbuf(
+ wxPrintfStringHelper<CharType>::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;
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)
{
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:
// 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<typename CharType>
static int wxCopyStrWithPercents(
size_t maxOut,
- wxChar *dest,
+ CharType *dest,
size_t maxIn,
- const wxChar *source)
+ const CharType *source)
{
size_t written = 0;
return written;
}
-int WXDLLEXPORT wxVsnprintf_(wxChar *buf, size_t lenMax,
- const wxChar *format, va_list argptr)
+template<typename CharType>
+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<CharType> arg[wxMAX_SVNPRINTF_ARGUMENTS];
wxPrintfArg argdata[wxMAX_SVNPRINTF_ARGUMENTS];
- wxPrintfConvSpec *pspec[wxMAX_SVNPRINTF_ARGUMENTS] = { NULL };
+ wxPrintfConvSpec<CharType> *pspec[wxMAX_SVNPRINTF_ARGUMENTS] = { NULL };
size_t i;
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;
if (arg[nargs].Parse(toparse))
{
// ...yes it is
- wxPrintfConvSpec *current = &arg[nargs];
+ wxPrintfConvSpec<CharType> *current = &arg[nargs];
// make toparse point to the end of this specifier
toparse = current->m_pArgEnd;
#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