Skip to content

Commit d140425

Browse files
committed
Accept multiple mode arguments
1 parent f06f2d9 commit d140425

2 files changed

Lines changed: 87 additions & 53 deletions

File tree

ext/io/console/console.c

Lines changed: 50 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1914,90 +1914,94 @@ console_ttyname(VALUE io)
19141914
# define console_ttyname rb_f_notimplement
19151915
#endif
19161916

1917-
typedef enum {
1918-
platform_none,
19191917
#ifdef HAVE_RB_PREPEND_MODULE
1920-
platform_any,
1918+
typedef enum {
1919+
platform_default,
19211920
#if defined _WIN32 || defined __CYGWIN__
19221921
platform_cygwin,
19231922
platform_msys,
19241923
#endif
1924+
platform_any,
1925+
1926+
platform_default_bit = 1U << platform_default,
1927+
#if defined _WIN32 || defined __CYGWIN__
1928+
platform_cygwin_bit = 1U << platform_cygwin,
1929+
platform_msys_bit = 1U << platform_msys,
19251930
#endif
1926-
platform_max
1931+
platform_any_bit = (1U << platform_any) - 1 /* all bits */
19271932
} console_platform_t;
19281933

1929-
#ifdef HAVE_RB_PREPEND_MODULE
19301934
/*
19311935
* call-seq:
1932-
* io.tty?([mode]) -> true or false
1936+
* io.tty?([mode, ...]) -> true or false
19331937
*
19341938
* Returns +true+ if the stream is associated with a terminal device (tty),
19351939
* +false+ otherwise.
19361940
*
1937-
* If non-nil +mode+ is given, platform dependent tty is also checked
1938-
* in addition to the default tty.
1941+
* If one or more +type+s are given, returns +true+ if the stream is
1942+
* associated with any of the specified tty types.
19391943
*
1940-
* - +:any+ : Returns +true+ for any known kind of tty.
1944+
* - +:any+ : Returns +true+ for any known kind of tty, including the
1945+
* default tty.
19411946
* - +:cygwin+ : Returns +true+ for cygwin tty, on Windows.
19421947
* - +:msys+ : Returns +true+ for msys2 tty, on Windows.
19431948
*/
19441949
static VALUE
19451950
console_platform_tty_p(int argc, VALUE *argv, VALUE io)
19461951
{
1947-
VALUE ret;
1948-
console_platform_t mode = platform_none;
1952+
VALUE ret = Qfalse;
1953+
int mode = 0;
19491954

1950-
if (rb_check_arity(argc, 0, 1)) {
1951-
VALUE m = argv[0];
1952-
if (!NIL_P(m)) {
1955+
if (argc > 0) {
1956+
int i;
1957+
for (i = 0; i < argc; ++i) {
1958+
VALUE m = argv[i];
1959+
if (NIL_P(m)) continue;
19531960
Check_Type(m, T_SYMBOL);
19541961
if (m == ID2SYM(rb_intern("any"))) {
1955-
mode = platform_any;
1962+
mode |= platform_any_bit;
19561963
}
19571964
#if defined _WIN32 || defined __CYGWIN__
19581965
else if (m == ID2SYM(rb_intern("cygwin"))) {
1959-
mode = platform_cygwin;
1966+
mode |= platform_cygwin_bit;
19601967
}
19611968
else if (m == ID2SYM(rb_intern("msys"))) {
1962-
mode = platform_msys;
1969+
mode |= platform_msys_bit;
19631970
}
19641971
#endif
19651972
else {
19661973
rb_raise(rb_eArgError, "unknown tty type: %+" PRIsVALUE, m);
19671974
}
19681975
}
19691976
}
1970-
ret = rb_call_super(0, 0);
1971-
if (mode != platform_none && !RTEST(ret)) {
1977+
if ((mode & platform_default_bit) || (mode == 0)) {
1978+
ret = rb_call_super(0, 0);
1979+
}
1980+
if ((mode & ~platform_default_bit) && !RTEST(ret)) {
19721981
#if defined _WIN32 || defined __CYGWIN__
1973-
HANDLE h;
1974-
union {
1975-
FILE_NAME_INFO info;
1976-
WCHAR rest[MAX_PATH];
1977-
} buffer;
1978-
WCHAR *const name = buffer.info.FileName;
1979-
const WCHAR *ptr;
1980-
DWORD len;
1981-
1982-
h = (HANDLE)rb_w32_get_osfhandle(GetReadFD(io));
1983-
if (GetFileType(h) != FILE_TYPE_PIPE) return Qfalse;
1984-
if (!GetFileInformationByHandleEx(h, FileNameInfo, &buffer, sizeof(buffer))) return Qfalse;
1985-
len = buffer.info.FileNameLength / sizeof(WCHAR);
1986-
name[len] = L'\0';
1987-
# define skip_platform_tty_prefix(type) \
1988-
(memcmp(name, L"\\" #type "-", sizeof(L"\\" #type)) == 0 ? \
1989-
&name[rb_strlen_lit(L"\\" #type "-")] : 0)
1990-
if (mode == platform_cygwin || mode == platform_any) {
1991-
ptr = skip_platform_tty_prefix(cygwin);
1992-
}
1993-
else if (mode == platform_msys || mode == platform_any) {
1994-
ptr = skip_platform_tty_prefix(msys);
1995-
}
1996-
else {
1997-
return Qfalse;
1982+
if (mode & (platform_cygwin_bit | platform_msys_bit)) {
1983+
struct {
1984+
FILE_NAME_INFO info;
1985+
WCHAR rest[MAX_PATH];
1986+
} buffer;
1987+
1988+
HANDLE h = (HANDLE)rb_w32_get_osfhandle(GetReadFD(io));
1989+
if ((GetFileType(h) == FILE_TYPE_PIPE) &&
1990+
GetFileInformationByHandleEx(h, FileNameInfo, &buffer, sizeof(buffer))) {
1991+
WCHAR *const name = buffer.info.FileName;
1992+
DWORD len = buffer.info.FileNameLength / sizeof(WCHAR);
1993+
name[len] = L'\0';
1994+
# define tty_pipe_p(type) \
1995+
(memcmp(name, L"\\" #type "-", sizeof(L"\\" #type)) == 0 && \
1996+
wcsstr(&name[rb_strlen_lit("\\" #type "-")], L"-pty") != NULL)
1997+
if (!ret && (mode & platform_cygwin_bit)) {
1998+
ret = tty_pipe_p(cygwin);
1999+
}
2000+
if (!ret && (mode & platform_msys_bit)) {
2001+
ret = tty_pipe_p(msys);
2002+
}
2003+
}
19982004
}
1999-
if (!ptr) return Qfalse;
2000-
if (wcsstr(ptr, L"-pty")) ret = Qtrue;
20012005
#endif
20022006
}
20032007
return ret;

test/io/console/test_io_console.rb

Lines changed: 37 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -61,16 +61,32 @@ def test_bad_keyword
6161
end
6262
end
6363

64+
TTY_ENHANCED = IO.instance_method(:tty?).arity != 0
65+
6466
def test_tty?
65-
omit "not supported" if IO.instance_method(:tty?).arity == 0
66-
assert_include([true, false], STDIN.tty?(:any))
67+
pend "not supported" unless TTY_ENHANCED
68+
69+
tty = STDIN.tty?(:any)
70+
assert_include([true, false], tty)
71+
assert_equal(tty, STDIN.tty?(:any, :any))
72+
end
73+
74+
def test_tty_non_tty
75+
pend "not supported" unless TTY_ENHANCED
76+
6777
File.open(IO::NULL) do |f|
78+
assert_not_predicate(f, :tty?)
6879
assert_not_operator(f, :tty?, :any)
80+
assert_not_send([f, :tty?, :any, :any])
81+
82+
assert_raise(TypeError) {f.tty?("any")}
83+
assert_raise(ArgumentError) {f.tty?(:unknown)}
6984
end
7085
end
7186
end
7287

73-
defined?(PTY) and defined?(IO.console) and TestIO_Console.class_eval do
88+
defined?(PTY) and defined?(IO.console) and \
89+
class TestIO_Console
7490
Bug6116 = '[ruby-dev:45309]'
7591

7692
def test_raw
@@ -250,6 +266,19 @@ def test_setecho2
250266
}
251267
end
252268

269+
def test_tty_on_pty
270+
pend "not supported" unless TTY_ENHANCED
271+
272+
helper {|_, s|
273+
assert_predicate(s, :tty?)
274+
assert_operator(s, :tty?, :any)
275+
assert_send([s, :tty?, :any, :any])
276+
277+
assert_raise(TypeError) {s.tty?("any")}
278+
assert_raise(ArgumentError) {s.tty?(:unknown)}
279+
}
280+
end
281+
253282
def test_getpass
254283
run_pty("p IO.console.getpass('> ')") do |r, w|
255284
assert_equal("> ", r.readpartial(10))
@@ -503,7 +532,8 @@ def run_pty(src, n = 1)
503532
end
504533
end
505534

506-
defined?(IO.console) and IO.console and TestIO_Console.class_eval do
535+
defined?(IO.console) and IO.console and \
536+
class TestIO_Console
507537
def test_get_winsize_console
508538
s = IO.console.winsize
509539
assert_kind_of(Array, s)
@@ -613,8 +643,8 @@ def test_noctty
613643
end
614644
end
615645

616-
defined?(IO.console) and IO.console and IO.console.respond_to?(:pressed?) and
617-
TestIO_Console.class_eval do
646+
defined?(IO.console) and IO.console and IO.console.respond_to?(:pressed?) and \
647+
class TestIO_Console
618648
def test_pressed_valid
619649
assert_include([true, false], IO.console.pressed?("HOME"))
620650
assert_include([true, false], IO.console.pressed?(:"HOME"))
@@ -628,7 +658,7 @@ def test_pressed_invalid
628658
end
629659
end
630660

631-
TestIO_Console.class_eval do
661+
class TestIO_Console
632662
def test_stringio_getch
633663
assert_ruby_status %w"--disable=gems -rstringio -rio/console", %q{
634664
abort unless StringIO.method_defined?(:getch)

0 commit comments

Comments
 (0)