Now that we have established (two) ways to handle unicode input in Windows, the
next matter to address is our inability to redirect unicode output to a file.
As a first step let's see how we can handle this in **C (GCC)** :
* For unicode input to work, input has to be **UTF-16LE** encoded. So, for
piping/redirection to work, unicode output also has to be **UTF-16LE** encoded
and, additionally, **cmd** has to be started with the **/ u** switch (as "
**cmd /u**").
* In order to make **fgetws** and **fputws** correctly process **UTF-16LE**
strings, **_setmode(_fileno(stdin, _O_U16TEXT))** and
**_setmode(_fileno(stdout, _O_U16TEXT))** must be used.
* **SetConsoleCP(65001)** and **SetConsoleOutputCP(65001)** are completely
irrelevant and do not affect the result whether present or absent.
* Output redirected to a file will have no **BOM** , so manually selecting
its encoding may be necessary to correctly opening it e.g. using **Notepad**.
Now let's use these findings to work our way in **Nim** :
#console.nim
import strutils
when defined(windows):
import system/widestrs
proc setMode(fd: int, mode: int): int
{.importc: "_setmode", header: "io.h".}
proc fgetws(str: WideCString, numChars: int, stream: File): bool
{.importc, header: "stdio.h".}
proc fputws(str: WideCString, stream: File): int
{.importc, header: "stdio.h".}
discard stdin.getFileHandle.setMode(0x20000) #_O_U16TEXT
discard stdout.getFileHandle.setMode(0x20000) #_O_U16TEXT
proc consoleReadLine*(line: var string): bool =
let buffer = newWideCString("", 256)
result = fgetws(buffer, 256, stdin)
let length = buffer.len
if length > 0 and buffer[length - 1].int == 10: #discard '\n'
buffer[length - 1] = Utf16Char(0)
let buffer2 = newWideCString("", 2) #discard extra '\n' - MinGW-w64
discard fgetws(buffer2, 2, stdin)
line = $buffer
proc consoleReadLine*(): string =
discard consoleReadLine(result)
proc consoleEcho*(x: varargs[string, `$`]) =
discard fputws(x.join.newWideCString, stdout)
else:
proc consoleReadLine*(line: var string): bool =
result = stdin.readLine(line)
proc consoleReadLine*(): string =
result = stdin.readLine
proc consoleEcho*(x: varargs[string, `$`]) =
echo x.join
Run