/**************************************************************
 *
 *	CRISP - Custom Reduced Instruction Set Programmers Editor
 *
 *	(C) Paul Fox, 1989
 *
 *    Please See COPYLEFT notice.
 *
 **************************************************************/
# include	"list.h"
# include	"alt.h"
# include	<signal.h>
# include	"tty.h"
# include	"clk.h"
# if	CR_DOS
# include	<process.h>
# endif

extern	vbyte_t	*blanks;

# define	BOLD	0x01
# define	REVERSE	0x02

static int entry = 0;
extern fd_set	sel_bits;

/**********************************************************************/
/*   Prototypes							      */
/**********************************************************************/
int	check_if_died();
int	create_ipc();
int	create_pipe();
int	create_pty();
int	dup2();
static char *	flush_pty_buf();
static void	free_display();
void	do_connect();
void	do_disconnect();
void	inq_process_position();
void	p_wait_common();
void	p_wait_for();
void	send_signal();
void	set_process_position();


int	num_pty = 0;

void
send_signal()
{
	if (curbp->b_display) {
		/* Send signal to process group */
		acc_assign_int((long) kill(-curbp->b_display->d_pid, argv[1].l_int));
		}
	else
		acc_assign_int(0L);
}
void
inq_process_position()
{
	if (curbp->b_display == NULL) {
		acc_assign_int(-1L);
		return;
		}
	acc_assign_int(0L);
	argv_assign(1, (long) curbp->b_display->d_line_marker);
	argv_assign(2, (long) curbp->b_display->d_col_marker);
}
void
set_process_position()
{	int	line = argv[1].l_int > curbp->b_numlines
			? curbp->b_numlines
			: argv[1].l_int;

	if (curbp->b_display == NULL) {
		acc_assign_int(-1L);
		return;
		}
	acc_assign_int(0L);
	if (argv[1].l_flags != F_NULL) {
		curbp->b_display->d_line_marker = line;
		curbp->b_display->d_col_marker = 1;
		}
	if (argv[2].l_flags != F_NULL)
		curbp->b_display->d_col_marker = argv[2].l_int;
}
static void
free_display(dp)
DISPLAY *dp;
{
	chk_free((char *) dp);
}
DISPLAY *
p_create(x, y)
int	x;
int	y;
{
	DISPLAY	*dp = (DISPLAY *)  chk_alloc(sizeof (DISPLAY));

	if (dp == NULL)
		return (DISPLAY *) NULL;
	dp->d_escptr = NULL;
	dp->d_flags = 0;
	dp->d_x = dp->d_y = 0;
	dp->d_rows = (short) y;
	dp->d_cols = (short) x;
	dp->d_color = FG(WHITE);
	dp->d_attr = 0;
	dp->d_wlen = 0;
	dp->d_waitfor = (char *) NULL;
	dp->d_line_marker = 1;
	dp->d_col_marker = 1;

	return dp;
}
void
p_destroy(bp)
BUFFER	*bp;
{
	if (bp->b_display) {
		chk_free((char *) bp->b_display);
		if (bp->b_display->d_waitfor)
			chk_free(bp->b_display->d_waitfor);
		bp->b_display = NULL;
		}
}
void
p_wait()
{

	if (curbp->b_display == NULL) {
		acc_assign_int(-1L);
		return;
		}
		
	/***********************************************/
	/*   Wait for process to disappear.	       */
	/***********************************************/
	acc_assign_int(0L);
	while (curbp->b_display) {
		if (getkey(1000) == ' ') {
			acc_assign_int(-2L);
			break;
			}
		}	
	argv_assign(1, (long) curbp->b_wstat);
}
void
p_wait_for()
{				      
 	p_wait_common(argv[1].l_flags == F_NULL ? 0l : argv[1].l_int,
			argv[2].l_flags,
			(LIST *) get_str(2), FALSE);
}
void
p_wait_common(tmo, type, lp, waiting)
long	tmo;
int	type;
LIST	*lp;
int	waiting;
{
# if	defined(VMS) || defined(MSDOS)
	return;
# else
	char	buf[2];
# define	QUEUE_SIZE 32
	char	queue[QUEUE_SIZE+1];
	int	i;
	int	len;
	char	*str_arg = NULL;
	int	fd = curbp->b_display->d_pipe_in;
	int	flags = fcntl(fd, F_GETFL, 0);
	extern REGEXP *prog;
	extern int child_sig;
	char	*qp;

	acc_assign_int(-1L);
	if (curbp->b_display == NULL) {
		if (!waiting)
			ewprintf("cannot wait on a normal buffer.");
		return;
		}

	if (type != F_LIST)
		str_arg = (char *) lp;
	curbp->b_display->d_flags |= P_WAITING;
	buf[1] = NULL;
	queue[QUEUE_SIZE] = NULL;
	qp = &queue[QUEUE_SIZE];
	if (tmo)
		wait_state |= WAIT_WAIT;
	len = QUEUE_SIZE;
	if (str_arg && (prog = regcomp(str_arg)) == NULL)
		goto end_of_function;

	while (1) {
		int	n;
		LIST	*lp1;

		if (curbp->b_display == NULL) {
			acc_assign_int(-1L);
			break;
			}
		if (typeahead()) {
			break;
			}
			
		/***********************************************/
		/*   There  is  a  race condition in the code  */
		/*   below  and  I  dont know how to solve it  */
		/*   portably.  Hopefully  the  window is too  */
		/*   small to cause a problem.		       */
		/***********************************************/
		if (child_sig) {
			i = -1;
			}
		else {
			fcntl(fd, F_SETFL, flags & ~O_NDELAY);
			if (child_sig) {
				i = -1;
				}
			if (second_passed)
				update();       
			i = read(fd, buf, 1);
			fcntl(fd, F_SETFL, flags);
			}
		if (i != 1) {
			if (check_if_died(curbp)) {
				break;
				}
			update();
			i = read(fd, buf, 1);
			}
		if (i != 1)
			continue;
		p_update(curbp, buf);
		if (waiting)
			continue;

		memcpy(queue, queue+1, QUEUE_SIZE - 1);
		queue[QUEUE_SIZE - 1] = buf[0];
		if (qp > queue)
			qp--;
		if (len > 0)
			len--;
		if (str_arg) {
			if (regexec(prog, qp, strlen(qp)) == TRUE) {
				acc_assign_int(1L);
				break;
				}
			continue;
			}
		for (n = 0, lp1 = lp; *lp1 != F_HALT; n++, lp1 += sizeof_atoms[*lp1]) {
			char *str;
			if (*lp1 == F_STR || *lp1 == F_LIT)
				str = (char *) LGET32(lp1);
			else if (*lp1 == F_RSTR)
				str = ((ref_t *) LGET32(lp1))->r_ptr;
			else
				continue;
			if ((prog = regcomp(str)) == NULL)
				goto end_of_function;

			qp = queue + QUEUE_SIZE - strlen(str);
			if (regexec(prog, qp, strlen(qp)) == TRUE) {
				acc_assign_int((long) n);
				goto end_of_function;
				}
			}
		}
end_of_function:
	update();
	if (curbp->b_display)
		curbp->b_display->d_flags &= ~P_WAITING;
	wait_state &= ~WAIT_WAIT;
# endif
}
void
p_update(bp, buf)
BUFFER	*bp;
char	*buf;
{	WINDOW	*wp;

	p_addstr(bp, buf);
	for (wp = wheadp; wp; wp = wp->w_wndp)
		if (wp->w_bufp == bp) {
			wp->w_flag |= WFHARD;
			wp->w_line = bp->b_display->d_line_marker;
			}
}
void
p_addstr(bp, str)
BUFFER	*bp;
char	*str;
{	register DISPLAY *dp = bp->b_display;
	BUFFER *saved_bp = curbp;
	int	pos;
	int	cursor_moved = FALSE;
	int	orig_line;
	int	saved_system = bp->b_flag & BF_NO_UNDO;
	char	*start_ptr = NULL;
	char	*endstr;

	curbp = bp;
	curbp->b_flag |= BF_NO_UNDO;

	set_hooked();
	pos = current_col(llength(linep(*cur_line))) - *cur_col;
	orig_line = *cur_line;
	*cur_line = dp->d_line_marker;
	if (*cur_line > curbp->b_numlines)
		*cur_line = curbp->b_numlines;
	*cur_col = dp->d_col_marker;

	for ( ; *str; str++) {
		if (dp->d_escptr) {
			*dp->d_escptr++ = *str;
			if (isalpha(*str) || dp->d_escape[0] != '[') {
				*dp->d_escptr = NULL;
				cursor_moved = TRUE;
				p_escape(dp, TRUE);
				}
			continue;
			}
		endstr = str;
		switch (*str) {
		  case ESC:
		  	start_ptr = flush_pty_buf(start_ptr, str);
			dp->d_escptr = dp->d_escape;
			break;
		  case 0x07:
		  	start_ptr = flush_pty_buf(start_ptr, str);
		  	ttbeep();
			break;
		  case '\r':
		  	if (str[1] != '\n') {
			  	start_ptr = flush_pty_buf(start_ptr, str);
				*cur_col = 1;
			  	break;
				}
			endstr = str++;
			/* Fallthru.. */
		  case '\n':
		  	start_ptr = flush_pty_buf(start_ptr, endstr);
			if (dp->d_flags & P_OVERWRITE) {
			  	if (*cur_line < curbp->b_numlines) {
					(*cur_line)++;
					*cur_col = 1;
					break;
					}
			  	linsert(str, 1);
				}
			else {
				lnewline();
				flush_cache(curbp);
				}
			break;
		  case '\b':
		  	start_ptr = flush_pty_buf(start_ptr, str);
		  	if (*cur_col > 1)
				(*cur_col)--;
			break;
		  case '\f':
		  	start_ptr = flush_pty_buf(start_ptr, str);
			break;
		  default:
		  	if (start_ptr == NULL)
				start_ptr = str;
			break;
		  }
		}
  	start_ptr = flush_pty_buf(start_ptr, str);
	dp->d_line_marker = *cur_line;
	dp->d_col_marker = *cur_col;

	if (!cursor_moved) {
		if (*cur_line != orig_line)
			pos = 0;
		*cur_col = current_col(llength(linep(*cur_line))) - pos;
		if (curwp && curwp->w_bufp == curbp)
			set_buffer_parms(curwp, bp);
		}

	curbp->b_flag = (curbp->b_flag & ~BF_NO_UNDO) | saved_system;
	curbp = saved_bp;
	set_hooked();
}
static char *
flush_pty_buf(start, end)
char	*start;
char *end;
{	LINE *lp = linep(*cur_line);
	int	coff;
	RSIZE 	diff;
	int	len;

	if (start == NULL)
		return NULL;
		
	coff = current_offset(*cur_col, TRUE);
	len = end - start;
	diff = lp->l_used - coff;
	if (diff > len)
		diff = len;
	if (diff && (curbp->b_display->d_flags & P_OVERWRITE)) {
		lreplace(start, len, diff, coff);
		return NULL;
		}
	llinsert(start, (u_int32) len, FALSE);
	return NULL;
}
void
p_escape(dp, modify)
register DISPLAY	*dp;
int	modify;
{
	register char *cp = dp->d_escape;
	u_int16	args[MAX_ESCAPE];
	u_int16	arg_no = 0;
	u_int16	one_base;
	u_int16	two_base;
	u_int16	i;
	LISTV	local_argv[MAX_ARGC];

	argv = local_argv;
	for(arg_no = 0; arg_no < MAX_ESCAPE; )
		args[arg_no++] = 0;
	arg_no = 0;

	dp->d_escptr = NULL;
	if (*cp++ != '[')
		return;
	while (*cp) {
		if (isalpha(*cp))
			break;
		if (*cp == ';') {
			cp++;
			args[arg_no++] = 0;
			continue;
			}
		if (!isdigit(*cp))
			return;
		args[arg_no++] = (u_int16) atoi(cp);
		while (isdigit(*cp))
			cp++;
		if (*cp == ';')
			cp++;
		}

	one_base = (u_int16) (args[0] == 0 ? 1 : args[0]);
	two_base = (u_int16) (args[1] == 0 ? 1 : args[1]);
	switch (*cp) {
	  case '@':
	  case 'A':
		dp->d_y -= one_base;
		break;
	  case 'B':
		dp->d_y += one_base;
		break;
	  case 'C':
		*cur_col += one_base;
		break;
	  case 'D':
	  	*cur_col -= one_base;
		break;
	  case 'f':
	  case 'H': {
	  	int lines_to_insert = one_base - curbp->b_numlines;
		if (lines_to_insert > 256)
			lines_to_insert = 256;
	  	*cur_line = one_base;
		*cur_col = two_base; 
		lpad_lines();
		dp->d_y = curwp->w_top_line + one_base;
		dp->d_x = two_base;
		break;
		}
	  case 'J': {
		if (args[0] == 2)
	  		*cur_line = curwp->w_top_line;
		argv[1].l_int = MK_LINE;
		argv[1].l_flags = F_INT;
		while (*cur_line < curbp->b_numlines)
			lfree(curbp, *cur_line);
		break;
		}
	  case 'K':
	  	del_to_eol();
		break;
	  case 'M':
	  case 'X':
		break;
	  case 'm':
		for (i = 0; i < arg_no; i++) {
			int j = args[i];
			extern int ab_color_map[];
			switch (j) {
			  case 0:
			  	dp->d_color = FG(WHITE);
				dp->d_attr &= ~(BOLD | REVERSE);
				break;
			  case 1:
				dp->d_attr |= BOLD;
				break;
			  case 7:
				dp->d_attr |= REVERSE;
				break;
			  case 30: case 31: case 32: case 33: case 34:
			  case 35: case 36: case 37:
			  	j = ab_color_map[j - 30];
				dp->d_color = (dp->d_color & ~FG_COLOR) | 
						FG(j);
				j += 30;
				break;
			  case 40: case 41: case 42: case 43: case 44:
			  case 45: case 46: case 47:
			  	j = ab_color_map[j - 40];
				dp->d_color = (dp->d_color & ~BG_COLOR) | 
						BG(j);
				j += 40;
				break;
			  }
			if (modify) {
				extern int global_dot;
				extern LINE *global_lp;
				u_char	*cp;
				sprintf(dp->d_escape, "\033[%dm", args[i]);
				
				llinsert("", 0, 0);
				cp = &global_lp->l_text[global_dot]; 
				if (global_dot >= 5 &&
				    cp[-1] == 'm' && isdigit(cp[-2]) && isdigit(cp[-3]) &&
				    cp[-3] == dp->d_escape[2] &&
				    cp[-4] == '[' && cp[-5] == '\033')
				    	memcpy(cp-5, dp->d_escape, 5);
				else
					linsert(dp->d_escape, strlen(dp->d_escape));
				dp->d_x = *cur_col;
				dp->d_y = *cur_line;
				}
			}
		break;
	  }

	if (*cur_col < 1)
		*cur_col = 1;
	if (dp->d_x < 0)
		dp->d_x = 0;
	else if (dp->d_x >= dp->d_cols)
		dp->d_x = dp->d_cols - 1;
	if (dp->d_y < 0)
		dp->d_y = 0;
	else if (dp->d_y >= dp->d_rows)
		dp->d_y = dp->d_rows - 1;

}
static	int	pipe1[2], pipe2[2];
int
create_ipc(send, recv)
int	*send;
int	*recv;
{	int	pid;

	/***********************************************/
	/*   Try  to  use a pty first. If that fails,  */
	/*   then  try  and  use  a  pipe. On systems  */
	/*   with  pty  support  but running a binary  */
	/*   with  the  pty code compiled in, then we  */
	/*   should work just fine.		       */
	/***********************************************/
	if ((pid = create_pty(send, recv)) < 0)
		if ((pid = create_pipe(send, recv)) < 0)
			return -1;

	/***********************************************/
	/*   At  this  point  we have created the IPC  */
	/*   mechanism,  and  we  are running in both  */
	/*   the parent and child, via fork().	       */
	/***********************************************/
# if	defined(SIGTTIN)
	if (pid == 0) {
		signal(SIGTTIN, SIG_DFL);
		signal(SIGTTOU, SIG_DFL);
		}
# endif
	return pid;
}
int
create_pty(send, recv)
int	*send;
int	*recv;
{	int	pid;
# if !defined(HAVE_PTY)
	return -1;
# else
	/***********************************************/
	/*   System  V  ptys  (386/ix  +  TCP) are of  */
	/*   the   form  /dev/ptyp0,  /dev/ptyp1,  ..  */
	/*   SunOS/BSD   ptys   are   of   the   form  */
	/*   /dev/ptyq0,   /dev/ptyq1,   ..   So   we  */
	/*   complicate  the  code  below  to  handle  */
	/*   both.				       */
	/***********************************************/
# define	PTY_NAME	"/dev/ptyXX"
# define	TTY_NAME	"/dev/ttyXX"
# define	TTY_MODE	0622
	char	pty_name[20];
	char	tty_name[20];
	int	first_letter = 'q';
	int	last_letter = 'z';
	int	xx;
	int	c1, c2;
	int	mode = O_RDWR;
	
	if (getenv("BIPC"))
		return -1;
	strcpy(pty_name, PTY_NAME);
	strcpy(tty_name, TTY_NAME);
	for (xx = 0; pty_name[xx] != 'X'; )
		xx++;
# if defined(SYSV)
	first_letter = 'p';
# endif
	for (c1 = first_letter; c1 != last_letter; c1++) {
		for (c2 = 0; c2 < 0x10; c2++) {
			tty_name[xx] = pty_name[xx] = c1;
			tty_name[xx+1] = pty_name[xx+1] = 
				c2 >= 0x0a ? (c2 + 'a' - 0x0a) 
					   : (c2 + '0');
			if ((*send = open(pty_name, mode)) >= 0) {
				goto ipc_created;
				}
			}
		}
	if (c1 >= 'z')
		return -1;

ipc_created:
	if ((pid = fork()) < 0)	{
		close(*send);
		close(*recv);
		return -1;
		}
	if (pid == 0) {
		int	mypid = getpid();
{extern int dflag; dflag = -1;}
# if defined(SIGTTIN)
		signal(SIGTTIN, SIG_DFL);
		signal(SIGTTOU, SIG_DFL);
# endif
		signal(SIGINT, SIG_DFL);
		/***********************************************/
		/*   Close our controlling tty.		       */
		/***********************************************/
		close(0);
		close(1);
		close(2);
		close(*send);
		
		/***********************************************/
		/*   Change  our  process group so we get the  */
		/*   tty as a controlling tty.		       */
		/***********************************************/
#ifdef LINUX
		setpgid(mypid, 0);
#else
		setpgrp(mypid, 0);
#endif
       		if ((*recv = open(tty_name, mode)) < 0) {
			_exit(0);
			}
		chown(tty_name, getuid(), getgid());
		chmod(tty_name, TTY_MODE);

		dup(*recv);
		dup(*recv);
		if (*recv != 0)
			close(*recv);
		/***********************************************/
		/*   Turn  off  echo and go into raw mode for  */
		/*   the pty.				       */
		/***********************************************/
# if defined(ICANON)
		setup_pty_mode(0);
# endif
		}
	else {
		*recv = *send;
# if defined(SIGTTIN)
		signal(SIGTTIN, SIG_IGN);
		signal(SIGTTOU, SIG_IGN);
# endif
		}
	return pid;
# endif
}
int
create_pipe(send, recv)	
int	*send;
int	*recv;
{	int	pid;

	if (pipe(pipe1) < 0)
		return -1;
	if (pipe(pipe2) < 0) {
		close(pipe1[0]);
		close(pipe1[1]);
		return -1;
		}
# if	defined(SPAWN)
	*send = pipe1[1];
	*recv = pipe2[0];
# else
	if ((pid = fork()) < 0) {
		close(pipe1[0]);
		close(pipe1[1]);
		close(pipe2[0]);
		close(pipe2[1]);
		return -1;
		}
	if (pid == 0) {
		/***********************************************/
		/*   Set  the  process  group  to be the same  */
		/*   as  the  current  PID  so we can send it  */
		/*   signals.  We  pass  an  argument so this  */
		/*   will work on SYSV and BSD		       */
		/***********************************************/
#ifdef LINUX
		setpgid(getpid(), getpid());
#else
		setpgrp(getpid(), getpid());
#endif
		dup2(pipe1[0], 0);
		dup2(pipe2[1], 1);
		dup2(pipe2[1], 2);
		close(pipe1[0]);
		close(pipe1[1]);
		close(pipe2[0]);
		close(pipe2[1]);
		}
	else {
		close(pipe2[1]);
		close(pipe1[0]);
		*send = pipe1[1];
		*recv = pipe2[0];
		}
	return pid;
# endif
}
void
do_connect()
{	register DISPLAY *dp;
	int	flags = argv[1].l_flags == F_NULL ? P_ECHO : argv[1].l_int;
	char	*sh = get_str(2);
	extern	char *get_shell();
	char *shell = (sh && sh[0]) ? sh : get_shell();
	
	if (curbp->b_display) {
		acc_assign_int(0L);
		curbp->b_display->d_flags = (u_int16) flags;
		return;
		}
	acc_assign_int(1L);
	dp = p_create(ncol, nrow-2);
	if (dp == NULL) {
		ewprintf("Couldn't allocate memory for connection.");
		return;
		}
	dp->d_flags = (u_int16) flags;
	
	/***********************************************/
	/*   Create  the  IPC mechanism (pipe or pty)  */
	/*   and fork a child.			       */
	/***********************************************/
	if ((dp->d_pid = create_ipc(&dp->d_pipe_out, &dp->d_pipe_in)) < 0) {
		free_display(dp);
		ewprintf("Couldn't create IPC.");
		return;
		}
# if	defined(SPAWN)
	{
	int saved_stdin = dup(0);
	int	saved_stdout = dup(1);
	int	saved_stderr = dup(2);
	noinherit(saved_stdin);
	noinherit(saved_stdout);
	noinherit(saved_stderr);
	noinherit(dp->d_pipe_out);
	noinherit(dp->d_pipe_in);
	
	dup2(pipe1[0], 0);
	dup2(pipe2[1], 1);
	dup2(pipe2[1], 2);
	noinherit(pipe1[0]);
	noinherit(pipe2[1]);
	dp->d_pid = spawnl(P_NOWAIT, shell, shell, "-i", (char *) NULL);
	dup2(saved_stdin, 0);
	close(saved_stdin);
	dup2(saved_stdout, 1);
	close(saved_stdout);
	dup2(saved_stderr, 2);
	close(saved_stderr);
	if (dp->d_pid < 0) {
		ewprintf("Couldn't spawn %s.", shell);
disp_err:
		close(pipe1[0]);
		close(pipe2[0]);
		close(pipe1[1]);
		close(pipe2[1]);
		free_display(dp);
		return;
		}
	if (create_pty_thread(dp) < 0) {
		ewprintf("Cannot create thread.");
		goto disp_err;
		}
	}
# endif
	proc_add(dp->d_pid, (char *) NULL);
	
	/***********************************************/
	/*   Child gets to exec a shell.	       */
	/***********************************************/
	if (dp->d_pid == 0) {
# if	defined(SIGCLD)
		signal(SIGCLD, SIG_DFL);
# endif
		execlp(shell, shell, "-i", (char *) NULL);
		trace_log("exec failed");
		_exit(1);
		}

	/***********************************************/
	/*   Parent gets to tidy up.		       */
	/***********************************************/
# if	defined(F_GETFL)
	flags = fcntl(dp->d_pipe_in, F_GETFL, 0);
	if (fcntl(dp->d_pipe_in, F_SETFL, flags | O_NDELAY) < 0)
		errorf("connect: fcntl error.");
	flags = fcntl(dp->d_pipe_out, F_GETFL, 0);
	if (fcntl(dp->d_pipe_out, F_SETFL, flags | O_NDELAY) < 0)
		errorf("connect: fcntl error.");
# endif
	acc_assign_int(0L);
	curbp->b_display = dp;
	if (dp->d_pid >= 0)
		infof("Buffer connected.");
	num_pty++;
	wait_state |= WAIT_PTY;
	add_input_device(dp->d_pipe_in);
	p_poll();
}
void
p_cleanup(bp)
BUFFER	*bp;
{
	DISPLAY *dp = bp->b_display;
	if (dp == NULL)
		return;
	remove_input_device(dp->d_pipe_in);
	close(dp->d_pipe_in);
	close(dp->d_pipe_out);
	if (dp->d_pid) {
		kill(dp->d_pid, SIGTERM); 
# if defined(SIGKILL)
		kill(dp->d_pid, SIGKILL); 
# endif
		}
	p_destroy(bp);
	infof("%s disconnected.", bp->b_fname);
	if (--num_pty == 0)
		wait_state &= ~WAIT_PTY;
}
void
do_disconnect()
{	register DISPLAY *dp = curbp->b_display;

	acc_assign_int(0L);
	if (dp == NULL)
		return;
	p_cleanup(curbp);
	p_poll();
}

/**********************************************************************/
/*   Function  to  poll  the  process  buffers to see if we have any  */
/*   input to update on the screen.				      */
/**********************************************************************/
void
p_poll()
{	register BUFFER	*bp;
	char	buf[256];
	DISPLAY	*dp;
	BUFFER	*saved_curbp = curbp;
	int	updated;
	int	i;

	/***********************************************/
	/*   Protect this code from being re-entered.  */
	/***********************************************/
	if (entry || num_pty <= 0) {
		num_pty = 0;
		wait_state &= ~WAIT_PTY;
		return;
		}

	entry++;
start_again:
	do {
		updated = FALSE;
		for (bp = bheadp; bp; bp = bp->b_bufp) {
			while (1) {
				dp = bp->b_display;
				if (dp == NULL || dp->d_flags & P_WAITING)
					break;
# if CR_DOS
				i = dos_read_pty(bp);
# else
				i = read(dp->d_pipe_in, buf, sizeof buf - 1);
# endif
				if (i <= 0) {
					/***********************************************/
					/*   If   process   died  start  loop  again,  */
					/*   because  this  buffer  entry  will  have  */
					/*   been modified.			       */
					/***********************************************/
					if (check_if_died(bp))
						goto start_again;
					break;
					}
# if !CR_DOS
				buf[i] = NULL;
				p_update(bp, buf);
# endif
				updated = TRUE;
				}
			}
			
		/***********************************************/
		/*   Update  screen  if  necessary  and  make  */
		/*   sure   that   the   current   buffer  is  */
		/*   restored  so  that  cursor goes at right  */
		/*   place and in case we exit this loop.      */
		/***********************************************/
		curbp = saved_curbp;
		set_hooked();
		if (updated)
			update();
		}
	while (updated && !typeahead());
	
	/***********************************************/
	/*   Clear  semaphone  allowing  code  to  be  */
	/*   re-entered.			       */
	/***********************************************/
	entry--;
}
int
check_if_died(bp)
register BUFFER *bp;
{	extern int child_sig;

	if (child_sig)
		proc_wait(-1);
# if CR_DOS
	if (bp->b_display->d_dead) {
		p_cleanup(bp);
		return TRUE;
		}
# else
	if (kill(bp->b_display->d_pid, 0) < 0) {
		p_cleanup(bp);
		return TRUE;
		}
# endif
	return FALSE;
}
void
p_write(buf, len)
char	*buf;
int	len;
{
	if (curbp->b_display == NULL)
		return;
	write(curbp->b_display->d_pipe_out, buf, (int) len);
}
/*
static int
dup2(old, new)
int	old;
int	new;
{
	close(new);
	return dup(old);
}
*/
