---------------------------------------------------------------------------
MODULE---------------------------------------------------------------------------System EXPORTSSystem ; IMPORT ASCII, Process, TextRd, Rd, Wr, Pipe, File, FileRd, FileWr, Thread, AtomList, Atom, Text, TextSeq, OSError, Pathname, RegularFile, RefSeq, IntRefTbl; IMPORT (* SMsg, *) MsgX, MsgIF, ProcessEnv, TextReadingUtils, OSSpecials; IMPORT (* FSFixed AS *) FS;
PROCEDURE---------------------------------------------------------------------------AtomListToText (l : AtomList.T) : TEXT = VAR res : TEXT; BEGIN res := Atom.ToText(l.head); l := l.tail; WHILE l # NIL DO res := res & " " & Atom.ToText(l.head); l := l.tail; END; RETURN res; END AtomListToText;
PROCEDURE---------------------------------------------------------------------------ParListToText (params : TextSeq.T) : TEXT = VAR res : TEXT := ""; BEGIN FOR i := 0 TO params.size() - 1 DO res := res & ", " & params.get(i); END; RETURN res; END ParListToText;
PROCEDURE---------------------------------------------------------------------------ExecWithFileHandles (pgm : TEXT; params : TextSeq.T; stdin, stdout, stderr : File.T; env : ProcessEnv.T := NIL; msgif : MsgIF.T := NIL; wd : TEXT := NIL) : INTEGER RAISES {ExecuteError} = VAR p: Process.T; BEGIN p := RunWithFileHandles(pgm, params, stdin, stdout, stderr, env, msgif, wd); IF p = NIL THEN RETURN -1; ELSE RETURN Process.Wait(p); END; END ExecWithFileHandles;
PROCEDURE---------------------------------------------------------------------------RunWithFileHandles (pgm : TEXT; params : TextSeq.T; stdin, stdout, stderr : File.T; env : ProcessEnv.T := NIL; msgif : MsgIF.T := NIL; wd : TEXT := NIL) : Process.T RAISES {ExecuteError} = VAR args := NEW(REF ARRAY OF TEXT, params.size()); stdinParent, stdoutParent, stderrParent : File.T; child : Process.T; senv := ProcessEnv.SystemRepr(env); BEGIN MsgX.D(msgif, "System.RunWithFileHandles(" & pgm & ParListToText(params) & ")"); FOR i := 0 TO params.size() - 1 DO args^[i] := OSSpecials.QuotedProcessArgument(params.get(i)); END; Process.GetStandardFileHandles(stdinParent, stdoutParent, stderrParent); IF stdin = NIL THEN stdin := stdinParent; END; IF stdout = NIL THEN stdout := stdoutParent; END; IF stderr = NIL THEN stderr := stderrParent; END; TRY (* IF Text.Equal(pgm, "echo") THEN VAR wr := NEW(FileWr.T).init(stdout, TRUE); nl := TRUE; BEGIN FOR i := 0 TO params.size() - 1 DO WITH par = params.get(i) DO IF i = 0 AND Text.Equal(par, "-c") OR Text.Equal(par, "-n") THEN nl := FALSE; ELSE (* add blank after all params except the last *) IF i < params.size() - 1 THEN Wr.PutText(wr, par & " "); ELSE Wr.PutText(wr, par); END; END; END; END; Wr.Flush(wr); IF nl THEN Wr.PutChar(wr, '\n'); Wr.Flush(wr); END; END; RETURN NIL; (* no process created, just bail *) ELSE *) child := Process.Create(pgm, args^, senv, wd, stdin, stdout, stderr); (*END;*) EXCEPT OSError.E(list) => RAISE ExecuteError("execution of `" & pgm & "' failed: " & AtomListToText(list)); END; RETURN child; END RunWithFileHandles;
PROCEDURE---------------------------------------------------------------------------ExecNW (VAR estdin: File.T; VAR estdout: File.T; VAR estderr: File.T; pgm: TEXT; params: TextSeq.T; env: ProcessEnv.T := NIL; msgif: MsgIF.T := NIL; wd: TEXT := NIL; pstdin : File.T := NIL; pstdout : File.T := NIL; pstderr : File.T := NIL) : Process.T RAISES {ExecuteError} = PROCEDURE MakeAbsolute(pn : Pathname.T) : Pathname.T = BEGIN IF Pathname.Absolute(pn) THEN RETURN pn; ELSE RETURN Pathname.Join(wd, pn, NIL); END; END MakeAbsolute; VAR stdin, stdout, stderr : RegularFile.T; args := NEW(TextSeq.T).init(params.size()); i : INTEGER; psize := params.size(); BEGIN MsgX.D(msgif, "System.ExecNW(" & pgm & ParListToText(params) & ")"); stdin := NIL; stdout := NIL; stderr := NIL; i := 0; WHILE i < psize DO WITH arg = params.get(i), arglen = Text.Length(arg) DO IF (arglen = 1) AND Text.Equal(arg, "<") THEN INC(i); IF i = psize THEN RAISE ExecuteError("missing redirection argument"); END; IF stdin # NIL THEN RAISE ExecuteError("too many input redirections"); END; VAR pn := MakeAbsolute(params.get(i)); BEGIN TRY stdin := FS.OpenFile(pn, truncate := FALSE, create := FS.CreateOption.Never); EXCEPT OSError.E(list) => RAISE ExecuteError("open failed on " & pn & ": " & AtomListToText(list)); END; END; ELSIF (arglen < 3) AND (Text.Equal(arg, ">") OR Text.Equal(arg, "1>")) THEN INC(i); IF i = psize THEN RAISE ExecuteError("missing redirection argument"); END; IF stdout # NIL THEN RAISE ExecuteError("too many output redirections"); END; VAR pn := MakeAbsolute(params.get(i)); BEGIN TRY stdout := FS.OpenFile(pn, truncate := TRUE, create := FS.CreateOption.Ok); EXCEPT OSError.E(list) => RAISE ExecuteError("open failed on " & pn & ": " & AtomListToText(list)); END; END; ELSIF (arglen < 4) AND (Text.Equal(arg, ">>") OR Text.Equal(arg, "1>>")) THEN INC(i); IF i = psize THEN RAISE ExecuteError("missing redirection argument"); END; IF stdout # NIL THEN RAISE ExecuteError("too many output redirections"); END; VAR pn := MakeAbsolute(params.get(i)); BEGIN TRY stdout := FS.OpenFile(pn, truncate := FALSE, create := FS.CreateOption.Ok); EVAL stdout.seek(RegularFile.Origin.End, 0); EXCEPT OSError.E(list) => RAISE ExecuteError("open failed on " & pn & ": " & AtomListToText(list)); END; END; ELSIF (arglen = 2) AND Text.Equal(arg, "2>") THEN INC(i); IF i = psize THEN RAISE ExecuteError("missing redirection argument"); END; IF stderr # NIL THEN RAISE ExecuteError("too many output redirections"); END; VAR pn := MakeAbsolute(params.get(i)); BEGIN TRY stderr := FS.OpenFile(pn, truncate := TRUE, create := FS.CreateOption.Ok); EXCEPT | OSError.E(list) => RAISE ExecuteError("open failed on " & pn & ": " & AtomListToText(list)); END; END; ELSIF (arglen = 3) AND Text.Equal(arg, "2>>") THEN INC(i); IF i = psize THEN RAISE ExecuteError("missing redirection argument"); END; IF stderr # NIL THEN RAISE ExecuteError("too many output redirections"); END; VAR pn := MakeAbsolute(params.get(i)); BEGIN TRY stderr := FS.OpenFile(pn, truncate := FALSE, create := FS.CreateOption.Ok); EVAL stderr.seek(RegularFile.Origin.End, 0); EXCEPT OSError.E(list) => RAISE ExecuteError("open failed on " & pn & ": " & AtomListToText(list)); END; END; ELSIF (arglen = 2) AND Text.Equal(arg, "&>") THEN INC(i); IF i = psize THEN RAISE ExecuteError("missing redirection argument"); END; IF stdout # NIL OR stderr # NIL THEN RAISE ExecuteError("too many output redirections"); END; VAR pn := MakeAbsolute(params.get(i)); BEGIN TRY stdout := FS.OpenFile(pn, truncate := TRUE, create := FS.CreateOption.Ok); EXCEPT OSError.E(list) => RAISE ExecuteError("open failed on " & pn & ": " & AtomListToText(list)); END; END; stderr := stdout; ELSIF (arglen = 3) AND Text.Equal(arg, "&>>") THEN INC(i); IF i = psize THEN RAISE ExecuteError("missing redirection argument"); END; IF stdout # NIL OR stderr # NIL THEN RAISE ExecuteError("too many output redirections"); END; VAR pn := MakeAbsolute(params.get(i)); BEGIN TRY stdout := FS.OpenFile(pn, truncate := FALSE, create := FS.CreateOption.Ok); EVAL stdout.seek(RegularFile.Origin.End, 0); EXCEPT OSError.E(list) => RAISE ExecuteError("open failed on " & pn & ": " & AtomListToText(list)); END; END; stderr := stdout; ELSIF (arglen = 2) AND Text.Equal(arg, "$<") THEN (* file contents substitution *) INC(i); WHILE i < psize AND NOT Text.Equal(params.get(i), ">") DO VAR rd : FileRd.T; token : TEXT; fn := MakeAbsolute(params.get(i)); BEGIN TRY rd := FileRd.Open(fn); EXCEPT OSError.E => RAISE ExecuteError("cannot open file " & fn); END; TRY WHILE NOT Rd.EOF(rd) DO token := TextReadingUtils.GetTokenOrString(rd); args.addhi(token); END; EXCEPT Rd.Failure, Thread.Alerted => RAISE ExecuteError("cannot read file " & fn); | Rd.EndOfFile => (* skip *) END; TRY Rd.Close(rd); EXCEPT Rd.Failure, Thread.Alerted => RAISE ExecuteError("cannot close file " & fn); END; END; INC(i); END; IF i = psize THEN RAISE ExecuteError("missing file contents closing `>' "); END; ELSIF (arglen = 2) AND Text.Equal(arg, "$(") THEN (* command substitution *) RAISE ExecuteError("Sorry, command substitution not yet " & "implemented. "); ELSE args.addhi(arg); END; END; INC(i); END; estdin := stdin; estdout := stdout; estderr := stderr; IF estdin = NIL AND pstdin # NIL THEN estdin := pstdin; END; IF estdout = NIL AND pstdout # NIL THEN estdout := pstdout; END; IF estderr = NIL AND pstderr # NIL THEN estderr := pstderr; END; RETURN RunWithFileHandles(pgm, args, estdin, estdout, estderr, env, msgif, wd); END ExecNW;
PROCEDURE---------------------------------------------------------------------------Exec (pgm : TEXT; params : TextSeq.T; env : ProcessEnv.T := NIL; msgif : MsgIF.T := NIL; wd : TEXT := NIL; pstdin : File.T := NIL; pstdout : File.T := NIL; pstderr : File.T := NIL) : INTEGER RAISES {ExecuteError} = VAR stdin, stdout, stderr : File.T := NIL; ret: INTEGER; p : Process.T; BEGIN MsgX.D(msgif, "System.Exec(" & pgm & ParListToText(params) & ")"); p := ExecNW(stdin, stdout, stderr, pgm, params, env, msgif, wd, pstdin, pstdout, pstderr); IF p = NIL THEN ret := -1; ELSE ret := Process.Wait(p); END; IF stdin # NIL THEN TRY stdin.close(); EXCEPT OSError.E(list) => RAISE ExecuteError("close failed on stdin: " & AtomListToText(list)); END; END; IF stdout # NIL THEN TRY stdout.close(); EXCEPT OSError.E(list) => RAISE ExecuteError("close failed on stdout: " & AtomListToText(list)); END; END; IF stderr # NIL AND stderr # stdout THEN TRY stderr.close(); EXCEPT OSError.E(list) => RAISE ExecuteError("close failed on stderr: " & AtomListToText(list)); END; END; RETURN ret; END Exec;
PROCEDURE---------------------------------------------------------------------------Execute (cmd : TEXT; env : ProcessEnv.T := NIL; msgif : MsgIF.T := NIL; wd : TEXT := NIL) : INTEGER RAISES {ExecuteError, Thread.Alerted} = VAR rd := TextRd.New(cmd); token : TEXT; pgm : TEXT; args := NEW(TextSeq.T).init(10); BEGIN MsgX.D(msgif, "System.Execute(" & cmd & ")"); TRY pgm := TextReadingUtils.GetToken(rd); WHILE NOT Rd.EOF(rd) DO token := TextReadingUtils.GetTokenOrString(rd); args.addhi(token); END; EXCEPT Rd.Failure, Rd.EndOfFile => (* skip *) END; RETURN Exec(pgm, args, env, msgif, wd); END Execute;
PROCEDURE---------------------------------------------------------------------------ExecuteShell (cmd : TEXT; shell := "/bin/sh"; env : ProcessEnv.T := NIL; msgif : MsgIF.T := NIL; wd : TEXT := NIL) : INTEGER RAISES {ExecuteError} = VAR stdin, stdout, stderr: File.T; child : Process.T; args : ARRAY [1..2] OF TEXT; senv := ProcessEnv.SystemRepr(env); BEGIN MsgX.D(msgif, "System.ExecuteShell(" & cmd & ")"); Process.GetStandardFileHandles(stdin, stdout, stderr); args[1] := "-c"; args[2] := OSSpecials.QuotedProcessArgument(cmd); TRY child := Process.Create(shell, args, senv, wd, stdin, stdout, stderr); EXCEPT OSError.E(list) => RAISE ExecuteError("execution of `" & shell & " -c " & cmd & "' failed: " & AtomListToText(list)); END; RETURN Process.Wait(child); END ExecuteShell;
PROCEDURE---------------------------------------------------------------------------ExecuteList (cmd : TEXT; env : ProcessEnv.T := NIL; msgif : MsgIF.T := NIL; wd : TEXT := NIL) : INTEGER RAISES {ExecuteError, Thread.Alerted} = CONST STDINC = 10000000; STDOUTC = 10000001; STDERRC = 10000002; PIPEWR = 10000003; SPACES = ASCII.Spaces; IDEND = SPACES + ASCII.Set{ '<', '>', '&', '|', ';', '$' }; OPS = ASCII.Set{ '<', '>', '&', '|', ';', '$' }; OPEND = ASCII.All - OPS; S12 = ASCII.Set{ '1', '2' }; NUM = ASCII.Digits; NUMEND = ASCII.All - NUM; STRDELIM = ASCII.Set{ '\'', '\"' }; VAR rd := TextRd.New(cmd); token : TEXT; tokenLength : CARDINAL; token2: TEXT; pgm : TEXT := NIL; args : TextSeq.T := NIL; done : BOOLEAN; ret : INTEGER := 0; childWr, childRd : Pipe.T := NIL; stdin, stdout, stderr: File.T; child: Process.T; jobid: INTEGER := 1; cjobid: INTEGER := 1; openFiles: IntRefTbl.T := NEW(IntRefTbl.Default).init(); processes: RefSeq.T := NEW(RefSeq.T).init(); c: CHAR; readOp: BOOLEAN := FALSE; PROCEDURE WaitForAll() : INTEGER = VAR p: Process.T; ret: INTEGER := 0; BEGIN WHILE processes.size() > 0 DO p := NARROW(processes.remlo(), Process.T); ret := Process.Wait(p); CloseFiles(cjobid); INC(cjobid); END; RETURN ret; END WaitForAll; PROCEDURE RememberFiles(stdin: File.T; stdout: File.T; stderr: File.T; pipewr: File.T) = BEGIN IF stdin # NIL THEN EVAL openFiles.put(STDINC + jobid, stdin) END; IF stdout # NIL THEN EVAL openFiles.put(STDOUTC + jobid, stdout) END; IF stderr # NIL THEN EVAL openFiles.put(STDERRC + jobid, stderr) END; IF pipewr # NIL THEN EVAL openFiles.put(PIPEWR + jobid, pipewr) END; END RememberFiles; PROCEDURE CloseFiles(jobid: INTEGER) = VAR ref: REFANY; BEGIN IF openFiles.get(PIPEWR + jobid, ref) THEN TRY WITH f = NARROW(ref, File.T) DO f.close(); END; EXCEPT OSError.E => (* skip *) END; END; IF openFiles.get(STDINC + jobid, ref) THEN TRY WITH f = NARROW(ref, File.T) DO f.close(); END; EXCEPT OSError.E => (* skip *) END; END; IF openFiles.get(STDOUTC + jobid, ref) THEN TRY WITH f = NARROW(ref, File.T) DO f.close(); END; EXCEPT OSError.E => (* skip *) END; END; IF openFiles.get(STDERRC + jobid, ref) THEN TRY WITH f = NARROW(ref, File.T) DO f.close(); END; EXCEPT OSError.E => (* skip *) END; END; END CloseFiles; PROCEDURE CheckOp( token: TEXT ) RAISES {ExecuteError} = VAR len := Text.Length(token); BEGIN IF (len = 0) OR (len > 3) OR ( NOT Text.Equal(token, "<") AND NOT Text.Equal(token, ">") AND NOT Text.Equal(token, "1>") AND NOT Text.Equal(token, "2>") AND NOT Text.Equal(token, "&>") AND NOT Text.Equal(token, ">>") AND NOT Text.Equal(token, "1>>") AND NOT Text.Equal(token, "2>>") AND NOT Text.Equal(token, "&>>") AND NOT Text.Equal(token, ";") AND NOT Text.Equal(token, "|") AND NOT Text.Equal(token, "||") AND NOT Text.Equal(token, "&&")) THEN RAISE ExecuteError("operator syntax error: " & token); END; END CheckOp; PROCEDURE CurrentChar( rd: Rd.T ): CHAR RAISES {Thread.Alerted, Rd.Failure, Rd.EndOfFile} = VAR c: CHAR; BEGIN c := Rd.GetChar( rd ); Rd.UnGetChar( rd ); RETURN c; END CurrentChar; BEGIN MsgX.D(msgif, "System.ExecuteList(" & cmd & ")"); TRY WHILE NOT Rd.EOF(rd) DO pgm := TextReadingUtils.GetToken(rd, terminate := IDEND, unget := TRUE); args := NEW(TextSeq.T).init(10); done := FALSE; WHILE NOT done AND NOT Rd.EOF(rd) DO readOp := FALSE; token := NIL; c := RdExtras_Skip(rd, unget := TRUE); IF c IN NUM THEN token := TextReadingUtils.GetToken(rd, terminate := NUMEND, unget := TRUE); IF c IN S12 AND Text.Length( token ) = 1 THEN c := CurrentChar( rd ); readOp := c = '>'; END; END; IF c IN OPS OR readOp THEN token2 := TextReadingUtils.GetToken(rd, terminate := OPEND, unget := TRUE); IF token = NIL THEN token := token2; ELSE token := token & token2; END; IF c IN OPS THEN CheckOp( token ); END; ELSIF c IN STRDELIM THEN token := TextReadingUtils.GetString(rd); ELSIF token = NIL THEN token := TextReadingUtils.GetToken(rd, terminate := IDEND, unget := TRUE); END; tokenLength := Text.Length( token ); (* MsgX.D(msgif, " token = " & token); *) IF (tokenLength = 1) AND Text.Equal(token, ";") THEN IF childRd = NIL THEN ret := Exec(pgm, args, env, msgif, wd); ELSE child := ExecNW(stdin, stdout, stderr, pgm, args, env, msgif, wd, pstdin := childRd); IF child # NIL THEN processes.addhi(child) END; RememberFiles(stdin, stdout, stderr, NIL); IF processes.size() > 0 THEN ret := WaitForAll(); END; INC(jobid); childRd := NIL; END; done := TRUE; ELSIF (tokenLength = 2) AND Text.Equal(token, "&&") THEN IF childRd = NIL THEN ret := Exec(pgm, args, env, msgif, wd); ELSE child := ExecNW(stdin, stdout, stderr, pgm, args, env, msgif, wd, pstdin := childRd); IF child # NIL THEN processes.addhi(child) END; RememberFiles(stdin, stdout, stderr, NIL); IF processes.size() > 0 THEN ret := WaitForAll(); END; INC(jobid); childRd := NIL; END; IF ret # 0 THEN RETURN ret; END; done := TRUE; ELSIF (tokenLength = 2) AND Text.Equal(token, "||") THEN IF childRd = NIL THEN ret := Exec(pgm, args, env, msgif, wd); ELSE child := ExecNW(stdin, stdout, stderr, pgm, args, env, msgif, wd, pstdin := childRd); IF child # NIL THEN processes.addhi(child) END; RememberFiles(stdin, stdout, stderr, NIL); IF processes.size() > 0 THEN ret := WaitForAll(); END; INC(jobid); childRd := NIL; END; IF ret = 0 THEN RETURN ret; END; done := TRUE; ELSIF (tokenLength = 1) AND Text.Equal(token, "|") THEN VAR lastChildRd := childRd; BEGIN TRY Pipe.Open(hr := childRd, hw := childWr); EXCEPT OSError.E(l) => RAISE ExecuteError("pipe creation error (" & AtomListToText(l) & ")"); END; child := ExecNW(stdin, stdout, stderr, pgm, args, env, msgif, wd, pstdin := lastChildRd, pstdout := childWr); END; IF child # NIL THEN processes.addhi(child) END; RememberFiles(stdin, stdout, stderr, childWr); done := TRUE; INC(jobid); ELSE args.addhi(token); END; END; END; EXCEPT Rd.Failure, Rd.EndOfFile => (* skip *) END; IF NOT done AND pgm # NIL AND args # NIL THEN IF childRd = NIL THEN ret := Exec(pgm, args, env, msgif, wd); ELSE child := ExecNW(stdin, stdout, stderr, pgm, args, env, msgif, wd, pstdin := childRd); IF child # NIL THEN processes.addhi(child) END; RememberFiles(stdin, stdout, stderr, NIL); INC(jobid); END; END; IF processes.size() > 0 THEN ret := WaitForAll(); END; RETURN ret; END ExecuteList;
PROCEDURE---------------------------------------------------------------------------SplitCmd (cmd : TEXT; VAR prog : TEXT; VAR pargs : REF ARRAY OF TEXT) RAISES {Thread.Alerted} = VAR args := NEW(TextSeq.T).init(10); BEGIN TRY WITH tmpRd = TextRd.New(cmd) DO prog := TextReadingUtils.GetToken(tmpRd); WHILE NOT Rd.EOF(tmpRd) DO args.addhi(TextReadingUtils.GetTokenOrString(tmpRd)); END; END; EXCEPT Rd.Failure, Rd.EndOfFile => (* skip *) END; pargs := NEW(REF ARRAY OF TEXT, args.size()); FOR i := 0 TO args.size() - 1 DO pargs^[i] := OSSpecials.QuotedProcessArgument(args.get(i)); END; END SplitCmd;
PROCEDURE---------------------------------------------------------------------------RdExecute (cmd : TEXT; VAR rd : Rd.T; wd : TEXT := NIL; env : ProcessEnv.T := NIL; msgif : MsgIF.T := NIL) : Process.T RAISES {ExecuteError, Thread.Alerted} = VAR prog : TEXT; pargs : REF ARRAY OF TEXT; childWr, selfRd : Pipe.T; pid : Process.T; senv := ProcessEnv.SystemRepr(env); stdinParent, stdoutParent, stderrParent : File.T; BEGIN IF wd = NIL THEN wd := "." END; MsgX.D(msgif, "RdExecute(" & cmd & ")(" & wd & ")"); Process.GetStandardFileHandles(stdinParent, stdoutParent, stderrParent); SplitCmd(cmd, prog, pargs); TRY Pipe.Open(hr := selfRd, hw := childWr); pid := Process.Create(prog, pargs^, senv, wd, stdinParent, childWr, childWr); EXCEPT OSError.E(l) => VAR t := AtomListToText(l); BEGIN IF Text.Equal(t, "errno=2") THEN RAISE ExecuteError("execution of: '" & cmd & "' in wd: " & wd & "\n *** process creation error. (executable not found)"); END; RAISE ExecuteError("process/pipe creation error. (" & t & ")"); END; END; TRY childWr.close(); EXCEPT OSError.E => (* skip *) END; TRY rd := NEW(FileRd.T).init(selfRd); EXCEPT OSError.E(l) => RAISE ExecuteError("pipe read error. (" & AtomListToText(l) & ")"); END; RETURN pid; END RdExecute;
PROCEDURE---------------------------------------------------------------------------PipeTo (cmd : TEXT; VAR wr : Wr.T; wd : TEXT := NIL; env : ProcessEnv.T := NIL; msgif : MsgIF.T := NIL) : Process.T RAISES {ExecuteError, Thread.Alerted} = VAR prog : TEXT; pargs : REF ARRAY OF TEXT; childRd, selfWr : Pipe.T; pid : Process.T; senv := ProcessEnv.SystemRepr(env); stdinParent, stdoutParent, stderrParent : File.T; BEGIN IF wd = NIL THEN wd := "." END; MsgX.D(msgif, "PipeTo(" & cmd & ")(" & wd & ")"); Process.GetStandardFileHandles(stdinParent, stdoutParent, stderrParent); SplitCmd(cmd, prog, pargs); TRY Pipe.Open(hr := childRd, hw := selfWr); pid := Process.Create(prog, pargs^, senv, wd, childRd, stdoutParent, stderrParent); EXCEPT OSError.E(l) => VAR t := AtomListToText(l); BEGIN IF Text.Equal(t, "errno=2") THEN RAISE ExecuteError("execution of: '" & cmd & "' in wd: " & wd & "\n *** process creation error. (executable not found)"); END; RAISE ExecuteError("process/pipe creation error. (" & t & ")"); END; END; TRY childRd.close(); EXCEPT OSError.E => (* skip *) END; TRY wr := NEW(FileWr.T).init(selfWr); EXCEPT OSError.E(l) => RAISE ExecuteError("pipe write error. (" & AtomListToText(l) & ")"); END; RETURN pid; END PipeTo;
PROCEDURE---------------------------------------------------------------------------Filter (cmd : TEXT; VAR rd : Rd.T; VAR wr : Wr.T; wd : TEXT := NIL; env : ProcessEnv.T := NIL; msgif : MsgIF.T := NIL) : Process.T RAISES {ExecuteError, Thread.Alerted} = VAR prog : TEXT; pargs : REF ARRAY OF TEXT; childRd, childWr, selfRd , selfWr : Pipe.T; pid : Process.T; senv := ProcessEnv.SystemRepr(env); stdinParent, stdoutParent, stderrParent : File.T; BEGIN IF wd = NIL THEN wd := "." END; MsgX.D(msgif, "Filter(" & cmd & ")(" & wd & ")"); Process.GetStandardFileHandles(stdinParent, stdoutParent, stderrParent); SplitCmd(cmd, prog, pargs); TRY Pipe.Open(hr := selfRd, hw := childWr); Pipe.Open(hr := childRd, hw := selfWr); pid := Process.Create(prog, pargs^, senv, wd, childRd, childWr, stderrParent); EXCEPT OSError.E(l) => VAR t := AtomListToText(l); BEGIN IF Text.Equal(t, "errno=2") THEN RAISE ExecuteError("execution of: '" & cmd & "' in wd: " & wd & "\n *** process creation error. (executable not found)"); END; RAISE ExecuteError("process/pipe creation error. (" & t & ")"); END; END; TRY childRd.close(); childWr.close(); EXCEPT OSError.E => (* skip *) END; TRY wr := NEW(FileWr.T).init(selfWr); rd := NEW(FileRd.T).init(selfRd); EXCEPT OSError.E(l) => RAISE ExecuteError("pipe write error. (" & AtomListToText(l) & ")"); END; RETURN pid; END Filter;
PROCEDURE---------------------------------------------------------------------------RdExtras_Skip ( s: Rd.T; READONLY skip := ASCII.Spaces; unget := TRUE) : CHAR RAISES {Rd.Failure, Rd.EndOfFile, Thread.Alerted}= VAR ch: CHAR; BEGIN REPEAT ch := Rd.GetChar(s); UNTIL NOT(ch IN skip); IF unget THEN Rd.UnGetChar(s) END; RETURN ch; END RdExtras_Skip;
BEGIN END System.