Bug 1060419 - add %S and %ls support to Smprintf; r=froydnj
authorTom Tromey <tom@tromey.com>
Thu, 19 Jan 2017 15:56:09 -0700
changeset 343530 aa5def25fb21a58c89a44fb0e909f1917fb38063
parent 343529 dd0cf6092b85c4ed51fb246cda4cf259713e9810
child 343531 36ead380cb480c3914bf4343a4586ac1897565c9
push id31381
push userkwierso@gmail.com
push dateFri, 17 Feb 2017 20:45:51 +0000
treeherdermozilla-central@f302def88fe5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersfroydnj
bugs1060419
milestone54.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1060419 - add %S and %ls support to Smprintf; r=froydnj MozReview-Commit-ID: CQMZCkCOXDV
mozglue/misc/Printf.cpp
--- a/mozglue/misc/Printf.cpp
+++ b/mozglue/misc/Printf.cpp
@@ -8,23 +8,28 @@
  * Portable safe sprintf code.
  *
  * Author: Kipp E.B. Hickman
  */
 
 #include "mozilla/AllocPolicy.h"
 #include "mozilla/Printf.h"
 #include "mozilla/Sprintf.h"
+#include "mozilla/UniquePtrExtensions.h"
 #include "mozilla/Vector.h"
 
 #include <stdarg.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 
+#if defined(XP_WIN)
+#include <windows.h>
+#endif
+
 /*
  * Note: on some platforms va_list is defined as an array,
  * and requires array notation.
  */
 #ifdef HAVE_VA_COPY
 #define VARARGS_ASSIGN(foo, bar)        VA_COPY(foo, bar)
 #elif defined(HAVE_VA_LIST_AS_ARRAY)
 #define VARARGS_ASSIGN(foo, bar)        foo[0] = bar[0]
@@ -51,16 +56,19 @@ typedef mozilla::Vector<NumArgState, 20,
 #define TYPE_LONG       4
 #define TYPE_ULONG      5
 #define TYPE_LONGLONG   6
 #define TYPE_ULONGLONG  7
 #define TYPE_STRING     8
 #define TYPE_DOUBLE     9
 #define TYPE_INTSTR     10
 #define TYPE_POINTER    11
+#if defined(XP_WIN)
+#define TYPE_WSTRING    12
+#endif
 #define TYPE_UNKNOWN    20
 
 #define FLAG_LEFT       0x1
 #define FLAG_SIGNED     0x2
 #define FLAG_SPACED     0x4
 #define FLAG_ZEROS      0x8
 #define FLAG_NEG        0x10
 
@@ -441,27 +449,42 @@ BuildArgArray(const char* fmt, va_list a
         case 'g':
             nas[cn].type = TYPE_DOUBLE;
             break;
 
         case 'p':
             nas[cn].type = TYPE_POINTER;
             break;
 
+        case 'S':
+#if defined(XP_WIN)
+            nas[cn].type = TYPE_WSTRING;
+            break;
+#endif
+            /* Fall through here when not XP_WIN.  */
         case 'C':
-        case 'S':
         case 'E':
         case 'G':
             // XXX not supported I suppose
             MOZ_ASSERT(0);
             nas[cn].type = TYPE_UNKNOWN;
             break;
 
         case 's':
-            nas[cn].type = TYPE_STRING;
+#if defined(XP_WIN)
+            if (nas[cn].type == TYPE_LONG) {
+                nas[cn].type = TYPE_WSTRING;
+                break;
+            }
+#endif
+            if (nas[cn].type == TYPE_INTN) {
+                nas[cn].type = TYPE_STRING;
+            } else {
+                nas[cn].type = TYPE_UNKNOWN;
+            }
             break;
 
         case 'n':
             nas[cn].type = TYPE_INTSTR;
             break;
 
         default:
             MOZ_ASSERT(0);
@@ -495,16 +518,19 @@ BuildArgArray(const char* fmt, va_list a
         case TYPE_LONG:         (void) va_arg(ap, long);        break;
         case TYPE_ULONG:        (void) va_arg(ap, unsigned long); break;
         case TYPE_LONGLONG:     (void) va_arg(ap, long long);   break;
         case TYPE_ULONGLONG:    (void) va_arg(ap, unsigned long long); break;
         case TYPE_STRING:       (void) va_arg(ap, char*);       break;
         case TYPE_INTSTR:       (void) va_arg(ap, int*);        break;
         case TYPE_DOUBLE:       (void) va_arg(ap, double);      break;
         case TYPE_POINTER:      (void) va_arg(ap, void*);       break;
+#if defined(XP_WIN)
+        case TYPE_WSTRING:      (void) va_arg(ap, wchar_t*);    break;
+#endif
 
         default: MOZ_CRASH();
         }
 
         cn++;
     }
 
     return true;
@@ -519,16 +545,19 @@ mozilla::PrintfTarget::vprint(const char
         char ch;
         int i;
         long l;
         long long ll;
         double d;
         const char* s;
         int* ip;
         void* p;
+#if defined(XP_WIN)
+        const wchar_t* ws;
+#endif
     } u;
     const char* fmt0;
     static const char hex[] = "0123456789abcdef";
     static const char HEX[] = "0123456789ABCDEF";
     const char* hexp;
     int i;
     char pattern[20];
     const char* dolPt = nullptr;  // in "%4$.2f", dolPt will point to '.'
@@ -777,28 +806,63 @@ mozilla::PrintfTarget::vprint(const char
 
           case 'p':
             type = TYPE_POINTER;
             radix = 16;
             goto fetch_and_convert;
 
 #if 0
           case 'C':
-          case 'S':
           case 'E':
           case 'G':
             // XXX not supported I suppose
             MOZ_ASSERT(0);
             break;
 #endif
 
           case 's':
-            u.s = va_arg(ap, const char*);
-            if (!cvt_s(u.s, width, prec, flags))
-                return false;
+            if (type == TYPE_INTN) {
+                u.s = va_arg(ap, const char*);
+                if (!cvt_s(u.s, width, prec, flags))
+                    return false;
+                break;
+            } else if (type == TYPE_LONGLONG) {
+                // This should have asserted during BuildArgArray anyway.
+                MOZ_ASSERT(0);
+                break;
+            }
+            MOZ_ASSERT(type == TYPE_LONG);
+            MOZ_FALLTHROUGH;
+          case 'S':
+#if defined(XP_WIN)
+            {
+                u.ws = va_arg(ap, const wchar_t*);
+
+                int rv = WideCharToMultiByte(CP_ACP, 0, u.ws, -1, NULL, 0, NULL, NULL);
+                if (rv == 0 && GetLastError() == ERROR_NO_UNICODE_TRANSLATION) {
+                    if (!cvt_s("<unicode errors in string>", width, prec, flags)) {
+                        return false;
+                    }
+                } else {
+                    if (rv == 0) {
+                        rv = 1;
+                    }
+                    UniqueFreePtr<char[]> buf((char*)malloc(rv));
+                    WideCharToMultiByte(CP_ACP, 0, u.ws, -1, buf.get(), rv, NULL, NULL);
+                    buf[rv - 1] = '\0';
+
+                    if (!cvt_s(buf.get(), width, prec, flags)) {
+                        return false;
+                    }
+                }
+            }
+#else
+            // This should have asserted during BuildArgArray anyway.
+            MOZ_ASSERT(0);
+#endif
             break;
 
           case 'n':
             u.ip = va_arg(ap, int*);
             if (u.ip) {
                 *u.ip = mEmitted;
             }
             break;
@@ -842,15 +906,16 @@ mozilla::PrintfTarget::print(const char*
 #undef TYPE_LONG
 #undef TYPE_ULONG
 #undef TYPE_LONGLONG
 #undef TYPE_ULONGLONG
 #undef TYPE_STRING
 #undef TYPE_DOUBLE
 #undef TYPE_INTSTR
 #undef TYPE_POINTER
+#undef TYPE_WSTRING
 #undef TYPE_UNKNOWN
 
 #undef FLAG_LEFT
 #undef FLAG_SIGNED
 #undef FLAG_SPACED
 #undef FLAG_ZEROS
 #undef FLAG_NEG