Comment capturer (temporairement) stdout
Comment capturer temporairement stdout dans Nim?
Je souhaite avoir un modèle avec la signature suivante:
template captureStdout(ident: untyped, body: untyped) = discard
Telle que ce code ( main.nim) s'exécute sans erreur:
var msg = "hello"
echo msg & "1"
var s: string
captureStdout(s):
echo msg & "2"
msg = "ciao"
echo msg & "3"
assert s == "hello2\n"
et la sortie doit être:
hello1
ciao3
efforts actuels
actuellement, je suis capable de capturer stdout à l'aide d'un fichier temporaire, mais je ne suis pas en mesure de relâcher vers stdout. Je fais cela avec ce qui suit:
template captureStdout*(ident: untyped, body: untyped) =
discard reopen(stdout, tmpFile, fmWrite)
body
ident = readFile(tmpFile)
avec ceci main.nims'exécute sans erreur d'assertion mais la sortie est seulement
hello1
et dans tmpFile je vois:
hello2
ciao3
Réponses
Lorsque vous appelez, reopenvous réaffectez la variable stdoutà un Filequi écrit dans tmpFile.
Pour imprimer la sortie sur le système STDOUT, vous devez réaffecter la variable stdoutà un Filequi écrit dans votre système STDOUT.
Par conséquent, la réponse diffère entre Linux et Windows.
Pour Linux, la façon de faire est d'utiliser les fonctions dup et dup2 C pour dupliquer le stdoutdescripteur de fichier et utiliser un fichier différent (afin que vous puissiez restaurer stdout). Puisque, dup et dup2 ne sont pas system/iodans Nim, nous devrons avoir des liaisons unistd.h.
Voici un exemple:
#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()