mirror of
https://github.com/mruby/mruby
synced 2026-06-08 16:11:16 +00:00
Merge pull request #63 from ksss/opt
Enable option :in, :out, :err to IO.popen
This commit is contained in:
+2
-2
@@ -26,11 +26,11 @@ class IO
|
||||
end
|
||||
end
|
||||
|
||||
def self.popen(command, mode = 'r', &block)
|
||||
def self.popen(command, mode = 'r', opts={}, &block)
|
||||
if !self.respond_to?(:_popen)
|
||||
raise NotImplementedError, "popen is not supported on this platform"
|
||||
end
|
||||
io = self._popen(command, mode)
|
||||
io = self._popen(command, mode, opts)
|
||||
return io unless block
|
||||
|
||||
begin
|
||||
|
||||
@@ -264,6 +264,26 @@ mrb_io_alloc(mrb_state *mrb)
|
||||
#endif
|
||||
|
||||
#ifndef _WIN32
|
||||
static int
|
||||
option_to_fd(mrb_state *mrb, mrb_value obj, const char *key)
|
||||
{
|
||||
mrb_value opt = mrb_funcall(mrb, obj, "[]", 1, mrb_symbol_value(mrb_intern_static(mrb, key, strlen(key))));
|
||||
if (mrb_nil_p(opt)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (mrb_type(opt)) {
|
||||
case MRB_TT_DATA: /* IO */
|
||||
return mrb_fixnum(mrb_io_fileno(mrb, opt));
|
||||
case MRB_TT_FIXNUM:
|
||||
return mrb_fixnum(opt);
|
||||
default:
|
||||
mrb_raise(mrb, E_ARGUMENT_ERROR, "wrong exec redirect action");
|
||||
break;
|
||||
}
|
||||
return -1; /* never reached */
|
||||
}
|
||||
|
||||
mrb_value
|
||||
mrb_io_s_popen(mrb_state *mrb, mrb_value klass)
|
||||
{
|
||||
@@ -278,6 +298,7 @@ mrb_io_s_popen(mrb_state *mrb, mrb_value klass)
|
||||
int pw[2] = { -1, -1 };
|
||||
int doexec;
|
||||
int saved_errno;
|
||||
int opt_in, opt_out, opt_err;
|
||||
|
||||
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));
|
||||
@@ -286,6 +307,9 @@ mrb_io_s_popen(mrb_state *mrb, mrb_value klass)
|
||||
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");
|
||||
|
||||
if (flags & FMODE_READABLE) {
|
||||
if (pipe(pr) == -1) {
|
||||
@@ -315,6 +339,15 @@ mrb_io_s_popen(mrb_state *mrb, mrb_value klass)
|
||||
result = mrb_nil_value();
|
||||
switch (pid = fork()) {
|
||||
case 0: /* child */
|
||||
if (opt_in != -1) {
|
||||
dup2(opt_in, 0);
|
||||
}
|
||||
if (opt_out != -1) {
|
||||
dup2(opt_out, 1);
|
||||
}
|
||||
if (opt_err != -1) {
|
||||
dup2(opt_err, 2);
|
||||
}
|
||||
if (flags & FMODE_READABLE) {
|
||||
close(pr[0]);
|
||||
if (pr[1] != 1) {
|
||||
|
||||
+38
@@ -393,6 +393,44 @@ assert('IO.popen') do
|
||||
end
|
||||
end
|
||||
|
||||
assert('IO.popen with in option') do
|
||||
begin
|
||||
IO.pipe do |r, w|
|
||||
w.write 'hello'
|
||||
w.close
|
||||
assert_equal "hello", IO.popen("cat", "r", in: r) { |i| i.read }
|
||||
assert_equal "", r.read
|
||||
end
|
||||
assert_raise(ArgumentError) { IO.popen("hello", "r", in: Object.new) }
|
||||
rescue NotImplementedError => e
|
||||
skip e.message
|
||||
end
|
||||
end
|
||||
|
||||
assert('IO.popen with out option') do
|
||||
begin
|
||||
IO.pipe do |r, w|
|
||||
IO.popen("echo 'hello'", "w", out: w) {}
|
||||
w.close
|
||||
assert_equal "hello\n", r.read
|
||||
end
|
||||
rescue NotImplementedError => e
|
||||
skip e.message
|
||||
end
|
||||
end
|
||||
|
||||
assert('IO.popen with err option') do
|
||||
begin
|
||||
IO.pipe do |r, w|
|
||||
assert_equal "", IO.popen("echo 'hello' 1>&2", "r", err: w) { |i| i.read }
|
||||
w.close
|
||||
assert_equal "hello\n", r.read
|
||||
end
|
||||
rescue NotImplementedError => e
|
||||
skip e.message
|
||||
end
|
||||
end
|
||||
|
||||
assert('IO.read') do
|
||||
# empty file
|
||||
fd = IO.sysopen $mrbtest_io_wfname, "w"
|
||||
|
||||
Reference in New Issue
Block a user