summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog5
-rw-r--r--ext/io/console/console.c58
-rw-r--r--test/io/console/test_io_console.rb15
3 files changed, 76 insertions, 2 deletions
diff --git a/ChangeLog b/ChangeLog
index b271d94abd1..28c8868bccf 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+Fri Nov 18 16:12:11 2011 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/io/console/console.c (console_cooked, console_set_cooked):
+ new methods to reset cooked mode. [EXPERIMENTAL]
+
Fri Nov 18 13:20:26 2011 NAKAMURA Usaku <usa@ruby-lang.org>
* test/unit/assertions.rb (MINI_DIR): quick dirty hack to get rid of
diff --git a/ext/io/console/console.c b/ext/io/console/console.c
index 1f87a31002b..75f8ed5c945 100644
--- a/ext/io/console/console.c
+++ b/ext/io/console/console.c
@@ -96,8 +96,7 @@ set_rawmode(conmode *t)
{
#ifdef HAVE_CFMAKERAW
cfmakeraw(t);
-#else
-#if defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H
+#elif defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H
t->c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
t->c_oflag &= ~OPOST;
t->c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
@@ -109,6 +108,20 @@ set_rawmode(conmode *t)
#elif defined _WIN32
*t = 0;
#endif
+}
+
+static void
+set_cookedmode(conmode *t)
+{
+#if defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H
+ t->c_iflag |= (BRKINT|ISTRIP|ICRNL|IXON);
+ t->c_oflag |= OPOST;
+ t->c_lflag |= (ECHO|ECHOE|ECHOK|ECHONL|ICANON|ISIG|IEXTEN);
+#elif defined HAVE_SGTTY_H
+ t->sg_flags |= ECHO;
+ t->sg_flags &= ~RAW;
+#elif defined _WIN32
+ *t |= ENABLE_ECHO_INPUT|ENABLE_LINE_INPUT|ENABLE_PROCESSED_INPUT;
#endif
}
@@ -277,6 +290,45 @@ console_set_raw(VALUE io)
return io;
}
+/*
+ * call-seq:
+ * io.cooked {|io| }
+ *
+ * Yields +self+ within cooked mode.
+ *
+ * STDIN.cooked(&:gets)
+ *
+ * will read and return a line with echo back and line editing.
+ */
+static VALUE
+console_cooked(VALUE io)
+{
+ return ttymode(io, rb_yield, set_cookedmode);
+}
+
+/*
+ * call-seq:
+ * io.cooked!
+ *
+ * Enables cooked mode.
+ *
+ * If the terminal mode needs to be back, use io.cooked { ... }.
+ */
+static VALUE
+console_set_cooked(VALUE io)
+{
+ conmode t;
+ rb_io_t *fptr;
+ int fd;
+
+ GetOpenFile(io, fptr);
+ fd = GetReadFD(fptr);
+ if (!getattr(fd, &t)) rb_sys_fail(0);
+ set_cookedmode(&t);
+ if (!setattr(fd, &t)) rb_sys_fail(0);
+ return io;
+}
+
static VALUE
getc_call(VALUE io)
{
@@ -615,6 +667,8 @@ InitVM_console(void)
{
rb_define_method(rb_cIO, "raw", console_raw, 0);
rb_define_method(rb_cIO, "raw!", console_set_raw, 0);
+ rb_define_method(rb_cIO, "cooked", console_cooked, 0);
+ rb_define_method(rb_cIO, "cooked!", console_set_cooked, 0);
rb_define_method(rb_cIO, "getch", console_getch, 0);
rb_define_method(rb_cIO, "echo=", console_set_echo, 1);
rb_define_method(rb_cIO, "echo?", console_echo_p, 0);
diff --git a/test/io/console/test_io_console.rb b/test/io/console/test_io_console.rb
index 34202484152..05ab1a353ec 100644
--- a/test/io/console/test_io_console.rb
+++ b/test/io/console/test_io_console.rb
@@ -19,6 +19,21 @@ class TestIO_Console < Test::Unit::TestCase
}
end
+ def test_cooked
+ helper {|m, s|
+ s.raw {
+ s.print "abc\n"
+ assert_equal("abc\n", m.gets)
+ s.cooked {
+ s.print "def\n"
+ assert_equal("def\r\n", m.gets)
+ }
+ }
+ s.print "ghi\n"
+ assert_equal("ghi\r\n", m.gets)
+ }
+ end
+
def test_echo
helper {|m, s|
assert(s.echo?)