Hi all, I am just sending this because there were some people who thought it could be useful. It works for Hugs98, but some hacks I use might be specific to our local system. I think a built-in module with the same function signatures would be extremely useful! Regards, Koen. -------------------------------------------------------------------- module Unix ( Command --:: String , sys --:: Command -> IO () -- using stdin and stdout , sysIn --:: Command -> String -> IO () , sysOut --:: Command -> IO String , sysInOut --:: Command -> String -> IO String -- using files as arguments , sysWithIn --:: (FilePath -> Command) -> String -> IO () , sysWithOut --:: (FilePath -> Command) -> IO String , sysInWithOut --:: (FilePath -> Command) -> String -> IO String , sysWithInOut --:: (FilePath -> FilePath -> Command) -> String -> IO String -- lazily generating output , sysOutLazy --:: Command -> IO String , sysInOutLazy --:: Command -> String -> IO String , sysWithOutLazy --:: (FilePath -> Command) -> IO String , sysInWithOutLazy --:: (FilePath -> Command) -> String -> IO String , sysWithInOutLazy --:: (FilePath -> FilePath -> Command) -> String -> IO String ) where import System( system ) import IO( try ) -------------------------------------------------------------------- -- internal file names prefix :: FilePath prefix = "/tmp/hugs-sys-" lockfile = prefix ++ "lock" numfile = prefix ++ "number" tmpfile n = prefix ++ show n -------------------------------------------------------------------- -- comm type Command = String type Comm = ([FilePath] -> String, IO String) comm0 :: Command -> Comm comm0 s = (\_ -> s, return "") comm1 :: (FilePath -> Command) -> Comm comm1 f = (\(s:_) -> f s, return "") comm2 :: (FilePath -> FilePath -> Command) -> Comm comm2 f = (\(s1:s2:_) -> f s1 s2, return "") -- decorator type Decorator = Comm -> IO Comm sysDecorate :: Decorator -> Comm -> IO String sysDecorate decorate comm = do (f, after) <- decorate comm system (f []) after -------------------------------------------------------------------- -- several decorators inputArg :: String -> Decorator inputArg inpS (f, after) = do inpF <- uniqueTmpName writeFile inpF inpS return (\args -> f (args ++ [inpF]), after) input :: String -> Decorator input inpS (f, after) = do inpF <- uniqueTmpName writeFile inpF inpS let after' = do s <- after rm inpF return s return (\args -> f args ++ " < " ++ inpF, after') outputArg :: Decorator outputArg (f, after) = do outP <- uniqueTmpName writeFile outP "" let after' = do s1 <- after s2 <- readFile outP rm outP return (s1 ++ s2) return (\args -> f (args ++ [outP]), after') output :: Decorator output (f, after) = do outP <- uniqueTmpName writeFile outP "" let after' = do s1 <- after s2 <- readFile outP rm outP return (s1 ++ s2) return (\args -> f args ++ " > " ++ outP, after') outputArgLazy :: Decorator outputArgLazy (f, after) = do outP <- uniqueTmpName mkpipe outP let after' = do s1 <- after s2 <- readFile outP rm outP return (s1 ++ s2) return (\args -> f (args ++ [outP]) ++ " &", after') outputLazy :: Decorator outputLazy (f, after) = do outP <- uniqueTmpName mkpipe outP let after' = do s1 <- after s2 <- readFile outP rm outP return (s1 ++ s2) return (\args -> f args ++ " > " ++ outP ++ " &", after') -------------------------------------------------------------------- -- several system functions sys :: Command -> IO () sys comm = void (system comm) sysIn :: Command -> String -> IO () sysIn comm inpS = void $ sysDecorate (input inpS) (comm0 comm) sysOut :: Command -> IO String sysOut comm = sysDecorate (output) (comm0 comm) sysInOut :: Command -> String -> IO String sysInOut comm inpS = sysDecorate (input inpS <> output) (comm0 comm) sysWithIn :: (FilePath -> Command) -> String -> IO () sysWithIn comm inpS = void $ sysDecorate (inputArg inpS) (comm1 comm) sysWithOut :: (FilePath -> Command) -> IO String sysWithOut comm = sysDecorate (outputArg) (comm1 comm) sysInWithOut :: (FilePath -> Command) -> String -> IO String sysInWithOut comm inpS = sysDecorate (input inpS <> outputArg) (comm1 comm) sysWithInOut :: (FilePath -> FilePath -> Command) -> String -> IO String sysWithInOut comm inpS = sysDecorate (inputArg inpS <> outputArg) (comm2 comm) -- lazy versions sysOutLazy :: Command -> IO String sysOutLazy comm = sysDecorate (outputLazy) (comm0 comm) sysInOutLazy :: Command -> String -> IO String sysInOutLazy comm inpS = sysDecorate (input inpS <> outputLazy) (comm0 comm) sysWithOutLazy :: (FilePath -> Command) -> IO String sysWithOutLazy comm = sysDecorate (outputArgLazy) (comm1 comm) sysInWithOutLazy :: (FilePath -> Command) -> String -> IO String sysInWithOutLazy comm inpS = sysDecorate (input inpS <> outputArgLazy) (comm1 comm) sysWithInOutLazy :: (FilePath -> FilePath -> Command) -> String -> IO String sysWithInOutLazy comm inpS = sysDecorate (inputArg inpS <> outputArgLazy) (comm2 comm) -------------------------------------------------------------------- -- create unique names uniqueTmpName :: IO String uniqueTmpName = mutex $ do enum <- try (readFile numfile) let num = either (const 0) read enum num `seq` writeFile numfile (show (num+1)) chmod "a+w" numfile return (tmpfile num) mutex :: IO a -> IO a mutex io = do lock a <- io rm lockfile return a -------------------------------------------------------------------- -- calls to system chmod :: String -> FilePath -> IO () chmod s file = void $ system ("chmod " ++ s ++ " " ++ file) lock :: IO () lock = void $ system ("lockfile -1 -l 4 " ++ lockfile) rm :: FilePath -> IO () rm file = void $ system ("rm -f " ++ file) mkpipe :: FilePath -> IO () mkpipe file = void $ system ("mknod " ++ file ++ " p") -------------------------------------------------------------------- -- monadic help functions void :: Monad m => m a -> m () void m = m >> return () (<>) :: Monad m => (a -> m b) -> (b -> m c) -> (a -> m c) m1 <> m2 = \x -> m1 x >>= m2 -------------------------------------------------------------------- -- the end.