-- | 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