X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/7a828c7ffb2e77f6e8c65b3d72f7364826131d1f..83b7b21b1c0579fe210994d030b5b01ff76d7855:/src/common/wxchar.cpp diff --git a/src/common/wxchar.cpp b/src/common/wxchar.cpp index a547a1e201..089d645b82 100644 --- a/src/common/wxchar.cpp +++ b/src/common/wxchar.cpp @@ -1,8 +1,8 @@ ///////////////////////////////////////////////////////////////////////////// // 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 @@ -186,7 +186,7 @@ bool WXDLLEXPORT wxOKlibc() #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, @@ -213,7 +213,7 @@ enum wxPrintfArgType { 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 @@ -240,7 +240,7 @@ typedef union { // 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 @@ -274,13 +274,16 @@ public: // 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(); @@ -310,7 +313,10 @@ void wxPrintfConvSpec::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) @@ -329,7 +335,7 @@ bool wxPrintfConvSpec::Parse(const wxChar *format) #define CHECK_PREC \ if (in_prec && !prec_dot) \ { \ - szFlags[flagofs++] = '.'; \ + szFlags[flagofs++] = (char)'.'; \ prec_dot = true; \ } @@ -349,13 +355,13 @@ bool wxPrintfConvSpec::Parse(const wxChar *format) 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('.'): @@ -370,26 +376,26 @@ bool wxPrintfConvSpec::Parse(const wxChar *format) 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('*'): @@ -410,7 +416,7 @@ bool wxPrintfConvSpec::Parse(const wxChar *format) // 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'): @@ -422,7 +428,7 @@ bool wxPrintfConvSpec::Parse(const wxChar *format) while ( (*argend >= wxT('0')) && (*argend <= wxT('9')) ) { - szFlags[flagofs++] = *argend; + szFlags[flagofs++] = (char)(*argend); len = len*10 + (*argend - wxT('0')); argend++; } @@ -464,8 +470,8 @@ bool wxPrintfConvSpec::Parse(const wxChar *format) 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) @@ -492,8 +498,8 @@ bool wxPrintfConvSpec::Parse(const wxChar *format) 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 @@ -652,10 +658,10 @@ bool wxPrintfConvSpec::LoadArg(wxPrintfArg *p, va_list &argptr) 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: @@ -752,11 +758,13 @@ int wxPrintfConvSpec::Process(wxChar *buf, size_t lenMax, wxPrintfArg *p) #else p->pad_char; +#if wxUSE_WCHAR_T if (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]; } +#endif #endif size_t i; @@ -783,22 +791,26 @@ int wxPrintfConvSpec::Process(wxChar *buf, size_t lenMax, wxPrintfArg *p) if (type == wxPAT_PCHAR) { // user passed a string explicitely indicated as ANSI... - val = wxString(p->pad_pchar, wxConvLibc); + val = s = wxString(p->pad_pchar, wxConvLibc); } #else p->pad_pchar; +#if wxUSE_WCHAR_T if (type == wxPAT_PWCHAR) { // user passed a string explicitely indicated as Unicode... - val = wxString(p->pad_pwchar, wxConvLibc); + val = s = wxString(p->pad_pwchar, wxConvLibc); } +#endif #endif int len; if (val) { #if wxUSE_STRUTILS - len = wxMin(max_width, wxStrlen(val)); + // at this point we are sure that max_width is positive or null + // (see top of wxPrintfConvSpec::LoadArg) + len = wxMin((unsigned int)max_width, wxStrlen(val)); #else for ( len = 0; val[len] && (len < max_width); len++ ) ; @@ -824,7 +836,9 @@ int wxPrintfConvSpec::Process(wxChar *buf, size_t lenMax, wxPrintfArg *p) } #if wxUSE_STRUTILS - len = wxMin(len, lenMax-lenCur); + // at this point we are sure that max_width is positive or null + // (see top of wxPrintfConvSpec::LoadArg) + len = wxMin((unsigned int)len, lenMax-lenCur); wxStrncpy(buf+lenCur, val, len); lenCur += len; #else @@ -845,7 +859,7 @@ int wxPrintfConvSpec::Process(wxChar *buf, size_t lenMax, wxPrintfArg *p) break; case wxPAT_NSHORTINT: - *p->pad_nshortint = lenCur; + *p->pad_nshortint = (short int)lenCur; break; case wxPAT_NLONGINT: @@ -893,6 +907,36 @@ int wxPrintfConvSpec::Process(wxChar *buf, size_t lenMax, wxPrintfArg *p) 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) { @@ -950,15 +994,26 @@ int WXDLLEXPORT wxVsnprintf_(wxChar *buf, size_t lenMax, 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++) @@ -969,8 +1024,7 @@ int WXDLLEXPORT wxVsnprintf_(wxChar *buf, size_t lenMax, 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]); @@ -990,8 +1044,9 @@ int WXDLLEXPORT wxVsnprintf_(wxChar *buf, size_t lenMax, 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!