From a3b95162499833c17699e0d22c44d3dd09a1ef54 Mon Sep 17 00:00:00 2001 From: ktamp Date: Tue, 23 Jun 2020 23:31:41 +0300 Subject: readLine: Unicode support for Windows console When input is read from the Windows console, input encoding is UTF16. This is translated internally to UTF8. --- lib/system/io.nim | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) (limited to 'lib/system') diff --git a/lib/system/io.nim b/lib/system/io.nim index 482057214..330b67dff 100644 --- a/lib/system/io.nim +++ b/lib/system/io.nim @@ -14,6 +14,11 @@ include inclrtl import std/private/since import formatfloat +when defined(windows) and not defined(useWinAnsi): + import os + import system/widestrs + import terminal + # ----------------- IO Part ------------------------------------------------ type CFile {.importc: "FILE", header: "", @@ -352,6 +357,37 @@ proc readLine*(f: File, line: var TaintedString): bool {.tags: [ReadIOEffect], proc c_memchr(s: pointer, c: cint, n: csize_t): pointer {. importc: "memchr", header: "".} + when defined(windows) and not defined(useWinAnsi): + proc readConsole(hConsoleInput: FileHandle, lpBuffer: pointer, + nNumberOfCharsToRead: uint32, + lpNumberOfCharsRead: ptr uint32, + pInputControl: pointer): int32 {. + stdcall, dynlib: "kernel32", importc: "ReadConsoleW".} + + if f.isatty: + if c_feof(f) < 0: + return false + const numberOfCharsToRead = 2048 + var numberOfCharsRead = 0'u32 + var buffer = newWideCString("", numberOfCharsToRead) + if readConsole(getOsFileHandle(f), addr(buffer[0]), + numberOfCharsToRead, addr(numberOfCharsRead), nil) == 0: + var error = osLastError() + raiseEIO("error: " & $error & " `" & osErrorMsg(error) & "`") + # input always ends with "\r\n" + numberOfCharsRead -= 2 + # handle Ctrl+Z as EOF + for i in 0'u32.. Date: Thu, 25 Jun 2020 00:22:24 +0300 Subject: readLine: Remove recursive imports --- lib/system/io.nim | 41 +++++++++++++++++++++++++++++++---------- 1 file changed, 31 insertions(+), 10 deletions(-) (limited to 'lib/system') diff --git a/lib/system/io.nim b/lib/system/io.nim index 330b67dff..b550b6b7b 100644 --- a/lib/system/io.nim +++ b/lib/system/io.nim @@ -14,11 +14,6 @@ include inclrtl import std/private/since import formatfloat -when defined(windows) and not defined(useWinAnsi): - import os - import system/widestrs - import terminal - # ----------------- IO Part ------------------------------------------------ type CFile {.importc: "FILE", header: "", @@ -362,18 +357,44 @@ proc readLine*(f: File, line: var TaintedString): bool {.tags: [ReadIOEffect], nNumberOfCharsToRead: uint32, lpNumberOfCharsRead: ptr uint32, pInputControl: pointer): int32 {. - stdcall, dynlib: "kernel32", importc: "ReadConsoleW".} + importc: "ReadConsoleW", stdcall, dynlib: "kernel32".} + + proc getLastError(): int32 {. + importc: "GetLastError", stdcall, dynlib: "kernel32", sideEffect.} + + proc formatMessageW(dwFlags: int32, lpSource: pointer, + dwMessageId, dwLanguageId: int32, + lpBuffer: pointer, nSize: int32, + arguments: pointer): int32 {. + importc: "FormatMessageW", stdcall, dynlib: "kernel32".} + proc localFree(p: pointer) {. + importc: "LocalFree", stdcall, dynlib: "kernel32".} + + proc isatty(f: File): bool = + when defined(posix): + proc isatty(fildes: FileHandle): cint {. + importc: "isatty", header: "".} + else: + proc isatty(fildes: FileHandle): cint {. + importc: "_isatty", header: "".} + result = isatty(getFileHandle(f)) != 0'i32 + + # this implies the file is open if f.isatty: - if c_feof(f) < 0: - return false const numberOfCharsToRead = 2048 var numberOfCharsRead = 0'u32 var buffer = newWideCString("", numberOfCharsToRead) if readConsole(getOsFileHandle(f), addr(buffer[0]), numberOfCharsToRead, addr(numberOfCharsRead), nil) == 0: - var error = osLastError() - raiseEIO("error: " & $error & " `" & osErrorMsg(error) & "`") + var error = getLastError() + var errorMsg: string + var msgbuf: WideCString + if formatMessageW(0x00000100 or 0x00001000 or 0x00000200, + nil, error, 0, addr(msgbuf), 0, nil) != 0'i32: + errorMsg = $msgbuf + if msgbuf != nil: localFree(cast[pointer](msgbuf)) + raiseEIO("error: " & $error & " `" & errorMsg & "`") # input always ends with "\r\n" numberOfCharsRead -= 2 # handle Ctrl+Z as EOF -- cgit 1.4.1-2-gfad0 From 41c97e4b70d8d3b67f9080939790c6b9a64a7e74 Mon Sep 17 00:00:00 2001 From: ktamp Date: Fri, 26 Jun 2020 00:31:06 +0300 Subject: readLine: Fix issues with --gc:arc **--gc:arc** defines **nimv2**. This changes the definition of **WideCStringObj**. Also an empty string should be returned in case of EOF. --- lib/system/io.nim | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) (limited to 'lib/system') diff --git a/lib/system/io.nim b/lib/system/io.nim index b550b6b7b..9f12a1767 100644 --- a/lib/system/io.nim +++ b/lib/system/io.nim @@ -354,8 +354,8 @@ proc readLine*(f: File, line: var TaintedString): bool {.tags: [ReadIOEffect], when defined(windows) and not defined(useWinAnsi): proc readConsole(hConsoleInput: FileHandle, lpBuffer: pointer, - nNumberOfCharsToRead: uint32, - lpNumberOfCharsRead: ptr uint32, + nNumberOfCharsToRead: int32, + lpNumberOfCharsRead: ptr int32, pInputControl: pointer): int32 {. importc: "ReadConsoleW", stdcall, dynlib: "kernel32".} @@ -383,7 +383,7 @@ proc readLine*(f: File, line: var TaintedString): bool {.tags: [ReadIOEffect], # this implies the file is open if f.isatty: const numberOfCharsToRead = 2048 - var numberOfCharsRead = 0'u32 + var numberOfCharsRead = 0'i32 var buffer = newWideCString("", numberOfCharsToRead) if readConsole(getOsFileHandle(f), addr(buffer[0]), numberOfCharsToRead, addr(numberOfCharsRead), nil) == 0: @@ -393,20 +393,25 @@ proc readLine*(f: File, line: var TaintedString): bool {.tags: [ReadIOEffect], if formatMessageW(0x00000100 or 0x00001000 or 0x00000200, nil, error, 0, addr(msgbuf), 0, nil) != 0'i32: errorMsg = $msgbuf - if msgbuf != nil: localFree(cast[pointer](msgbuf)) + if msgbuf != nil: + localFree(cast[pointer](msgbuf)) raiseEIO("error: " & $error & " `" & errorMsg & "`") # input always ends with "\r\n" numberOfCharsRead -= 2 # handle Ctrl+Z as EOF - for i in 0'u32..