PAGER without fork&exec too [Feature #16754]

This commit is contained in:
Nobuyoshi Nakada 2020-02-04 11:28:20 +09:00
parent f22c4ff359
commit e6551d835f
Notes: git 2020-04-12 14:58:38 +09:00
3 changed files with 37 additions and 7 deletions

View File

@ -23,6 +23,7 @@ void rb_io_fptr_finalize_internal(void *ptr);
# undef rb_io_fptr_finalize
#endif
#define rb_io_fptr_finalize rb_io_fptr_finalize_internal
VALUE rb_io_popen(VALUE pname, VALUE pmode, VALUE env, VALUE opt);
RUBY_SYMBOL_EXPORT_BEGIN
/* io.c (export) */

24
io.c
View File

@ -6868,6 +6868,8 @@ pipe_close(VALUE io)
return Qnil;
}
static VALUE popen_finish(VALUE port, VALUE klass);
/*
* call-seq:
* IO.popen([env,] cmd, mode="r" [, opt]) -> io
@ -6957,10 +6959,7 @@ pipe_close(VALUE io)
static VALUE
rb_io_s_popen(int argc, VALUE *argv, VALUE klass)
{
const char *modestr;
VALUE pname, pmode = Qnil, port, tmp, opt = Qnil, env = Qnil, execarg_obj = Qnil;
int oflags, fmode;
convconfig_t convconfig;
VALUE pname, pmode = Qnil, opt = Qnil, env = Qnil;
if (argc > 1 && !NIL_P(opt = rb_check_hash_type(argv[argc-1]))) --argc;
if (argc > 1 && !NIL_P(env = rb_check_hash_type(argv[0]))) --argc, ++argv;
@ -6976,6 +6975,16 @@ rb_io_s_popen(int argc, VALUE *argv, VALUE klass)
rb_error_arity(argc + ex, 1 + ex, 2 + ex);
}
}
return popen_finish(rb_io_popen(pname, pmode, env, opt), klass);
}
VALUE
rb_io_popen(VALUE pname, VALUE pmode, VALUE env, VALUE opt)
{
const char *modestr;
VALUE tmp, execarg_obj = Qnil;
int oflags, fmode;
convconfig_t convconfig;
tmp = rb_check_array_type(pname);
if (!NIL_P(tmp)) {
@ -7003,7 +7012,12 @@ rb_io_s_popen(int argc, VALUE *argv, VALUE klass)
rb_io_extract_modeenc(&pmode, 0, opt, &oflags, &fmode, &convconfig);
modestr = rb_io_oflags_modestr(oflags);
port = pipe_open(execarg_obj, modestr, fmode, &convconfig);
return pipe_open(execarg_obj, modestr, fmode, &convconfig);
}
static VALUE
popen_finish(VALUE port, VALUE klass)
{
if (NIL_P(port)) {
/* child */
if (rb_block_given_p()) {

19
ruby.c
View File

@ -1606,12 +1606,12 @@ process_options(int argc, char **argv, ruby_cmdline_options_t *opt)
(argc > 0 && argv && argv[0] ? argv[0] :
origarg.argc > 0 && origarg.argv && origarg.argv[0] ? origarg.argv[0] :
ruby_engine);
#ifdef HAVE_WORKING_FORK
if (opt->dump & DUMP_BIT(help)) {
const char *pager_env = getenv("RUBY_PAGER");
if (!pager_env) pager_env = getenv("PAGER");
if (pager_env && *pager_env && isatty(0) && isatty(1)) {
VALUE pager = rb_str_new_cstr(pager_env);
#ifdef HAVE_WORKING_FORK
int fds[2];
if (rb_pipe(fds) == 0) {
rb_pid_t pid = fork();
@ -1632,9 +1632,24 @@ process_options(int argc, char **argv, ruby_cmdline_options_t *opt)
rb_waitpid(pid, 0, 0);
}
}
}
#else
VALUE port = rb_io_popen(pager, rb_str_new_lit("w"), Qnil, Qnil);
if (!NIL_P(port)) {
int oldout = dup(1);
int olderr = dup(2);
int fd = RFILE(port)->fptr->fd;
dup2(fd, 1);
dup2(fd, 2);
usage(progname, 1);
fflush(stdout);
dup2(oldout, 1);
dup2(olderr, 2);
rb_io_close(port);
return Qtrue;
}
#endif
}
}
usage(progname, (opt->dump & DUMP_BIT(help)));
return Qtrue;
}