process (empty) → 1.0.0.0
raw patch · 9 files changed
+1612/−0 lines, 9 filesdep +basedep +directorydep +filepathsetup-changed
Dependencies added: base, directory, filepath, unix
Files
- LICENSE +63/−0
- Setup.hs +6/−0
- System/Cmd.hs +144/−0
- System/Process.hs +328/−0
- System/Process/Internals.hs +422/−0
- cbits/runProcess.c +458/−0
- include/HsProcessConfig.h +83/−0
- include/runProcess.h +74/−0
- process.cabal +34/−0
+ LICENSE view
@@ -0,0 +1,63 @@+This library (libraries/process) is derived from code from two+sources: ++ * Code from the GHC project which is largely (c) The University of+ Glasgow, and distributable under a BSD-style license (see below),++ * Code from the Haskell 98 Report which is (c) Simon Peyton Jones+ and freely redistributable (but see the full license for+ restrictions).++The full text of these licenses is reproduced below. Both of the+licenses are BSD-style or compatible.++-----------------------------------------------------------------------------++The Glasgow Haskell Compiler License++Copyright 2004, The University Court of the University of Glasgow. +All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++- Redistributions of source code must retain the above copyright notice,+this list of conditions and the following disclaimer.+ +- Redistributions in binary form must reproduce the above copyright notice,+this list of conditions and the following disclaimer in the documentation+and/or other materials provided with the distribution.+ +- Neither name of the University nor the names of its contributors may be+used to endorse or promote products derived from this software without+specific prior written permission. ++THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY COURT OF THE UNIVERSITY OF+GLASGOW AND THE CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE+UNIVERSITY COURT OF THE UNIVERSITY OF GLASGOW OR THE CONTRIBUTORS BE LIABLE+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH+DAMAGE.++-----------------------------------------------------------------------------++Code derived from the document "Report on the Programming Language+Haskell 98", is distributed under the following license:++ Copyright (c) 2002 Simon Peyton Jones++ The authors intend this Report to belong to the entire Haskell+ community, and so we grant permission to copy and distribute it for+ any purpose, provided that it is reproduced in its entirety,+ including this Notice. Modified versions of this Report may also be+ copied and distributed for any purpose, provided that the modified+ version is clearly presented as such, and that it does not claim to+ be a definition of the Haskell 98 Language.++-----------------------------------------------------------------------------
+ Setup.hs view
@@ -0,0 +1,6 @@+module Main (main) where++import Distribution.Simple++main :: IO ()+main = defaultMainWithHooks defaultUserHooks
+ System/Cmd.hs view
@@ -0,0 +1,144 @@+-----------------------------------------------------------------------------+-- |+-- Module : System.Cmd+-- Copyright : (c) The University of Glasgow 2001+-- License : BSD-style (see the file libraries/base/LICENSE)+--+-- Maintainer : libraries@haskell.org+-- Stability : provisional+-- Portability : portable+--+-- Executing an external command.+--+-- This module provides a simple interface for executing external commands.+-- For a more complex, but more powerful, interface, see the "System.Process"+-- module.+--+-----------------------------------------------------------------------------++module System.Cmd+ ( system, -- :: String -> IO ExitCode+ rawSystem, -- :: FilePath -> [String] -> IO ExitCode+ ) where++import Prelude++import System.Exit ( ExitCode )++#ifdef __GLASGOW_HASKELL__+import System.Process+import GHC.IOBase ( ioException, IOException(..), IOErrorType(..) )+#if !defined(mingw32_HOST_OS)+import System.Process.Internals+import System.Posix.Signals+#endif+#endif++#ifdef __HUGS__+import Hugs.System+#endif++#ifdef __NHC__+import System (system)+#endif++-- ---------------------------------------------------------------------------+-- system++{-| +Computation @system cmd@ returns the exit code+produced when the operating system processes the command @cmd@.++This computation may fail with++ * @PermissionDenied@: The process has insufficient privileges to+ perform the operation.++ * @ResourceExhausted@: Insufficient resources are available to+ perform the operation.++ * @UnsupportedOperation@: The implementation does not support+ system calls.++On Windows, 'system' is implemented using Windows's native system+call, which ignores the @SHELL@ environment variable, and always+passes the command to the Windows command interpreter (@CMD.EXE@ or+@COMMAND.COM@), hence Unixy shell tricks will not work.+-}+#ifdef __GLASGOW_HASKELL__+system :: String -> IO ExitCode+system "" = ioException (IOError Nothing InvalidArgument "system" "null command" Nothing)+system str = do+#if mingw32_HOST_OS+ p <- runCommand str+ waitForProcess p+#else+ -- The POSIX version of system needs to do some manipulation of signal+ -- handlers. Since we're going to be synchronously waiting for the child,+ -- we want to ignore ^C in the parent, but handle it the default way+ -- in the child (using SIG_DFL isn't really correct, it should be the+ -- original signal handler, but the GHC RTS will have already set up+ -- its own handler and we don't want to use that).+ old_int <- installHandler sigINT Ignore Nothing+ old_quit <- installHandler sigQUIT Ignore Nothing+ (cmd,args) <- commandToProcess str+ p <- runProcessPosix "runCommand" cmd args Nothing Nothing + Nothing Nothing Nothing+ (Just defaultSignal) (Just defaultSignal)+ r <- waitForProcess p+ installHandler sigINT old_int Nothing+ installHandler sigQUIT old_quit Nothing+ return r+#endif /* mingw32_HOST_OS */+#endif /* __GLASGOW_HASKELL__ */++{-|+The computation @'rawSystem' cmd args@ runs the operating system command+@cmd@ in such a way that it receives as arguments the @args@ strings+exactly as given, with no funny escaping or shell meta-syntax expansion.+It will therefore behave more portably between operating systems than 'system'.++The return codes and possible failures are the same as for 'system'.+-}+rawSystem :: String -> [String] -> IO ExitCode+#ifdef __GLASGOW_HASKELL__+rawSystem cmd args = do++#if mingw32_HOST_OS+ p <- runProcess cmd args Nothing Nothing Nothing Nothing Nothing+ waitForProcess p+#else+ old_int <- installHandler sigINT Ignore Nothing+ old_quit <- installHandler sigQUIT Ignore Nothing+ p <- runProcessPosix "rawSystem" cmd args Nothing Nothing + Nothing Nothing Nothing+ (Just defaultSignal) (Just defaultSignal)+ r <- waitForProcess p+ installHandler sigINT old_int Nothing+ installHandler sigQUIT old_quit Nothing+ return r+#endif++#elif !mingw32_HOST_OS+-- crude fallback implementation: could do much better than this under Unix+rawSystem cmd args = system (unwords (map translate (cmd:args)))++translate :: String -> String+translate str = '\'' : foldr escape "'" str+ where escape '\'' = showString "'\\''"+ escape c = showChar c+#else /* mingw32_HOST_OS && ! __GLASGOW_HASKELL__ */+# if __HUGS__+rawSystem cmd args = system (unwords (cmd : map translate args))+# else+rawSystem cmd args = system (unwords (map translate (cmd:args)))+#endif++-- copied from System.Process (qv)+translate :: String -> String+translate str = '"' : snd (foldr escape (True,"\"") str)+ where escape '"' (b, str) = (True, '\\' : '"' : str)+ escape '\\' (True, str) = (True, '\\' : '\\' : str)+ escape '\\' (False, str) = (False, '\\' : str)+ escape c (b, str) = (False, c : str)+#endif
+ System/Process.hs view
@@ -0,0 +1,328 @@+{-# OPTIONS_GHC -cpp -fffi #-}+-----------------------------------------------------------------------------+-- |+-- Module : System.Process+-- Copyright : (c) The University of Glasgow 2004+-- License : BSD-style (see the file libraries/base/LICENSE)+--+-- Maintainer : libraries@haskell.org+-- Stability : experimental+-- Portability : portable+--+-- Operations for creating and interacting with sub-processes.+--+-- For a simpler, but less powerful, interface, see the "System.Cmd" module.+--+-----------------------------------------------------------------------------++-- ToDo:+-- * Flag to control whether exiting the parent also kills the child.+-- * Windows impl of runProcess should close the Handles.+-- * Add system/rawSystem replacements++{- NOTES on createPipe:+ + createPipe is no longer exported, because of the following problems:++ - it wasn't used to implement runInteractiveProcess on Unix, because+ the file descriptors for the unused ends of the pipe need to be closed+ in the child process.++ - on Windows, a special version of createPipe is needed that sets+ the inheritance flags correctly on the ends of the pipe (see+ mkAnonPipe below).+-}++module System.Process (+ -- * Running sub-processes+ ProcessHandle,+ runCommand,+ runProcess,+ runInteractiveCommand,+ runInteractiveProcess,++ -- * Process completion+ waitForProcess,+ getProcessExitCode,+ terminateProcess,+ ) where++import Prelude++import System.Process.Internals++import Foreign+import Foreign.C +import System.IO ( IOMode(..), Handle, hClose )+import System.Exit ( ExitCode(..) )++import System.Posix.Internals+import GHC.IOBase ( FD )+import GHC.Handle ( fdToHandle' )++-- ----------------------------------------------------------------------------+-- runCommand++{- | Runs a command using the shell.+ -}+runCommand+ :: String+ -> IO ProcessHandle++runCommand string = do+ (cmd,args) <- commandToProcess string+#if !defined(mingw32_HOST_OS) && !defined(__MINGW32__)+ runProcessPosix "runCommand" cmd args Nothing Nothing Nothing Nothing Nothing+ Nothing Nothing+#else+ runProcessWin32 "runCommand" cmd [] Nothing Nothing Nothing Nothing Nothing args+#endif++-- ----------------------------------------------------------------------------+-- runProcess++{- | Runs a raw command, optionally specifying 'Handle's from which to+ take the @stdin@, @stdout@ and @stderr@ channels for the new+ process (otherwise these handles are inherited from the current+ process).++ Any 'Handle's passed to 'runProcess' are placed immediately in the + closed state.+-}+runProcess+ :: FilePath -- ^ Filename of the executable+ -> [String] -- ^ Arguments to pass to the executable+ -> Maybe FilePath -- ^ Optional path to the working directory+ -> Maybe [(String,String)] -- ^ Optional environment (otherwise inherit)+ -> Maybe Handle -- ^ Handle to use for @stdin@+ -> Maybe Handle -- ^ Handle to use for @stdout@+ -> Maybe Handle -- ^ Handle to use for @stderr@+ -> IO ProcessHandle++runProcess cmd args mb_cwd mb_env mb_stdin mb_stdout mb_stderr = do+#if !defined(mingw32_HOST_OS) && !defined(__MINGW32__)+ h <- runProcessPosix "runProcess" cmd args mb_cwd mb_env + mb_stdin mb_stdout mb_stderr+ Nothing Nothing+#else+ h <- runProcessWin32 "runProcess" cmd args mb_cwd mb_env + mb_stdin mb_stdout mb_stderr ""+#endif+ maybe (return ()) hClose mb_stdin+ maybe (return ()) hClose mb_stdout+ maybe (return ()) hClose mb_stderr+ return h++-- ----------------------------------------------------------------------------+-- runInteractiveCommand++{- | Runs a command using the shell, and returns 'Handle's that may+ be used to communicate with the process via its @stdin@, @stdout@,+ and @stderr@ respectively.+-}+runInteractiveCommand+ :: String+ -> IO (Handle,Handle,Handle,ProcessHandle)++runInteractiveCommand string = do+ (cmd,args) <- commandToProcess string+#if !defined(mingw32_HOST_OS) && !defined(__MINGW32__)+ runInteractiveProcess1 "runInteractiveCommand" cmd args Nothing Nothing+#else+ runInteractiveProcess1 "runInteractiveCommand" cmd [] Nothing Nothing args+#endif++-- ----------------------------------------------------------------------------+-- runInteractiveProcess++{- | Runs a raw command, and returns 'Handle's that may be used to communicate+ with the process via its @stdin@, @stdout@ and @stderr@ respectively.++ For example, to start a process and feed a string to its stdin:+ +> (inp,out,err,pid) <- runInteractiveProcess "..."+> forkIO (hPutStr inp str)+-}+runInteractiveProcess+ :: FilePath -- ^ Filename of the executable+ -> [String] -- ^ Arguments to pass to the executable+ -> Maybe FilePath -- ^ Optional path to the working directory+ -> Maybe [(String,String)] -- ^ Optional environment (otherwise inherit)+ -> IO (Handle,Handle,Handle,ProcessHandle)++#if !defined(mingw32_HOST_OS) && !defined(__MINGW32__)++runInteractiveProcess cmd args mb_cwd mb_env = + runInteractiveProcess1 "runInteractiveProcess" cmd args mb_cwd mb_env++runInteractiveProcess1 fun cmd args mb_cwd mb_env = do+ withFilePathException cmd $+ alloca $ \ pfdStdInput ->+ alloca $ \ pfdStdOutput ->+ alloca $ \ pfdStdError ->+ maybeWith withCEnvironment mb_env $ \pEnv ->+ maybeWith withCString mb_cwd $ \pWorkDir ->+ withMany withCString (cmd:args) $ \cstrs ->+ withArray0 nullPtr cstrs $ \pargs -> do+ proc_handle <- throwErrnoIfMinus1 fun+ (c_runInteractiveProcess pargs pWorkDir pEnv + pfdStdInput pfdStdOutput pfdStdError)+ hndStdInput <- fdToHandle pfdStdInput WriteMode+ hndStdOutput <- fdToHandle pfdStdOutput ReadMode+ hndStdError <- fdToHandle pfdStdError ReadMode+ ph <- mkProcessHandle proc_handle+ return (hndStdInput, hndStdOutput, hndStdError, ph)++foreign import ccall unsafe "runInteractiveProcess" + c_runInteractiveProcess+ :: Ptr CString+ -> CString+ -> Ptr CString+ -> Ptr FD+ -> Ptr FD+ -> Ptr FD+ -> IO PHANDLE++#else++runInteractiveProcess cmd args mb_cwd mb_env = + runInteractiveProcess1 "runInteractiveProcess" cmd args mb_cwd mb_env ""++runInteractiveProcess1 fun cmd args workDir env extra_cmdline+ = withFilePathException cmd $ do+ let cmdline = translate cmd ++ + concat (map ((' ':) . translate) args) +++ (if null extra_cmdline then "" else ' ':extra_cmdline)+ withCString cmdline $ \pcmdline ->+ alloca $ \ pfdStdInput ->+ alloca $ \ pfdStdOutput ->+ alloca $ \ pfdStdError -> do+ maybeWith withCEnvironment env $ \pEnv -> do+ maybeWith withCString workDir $ \pWorkDir -> do+ proc_handle <- throwErrnoIfMinus1 fun $+ c_runInteractiveProcess pcmdline pWorkDir pEnv+ pfdStdInput pfdStdOutput pfdStdError+ hndStdInput <- fdToHandle pfdStdInput WriteMode+ hndStdOutput <- fdToHandle pfdStdOutput ReadMode+ hndStdError <- fdToHandle pfdStdError ReadMode+ ph <- mkProcessHandle proc_handle+ return (hndStdInput, hndStdOutput, hndStdError, ph)++foreign import ccall unsafe "runInteractiveProcess" + c_runInteractiveProcess+ :: CString + -> CString+ -> Ptr ()+ -> Ptr FD+ -> Ptr FD+ -> Ptr FD+ -> IO PHANDLE++#endif++fdToHandle :: Ptr FD -> IOMode -> IO Handle+fdToHandle pfd mode = do+ fd <- peek pfd+ fdToHandle' fd (Just Stream)+ False{-not a socket-}+ ("fd:" ++ show fd) mode True{-binary-}++-- ----------------------------------------------------------------------------+-- waitForProcess++{- | Waits for the specified process to terminate, and returns its exit code.+ + GHC Note: in order to call @waitForProcess@ without blocking all the+ other threads in the system, you must compile the program with+ @-threaded@.+-}+waitForProcess+ :: ProcessHandle+ -> IO ExitCode+waitForProcess ph = do+ p_ <- withProcessHandle ph $ \p_ -> return (p_,p_)+ case p_ of+ ClosedHandle e -> return e+ OpenHandle h -> do+ -- don't hold the MVar while we call c_waitForProcess...+ -- (XXX but there's a small race window here during which another+ -- thread could close the handle or call waitForProcess)+ code <- throwErrnoIfMinus1 "waitForProcess" (c_waitForProcess h)+ withProcessHandle ph $ \p_ ->+ case p_ of+ ClosedHandle e -> return (p_,e)+ OpenHandle ph -> do+ closePHANDLE ph+ let e = if (code == 0)+ then ExitSuccess+ else (ExitFailure (fromIntegral code))+ return (ClosedHandle e, e)++-- ----------------------------------------------------------------------------+-- terminateProcess++-- | Attempts to terminate the specified process. This function should+-- not be used under normal circumstances - no guarantees are given regarding+-- how cleanly the process is terminated. To check whether the process+-- has indeed terminated, use 'getProcessExitCode'.+--+-- On Unix systems, 'terminateProcess' sends the process the SIGKILL signal.+-- On Windows systems, the Win32 @TerminateProcess@ function is called, passing+-- an exit code of 1.+terminateProcess :: ProcessHandle -> IO ()+terminateProcess ph = do+ withProcessHandle_ ph $ \p_ ->+ case p_ of + ClosedHandle _ -> return p_+ OpenHandle h -> do+ throwErrnoIfMinus1_ "terminateProcess" $ c_terminateProcess h+ return p_+ -- does not close the handle, we might want to try terminating it+ -- again, or get its exit code.++-- ----------------------------------------------------------------------------+-- getProcessExitCode++{- | +This is a non-blocking version of 'waitForProcess'. If the process is+still running, 'Nothing' is returned. If the process has exited, then+@'Just' e@ is returned where @e@ is the exit code of the process.+Subsequent calls to @getProcessExitStatus@ always return @'Just'+'ExitSuccess'@, regardless of what the original exit code was.+-}+getProcessExitCode :: ProcessHandle -> IO (Maybe ExitCode)+getProcessExitCode ph = do+ withProcessHandle ph $ \p_ ->+ case p_ of+ ClosedHandle e -> return (p_, Just e)+ OpenHandle h ->+ alloca $ \pExitCode -> do+ res <- throwErrnoIfMinus1 "getProcessExitCode" $+ c_getProcessExitCode h pExitCode+ code <- peek pExitCode+ if res == 0+ then return (p_, Nothing)+ else do+ closePHANDLE h+ let e | code == 0 = ExitSuccess+ | otherwise = ExitFailure (fromIntegral code)+ return (ClosedHandle e, Just e)++-- ----------------------------------------------------------------------------+-- Interface to C bits++foreign import ccall unsafe "terminateProcess"+ c_terminateProcess+ :: PHANDLE+ -> IO CInt++foreign import ccall unsafe "getProcessExitCode"+ c_getProcessExitCode+ :: PHANDLE+ -> Ptr CInt+ -> IO CInt++foreign import ccall safe "waitForProcess" -- NB. safe - can block+ c_waitForProcess+ :: PHANDLE+ -> IO CInt
+ System/Process/Internals.hs view
@@ -0,0 +1,422 @@+{-# OPTIONS_GHC -cpp -fffi #-}+-----------------------------------------------------------------------------+-- |+-- Module : System.Process.Internals+-- Copyright : (c) The University of Glasgow 2004+-- License : BSD-style (see the file libraries/base/LICENSE)+-- +-- Maintainer : libraries@haskell.org+-- Stability : experimental+-- Portability : portable+--+-- Operations for creating and interacting with sub-processes.+--+-----------------------------------------------------------------------------++-- #hide+module System.Process.Internals (+#ifndef __HUGS__+ ProcessHandle(..), ProcessHandle__(..), + PHANDLE, closePHANDLE, mkProcessHandle, + withProcessHandle, withProcessHandle_,+#endif+#if !defined(mingw32_HOST_OS) && !defined(__MINGW32__)+ pPrPr_disableITimers, c_execvpe,+# ifdef __GLASGOW_HASKELL__+ runProcessPosix,+# endif+ ignoreSignal, defaultSignal,+#else+# ifdef __GLASGOW_HASKELL__+ runProcessWin32, translate,+# endif+#endif+#ifndef __HUGS__+ commandToProcess,+#endif+ withFilePathException, withCEnvironment+ ) where++import Prelude -- necessary to get dependencies right++#if !defined(mingw32_HOST_OS) && !defined(__MINGW32__)+import System.Posix.Types ( CPid )+import System.Posix.Process.Internals ( pPrPr_disableITimers, c_execvpe )+import System.IO ( Handle )+#else+import Data.Word ( Word32 )+import Data.IORef+#endif++import System.Exit ( ExitCode )+import Data.Maybe ( fromMaybe )+# ifdef __GLASGOW_HASKELL__+import GHC.IOBase ( haFD, FD, Exception(..), IOException(..) )+import GHC.Handle ( stdin, stdout, stderr, withHandle_ )+# elif __HUGS__+import Hugs.Exception ( Exception(..), IOException(..) )+# endif++import Control.Concurrent+import Control.Exception ( handle, throwIO )+import Foreign.C+import Foreign++#if defined(mingw32_HOST_OS)+import Control.Monad ( when )+import System.Directory ( doesFileExist )+import Control.Exception ( catchJust, ioErrors )+import System.IO.Error ( isDoesNotExistError, doesNotExistErrorType,+ mkIOError )+import System.Environment ( getEnv )+import System.FilePath+#endif++#ifdef __HUGS__+{-# CFILES cbits/execvpe.c #-}+#endif++#include "HsProcessConfig.h"++#ifndef __HUGS__+-- ----------------------------------------------------------------------------+-- ProcessHandle type++{- | A handle to a process, which can be used to wait for termination+ of the process using 'waitForProcess'.++ None of the process-creation functions in this library wait for+ termination: they all return a 'ProcessHandle' which may be used+ to wait for the process later.+-}+data ProcessHandle__ = OpenHandle PHANDLE | ClosedHandle ExitCode+newtype ProcessHandle = ProcessHandle (MVar ProcessHandle__)++withProcessHandle+ :: ProcessHandle + -> (ProcessHandle__ -> IO (ProcessHandle__, a))+ -> IO a+withProcessHandle (ProcessHandle m) io = modifyMVar m io++withProcessHandle_+ :: ProcessHandle + -> (ProcessHandle__ -> IO ProcessHandle__)+ -> IO ()+withProcessHandle_ (ProcessHandle m) io = modifyMVar_ m io++#if !defined(mingw32_HOST_OS) && !defined(__MINGW32__)++type PHANDLE = CPid++mkProcessHandle :: PHANDLE -> IO ProcessHandle+mkProcessHandle p = do+ m <- newMVar (OpenHandle p)+ return (ProcessHandle m)++closePHANDLE :: PHANDLE -> IO ()+closePHANDLE _ = return ()++#else++type PHANDLE = Word32++-- On Windows, we have to close this HANDLE when it is no longer required,+-- hence we add a finalizer to it, using an IORef as the box on which to+-- attach the finalizer.+mkProcessHandle :: PHANDLE -> IO ProcessHandle+mkProcessHandle h = do+ m <- newMVar (OpenHandle h)+ addMVarFinalizer m (processHandleFinaliser m)+ return (ProcessHandle m)++processHandleFinaliser m =+ modifyMVar_ m $ \p_ -> do + case p_ of+ OpenHandle ph -> closePHANDLE ph+ _ -> return ()+ return (error "closed process handle")++closePHANDLE :: PHANDLE -> IO ()+closePHANDLE ph = c_CloseHandle ph++foreign import stdcall unsafe "CloseHandle"+ c_CloseHandle+ :: PHANDLE+ -> IO ()+#endif+#endif /* !__HUGS__ */++-- ----------------------------------------------------------------------------++#if !defined(mingw32_HOST_OS) && !defined(__MINGW32__)++#ifdef __GLASGOW_HASKELL__+-- -----------------------------------------------------------------------------+-- POSIX runProcess with signal handling in the child++runProcessPosix+ :: String+ -> FilePath -- ^ Filename of the executable+ -> [String] -- ^ Arguments to pass to the executable+ -> Maybe FilePath -- ^ Optional path to the working directory+ -> Maybe [(String,String)] -- ^ Optional environment (otherwise inherit)+ -> Maybe Handle -- ^ Handle to use for @stdin@+ -> Maybe Handle -- ^ Handle to use for @stdout@+ -> Maybe Handle -- ^ Handle to use for @stderr@+ -> Maybe CLong -- handler for SIGINT+ -> Maybe CLong -- handler for SIGQUIT+ -> IO ProcessHandle++runProcessPosix fun cmd args mb_cwd mb_env mb_stdin mb_stdout mb_stderr+ mb_sigint mb_sigquit+ = withFilePathException cmd $ do+ fd_stdin <- withHandle_ fun (fromMaybe stdin mb_stdin) $ return . haFD+ fd_stdout <- withHandle_ fun (fromMaybe stdout mb_stdout) $ return . haFD+ fd_stderr <- withHandle_ fun (fromMaybe stderr mb_stderr) $ return . haFD+ -- some of these might refer to the same Handle, so don't do+ -- nested withHandle_'s (that will deadlock).+ maybeWith withCEnvironment mb_env $ \pEnv -> do+ maybeWith withCString mb_cwd $ \pWorkDir -> do+ withMany withCString (cmd:args) $ \cstrs -> do+ let (set_int, inthand) + = case mb_sigint of+ Nothing -> (0, 0)+ Just hand -> (1, hand)+ (set_quit, quithand) + = case mb_sigquit of+ Nothing -> (0, 0)+ Just hand -> (1, hand)+ withArray0 nullPtr cstrs $ \pargs -> do+ ph <- throwErrnoIfMinus1 fun $+ c_runProcess pargs pWorkDir pEnv + fd_stdin fd_stdout fd_stderr+ set_int inthand set_quit quithand+ mkProcessHandle ph++foreign import ccall unsafe "runProcess" + c_runProcess+ :: Ptr CString -- args+ -> CString -- working directory (or NULL)+ -> Ptr CString -- env (or NULL)+ -> FD -- stdin+ -> FD -- stdout+ -> FD -- stderr+ -> CInt -- non-zero: set child's SIGINT handler+ -> CLong -- SIGINT handler+ -> CInt -- non-zero: set child's SIGQUIT handler+ -> CLong -- SIGQUIT handler+ -> IO PHANDLE++#endif /* __GLASGOW_HASKELL__ */++ignoreSignal = CONST_SIG_IGN :: CLong+defaultSignal = CONST_SIG_DFL :: CLong++#else++#ifdef __GLASGOW_HASKELL__++runProcessWin32 fun cmd args mb_cwd mb_env+ mb_stdin mb_stdout mb_stderr extra_cmdline+ = withFilePathException cmd $ do+ fd_stdin <- withHandle_ fun (fromMaybe stdin mb_stdin) $ return . haFD+ fd_stdout <- withHandle_ fun (fromMaybe stdout mb_stdout) $ return . haFD+ fd_stderr <- withHandle_ fun (fromMaybe stderr mb_stderr) $ return . haFD+ -- some of these might refer to the same Handle, so don't do+ -- nested withHandle_'s (that will deadlock).+ maybeWith withCEnvironment mb_env $ \pEnv -> do+ maybeWith withCString mb_cwd $ \pWorkDir -> do+ let cmdline = translate cmd ++ + concat (map ((' ':) . translate) args) +++ (if null extra_cmdline then "" else ' ':extra_cmdline)+ withCString cmdline $ \pcmdline -> do+ proc_handle <- throwErrnoIfMinus1 fun+ (c_runProcess pcmdline pWorkDir pEnv + fd_stdin fd_stdout fd_stderr)+ mkProcessHandle proc_handle++foreign import ccall unsafe "runProcess" + c_runProcess+ :: CString+ -> CString+ -> Ptr ()+ -> FD+ -> FD+ -> FD+ -> IO PHANDLE++-- ------------------------------------------------------------------------+-- Passing commands to the OS on Windows++{-+On Windows this is tricky. We use CreateProcess, passing a single+command-line string (lpCommandLine) as its argument. (CreateProcess+is well documented on http://msdn.microsoft.com.)++ - It parses the beginning of the string to find the command. If the+ file name has embedded spaces, it must be quoted, using double+ quotes thus + "foo\this that\cmd" arg1 arg2++ - The invoked command can in turn access the entire lpCommandLine string,+ and the C runtime does indeed do so, parsing it to generate the + traditional argument vector argv[0], argv[1], etc. It does this+ using a complex and arcane set of rules which are described here:+ + http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vccelng/htm/progs_12.asp++ (if this URL stops working, you might be able to find it by+ searching for "Parsing C Command-Line Arguments" on MSDN. Also,+ the code in the Microsoft C runtime that does this translation+ is shipped with VC++).++Our goal in runProcess is to take a command filename and list of+arguments, and construct a string which inverts the translatsions+described above, such that the program at the other end sees exactly+the same arguments in its argv[] that we passed to rawSystem.++This inverse translation is implemented by 'translate' below.++Here are some pages that give informations on Windows-related +limitations and deviations from Unix conventions:++ http://support.microsoft.com/default.aspx?scid=kb;en-us;830473+ Command lines and environment variables effectively limited to 8191 + characters on Win XP, 2047 on NT/2000 (probably even less on Win 9x):++ http://www.microsoft.com/windowsxp/home/using/productdoc/en/default.asp?url=/WINDOWSXP/home/using/productdoc/en/percent.asp+ Command-line substitution under Windows XP. IIRC these facilities (or at + least a large subset of them) are available on Win NT and 2000. Some + might be available on Win 9x.++ http://www.microsoft.com/windowsxp/home/using/productdoc/en/default.asp?url=/WINDOWSXP/home/using/productdoc/en/Cmd.asp+ How CMD.EXE processes command lines.+++Note: CreateProcess does have a separate argument (lpApplicationName)+with which you can specify the command, but we have to slap the+command into lpCommandLine anyway, so that argv[0] is what a C program+expects (namely the application name). So it seems simpler to just+use lpCommandLine alone, which CreateProcess supports.+-}++-- Translate command-line arguments for passing to CreateProcess().+translate :: String -> String+translate str = '"' : snd (foldr escape (True,"\"") str)+ where escape '"' (b, str) = (True, '\\' : '"' : str)+ escape '\\' (True, str) = (True, '\\' : '\\' : str)+ escape '\\' (False, str) = (False, '\\' : str)+ escape c (b, str) = (False, c : str)+ -- See long comment above for what this function is trying to do.+ --+ -- The Bool passed back along the string is True iff the+ -- rest of the string is a sequence of backslashes followed by+ -- a double quote.++#endif /* __GLASGOW_HASKELL__ */++#endif++#ifndef __HUGS__+-- ----------------------------------------------------------------------------+-- commandToProcess++{- | Turns a shell command into a raw command. Usually this involves+ wrapping it in an invocation of the shell.++ There's a difference in the signature of commandToProcess between+ the Windows and Unix versions. On Unix, exec takes a list of strings,+ and we want to pass our command to /bin/sh as a single argument. ++ On Windows, CreateProcess takes a single string for the command,+ which is later decomposed by cmd.exe. In this case, we just want+ to prepend @\"c:\WINDOWS\CMD.EXE \/c\"@ to our command line. The+ command-line translation that we normally do for arguments on+ Windows isn't required (or desirable) here.+-}++#if !defined(mingw32_HOST_OS) && !defined(__MINGW32__)++commandToProcess+ :: String+ -> IO (FilePath,[String])+commandToProcess string = return ("/bin/sh", ["-c", string])++#else++commandToProcess+ :: String+ -> IO (FilePath,String)+commandToProcess string = do+ cmd <- findCommandInterpreter+ return (cmd, "/c "++string)+ -- We don't want to put the cmd into a single+ -- argument, because cmd.exe will not try to split it up. Instead,+ -- we just tack the command on the end of the cmd.exe command line,+ -- which partly works. There seem to be some quoting issues, but+ -- I don't have the energy to find+fix them right now (ToDo). --SDM+ -- (later) Now I don't know what the above comment means. sigh.++-- Find CMD.EXE (or COMMAND.COM on Win98). We use the same algorithm as+-- system() in the VC++ CRT (Vc7/crt/src/system.c in a VC++ installation).+findCommandInterpreter :: IO FilePath+findCommandInterpreter = do+ -- try COMSPEC first+ catchJust ioErrors (getEnv "COMSPEC") $ \e -> do+ when (not (isDoesNotExistError e)) $ ioError e++ -- try to find CMD.EXE or COMMAND.COM+ {-+ XXX We used to look at _osver (using cbits) and pick which shell to+ use with+ let filename | osver .&. 0x8000 /= 0 = "command.com"+ | otherwise = "cmd.exe"+ We ought to use GetVersionEx instead, but for now we just look for+ either filename+ -}+ path <- getEnv "PATH"+ let+ -- use our own version of System.Directory.findExecutable, because+ -- that assumes the .exe suffix.+ search :: [FilePath] -> IO (Maybe FilePath)+ search [] = return Nothing+ search (d:ds) = do+ let path1 = d </> "cmd.exe"+ path2 = d </> "command.com"+ b1 <- doesFileExist path1+ b2 <- doesFileExist path2+ if b1 then return (Just path1)+ else if b2 then return (Just path2)+ else search ds+ --+ mb_path <- search (splitSearchPath path)++ case mb_path of+ Nothing -> ioError (mkIOError doesNotExistErrorType + "findCommandInterpreter" Nothing Nothing)+ Just cmd -> return cmd+#endif++#endif /* __HUGS__ */++-- ----------------------------------------------------------------------------+-- Utils++withFilePathException :: FilePath -> IO a -> IO a+withFilePathException fpath act = handle mapEx act+ where+ mapEx (IOException (IOError h iot fun str _)) = ioError (IOError h iot fun str (Just fpath))+ mapEx e = throwIO e++#if !defined(mingw32_HOST_OS) && !defined(__MINGW32__)+withCEnvironment :: [(String,String)] -> (Ptr CString -> IO a) -> IO a+withCEnvironment env act =+ let env' = map (\(name, val) -> name ++ ('=':val)) env + in withMany withCString env' (\pEnv -> withArray0 nullPtr pEnv act)+#else+withCEnvironment :: [(String,String)] -> (Ptr () -> IO a) -> IO a+withCEnvironment env act =+ let env' = foldr (\(name, val) env -> name ++ ('=':val)++'\0':env) "\0" env + in withCString env' (act . castPtr)+#endif+
+ cbits/runProcess.c view
@@ -0,0 +1,458 @@+/* ----------------------------------------------------------------------------+ (c) The University of Glasgow 2004+ + Support for System.Process+ ------------------------------------------------------------------------- */++/* XXX This is a nasty hack; should put everything necessary in this package */+#include "HsBase.h"++#include "runProcess.h"++#if !(defined(_MSC_VER) || defined(__MINGW32__) || defined(_WIN32))++#include "execvpe.h"++/* ----------------------------------------------------------------------------+ UNIX versions+ ------------------------------------------------------------------------- */++ProcHandle+runProcess (char *const args[], char *workingDirectory, char **environment, + int fdStdInput, int fdStdOutput, int fdStdError,+ int set_inthandler, long inthandler, + int set_quithandler, long quithandler)+{+ int pid;+ struct sigaction dfl;++ switch(pid = fork())+ {+ case -1:+ return -1;+ + case 0:+ {+ pPrPr_disableITimers();+ + if (workingDirectory) {+ if (chdir (workingDirectory) < 0) {+ // See #1593. The convention for the exit code when+ // exec() fails seems to be 127 (gleened from C's+ // system()), but there's no equivalent convention for+ // chdir(), so I'm picking 126 --SimonM.+ _exit(126);+ }+ }+ + /* Set the SIGINT/SIGQUIT signal handlers in the child, if requested + */+ (void)sigemptyset(&dfl.sa_mask);+ dfl.sa_flags = 0;+ if (set_inthandler) {+ dfl.sa_handler = (void *)inthandler;+ (void)sigaction(SIGINT, &dfl, NULL);+ }+ if (set_quithandler) {+ dfl.sa_handler = (void *)quithandler;+ (void)sigaction(SIGQUIT, &dfl, NULL);+ }++ dup2 (fdStdInput, STDIN_FILENO);+ dup2 (fdStdOutput, STDOUT_FILENO);+ dup2 (fdStdError, STDERR_FILENO);+ + if (environment) {+ execvpe(args[0], args, environment);+ } else {+ execvp(args[0], args);+ }+ }+ _exit(127);+ }+ + return pid;+}++ProcHandle+runInteractiveProcess (char *const args[], + char *workingDirectory, char **environment,+ int *pfdStdInput, int *pfdStdOutput, int *pfdStdError)+{+ int pid;+ int fdStdInput[2], fdStdOutput[2], fdStdError[2];++ pipe(fdStdInput);+ pipe(fdStdOutput);+ pipe(fdStdError);++ switch(pid = fork())+ {+ case -1:+ close(fdStdInput[0]);+ close(fdStdInput[1]);+ close(fdStdOutput[0]);+ close(fdStdOutput[1]);+ close(fdStdError[0]);+ close(fdStdError[1]);+ return -1;+ + case 0:+ {+ pPrPr_disableITimers();+ + if (workingDirectory) {+ if (chdir (workingDirectory) < 0) {+ // See #1593. The convention for the exit code when+ // exec() fails seems to be 127 (gleened from C's+ // system()), but there's no equivalent convention for+ // chdir(), so I'm picking 126 --SimonM.+ _exit(126);+ }+ }+ + if (fdStdInput[0] != STDIN_FILENO) {+ dup2 (fdStdInput[0], STDIN_FILENO);+ close(fdStdInput[0]);+ }++ if (fdStdOutput[1] != STDOUT_FILENO) {+ dup2 (fdStdOutput[1], STDOUT_FILENO);+ close(fdStdOutput[1]);+ }++ if (fdStdError[1] != STDERR_FILENO) {+ dup2 (fdStdError[1], STDERR_FILENO);+ close(fdStdError[1]);+ }+ + close(fdStdInput[1]);+ close(fdStdOutput[0]);+ close(fdStdError[0]);+ + /* the child */+ if (environment) {+ execvpe(args[0], args, environment);+ } else {+ execvp(args[0], args);+ }+ }+ _exit(127);+ + default:+ close(fdStdInput[0]);+ close(fdStdOutput[1]);+ close(fdStdError[1]);+ + *pfdStdInput = fdStdInput[1];+ *pfdStdOutput = fdStdOutput[0];+ *pfdStdError = fdStdError[0];+ break;+ }+ + return pid;+}++int+terminateProcess (ProcHandle handle)+{+ return (kill(handle, SIGTERM) == 0);+}++int+getProcessExitCode (ProcHandle handle, int *pExitCode)+{+ int wstat, res;+ + *pExitCode = 0;+ + if ((res = waitpid(handle, &wstat, WNOHANG)) > 0)+ {+ if (WIFEXITED(wstat))+ {+ *pExitCode = WEXITSTATUS(wstat);+ return 1;+ }+ else+ if (WIFSIGNALED(wstat))+ {+ errno = EINTR;+ return -1;+ }+ else+ {+ /* This should never happen */+ }+ }+ + if (res == 0) return 0;++ if (errno == ECHILD) + {+ *pExitCode = 0;+ return 1;+ }++ return -1;+}++int waitForProcess (ProcHandle handle)+{+ int wstat;+ + while (waitpid(handle, &wstat, 0) < 0)+ {+ if (errno != EINTR)+ {+ return -1;+ }+ }+ + if (WIFEXITED(wstat))+ return WEXITSTATUS(wstat);+ else+ if (WIFSIGNALED(wstat))+ {+ return wstat;+ }+ else+ {+ /* This should never happen */+ }+ + return -1;+}++#else+/* ----------------------------------------------------------------------------+ Win32 versions+ ------------------------------------------------------------------------- */++/* -------------------- WINDOWS VERSION --------------------- */++/*+ * Function: mkAnonPipe+ *+ * Purpose: create an anonymous pipe with read and write ends being+ * optionally (non-)inheritable.+ */+static BOOL+mkAnonPipe (HANDLE* pHandleIn, BOOL isInheritableIn, + HANDLE* pHandleOut, BOOL isInheritableOut)+{+ HANDLE hTemporaryIn = NULL;+ HANDLE hTemporaryOut = NULL;+ BOOL status;+ SECURITY_ATTRIBUTES sec_attrs;++ /* Create inheritable security attributes */+ sec_attrs.nLength = sizeof(SECURITY_ATTRIBUTES);+ sec_attrs.lpSecurityDescriptor = NULL;+ sec_attrs.bInheritHandle = TRUE;++ /* Create the anon pipe with both ends inheritable */+ if (!CreatePipe(&hTemporaryIn, &hTemporaryOut, &sec_attrs, 0))+ {+ maperrno();+ *pHandleIn = NULL;+ *pHandleOut = NULL;+ return FALSE;+ }++ if (isInheritableIn)+ *pHandleIn = hTemporaryIn;+ else+ {+ /* Make the read end non-inheritable */+ status = DuplicateHandle(GetCurrentProcess(), hTemporaryIn,+ GetCurrentProcess(), pHandleIn,+ 0,+ FALSE, /* non-inheritable */+ DUPLICATE_SAME_ACCESS);+ CloseHandle(hTemporaryIn);+ if (!status)+ {+ maperrno();+ *pHandleIn = NULL;+ *pHandleOut = NULL;+ CloseHandle(hTemporaryOut);+ return FALSE;+ }+ }++ if (isInheritableOut)+ *pHandleOut = hTemporaryOut;+ else+ {+ /* Make the write end non-inheritable */+ status = DuplicateHandle(GetCurrentProcess(), hTemporaryOut,+ GetCurrentProcess(), pHandleOut,+ 0,+ FALSE, /* non-inheritable */+ DUPLICATE_SAME_ACCESS);+ CloseHandle(hTemporaryOut);+ if (!status)+ {+ maperrno();+ *pHandleIn = NULL;+ *pHandleOut = NULL;+ CloseHandle(*pHandleIn);+ return FALSE;+ }+ }++ return TRUE;+}++ProcHandle+runProcess (char *cmd, char *workingDirectory, void *environment,+ int fdStdInput, int fdStdOutput, int fdStdError)+{+ STARTUPINFO sInfo;+ PROCESS_INFORMATION pInfo;+ DWORD flags;++ ZeroMemory(&sInfo, sizeof(sInfo));+ sInfo.cb = sizeof(sInfo); + sInfo.hStdInput = (HANDLE) _get_osfhandle(fdStdInput);+ sInfo.hStdOutput= (HANDLE) _get_osfhandle(fdStdOutput);+ sInfo.hStdError = (HANDLE) _get_osfhandle(fdStdError);++ if (sInfo.hStdInput == INVALID_HANDLE_VALUE)+ sInfo.hStdInput = NULL;+ if (sInfo.hStdOutput == INVALID_HANDLE_VALUE)+ sInfo.hStdOutput = NULL;+ if (sInfo.hStdError == INVALID_HANDLE_VALUE)+ sInfo.hStdError = NULL;++ if (sInfo.hStdInput || sInfo.hStdOutput || sInfo.hStdError)+ sInfo.dwFlags = STARTF_USESTDHANDLES;++ if (sInfo.hStdInput != GetStdHandle(STD_INPUT_HANDLE) &&+ sInfo.hStdOutput != GetStdHandle(STD_OUTPUT_HANDLE) &&+ sInfo.hStdError != GetStdHandle(STD_ERROR_HANDLE))+ flags = CREATE_NO_WINDOW; // Run without console window only when both output and error are redirected+ else+ flags = 0;++ if (!CreateProcess(NULL, cmd, NULL, NULL, TRUE, flags, environment, workingDirectory, &sInfo, &pInfo))+ {+ maperrno();+ return -1;+ }++ CloseHandle(pInfo.hThread);+ return (ProcHandle)pInfo.hProcess;+}++ProcHandle+runInteractiveProcess (char *cmd, char *workingDirectory, void *environment,+ int *pfdStdInput, int *pfdStdOutput, int *pfdStdError)+{+ STARTUPINFO sInfo;+ PROCESS_INFORMATION pInfo;+ HANDLE hStdInputRead, hStdInputWrite;+ HANDLE hStdOutputRead, hStdOutputWrite;+ HANDLE hStdErrorRead, hStdErrorWrite;++ if (!mkAnonPipe(&hStdInputRead, TRUE, &hStdInputWrite, FALSE))+ return -1;++ if (!mkAnonPipe(&hStdOutputRead, FALSE, &hStdOutputWrite, TRUE))+ {+ CloseHandle(hStdInputRead);+ CloseHandle(hStdInputWrite);+ return -1;+ }++ if (!mkAnonPipe(&hStdErrorRead, FALSE, &hStdErrorWrite, TRUE))+ {+ CloseHandle(hStdInputRead);+ CloseHandle(hStdInputWrite);+ CloseHandle(hStdOutputRead);+ CloseHandle(hStdOutputWrite);+ return -1;+ }++ ZeroMemory(&sInfo, sizeof(sInfo));+ sInfo.cb = sizeof(sInfo);+ sInfo.dwFlags = STARTF_USESTDHANDLES;+ sInfo.hStdInput = hStdInputRead;+ sInfo.hStdOutput= hStdOutputWrite;+ sInfo.hStdError = hStdErrorWrite;++ if (!CreateProcess(NULL, cmd, NULL, NULL, TRUE, CREATE_NO_WINDOW, environment, workingDirectory, &sInfo, &pInfo))+ {+ maperrno();+ CloseHandle(hStdInputRead);+ CloseHandle(hStdInputWrite);+ CloseHandle(hStdOutputRead);+ CloseHandle(hStdOutputWrite);+ CloseHandle(hStdErrorRead);+ CloseHandle(hStdErrorWrite);+ return -1;+ }+ CloseHandle(pInfo.hThread);++ // Close the ends of the pipes that were inherited by the+ // child process. This is important, otherwise we won't see+ // EOF on these pipes when the child process exits.+ CloseHandle(hStdInputRead);+ CloseHandle(hStdOutputWrite);+ CloseHandle(hStdErrorWrite);++ *pfdStdInput = _open_osfhandle((intptr_t) hStdInputWrite, _O_WRONLY);+ *pfdStdOutput = _open_osfhandle((intptr_t) hStdOutputRead, _O_RDONLY);+ *pfdStdError = _open_osfhandle((intptr_t) hStdErrorRead, _O_RDONLY);++ return (int) pInfo.hProcess;+}++int+terminateProcess (ProcHandle handle)+{+ if (!TerminateProcess((HANDLE) handle, 1)) {+ maperrno();+ return -1;+ }+ return 0;+}++int+getProcessExitCode (ProcHandle handle, int *pExitCode)+{+ *pExitCode = 0;++ if (WaitForSingleObject((HANDLE) handle, 1) == WAIT_OBJECT_0)+ {+ if (GetExitCodeProcess((HANDLE) handle, (DWORD *) pExitCode) == 0)+ {+ maperrno();+ return -1;+ }+ return 1;+ }+ + return 0;+}++int+waitForProcess (ProcHandle handle)+{+ DWORD retCode;++ if (WaitForSingleObject((HANDLE) handle, INFINITE) == WAIT_OBJECT_0)+ {+ if (GetExitCodeProcess((HANDLE) handle, &retCode) == 0)+ {+ maperrno();+ return -1;+ }+ return retCode;+ }+ + maperrno();+ return -1;+}++#endif /* Win32 */
+ include/HsProcessConfig.h view
@@ -0,0 +1,83 @@+/* include/HsProcessConfig.h. Generated from HsProcessConfig.h.in by configure. */+/* include/HsProcessConfig.h.in. Generated from configure.ac by autoheader. */++/* The value of SIG_DFL. */+#define CONST_SIG_DFL -1++/* The value of SIG_IGN. */+#define CONST_SIG_IGN -1++/* Define to 1 if you have the `fork' function. */+#define HAVE_FORK 1++/* Define to 1 if you have the <inttypes.h> header file. */+#define HAVE_INTTYPES_H 1++/* Define to 1 if you have the <memory.h> header file. */+#define HAVE_MEMORY_H 1++/* Define to 1 if you have the `setitimer' function. */+#define HAVE_SETITIMER 1++/* Define to 1 if you have the <signal.h> header file. */+#define HAVE_SIGNAL_H 1++/* Define to 1 if you have the <stdint.h> header file. */+#define HAVE_STDINT_H 1++/* Define to 1 if you have the <stdlib.h> header file. */+#define HAVE_STDLIB_H 1++/* Define to 1 if you have the <strings.h> header file. */+#define HAVE_STRINGS_H 1++/* Define to 1 if you have the <string.h> header file. */+#define HAVE_STRING_H 1++/* Define to 1 if you have the <sys/stat.h> header file. */+#define HAVE_SYS_STAT_H 1++/* Define to 1 if you have the <sys/types.h> header file. */+#define HAVE_SYS_TYPES_H 1++/* Define to 1 if you have the <sys/wait.h> header file. */+#define HAVE_SYS_WAIT_H 1++/* Define to 1 if you have the <unistd.h> header file. */+#define HAVE_UNISTD_H 1++/* Define to 1 if you have the `vfork' function. */+#define HAVE_VFORK 1++/* Define to 1 if you have the <vfork.h> header file. */+/* #undef HAVE_VFORK_H */++/* Define to 1 if `fork' works. */+#define HAVE_WORKING_FORK 1++/* Define to 1 if `vfork' works. */+#define HAVE_WORKING_VFORK 1++/* Define to the address where bug reports for this package should be sent. */+#define PACKAGE_BUGREPORT "libraries@haskell.org"++/* Define to the full name of this package. */+#define PACKAGE_NAME "Haskell process package"++/* Define to the full name and version of this package. */+#define PACKAGE_STRING "Haskell process package 1.0"++/* Define to the one symbol short name of this package. */+#define PACKAGE_TARNAME "process"++/* Define to the version of this package. */+#define PACKAGE_VERSION "1.0"++/* Define to 1 if you have the ANSI C header files. */+#define STDC_HEADERS 1++/* Define to `int' if <sys/types.h> does not define. */+/* #undef pid_t */++/* Define as `fork' if `vfork' does not work. */+/* #undef vfork */
+ include/runProcess.h view
@@ -0,0 +1,74 @@+/* ----------------------------------------------------------------------------+ (c) The University of Glasgow 2004++ Interface for code in runProcess.c (providing support for System.Process)+ ------------------------------------------------------------------------- */++#include "HsProcessConfig.h"+// Otherwise these clash with similar definitions from other packages:+#undef PACKAGE_BUGREPORT+#undef PACKAGE_NAME+#undef PACKAGE_STRING+#undef PACKAGE_TARNAME+#undef PACKAGE_VERSION++#if defined(_MSC_VER) || defined(__MINGW32__) || defined(_WIN32)+#include <windows.h>+#include <stdlib.h>+#endif++#include <unistd.h>+#include <sys/types.h>++#ifdef HAVE_VFORK_H+#include <vfork.h>+#endif++#ifdef HAVE_VFORK+#define fork vfork+#endif++#ifdef HAVE_SIGNAL_H+#include <signal.h>+#endif++#if !(defined(_MSC_VER) || defined(__MINGW32__) || defined(_WIN32))+typedef pid_t ProcHandle;+#else+// Should really be intptr_t, but we don't have that type on the Haskell side+typedef long ProcHandle;+#endif++#if !(defined(_MSC_VER) || defined(__MINGW32__) || defined(_WIN32))++extern ProcHandle runProcess( char *const args[], + char *workingDirectory, char **environment, + int fdStdInput, int fdStdOutput, int fdStdError,+ int set_inthandler, long inthandler, + int set_quithandler, long quithandler);++extern ProcHandle runInteractiveProcess( char *const args[], + char *workingDirectory, + char **environment, + int *pfdStdInput, + int *pfdStdOutput, + int *pfdStdError);++#else++extern ProcHandle runProcess( char *cmd, + char *workingDirectory, void *environment, + int fdStdInput, int fdStdOutput, int fdStdError);++extern ProcHandle runInteractiveProcess( char *cmd, + char *workingDirectory, + void *environment,+ int *pfdStdInput,+ int *pfdStdOutput,+ int *pfdStdError);++#endif++extern int terminateProcess( ProcHandle handle );+extern int getProcessExitCode( ProcHandle handle, int *pExitCode );+extern int waitForProcess( ProcHandle handle );
+ process.cabal view
@@ -0,0 +1,34 @@+name: process+version: 1.0.0.0+license: BSD3+license-file: LICENSE+maintainer: libraries@haskell.org+synopsis: Process libraries+description:+ This package contains libraries for dealing with system processes.+extra-tmp-files:+ config.log config.status autom4te.cache+ include/HsProcessConfig.h+build-type: Configure+cabal-version: >=1.2++Library {+ exposed-modules:+ System.Cmd+ System.Process.Internals+ if impl(ghc)+ exposed-modules:+ System.Process+ c-sources:+ cbits/runProcess.c+ include-dirs: include+ includes:+ runProcess.h+ install-includes:+ runProcess.h+ HsProcessConfig.h+ extensions: CPP+ build-depends: base, directory, filepath+ if !os(windows)+ build-depends: unix+}