/* pty.q: run a child process in a pseudo terminal (UNIX only) */ public pty CMD; private driver PID FD, noecho FD; pty CMD = driver PID MASTER if PID > 0 where (PID, MASTER) = forkpty; = noecho 0 || exec "/bin/sh" ["/bin/sh", "-c", CMD] otherwise; /* Change the child's terminal attributes to disable echoing. */ noecho FD = tcsetattr FD TCSAFLUSH ATTR where ATTR = tcgetattr FD, (IF,OF,CF,LF,IS,OS,CC) = ATTR, LF = LF and not (ECHO or ECHOE or ECHOK or ECHONL), ATTR = (IF,OF,CF,LF,IS,OS,CC); /* A simple driver routine. We copy our standard input to the child's input and the child's output to our standard output. This has to be done in parallel, so we execute the input processing in a secondary thread. The returned result is the child's exit status. */ def EOF = bytestr "\4"; private fcopy F G; driver PID FD = fcopy FD 1 || close FD || waitpid PID 0!1 where TH:Thread = thread (fcopy 0 FD || bwrite FD EOF); def BUFSZ = 8192; fcopy F G = fcopy F G if (#B>0) and then (bwrite G B>0) where B:ByteStr = bread F BUFSZ; = () otherwise;