[Haskell-cafe] Intercept stdin in Haskell

Andrew Gibiansky andrew.gibiansky at gmail.com
Mon Jan 6 00:45:32 UTC 2014

You are a saviour!

We'd actually already tried going down this path with takeMVars and
putMVars, but somehow it didn't quite work. Let's see if this works in
practice in IHaskell!

Working program below:

import Control.Concurrent
import Control.Monad
import GHC.IO.Handle
import GHC.IO.Handle.Types
import System.IO
import System.Posix.IO

main = do
  -- Create a pipe using System.Posix and turn it into handles.
  (readEnd, writeEnd) <- createPipe
  newStdin <- fdToHandle readEnd
  stdinInput <- fdToHandle writeEnd

  -- Store old stdin and swap in new stdin.
  oldStdin <- hDuplicate stdin
  hDuplicateTo newStdin stdin

  -- In a separate thread, wait for the read.
  forkIO $ forever $ do
    let FileHandle _ mvar = stdin
    threadDelay $ 200 * 1000
    empty <- isEmptyMVar mvar
    when empty $ do
      putStrLn "Empty!"
      hPutStrLn stdinInput "foo"
      hFlush stdinInput

  putStrLn "Waiting."
  threadDelay $ 3 * 1000 * 1000
  putStrLn "Reading."
  getChar >>= print

On Sun, Jan 5, 2014 at 7:11 PM, John Lato <jwlato at gmail.com> wrote:

> Here's a stupid idea:
> A Handle contains an MVar Handle__, and when a thread calls hGetLine
> stdin, it will take that MVar, attempt to read from the buffered device,
> and then block until there's data available to be read from the device.
>  You could check if the MVar is empty, and if so, assume that something is
> trying to read from stdin and write your input into the device.
> Horrible, unsound hack, I'm sure, but it's all I've got...
> On Sun, Jan 5, 2014 at 3:14 PM, Andrew Gibiansky <
> andrew.gibiansky at gmail.com> wrote:
>> Looks like the excitement was a bit premature. The types work, and in
>> Haskell that often means the program works... but looks like hDupTo relies
>> on the `dup2` of the IODevice class, and attempts to cast one IODevice to
>> another IODevice. Since I'm trying to replace stdin (with IODevice type Fd)
>> with my own IODevice, the cast fails and raises an exception. Practically
>> ClassCastException.... yeesh.
>> On Sun, Jan 5, 2014 at 5:19 PM, Andrew Gibiansky <
>> andrew.gibiansky at gmail.com> wrote:
>>> I think we found a way! (With a *ton* of help from @aavogt - might
>>> actually be more correct to say he found the way :) )
>>> You can use `hDupTo` to change what a Handle points to. You can use
>>> `mkFileHandle` in GHC.IO.Internal to create a new file handle. You can
>>> implement your own IODevice and BufferedIO datatype to give to
>>> `mkFileHandle` instead of using `Fd`. Then, when your "device" is being
>>> read from, you just implement `newBuffer` and `readBuffer` to do whatever
>>> you need them to.
>>> Results pending.
>>> -- Andrew
>>> On Sun, Jan 5, 2014 at 4:14 PM, Donn Cave <donn at avvanta.com> wrote:
>>>> I bet a quarter you can't do it.  You'd need access to the process
>>>> state -
>>>> whether it's blocking for I/O and whether one of the units in the input
>>>> set
>>>> is 0 ("stdin".)  Even if you could get that? you'd have to poll for it,
>>>> which
>>>> would be hideous.
>>>> That's the UNIX I/O model.  I've always found it a little annoying,
>>>> because
>>>> I could do this with the VMS `mailbox' device, analogous to UNIX pipes -
>>>> in various ways a more sophisticated interprocess communication system
>>>> than
>>>> UNIX's.
>>>>         Donn
>>>> _______________________________________________
>>>> Haskell-Cafe mailing list
>>>> Haskell-Cafe at haskell.org
>>>> http://www.haskell.org/mailman/listinfo/haskell-cafe
>> _______________________________________________
>> Haskell-Cafe mailing list
>> Haskell-Cafe at haskell.org
>> http://www.haskell.org/mailman/listinfo/haskell-cafe
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.haskell.org/pipermail/haskell-cafe/attachments/20140105/d07e7f2d/attachment.html>

More information about the Haskell-Cafe mailing list