[project @ 2003-06-12 16:06:06 by simonmar]
[ghc-base.git] / System / Cmd.hs
1 -----------------------------------------------------------------------------
2 -- |
3 -- Module      :  System.Cmd
4 -- Copyright   :  (c) The University of Glasgow 2001
5 -- License     :  BSD-style (see the file libraries/base/LICENSE)
6 -- 
7 -- Maintainer  :  libraries@haskell.org
8 -- Stability   :  provisional
9 -- Portability :  portable
10 --
11 -- Executing an external command.
12 --
13 -----------------------------------------------------------------------------
14
15 module System.Cmd
16     ( system,        -- :: String -> IO ExitCode
17 #ifdef __GLASGOW_HASKELL__
18       rawSystem,     -- :: String -> IO ExitCode
19 #endif
20     ) where
21
22 import Prelude
23
24 #ifdef __GLASGOW_HASKELL__
25 import Foreign
26 import Foreign.C
27 import System.Exit
28 import GHC.IOBase
29 #endif
30
31 #ifdef __HUGS__
32 import Hugs.System
33 #endif
34
35 #ifdef __NHC__
36 import System (system)
37 #endif
38
39 -- ---------------------------------------------------------------------------
40 -- system
41
42 {-| 
43 Computation @system cmd@ returns the exit code
44 produced when the operating system processes the command @cmd@.
45
46 This computation may fail with
47
48    * @PermissionDenied@: The process has insufficient privileges to
49      perform the operation.
50
51    * @ResourceExhausted@: Insufficient resources are available to
52      perform the operation.
53
54    * @UnsupportedOperation@: The implementation does not support
55      system calls.
56
57 On Windows, 'system' is implemented using Windows's native system
58 call, which ignores the @SHELL@ environment variable, and always
59 passes the command to the Windows command interpreter (@CMD.EXE@ or
60 @COMMAND.COM@), hence Unixy shell tricks will not work.
61 -}
62 #ifdef __GLASGOW_HASKELL__
63 system :: String -> IO ExitCode
64 system "" = ioException (IOError Nothing InvalidArgument "system" "null command" Nothing)
65 system cmd =
66   withCString cmd $ \s -> do
67     status <- throwErrnoIfMinus1 "system" (primSystem s)
68     case status of
69         0  -> return ExitSuccess
70         n  -> return (ExitFailure n)
71
72 foreign import ccall unsafe "systemCmd" primSystem :: CString -> IO Int
73
74 {- | 
75 The same as 'system', but bypasses the shell (GHC only).
76 Will behave more portably between systems,
77 because there is no interpretation of shell metasyntax.
78 -}
79
80 rawSystem :: FilePath -> [String] -> IO ExitCode
81
82 #ifndef mingw32_TARGET_OS
83
84 rawSystem cmd args =
85   withCString cmd $ \pcmd ->
86     withMany withCString (cmd:args) $ \cstrs ->
87       withArray0 nullPtr cstrs $ \arr -> do
88         status <- throwErrnoIfMinus1 "rawSystem" (c_rawSystem pcmd arr)
89         case status of
90             0  -> return ExitSuccess
91             n  -> return (ExitFailure n)
92
93 foreign import ccall unsafe "rawSystem"
94   c_rawSystem :: CString -> Ptr CString -> IO Int
95
96 #else
97
98 -- On Windows, the command line is passed to the operating system as
99 -- a single string.  Command-line parsing is done by the executable
100 -- itself.
101 rawSystem cmd args = do
102   let cmdline = translate cmd ++ concat (map ((' ':) . translate) args)
103   withCString cmdline $ \pcmdline -> do
104     status <- throwErrnoIfMinus1 "rawSystem" (c_rawSystem pcmdline)
105     case status of
106        0  -> return ExitSuccess
107        n  -> return (ExitFailure n)
108
109 translate :: String -> String
110 translate str = '"' : foldr escape "\"" str
111   where escape '"'  str = '\\' : '"'  : str
112         escape '\\' str = '\\' : '\\' : str
113         escape c    str = c : str
114
115 foreign import ccall unsafe "rawSystem"
116   c_rawSystem :: CString -> IO Int
117
118 #endif
119
120 #endif  /* __GLASGOW_HASKELL__ */