
/* pty.q: run a child process in a pseudo terminal (UNIX only) */

import system;

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";

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;
