Reputation: 888
I am writing a program that runs an external sub process interactively and I need the contents of the output handle to be output to stdout as soon as it is available. I have tried something like this:
main = do processInfo <- createProcess (proc "ghci" []){std_out = CreatePipe,
std_in = CreatePipe }
case processInfo of
(Just hIn, Just hOut, _, _) -> do mainloop hIn hOut
hClose hIn
hClose hOut
_ -> do error "Unable to start process"
mainloop :: Handle -> Handle -> IO ()
mainloop inh outh =
do ineof <- hIsEOF outh
if ineof
then return ()
else do inpStr <- hGetLine outh
putStrLn inpStr
mainloop inh outh
But this doesn't work since it only recognizes output line by line, so any output on the processes output handle that isn't terminated by a newline doesn't show up. I have tried the same thing with hGetContents but it produces the same result. I have read through the documentation of both System.Process and System.IO and haven't really found anything conclusive.
Upvotes: 5
Views: 1321
Reputation: 111
Buffering is one thing, but you are also using gGetLine
which will wait for a whole line (or end of file). Consider using hGetChar
if you really want to read one character at the time.
And btw, another way of overcoming buffering is to use hFlush
.
Upvotes: 0
Reputation: 5155
hSetBuffering
is what you're looking for, the default (on Unix at least) is line buffering. Use it on the stdin before starting the main loop
hSetBuffering hIn NoBuffering
and optionally also on the output handle if you want to see the results immediately on the output side. Note, however, that disabling buffering can quite drastically decrease performance.
Upvotes: 4
Reputation: 12077
I'm very much a Haskell newbie, but I remember coming across an example recently of processing input character-by-character. Is hSetBuffering possibly what you are looking for?
Upvotes: 2