packages feed

uni-posixutil (empty) → 2.2.0.0

raw patch · 8 files changed

+847/−0 lines, 8 filesdep +basedep +directorydep +processsetup-changed

Dependencies added: base, directory, process, uni-events, uni-util, unix

Files

+ LICENSE view
@@ -0,0 +1,123 @@+License Agreement++Preamble++The aim of this licence agreement is to enable the free use of the+software that is described in the sequel by anyone. In order to+guarantee this, it is necessary to set up rules for the use of the+software that hold for any user.++Provider of this licence is the University of Bremen, represented by+its principal (called "licence provider" in the sequel). The provider+of the licence has developed the "Uniform Workbench" (just+called "software" in the sequel). The software includes a+graphical tool for accessing documents stored in a versioned repository,+but also contains libraries and some other tools.++Following the ideas of open source software, the licence provider+gives access to the software without fee for anyone (called "licence+taker" in the sequel) under the following conditions which are similar+to the Lesser Gnu Public License (LGPL). Each licence taker obligates+himself to follow the terms of use below.++++1 Principle++Each licence taker appreciating these terms of use receives a simple+right, not resctricted in time and space and without any fee, to use+the software, in particular, to copy, distribute and process+it. Exclusively the following terms of use do hold.  The licence+provider explicitly contradicts any conflicting terms of business. By+making use of the rights described below, in particular by copying or+distributing it, a licence treaty between the licence provider and the+licence takes is concluded.++++2 Copying++The licence taker has the right to make and distribute unmodified+copies of the software on any media. Prerequisite for this is that the+licence provider and this licence agreement is clearly recognizable,+and that the sources are distributed together with the software.++++3 Modification and Distribution++The licence taker has the right to modify copies of the software (or+parts thereof) and to distribute these modifications under the terms+of 2 above and the following conditions:++1. The modified software has to carry a clear mark that points to the+original licence provider, the modification that has been made, and+the date of the modification.++2. The licence taker has to ensure that the software as a whole or+parts of it are accessible to third parties under the terms of this+licence agreement without fee.++3. If during the modification a copyright of the licence taker+emerges, then this copyright must be put under the terms of this+licence if the modified software is distributed.+++4 Other duties++1. Reference to the validity of this licence agreement must not be+modified or deleted by the licence taker.++2. The use of the software by third parties must not be conditioned by+the fulfilment of duties that are not mentioned in this licence+agreement.++3. The use of the software must not be prevented or complicated by+means fo technical protection, in particular copy protection means.++++5 Liability, Update++1. Liability of the licence provider is restriced to fraudulent+withheld factual or legal errors. The licence provider does not give+any warranty, and neither ensures any properties of the+software. Furthermore, he is liable only for those damages that are+caused by willful or grossly negligent violation of duty.++2. The licence provider has the right to update these terms of use at+any time.+++++6 Forum for users++The licence provider does provide neither support nor+consultation. Without acknowledgement of any legal duty, the licence+provider will care about the installation of a user forum for+discussions about the software and its further development.+++7 Legal domicile++It is agreed that the law of the Federal Republic of Germany is valid+for this licence agreement. For any lawsuits or legal actions emerging+from this licence agreement, it is agreed that exclusively German+courts are competent. Legal domicile is Bremen.+++8 Termination through Offence++Any violation of a duty of this agreement automatically terminates the+rights of use of the offender.++++9 Salvatorian Clause++If any rule of this agreement should be or become inoperative,+validity of the other rules is not affected. The parties will care+about replacing the invalid rule by some valid rule that comes close+to the purpose of this agreement.+
+ Posixutil/BlockSigPIPE.hs view
@@ -0,0 +1,20 @@+{-# LANGUAGE CPP #-}+-- | Module that should also compile on Windows for blocking sigPIPE on+-- Unix, something you need to do to avoid the entire system crashing when+-- a pipe is closed.+module Posixutil.BlockSigPIPE(+   blockSigPIPE, -- :: IO ()+   ) where++import Util.Computation++#ifndef WINDOWS+import System.Posix.Signals+#endif++blockSigPIPE :: IO ()+blockSigPIPE = do+#ifndef WINDOWS+  installHandler sigPIPE Ignore Nothing+#endif+  done
+ Posixutil/ChildProcess.hs view
@@ -0,0 +1,370 @@+-- |+-- Description: Calling other programs.+--+-- Calling other programs.+--+-- This module now serves basically as an interface to GHC's new+-- System.Process module.+module Posixutil.ChildProcess (+   ChildProcess,+   PosixProcess, -- holds information about a process to be created++   ChildProcessStatus(ChildExited,ChildTerminated),++   -- linemode, arguments, &c encode configuration options for+   -- a process to be created.  Various functions for creating new+   -- processes take a [Config PosixProcess] as an argument.+   -- In particular newChildProcess does.+   linemode,       -- :: Bool -> Config PosixProcess+   -- for meaning of linemode see readMsg.+   arguments,      -- :: [String] -> Config PosixProcess+   appendArguments,-- :: [String] -> Config PosixProcess+   environment,    -- :: [(String,String)] -> Config PosixProcess+   standarderrors, -- :: Bool -> Config PosixProcess+   -- if standarderrors is true, we send stderr to the childprocesses+   -- out channel (of which there is only one).  Otherwise we+   -- display them, with the name of the responsible process,+   -- on our stderr.+   challengeResponse, -- :: (String,String) -> Config PosixProcess+   -- Set a "challenge" and "response".  Each is given as a String.+   -- The challenge (first String) will have newline appended if in line-mode.+   -- However the response will always be expected exactly as is.+   toolName, -- :: String -> Config PosixProcess+   -- The name of the tool, used in error messages and in the debug file.++   newChildProcess, -- :: FilePath -> [Config PosixProcess] -> IO ChildProcess+++   sendMsg, -- :: ChildProcess -> String -> IO ()+   -- sendMsg sends a String to the ChildProcess, adding a new line+   -- for line mode.++   sendMsgRaw, -- :: ChildProcess -> CStringLen -> IO ()+   -- sendMsgRaw writes a CStringLen+   -- to the child process.  It does not append a newline.++   readMsg, -- :: ChildProcess -> IO String++   waitForChildProcess, -- :: ChildProcess -> IO ChildProcessStatus+    -- waits until the ChildProcess exits or is terminated+   )+where++import System.IO+import System.IO.Error as IO++import Foreign.C.String+import System.Exit+import System.Process+import Control.Concurrent+import qualified Control.Exception as Exception++import Util.Computation+import Util.CompileFlags+import Util.Object+import Util.IOExtras+import Util.Debug+import Util.FileNames++import Events.Destructible++import Posixutil.BlockSigPIPE+import Posixutil.ProcessClasses++-- --------------------------------------------------------------------------+--  Tool Parameters+-- --------------------------------------------------------------------------++-- | Describes configuration options for the process.+data PosixProcess =+   PosixProcess {+      args            :: [String],+      ppenv           :: Maybe [(String, String)],+      lmode           :: Bool, -- line mode+      includestderr   :: Bool, -- include stderr+      cresponse       :: Maybe (String,String),+      toolname        :: Maybe String+     }++-- | Initial configuration options.+defaultPosixProcess :: PosixProcess+defaultPosixProcess =+   PosixProcess {+      args = [],+      ppenv = Nothing,+      lmode = True,+      includestderr = True,+      cresponse = Nothing,+      toolname = Nothing+      }+++-- | If 'True', 'readMsg' returns lines, otherwise it returs the first input+-- that's available+linemode :: Bool -> Config PosixProcess+linemode lm' parms = return parms{lmode = lm'}++-- | Set command arguments+arguments :: [String] -> Config PosixProcess+arguments args' parms = return parms{args = args'}++-- | Append command arguments+appendArguments :: [String] -> Config PosixProcess+appendArguments args' parms = return parms{args = (args parms) ++ args'}++-- | Set the process' environment.+environment :: [(String,String)] -> Config PosixProcess+environment env' parms = return parms{ppenv = Just env'}++-- if 'True', we send stderr to the childprocesses+-- out channel (of which there is only one).  Otherwise we+-- display them, with the name of the responsible process,+-- on our stderr.+standarderrors :: Bool -> Config PosixProcess+standarderrors err' parms = return parms{includestderr = err'}++-- | Set a "challenge" and "response".  This is used as a test+-- when the tool starts up, to make sure that everything is+-- working properly.+---+-- The challenge (first String) will have newline appended if in line-mode.+-- However the response will always be expected exactly as is.+challengeResponse :: (String,String) -> Config PosixProcess+challengeResponse cr parms = return parms {cresponse = Just cr}++-- | The name of the tool, used in error messages and in the debug file.+toolName :: String -> Config PosixProcess+toolName n parms = return parms {toolname = Just n}+++-- -------------------------------------------------------------------------+-- Data Declaration+-- -------------------------------------------------------------------------++-- | A running process+data ChildProcess = ChildProcess {+   processHandle :: ProcessHandle,+      -- | GHC's handle to the process.++   processIn :: Handle,+   processOutput :: Chan String,++   childObjectID :: ObjectID,+   lineMode :: Bool,+      -- | if True readMsg returns lines, otherwise+      -- it returns the first input that's available.+   toolTitle :: String+      -- Title of the tool, derived from the file name or+      -- supplied by the toolName function,+      -- used in the debugging file.+   }++-- | Status if a process+data ChildProcessStatus = ChildExited ExitCode+                        | ChildTerminated+   deriving (Eq, Ord, Show)++-- -------------------------------------------------------------------------+-- Initialising+-- -------------------------------------------------------------------------++-- | Starting a new 'ChildProcess'+newChildProcess :: FilePath -> [Config PosixProcess] -> IO ChildProcess+newChildProcess filePath configurations =+   do+      parms <- configure defaultPosixProcess configurations++      debug("newChildProcess:")+      debug(filePath:(args parms))++      blockSigPIPE++      -- run the process.+      (processIn,processOut,processErr,processHandle) <- runInteractiveProcess+         filePath (args parms) Nothing (ppenv parms)++      childObjectID <- newObject++      processOutput <- newChan++      let+         toolTitle :: String+         toolTitle =+            case (toolname parms,splitName filePath) of+               (Just toolTitle,_) -> toolTitle+               (Nothing,(dir,toolTitle)) -> toolTitle++         lineMode :: Bool+         lineMode = lmode parms++         getFn :: Handle -> IO String+         getFn = if lineMode then hGetLine else getAvail++         -- Worker thread which reads input from the tool and sends it to+         -- processOutput+         monitorHandle :: Handle -> IO ()+         monitorHandle handle =+            foreverUntil (+               do+                  nextOrEOF <- catchEOF (getFn handle)+                  case nextOrEOF of+                     Nothing -> return True+                     Just line ->+                        do+                           debugRead childProcess (line ++ "\n")+                           writeChan processOutput line+                           return False+               )++         -- Worker thread which reads input from the tool (in fact, stderr)+         -- and reports it.+         reportErrors :: IO ()+         reportErrors =+            foreverUntil (+               do+                  nextOrEOF <- catchEOF (getFn processErr)+                  case nextOrEOF of+                     Nothing -> return True+                     Just line ->+                        do+                           hPutStrLn stderr ("Error from " ++ toolTitle+                              ++ ": " ++ line)+                           hFlush stderr+                           return False+               )++         getAvail :: Handle -> IO String+         getAvail handle =+            do+               c0 <- hGetChar handle -- force a wait if necessary+               getAvail0 [c0] handle++         getAvail0 :: String -> Handle -> IO String+         getAvail0 acc handle =+            do+               ready <- hReady handle+               if ready+                  then+                     do+                        c <- hGetChar handle+                        getAvail0 (c : acc) handle+                  else+                     return (reverse acc)++         childProcess = ChildProcess {+            processHandle = processHandle,+            processIn = processIn,+            processOutput = processOutput,+            childObjectID = childObjectID,+            lineMode = lineMode,+            toolTitle = toolTitle+            }++      -- Do challenge-response+      case cresponse parms of+         Nothing -> done+         Just (challenge,response) ->+            do+               sendMsg childProcess challenge+               responseLineOrError+                  <- IO.try (mapM (const (hGetChar processOut))+                     [1..length response])+               case responseLineOrError of+                  Left excep -> error (+                     "Starting " ++ toolTitle ++ " got IO error "+                     ++ show excep)+                  Right line -> if line == response+                     then+                        done+                     else+                        do+                           remainder <- getAvail0 [] processOut+                           error (+                              "Starting " ++ toolTitle+                              ++ " got unexpected response "+                              ++ line ++ remainder+                              )++      forkIO (monitorHandle processOut)+      if includestderr parms+         then+            forkIO (monitorHandle processErr)+         else+            forkIO (reportErrors)++      return childProcess++-- -------------------------------------------------------------------------+-- Communicating with the process+-- -------------------------------------------------------------------------++-- | Sends a String to the ChildProcess, adding a new line+-- for line mode.+sendMsg :: ChildProcess -> String -> IO ()+sendMsg childProcess line =+   do+      debugWrite childProcess line+      let+         lineToWrite =+            if lineMode childProcess then line ++ recordSep else line+      hPutStr (processIn childProcess) lineToWrite+      hFlush (processIn childProcess)++++-- | Writes a CStringLen+-- to the child process.  It does not append a newline.+sendMsgRaw :: ChildProcess -> CStringLen -> IO ()+sendMsgRaw childProcess (cStrLn@(ptr,len)) =+   do+      if isDebug+         then+            do+               str <- peekCStringLen cStrLn+               debugWrite childProcess str+         else+            done+      hPutBuf (processIn childProcess) ptr len+      hFlush (processIn childProcess)++-- | Reads a string from the ChildProcess+readMsg :: ChildProcess -> IO String+readMsg childProcess = readChan (processOutput childProcess)++-- -------------------------------------------------------------------------+-- Waiting for a process+-- -------------------------------------------------------------------------++-- | Waits for the ChildProcess to exit or be terminated+waitForChildProcess :: ChildProcess -> IO ChildProcessStatus+waitForChildProcess p =+  Exception.catch (waitForChild p) (\_ -> return ChildTerminated)+  where+    waitForChild p = do+      exitCode <- waitForProcess (processHandle p)+      return (ChildExited exitCode)++-- -------------------------------------------------------------------------+-- Writing debugging information to a file+-- -------------------------------------------------------------------------++debugWrite :: ChildProcess -> String -> IO ()+debugWrite childProcess str =+   debugString (toolTitle childProcess++">"++str++"\n")++debugRead :: ChildProcess -> String -> IO ()+debugRead childProcess str =+   debugString (toolTitle childProcess++"<"++str++"\n")++-- -------------------------------------------------------------------------+-- Instances+-- -------------------------------------------------------------------------++instance Object ChildProcess where+   objectID = childObjectID++instance Destroyable ChildProcess where+   destroy childProcess = terminateProcess (processHandle childProcess)++instance Tool ChildProcess where+   getToolStatus childProcess = getProcessExitCode (processHandle childProcess)
+ Posixutil/CopyFile.hs view
@@ -0,0 +1,186 @@+-- | This contains functions for copying to and from files+module Posixutil.CopyFile(+   copyFile,+   copyFileWE,+   copyStringToFile,+   copyStringToFileCheck,+   copyFileToString,+   copyFileToStringCheck,+   copyICStringLenToFile,+   copyFileToICStringLenCheck,++   copyCStringLenToFile,+   copyFileToCStringLen,+   copyFileToICStringLen,+   ) where++import System.IO as IO+import System.IO.Error as IO+import qualified System.IO.Error as IOErr++import Foreign.C+import Control.Exception+import qualified System.Directory as Dir++import Util.Computation+import Util.ICStringLen+import Util.DeepSeq++-- amahnke: Supplemented C-Code by System.Directory.CopyFile:+--+-- foreign import ccall unsafe "copy_file.h copy_file" copyFilePrim+--   :: CString -> CString -> IO Int++copyFile :: String -> String -> IO ()+copyFile source destination =+   do+      unitWE <- copyFileWE source destination+      coerceWithErrorIO unitWE++copyFileWE :: String -> String -> IO (WithError ())+copyFileWE source destination =+   if source == destination+      then+         return (hasValue ())+      else+             IOErr.catch (do+                            Dir.copyFile source destination+                            return(hasValue()))+              (\ioErr ->+                  let+                     codeStr = if IOErr.isAlreadyExistsError ioErr+                                 then  ("Can't write to " ++ destination ++ ". File already exists!")+                                 else if IOErr.isDoesNotExistError ioErr+                                        then ("Can't read from " ++ source ++ ". File doesn't exists!")+                                        else if IOErr.isPermissionError ioErr+                                               then ("Can't write to " ++ destination ++ ". Insufficient permissions!")+                                               else if IOErr.isFullError ioErr+                                                      then ("Can't write to " ++ destination ++ ". Disk full!")+                                                      else ("Something went wrong within copyFile.")+                  in+                    return(hasError codeStr)+              )+ {--+           code <-+               withCString source (\ sourcePrim ->+                  withCString destination (\ destinationPrim ->+                     copyFilePrim sourcePrim destinationPrim+                     )+                  )+            if (code<0)+               then+                  let+                     codeStr = case code of+                        -- see includes/copy_file.h+                        -1 -> "Can't read from "++source+                        -2 -> "Can't write to "++destination+                        -3 -> "Not enough memory to allocate buffer"+                        _ -> "Unknown error!!"+                  in+                     return(hasError codeStr)+               else+                  return(hasValue ())+--}++-- | Reads in a file to a String.  NB - differs from readFile in that this+-- is done instantly, so we don\'t have to worry about semi-closed handles+-- hanging around.+copyFileToString :: FilePath -> IO String+copyFileToString filePath =+   do+      s <- IO.readFile filePath++--      (cString,len) <- copyFileToCStringLen filePath+--      string <- peekCStringLen (cString,len)+--      free cString+      s `deepSeq` (return s)++-- | Read in a file, catching certain errors+copyFileToStringCheck :: FilePath -> IO (WithError String)+copyFileToStringCheck filePath =+   exceptionToError+      (\ exception ->+         case ioErrors exception of+         Nothing -> Nothing+         Just ioError ->+            if IO.isDoesNotExistError ioError+            then+               Just "File does not exist"+            else if IO.isAlreadyInUseError ioError+            then+               Just "File is already in use"+            else if IO.isPermissionError ioError+            then+               Just "No read access to file"+            else+               Nothing+         )+      (copyFileToString filePath)++copyFileToCStringLen :: FilePath -> IO CStringLen+copyFileToCStringLen file =+   do+      str <- readFile file+      newCStringLen $!! str++copyFileToICStringLenCheck :: FilePath -> IO (WithError ICStringLen)+copyFileToICStringLenCheck filePath =+   exceptionToError+      (\ exception ->+         case ioErrors exception of+            Nothing -> Nothing+            Just ioError -> Just (show ioError)+         )+      (copyFileToICStringLen filePath)++copyFileToICStringLen :: FilePath -> IO ICStringLen+copyFileToICStringLen filePath =+   do+      -- shamelessly pirated from GHC's slurpFile function.+      handle <- IO.openFile filePath IO.ReadMode+      len <- IO.hFileSize handle+      if len > fromIntegral (maxBound::Int)+         then+            error "CopyFile.copyFileToICStringLen: file too big"+         else+            do+               let+                  len_i = fromIntegral len+               mkICStringLen len_i+                  (\ cString ->+                     do+                        lenRead <- hGetBuf handle cString len_i+                        when (lenRead < len_i)+                           (error"EOF within CopyFile.copyFileToICStringLen")+                     )++copyICStringLenToFile :: ICStringLen -> FilePath -> IO ()+copyICStringLenToFile icsl filePath =+   withICStringLen icsl (\ i cstr ->+      copyCStringLenToFile (cstr,i) filePath+      )++-- | Write to a file, catching certain errors.+-- (At the moment this is not very helpful, returning messages like+-- \"system error\").+copyStringToFileCheck :: String -> FilePath -> IO (WithError ())+copyStringToFileCheck str filePath =+   exceptionToError+      (\ exception ->+         case ioErrors exception of+            Nothing -> Nothing+            Just ioError -> Just (show ioError)+         )+      (copyStringToFile str filePath)++copyStringToFile :: String -> FilePath -> IO ()+copyStringToFile str filePath =+   withCStringLen str+      (\ cStringLen -> copyCStringLenToFile cStringLen filePath)++copyCStringLenToFile :: CStringLen -> FilePath -> IO ()+copyCStringLenToFile (ptr,len) filePath =+   do+      handle <- IO.openFile filePath IO.WriteMode+      hPutBuf handle ptr len+      IO.hFlush handle
+ Posixutil/ProcessClasses.hs view
@@ -0,0 +1,46 @@+-- | ProcessClasses describes some classes which tools encapsulating+-- processes may instance.+module Posixutil.ProcessClasses(+   ToolStatus, -- encodes status of process+   Tool(..), -- can get tool status+   SingleInstanceTool(..), -- this tool has at most one instance+   CommandTool(..), -- can send commands.+   ) where++import System.Exit++-- --------------------------------------------------------------------------+--  Can get status+-- --------------------------------------------------------------------------++type ToolStatus = Maybe ExitCode++class Tool t where+    getToolStatus   :: t -> IO ToolStatus++-- --------------------------------------------------------------------------+-- Tool has at most one instance, which this gets.+-- --------------------------------------------------------------------------++class SingleInstanceTool t where+    getToolInstance :: IO t++-- --------------------------------------------------------------------------+-- Command tools, IE tools where you can send a message and (maybe)+-- get a response.+-- --------------------------------------------------------------------------++class Tool t => CommandTool t where+   -- Tools have two sorts of output.  One is what comes out of their+   -- stdout channel (and if the appropriate mode in ChildProcess is set+   -- their stderr channel as well).+   -- execOneWayCmd is used when that's all there is.+   -- execCmd is used when there's also a string from somewhere else as well.+   evalCmd         :: String -> t -> IO String+   execCmd         :: String -> t -> IO ()+   execOneWayCmd   :: String -> t -> IO ()+   execCmd cmd t   =+      do+         _ <- evalCmd cmd t+         return ()+   -- only overrridden by Expect, in which all commands are one-way.
+ Posixutil/SafeSystem.hs view
@@ -0,0 +1,64 @@+-- | SafeSystem.safeSystem executes a command (supplied as a String) and+-- returns its exit code.  It differs from System.system in that it does+-- NOT stop the world while doing this, so that other threads can run.+-- How it works: we use ChildProcess to run the runCommand C program,+-- and feed it the command over stdin.  Ugly, but is there a better way?+module Posixutil.SafeSystem(+   safeSystemGeneral,+   safeSystem,+   ) where++import System.Exit++import Util.WBFiles+import Util.FileNames+import Util.Computation++import Posixutil.ChildProcess++safeSystem :: String -> IO ExitCode+safeSystem command =+   let+      -- We ignore blank output lines.+      outputSink "" = done+      outputSink str = putStrLn ("SafeSystem output: "++str)+   in+      safeSystemGeneral command outputSink++-- | Run \"command\", displaying any output using the supplied+-- outputSink function.  (This output had better not include+-- \"EXITCODE [number]\".)+--+-- outputSink is fed output line by line, and without the newlines.+safeSystemGeneral :: String -> (String -> IO ()) -> IO ExitCode+safeSystemGeneral command outputSink =+   do+      -- Get location of runCommand+      top <- getTOP+      let+         fullName = (trimDir top) `combineNames`+            ("posixutil" `combineNames` "runCommand")+      childProcess <- newChildProcess fullName [+         linemode True,+         standarderrors True+         ]+      sendMsg childProcess (command++"\n")+      let+         readOutput =+            do+               let+                  -- we ignore blank input lines.+                  notExit str =+                     do+                        outputSink str+                        readOutput+               nextLine <- readMsg childProcess+               case nextLine of+                  'E':'X':'I':'T':'C':'O':'D':'E':' ':numberStr ->+                     case readsPrec 0 numberStr of+                        [(0,"")] -> return ExitSuccess+                        [(n,"")] -> return (ExitFailure n)+                        _ -> notExit nextLine+                  _ -> notExit nextLine+      readOutput+
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ uni-posixutil.cabal view
@@ -0,0 +1,36 @@+name:           uni-posixutil+version:        2.2.0.0+build-type:     Simple+license:        LGPL+license-file:   LICENSE+author:         uniform@informatik.uni-bremen.de+maintainer:     Christian.Maeder@dfki.de+homepage:       http://www.informatik.uni-bremen.de/uniform/wb/+category:       Uniform+synopsis:       Posix utilities for the uniform workbench+description:    posix utilities+cabal-version:  >= 1.4+tested-with:    GHC==6.8.3, GHC==6.10.4, GHC==6.12.3++library+  exposed-modules:+    Posixutil.CopyFile,+    Posixutil.SafeSystem,+    Posixutil.ProcessClasses,+    Posixutil.ChildProcess,+    Posixutil.BlockSigPIPE++  build-depends:+        base >=3 && < 4,+        directory,+        process,+        uni-util,+        uni-events++  if os(windows)+     cpp-options: -DWINDOWS+  else+     build-Depends: unix++  if impl(ghc > 6.10)+    ghc-options: -fwarn-unused-imports -fno-warn-warnings-deprecations