(* SP1 Aufgabe "Clash" in Standard ML * $Id: clash.sml,v 1.10 2024/03/21 17:10:26 oj14ozun Exp $ * https://wwwcip.cs.fau.de/~oj14ozun/src+etc/clash.sml *) open TextIO open Posix val bgProcs = ref ([] : (Process.pid * string) list) fun report msg = output (stdErr, msg ^ "\n") fun printProc (pid, cmd) = let val name = Int.toString o SysWord.toInt o Process.pidToWord in print ("[" ^ (name pid) ^ "] " ^ cmd ^ "\n") end fun cleanup () = case (Process.waitpid_nh (Process.W_ANY_CHILD, []) handle _ => NONE) of SOME (pid, _) => (let fun this (pid', _) = pid <> pid' in (case (List.find (not o this) (!bgProcs)) of SOME ent => ( bgProcs := List.filter this (!bgProcs); printProc ent) | NONE => ()) end; cleanup ()) | NONE => () fun prompt () = (print ((FileSys.getcwd ()) ^ ": "); flushOut stdOut) fun execute ["cd", dir] = OS.FileSys.chDir dir | execute ("cd" :: _) = report "usage: cd [dir]" | execute ["jobs"] = app printProc (!bgProcs) | execute ("jobs" :: _) = report "usage: jobs\n" | execute (argv as (cmd :: _)) = let val isBg = List.last argv = "&" val use = (List.length argv) - (if isBg then 1 else 0) val argv' = List.take (argv, use) in case Process.fork () of SOME pid => ( if isBg then let val l = String.concatWith " " argv' in bgProcs := (pid, l) :: !bgProcs end else ignore (Process.waitpid (Process.W_CHILD pid, []))) | NONE => Process.execp (cmd, argv') end | execute _ = () fun read () = case inputLine stdIn of SOME line => let val toks = String.tokens Char.isSpace line in execute toks handle e => report (exnMessage e); true end | NONE => false (* the input loop starts here: *) val _ = while (cleanup (); prompt (); read ()) do ()