On Feb 26, 2010, at 14:44 , Louis Wasserman wrote:
Is there any way I can temporarily reassign stdout? In particular, will this be handled well by the FFI? I'm hoping there's maybe something like PHP's output buffering thingy. I'm *binding* (not doing a process call) to an external library which outputs directly to stdout, but whose output I'd like to use...
That way lies pain. It can be done, but if it breaks it will break rather thoroughly and leave you stranded. Untested (aside from compilation), no warranty, etc.:
module Redirect (withRedirectedStdout) where
import System.IO
import System.Posix.IO
-- usage: withRedirectedStdout destinationFileName $ yourIOActionHere
-- this might work with Haskell I/O, if you're lucky; don't bet on it
-- stick to FFI calls that use raw I/O
withRedirectedStdout :: FilePath -> IO a -> IO a
withRedirectedStdout f io= do
hFlush stdout
-- style note: should be stdOutput but that doesn't work for the binds
-- and I'm not sure it's worth doing those "right". maybe if someone wants this
-- for the library I'll clean it up
old <- dup 1
closeFd 1
-- this will pattern-match fail if we don't get stdout back; if you manage to trigger it,
-- you get to keep both pieces. (you probably closed stdin, which is usually a
-- recipe for disaster, or at minimum extreme confusion)
1 <- openFd f WriteOnly (Just 0600) (defaultFileFlags {noctty = True, trunc = True, nonBlock = False})
res <- io
closeFd 1
1 <- dup old
closeFd old
return res
Actually, I bet this fails because your FFI function uses C/C++ stdio and doesn't flush it. That will probably require bringing in C stdio's fflush(stdout), which will be even more painful.