/////////////////////////////////////////////////////////////////////////////
// Name: src/common/wxchar.cpp
// Purpose: wxChar implementation
-// Author: Ove Kåven
-// Modified by: Ron Lee
+// Author: Ove Kaven
+// Modified by: Ron Lee, Francesco Montorsi
// Created: 09/04/99
// RCS-ID: $Id$
// Copyright: (c) wxWidgets copyright
#define wxMAX_SVNPRINTF_ARGUMENTS 64
#define wxMAX_SVNPRINTF_FLAGBUFFER_LEN 32
-// the conversion specifiers accepted by wxMyPosVsnprintf_
+// the conversion specifiers accepted by wxVsnprintf_
enum wxPrintfArgType {
wxPAT_INVALID = -1,
wxPAT_NLONGINT // %ln
};
-// an argument passed to wxMyPosVsnprintf_
+// an argument passed to wxVsnprintf_
typedef union {
int pad_int; // %d, %i, %o, %u, %x, %X
long int pad_longint; // %ld, etc
// Contains parsed data relative to a conversion specifier given to
-// wxMyPosVsnprintf_ and parsed from the format string
+// wxVsnprintf_ 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...
class wxPrintfConvSpec
// a little buffer where formatting flags like #+\.hlqLZ are stored by Parse()
// for use in Process()
+ // NB: this buffer can be safely a char buffer instead of a wchar_t buffer
+ // since it's used only for numeric conversion specifier and always
+ // with sprintf().
char 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, wxMyPosVsnprintf_
+ // automatically and we don't want this: to be optimized, wxVsnprintf_
// calls this function only on really-used instances of this class.
void Init();
adj_left = false;
argpos = argend = NULL;
type = wxPAT_INVALID;
- szFlags[0] = wxT('%');
+
+ // this character will never be removed from szFlags array and
+ // is important when calling sprintf() in wxPrintfConvSpec::Process() !
+ szFlags[0] = '%';
}
bool wxPrintfConvSpec::Parse(const wxChar *format)
#define CHECK_PREC \
if (in_prec && !prec_dot) \
{ \
- szFlags[flagofs++] = '.'; \
+ szFlags[flagofs++] = (char)'.'; \
prec_dot = true; \
}
case wxT('+'):
case wxT('\''):
CHECK_PREC
- szFlags[flagofs++] = ch;
+ szFlags[flagofs++] = (char)ch;
break;
case wxT('-'):
CHECK_PREC
adj_left = true;
- szFlags[flagofs++] = ch;
+ szFlags[flagofs++] = (char)ch;
break;
case wxT('.'):
case wxT('h'):
ilen = -1;
CHECK_PREC
- szFlags[flagofs++] = ch;
+ szFlags[flagofs++] = (char)ch;
break;
case wxT('l'):
ilen = 1;
CHECK_PREC
- szFlags[flagofs++] = ch;
+ szFlags[flagofs++] = (char)ch;
break;
case wxT('q'):
case wxT('L'):
ilen = 2;
CHECK_PREC
- szFlags[flagofs++] = ch;
+ szFlags[flagofs++] = (char)ch;
break;
case wxT('Z'):
ilen = 3;
CHECK_PREC
- szFlags[flagofs++] = ch;
+ szFlags[flagofs++] = (char)ch;
break;
case wxT('*'):
// save the * in our formatting buffer...
// will be replaced later by Process()
- szFlags[flagofs++] = ch;
+ szFlags[flagofs++] = (char)ch;
break;
case wxT('1'): case wxT('2'): case wxT('3'):
while ( (*argend >= wxT('0')) &&
(*argend <= wxT('9')) )
{
- szFlags[flagofs++] = *argend;
+ szFlags[flagofs++] = (char)(*argend);
len = len*10 + (*argend - wxT('0'));
argend++;
}
case wxT('x'):
case wxT('X'):
CHECK_PREC
- szFlags[flagofs++] = ch;
- szFlags[flagofs] = '\0';
+ szFlags[flagofs++] = (char)ch;
+ szFlags[flagofs] = (char)'\0';
if (ilen == 0)
type = wxPAT_INT;
else if (ilen == -1)
case wxT('g'):
case wxT('G'):
CHECK_PREC
- szFlags[flagofs++] = ch;
- szFlags[flagofs] = '\0';
+ szFlags[flagofs++] = (char)ch;
+ szFlags[flagofs] = (char)'\0';
if (ilen == 2)
type = wxPAT_LONGDOUBLE;
else
break;
case wxPAT_CHAR:
- p->pad_char = va_arg(argptr, int); // char is promoted to int when passed through '...'
+ p->pad_char = (char)va_arg(argptr, int); // char is promoted to int when passed through '...'
break;
case wxPAT_WCHAR:
- p->pad_wchar = va_arg(argptr, int); // char is promoted to int when passed through '...'
+ p->pad_wchar = (wchar_t)va_arg(argptr, int); // char is promoted to int when passed through '...'
break;
case wxPAT_PCHAR:
break;
case wxPAT_NSHORTINT:
- *p->pad_nshortint = lenCur;
+ *p->pad_nshortint = (short int)lenCur;
break;
case wxPAT_NLONGINT:
return lenCur;
}
+// differences from standard strncpy:
+// 1) copies everything from 'source' except for '%%' sequence which is copied as '%'
+// 2) returns the number of written characters in 'dest' as it could differ from given 'n'
+// 3) much less optimized, unfortunately...
+static int wxCopyStrWithPercents(wxChar *dest, const wxChar *source, size_t n)
+{
+ size_t written = 0;
+
+ if (n == 0)
+ return 0;
+
+ size_t i;
+ for ( i = 0; i < n-1; source++, i++)
+ {
+ dest[written++] = *source;
+ if (*(source+1) == wxT('%'))
+ {
+ // skip this additional '%' character
+ source++;
+ i++;
+ }
+ }
+
+ if (i < n)
+ // copy last character inconditionally
+ dest[written++] = *source;
+
+ return written;
+}
+
int WXDLLEXPORT wxVsnprintf_(wxChar *buf, size_t lenMax,
const wxChar *format, va_list argptr)
{
return -1; // format strings with both positional and
// non-positional conversion specifier are unsupported !!
+ // on platforms where va_list is an array type, it is necessary to make a
+ // copy to be able to pass it to LoadArg as a reference.
+ bool ok = true;
+ va_list ap;
+ wxVaCopy(ap, argptr);
+
// now load arguments from stack
- for (i=0; i < nargs; i++) {
- if (!pspec[i])
- return -1; // user forgot a positional parameter (e.g. %$1s %$3s) ?
- if (!pspec[i]->LoadArg(&argdata[i], argptr))
- return -1; // this means that wxPrintfConvSpec::Parse failed
- // to set its 'type' to a valid value...
+ for (i=0; i < nargs && ok; i++) {
+ // !pspec[i] if user forgot a positional parameter (e.g. %$1s %$3s) ?
+ // or LoadArg false if wxPrintfConvSpec::Parse failed to set its 'type'
+ // to a valid value...
+ ok = pspec[i] && pspec[i]->LoadArg(&argdata[i], ap);
}
+ va_end(ap);
+
+ // something failed while loading arguments from the variable list...
+ if (!ok)
+ return -1;
+
// finally, process each conversion specifier with its own argument
toparse = format;
for (i=0; i < nargs; i++)
if (lenCur+tocopy >= lenMax)
return -1; // not enough space in the output buffer !
- wxStrncpy(buf+lenCur, toparse, tocopy);
- lenCur += tocopy;
+ lenCur += wxCopyStrWithPercents(buf+lenCur, toparse, tocopy);
// process this specifier directly in the output buffer
int n = arg[i].Process(buf+lenCur, lenMax - lenCur, &argdata[arg[i].pos]);
size_t tocopy = wxStrlen(format) + 1 - ( toparse - format ) ;
if (lenCur+tocopy >= lenMax)
return -1; // not enough space in the output buffer !
- wxStrncpy(buf+lenCur, toparse, tocopy);
- lenCur += tocopy - 1; // the -1 is because of the '\0'
+
+ // the -1 is because of the '\0'
+ lenCur += wxCopyStrWithPercents(buf+lenCur, toparse, tocopy) - 1;
// clean the static array portion used...
// NOTE: other arrays do not need cleanup!