]> git.saurik.com Git - wxWidgets.git/blobdiff - src/common/wxchar.cpp
i18n files are installed as part of wxBase (and should be ideally part of separate...
[wxWidgets.git] / src / common / wxchar.cpp
index 3532e0533bc5cf95be0cd44f5280518dbe60ba2e..089d645b8272c2d2b13162b0c93ea2243fe32207 100644 (file)
@@ -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:
@@ -853,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:
@@ -901,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)
 {
@@ -958,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++)
@@ -977,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]);
@@ -998,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!