1119380Sjake(* Copied from Moscow ML source *)
2119380Sjakestructure Mosml =
3119380Sjakestruct
4119380Sjakedatatype runresult =
5119380Sjake    Success of string
6119380Sjake  | Failure of string
7119380Sjakefun run cmd args inp =
8119380Sjake    let fun catenate xs =
9119380Sjake	    String.concat (List.foldr (fn (s, res) => s :: " " :: res) [] xs)
10119380Sjake	fun write filename s =
11119380Sjake	    let open BinIO
12119380Sjake		val os = openOut filename
13119380Sjake	    in output(os, s); closeOut os end
14119380Sjake	fun read filename =
15119380Sjake	    let open BinIO
16119380Sjake		val is  = openIn filename
17119380Sjake		val res = inputAll is
18119380Sjake	    in closeIn is; res end
19119380Sjake	val infile  = OS.FileSys.tmpName ()
20119380Sjake	val outfile = OS.FileSys.tmpName ()
21119380Sjake    in let
22119380Sjake	val _ = write infile (Byte.stringToBytes inp)
23119380Sjake	val cmdline =
24119380Sjake	    (* This should work for Bourne sh, POSIX sh, ksh, bash: *)
25119380Sjake	    catenate (cmd :: List.@(args, ["<", infile, "1>", outfile,
26119380Sjake					   "2>&1"]))
27119380Sjake	    (* This works for bash, csh and tcsh: *)
28119380Sjake	    (* catenate (cmd :: List.@(args, ["<", infile, "&>", outfile])) *)
29119380Sjake	val status = OS.Process.system cmdline
30119380Sjake	val result = if OS.Process.isSuccess status then
31119380Sjake			 Success (Byte.bytesToString (read outfile))
32119380Sjake		     else
33119380Sjake			 ((Failure (Byte.bytesToString (read outfile)))
34119380Sjake			  handle IO.Io _ => Failure (cmd ^ ": command failed"))
35119380Sjake    in
36119380Sjake	(OS.FileSys.remove infile)  handle OS.SysErr _ => ();
37119380Sjake	(OS.FileSys.remove outfile) handle OS.SysErr _ => ();
38119380Sjake	result
39119380Sjake    end
40119380Sjakehandle e =>
41119380Sjake((OS.FileSys.remove infile)  handle OS.SysErr _ => ();
42119380Sjake (OS.FileSys.remove outfile) handle OS.SysErr _ => ();
43119380Sjake raise e)
44119380Sjakeend
45119380Sjakeend;
46119380Sjake