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 + + * 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 * 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 + +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;