diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2015-04-15 22:12:00 -0700 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2015-04-15 22:12:00 -0700 |
commit | 56beef8defcb5944be1ee523400b382119dbe8fc (patch) | |
tree | bf06cef34f2765997d5e534a4d1256f42df2f50f | |
parent | fff6c80a0f7dd2c90033a48444aad0db36ff9b80 (diff) | |
download | txr-56beef8defcb5944be1ee523400b382119dbe8fc.tar.gz txr-56beef8defcb5944be1ee523400b382119dbe8fc.tar.bz2 txr-56beef8defcb5944be1ee523400b382119dbe8fc.zip |
Fix escaping issues in open-process on Windows.
This can now execute programs with spaces in their path names.
Arguments can contain embedded double quotes, and other characters
that are special to cmd.exe, like &, |, (, ), ^ and others.
* stream.c (string_extend_count, win_escape_cmd): New static functions.
(win_escape_arg): Fix and extend escaping scheme to cover not only
the argument processing scheme implemented by programs which use Microsoft's
C library, but also to smuggle the command line through cmd.exe.
(win_make_cmdline): Use win_escape_cmd to wrap the command.
Escape the quotes which are placed around arguments, so cmd.exe
doesn't interpret them, which will cause it to suppress its processing
of the caret escapes.
-rw-r--r-- | ChangeLog | 17 | ||||
-rw-r--r-- | stream.c | 59 |
2 files changed, 64 insertions, 12 deletions
@@ -1,5 +1,22 @@ 2015-04-15 Kaz Kylheku <kaz@kylheku.com> + Fix escaping issues in open-process on Windows. + + This can now execute programs with spaces in their path names. + Arguments can contain embedded double quotes, and other characters + that are special to cmd.exe, like &, |, (, ), ^ and others. + + * stream.c (string_extend_count, win_escape_cmd): New static functions. + (win_escape_arg): Fix and extend escaping scheme to cover not only + the argument processing scheme implemented by programs which use Microsoft's + C library, but also to smuggle the command line through cmd.exe. + (win_make_cmdline): Use win_escape_cmd to wrap the command. + Escape the quotes which are placed around arguments, so cmd.exe + doesn't interpret them, which will cause it to suppress its processing + of the caret escapes. + +2015-04-15 Kaz Kylheku <kaz@kylheku.com> + Allow quasiquotes in braces and quasiliterals, and quotes in braces. * parser.l: Consolidate rules for recognizing quote, unquote, and @@ -2452,6 +2452,33 @@ val open_process(val name, val mode_str, val args) } #else +static void string_extend_count(int count, val out, val tail) +{ + int i; + for (i = 0; i < count; i++) + string_extend(out, tail); +} + +static val win_escape_cmd(val str) +{ + const wchar_t *s; + val out = string(L""); + + for (s = c_str(str); *s; s++) { + switch (*s) { + case ' ': case '\t': + string_extend(out, lit("\"")); + string_extend(out, chr(*s)); + string_extend(out, lit("\"")); + break; + default: + string_extend(out, chr(*s)); + } + } + + return out; +} + static val win_escape_arg(val str) { int bscount = 0, i; @@ -2461,17 +2488,25 @@ static val win_escape_arg(val str) for (s = c_str(str); *s; s++) { switch (*s) { case '"': - for (i = 0; i < bscount; i++) - string_extend(out, lit("\\\\")); - string_extend(out, lit("\\\"")); + string_extend_count(bscount, out, lit("\\\\")); + string_extend(out, lit("\\^\"")); bscount = 0; break; case '\\': bscount++; break; + case '^': case '%': case '!': + case '\n': case '&': case '|': + case '<': case '>': + case '(': case ')': + for (i = 0; i < bscount; i++) + string_extend_count(bscount, out, lit("\\")); + string_extend(out, chr('^')); + string_extend(out, chr(*s)); + break; default: for (i = 0; i < bscount; i++) - string_extend(out, lit("\\")); + string_extend_count(bscount, out, lit("\\")); string_extend(out, chr(*s)); bscount = 0; break; @@ -2488,16 +2523,16 @@ static val win_make_cmdline(val args) { val out = string(L""); - string_extend(out, pop(&args)); - string_extend(out, lit(" ")); + string_extend(out, win_escape_cmd(pop(&args))); + string_extend(out, chr(' ')); - for (; args; args = cdr(args)) { - string_extend(out, lit("\"")); - string_extend(out, win_escape_arg(car(args))); - if (cdr(args)) - string_extend(out, lit("\" ")); + while (args) { + string_extend(out, lit("^\"")); + string_extend(out, win_escape_arg(pop(&args))); + if (args) + string_extend(out, lit("^\" ")); else - string_extend(out, lit("\"")); + string_extend(out, lit("^\"")); } return out; |