console.c: IO.console arguments passing

* ext/io/console/console.c (console_dev): send the given arguments
  to the opened console.  as a special case, do nothing if :close
  is given.
* test/lib/leakchecker.rb (LeakChecker#check_fd_leak): close if
  console.

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@48993 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
nobu 2014-12-25 07:14:12 +00:00
Родитель f0806c4863
Коммит 945e4692ca
4 изменённых файлов: 55 добавлений и 8 удалений

Просмотреть файл

@ -1,3 +1,12 @@
Thu Dec 25 16:14:10 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
* ext/io/console/console.c (console_dev): send the given arguments
to the opened console. as a special case, do nothing if :close
is given.
* test/lib/leakchecker.rb (LeakChecker#check_fd_leak): close if
console.
Thu Dec 25 16:01:19 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
* file.c (rb_file_expand_path_internal): drop characters ignored

Просмотреть файл

@ -77,7 +77,7 @@ getattr(int fd, conmode *t)
#define SET_LAST_ERROR (0)
#endif
static ID id_getc, id_console;
static ID id_getc, id_console, id_close;
typedef struct {
int vmin;
@ -629,27 +629,49 @@ console_ioflush(VALUE io)
/*
* call-seq:
* IO.console -> #<File:/dev/tty>
* IO.console(sym, *args)
*
* Returns an File instance opened console.
*
* If +sym+ is given, it will be sent to the opened console with
* +args+ and the result will be returned instead of the console IO
* itself.
*
* You must require 'io/console' to use this method.
*/
static VALUE
console_dev(VALUE klass)
console_dev(int argc, VALUE *argv, VALUE klass)
{
VALUE con = 0;
rb_io_t *fptr;
VALUE sym = 0;
rb_check_arity(argc, 0, 1);
if (argc) {
Check_Type(sym = argv[0], T_SYMBOL);
--argc;
++argv;
}
if (klass == rb_cIO) klass = rb_cFile;
if (rb_const_defined(klass, id_console)) {
con = rb_const_get(klass, id_console);
if (RB_TYPE_P(con, T_FILE)) {
if ((fptr = RFILE(con)->fptr) && GetReadFD(fptr) != -1)
return con;
if (!RB_TYPE_P(con, T_FILE) ||
(!(fptr = RFILE(con)->fptr) || GetReadFD(fptr) == -1)) {
rb_const_remove(klass, id_console);
con = 0;
}
rb_const_remove(klass, id_console);
}
{
if (sym) {
if (sym == ID2SYM(id_close) && !argc) {
if (con) {
rb_io_close(con);
rb_const_remove(klass, id_console);
con = 0;
}
return Qnil;
}
}
if (!con) {
VALUE args[2];
#if defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H || defined HAVE_SGTTY_H
# define CONSOLE_DEVICE "/dev/tty"
@ -697,6 +719,10 @@ console_dev(VALUE klass)
fptr->mode |= FMODE_SYNC;
rb_const_set(klass, id_console, con);
}
if (sym) {
/* TODO: avoid inadvertent pindown */
return rb_funcall(con, SYM2ID(sym), argc, argv);
}
return con;
}
@ -720,6 +746,7 @@ Init_console(void)
{
id_getc = rb_intern("getc");
id_console = rb_intern("console");
id_close = rb_intern("close");
InitVM(console);
}
@ -739,7 +766,7 @@ InitVM_console(void)
rb_define_method(rb_cIO, "iflush", console_iflush, 0);
rb_define_method(rb_cIO, "oflush", console_oflush, 0);
rb_define_method(rb_cIO, "ioflush", console_ioflush, 0);
rb_define_singleton_method(rb_cIO, "console", console_dev, 0);
rb_define_singleton_method(rb_cIO, "console", console_dev, -1);
{
VALUE mReadable = rb_define_module_under(rb_cIO, "generic_readable");
rb_define_method(mReadable, "getch", io_getch, -1);

Просмотреть файл

@ -222,14 +222,22 @@ class TestIO_Console < Test::Unit::TestCase
IO.console.close
assert_kind_of(IO, IO.console)
assert_nothing_raised(IOError) {IO.console.fileno}
IO.console(:close)
assert(IO.console(:tty?))
ensure
IO.console(:close)
end
def test_sync
assert(IO.console.sync, "console should be unbuffered")
ensure
IO.console(:close)
end
else
def test_close
assert_equal(["true"], run_pty("IO.console.close; p IO.console.fileno >= 0"))
assert_equal(["true"], run_pty("IO.console(:close); p IO.console(:tty?)"))
end
def test_sync

Просмотреть файл

@ -31,6 +31,9 @@ class LeakChecker
def check_fd_leak(test_name)
leaked = false
live1 = @fd_info
if IO.respond_to?(:console)
IO.console(:close)
end
live2 = find_fds
fd_closed = live1 - live2
if !fd_closed.empty?