popenhs-1.0.0: System/Posix/POpen.hs
-- popen-like library
--
-- Author : Jens-Ulrik Petersen
-- Created: 16 August 2001
--
-- Version: $Revision: 1.5 $ from $Date: 2001/10/17 07:30:53 $
--
-- Copyright (c) 2001 Jens-Ulrik Holger Petersen
-- (c) The GRASP/AQUA Project, Glasgow University, 1995-1996
--
-- This library is free software; you can redistribute it and/or
-- modify it under the terms of the GNU Library General Public
-- License as published by the Free Software Foundation; either
-- version 2 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
-- Library General Public License for more details.
--
-- Description
--
-- This code is based on runProcess from the hslibs posix
-- library, but internally it uses file descriptors instead
-- of handles and returns the output and error streams
-- lazily as strings as well as the pid of forked process,
-- instead of just IO ().
module System.Posix.POpen (popen, popenEnvDir)
where
import System.Posix.Types (Fd(), ProcessID())
import System.Posix.IO (createPipe, fdToHandle, closeFd, dupTo, stdInput, stdOutput, stdError)
-- import Control.Concurrent (forkIO)
import System.Posix.Process (executeFile)
import System.Directory (setCurrentDirectory)
import System.IO (hGetContents, hPutStr, hClose)
import Data.Maybe (fromJust, isJust)
import Control.Monad (when)
popen :: FilePath -- Command
-> [String] -- Arguments
-> Maybe String -- Input
-> IO (String, String, ProcessID) -- (stdout, stderr, pid)
popen path args inpt =
popenEnvDir path args inpt Nothing Nothing
popenEnvDir :: FilePath -- Command
-> [String] -- Arguments
-> Maybe String -- Input
-> Maybe [(String, String)] -- Environment
-> Maybe FilePath -- Working directory
-- (stdin, stdout, stderr, pid)
-> IO (String, String, ProcessID)
popenEnvDir path args inpt env dir =
do
inr <- if (isJust inpt) then
do
(inr', inw) <- createPipe
hin <- fdToHandle inw
hPutStr hin $ fromJust inpt
hClose hin
return $ Just inr'
else
return Nothing
(outr, outw) <- createPipe
(errr, errw) <- createPipe
-- pid <- forkIO
p <- doTheBusiness inr outw errw
do
-- close other end of pipes in here
when (isJust inr) $
closeFd $ fromJust inr
closeFd outw
closeFd errw
hout <- fdToHandle outr
outstrm <- hGetContents hout
herr <- fdToHandle errr
errstrm <- hGetContents herr
return (outstrm, errstrm, (third p))
where
third (_,_,c) = c
doTheBusiness ::
Maybe Fd -- stdin
-> Fd -- stdout
-> Fd -- stderr
-> IO (String, String, ProcessID) -- (stdout, stderr)
doTheBusiness inr outw errw =
do
maybeChangeWorkingDirectory dir
when (isJust inr) $
dupTo (fromJust inr) stdInput >> return ()
dupTo outw stdOutput
dupTo errw stdError
executeFile path True args env
-- for typing, should never actually run
error "executeFile failed!"
maybeChangeWorkingDirectory :: Maybe FilePath -> IO ()
maybeChangeWorkingDirectory dir =
case dir of
Nothing -> return ()
Just x -> setCurrentDirectory x