diff options
author | Andreas Rumpf <rumpf_a@web.de> | 2020-07-20 14:39:27 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-07-20 14:39:27 +0200 |
commit | 70acba7f0d4d73bce941dbd067a00255426bc697 (patch) | |
tree | f4a7c16b731c88974e04be7e1dbe756a7eb3046d /lib | |
parent | 49d4b50fe52f0e961ef367a44be8b1bd79994a03 (diff) | |
parent | 41c97e4b70d8d3b67f9080939790c6b9a64a7e74 (diff) | |
download | Nim-70acba7f0d4d73bce941dbd067a00255426bc697.tar.gz |
readLine: Unicode support for Windows console (#14782)
* readLine: Unicode support for Windows console When input is read from the Windows console, input encoding is UTF16. This is translated internally to UTF8. * readLine: Remove recursive imports * 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.
Diffstat (limited to 'lib')
-rw-r--r-- | lib/system/io.nim | 62 |
1 files changed, 62 insertions, 0 deletions
diff --git a/lib/system/io.nim b/lib/system/io.nim index 0b624de8f..3d5cf981a 100644 --- a/lib/system/io.nim +++ b/lib/system/io.nim @@ -357,6 +357,68 @@ proc readLine*(f: File, line: var TaintedString): bool {.tags: [ReadIOEffect], proc c_memchr(s: pointer, c: cint, n: csize_t): pointer {. importc: "memchr", header: "<string.h>".} + when defined(windows) and not defined(useWinAnsi): + proc readConsole(hConsoleInput: FileHandle, lpBuffer: pointer, + nNumberOfCharsToRead: int32, + lpNumberOfCharsRead: ptr int32, + pInputControl: pointer): int32 {. + 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: "<unistd.h>".} + else: + proc isatty(fildes: FileHandle): cint {. + importc: "_isatty", header: "<io.h>".} + result = isatty(getFileHandle(f)) != 0'i32 + + # this implies the file is open + if f.isatty: + const numberOfCharsToRead = 2048 + var numberOfCharsRead = 0'i32 + var buffer = newWideCString("", numberOfCharsToRead) + if readConsole(getOsFileHandle(f), addr(buffer[0]), + numberOfCharsToRead, addr(numberOfCharsRead), nil) == 0: + 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 + for i in 0..<numberOfCharsRead: + if buffer[i].uint16 == 26: #Ctrl+Z + close(f) #has the same effect as setting EOF + if i == 0: + line = TaintedString("") + return false + numberOfCharsRead = i + break + buffer[numberOfCharsRead] = 0.Utf16Char + when defined(nimv2): + line = TaintedString($toWideCString(buffer)) + else: + line = TaintedString($buffer) + return(true) + var pos = 0 # Use the currently reserved space for a first try |