content: {-# LANGUAGE CPP,ScopedTypeVariables #-}
  -- 
  -- Copyright (c) 2005 Don Stewart - http://www.cse.unsw.edu.au/~dons
  --
  -- This library is free software; you can redistribute it and/or
  -- modify it under the terms of the GNU Lesser General Public
  -- License as published by the Free Software Foundation; either
  -- version 2.1 of the License, or (at your option) any later version.
  -- 
  -- This library is distributed in the hope that it will be useful,
  -- but WITHOUT ANY WARRANTY; without even the implied warranty of
  -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  -- Lesser General Public License for more details.
  --
  -- You should have received a copy of the GNU Lesser General Public
  -- License along with this library; if not, write to the Free Software
  -- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
  --
  
  -- stolen from Yi
  
  --
  -- | A Posix.popen compatibility mapping.
  -- Based on PosixCompat, originally written by Derek Elkins for lambdabot
  --
  module Test.Framework.Process ( popen, popenShell ) where
  
  import System.IO
  import System.Process
  import System.Exit
  import Control.Concurrent       (forkIO)
  import qualified Control.Exception
  
  -- | Run a command using the shell.
  popenShell :: String        -- ^ Command
             -> Maybe String  -- ^ Content of stdin
             -> IO (String,String,ExitCode)  -- ^ (stdout, stderr, exit code)
  popenShell cmd = popen' $ runInteractiveCommand cmd
  
  -- | Run a command.
  popen :: FilePath         -- ^ Binary
        -> [String]         -- ^ Arguments
        -> Maybe String     -- ^ Content of stdin
        -> IO (String,String,ExitCode)  -- ^ (stdout, stderr, exit code)
  popen file args =
      popen' $ runInteractiveProcess file args Nothing Nothing
  
  popen' :: IO (Handle, Handle, Handle, ProcessHandle)
         -> Maybe String
         -> IO (String,String,ExitCode)
  popen' run minput =
      Control.Exception.handle (\ (e :: Control.Exception.SomeException) ->
                                  return ([],show e,error (show e))) $ do
  
      (inp,out,err,pid) <- run
  
      case minput of
          Just input -> hPutStr inp input >> hClose inp -- importante!
          Nothing    -> return ()
  
      -- Now, grab the input
      output <- hGetContents out
      errput <- hGetContents err
  
      -- SimonM sez:
      --  ... avoids blocking the main thread, but ensures that all the
      --  data gets pulled as it becomes available. you have to force the
      --  output strings before waiting for the process to terminate.
      --
      _ <- forkIO (Control.Exception.evaluate (length output) >> return ())
      _ <- forkIO (Control.Exception.evaluate (length errput) >> return ())
  
      -- And now we wait. We must wait after we read, unsurprisingly.
      ecode <- waitForProcess pid -- blocks without -threaded, you're warned.
  
      -- so what's the point of returning the pid then?
      return (output,errput,ecode)
  
  