[comp.sources.unix] v16i064: Front end editor program, Part04/05

rsalz@uunet.uu.net (Rich Salz) (11/11/88)

Submitted-by: Kazumasa Utashiro <kddlab!sra.junet!utashiro>
Posting-number: Volume 16, Issue 64
Archive-name: fep/part04

#!/bin/sh
# to extract, remove the header and type "sh filename"
if `test ! -s ./fep_defs.h`
then
echo "writing ./fep_defs.h"
cat > ./fep_defs.h << '\End\Of\File\'
/*	Copyright (c) 1987, 1988 by Software Research Associates, Inc.	*/

#ifndef lint
# define FEP_DEFS \
    "$Header: fep_defs.h,v 4.0 88/08/05 20:21:51 utashiro Rel $ (SRA)"
#endif lint

#define	MAXCOMLEN		512	/* maximum command length */
#define MAXARGS			64	/* maximum number of arguments */
#define ON			1	/* on switch */
#define OFF			0	/* off switch */
#define DFL_HISTLEN		100	/* default history length */
#define DFL_SHOWHIST		20	/* default show history length */
#define	IGNORED			2	/* ignored */
#define	PROCESSED		1	/* processed or not by history */
#define	NOT_PROCESSED		0	/* built-in functions */

#define BS			'\b'	/* backspace character */
#define SP			' '	/* space character */

#define	DEFAULT_DELIMITERS	" \t"	/* default delimiter character */

/*
 * Pseudo functions
 */
#define eq(a,b)		(strcmp(a,b) == 0)
#define abs(a)		((a)>0?(a):-(a))
#define max(a,b)	((a)>(b)?(a):(b))
#define min(a,b)	((a)<(b)?(a):(b))
#ifdef KANJI
# define isctlchar(c)	(c && !iskanji(c) && (!(c&0140) || c=='\177'))
# define iswordchar(c)	(c && (iskanji(c) || isalnum(c) || iscntrl(c)))
# define isWordchar(c)	((c) && !isspace((c)))
#else KANJI
# define isctlchar(c)	(c && (!(c&0140) || c=='\177'))
# define iswordchar(c)	(isalnum(c) || iscntrl(c))
# define isWordchar(c)	((c) && !isspace((c)))
#endif KANJI
#define unctl(c)	(((c)=='\177') ? '?' : ((c) >= 040) ? (c) : (c)|0100)
#define toctrl(c)	((c)&~0100)

#define	INDIRECTED	(1<<(sizeof(char*)*8-1))
			/* this is actually 0x80000000 on 32 bit machine,
			that addresses kernel address space */
#define isIndirect(f)	((u_int)(f)&(u_int)INDIRECTED)
#define setIndirect(f)	(FUNC)((u_int)(f)|(u_int)INDIRECTED)
#define	maskIndirect(f)	(FUNC *)((u_int)(f)&~(u_int)INDIRECTED)

/*
 * Type of character
 */
#ifdef KANJI
# define CHAR		unsigned char
# define CHARMASK	0377
#else KANJI
# define CHAR		char
# define CHARMASK	0177
#endif KANJI

/*
 * Only one machine I know alloca() works is vax.
 */
#ifdef vax
# define ALLOCA
#endif vax

/*
 * Typedef's
 */
typedef	int	(*FUNC)();		/* pointer to funciton */

typedef enum {				/* edit status */
	EDITING,
	NOTEDITING
} EDITSTATUS;

typedef enum {				/* edit mode */
	NOTYET,
	EMACS,
	VI
} EDITMODE;

typedef struct {			/* bind table entry type */
	char	*bt_s;
	FUNC	bt_func;
} BINDENT;

typedef struct _var {
	char *v_name;
	char *v_value;
	char *v_help;
	struct _var *v_next;
} VAR;

typedef struct {
    char *buf;			/* buffer */
    char *last_buf;		/* last i/o done pointer */
    int b_max;			/* max size */
    int start;			/* start point */
    int next;			/* next read point */
    int count;			/* count */
    int hiwater;		/* high water mark */
} BUFFER;

#define buf_count(b) ((b)->count)
#define buf_remain(b) ((b)->size - (b)->count)
/*
char buf_char (b, n)
    BUFFER *b;
    int n;
{
    if (n >= 0) {
	if (n >= b->count)
	    return ((char*)-1);
	return (b->buf[(b->start+n)%b->count]);
    } else {
	if (-n >= b->count)
	    return (-1);
	if (b->next+n >= 0)
	    return (b->buf[b->next+n]);
	else
	    return (b->buf[b->next+n+b->count]);
    }
}
*/	    
#define buf_char(b,n) \
	(((n)>=0) \
	 ?(((n)>=(b)->count) \
	   ? ((char)-1) \
	   : ((b)->buf[((b)->start+n)%(b)->count])) \
	 :((-(n) > (b)->count) \
	   ?((char)-1) \
	   :((((b)->next+n) >= 0) \
	     ? ((b)->buf[(b)->next+(n)]) \
	     : ((b)->buf[(b)->next+n+(b)->count]))))
\End\Of\File\
else
  echo "will not over write ./fep_defs.h"
fi
if `test ! -s ./fep_glob.h`
then
echo "writing ./fep_glob.h"
cat > ./fep_glob.h << '\End\Of\File\'
/*	Copyright (c) 1987, 1988 by Software Research Associates, Inc.	*/

#ifndef lint
# define FEP_GLOB \
    "$Header: fep_glob.h,v 4.0 88/08/05 20:21:55 utashiro Rel $ (SRA)"
#endif lint

extern FUNC	*curFuncTab;	/* function table */
extern FUNC	*altFuncTab;	/* altanative function table */
extern int	debug;		/* debug flag */
extern char	*prompt;	/* prompt string */
extern char	*delimiters;	/* delimiter characters */
extern EDITMODE	editmode;	/* edit mode */
extern FILE	*redirect_fp;	/* FILE pointer for I/O redirection */
extern FILE	*script_fp;	/* FILE pointer for script */
extern int	redirect_line;	/* number of line for redirecting */
extern int	redirect_pid;	/* process id redirecting from */
extern int	auto_tty_fix;	/* fix tty mode automatically */
extern int	tty_fix_bell;	/* ring bell when tty mode is changed */
extern int	Transparency;	/* transparent flag */
extern EDITSTATUS   editstatus;	/* edit status */
extern BUFFER	*output_buffer;	/* output buffer */

extern int	lines, columns;	/* terminal sizes */
extern char	*term_clear;	/* terminal clear code */

/*
 * tty control caracters.
 * defined in fep_main.c
 */
extern struct tchars tchars_buf;
extern struct ltchars ltchars_buf;
extern struct sgttyb initial_ttymode;
\End\Of\File\
else
  echo "will not over write ./fep_glob.h"
fi
if `test ! -s ./fep_funcs.h`
then
echo "writing ./fep_funcs.h"
cat > ./fep_funcs.h << '\End\Of\File\'
/*	Copyright (c) 1987, 1988 by Software Research Associates, Inc.	*/

#ifndef lint
# define FEP_FUNCS \
    "$Header: fep_funcs.h,v 4.0 88/08/05 20:21:53 utashiro Rel $ (SRA)"
#endif lint

/*
 * command line edit functions
 */
int	abort();
int	backward_character();
int	backward_word();
int	backward_Word();
int	beginning_of_line();
int	clear_screen();
int	delete_line();
int	delete_next_character();
int	delete_next_word();
int	delete_next_Word();
int	delete_previous_character();
int	delete_previous_word();
int	delete_previous_Word();
int	delete_to_kill_buffer();
int	terminate();
int	end_of_line();
int	expand_file_name();
int	forward_character();
int	forward_to_end_of_word();
int	forward_to_end_of_Word();
int	forward_word();
int	forward_Word();
int	ignore();
int	insert_and_flush();
int	insert_tab();
int	kill_to_end_of_line();
int	kill_to_top_of_line();
int	list_file_name();
int	literal_next();
int	mark();
int	new_line();
int	next_history();
int	previous_history();
int	reprint();
int	search_reverse();
int	search_forward();
int	self_insert();
int	send_eof();
int	show_bindings();
int	show_history();
int	toggle_transparency();
int	fix_transparency();
int	yank_from_kill_buffer();
int	invoke_shell();
int	show_help();

/*
 * Vi mode functions.
 */
int	vi_num();
int	vi_edit();
int	vi_motion();
int	vi_c();
int	vi_d();
int	vi_ins_edit();
int	vi_new_line();

/*
 * fep builtin command functions.
 */
int	suspend();
int	bind_to_key();
int	alias();
int	unalias();
int	set();
int	unset();
int	fep_chdir();
int	fep_pwd();
int	fep_history();
int	show_bindings();
int	fep_source();
int	fep_command();
int	fep_save_history();
int	fep_start_script();
int	fep_end_script();
int	fep_read_history();
int	fep_read_from_file();
int	fep_read_from_command();
int	fep_echo();
int	fep_if();
int	fep_else();
int	fep_endif();
int	fep_repaint();
#ifdef STAT
int	fep_showstat();
#endif

/*
 * FunctionNameTable
 */
typedef struct {
	int (*func)();
	char *name;
	char *help;
} FunctionTableEnt;

extern FunctionTableEnt FunctionNameTable[];
extern FunctionTableEnt BuiltinFuncTable[];

char *look_var();
char *push_condition();
char *pop_condition();
char *change_condition();
\End\Of\File\
else
  echo "will not over write ./fep_funcs.h"
fi
if `test ! -s ./fep_stat.h`
then
echo "writing ./fep_stat.h"
cat > ./fep_stat.h << '\End\Of\File\'
/*	Copyright (c) 1987, 1988 by Software Research Associates, Inc.	*/

#ifndef lint
# define FEP_STAT \
    "$Header: fep_stat.h,v 4.0 88/08/05 20:21:58 utashiro Rel $ (SRA)"
#endif lint

extern long stat_obyte;
extern long stat_ibyte;
extern long stat_rerror;
extern long stat_werror;
extern long stat_nselect;

struct statistics {
    char *info_name;
    long *info_valp;
};
\End\Of\File\
else
  echo "will not over write ./fep_stat.h"
fi
if `test ! -s ./fep_main.c`
then
echo "writing ./fep_main.c"
cat > ./fep_main.c << '\End\Of\File\'
/*	Copyright (c) 1987, 1988 by Software Research Associates, Inc.	*/

#ifndef lint
static char rcsid[]=
"$Header: fep_main.c,v 4.0 88/08/05 20:22:17 utashiro Rel $ (SRA)";
#endif lint

#include <stdio.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/file.h>
#include <sgtty.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/errno.h>

#include "fep_defs.h"
#include "fep_glob.h"
#include "fep_funcs.h"
#ifdef STAT
#include "fep_stat.h"
#endif

#ifndef lint
  static char fep_defsrc[] = FEP_DEFS;
  static char fep_globrc[] = FEP_GLOB;
  static char fep_funcsrc[] = FEP_FUNCS;
#ifdef STAT
  static char fep_statrc[] = FEP_STAT;
#endif
#endif lint

char	*myself;			/* the command name */
char	*prompt = "";			/* prompt string */
char	*delimiters = DEFAULT_DELIMITERS;
					/* delimiter characters */
int	master;				/* file discriptor for pty master */
int	slave;				/* file discriptor for pty slave */
int	mastermask;			/* 1<<master */
int	stdinmask;			/* 1<<fileno(stdin) */
int	selectmask;			/* stdinmask | mastermask */
int	selectnfds;			/* max (fileno(stdin), master) + 1*/
int	child_pid;			/* child pid */
int	ptyflag = ON;			/* flag to use pty or not */
int	histlen = -1;			/* history length */
int	debug = OFF;			/* debug switch */
int	auto_tty_fix = ON;		/* fix tty mode automaticaly */
FILE	*script_fp = NULL;		/* script file pointer */
int	catchsig();			/* function take care SIGCHILD */

struct	sgttyb initial_ttymode;		/* initial tty mode */
struct	sgttyb master_ttymode;		/* master tty mode */
struct	sgttyb slave_ttymode;		/* slave tty mode */

int	lines;				/* terminal line size */
int	columns;			/* terminal coulumn size */
char	*term_clear;			/* terminal clear code */

FUNC	sighup, sigchld, sigtstp;	/* function buffer for signal */

struct	tchars tchars_buf;		/* tty characters */
struct	ltchars ltchars_buf;		/* tty characters */
int	lmode_buf;			/* local mode */
int	line_desc;			/* line descipline */
#ifdef KANJI
struct	jtchars jtchars_buf;		/* kanji tty characters */
int	kmode_buf;			/* kanji mode */
#endif KANJI

char	master_tty[16];			/* master tty name */
char	slave_tty[16];			/* slave tty name */

BUFFER iobuffer;			/* buffer self */
BUFFER *output_buffer = &iobuffer;	/* buffer pointer */

struct cmdinfo {
	char *command;
	char *prompt;
	char *delimiters;
} cmdinfo_tab [] = {
	{"/bin/sh",		"$ ",		" \t()<>{};&|='\""},
	{"sh",			"$ ",		" \t()<>{};&|='\""},
	{"jsh",			"$ ",		" \t()<>{};&|='\""},
	{"/bin/csh",		"% ",		" \t()<>{};&|='\""},
	{"csh",			"% ",		" \t()<>{};&|='\""},
	{"jcsh",		"% ",		" \t()<>{};&|='\""},
	{"/usr/ucb/dbx",	"(dbx) ",	" \t>"},
	{"dbx",			"(dbx) ",	" \t>"},
	{"/etc/lpc",		"lpc> ",	" \t"},
	{"lpc",			"lpc> ",	" \t"},
	{"/usr/ucb/mail",	"& ",		" \t"},
	{"mail",		"& ",		" \t"},
	{"/usr/lib/sendmail",	"> ",		" \t"},
	{"sendmail",		"> ",		" \t"},
	{"/usr/sra/calc",	"CALC: ",	" \t"},
	{"calc",		"CALC: ",	" \t"},
	{0,			0}
};

main(argc, argv)
    int argc;
    char *argv[];
{
    int     i;
    char    *cp;
    char    *getenv();
    char    **commandv;
    char    *allocAndCopyThere();

    myself = argv[0];

    /*
     * Initialize binding table
     */
    init_bind_table ();

    /*
     * Set default variables before process arguments.
     */
    set_default_vars ();


    /*
     * Look environment variable first.
     */
    /* EDITMODE */
    if ((cp=getenv("EDITMODE")) && (eq(cp,"emacs")||eq(cp,"vi")))
	set_only_var ("editmode", cp);
    /* USER */
    if (cp=getenv("USER"))
	set_only_var ("user", cp);
    /* HOME */
    if (cp=getenv("HOME"))
	set_only_var ("home", cp);
    /* TERM */
    if (cp=getenv("TERM"))
	set_only_var ("term", cp);
    /* SHELL */
    if (cp=getenv("SHELL"))
	set_only_var ("shell", cp);

    /*
     * Check arguments.
     */
    while (argv[1] && argv[1][0] == '-') {
	switch (argv[1][1]) {

	    case '\0': /* - */
		ptyflag = 0;
		break;

	    case 'd':  /* -d */
		debug = ON;
		break;

	    case 'e': /* -emacs */
		if (strcmp (argv[1], "-emacs") == 0)
		    set_only_var ("editmode", "emacs");
		else
		    goto DEFAULT;
		break;

	    case 'h': /* -h */
		if (argv[1][2] == '\0') {
		    argv++;
		    argc--;
		    if (argc == 1)
			usageAndExit ();
		    histlen = atoi (argv[1]);
		}
		else {
		    histlen = atoi (&argv[1] + 2);
		}
		break;

	    case 'p': /* -p */
		if (argv[1][2] == '\0') {
		    argv++;
		    argc--;
		    if (argc == 1)
			usageAndExit ();
		    prompt = allocAndCopyThere (argv[1]);
		}
		else {
		    prompt = allocAndCopyThere (argv[1] + 2);
		}
		break;

	    case 'v': /* -vi */
		if (strcmp (argv[1], "-vi") == 0)
		    set_only_var ("editmode", "vi");
		else
		    goto DEFAULT;
		break;
DEFAULT:
	    default: 
		printf ("Unknown option \"%s\"\n", argv[1]);
	}
	argv++;
	argc--;
    }
    fflush (stdout);

    if (argc < 2 && ptyflag) {
	usageAndExit ();
    }

    look_cmdinfo (argv[1]);

    /*
     * Set variable of command name.
     */
    {
	char *cp = argv[1], *rindex();

	if (any ('/', cp))
	    cp = rindex (cp, '/') + 1;
	set_var (cp, "1");
	set_var ("command", cp);
    }

    commandv = &argv[1];

    if (! isatty (0)) {
	execvp (*commandv, commandv, 0);
	perror (*commandv);
	exit (1);
    }

    get_pty_master ();
    fix_tty ();

    if (histlen < 0) {
	if (getenv ("HISTLEN"))
	    histlen = atoi (getenv ("HISTLEN"));
	else
	    histlen = DFL_HISTLEN;
    }

    /*
     * Initialize output buffer.
     */
    output_buffer->buf = (char *) malloc (5120);
    if (output_buffer->buf <= 0) {
	fprintf (stderr, "Can't allocate enough momory\n");
	kill_process ();
	exit (1);
    }
    output_buffer->b_max = 5120;
    output_buffer->hiwater = 4096;
    output_buffer->count = output_buffer->next = output_buffer->start = 0;

    init_hist (histlen);
    init_edit_params ();

    if (ptyflag) {
	child_pid = fork ();
	if (child_pid < 0) {
	    perror ("fork");
	    kill_process ();
	    exit (1);
	}
	if (child_pid == 0)
	    exec_to_command (commandv);
    }
    fix_signal ();

    input_handler ();
}

fix_signal ()
{

    sighup = signal (SIGHUP, catchsig);
    sigchld = signal (SIGCHLD, catchsig);
    sigtstp = signal (SIGTSTP, SIG_IGN);    
}

recover_signal ()
{

    (void) signal (SIGHUP, sighup);
    (void) signal (SIGCHLD, sigchld);
    (void) signal (SIGTSTP, sigtstp);
}

input_handler()
{
    char   *inputline;
    char   *getline ();

    /*
     * Get slave tty descriptor for auto-tty-fix
     */
    if ((slave = open (slave_tty, O_RDONLY)) < 0)
	perror ("open");

    while (inputline = getline ()) {
	register int nbyte = strlen (inputline);

	/*
	 * Write to master pty
	 */
	write (master, inputline, nbyte);

	/*
	 * NOTE:
	 * Saving command line to output buffer is done in getline().
	 * Because inputline here is converted by alias.
	 */

#ifdef STAT
	stat_ibyte += nbyte;
#endif

	/*
	 * Write to script file.
	 */
	if (Transparency == OFF && script_fp)
	    fwrite (inputline, sizeof(CHAR), strlen (inputline), script_fp);
    }
    terminate ();
}

#define INPUT_BUFFER_SIZE 1024

#ifdef USE_TIMEOUT
/*
 * NOTE:
 * Now these time mechanism is not used.
 * Terminal status is get at every input from stdin.
 */
struct timeval timeout_0s	= {0L, 0L};
struct timeval timeout_500ms	= {0L, 500000L};
struct timeval timeout_1s	= {1L, 0L};
struct timeval timeout_5s	= {5L, 0L};
struct timeval timeout_10s	= {10L, 0L};
struct timeval timeout_60s	= {60L, 0L};

#define TIMEOUT_IMMID		&timeout_500ms
#define TIMEOUT_SOON		&timeout_1s
#define TIMEOUT_SHORT		&timeout_5s
#define TIMEOUT_MID		&timeout_10s
#define TIMEOUT_LONG		&timeout_60s
#define TIMEOUT_FOREVER		(struct timeval *)0
#define TIMEOUT_NOBLOCK		&timeout_0s

struct timeval *timeout_list[] = {
	TIMEOUT_IMMID,
	TIMEOUT_SOON,
	TIMEOUT_SHORT,
	TIMEOUT_MID,
	TIMEOUT_LONG,
	TIMEOUT_FOREVER
};
#else
struct timeval timeout_0s	= {0L, 0L};
#define TIMEOUT_FOREVER		(struct timeval *)0
#define TIMEOUT_NOBLOCK		&timeout_0s
#endif

struct timeval *notimeout[] = {
	TIMEOUT_FOREVER
};

getcharacter()
{
    char c;
    int n;
/*
    char buf[INPUT_BUFFER_SIZE];
*/
    int nfound, readfd, writefd = 0, execptfd = 0;
#ifdef USE_TIMEOUT
    struct timeval **timeout = auto_tty_fix ? timeout_list : notimeout;
#else
    struct timeval **timeout = notimeout;
#endif


    /*
     * Sorry, this cording depends to an implementation of getc().
     */
#   define CHAR_IN_BUFFER (stdin->_cnt)
    if (CHAR_IN_BUFFER)
	goto RETURNCHAR;

RETRY:
    readfd = selectmask;

#ifdef STAT
    stat_nselect++;
#endif
    if ((nfound = select (selectnfds, &readfd, 0, 0, *timeout)) < 0)
	perror ("select");

    /*
     * Found output from pty.
     */
    if (readfd & mastermask) {
	int nbyte;

	/*
	 * Read from pty.
	 */
/*
	nbyte = read (master, buf, INPUT_BUFFER_SIZE);
*/
	nbyte = buf_read (master, output_buffer);

	if (nbyte > 0) {
	    /*
	     * Write to stdout
	     */
/*
	    write (1, buf, nbyte);
*/
	    write (1, output_buffer->last_buf, nbyte);

	    /*
	     * Write to script file
	     */
	    if (script_fp)
/*
		fwrite (buf, sizeof(CHAR), nbyte, script_fp);
*/
		fwrite (output_buffer->last_buf,
			sizeof(CHAR), nbyte, script_fp);

#ifdef STAT
	    stat_obyte += nbyte;
#endif
	}
	else if (nbyte < 0) {
	    perror ("read");
#ifdef STAT
	    stat_rerror++;
#endif
	}
    }

    /*
     * Found input from terminal
     */
    if (CHAR_IN_BUFFER || readfd & stdinmask) {

#ifndef USE_TIMEOUT
	/*
	 * Look slave tty mode before every input.
	 * This will be done only before real input from stdin, because
	 * if character remained in FILE buffer, control goes to RETURNCHAR
	 * label.
	 */
    	if (auto_tty_fix)
	    (void) fix_transparency ();
#endif

	RETURNCHAR:
	if ((c = getc (stdin)) == EOF) {
	    if (debug)
		printf ("EOF chatched\n");
	    terminate ();
	}
	else
	    return (c & CHARMASK);
    }

#ifdef USE_TIMEOUT
    /*
     * In the case of timeout.
     */
    if (nfound == 0) {

	/*
	 * Only to make sure
	 */
    	if (!auto_tty_fix) {
	    printf ("Timeout should not happen!!\n");
	    timeout = notimeout;
	    goto RETRY;
	}

	(void) fix_transparency ();
	++timeout;

	if (debug)
	    errorBell();
    }
#endif

    goto RETRY;
}

int buf_read (fd, bp)
    int fd;			/* file discriptor */
    BUFFER *bp;			/* buffer pointer */
{
    int nbyte;

    /*
     * save previous next pointer
     */
    bp->last_buf = bp->buf + bp->next;

    /*
     * read from fd as possible
     */
    nbyte = read (fd, bp->buf + bp->next, bp->b_max - bp->next);

    /*
     * move next read pointer
     */
    bp->next += nbyte;

    /*
     * If count has not reached high-water mark, increment count
     * by read count, otherwise start pointer should be pushed by
     * next pointer.
     */
    if (bp->count < bp->hiwater)
	bp->count += nbyte;
    else
	bp->start += nbyte;
	
    /*
     * If next pointer goes further than high-water mark, discard contents
     * after next pointer, and move start and next pointer to buffer top.
     */
    if (bp->next > bp->hiwater) {
	bp->count = bp->next;
	bp->start = 0;
	bp->next = 0;
    }

    return (nbyte);
}

buf_put (bp, s)
    BUFFER *bp;			/* buffer pointer */
    char *s;			/* string pointer */
{
    int nbyte;
    int slen;

    nbyte = strlen (s);

    while (nbyte > 0) {

	slen = min (bp->b_max - bp->next, nbyte);
	strncpy (bp->buf + bp->next, s, slen);
	s += slen;
	nbyte -= slen;
	bp->next += slen;

	if (bp->count < bp->hiwater)
	    bp->count += slen;
	else
	    bp->start += slen;

	if (bp->next > bp->hiwater) {
	    bp->count = bp->next;
	    bp->start = 0;
	    bp->next = 0;
	}
    }
}

swallow_output()
{
/*
    char buf[INPUT_BUFFER_SIZE];
*/
    int readfd = mastermask;
    int r;
    int nbyte;
    int ncount = 10;

    while (
	ncount-- &&
	select (selectnfds, &readfd, 0, 0, TIMEOUT_NOBLOCK) > 0 &&
	readfd & mastermask
    ) {
/*
	nbyte = read (master, buf, INPUT_BUFFER_SIZE);
*/
	nbyte = buf_read (master, output_buffer);
	if (nbyte > 0) {
/*
	    write (1, buf, nbyte);
*/
	    write (1, output_buffer->last_buf, nbyte);
#ifdef STAT
	    stat_obyte += nbyte;
	    stat_nselect++;
#endif

	    /*
	     * Write to script file
	     */
	    if (script_fp)
/*
		fwrite (buf, sizeof(CHAR), nbyte, script_fp);
*/
		fwrite (output_buffer->last_buf,
			sizeof(CHAR), nbyte, script_fp);
	}
	else if (nbyte < 0) {
	    perror ("read");
#ifdef STAT
	    stat_rerror++;
#endif
	}
    }
    return;
}

#include <sys/wait.h>

catchsig()
{
    union wait status;
    struct rusage   ru;

    if (wait3 (&status.w_status, WNOHANG | WUNTRACED, &ru) != child_pid)
	return;
    if (WIFSTOPPED (status) /* || WIFSIGNALED (status) */) {
	if (debug) {
	    message ("Child has sttoped!!\n");
	}
	suspend ();
	return;
    }
    terminate ();
}

exec_to_command(argv)
    char *argv[];
{
    int t;

    /*
     * Disconnect control terminal
     */
    t = open ("/dev/tty", 2);
    if (t >= 0) {
	ioctl (t, TIOCNOTTY, (char *) 0);
	(void) close (t);
    }

    get_pty_slave ();

    (void) close (master);
    dup2 (slave, 0);
    dup2 (slave, 1);
    dup2 (slave, 2);
    (void) close (slave);

    ioctl (0, TIOCSETN, (char *) & slave_ttymode);

    execvp (*argv, argv, 0);
    perror (*argv);
    exit (1);
}

fix_tty()
{
    struct tchars tcbuf;
    struct ltchars lcbuf;

    master_ttymode = initial_ttymode;
    slave_ttymode = initial_ttymode;
    tcbuf = tchars_buf;
    lcbuf = ltchars_buf;

    master_ttymode.sg_flags |= CBREAK;
    master_ttymode.sg_flags &= ~ECHO;

    slave_ttymode.sg_erase = -1;
    slave_ttymode.sg_kill = -1;
    slave_ttymode.sg_flags &= ~(ECHO|CRMOD);

    tcbuf.t_intrc = -1;
    tcbuf.t_quitc = -1;
    tcbuf.t_eofc = -1;
    tcbuf.t_brkc = -1;

    lcbuf.t_suspc = -1;
    lcbuf.t_dsuspc = -1;
    lcbuf.t_rprntc = -1;
    lcbuf.t_flushc = -1;
    lcbuf.t_werasc = -1;
    lcbuf.t_lnextc = -1;

    ioctl (0, TIOCSETN, (char *) & master_ttymode);
    ioctl (0, TIOCSETC, (char *) & tcbuf);
    ioctl (0, TIOCSLTC, (char *) & lcbuf);
}

kill_process()
{

    if (child_pid)
	(void) killpg (child_pid, SIGTERM);
}

terminate()
{
    extern int errno;

    /*
     * Save history if 'history-file' is set
     */
    {
	char *cp, *mk_home_relative(), *look_var();
	char buf [256];
	int num;

	if (look_var ("savehist") && (cp = look_var ("history-file"))) {

	    num = lookd_var ("savehist");
	    strcpy (buf, mk_home_relative (cp));
	    save_history (buf, num);
	}
    }

    /*
     * If scripting, close script file.
     */
    if (script_fp)
	fclose (script_fp);

    (void) signal (SIGCHLD, SIG_IGN);
    if (killpg (child_pid, SIGTERM) < 0 && errno != ESRCH)
	if (killpg (child_pid, SIGHUP) < 0)
	    if (killpg (child_pid, SIGKILL) < 0)
		perror ("kill");

    ioctl (0, TIOCSETN, (char *) & initial_ttymode);
    ioctl (0, TIOCSETC, (char *) & tchars_buf);
    ioctl (0, TIOCSLTC, (char *) & ltchars_buf);
    exit (0);
}

get_pty_master()
{
    char    c;
    struct stat stb;
    int     i;

    if (ptyflag == 0) {
	master = 1;
	return;
    }
    for (c = 'p'; c <= 's'; c++) {
	for (i = 0; i < 16; i++) {
	    sprintf (master_tty, "/dev/pty%c%x", c, i);
	    master = open (master_tty, O_RDWR);
	    if (master >= 0) {
		sprintf (slave_tty, "/dev/tty%c%x", c, i);
		goto FOUND;
	    }
	}
    }

    /*
     * Can't get master tty
     */
    if (master < 0) {
	fprintf (stderr, "Couldn't open pseudo tty\n");
	kill_process ();
	exit (1);
    }

 FOUND:
    ioctl (0, TIOCGETP, (char *) &initial_ttymode);
    ioctl (0, TIOCGETC, (char *) &tchars_buf);
    ioctl (0, TIOCGETD, (char *) &line_desc);
    ioctl (0, TIOCGLTC, (char *) &ltchars_buf);
    ioctl (0, TIOCLGET, (char *) &lmode_buf);

#ifdef TIOCGWINSZ
    {
	struct winsize win;

	if (ioctl (0, TIOCGWINSZ, &win) >= 0) {
	    lines = win.ws_row;
	    columns = win.ws_col;
	}
    }
#endif

#ifdef KANJI
# if defined(TIOCKGET) && defined(TIOCKSET)
    ioctl (0, TIOCKGET, (char *) &kmode_buf);
# endif
# if defined(TIOCKGETC) && defined(TIOCKSETC)
    ioctl (0, TIOCKGETC, (char *) &jtchars_buf);
# endif
#endif KANJI

    stdinmask = 1 << fileno (stdin);
    mastermask = 1 << master;
    selectmask = stdinmask | mastermask;
    selectnfds = max (fileno(stdin), master) + 1;

    return;
}

get_pty_slave()
{

    slave = open (slave_tty, 2);
    if (slave < 0) {
	perror (slave_tty);
	exit (1);
    }
    ioctl (slave, TIOCSETN, (char *) &initial_ttymode);
    ioctl (slave, TIOCSETC, (char *) &tchars_buf);
    ioctl (slave, TIOCSLTC, (char *) &ltchars_buf);
    ioctl (slave, TIOCLSET, (char *) &lmode_buf);
    ioctl (slave, TIOCSETD, (char *) &line_desc);

#ifdef KANJI
# if defined(TIOCKGET) && defined(TIOCKSET)
    ioctl (slave, TIOCKSET, (char *) &kmode_buf);
# endif
# if defined(TIOCKGETC) && defined(TIOCKSETC)
    ioctl (slave, TIOCKSETC, (char *) &jtchars_buf);
# endif
#endif KANJI

#ifdef TIOCSWINSZ
    {
	struct winsize win;

	win.ws_row = lines;
	win.ws_col = columns;
	(void) ioctl (slave, TIOCSWINSZ, &win);
    }
#endif
}

recover_tty()
{

    ioctl (0, TIOCSETN, (char *) & initial_ttymode);
    ioctl (0, TIOCSETC, (char *) & tchars_buf);
    ioctl (0, TIOCSLTC, (char *) & ltchars_buf);
}

suspend()
{
    long	pid;
    int		(*func) ();
    int		omask;
    extern int	errno;

    pid = getpid ();
 /* reset signal handler so kill below stops us */
    func = signal (SIGCHLD, SIG_IGN);
    signal (SIGTSTP, SIG_DFL);
    recover_tty();
#define	mask(s)	(1 << ((s)-1))
    omask = sigsetmask (sigblock (0) & ~mask (SIGTSTP));
    kill (0, SIGTSTP);

    if (kill (child_pid, SIGCONT) < 0 && errno == ESRCH) {
	printf ("Where my child has gone?!\n");
	terminate ();
    }
    killpg (child_pid, SIGCONT);
    kill (0, SIGCONT);
    signal (SIGCHLD, func);
    signal (SIGTSTP, SIG_IGN);
    sigblock (mask (SIGTSTP));
    fix_tty ();
    if (look_var ("auto-repaint"))
	fep_repaint(0);
}

look_cmdinfo (command)
    char *command;
{
    struct cmdinfo *p;
    char *allocAndCopyThere();

    if (strcmp (prompt, "") != 0)
	return;

    for (p = cmdinfo_tab; p->command; p++) {
	if (strcmp (command, p->command) == 0) {
	    prompt = allocAndCopyThere (p->prompt);
	    set_var ("prompt", p->prompt);
	    set_var ("delimiters", p->delimiters);
	    break;
	}
    }
}

usageAndExit()
{

    printf ("Usage: %s [-emacs|-vi] command\n", myself);
    exit (1);
}
\End\Of\File\
else
  echo "will not over write ./fep_main.c"
fi
echo "Finished archive 4 of 5"
exit

-- 
Please send comp.sources.unix-related mail to rsalz@uunet.uu.net.