about summary refs log tree commit diff
path: root/src/rt/rust_run_program.cpp
diff options
context:
space:
mode:
authorGraydon Hoare <graydon@mozilla.com>2012-01-23 18:37:26 -0800
committerGraydon Hoare <graydon@mozilla.com>2012-01-23 18:37:26 -0800
commit7da3733c73e7a3ba4c18f3927bbbe185598ad233 (patch)
tree614a49b6f74c81a42faf9fbdec3b59f8886e0af4 /src/rt/rust_run_program.cpp
parent7c1d1d6c9a63e76e24ac31bad96940ab1fb44d0f (diff)
downloadrust-7da3733c73e7a3ba4c18f3927bbbe185598ad233.tar.gz
rust-7da3733c73e7a3ba4c18f3927bbbe185598ad233.zip
Fix win32 command-line quoting on rust_run_program.
Diffstat (limited to 'src/rt/rust_run_program.cpp')
-rw-r--r--src/rt/rust_run_program.cpp66
1 files changed, 62 insertions, 4 deletions
diff --git a/src/rt/rust_run_program.cpp b/src/rt/rust_run_program.cpp
index 1b17a510b2e..df4714758dd 100644
--- a/src/rt/rust_run_program.cpp
+++ b/src/rt/rust_run_program.cpp
@@ -5,6 +5,64 @@
 #include <process.h>
 #include <io.h>
 
+bool backslash_run_ends_in_quote(char const *c) {
+    while (*c == '\\') ++c;
+    return *c == '"';
+}
+
+void append_first_char(char *&buf, char const *c) {
+    switch (*c) {
+
+    case '"':
+        // Escape quotes.
+        *buf++ = '\\';
+        *buf++ = '"';
+        break;
+
+
+    case '\\':
+        if (backslash_run_ends_in_quote(c)) {
+            // Double all backslashes that are in runs before quotes.
+            *buf++ = '\\';
+            *buf++ = '\\';
+        } else {
+            // Pass other backslashes through unescaped.
+            *buf++ = '\\';
+        }
+        break;
+
+    default:
+        *buf++ = *c;
+    }
+}
+
+bool contains_whitespace(char const *arg) {
+    while (*arg) {
+        switch (*arg++) {
+        case ' ':
+        case '\t':
+            return true;
+        }
+    }
+    return false;
+}
+
+void append_arg(char *& buf, char const *arg, bool last) {
+    bool quote = contains_whitespace(arg);
+    if (quote)
+        *buf++ = '"';
+    while (*arg)
+        append_first_char(buf, arg++);
+    if (quote)
+        *buf++ = '"';
+
+    if (! last) {
+        *buf++ = ' ';
+    } else {
+        *buf++ = '\0';
+    }
+}
+
 extern "C" CDECL int
 rust_run_program(const char* argv[], int in_fd, int out_fd, int err_fd) {
     STARTUPINFO si;
@@ -29,14 +87,14 @@ rust_run_program(const char* argv[], int in_fd, int out_fd, int err_fd) {
     size_t cmd_len = 0;
     for (const char** arg = argv; *arg; arg++) {
         cmd_len += strlen(*arg);
-        cmd_len++; // Space or \0
+        cmd_len += 3; // Two quotes plus trailing space or \0
     }
+    cmd_len *= 2; // Potentially backslash-escape everything.
+
     char* cmd = (char*)malloc(cmd_len);
     char* pos = cmd;
     for (const char** arg = argv; *arg; arg++) {
-        strcpy(pos, *arg);
-        pos += strlen(*arg);
-        if (*(arg+1)) *(pos++) = ' ';
+        append_arg(pos, *arg, *(arg+1) == NULL);
     }
 
     PROCESS_INFORMATION pi;