Question

Code:

main = do
         putStrLn "4917 Microprocessor\nEnter the Machine Code to be run: "
         inp <- getContents
         putStrLn "The output of the Program is:"
         fState <- ((runStateT _4917) . construct . parse) inp
         args <- getArgs
         if elem "-v" args then putStrLn ("\nFinal state was: " ++ (show . snd) fState) else return ()
         putStrLn "\n================================ RESTART ================================"
         main
        where parse xs = array (0,15) $
                         zip [0..15] $
                         take 16 $
                         map ((makeArbInt 4) . read) (words (filter ((/=)'.') xs)) ++ repeat (makeArbInt 4 0)
              construct xs = Program xs z z z z 0 False
              z = (makeArbInt 4 0)

There's more but this is the relevant part. Basically line 3 needs to be evaluated multiple times but getContents is closing the stdin handle:

4917: <stdin>: hGetContents: illegal operation (handle is closed)

Is there a way to reopen the handle? Or some way of preventing getContents from doing that? (Maybe I'm sending the wrong signal. I'm sending over a Ctrl-D EOF on Linux. Maybe I should use EOT or something instead?)

edit: I've managed to get the desired behaviour but it won't port to windows.

mystdin <- openFile "/dev/tty" ReadMode
inp <- hGetContents mystdin

New question: is there a generic way to portably open a handle to stdin?

Was it helpful?

Solution 3

To open a handle to stdin portably, use hDuplicate function on the existing stdio handle to get a new one:

mystdin <- hDuplicate stdin
inp <- hGetContents mystdin

Make sure never to close the original stdin, so that you can make more duplicates as appropriate. (I'm not sure if this is good Haskell style)

OTHER TIPS

You cannot prevent getContents from closing the file, and a closed file stays closed.

It seems to me that you need some other function. Usually, when you read parts of a file, you know when to stop (end of line, certain bytes on the stream). So yes: If you cannot parse the data that you are reading and detect when it is done, you should use some kind of delimiter (possibly EOT, or an empty line, or special text unlikely to occur in the data like __END__).

Have them enter a blank line to end input:

getContents2 = helper "" where 
  helper str = do
    a <- getLine
    if "" == a then return str
    else helper (str++"\n"++a)

You might also haven them signal the end of the session by entering a single blank line.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top