module System.Cmd
( system, -- :: String -> IO ExitCode
- rawSystem, -- :: String -> IO ExitCode
+#ifdef __GLASGOW_HASKELL__
+ rawSystem, -- :: FilePath -> [String] -> IO ExitCode
+#endif
) where
import Prelude
-import System.Exit
-#ifndef __HUGS__
-import Foreign.C
-#endif
-
#ifdef __GLASGOW_HASKELL__
+import Foreign
+import Foreign.C
+import System.Exit
import GHC.IOBase
+#include "config.h"
#endif
#ifdef __HUGS__
import Hugs.System
#endif
+#ifdef __NHC__
+import System (system)
+#endif
+
-- ---------------------------------------------------------------------------
-- system
passes the command to the Windows command interpreter (@CMD.EXE@ or
@COMMAND.COM@), hence Unixy shell tricks will not work.
-}
-#ifndef __HUGS__
+#ifdef __GLASGOW_HASKELL__
system :: String -> IO ExitCode
system "" = ioException (IOError Nothing InvalidArgument "system" "null command" Nothing)
system cmd =
n -> return (ExitFailure n)
foreign import ccall unsafe "systemCmd" primSystem :: CString -> IO Int
-#endif /* __HUGS__ */
{- |
-The same as 'system', but bypasses the shell. Will behave more portably between
-systems, because there is no interpretation of shell metasyntax.
+The same as 'system', but bypasses the shell (GHC only).
+Will behave more portably between systems,
+because there is no interpretation of shell metasyntax.
-}
-rawSystem :: String -> IO ExitCode
-rawSystem "" = ioException (IOError Nothing InvalidArgument "rawSystem" "null command" Nothing)
-rawSystem cmd =
- withCString cmd $ \s -> do
- status <- throwErrnoIfMinus1 "rawSystem" (primRawSystem s)
+rawSystem :: FilePath -> [String] -> IO ExitCode
+
+#ifndef mingw32_TARGET_OS
+
+rawSystem cmd args =
+ withCString cmd $ \pcmd ->
+ withMany withCString (cmd:args) $ \cstrs ->
+ withArray0 nullPtr cstrs $ \arr -> do
+ status <- throwErrnoIfMinus1 "rawSystem" (c_rawSystem pcmd arr)
+ case status of
+ 0 -> return ExitSuccess
+ n -> return (ExitFailure n)
+
+foreign import ccall unsafe "rawSystem"
+ c_rawSystem :: CString -> Ptr CString -> IO Int
+
+#else
+
+-- On Windows, the command line is passed to the operating system as
+-- a single string. Command-line parsing is done by the executable
+-- itself.
+rawSystem cmd args = do
+ -- NOTE: 'cmd' is assumed to contain the application to run _only_,
+ -- as it'll be quoted surrounded in quotes here.
+ let cmdline = translate cmd ++ concat (map ((' ':) . translate) args)
+ withCString cmdline $ \pcmdline -> do
+ status <- throwErrnoIfMinus1 "rawSystem" (c_rawSystem pcmdline)
case status of
- 0 -> return ExitSuccess
- n -> return (ExitFailure n)
+ 0 -> return ExitSuccess
+ n -> return (ExitFailure n)
+
+translate :: String -> String
+translate str@('"':_) = str -- already escaped.
+translate str = '"' : foldr escape "\"" str
+ where escape '"' str = '\\' : '"' : str
+ escape '\\' str = '\\' : '\\' : str
+ escape c str = c : str
-foreign import ccall unsafe "rawSystemCmd" primRawSystem :: CString -> IO Int
+foreign import ccall unsafe "rawSystem"
+ c_rawSystem :: CString -> IO Int
+
+#endif
+#endif /* __GLASGOW_HASKELL__ */