]> git.lizzy.rs Git - rust.git/commitdiff
Merge pull request #1627 from graydon/win32-quoting
authorBrian Anderson <andersrb@gmail.com>
Wed, 25 Jan 2012 22:33:10 +0000 (14:33 -0800)
committerBrian Anderson <andersrb@gmail.com>
Wed, 25 Jan 2012 22:33:10 +0000 (14:33 -0800)
Fix win32 command-line quoting on rust_run_program.

src/rt/rust_run_program.cpp

index 1b17a510b2e44fd0d3d301a9842df2a9f027219f..df4714758dd94ad6fcd3c54d80863f4446b2f3a3 100644 (file)
@@ -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;