diff options
-rw-r--r-- | ChangeLog | 14 | ||||
-rw-r--r-- | stream.c | 66 |
2 files changed, 79 insertions, 1 deletions
@@ -1,5 +1,19 @@ 2012-05-18 Kaz Kylheku <kaz@kylheku.com> + Implement open_pipev in terms of popen for Windows which + does not have for or exec. We could use CreateProcess and CreatePipe, + et cetera, but it won't buy us anything because the whole point + of this function is to improve the argument passing, and CreateProcess + takes a single command line string, not too different from popen. + + * stream.c (pipev_close, make_pipev_stream): Surrounded with + HAVE_FORK_STUFF ifdef. + (pipe_close): Choice of close strategy conditional on HAVE_FORK_STUFF. + (open_pipev): Conditionally defined in two ways now. + (win_escape_arg, win_make_cmdline): New static functions. + +2012-05-18 Kaz Kylheku <kaz@kylheku.com> + * configure: New test added for fork, pipe, exec and waitpid. Produces HAVE_FORK_STUFF in config.h. @@ -274,6 +274,7 @@ static struct strm_ops stdio_ops = { stdio_flush }; +#if HAVE_FORK_STUFF static int pipevp_close(FILE *f, pid_t pid) { int status; @@ -282,13 +283,18 @@ static int pipevp_close(FILE *f, pid_t pid) ; return status; } +#endif static val pipe_close(val stream, val throw_on_error) { struct stdio_handle *h = (struct stdio_handle *) stream->co.handle; if (h->f != 0) { +#if HAVE_FORK_STUFF int status = h->pid != 0 ? pipevp_close(h->f, h->pid) : pclose(h->f); +#else + int status = pclose(h->f); +#endif h->f = 0; if (status != 0 && throw_on_error) { @@ -730,6 +736,7 @@ val make_pipe_stream(FILE *f, val descr, val input, val output) return stream; } +#if HAVE_FORK_STUFF static val make_pipevp_stream(FILE *f, val descr, pid_t pid) { struct stdio_handle *h = (struct stdio_handle *) chk_malloc(sizeof *h); @@ -740,7 +747,7 @@ static val make_pipevp_stream(FILE *f, val descr, pid_t pid) h->pid = pid; return stream; } - +#endif val make_string_input_stream(val string) { @@ -1529,6 +1536,7 @@ val open_pipe(val path, val mode_str) return make_pipe_stream(f, path, input, output); } +#if HAVE_FORK_STUFF val open_pipevp(val name, val mode_str, val args) { int input = equal(mode_str, lit("r")) || equal(mode_str, lit("rb")); @@ -1600,6 +1608,62 @@ val open_pipevp(val name, val mode_str, val args) return make_pipevp_stream(f, name, pid); } } +#else + +static val win_escape_arg(val str) +{ + int bscount = 0, i; + const wchar_t *s; + val out = string(L""); + + for (s = c_str(str); *s; s++) { + switch (*s) { + case '"': + for (i = 0; i < bscount; i++) + string_extend(out, lit("\\\\")); + string_extend(out, lit("\\\"")); + bscount = 0; + break; + case '\\': + bscount++; + break; + default: + for (i = 0; i < bscount; i++) + string_extend(out, lit("\\")); + string_extend(out, chr(*s)); + bscount = 0; + break; + } + } + + for (i = 0; i < bscount; i++) + string_extend(out, lit("\\")); + + return out; +} + +static val win_make_cmdline(val args) +{ + val out = string(L""); + + for (; args; args = cdr(args)) { + string_extend(out, lit("\"")); + string_extend(out, win_escape_arg(car(args))); + if (cdr(args)) + string_extend(out, lit("\" ")); + else + string_extend(out, lit("\"")); + } + + return out; +} + +val open_pipevp(val name, val mode_str, val args) +{ + val win_cmdline = win_make_cmdline(cons(name, args)); + return open_pipe(win_cmdline, mode_str); +} +#endif void stream_init(void) { |