From 7da3733c73e7a3ba4c18f3927bbbe185598ad233 Mon Sep 17 00:00:00 2001 From: Graydon Hoare Date: Mon, 23 Jan 2012 18:37:26 -0800 Subject: [PATCH] Fix win32 command-line quoting on rust_run_program. --- src/rt/rust_run_program.cpp | 66 ++++++++++++++++++++++++++++++++++--- 1 file 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 #include +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;