mirror of
https://gitlab.com/embeddable-common-lisp/ecl.git
synced 2026-01-15 05:43:19 -08:00
run-program: Major function refactor
A lot of code was duplicated due to creating descriptors for output, input and error streams. It is reduced by extracting function `create_descriptor'. Signed-off-by: Daniel Kochmański <dkochmanski@turtle-solutions.eu>
This commit is contained in:
parent
623857e379
commit
788eaf041a
1 changed files with 133 additions and 252 deletions
385
src/c/unixsys.d
385
src/c/unixsys.d
|
|
@ -404,6 +404,107 @@ ecl_stream_to_HANDLE(cl_object s, bool output)
|
|||
}
|
||||
#endif
|
||||
|
||||
#if defined(ECL_MS_WINDOWS_HOST)
|
||||
static void
|
||||
create_descriptor(cl_object stream, cl_object direction,
|
||||
HANDLE *child, int *parent) {
|
||||
SECURITY_ATTRIBUTES attr;
|
||||
HANDLE current = GetCurrentProcess();
|
||||
attr.nLength = sizeof(SECURITY_ATTRIBUTES);
|
||||
attr.lpSecurityDescriptor = NULL;
|
||||
attr.bInheritHandle = TRUE;
|
||||
|
||||
if (stream == @':stream') {
|
||||
/* Creates a pipe that we can write to and the
|
||||
child reads from. We duplicate one extreme of the
|
||||
pipe so that the child does not inherit it. */
|
||||
HANDLE tmp;
|
||||
if (CreatePipe(&tmp, child, &attr, 0) == 0)
|
||||
return;
|
||||
|
||||
if (DuplicateHandle(current, tmp, current,
|
||||
&tmp, 0, FALSE,
|
||||
DUPLICATE_CLOSE_SOURCE |
|
||||
DUPLICATE_SAME_ACCESS) == 0)
|
||||
return;
|
||||
|
||||
if (direction == @':input') {
|
||||
#ifdef cygwin
|
||||
*parent = cygwin_attach_handle_to_fd
|
||||
(0, -1, tmp, S_IRWXU, GENERIC_WRITE);
|
||||
#else
|
||||
*parent = _open_osfhandle
|
||||
((intptr_t)tmp, _O_WRONLY);
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
#ifdef cygwin
|
||||
*parent = cygwin_attach_handle_to_fd
|
||||
(0, -1, tmp, S_IRWXU, GENERIC_READ);
|
||||
#else
|
||||
*parent = _open_osfhandle
|
||||
((intptr_t)tmp, _O_RDONLY);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (*parent < 0)
|
||||
printf("open_osfhandle failed\n");
|
||||
}
|
||||
else if (Null(stream)) {
|
||||
*child = NULL;
|
||||
}
|
||||
else if (!Null(cl_streamp(stream))) {
|
||||
HANDLE stream_handle = ecl_stream_to_HANDLE
|
||||
(stream, direction == @':output');
|
||||
if (stream_handle == INVALID_HANDLE_VALUE) {
|
||||
FEerror(":INPUT argument to RUN-PROGRAM does not "
|
||||
"have a file handle:~%~S", 1, stream);
|
||||
}
|
||||
DuplicateHandle(current, stream_handle,
|
||||
current, child, 0, TRUE,
|
||||
DUPLICATE_SAME_ACCESS);
|
||||
}
|
||||
else {
|
||||
FEerror("Invalid ~S argument to EXT:RUN-PROGRAM", 1, stream);
|
||||
}
|
||||
}
|
||||
#else
|
||||
static void
|
||||
create_descriptor(cl_object stream, cl_object direction,
|
||||
int *child, int *parent) {
|
||||
if (stream == @':stream') {
|
||||
int fd[2];
|
||||
pipe(fd);
|
||||
if (direction == @':input') {
|
||||
*parent = fd[1];
|
||||
*child = fd[0];
|
||||
} else {
|
||||
*parent = fd[0];
|
||||
*child = fd[1];
|
||||
}
|
||||
}
|
||||
else if (Null(stream)) {
|
||||
if (direction == @':output')
|
||||
*child = open("/dev/null", O_WRONLY);
|
||||
else
|
||||
*child = open("/dev/null", O_RDONLY);
|
||||
}
|
||||
else if (!Null(cl_streamp(stream))) {
|
||||
*child = ecl_stream_to_handle
|
||||
(stream, direction == @':output');
|
||||
if (*child >= 0) {
|
||||
*child = dup(*child);
|
||||
} else {
|
||||
FEerror(":INPUT argument to RUN-PROGRAM does not "
|
||||
"have a file handle:~%~S", 1, stream);
|
||||
}
|
||||
}
|
||||
else {
|
||||
FEerror("Invalid ~S argument to EXT:RUN-PROGRAM", 1, stream);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@(defun ext::run-program (command argv &key (input @':stream') (output @':stream')
|
||||
(error @'t') (wait @'t') (environ ECL_NIL)
|
||||
(if_output_exists @':supersede'))
|
||||
|
|
@ -418,6 +519,30 @@ ecl_stream_to_HANDLE(cl_object s, bool output)
|
|||
command = si_copy_to_simple_base_string(command);
|
||||
argv = cl_mapcar(2, @'si::copy-to-simple-base-string', argv);
|
||||
process = make_external_process();
|
||||
|
||||
{
|
||||
if (input == @'t')
|
||||
input = ecl_symbol_value(@'*standard-input*');
|
||||
if (ECL_STRINGP(input) || ECL_PATHNAMEP(input))
|
||||
input = cl_open(5, input,
|
||||
@':direction', @':input',
|
||||
@':if-does-not-exist', @':error');
|
||||
|
||||
if (output == @'t')
|
||||
output = ecl_symbol_value(@'*standard-output*');
|
||||
if (ECL_STRINGP(output) || ECL_PATHNAMEP(output))
|
||||
output = cl_open(7, output,
|
||||
@':direction', @':output',
|
||||
@':if-exists', if_output_exists,
|
||||
@':if-does-not-exist', @':create');
|
||||
|
||||
if (error == @'t')
|
||||
error = ecl_symbol_value(@'*error-output*');
|
||||
if (ECL_STRINGP(error) || ECL_PATHNAMEP(error))
|
||||
error = cl_open(7, error,
|
||||
@':direction', @':output',
|
||||
@':if-does-not-exist', @':create');
|
||||
}
|
||||
#if defined(ECL_MS_WINDOWS_HOST)
|
||||
{
|
||||
BOOL ok;
|
||||
|
|
@ -426,7 +551,6 @@ ecl_stream_to_HANDLE(cl_object s, bool output)
|
|||
HANDLE child_stdout, child_stdin, child_stderr;
|
||||
HANDLE current = GetCurrentProcess();
|
||||
HANDLE saved_stdout, saved_stdin, saved_stderr;
|
||||
SECURITY_ATTRIBUTES attr;
|
||||
cl_object env_buffer;
|
||||
char *env = NULL;
|
||||
|
||||
|
|
@ -444,173 +568,10 @@ ecl_stream_to_HANDLE(cl_object s, bool output)
|
|||
env_buffer = from_list_to_execve_argument(environ, NULL);
|
||||
env = env_buffer->base_string.self;
|
||||
}
|
||||
create_descriptor(input, @':input', &child_stdin, &parent_write);
|
||||
create_descriptor(output, @':output', &child_stdout, &parent_read);
|
||||
create_descriptor(error, @':output', &child_stderr, &parent_error);
|
||||
|
||||
attr.nLength = sizeof(SECURITY_ATTRIBUTES);
|
||||
attr.lpSecurityDescriptor = NULL;
|
||||
attr.bInheritHandle = TRUE;
|
||||
AGAIN_INPUT:
|
||||
if (input == @':stream') {
|
||||
/* Creates a pipe that we can read from what the child
|
||||
writes to it. We duplicate one extreme of the pipe
|
||||
so that the child does not inherit it. */
|
||||
HANDLE tmp;
|
||||
ok = CreatePipe(&child_stdin, &tmp, &attr, 0);
|
||||
if (ok) {
|
||||
ok = DuplicateHandle(current, tmp, current,
|
||||
&tmp, 0, FALSE,
|
||||
DUPLICATE_CLOSE_SOURCE |
|
||||
DUPLICATE_SAME_ACCESS);
|
||||
if (ok) {
|
||||
#ifdef cygwin
|
||||
parent_write =
|
||||
cygwin_attach_handle_to_fd
|
||||
(0, -1, tmp, S_IRWXU, GENERIC_WRITE);
|
||||
#else
|
||||
parent_write = _open_osfhandle((intptr_t)tmp,
|
||||
_O_WRONLY /*| _O_TEXT*/);
|
||||
#endif
|
||||
if (parent_write < 0)
|
||||
printf("open_osfhandle failed\n");
|
||||
}
|
||||
}
|
||||
} else if (input == @'t') {
|
||||
/* The child inherits a duplicate of our input
|
||||
handle. Creating a duplicate avoids problems when
|
||||
the child closes it */
|
||||
input = ecl_symbol_value(@'*standard-input*');
|
||||
goto AGAIN_INPUT;
|
||||
} else if (Null(input)) {
|
||||
child_stdin = NULL;
|
||||
/*child_stdin = open("/dev/null", O_RDONLY);*/
|
||||
} else if (!Null(cl_streamp(input))) {
|
||||
/* If stream provides a handle, pass it to the child. Otherwise
|
||||
* complain. */
|
||||
HANDLE stream_handle = ecl_stream_to_HANDLE(input, 0);
|
||||
unlikely_if (stream_handle == INVALID_HANDLE_VALUE) {
|
||||
FEerror(":INPUT argument to RUN-PROGRAM does not "
|
||||
"have a file handle:~%~S", 1, input);
|
||||
}
|
||||
DuplicateHandle(current, stream_handle,
|
||||
/*GetStdHandle(STD_INPUT_HANDLE)*/
|
||||
current, &child_stdin, 0, TRUE,
|
||||
DUPLICATE_SAME_ACCESS);
|
||||
} else if (ECL_STRINGP(input) || ECL_PATHNAMEP(input)) {
|
||||
input = cl_open(5, input,
|
||||
@':direction', @':input',
|
||||
@':if-does-not-exist', @':error');
|
||||
goto AGAIN_INPUT;
|
||||
} else {
|
||||
FEerror("Invalid :INPUT argument to EXT:RUN-PROGRAM", 1,
|
||||
input);
|
||||
}
|
||||
AGAIN_OUTPUT:
|
||||
if (output == @':stream') {
|
||||
/* Creates a pipe that we can write to and the
|
||||
child reads from. We duplicate one extreme of the
|
||||
pipe so that the child does not inherit it. */
|
||||
HANDLE tmp;
|
||||
ok = CreatePipe(&tmp, &child_stdout, &attr, 0);
|
||||
if (ok) {
|
||||
ok = DuplicateHandle(current, tmp, current,
|
||||
&tmp, 0, FALSE,
|
||||
DUPLICATE_CLOSE_SOURCE |
|
||||
DUPLICATE_SAME_ACCESS);
|
||||
if (ok) {
|
||||
#ifdef cygwin
|
||||
parent_read =
|
||||
cygwin_attach_handle_to_fd
|
||||
(0, -1, tmp, S_IRWXU, GENERIC_READ);
|
||||
#else
|
||||
parent_read = _open_osfhandle((intptr_t)tmp,
|
||||
_O_RDONLY /*| _O_TEXT*/);
|
||||
#endif
|
||||
if (parent_read < 0)
|
||||
printf("open_osfhandle failed\n");
|
||||
}
|
||||
}
|
||||
} else if (output == @'t') {
|
||||
/* The child inherits a duplicate of our output
|
||||
handle. Creating a duplicate avoids problems when
|
||||
the child closes it */
|
||||
output = ecl_symbol_value(@'*standard-output*');
|
||||
goto AGAIN_OUTPUT;
|
||||
} else if (Null(output)) {
|
||||
child_stdout = NULL;
|
||||
} else if (!Null(cl_streamp(output))) {
|
||||
HANDLE stream_handle = ecl_stream_to_HANDLE(output, 1);
|
||||
unlikely_if(stream_handle == INVALID_HANDLE_VALUE) {
|
||||
FEerror(":OUTPUT argument to RUN-PROGRAM does not "
|
||||
"have a file handle:~%~S", 1, output);
|
||||
}
|
||||
DuplicateHandle(current, stream_handle,
|
||||
/*GetStdHandle(STD_OUTPUT_HANDLE)*/
|
||||
current, &child_stdout, 0, TRUE,
|
||||
DUPLICATE_SAME_ACCESS);
|
||||
} else if (ECL_STRINGP(output) || ECL_PATHNAMEP(output)) {
|
||||
output = cl_open(7, output,
|
||||
@':direction', @':output',
|
||||
@':if-exists', if_output_exists,
|
||||
@':if-does-not-exist', @':create');
|
||||
goto AGAIN_OUTPUT;
|
||||
} else {
|
||||
FEerror("Invalid :OUTPUT argument to EXT:RUN-PROGRAM", 1,
|
||||
output);
|
||||
}
|
||||
AGAIN_ERROR:
|
||||
if (error == @':output') {
|
||||
/* The child inherits a duplicate of its own output
|
||||
handle.*/
|
||||
DuplicateHandle(current, child_stdout, current,
|
||||
&child_stderr, 0, TRUE,
|
||||
DUPLICATE_SAME_ACCESS);
|
||||
} else if (error == @':stream') {
|
||||
HANDLE tmp;
|
||||
ok = CreatePipe(&tmp, &child_stderr, &attr, 0);
|
||||
if (ok) {
|
||||
ok = DuplicateHandle(current, tmp, current,
|
||||
&tmp, 0, FALSE,
|
||||
DUPLICATE_CLOSE_SOURCE |
|
||||
DUPLICATE_SAME_ACCESS);
|
||||
if (ok) {
|
||||
#ifdef cygwin
|
||||
parent_error =
|
||||
cygwin_attach_handle_to_fd
|
||||
(0, -1, tmp, S_IRWXU, GENERIC_READ);
|
||||
#else
|
||||
parent_error = _open_osfhandle((intptr_t)tmp,
|
||||
_O_RDONLY /*| _O_TEXT*/);
|
||||
#endif
|
||||
if (parent_error < 0)
|
||||
printf("open_osfhandle failed\n");
|
||||
}
|
||||
}
|
||||
} else if (error == @'t') {
|
||||
/* The child inherits a duplicate of our output
|
||||
handle. Creating a duplicate avoids problems when
|
||||
the child closes it */
|
||||
error = ecl_symbol_value(@'*error-output*');
|
||||
goto AGAIN_ERROR;
|
||||
} else if (Null(error)) {
|
||||
child_stderr = NULL;
|
||||
} else if (!Null(cl_streamp(error))) {
|
||||
HANDLE stream_handle = ecl_stream_to_HANDLE(error, 1);
|
||||
unlikely_if (stream_handle == INVALID_HANDLE_VALUE) {
|
||||
FEerror(":ERROR argument to RUN-PROGRAM does not "
|
||||
"have a file handle:~%~S", 1, error);
|
||||
}
|
||||
DuplicateHandle(current, stream_handle,
|
||||
/*GetStdHandle(STD_ERROR_HANDLE)*/
|
||||
current, &child_stderr, 0, TRUE,
|
||||
DUPLICATE_SAME_ACCESS);
|
||||
} else if (ECL_STRINGP(error) || ECL_PATHNAMEP(error)) {
|
||||
error = cl_open(7, error,
|
||||
@':direction', @':output',
|
||||
@':if-does-not-exist', @':create');
|
||||
goto AGAIN_ERROR;
|
||||
} else {
|
||||
FEerror("Invalid :ERROR argument to EXT:RUN-PROGRAM:~%~S", 1,
|
||||
error);
|
||||
}
|
||||
add_external_process(the_env, process);
|
||||
#if 1
|
||||
ZeroMemory(&st_info, sizeof(STARTUPINFO));
|
||||
|
|
@ -679,91 +640,11 @@ ecl_stream_to_HANDLE(cl_object s, bool output)
|
|||
int pipe_fd[2];
|
||||
argv = CONS(command, ecl_nconc(argv, ecl_list1(ECL_NIL)));
|
||||
argv = _ecl_funcall3(@'coerce', argv, @'vector');
|
||||
AGAIN_INPUT:
|
||||
if (input == @':stream') {
|
||||
int fd[2];
|
||||
pipe(fd);
|
||||
parent_write = fd[1];
|
||||
child_stdin = fd[0];
|
||||
} else if (input == @'t') {
|
||||
input = ecl_symbol_value(@'*standard-input*');
|
||||
goto AGAIN_INPUT;
|
||||
} else if (Null(input)) {
|
||||
child_stdin = open("/dev/null", O_RDONLY);
|
||||
} else if (!Null(cl_streamp(input))) {
|
||||
child_stdin = ecl_stream_to_handle(input, 0);
|
||||
if (child_stdin >= 0) {
|
||||
child_stdin = dup(child_stdin);
|
||||
} else {
|
||||
FEerror(":INPUT argument to RUN-PROGRAM does not "
|
||||
"have a file handle:~%~S", 1, input);
|
||||
}
|
||||
} else if (ECL_STRINGP(input) || ECL_PATHNAMEP(input)) {
|
||||
input = cl_open(5, input,
|
||||
@':direction', @':input',
|
||||
@':if-does-not-exist', @':error');
|
||||
goto AGAIN_INPUT;
|
||||
} else {
|
||||
FEerror("Invalid :INPUT argument to EXT:RUN-PROGRAM:~%~S", 1,
|
||||
input);
|
||||
}
|
||||
AGAIN_OUTPUT:
|
||||
if (output == @':stream') {
|
||||
int fd[2];
|
||||
pipe(fd);
|
||||
parent_read = fd[0];
|
||||
child_stdout = fd[1];
|
||||
} else if (output == @'t') {
|
||||
output = ecl_symbol_value(@'*standard-output*');
|
||||
goto AGAIN_OUTPUT;
|
||||
} else if (Null(output)) {
|
||||
child_stdout = open("/dev/null", O_WRONLY);
|
||||
} else if (!Null(cl_streamp(output))) {
|
||||
child_stdout = ecl_stream_to_handle(output, 1);
|
||||
unlikely_if (child_stdout < 0) {
|
||||
FEerror(":OUTPUT argument to RUN-PROGRAM does not "
|
||||
"have a file handle:~%~S", 1, output);
|
||||
}
|
||||
child_stdout = dup(child_stdout);
|
||||
} else if (ECL_STRINGP(output) || ECL_PATHNAMEP(output)) {
|
||||
output = cl_open(7, output,
|
||||
@':direction', @':output',
|
||||
@':if-exists', if_output_exists,
|
||||
@':if-does-not-exist', @':create');
|
||||
goto AGAIN_OUTPUT;
|
||||
} else {
|
||||
FEerror("Invalid :OUTPUT argument to EXT:RUN-PROGRAM:~%~S", 1,
|
||||
output);
|
||||
}
|
||||
AGAIN_ERROR:
|
||||
if (error == @':output') {
|
||||
child_stderr = child_stdout;
|
||||
} else if (error == @':stream') {
|
||||
int fd[2];
|
||||
pipe(fd);
|
||||
parent_error = fd[0];
|
||||
child_stderr = fd[1];
|
||||
} else if (error == @'t') {
|
||||
error = ecl_symbol_value(@'*error-output*');
|
||||
goto AGAIN_ERROR;
|
||||
} else if (Null(error)) {
|
||||
child_stderr = open("/dev/null", O_WRONLY);
|
||||
} else if (!Null(cl_streamp(error))) {
|
||||
child_stderr = ecl_stream_to_handle(error, 1);
|
||||
unlikely_if (child_stderr < 0) {
|
||||
FEerror(":ERROR argument to RUN-PROGRAM does not "
|
||||
"have a file handle:~%~S", 1, error);
|
||||
}
|
||||
child_stderr = dup(child_stderr);
|
||||
} else if (ECL_STRINGP(error) || ECL_PATHNAMEP(error)) {
|
||||
output = cl_open(7, error,
|
||||
@':direction', @':output',
|
||||
@':if-does-not-exist', @':create');
|
||||
goto AGAIN_ERROR;
|
||||
} else {
|
||||
FEerror("Invalid :ERROR argument to EXT:RUN-PROGRAM:~%~S", 1,
|
||||
error);
|
||||
}
|
||||
|
||||
create_descriptor(input, @':input', &child_stdin, &parent_write);
|
||||
create_descriptor(output, @':output', &child_stdout, &parent_read);
|
||||
create_descriptor(error, @':output', &child_stderr, &parent_error);
|
||||
|
||||
add_external_process(the_env, process);
|
||||
pipe(pipe_fd);
|
||||
child_pid = fork();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue