mirror of
https://github.com/mruby/mruby
synced 2026-06-08 16:11:16 +00:00
implement popen on Windows
This commit is contained in:
+121
-7
@@ -29,6 +29,7 @@
|
||||
#define write _write
|
||||
#define lseek _lseek
|
||||
#define isatty _isatty
|
||||
#define WEXITSTATUS(x) (x)
|
||||
#else
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
@@ -70,7 +71,6 @@ io_get_open_fptr(mrb_state *mrb, mrb_value self)
|
||||
return fptr;
|
||||
}
|
||||
|
||||
#if !defined(_WIN32) && !defined(_WIN64)
|
||||
static void
|
||||
io_set_process_status(mrb_state *mrb, pid_t pid, int status)
|
||||
{
|
||||
@@ -91,7 +91,6 @@ io_set_process_status(mrb_state *mrb, pid_t pid, int status)
|
||||
}
|
||||
mrb_gv_set(mrb, mrb_intern_cstr(mrb, "$?"), v);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
mrb_io_modestr_to_flags(mrb_state *mrb, const char *mode)
|
||||
@@ -265,7 +264,6 @@ mrb_io_alloc(mrb_state *mrb)
|
||||
#define NOFILE 64
|
||||
#endif
|
||||
|
||||
#ifndef _WIN32
|
||||
static int
|
||||
option_to_fd(mrb_state *mrb, mrb_value obj, const char *key)
|
||||
{
|
||||
@@ -286,6 +284,7 @@ option_to_fd(mrb_state *mrb, mrb_value obj, const char *key)
|
||||
return -1; /* never reached */
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
mrb_value
|
||||
mrb_io_s_popen(mrb_state *mrb, mrb_value klass)
|
||||
{
|
||||
@@ -420,6 +419,105 @@ mrb_io_s_popen(mrb_state *mrb, mrb_value klass)
|
||||
}
|
||||
return result;
|
||||
}
|
||||
#else
|
||||
mrb_value
|
||||
mrb_io_s_popen(mrb_state *mrb, mrb_value klass)
|
||||
{
|
||||
mrb_value cmd, io, result;
|
||||
mrb_value mode = mrb_str_new_cstr(mrb, "r");
|
||||
mrb_value opt = mrb_hash_new(mrb);
|
||||
|
||||
struct mrb_io *fptr;
|
||||
const char *pname;
|
||||
int pid = 0, flags;
|
||||
STARTUPINFO si;
|
||||
PROCESS_INFORMATION pi;
|
||||
SECURITY_ATTRIBUTES saAttr;
|
||||
|
||||
HANDLE ifd[2];
|
||||
HANDLE ofd[2];
|
||||
|
||||
int doexec;
|
||||
int saved_errno;
|
||||
int opt_in, opt_out, opt_err;
|
||||
|
||||
ifd[0] = INVALID_HANDLE_VALUE;
|
||||
ifd[1] = INVALID_HANDLE_VALUE;
|
||||
ofd[0] = INVALID_HANDLE_VALUE;
|
||||
ofd[1] = INVALID_HANDLE_VALUE;
|
||||
|
||||
mrb_get_args(mrb, "S|SH", &cmd, &mode, &opt);
|
||||
io = mrb_obj_value(mrb_data_object_alloc(mrb, mrb_class_ptr(klass), NULL, &mrb_io_type));
|
||||
|
||||
pname = mrb_string_value_cstr(mrb, &cmd);
|
||||
flags = mrb_io_modestr_to_flags(mrb, mrb_string_value_cstr(mrb, &mode));
|
||||
|
||||
doexec = (strcmp("-", pname) != 0);
|
||||
opt_in = option_to_fd(mrb, opt, "in");
|
||||
opt_out = option_to_fd(mrb, opt, "out");
|
||||
opt_err = option_to_fd(mrb, opt, "err");
|
||||
|
||||
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
|
||||
saAttr.bInheritHandle = TRUE;
|
||||
saAttr.lpSecurityDescriptor = NULL;
|
||||
|
||||
if (flags & FMODE_READABLE) {
|
||||
if (!CreatePipe(&ofd[0], &ofd[1], &saAttr, 0)
|
||||
|| !SetHandleInformation(ofd[0], HANDLE_FLAG_INHERIT, 0)) {
|
||||
mrb_sys_fail(mrb, "pipe");
|
||||
}
|
||||
}
|
||||
|
||||
if (flags & FMODE_WRITABLE) {
|
||||
if (!CreatePipe(&ifd[0], &ifd[1], &saAttr, 0)
|
||||
|| !SetHandleInformation(ifd[1], HANDLE_FLAG_INHERIT, 0)) {
|
||||
mrb_sys_fail(mrb, "pipe");
|
||||
}
|
||||
}
|
||||
|
||||
if (doexec) {
|
||||
ZeroMemory(&pi, sizeof(pi));
|
||||
ZeroMemory(&si, sizeof(si));
|
||||
si.cb = sizeof(si);
|
||||
si.dwFlags |= STARTF_USESHOWWINDOW;
|
||||
si.wShowWindow = SW_HIDE;
|
||||
si.dwFlags |= STARTF_USESTDHANDLES;
|
||||
if (flags & FMODE_READABLE) {
|
||||
si.hStdOutput = ofd[1];
|
||||
si.hStdError = ofd[1];
|
||||
}
|
||||
if (flags & FMODE_WRITABLE) {
|
||||
si.hStdInput = ifd[0];
|
||||
}
|
||||
if (!CreateProcess(
|
||||
NULL, (char*)pname, NULL, NULL,
|
||||
TRUE, CREATE_NEW_PROCESS_GROUP, NULL, NULL, &si, &pi)) {
|
||||
CloseHandle(ifd[0]);
|
||||
CloseHandle(ifd[1]);
|
||||
CloseHandle(ofd[0]);
|
||||
CloseHandle(ofd[1]);
|
||||
mrb_raisef(mrb, E_IO_ERROR, "command not found: %S", cmd);
|
||||
}
|
||||
CloseHandle(pi.hThread);
|
||||
CloseHandle(ifd[0]);
|
||||
CloseHandle(ofd[1]);
|
||||
pid = pi.dwProcessId;
|
||||
}
|
||||
|
||||
mrb_iv_set(mrb, io, mrb_intern_cstr(mrb, "@buf"), mrb_str_new_cstr(mrb, ""));
|
||||
|
||||
fptr = mrb_io_alloc(mrb);
|
||||
fptr->fd = _open_osfhandle((intptr_t)ofd[0], 0);
|
||||
fptr->fd2 = _open_osfhandle((intptr_t)ifd[1], 0);
|
||||
fptr->pid = pid;
|
||||
fptr->readable = ((flags & FMODE_READABLE) != 0);
|
||||
fptr->writable = ((flags & FMODE_WRITABLE) != 0);
|
||||
fptr->sync = 0;
|
||||
|
||||
DATA_TYPE(io) = &mrb_io_type;
|
||||
DATA_PTR(io) = fptr;
|
||||
return io;
|
||||
}
|
||||
#endif
|
||||
|
||||
mrb_value
|
||||
@@ -486,9 +584,9 @@ fptr_finalize(mrb_state *mrb, struct mrb_io *fptr, int quiet)
|
||||
fptr->fd2 = -1;
|
||||
}
|
||||
|
||||
#if !defined(_WIN32) && !defined(_WIN64)
|
||||
if (fptr->pid != 0) {
|
||||
pid_t pid;
|
||||
#if !defined(_WIN32) && !defined(_WIN64)
|
||||
int status;
|
||||
do {
|
||||
pid = waitpid(fptr->pid, &status, 0);
|
||||
@@ -496,10 +594,16 @@ fptr_finalize(mrb_state *mrb, struct mrb_io *fptr, int quiet)
|
||||
if (!quiet && pid == fptr->pid) {
|
||||
io_set_process_status(mrb, pid, status);
|
||||
}
|
||||
#else
|
||||
HANDLE h = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, fptr->pid);
|
||||
DWORD status;
|
||||
if (WaitForSingleObject(h, INFINITE) && GetExitCodeProcess(h, &status))
|
||||
if (!quiet)
|
||||
io_set_process_status(mrb, fptr->pid, (int)status);
|
||||
#endif
|
||||
fptr->pid = 0;
|
||||
/* Note: we don't raise an exception when waitpid(3) fails */
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!quiet && saved_errno != 0) {
|
||||
errno = saved_errno;
|
||||
@@ -735,6 +839,17 @@ mrb_io_close(mrb_state *mrb, mrb_value self)
|
||||
return mrb_nil_value();
|
||||
}
|
||||
|
||||
mrb_value
|
||||
mrb_io_close_write(mrb_state *mrb, mrb_value self)
|
||||
{
|
||||
struct mrb_io *fptr;
|
||||
fptr = io_get_open_fptr(mrb, self);
|
||||
if (close((int)fptr->fd2) == -1) {
|
||||
mrb_sys_fail(mrb, "close");
|
||||
}
|
||||
return mrb_nil_value();
|
||||
}
|
||||
|
||||
mrb_value
|
||||
mrb_io_closed(mrb_state *mrb, mrb_value io)
|
||||
{
|
||||
@@ -1092,10 +1207,8 @@ mrb_init_io(mrb_state *mrb)
|
||||
MRB_SET_INSTANCE_TT(io, MRB_TT_DATA);
|
||||
|
||||
mrb_include_module(mrb, io, mrb_module_get(mrb, "Enumerable")); /* 15.2.20.3 */
|
||||
#ifndef _WIN32
|
||||
mrb_define_class_method(mrb, io, "_popen", mrb_io_s_popen, MRB_ARGS_ANY());
|
||||
mrb_define_class_method(mrb, io, "_sysclose", mrb_io_s_sysclose, MRB_ARGS_REQ(1));
|
||||
#endif
|
||||
mrb_define_class_method(mrb, io, "for_fd", mrb_io_s_for_fd, MRB_ARGS_ANY());
|
||||
mrb_define_class_method(mrb, io, "select", mrb_io_s_select, MRB_ARGS_ANY());
|
||||
mrb_define_class_method(mrb, io, "sysopen", mrb_io_s_sysopen, MRB_ARGS_ANY());
|
||||
@@ -1112,6 +1225,7 @@ mrb_init_io(mrb_state *mrb)
|
||||
mrb_define_method(mrb, io, "sysseek", mrb_io_sysseek, MRB_ARGS_REQ(1));
|
||||
mrb_define_method(mrb, io, "syswrite", mrb_io_syswrite, MRB_ARGS_REQ(1));
|
||||
mrb_define_method(mrb, io, "close", mrb_io_close, MRB_ARGS_NONE()); /* 15.2.20.5.1 */
|
||||
mrb_define_method(mrb, io, "close_write", mrb_io_close_write, MRB_ARGS_NONE());
|
||||
mrb_define_method(mrb, io, "close_on_exec=", mrb_io_set_close_on_exec, MRB_ARGS_REQ(1));
|
||||
mrb_define_method(mrb, io, "close_on_exec?", mrb_io_close_on_exec_p, MRB_ARGS_NONE());
|
||||
mrb_define_method(mrb, io, "closed?", mrb_io_closed, MRB_ARGS_NONE()); /* 15.2.20.5.2 */
|
||||
|
||||
Reference in New Issue
Block a user