Cara (sementara) menangkap stdout
Bagaimana cara menangkap stdout sementara di Nim?
Saya ingin memiliki template dengan tanda tangan berikut:
template captureStdout(ident: untyped, body: untyped) = discard
Sehingga kode ini ( main.nim) berjalan tanpa kesalahan:
var msg = "hello"
echo msg & "1"
var s: string
captureStdout(s):
echo msg & "2"
msg = "ciao"
echo msg & "3"
assert s == "hello2\n"
dan hasilnya harus:
hello1
ciao3
upaya saat ini
saat ini saya dapat menangkap stdout menggunakan file sementara, tetapi saya tidak dapat merilis kembali ke stdout. Saya melakukan ini dengan yang berikut:
template captureStdout*(ident: untyped, body: untyped) =
discard reopen(stdout, tmpFile, fmWrite)
body
ident = readFile(tmpFile)
dengan ini main.nimberjalan tanpa kesalahan pernyataan tetapi hanya keluaran
hello1
dan di tmpFile saya melihat:
hello2
ciao3
Jawaban
Ketika Anda memanggil reopenAnda menetapkan ulang variabel stdoutke Fileyang menulis ke tmpFile.
Untuk mencetak keluaran ke sistem STDOUT, Anda perlu menetapkan ulang variabel stdoutke a Fileyang menulis ke STDOUT systel Anda.
Oleh karena itu, jawabannya berbeda antara Linux dan Windows.
Untuk Linux, cara melakukannya adalah dengan menggunakan fungsi dup dan dup2 C untuk menggandakan stdoutdeskriptor file dan menggunakan file yang berbeda (sehingga Anda dapat memulihkan stdout). Karena, dup dan dup2 tidak ada system/iodi Nim, kita harus memiliki binding unistd.h.
Berikut contohnya:
#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()