diff --git a/spec/std/io/file_descriptor_spec.cr b/spec/std/io/file_descriptor_spec.cr index 4c980faf3ddf..4bf5dc759dd8 100644 --- a/spec/std/io/file_descriptor_spec.cr +++ b/spec/std/io/file_descriptor_spec.cr @@ -83,26 +83,69 @@ describe IO::FileDescriptor do describe "Windows console handle", focus: true do it do IO.pipe do |read, write| - fd = Win32ConsoleDileDescriptor.new(read) - write << "zażółć gęślą jaźń\n".to_utf16 + fd = Win32ConsoleFileDescriptor.new(read.fd) + write.write "zażółć gęślą jaźń\n".to_utf16.unsafe_slice_of(UInt8) fd.gets.should eq "zażółć gęślą jaźń" end end + it "empty" do + IO.pipe do |read, write| + fd = Win32ConsoleFileDescriptor.new(read.fd) + write.close + fd.gets.should eq nil + end + end + + it "read 1 byte" do + IO.pipe do |read, write| + fd = Win32ConsoleFileDescriptor.new(read.fd) + write.write "ż".to_utf16.unsafe_slice_of(UInt8) + fd.gets(1).should eq "\xC5" + end + end + + it "read 2 bytes" do + IO.pipe do |read, write| + fd = Win32ConsoleFileDescriptor.new(read.fd) + write.write "ż".to_utf16.unsafe_slice_of(UInt8) + fd.gets(2).should eq "ż" + end + end + + it "read 3 bytes" do + IO.pipe do |read, write| + fd = Win32ConsoleFileDescriptor.new(read.fd) + write.write "\u{10000}".to_utf16.unsafe_slice_of(UInt8) + fd.gets(3).should eq "\xF0\x90\x80" + end + end + + it "read 4 bytes" do + IO.pipe do |read, write| + fd = Win32ConsoleFileDescriptor.new(read.fd) + write.write "\u{10000}".to_utf16.unsafe_slice_of(UInt8) + fd.gets(4).should eq "\u{10000}" + end + end end {% end %} end {% if flag?(:win32) %} - class Win32ConsoleDileDescriptor < IO::FileDescriptor - private def console_mode? + class Win32ConsoleFileDescriptor < IO::FileDescriptor + private def console_mode?(handle) true end private def read_console(hConsoleInput, lpBuffer, nNumberOfCharsToRead, lpNumberOfCharsRead, pInputControl) - lpNumberOfCharsRead.value = blocking_read(Slice.new(lpBuffer, nNumberOfCharsToRead)) - 0 - rescue + bytesBuffer = lpBuffer[0, nNumberOfCharsToRead].unsafe_slice_of(UInt8) + bytes_read = blocking_read(bytesBuffer) + p! nNumberOfCharsToRead, bytes_read + lpNumberOfCharsRead.value = bytes_read.to_u32 // 2 + p! bytesBuffer[0, bytes_read] 1 + rescue + 0 end end {% end %} diff --git a/src/crystal/system/win32/file_descriptor.cr b/src/crystal/system/win32/file_descriptor.cr index 809aae7b42d3..8afce38ac563 100644 --- a/src/crystal/system/win32/file_descriptor.cr +++ b/src/crystal/system/win32/file_descriptor.cr @@ -17,7 +17,7 @@ module Crystal::System::FileDescriptor @console_units = Slice(UInt16).empty @console_units_buffer : Slice(UInt16)? - private def console_mode? + private def console_mode?(handle) LibC.GetConsoleMode(handle, out _) != 0 end @@ -35,10 +35,10 @@ module Crystal::System::FileDescriptor private def unbuffered_read(slice : Bytes) handle = windows_handle - if console_mode? + if console_mode?(handle) read_console(handle, slice) elsif system_blocking? - blocking_read + blocking_read(slice) else overlapped_operation(handle, "ReadFile", read_timeout) do |overlapped| ret = LibC.ReadFile(handle, slice, slice.size, out byte_count, overlapped) @@ -50,7 +50,7 @@ module Crystal::System::FileDescriptor private def unbuffered_write(slice : Bytes) handle = windows_handle until slice.empty? - if console_mode? + if console_mode?(handle) bytes_written = write_console(handle, slice) elsif system_blocking? bytes_written = LibC._write(fd, slice, slice.size) @@ -326,7 +326,8 @@ module Crystal::System::FileDescriptor units_to_read = slice.size if slice.size < units_to_read # Reads code units from console. - if 0 == read_console(handle, units_buffer + @console_units.size, units_to_read, out units_read, nil) + units_read = uninitialized LibC::DWORD + if 0 == read_console(handle, units_buffer + @console_units.size, units_to_read, pointerof(units_read), nil) raise IO::Error.from_winerror("ReadConsoleW") end return bytes_read if units_read == 0