From 12143d90c828bb4142751a6511ce790aac8aca51 Mon Sep 17 00:00:00 2001 From: Regis Caillaud <35006197+Clonkk@users.noreply.github.com> Date: Tue, 27 Oct 2020 08:52:40 +0100 Subject: Add C function dup and dup2 posix to system/io (#15675) * * Add handle to dup and dup2 posix as duplicate and duplicateTo in std/ioutils. * Added small test & changelog entry * Fixed import in tioutils removed when isMainModule * * Nest test inside block. Rename proc var -> let in captureStdout * Renamed tmpfile to iotuils.txt * Added block: # duplicate, duplicateTo * Improved docstring * Clean non-idiomatic code * Added runnable examples * rm 2 trailing space in expected output * Made syntax prettier * Runnable example: file in getTempDir() * Tmp -> Temp * Fixed runnableExamples on windows --- lib/std/ioutils.nim | 85 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 lib/std/ioutils.nim (limited to 'lib/std') diff --git a/lib/std/ioutils.nim b/lib/std/ioutils.nim new file mode 100644 index 000000000..bef61c54a --- /dev/null +++ b/lib/std/ioutils.nim @@ -0,0 +1,85 @@ +when defined(windows): + proc c_dup(oldfd: FileHandle): FileHandle {. + importc: "_dup", header: "".} + proc c_dup2(oldfd: FileHandle, newfd: FileHandle): cint {. + importc: "_dup2", header: "".} +else: + proc c_dup(oldfd: FileHandle): FileHandle{. + importc: "dup", header: "".} + proc c_dup2(oldfd: FileHandle, newfd: FileHandle): cint {. + importc: "dup2", header: "".} + +# when false: +# const SupportIoctlInheritCtl = (defined(linux) or defined(bsd)) and +# not defined(nimscript) +# when SupportIoctlInheritCtl: +# var +# FIOCLEX {.importc, header: "".}: cint +# FIONCLEX {.importc, header: "".}: cint + +## Also defined in std/posix and system/io +proc strerror(errnum: cint): cstring {.importc, header: "".} +when not defined(nimscript): + var errno {.importc, header: "".}: cint ## error variable + +template checkError(ret: cint) = + if ret == -1: + when not defined(nimscript): + raise newException(IOError, $strerror(errno)) + else: + doAssert(false) + +proc duplicate*(oldfd: FileHandle): FileHandle = + ##[ + Return a copy of the file handle `oldfd`. + After a successful return, both `FileHandle` may be used interchangeably. + They refer to the same open file description and share file offset and status flags. + Calls POSIX function `dup` on Posix platform and `_dup` on Windows + ]## + runnableExamples: + # stdoutDuplicate is a copy of stdout FileHandle that points to STDOUT + let stdoutDuplicate = duplicate(stdout.getFileHandle()) + # Writing to stdoutDuplicate will write to stdout + doAssert(stdoutDuplicate != stdout.getFileHandle()) + # On windows, opening a file from a FileHandle does not work + when not defined(windows): + var f : File + let res = open(f, stdoutDuplicate, mode=fmWrite) + let msg = "This is a test message that will be displayed ! \n" + f.write(msg) + # Output "Test" + f.close() + + result = c_dup(oldfd) + checkError(result) + +proc duplicateTo*(oldfd: FileHandle, newfd: FileHandle) = + ##[ + Perform the same task a `duplicate` but instead of using the lowest unused file descriptor + it uses the FileHandle` specified by `newfd`. + Calls POSIX function `dup2` on Posix platform and `_dup2` on Windows. + ]## + runnableExamples: + import os + # Redirect stdout to a file temporarily + let tmpFileName = getTempDir() / "hidden_output.txt" + let stdoutFileno = stdout.getFileHandle() + let stdoutDupFd = duplicate(stdoutFileno) + + # Create a new file + let tmpFile: File = open(tmpFileName, fmAppend) + let tmpFileFd: FileHandle = tmpFile.getFileHandle() + + # stdoutFileno now writes to tmpFile + duplicateTo(tmpFileFd, stdoutFileno) + echo "This is not displayed, but written to tmpFile instead !" + + # Close file & restore stdout + tmpFile.close() + duplicateTo(stdoutDupFd, stdoutFileno) + + # stdout is now restored ! + echo "This is displayed" + + let retValue = c_dup2(oldfd, newfd) + checkError(retValue) -- cgit 1.4.1-2-gfad0