108 lines
3.1 KiB
Diff
108 lines
3.1 KiB
Diff
Fix Windows command line quoting of backslash runs: a trailing backslash, or
|
|
backslashes preceding a double quote, were not doubled, so CommandLineToArgvW
|
|
in the child parsed them as escapes and mangled the argument list.
|
|
|
|
Upstream PR: https://github.com/sheredom/subprocess.h/pull/101
|
|
Applied locally by scripts/sync_vendor.py until it is merged upstream.
|
|
|
|
(the test/ changes from the PR are omitted, we only vendor subprocess.h)
|
|
|
|
diff --git a/subprocess.h b/subprocess.h
|
|
index 5e80902..b06ad4d 100644
|
|
--- a/subprocess.h
|
|
+++ b/subprocess.h
|
|
@@ -653,6 +653,7 @@ int subprocess_create_ex(const char *const commandLine[], int options,
|
|
int wide_len;
|
|
int i, j;
|
|
int need_quoting;
|
|
+ subprocess_size_t bs_run;
|
|
unsigned long flags = 0;
|
|
unsigned long last_error = 0;
|
|
int result = subprocess_error_unknown;
|
|
@@ -906,25 +907,29 @@ int subprocess_create_ex(const char *const commandLine[], int options,
|
|
len++;
|
|
|
|
// Quote the argument if it has a space in it
|
|
- if (strpbrk(commandLine[i], "\t\v ") != SUBPROCESS_NULL ||
|
|
- commandLine[i][0] == SUBPROCESS_NULL)
|
|
+ need_quoting = strpbrk(commandLine[i], "\t\v ") != SUBPROCESS_NULL ||
|
|
+ commandLine[i][0] == SUBPROCESS_NULL;
|
|
+ if (need_quoting)
|
|
len += 2;
|
|
|
|
+ bs_run = 0;
|
|
for (j = 0; '\0' != commandLine[i][j]; j++) {
|
|
- switch (commandLine[i][j]) {
|
|
- default:
|
|
- break;
|
|
- case '\\':
|
|
- if (commandLine[i][j + 1] == '"') {
|
|
- len++;
|
|
- }
|
|
+ len++;
|
|
|
|
- break;
|
|
- case '"':
|
|
- len++;
|
|
- break;
|
|
+ if ('\\' == commandLine[i][j]) {
|
|
+ bs_run++;
|
|
+ } else {
|
|
+ if ('"' == commandLine[i][j]) {
|
|
+ // Duplicate the preceding run and escape the quote.
|
|
+ len += bs_run + 1;
|
|
+ }
|
|
+ bs_run = 0;
|
|
}
|
|
- len++;
|
|
+ }
|
|
+
|
|
+ if (need_quoting) {
|
|
+ // Duplicate trailing slashes before the generated closing quote.
|
|
+ len += bs_run;
|
|
}
|
|
}
|
|
|
|
@@ -949,22 +954,29 @@ int subprocess_create_ex(const char *const commandLine[], int options,
|
|
commandLineCombined[len++] = '"';
|
|
}
|
|
|
|
- for (j = 0; '\0' != commandLine[i][j]; j++) {
|
|
- switch (commandLine[i][j]) {
|
|
- default:
|
|
- break;
|
|
- case '\\':
|
|
- if (commandLine[i][j + 1] == '"') {
|
|
- commandLineCombined[len++] = '\\';
|
|
- }
|
|
+ for (j = 0; '\0' != commandLine[i][j];) {
|
|
+ bs_run = 0;
|
|
+ while ('\\' == commandLine[i][j]) {
|
|
+ bs_run++;
|
|
+ j++;
|
|
+ }
|
|
+
|
|
+ if ('"' == commandLine[i][j]) {
|
|
+ // 2n + 1 slashes preserve n slashes and escape the quote.
|
|
+ bs_run = (bs_run * 2) + 1;
|
|
+ } else if ('\0' == commandLine[i][j] && need_quoting) {
|
|
+ // 2n slashes preserve n slashes before the closing quote.
|
|
+ bs_run *= 2;
|
|
+ }
|
|
|
|
- break;
|
|
- case '"':
|
|
+ while (bs_run > 0) {
|
|
commandLineCombined[len++] = '\\';
|
|
- break;
|
|
+ bs_run--;
|
|
}
|
|
|
|
- commandLineCombined[len++] = commandLine[i][j];
|
|
+ if ('\0' != commandLine[i][j]) {
|
|
+ commandLineCombined[len++] = commandLine[i][j++];
|
|
+ }
|
|
}
|
|
if (need_quoting) {
|
|
commandLineCombined[len++] = '"';
|