Cómo capturar (temporalmente) stdout
¿Cómo capturo temporalmente stdout en Nim?
Me gustaría tener una plantilla con la siguiente firma:
template captureStdout(ident: untyped, body: untyped) = discard
De tal manera que este código ( main.nim) se ejecuta sin error:
var msg = "hello"
echo msg & "1"
var s: string
captureStdout(s):
echo msg & "2"
msg = "ciao"
echo msg & "3"
assert s == "hello2\n"
y la salida debe ser:
hello1
ciao3
esfuerzos actuales
actualmente puedo capturar stdout usando un archivo temporal, pero no puedo volver a liberarlo. Hago esto con lo siguiente:
template captureStdout*(ident: untyped, body: untyped) =
discard reopen(stdout, tmpFile, fmWrite)
body
ident = readFile(tmpFile)
con esto se main.nimejecuta sin error de afirmación, pero la salida es solo
hello1
y en tmpFile veo:
hello2
ciao3
Respuestas
Cuando llama reopen, reasigna la variable stdouta una Fileque escribe tmpFile.
Para imprimir la salida al sistema STDOUT, necesita reasignar la variable stdouta una Fileque escribe en su sistema STDOUT.
Por tanto, la respuesta difiere entre Linux y Windows.
Para Linux, la forma de hacer esto es usar la función dup y dup2 C para duplicar el stdoutdescriptor de archivo y usar un archivo diferente (para que pueda restaurar stdout). Dado que dup y dup2 no están system/ioen Nim, necesitaremos tener enlaces unistd.h.
He aquí un ejemplo:
#Create dup handles
proc dup(oldfd: FileHandle): FileHandle {.importc, header: "unistd.h".}
proc dup2(oldfd: FileHandle, newfd: FileHandle): cint {.importc,
header: "unistd.h".}
# Dummy filename
let tmpFileName = "tmpFile.txt"
template captureStdout*(ident: untyped, body: untyped) =
var stdout_fileno = stdout.getFileHandle()
# Duplicate stoud_fileno
var stdout_dupfd = dup(stdout_fileno)
echo stdout_dupfd
# Create a new file
# You can use append strategy if you'd like
var tmp_file: File = open(tmpFileName, fmWrite)
# Get the FileHandle (the file descriptor) of your file
var tmp_file_fd: FileHandle = tmp_file.getFileHandle()
# dup2 tmp_file_fd to stdout_fileno -> writing to stdout_fileno now writes to tmp_file
discard dup2(tmp_file_fd, stdout_fileno)
#
body
# Force flush
tmp_file.flushFile()
# Close tmp
tmp_file.close()
# Read tmp
ident = readFile(tmpFileName)
# Restore stdout
discard dup2(stdout_dupfd, stdout_fileno)
proc main() =
var msg = "hello"
echo msg & "1"
var s: string
captureStdout(s):
echo msg & "2"
msg = "ciao"
echo msg & "3"
echo ">> ", s
assert s == "hello2\n"
when isMainModule:
main()
# Check it works twice
main()