summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog17
-rw-r--r--stream.c59
2 files changed, 64 insertions, 12 deletions
diff --git a/ChangeLog b/ChangeLog
index e2d223b0..b06f0dab 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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
diff --git a/stream.c b/stream.c
index ef91a07d..7187749a 100644
--- a/stream.c
+++ b/stream.c
@@ -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;