summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authornobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2014-08-21 08:10:34 +0000
committernobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2014-08-21 08:10:34 +0000
commit43b00d8a118e946e57fae4b6a192d3b0e832cf1e (patch)
treeb2bfaa4fb5df353a13067cc5003c83eaf23c7821
parent4d9de3db0a9c84a8e0cb1564af348df4ed21dff2 (diff)
win32.c: manage reverse video
* win32/win32.c (constat_attr): manage reverse video internally since Windows console window does not manage it. based on the patch by white leaf in [ruby-dev:48483]. [Bug #10158] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@47241 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
-rw-r--r--ChangeLog6
-rw-r--r--ext/-test-/win32/console/attribute.c44
-rw-r--r--ext/-test-/win32/console/depend1
-rw-r--r--ext/-test-/win32/console/extconf.rb8
-rw-r--r--ext/-test-/win32/console/init.c11
-rw-r--r--test/-ext-/win32/test_console_attr.rb44
-rw-r--r--win32/win32.c37
7 files changed, 137 insertions, 14 deletions
diff --git a/ChangeLog b/ChangeLog
index cc0867e71d..d041f3d011 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+Thu Aug 21 17:10:31 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * win32/win32.c (constat_attr): manage reverse video internally
+ since Windows console window does not manage it. based on the
+ patch by white leaf in [ruby-dev:48483]. [Bug #10158]
+
Thu Aug 21 14:45:41 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
* lib/e2mmap.rb: removed commented-out code.
diff --git a/ext/-test-/win32/console/attribute.c b/ext/-test-/win32/console/attribute.c
new file mode 100644
index 0000000000..6b8bd96c49
--- /dev/null
+++ b/ext/-test-/win32/console/attribute.c
@@ -0,0 +1,44 @@
+#include <ruby.h>
+
+static VALUE rb_cConsoleScreenBufferInfo;
+
+static VALUE
+console_info(VALUE io)
+{
+ int fd = NUM2INT(rb_funcallv(io, rb_intern("fileno"), 0, 0));
+ HANDLE h = (HANDLE)rb_w32_get_osfhandle(fd);
+ CONSOLE_SCREEN_BUFFER_INFO csbi;
+
+ if (h == (HANDLE)-1) rb_raise(rb_eIOError, "invalid io");
+ if (!GetConsoleScreenBufferInfo(h, &csbi))
+ rb_syserr_fail(rb_w32_map_errno(GetLastError()), "not console");
+ return rb_struct_new(rb_cConsoleScreenBufferInfo,
+ INT2FIX(csbi.dwSize.X), INT2FIX(csbi.dwSize.Y),
+ INT2FIX(csbi.dwCursorPosition.X), INT2FIX(csbi.dwCursorPosition.Y),
+ INT2FIX(csbi.wAttributes));
+}
+
+#define FOREGROUND_MASK (FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY)
+#define BACKGROUND_MASK (BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_INTENSITY)
+
+void
+Init_attribute(VALUE m)
+{
+ rb_cConsoleScreenBufferInfo = rb_struct_define_under(m, "ConsoleScreenBufferInfo",
+ "size_x", "size_y",
+ "cur_x", "cur_y",
+ "attr", NULL);
+ rb_define_method(rb_cIO, "console_info", console_info, 0);
+
+ rb_define_const(m, "FOREGROUND_MASK", INT2FIX(FOREGROUND_MASK));
+ rb_define_const(m, "FOREGROUND_BLUE", INT2FIX(FOREGROUND_BLUE));
+ rb_define_const(m, "FOREGROUND_GREEN", INT2FIX(FOREGROUND_GREEN));
+ rb_define_const(m, "FOREGROUND_RED", INT2FIX(FOREGROUND_RED));
+ rb_define_const(m, "FOREGROUND_INTENSITY", INT2FIX(FOREGROUND_INTENSITY));
+
+ rb_define_const(m, "BACKGROUND_MASK", INT2FIX(BACKGROUND_MASK));
+ rb_define_const(m, "BACKGROUND_BLUE", INT2FIX(BACKGROUND_BLUE));
+ rb_define_const(m, "BACKGROUND_GREEN", INT2FIX(BACKGROUND_GREEN));
+ rb_define_const(m, "BACKGROUND_RED", INT2FIX(BACKGROUND_RED));
+ rb_define_const(m, "BACKGROUND_INTENSITY", INT2FIX(BACKGROUND_INTENSITY));
+}
diff --git a/ext/-test-/win32/console/depend b/ext/-test-/win32/console/depend
new file mode 100644
index 0000000000..f4f65adf9a
--- /dev/null
+++ b/ext/-test-/win32/console/depend
@@ -0,0 +1 @@
+attribute.o: $(ruby_headers) $(hdrdir)/ruby/win32.h
diff --git a/ext/-test-/win32/console/extconf.rb b/ext/-test-/win32/console/extconf.rb
new file mode 100644
index 0000000000..4de9fa7e4f
--- /dev/null
+++ b/ext/-test-/win32/console/extconf.rb
@@ -0,0 +1,8 @@
+if $mingw or $mswin
+ $srcs = Dir[File.join($srcdir, "*.{#{SRC_EXT.join(%q{,})}}")]
+ inits = $srcs.map {|s| File.basename(s, ".*")}
+ inits.delete("init")
+ inits.map! {|s|"X(#{s})"}
+ $defs << "-DTEST_INIT_FUNCS(X)=\"#{inits.join(' ')}\""
+ create_makefile("-test-/win32/console")
+end
diff --git a/ext/-test-/win32/console/init.c b/ext/-test-/win32/console/init.c
new file mode 100644
index 0000000000..f2e0d1c821
--- /dev/null
+++ b/ext/-test-/win32/console/init.c
@@ -0,0 +1,11 @@
+#include "ruby.h"
+
+#define init(n) {void Init_##n(VALUE m); Init_##n(m);}
+
+void
+Init_console(void)
+{
+ VALUE mBug = rb_define_module("Bug");
+ VALUE m = rb_define_module_under(mBug, "Win32");
+ TEST_INIT_FUNCS(init);
+}
diff --git a/test/-ext-/win32/test_console_attr.rb b/test/-ext-/win32/test_console_attr.rb
new file mode 100644
index 0000000000..6e8f93ab99
--- /dev/null
+++ b/test/-ext-/win32/test_console_attr.rb
@@ -0,0 +1,44 @@
+if /mswin|mingw/ =~ RUBY_PLATFORM and STDOUT.tty?
+ require '-test-/win32/console'
+ require 'io/console'
+ require 'test/unit'
+
+ class Test_Win32Console < Test::Unit::TestCase
+ def setup
+ print "\e[m!"
+ end
+
+ def teardown
+ print "\e[m!"
+ end
+
+ def test_default
+ info = STDOUT.console_info
+ assert_equal(7, info.attr);
+ end
+
+ def test_reverse
+ print "\e[7m"
+ info = STDOUT.console_info
+ assert_equal(0x70, info.attr);
+ end
+
+ def test_bold
+ print "\e[1m"
+ info = STDOUT.console_info
+ assert_equal(0x8, info.attr&0x8);
+ end
+
+ def test_bold_reverse
+ print "\e[1;7m"
+ info = STDOUT.console_info
+ assert_equal(0xf0, info.attr);
+ end
+
+ def test_reverse_bold
+ print "\e[7;1m"
+ info = STDOUT.console_info
+ assert_equal(0xf0, info.attr);
+ end
+ end
+end
diff --git a/win32/win32.c b/win32/win32.c
index 1f0f13e7bb..9e6e6a39c5 100644
--- a/win32/win32.c
+++ b/win32/win32.c
@@ -615,7 +615,7 @@ static char *uenvarea;
/* License: Ruby's */
struct constat {
struct {
- int state, seq[16];
+ int state, seq[16], reverse;
WORD attr;
COORD saved;
} vt100;
@@ -5901,6 +5901,7 @@ constat_handle(HANDLE h)
p = ALLOC(struct constat);
p->vt100.state = constat_init;
p->vt100.attr = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED;
+ p->vt100.reverse = 0;
p->vt100.saved.X = p->vt100.saved.Y = 0;
if (GetConsoleScreenBufferInfo(h, &csbi)) {
p->vt100.attr = csbi.wAttributes;
@@ -5922,16 +5923,26 @@ constat_reset(HANDLE h)
p->vt100.state = constat_init;
}
+#define FOREGROUND_MASK (FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY)
+#define BACKGROUND_MASK (BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_INTENSITY)
+
+#define constat_attr_color_reverse(attr) \
+ (attr) & ~(FOREGROUND_MASK | BACKGROUND_MASK) | \
+ (((attr) & FOREGROUND_MASK) << 4) | \
+ (((attr) & BACKGROUND_MASK) >> 4);
+
/* License: Ruby's */
static WORD
-constat_attr(int count, const int *seq, WORD attr, WORD default_attr)
+constat_attr(int count, const int *seq, WORD attr, WORD default_attr, int *reverse)
{
-#define FOREGROUND_MASK (FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED)
-#define BACKGROUND_MASK (BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED)
- WORD bold = attr & (FOREGROUND_INTENSITY | BACKGROUND_INTENSITY);
- int rev = 0;
+ int rev = *reverse;
+ WORD bold;
if (!count) return attr;
+ if (rev) attr = constat_attr_color_reverse(attr);
+ bold = attr & FOREGROUND_INTENSITY;
+ attr &= ~(FOREGROUND_INTENSITY | BACKGROUND_INTENSITY);
+
while (count-- > 0) {
switch (*seq++) {
case 0:
@@ -5940,7 +5951,7 @@ constat_attr(int count, const int *seq, WORD attr, WORD default_attr)
bold = 0;
break;
case 1:
- bold |= rev ? BACKGROUND_INTENSITY : FOREGROUND_INTENSITY;
+ bold = FOREGROUND_INTENSITY;
break;
case 4:
#ifndef COMMON_LVB_UNDERSCORE
@@ -6010,12 +6021,10 @@ constat_attr(int count, const int *seq, WORD attr, WORD default_attr)
break;
}
}
- if (rev) {
- attr = attr & ~(FOREGROUND_MASK | BACKGROUND_MASK) |
- ((attr & FOREGROUND_MASK) << 4) |
- ((attr & BACKGROUND_MASK) >> 4);
- }
- return attr | bold;
+ attr |= bold;
+ if (rev) attr = constat_attr_color_reverse(attr);
+ *reverse = rev;
+ return attr;
}
/* License: Ruby's */
@@ -6033,7 +6042,7 @@ constat_apply(HANDLE handle, struct constat *s, WCHAR w)
if (count > 0 && seq[0] > 0) arg1 = seq[0];
switch (w) {
case L'm':
- SetConsoleTextAttribute(handle, constat_attr(count, seq, csbi.wAttributes, s->vt100.attr));
+ SetConsoleTextAttribute(handle, constat_attr(count, seq, csbi.wAttributes, s->vt100.attr, &s->vt100.reverse));
break;
case L'F':
csbi.dwCursorPosition.X = 0;