Skip to content

Commit

Permalink
Fix read console input on windows with codepage support
Browse files Browse the repository at this point in the history
  • Loading branch information
straight-shoota committed Aug 16, 2023
1 parent 9390ee5 commit 13791e2
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 4 deletions.
18 changes: 16 additions & 2 deletions src/crystal/system/win32/file_descriptor.cr
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,22 @@ module Crystal::System::FileDescriptor
@system_blocking = true

private def unbuffered_read(slice : Bytes)
if system_blocking?
handle = windows_handle
if LibC.GetConsoleMode(handle, nil) != 0
u16buffer = Slice(UInt16).new(slice.size)
chars_read = LibC::DWORD.new(0)
if 0 == LibC.ReadConsoleW(handle, u16buffer, u16buffer.size, pointerof(chars_read), nil)
raise IO::Error.from_winerror("Error reading from console")
end

appender = slice.to_unsafe.appender
String.each_utf16_char(u16buffer[0, chars_read]) do |char|
char.each_byte do |byte|
appender << byte
end
end
chars_read
elsif system_blocking?
bytes_read = LibC._read(fd, slice, slice.size)
if bytes_read == -1
if Errno.value == Errno::EBADF
Expand All @@ -22,7 +37,6 @@ module Crystal::System::FileDescriptor
end
bytes_read
else
handle = windows_handle
overlapped_operation(handle, "ReadFile", read_timeout) do |overlapped|
ret = LibC.ReadFile(handle, slice, slice.size, out byte_count, overlapped)
{ret, byte_count}
Expand Down
8 changes: 8 additions & 0 deletions src/lib_c/x86_64-windows-msvc/c/consoleapi.cr
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,14 @@ lib LibC
fun GetConsoleCP : DWORD
fun GetConsoleOutputCP : DWORD

fun ReadConsoleW(
hConsoleInput : HANDLE,
lpBuffer : Void*,
nNumberOfCharsToRead : DWORD,
lpNumberOfCharsRead : DWORD*,
pInputControl : Void*
) : BOOL

CTRL_C_EVENT = 0
CTRL_BREAK_EVENT = 1

Expand Down
8 changes: 6 additions & 2 deletions src/string/utf16.cr
Original file line number Diff line number Diff line change
Expand Up @@ -128,8 +128,10 @@ class String
{string, pointer + 1}
end

# :nodoc:
#
# Yields each decoded char in the given slice.
private def self.each_utf16_char(slice : Slice(UInt16), &)
def self.each_utf16_char(slice : Slice(UInt16), &)
i = 0
while i < slice.size
byte = slice[i].to_i
Expand All @@ -153,8 +155,10 @@ class String
end
end

# :nodoc:
#
# Yields each decoded char in the given pointer, stopping at the first null byte.
private def self.each_utf16_char(pointer : Pointer(UInt16), &) : Pointer(UInt16)
def self.each_utf16_char(pointer : Pointer(UInt16), &) : Pointer(UInt16)
loop do
byte = pointer.value.to_i
break if byte == 0
Expand Down

0 comments on commit 13791e2

Please sign in to comment.