Newsgroups: comp.sources.misc
From: Peter Reilley <pvr@wang.com>
Subject:  v22i012:  beav - Binary file editor and viewer, Part03/09
Message-ID: <1991Aug14.200659.5655@sparky.IMD.Sterling.COM>
X-Md4-Signature: 5a9365b82fb045b34c28368e4c8bcd6e
Date: Wed, 14 Aug 1991 20:06:59 GMT
Approved: kent@sparky.imd.sterling.com

Submitted-by: Peter Reilley <pvr@wang.com>
Posting-number: Volume 22, Issue 12
Archive-name: beav/part03
Environment: UNIX, AIX, MSDOS

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 3 (of 9)."
# Contents:  basic.c line.c main.c ttykbd.c
# Wrapped by pvr@elf on Mon Aug 12 13:51:31 1991
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'basic.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'basic.c'\"
else
echo shar: Extracting \"'basic.c'\" \(11687 characters\)
sed "s/^X//" >'basic.c' <<'END_OF_FILE'
X/*
X*      Basic cursor motion commands.
X* The routines in this file are the basic
X* command functions for moving the cursor around on
X* the screen, setting mark, and swapping dot with
X* mark. Only moves between lines, which might make the
X* current buffer framing bad, are hard.
X*/
X
X#include    "def.h"
X
Xbool    move_ptr ();
Xbool    forwchar ();
Xbool    wind_on_dot ();
Xbool    backline ();
X
Xextern    char    MSG_mark_set[];
Xextern    char    MSG_no_mark[];
Xextern    char    MSG_go_b_n[];
Xextern    char    MSG_bad_num[];
X#if RUNCHK
Xextern    char    ERR_bas_1[];
X#endif
Xextern    char    MSG_lX[];
Xextern    char    MSG_lO[];
Xextern    char    MSG_lD[];
X
X
Xextern  bool    rplc_mode;
X
X/*  pvr
X* Move cursor backwards. Do the
X* right thing if the count is less than
X* 0. Error if you try to move back from
X* the beginning of the buffer.
X*/
Xbool backchar (f, n, k)
Xregister int    n;
X{
X	if (n < 0)
X		return (forwchar (f, -n, KRANDOM));
X
X	while (n--)
X	{
X		if (curwp -> w_unit_offset == 0)
X		{
X			if (!move_ptr (curwp,  -(long)R_B_PER_U(curwp),
X			    TRUE, TRUE, TRUE))
X				return (FALSE);
X
X			/* step to previous unit */
X			curwp -> w_unit_offset = R_CHR_PER_U(curwp) - 1;
X
X			/* if before first line in window then move window */
X			wind_on_dot (curwp);
X		}
X		else
X			curwp -> w_unit_offset--;
X	}
X	curwp -> w_flag |= WFMODE;  /* update mode line */
X	return (TRUE);
X}
X
X/*  pvr
X* Move cursor forwards. Do the
X* right thing if the count is less than
X* 0. Error if you try to move forward
X* from the end of the buffer.
X*/
Xbool forwchar (f, n, k)
Xregister int    n;
X{
X	if (n < 0)
X		return (backchar (f, -n, KRANDOM));
X
X	curwp -> w_flag |= WFMODE;  /* update mode line */
X	while (n--)
X	{
X		if (curwp -> w_unit_offset >= (R_CHR_PER_U(curwp) - 1))
X		{
X			/* move to the mext unit */
X			curwp -> w_unit_offset = 0;
X
X			if (!move_ptr (curwp,  (long)R_B_PER_U(curwp),
X			    TRUE, TRUE, TRUE))
X			{
X				/* I am at the the end of the buffer */
X				return (FALSE);
X			}
X
X			/* if after the last line in window then move window */
X			wind_on_dot (curwp);
X		}
X		else if/* if at last byte of buffer then do not step  */
X		(DOT_POS(curwp) < BUF_SIZE(curwp))
X			curwp -> w_unit_offset++;/* step within unit */
X	}
X	return (TRUE);
X}
X
X/*  pvr
X*   This function moves the specified pointer by the ammount specified
X*   in 'len'.   Move the dot pointer is 'dot' is true, else move
X*   the window pointer.  Do the fix up if 'fix' is TRUE.
X*   This is a relative move if 'rel' is TRUE, else it is an
X*   absolute move.
X*/
X
Xbool    move_ptr (wp, len, dot, fix, rel)
XWINDOW  *wp;
Xlong    len;
Xbool    dot, fix, rel;
X{
X	A32     cur_pos, dest_pos, fix_val, last_pos;
X	long    rel_pos;
X	A32     last_fixed_pos, align;
X	LINE    **line, *line_guess;
X	int     *l_off;
X	char    shift;
X	bool    no_limit;
X
X	no_limit = TRUE;
X	if (dot)
X	{                       /* move dot position */
X		l_off = (int *)&wp -> w_doto;
X		line = &wp -> w_dotp;
X		align = R_SIZE(wp);  /* bytes -1 in a unit */
X	}
X	else
X	{                       /* move window position */
X		l_off = (int *)&wp -> w_loff;
X		line = &wp -> w_linep;
X		align = R_ALIGN(wp) - 1; /* interval of bytes to align window */
X	}
X
X	/* get the current position in the buffer */
X	cur_pos = (*line) -> l_file_offset + *l_off;
X
X	if (rel)
X	{
X		rel_pos = len;
X		dest_pos = len + cur_pos;   /* destination position */
X	}
X	else
X	{
X		rel_pos = len - cur_pos;   /* relative move amount */
X		dest_pos = len;   /* destination position */
X	}
X	if (fix)
X	{
X		shift = wp -> w_disp_shift;
X
X		/* limit at begining */
X		if ((long)dest_pos < (long)shift)
X		{
X			rel_pos = shift - cur_pos;
X			no_limit = FALSE;
X		}
X		else
X		{
X			/* calculate fixed up destination position */
X			fix_val = dest_pos &= ~align;
X			fix_val += shift;
X
X			/* calculate the last position in the buffer */
X			last_pos = BUF_SIZE(wp);
X			if (last_pos < (last_fixed_pos = (last_pos & ~align) + shift))
X				last_pos = last_fixed_pos - align - 1;
X
X			/* if we are going to limit at the end of the buffer */
X			if (last_pos < fix_val)
X			{
X				fix_val = last_pos;
X				no_limit = FALSE;
X			}
X			rel_pos = fix_val - cur_pos;
X		}
X	}
X	while (TRUE)
X	{
X		if (rel_pos < 0)       /* move  backward through buffer */
X		{
X			/* current line? */
X			if (*l_off + rel_pos >= 0)
X			{
X				*l_off += (short) rel_pos;
X				return (no_limit);
X			}
X			/* are we at the first line */
X			if ((*line) -> l_bp -> l_size != 0)
X			{               /* no, so step back */
X				rel_pos += *l_off;
X				(*line) = (*line) -> l_bp;/* move back one line */
X				*l_off = (*line) -> l_used;
X			}
X			else
X			{               /* yes, limit at the begining */
X				*l_off = 0;
X				return (FALSE);
X			}
X		}
X		else /* move forward through buffer */
X		{
X			/* is in current line? */
X			if (((A32)(*l_off) + rel_pos) < ((A32)((*line) -> l_used)))
X			{
X				*l_off += (short) rel_pos;
X				return (no_limit);
X			}
X			if ((*line) -> l_fp -> l_size != 0)
X			{
X				rel_pos -= (*line) -> l_used - *l_off;
X				*l_off = 0;
X				(*line) = (*line) -> l_fp;/* move forward one line */
X			}
X			else
X			{
X				*l_off = (*line) -> l_used;/* at last line so limit it */
X				return (FALSE);
X			}
X		}
X	}
X}
X
X/*  pvr
X*   Move the window so that the dot is within it's
X*   area.   Return TRUE if window was moved.
X*/
X
Xbool wind_on_dot (wp)
X
XWINDOW * wp;
X{
X	long    diff, incr;
X	A32     d_offs, w_start, bytes, align;
X
X	/* number of bytes in a row */
X	bytes = R_BYTES(wp);
X	/* number of bytes to align on */
X	align = R_ALIGN(wp);
X	/* offset of window from start of the buffer */
X	w_start = WIND_POS(wp);
X	/* offset of dot from start of the buffer */
X	d_offs = DOT_POS(wp);
X	/* calculate the amount to move that is 1/3 of the window */
X	incr = bytes * wp -> w_ntrows / 3;
X	/* if dot is before first line in window */
X	if ((diff = (d_offs - w_start)) < 0)/* diff used later */
X	{
X		move_ptr (wp, diff - incr, FALSE, TRUE, TRUE);
X		wp -> w_flag |= WFHARD;
X		return (TRUE);
X	}
X	/* if dot is after the last line in window */
X	if (0 < (diff -= (wp -> w_ntrows * bytes - 1)))
X	{
X		if (align != 1)
X			diff = (diff & ~(align - 1)) + align;
X		move_ptr (wp, diff + incr, FALSE, TRUE, TRUE);
X		wp -> w_flag |= WFHARD;
X		return (TRUE);
X	}
X	/* is window aligned? */
X	if (w_start != ((w_start & ~(align - 1)) + wp -> w_disp_shift))
X	{                       /* if no then move into alignment */
X		move_ptr (wp, 0L, FALSE, TRUE, TRUE);
X		wp -> w_flag |= WFHARD;
X		return (TRUE);
X	}
X	return (FALSE);
X}
X
X/*  pvr
X* Go to the beginning of the
X* buffer. Setting WFHARD is conservative,
X* but almost always the case.
X*/
Xbool gotobob ()
X{
X	move_ptr (curwp, 0L, TRUE, TRUE, FALSE);    /* move dot */
X	move_ptr (curwp, 0L, FALSE, TRUE, FALSE);   /* move window */
X	curwp -> w_unit_offset = 0;
X	curwp -> w_flag |= WFHARD;
X	return (TRUE);
X}
X
X
X/*  pvr
X* Go to the end of the buffer.
X* Setting WFHARD is conservative, but
X* almost always the case.
X* Dot is one byte past the end of the buffer.
X*/
Xbool gotoeob ()
X{
X	long    f_off;
X	long    index;
X
X	move_ptr (curwp, BUF_SIZE(curwp), TRUE, TRUE, FALSE);  /* move dot */
X	curwp -> w_unit_offset = 0;
X	wind_on_dot (curwp);
X	return (TRUE);
X}
X
X
X/*  pvr
X* Move forward by full lines.
X* If the number of lines to move is less
X* than zero, call the backward line function to
X* actually do it. The last command controls how
X* the goal column is set.
X*/
Xbool forwline (f, n, k)
X{
X	if (n < 0)
X		return (backline (f, -n, KRANDOM));
X
X	if (rplc_mode)
X	{
X		next_pat ();
X	}
X	else
X	{
X		/* move dot */
X		if (!move_ptr (curwp,  (long)R_BYTES(curwp) * n,
X		    TRUE, TRUE, TRUE))
X			curwp -> w_unit_offset = 0;
X		wind_on_dot (curwp);
X		curwp -> w_flag |= WFMODE;  /* update mode line */
X	}
X	return (TRUE);
X}
X
X
X/*  pvr
X* This function is like "forwline", but
X* goes backwards. The scheme is exactly the same.
X* Check for arguments that are less than zero and
X* call your alternate. Figure out the new line and
X* call "movedot" to perform the motion.
X*/
Xbool backline (f, n, k)
X{
X	if (n < 0)
X		return (forwline (f, -n, KRANDOM));
X
X	if (rplc_mode)
X	{
X		next_pat ();
X	}
X	else
X	{
X		if (!move_ptr (curwp,  -((long)(R_BYTES(curwp) * n)),
X		    TRUE, TRUE, TRUE))
X			curwp -> w_unit_offset = 0;
X
X		/* is dot before the top of window? */
X		wind_on_dot (curwp);
X		curwp -> w_flag |= WFMODE;  /* update mode line */
X	}
X	return (TRUE);
X}
X
X/*  pvr
X* Scroll forward by a specified number
X* of lines, or by a full page if no argument.
X* (KRW) Added cursor (dot) weighting to force cursor
X*       to same position on new page.
X*/
Xbool forwpage (f, n, k)
Xregister int    n;
X{
X	long    mov_lines;
X
X	if (rplc_mode)
X		next_pat ();
X	else
X	{
X		if (curwp -> w_ntrows <= 2)
X			mov_lines = 2;
X		else
X			mov_lines = curwp -> w_ntrows - 2;
X
X		/* check if last line is already displayed */
X		if (WIND_POS(curwp) + (R_BYTES(curwp) * curwp -> w_ntrows) <
X		    curwp -> w_bufp -> b_linep -> l_bp -> l_file_offset +
X		    curwp -> w_bufp -> b_linep -> l_bp -> l_used)
X		{
X			move_ptr (curwp, (long)(R_BYTES(curwp) * mov_lines),
X			    FALSE, TRUE, TRUE);
X		}
X		/* move dot by same amount */
X		if (!move_ptr (curwp, (long)(R_BYTES(curwp) * mov_lines),
X		    TRUE, TRUE, TRUE))
X			curwp -> w_unit_offset = 0;
X
X		curwp -> w_flag |= WFHARD;
X	}
X	return (TRUE);
X}
X
X
X/*  pvr
X* This command is like "forwpage",
X* but it goes backwards. 
X*/
Xbool backpage (f, n, k)
Xregister int    n;
X{
X	long    mov_lines;
X
X	if (rplc_mode)
X		next_pat ();
X	else
X	{
X		if (curwp -> w_ntrows <= 2)
X			mov_lines = 2;
X		else
X			mov_lines = curwp -> w_ntrows - 2;
X
X		/* move window */
X		move_ptr (curwp, -(long)(R_BYTES(curwp) * mov_lines),
X		    FALSE, TRUE, TRUE);
X		/* move dot by same amount */
X		if (!move_ptr (curwp, -(long)(R_BYTES(curwp) * mov_lines),
X		    TRUE, TRUE, TRUE))
X			curwp -> w_unit_offset = 0;
X
X		curwp -> w_flag |= WFHARD;
X	}
X	return (TRUE);
X}
X
X
X/*
X* Set the mark in the current window
X* to the value of dot. A message is written to
X* the echo line unless we are running in a keyboard
X* macro, when it would be silly.
X*/
Xbool setmark ()
X{
X
X	if (curbp == blistp)        /* jam - hack to do goto/kill */
X		pickone ();
X	else
X	{
X		curwp -> w_markp = curwp -> w_dotp;
X		curwp -> w_marko = curwp -> w_doto;
X		if (kbdmop == NULL)
X		{
X			writ_echo (MSG_mark_set);
X		}
X	}
X	return (TRUE);
X}
X
X
X/*  pvr
X* Swap the values of "dot" and "mark" in
X* the current window. This is pretty easy, because
X* all of the hard work gets done by the standard routine
X* that moves the mark about. The only possible
X* error is "no mark".
X*/
Xbool swapmark ()
X{
X	register short  odoto;
X	register    LINE * odotp;
X
X	if (curwp -> w_markp == NULL)
X	{
X		writ_echo (MSG_no_mark);
X		return (FALSE);
X	}
X
X	odotp = curwp -> w_dotp;
X	curwp -> w_dotp = curwp -> w_markp;
X	curwp -> w_markp = odotp;
X	odoto = curwp -> w_doto;
X	curwp -> w_doto = curwp -> w_marko;
X	curwp -> w_marko = odoto;
X	wind_on_dot (curwp);
X	curwp -> w_flag |= WFMODE;  /* update mode line */
X	return (TRUE);
X}
X
X/*  pvr
X* Go to a specific byte position in buffer.
X* If an argument is present, then
X* it is the byte number, else prompt for a byte number
X* to use.
X*/
Xbool gotoline (f, n, k)
X{
X	A32      index;
X	register int    s;
X	char    buf[32];
X
X	if (f == FALSE)
X	{
X
X		if ((s = ereply (MSG_go_b_n, buf, sizeof (buf), 0) != TRUE))
X			return (s);
X		switch (R_TYPE(curwp))
X		{
X		case TEXT:
X		case ASCII:
X		case EBCDIC:
X		case BINARY:
X		case HEX:
X			sscanf (buf, MSG_lX, &index);
X			break;
X		case OCTAL:
X			sscanf (buf, MSG_lO, &index);
X			break;
X		case DECIMAL:
X			sscanf (buf, MSG_lD, &index);
X			break;
X#if RUNCHK
X		default:
X			writ_echo (ERR_bas_1);
X			break;
X#endif
X		}
X	}
X
X	if (n <= 0)
X	{
X		writ_echo (MSG_bad_num);
X		return (FALSE);
X	}
X
X	move_ptr (curwp, index, TRUE, TRUE, FALSE);
X	curwp -> w_unit_offset = 0;
X
X	curwp -> w_flag |= WFMODE;  /* update mode line */
X
X	wind_on_dot (curwp);
X	return (TRUE);
X}
X
END_OF_FILE
if test 11687 -ne `wc -c <'basic.c'`; then
    echo shar: \"'basic.c'\" unpacked with wrong size!
fi
# end of 'basic.c'
fi
if test -f 'line.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'line.c'\"
else
echo shar: Extracting \"'line.c'\" \(14084 characters\)
sed "s/^X//" >'line.c' <<'END_OF_FILE'
X/*
X*       Text line handling.
X* The functions in this file
X* are a general set of line management
X* utilities. They are the only routines that
X* touch the text. They also touch the buffer
X* and window structures, to make sure that the
X* necessary updating gets done. There are routines
X* in this file that handle the kill buffer too.
X* It isn't here for any good reason.
X*
X* Note that this code only updates the dot and
X* mark values in the window list. Since all the code
X* acts on the current window, the buffer that we
X* are editing must be being displayed, which means
X* that "b_nwnd" is non zero, which means that the
X* dot and mark values in the buffer headers are
X* nonsense.
X*/
X
X#include    "def.h"
X
Xvoid l_fix_up ();
X
Xextern    char    MSG_cnt_alloc[];
X#if RUNCHK
Xextern    char    ERR_no_alloc[];
Xextern    char    ERR_db_dalloc[];
Xextern    char    ERR_lock[];
Xextern    char    ERR_lock_del[];
X#endif
X
Xextern  LINE    *cur_pat;
Xextern  LINE    *cur_mask;
Xextern  bool    read_pat_mode;
Xextern  BUFFER  sav_buf;
X
X/*
X* This routine allocates a block
X* of memory large enough to hold a LINE
X* containing "size" characters. Return a pointer
X* to the new block, or NULL if there isn't
X* any memory left. Print a message in the
X* message line if no space.
X*/
XLINE * lalloc (size)
Xregister int    size;
X{
X	register    LINE * lp;
X	char    buf[80], buf1[50];
X#if RUNCHK
X	if (read_pat_mode)
X		printf (ERR_no_alloc);
X#endif
X
X	if ((lp = (LINE *) malloc (sizeof (LINE) + size)) == NULL)
X	{
X		sprintf (buf1, MSG_cnt_alloc, R_POS_FMT(curwp));
X		sprintf (buf, buf1, (A32)size);
X		err_echo (buf);
X		curbp -> b_flag |= BFBAD;/* may be trashed */
X		curwp -> w_flag |= WFMODE;
X		update ();
X		return (NULL);
X	}
X	lp -> l_size = size;
X	lp -> l_used = 0;
X	lp -> l_file_offset = 0;    /* set resonable initial value */
X	return (lp);
X}
X
X
X/*
X* Delete line "lp". Fix all of the
X* links that might point at it (they are
X* moved to offset 0 of the next line.
X* Unlink the line from whatever buffer it
X* might be in. Release the memory. The
X* buffers are updated too; the magic conditions
X* described in the above comments don't hold
X* here.
X*/
X
Xvoid lfree (lp)
Xregister    LINE * lp;
X{
X	register    BUFFER * bp;
X	register    WINDOW * wp;
X
X#if RUNCHK
X	if (read_pat_mode)
X		printf (ERR_db_dalloc);
X#endif
X
X	wp = wheadp;
X	while (wp != NULL)
X	{
X		if (wp -> w_linep == lp)
X		{
X			wp -> w_linep = lp -> l_fp;
X			wp -> w_loff = 0;
X		}
X
X		if (wp -> w_dotp == lp)
X		{
X			wp -> w_dotp = lp -> l_fp;
X			wp -> w_doto = 0;
X		}
X
X		if (wp -> w_markp == lp)
X		{
X			wp -> w_markp = lp -> l_fp;
X			wp -> w_marko = 0;
X		}
X
X		wp = wp -> w_wndp;
X	}
X
X	bp = bheadp;
X	while (bp != NULL)
X	{
X		if (bp -> b_nwnd == 0)
X		{
X			if (bp -> b_dotp == lp)
X			{
X				bp -> b_dotp = lp -> l_fp;
X				bp -> b_doto = 0;
X			}
X
X			if (bp -> b_markp == lp)
X			{
X				bp -> b_markp = lp -> l_fp;
X				bp -> b_marko = 0;
X			}
X		}
X		bp = bp -> b_bufp;
X	}
X
X	lp -> l_bp -> l_fp = lp -> l_fp;
X	lp -> l_fp -> l_bp = lp -> l_bp;
X	free ((char *) lp);
X}
X
X
X/*
X* This routine gets called when
X* a character is changed in place in the
X* current buffer. It updates all of the required
X* flags in the buffer and window system. The flag
X* used is passed as an argument; if the buffer is being
X* displayed in more than 1 window we change EDIT to
X* HARD. Set MODE if the mode line needs to be
X* updated (the "*" has to be set).
X*/
Xvoid lchange (flag)
Xregister int    flag;
X{
X	register    WINDOW * wp;
X
X	if (curbp -> b_nwnd != 1)   /* Ensure hard.     */
X		flag = WFHARD;
X	if ((curbp -> b_flag & BFCHG) == 0)
X	{
X		/* First change, so     */
X		flag |= WFMODE;         /* update mode lines.   */
X		curbp -> b_flag |= BFCHG;
X	}
X
X	wp = wheadp;
X	while (wp != NULL)
X	{
X		if (wp -> w_bufp == curbp)
X			wp -> w_flag |= flag;
X		wp = wp -> w_wndp;
X	}
X}
X
X
X/*
X *  Break the line "dotp" in two at the position "doto."
X */
X
XLINE *l_break_in_two (lp, lo, extra)
Xregister LINE  *lp;
Xregister LPOS  lo, extra;
X{
X	register LINE  *new_lp;
X	register char  *cp1;
X	register char  *cp2;
X	LPOS	cnt, i;
X
X	i = 0;
X	cnt = lp -> l_used - lo;
X	if ((new_lp = lalloc (cnt + extra)) == NULL)
X		return (NULL);
X
X	cp1 = &lp -> l_text[lo];  /* starting location, source */
X	cp2 = &new_lp -> l_text[0];  /* starting location, destination */
X
X	/* kill bytes in the current line */
X	while (i++ < cnt)
X	{
X		*cp2++ = *cp1++;
X	}
X	lp -> l_used -= cnt;
X	new_lp -> l_used = cnt;
X	new_lp -> l_file_offset = new_lp -> l_file_offset + lo;
X
X	/* insert into chain */
X	new_lp -> l_fp = lp -> l_fp;
X	lp -> l_fp = new_lp;
X	new_lp -> l_bp = lp;
X	new_lp -> l_fp -> l_bp = new_lp;
X	return (new_lp);
X}
X
X/*
X* Insert "n" copies of the character "c"
X* at the current location of dot. In the easy case
X* all that happens is the text is stored in the line.
X* Always allocate some extra space in line so that edit 
X* will be faster next time but will save space in the general case.
X* In the hard case, the line has to be reallocated.
X* When the window list is updated, take special
X* care; I screwed it up once. You always update dot
X* in the current window. You update mark, and a
X* dot in another window, if it is greater than
X* the place where you did the insert. Return TRUE
X* if all is well, and FALSE on errors.
X*/
Xbool linsert (n, c)
Xuchar   c;
X{
X	register char  *cp1;
X	register char  *cp2;
X	register    LINE * lp1;
X	register    LINE * lp2;
X	register    LINE * lp3;
X	register short  doto;
X	register int    i;
X	register    WINDOW * wp;
X
X#if RUNCHK
X	/* check that buffer size can be changed */
X	if (curbp -> b_flag & BFSLOCK)
X	{
X		writ_echo (ERR_lock);
X		return (FALSE);
X	}
X#endif
X
X	lchange (WFMOVE);
X	lp1 = curwp -> w_dotp;      /* Current line     */
X	if (lp1 == curbp -> b_linep)
X	{
X		/* At the end: special  */
X		/* break the current line at the end */
X		if ((lp2 = l_break_in_two (lp1, lp1 -> l_used, (LPOS)n + NBLOCK)) == NULL)
X			return (FALSE);
X		for (i = 0; i < n; ++i)     /* Add the characters   */
X			lp2 -> l_text[i] = c;
X		lp2 -> l_used = n;
X		curwp -> w_dotp = lp2;
X		curwp -> w_doto = n;
X		return (TRUE);
X	}
X
X	doto = curwp -> w_doto;     /* Save for later.  */
X	if (lp1 -> l_used + n > lp1 -> l_size)
X	{
X		/* break the current line and let the normal insert do it */
X		if ((lp2 = l_break_in_two (lp1, doto, (LPOS)n + NBLOCK)) == NULL)
X			return (FALSE);
X		lp1 -> l_text[doto] = c;
X		lp1 -> l_used++;
X		curwp -> w_doto++;
X		if (curwp -> w_doto >= lp1 -> l_used)
X		{
X			curwp -> w_dotp = lp2;
X			curwp -> w_doto = 0;
X		}
X		if (n > 1)
X			return (linsert (n - 1, c));    /* handle the rest in normal maner */
X	}
X	else
X	{
X		/* Easy: in place   */
X		lp2 = lp1;              /* Pretend new line */
X		lp2 -> l_used += n;
X		cp2 = &lp1 -> l_text[lp1 -> l_used];
X		cp1 = cp2 - n;
X		while (cp1 != &lp1 -> l_text[doto])
X			*--cp2 = *--cp1;
X		for (i = 0; i < n; ++i)     /* Add the characters   */
X			lp2 -> l_text[doto + i] = c;
X		move_ptr (curwp, (A32)n, TRUE, TRUE, TRUE);
X	}
X
X	wp = wheadp;                /* Update windows   */
X	while (wp != NULL)
X	{
X		if ((wp -> w_linep == lp1) && (wp -> w_loff >= lp1 -> l_used))
X		{
X			wp -> w_linep = lp2;
X			wp -> w_loff -= lp1 -> l_used;
X		}
X
X		/* move dot to next line but not to head line */
X		if ((wp -> w_dotp == lp1) && (wp -> w_doto >= lp1 -> l_used) &&
X		    (wp -> w_dotp -> l_fp -> l_size != 0))
X		{
X			wp -> w_dotp = lp2;
X			wp -> w_doto -= (lp1 -> l_used - 1);
X		}
X
X		if ((wp -> w_markp == lp1) && (wp -> w_marko >= lp1 -> l_used))
X		{
X			wp -> w_markp = lp2;
X			wp -> w_marko -= (lp1 -> l_used - 1);
X		}
X
X		wp = wp -> w_wndp;
X	}
X	l_fix_up (lp1);   /* re-adjust file offsets */
X	return (TRUE);
X}
X
X/*
X* This function deletes n_bytes,
X* starting at dot. It understands how to deal
X* with end of lines, etc. It returns TRUE if all
X* of the characters were deleted, and FALSE if
X* they were not (because dot ran into the end of
X* the buffer). The "kflag" is TRUE if the text
X* should be put in the kill buffer.
X*/
Xbool ldelete (n_bytes, kflag)
XA32	n_bytes;
X{
X	register LINE  *dotp, *lp, *lp_prev, *lp_next;
X	register LPOS  doto, l_size, l_used, l_cnt;
X	register WINDOW *wp;
X	D8       *cp1, *cp2;
X	D32      n_byt, dot_pos;
X
X#if RUNCHK
X	/* check that buffer size can be changed */
X	if (curbp -> b_flag & BFSLOCK)
X	{
X		writ_echo (ERR_lock_del);
X		return (FALSE);
X	}
X#endif
X	lchange (WFMOVE);
X	doto = curwp -> w_doto;
X	dotp = curwp -> w_dotp;
X	lp_prev = dotp -> l_bp;
X	dot_pos = DOT_POS(curwp);
X
X	/* if at the end of the buffer then delete nothing */
X	if (dot_pos >= BUF_SIZE(curwp))
X	{
X		l_fix_up (dotp);    /* re-adjust file offsets */
X		return (TRUE);
X	}
X
X	/* save dot and mark positions for later restore */
X	wp = wheadp;
X	while (wp != NULL)
X	{
X		wp->w_dot_temp = DOT_POS (wp);
X		wp->w_mark_temp = MARK_POS (wp);
X		wp->w_wind_temp = WIND_POS (wp);
X		wp = wp -> w_wndp;
X	}
X
X	/* is delete wholy within one line? */
X	if ((doto + n_bytes) < dotp -> l_used)
X	{
X		cp1 = &dotp -> l_text[doto];/* Scrunch text.    */
X		cp2 = cp1 + n_bytes;
X
X		/* put stuff to delete into the kill buffer */
X		if (kflag != FALSE)
X		{
X			/* Kill?        */
X			while (cp1 != cp2)
X			{
X				if (b_append_c (&sav_buf, *cp1) == FALSE)
X					return (FALSE);
X				++cp1;
X			}
X			cp1 = &dotp -> l_text[doto];
X		}
X		/* kill bytes in the current line */
X		while (cp2 < &dotp -> l_text[dotp -> l_used])
X			*cp1++ = *cp2++;
X
X		dotp -> l_used -= n_bytes;
X	}
X	else
X	{   /* wholesale delete by moving lines to save buffer */
X		if (doto != 0)
X		{
X			if ((lp = l_break_in_two (dotp, doto, 0l)) == NULL)
X				return (FALSE);
X		}
X		else
X			lp = dotp;
X
X		n_byt = n_bytes;
X		/* now handle whole lines if necessary */
X		while (n_byt > 0)
X		{
X			lp_next = lp -> l_fp;
X
X			if (n_byt < lp -> l_used)
X			{
X				/* get last piece of a line */
X				lp_next = l_break_in_two (lp, n_byt, 0l);
X			}
X			n_byt -= lp -> l_used;
X			if (kflag)
X			{
X				/* remove form linked list */
X				lp -> l_bp -> l_fp = lp -> l_fp;
X				lp -> l_fp -> l_bp = lp -> l_bp;
X				/* append it to the save buffer */
X				b_append_l (&sav_buf, lp);
X			}
X			else
X				/* if we don't want it, free it */
X				lfree (lp);
X			lp = lp_next;
X		}
X	}
X	l_fix_up (lp_prev);    /* re-adjust file offsets */
X
X	/* adjust dot and marks in other windows */
X	/* this should be ok because the save buffer dosn't disturb l_file_offset */
X	wp = wheadp;            /* Fix windows      */
X	while (wp != NULL)
X	{
X		A32	temp;
X
X		if (curbp == wp -> w_bufp)
X		{
X			A32    temp;
X
X			/* if dot is before delete position, do nothing */
X			if (dot_pos <= (temp = wp -> w_dot_temp))
X			{
X				/* step back to the previous line */
X				wp -> w_doto = 0;
X				wp -> w_dotp = lp_prev;
X
X				/* if dot is in deleted range, set to dot position */
X				if (temp > dot_pos + n_bytes)
X					/* if after deleted range, move back deleted ammount */
X					move_ptr (wp, temp - n_bytes, TRUE, TRUE, FALSE);
X				else
X					/* if in the deleted range, move to curwp dot position */
X					move_ptr (wp, dot_pos, TRUE, TRUE, FALSE);
X			}
X			/* mark may not be set in some windows */
X			if (wp -> w_markp != NULL)
X			{
X				/* do the same for mark */
X				if (dot_pos <= (temp = wp->w_mark_temp))
X				{
X					/* if in or after the deleted range, move to curwp dot position */
X					wp -> w_marko = curwp -> w_doto;
X					wp -> w_markp = curwp -> w_dotp;
X
X					/* if mark after deleted range */
X					if (temp > dot_pos + n_bytes)
X					{
X						/* if after deleted range, move back deleted ammount */
X						/* move dot then swap with mark to produce result */
X						move_ptr (wp, temp - n_bytes, TRUE, TRUE, FALSE);
X						lp_next = wp -> w_dotp;
X						wp -> w_dotp = wp -> w_markp;
X						wp -> w_markp = lp_next;
X						l_cnt = wp -> w_doto;
X						wp -> w_doto = wp -> w_marko;
X						wp -> w_marko = l_cnt;
X					}
X				}
X			}
X			/* if window position is before delete position, do nothing */
X			if (dot_pos <= (temp = wp -> w_wind_temp))
X			{
X				/* set window position to dot position */
X				wp -> w_loff = 0;
X				wp -> w_linep = wp -> w_dotp;
X				wind_on_dot (wp);
X			}
X		}
X		wp = wp -> w_wndp;
X	}
X	/* update buffer display */
X	if ((blistp -> b_nwnd != 0) &&
X	    (blistp -> b_type == BTLIST))
X		listbuffers ();
X	return (TRUE);
X}
X/*
X*   Replace character at dot position.
X*/
Xbool    lreplace (n, c)
Xint     n;
Xchar    c;
X{
X	lchange (WFEDIT);
X	while (n--)
X	{
X		DOT_CHAR(curwp) = c & 0xff;
X		move_ptr (curwp, 1L, TRUE, FALSE, TRUE);
X	}
X}
X
X/*
X* Replace plen characters before dot with argument string.
X*/
Xbool lrepl_str (plen, rstr, mstr)
X
Xregister int    plen;           /* length to remove     */
Xregister LINE   *rstr;          /* replace string       */
Xregister LINE   *mstr;          /* mask string       */
X{
X	register    int    i;       /* used for random characters   */
X	register    LINE   *dotp;   /* pointer to line structure */
X	register    int    doto;    /* offset into line     */
X	register    int     rlen;   /* rplace string length */
X	register    char    c;      /* temp storage for char */
X	register    char    mask;   /* temp storage for mask */
X
X	/* 
X  * make the string lengths match (either pad the line
X  * so that it will fit, or scrunch out the excess).
X  * be careful with dot's offset.
X  */
X	doto = curwp -> w_doto;
X	rlen = rstr -> l_used;
X	if (plen > rlen)
X	{
X		ldelete ((A32)(plen - rlen), FALSE);
X	}
X	else if (plen < rlen)
X	{
X		if (linsert (rlen - plen, ' ') == FALSE)
X			return (FALSE);
X	}
X	curwp -> w_doto = doto;
X	dotp = curwp -> w_dotp;     /* save dot line for later */
X
X	/* do the replacement. */
X	for (i = 0; i < rlen; i++)
X	{
X		c = DOT_CHAR(curwp);
X		mask = mstr -> l_text[i];
X		DOT_CHAR(curwp) = (c & mask) | (rstr -> l_text[i] & ~mask);
X		move_ptr (curwp, 1L, TRUE, FALSE, TRUE);
X	}
X	curwp -> w_doto = doto;
X	curwp -> w_dotp = dotp;
X	lchange (WFHARD);
X	return (TRUE);
X}
X
X/*
X*   Line fixup.
X*   This fixes the 'l_file_offset' variable in
X*   each line structure.
X*   This is necessary after every change in the size
X*   of the buffer.
X*/
Xvoid l_fix_up (line)
X
XLINE * line;                    /* points to buffer header line */
X
X{
X	long    offset;
X	LINE * end_line;
X
X	offset = line -> l_file_offset;/* starting offset */
X	offset += line -> l_used;
X	for (;;)
X	{
X		line = line -> l_fp;
X		if (line -> l_size == 0)
X			return;
X		line -> l_file_offset = offset;
X		offset += line -> l_used;
X	}
X}
END_OF_FILE
if test 14084 -ne `wc -c <'line.c'`; then
    echo shar: \"'line.c'\" unpacked with wrong size!
fi
# end of 'line.c'
fi
if test -f 'main.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'main.c'\"
else
echo shar: Extracting \"'main.c'\" \(11225 characters\)
sed "s/^X//" >'main.c' <<'END_OF_FILE'
X/*
X*	BEAV is based on the source for emacs for display and keyboard handling 
X* functions.   The binary file handling and display formats are special
X* to BEAV.   There is a full manual included in this release.   There
X* are makefiles for unix and MSC 5.1 under DOS.   The old Wang PC is
X* supported.   This release is for unix.   The def_unix.h file is the
X* header for unix and the def_dos.h file is the header for dos.   Rename 
X* the appropriate .h file to def.h to convert to your os.
X* 	I am willing to maintain BEAV and will entertain suggestions for
X* modifications and/or bug fixes.   I can be reached at;
X*
X* 		pvr@wang.com
X* 
X* or at;
X* 
X* 		Peter Reilley
X* 		19 Heritage Cir.
X* 		Hudson, N.H. 03051
X*/
X
X/*
X*	Bug fix log
X*	3/04/91		1.20		pvr
X*		Create new file with read/write permisions.
X*		Fix polled mode system hog tty bug.
X*		Add ANSI define for DOS.
X*		Define short for D16 type.
X*		Call ttclose on error exit.
X*		Limit nrow and ncol to actual array size.
X*		Added beavrc key binding functionallity.
X*		Added delete current window command.
X*		Support VT100 type function keys for binding.
X*/
X/*     
X*
X*     Mainline, macro commands.
X*/
X#include        "def.h"
X
Xbool    execute ();
Xvoid    edinit ();
Xbool    flush_all ();
Xchar    quit ();
Xchar    ctrlg ();
Xvoid    _lowercase ();
X
X
Xextern    char    MSG_ok[];
Xextern    char    MSG_main[];
Xextern    char    MSG_prog_name[];
Xextern    char    MSG_no_mod[];
Xextern    char    MSG_no_s_chg[];
Xextern    char    MSG_auto_fl[];
Xextern    char    MSG_quit[];
Xextern    char    MSG_not_now[];
Xextern    char    MSG_st_mac[];
Xextern    char    MSG_end_mac[];
Xextern    char    MSG_num_mod[];
Xextern    char    MSG_null[];
X
Xint     thisflag;               /* Flags, this command      */
Xint     lastflag;               /* Flags, last command          */
Xint     curgoal;                /* Goal column                  */
Xint     com_line_flags;         /* Count of cmd line switches   */
XBUFFER * curbp;                 /* Current buffer               */
XWINDOW * curwp;                 /* Current window               */
XBUFFER * bheadp;                /* BUFFER listhead              */
XWINDOW * wheadp;                /* WINDOW listhead              */
XBUFFER * blistp;                /* Buffer list BUFFER           */
Xshort   kbdm[NKBDM] = {
X	(KCTLX | ')')};  /* Macro (fitz)  */
Xshort  *kbdmip;                 /* Input  for above             */
Xshort  *kbdmop;                 /* Output for above             */
XSYMBOL * symbol[NSHASH];        /* Symbol table listhead.       */
XSYMBOL * binding[NKEYS];        /* Key bindings.                */
Xextern  ROW_FMT hex_8_fmt;
Xextern  bool    ibm_pc, mem_map;
X
Xchar   *okmsg = {
X	MSG_ok};
Xint     insert_mode = {
X	TRUE};
Xint     extend_buf = {
X	FALSE};
X
Xextern  bool    srch_mode;
Xextern  bool    rplc_mode;
Xextern  char    *getenv ();
Xint     initial_load = 0;
Xint     flush_count = 0;
Xint     flush_num = 500;
Xint     auto_update = 0;
X
Xvoid main (argc, argv)
Xchar   *argv[];
X{
X
X	register    int     c;
X	register    int     f;
X	register    int     n;
X	register    int     mflag;
X	char        bname[NBUFN];
X	register    char    *p;
X	extern      long    last_time;
X	long        last_second;
X
X#if MSDOS
X	is_wang ();                 /* Check for computer type */
X
X#endif
X	init_fmt ();				/* initialize format arrays */
X	strcpy (bname, MSG_main);     /* Get buffer name.     */
X	vtinit ();                  /* Virtual terminal.    */
X	keymapinit ();              /* Symbols, bindings.   */
X
X	if (argc == 1)
X	{
X		edinit (bname);
X		update ();
X		eerase ();
X	}
X
X	else
X	{
X		com_line_flags = 0;
X		initial_load = 1;
X		n = (argc - 1);         /* Load  them backwards */
X		if (n > com_line_flags)
X		{
X			/*            _lowercase (argv[n]); */
X			makename (bname, argv[n]);
X			edinit (bname);     /* Buffers, windows.    */
X			update ();
X			readin (argv[n--], 0L, MAXPOS);
X			for (; n > com_line_flags; n--)
X			{
X				/*                _lowercase (argv[n]); */
X				load_file (argv[n], 0L, MAXPOS);
X			}
X		}
X		else
X		{
X			edinit (bname);
X			update ();
X		}
X
X		initial_load = 0;
X	}
X
X	check_extend (NULL);  /* check for extended keys */
X	save_buf_init();		/* initialize save buffer */
X	lastflag = 0;               /* Fake last flags.     */
X
Xloop:
X	update ();
X	c = getkey ();
X	if (epresf != FALSE)
X	{
X		eerase ();
X		update ();
X	}
X	f = FALSE;
X	n = 1;
X	if (c == (KCTRL | 'U'))
X	{
X		/* ^U, start argument.  */
X		f = TRUE;
X		n = 4;
X		while ((c = getkey ()) == (KCTRL | 'U'))
X			n *= 4;
X		if ((c >= '0' && c <= '9') || c == '-')
X		{
X			if (c == '-')
X			{
X				n = 0;
X				mflag = TRUE;
X			}
X			else
X			{
X				n = c - '0';
X				mflag = FALSE;
X			}
X			while ((c = getkey ()) >= '0' && c <= '9')
X				n = 10 * n + c - '0';
X			if (mflag != FALSE)
X				n = -n;
X		}
X	}
X	if (kbdmip != NULL)
X	{
X		/* Save macro strokes.  */
X		if (c != (KCTLX | ')') && kbdmip > &kbdm[NKBDM - 6])
X		{
X			ctrlg (FALSE, 0, KRANDOM);
X			goto loop;
X		}
X		if (f != FALSE)
X		{
X			*kbdmip++ = (KCTRL | 'U');
X			*kbdmip++ = n;
X		}
X		*kbdmip++ = c;
X	}
X	execute (c, f, n);          /* Do it.               */
X	goto loop;
X}
X
X
X/*
X* Command execution. Look up the binding in the the
X* binding array, and do what it says. Return a very bad status
X* if there is no binding, or if the symbol has a type that
X* is not usable (there is no way to get this into a symbol table
X* entry now). Also fiddle with the flags.
X*/
Xchar    execute (c, f, n)
X{
X
X	register    SYMBOL * sp;
X	register int    status;
X
X	if ((sp = binding[c]) != NULL)
X	{
X		thisflag = 0;
X		if (sp -> s_modify & SMOD && (curbp -> b_flag & BFVIEW))
X		{
X			writ_echo (MSG_no_mod);
X			return (ABORT);
X		}
X		if (sp -> s_modify & SSIZE && (curbp -> b_flag & BFSLOCK))
X		{
X			writ_echo (MSG_no_s_chg);
X			return (ABORT);
X		}
X		if ((srch_mode  && !(sp -> s_modify & SSRCH)) ||
X		    (rplc_mode  && !(sp -> s_modify & SRPLC)))
X		{
X			ttbeep ();
X			return (TRUE);
X		}
X
X		status = (*sp -> s_funcp) (f, n, c);
X		if (sp -> s_modify & SMOD)
X			flush_count++;
X
X		if (flush_count >= flush_num && auto_update)
X			if (!(kbdmip != NULL || kbdmop != NULL))/* not during macro */
X			{
X				ttbeep ();
X				writ_echo (MSG_auto_fl);
X				flush_all ();
X			}
X		lastflag = thisflag;
X		return (status);
X	}
X	else
X		bad_key (c);
X
X	lastflag = 0;
X	return (ABORT);
X}
X
X
X/*
X* Initialize all of the buffers
X* and windows. The buffer name is passed down as
X* an argument, because the main routine may have been
X* told to read in a file by default, and we want the
X* buffer name to be right.
X*/
Xvoid edinit (bname)
Xchar    bname[];
X{
X
X	register    BUFFER * bp;
X	register    WINDOW * wp;
X
X	bp = bfind (bname, TRUE);   /* Text buffer.         */
X	blistp = bcreate (MSG_null);      /* Special list buffer. */
X	wp = (WINDOW *) malloc (sizeof (WINDOW));/* Initial window.      */
X	if (bp == NULL || wp == NULL || blistp == NULL)
X		abort ();
X	curbp = bp;                 /* Current ones.        */
X	wheadp = wp;
X	curwp = wp;
X	wp -> w_wndp = NULL;        /* Initialize window.   */
X	wp -> w_bufp = bp;
X	bp -> b_nwnd = 1;           /* Displayed.           */
X	wp -> w_fmt_ptr = &hex_8_fmt;/* HEX 8 bit display       pvr  */
X	wp -> w_linep = bp -> b_linep;
X	wp -> w_dotp = bp -> b_linep;
X	wp -> w_doto = 0;           /* set dot pos  pvr */
X	wp -> w_markp = NULL;
X	wp -> w_marko = 0;
X	wp -> w_toprow = 0;
X	wp -> w_ntrows = nrow - 2;  /* 2 = mode, echo.      */
X	wp -> w_flag = WFMODE | WFHARD;/* Full.                */
X	wp -> w_intel_mode = FALSE; /* default is no byte swap     pvr  */
X	wp -> w_disp_shift = 0;     /* default to no byte shift    pvr  */
X	wp -> w_loff = 0;           /* starting line offset        pvr  */
X	wp -> w_unit_offset = 0;    /* dot offset from file start  pvr  */
X}
X
X/*
X* Flush all the dirty buffers that have file names
X* associated with them.
X*/
Xbool flush_all ()
X{
X	register    BUFFER * bp,
X	*savbp = curbp;
X
X	for (bp = bheadp; bp != NULL; bp = bp -> b_bufp)
X		if (bp -> b_fname != NULL)
X		{
X			curbp = bp;         /* jam */
X			filesave ();
X			update ();
X		}
X	flush_count = 0;
X	writ_echo (okmsg);
X	curbp = savbp;
X	if (blistp -> b_nwnd != 0)  /* update buffer display */
X		listbuffers ();
X	update ();
X}
X
X
X/* call flush_all to empty the buffers
X* and quit
X*/
Xbool flushnquit (f, n, k)
X{
X	flush_all ();
X	quit (f, n, k);
X	return (TRUE);
X}
X
X
X/*
X* Quit command. If an argument, always
X* quit. Otherwise confirm if a buffer has been
X* changed and not written out. Normally bound
X* to "C-X C-C".
X*/
Xchar    quit (f, n, k)
X{
X
X	register char   s;
X
X	if (f != FALSE              /* Argument forces it.  */
X	|| anycb () == FALSE/* All buffers clean.   */
X	|| (s = eyesno (MSG_quit)) == TRUE)/* User says it's OK.   */
X	{
X
X		vttidy ();
X		exit (GOOD);
X	}
X
X	return (s);
X}
X
X
X/*
X* Begin a keyboard macro.
X* Error if not at the top level
X* in keyboard processing. Set up
X* variables and return.
X*/
Xbool ctlxlp (f, n, k)
X{
X
X	if (kbdmip != NULL || kbdmop != NULL)
X	{
X
X		writ_echo (MSG_not_now);
X		return (FALSE);
X	}
X
X	writ_echo (MSG_st_mac);
X	kbdmip = &kbdm[0];
X	return (TRUE);
X}
X
X
X/*
X* End keyboard macro. Check for
X* the same limit conditions as the
X* above routine. Set up the variables
X* and return to the caller.
X*/
Xbool ctlxrp (f, n, k)
X{
X
X	if (kbdmip == NULL)
X	{
X
X		writ_echo (MSG_not_now);
X		return (FALSE);
X	}
X
X	writ_echo (MSG_end_mac);
X	kbdmip = NULL;
X	return (TRUE);
X}
X
X
X/*
X* Execute a macro.
X* The command argument is the
X* number of times to loop. Quit as
X* soon as a command gets an error.
X* Return TRUE if all ok, else
X* FALSE.
X*/
Xbool ctlxe (f, n, k)
X{
X
X	register int    c;
X	register int    af;
X	register int    an;
X	register int    s;
X
X	if (kbdmip != NULL || kbdmop != NULL)
X	{
X
X		writ_echo (MSG_not_now);
X		return (FALSE);
X	}
X
X	if (n <= 0)
X		return (TRUE);
X	do
X	{
X
X		kbdmop = &kbdm[0];
X		do
X		{
X
X			af = FALSE;
X			an = 1;
X			if ((c = *kbdmop++) == (KCTRL | 'U'))
X			{
X
X				af = TRUE;
X				an = *kbdmop++;
X				c = *kbdmop++;
X			}
X
X			s = TRUE;
X		}        while (c != (KCTLX | ')') && (s = execute (c, af, an)) == TRUE);
X		kbdmop = NULL;
X	}    while (s == TRUE && --n);
X	return (s);
X}
X
X
X/*
X* Abort.
X* Beep the beeper.
X* Kill off any keyboard macro,
X* etc., that is in progress.
X* Sometimes called as a routine,
X* to do general aborting of
X* stuff.
X*/
Xchar    ctrlg (f, n, k)
X{
X	/*    ttbeep (); */
X	if (kbdmip != NULL)
X	{
X		kbdm[0] = (KCTLX | ')');
X		kbdmip = NULL;
X	}
X	return (ABORT);
X}
X
X
X/*
X* Display the version. All this does
X* is copy the text in the external "version" array into
X* the message system, and call the message reading code.
X* Don't call display if there is an argument.
X*/
Xchar    showversion (f, n, k)
X{
X	static  char    *cp;
X	char    buf[80];
X
X	cp = version;
X	sprintf (buf, cp);
X	writ_echo (buf);
X	return (TRUE);
X}
X
X
X/* ughly to_lower function for
X* files read in under MSDOS setargv function
X*/
Xvoid _lowercase (s)
Xregister char  *s;
X{
X
X#ifdef MSDOS
X	for (; *s; s++)
X		if (ISUPPER (*s))
X			*s = TOLOWER (*s);
X#endif
X}
X
X
X/* autosave control
X*/
Xbool autosave ()
X{
X	register    WINDOW * wp;
X	register int    s,
X	n;
X	char    buf[32];
X
X	if ((s = ereply (MSG_num_mod, buf, sizeof (buf), NULL)) == TRUE)
X	{
X
X		n = atoi (buf);
X		if (n >= 0)
X			auto_update = flush_num = n;/* not 0! */
X		else
X			auto_update = 0;
X	}
X
X	for (wp = wheadp; wp; wp = wp -> w_wndp)
X		if (wp -> w_bufp == curbp)
X			wp -> w_flag |= WFMODE;
X	return (TRUE);
X}
END_OF_FILE
if test 11225 -ne `wc -c <'main.c'`; then
    echo shar: \"'main.c'\" unpacked with wrong size!
fi
# end of 'main.c'
fi
if test -f 'ttykbd.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'ttykbd.c'\"
else
echo shar: Extracting \"'ttykbd.c'\" \(11161 characters\)
sed "s/^X//" >'ttykbd.c' <<'END_OF_FILE'
X/*
X *      Wang PC keyboard handler
X */
X#define LINT_ARGS   1           /* enable lint type checking */
X#include    "def.h"
X
Xextern    char    MSG_sp_key[];
Xextern    char    MSG_byte_shift[];
Xextern    char    MSG_back_char[];
Xextern    char    MSG_quit[];
Xextern    char    MSG_forw_del_char[];
Xextern    char    MSG_toggle_swap[];
Xextern    char    MSG_forw_char[];
Xextern    char    MSG_abort[];
Xextern    char    MSG_ins_self[];
Xextern    char    MSG_back_del_char[];
Xextern    char    MSG_refresh[];
Xextern    char    MSG_forw_line[];
Xextern    char    MSG_back_line[];
Xextern    char    MSG_quote[];
Xextern    char    MSG_recall[];
Xextern    char    MSG_twiddle[];
Xextern    char    MSG_forw_page[];
Xextern    char    MSG_kill_region[];
Xextern    char    MSG_yank[];
Xextern    char    MSG_down_window[];
Xextern    char    MSG_ins_toggle[];
Xextern    char    MSG_display_buffers[];
Xextern    char    MSG_quit[];
Xextern    char    MSG_exit_flush_all[];
Xextern    char    MSG_set_file_name[];
Xextern    char    MSG_file_insert[];
Xextern    char    MSG_buf_size_lock[];
Xextern    char    MSG_flush_all[];
Xextern    char    MSG_down_window[];
Xextern    char    MSG_up_window[];
Xextern    char    MSG_file_read[];
Xextern    char    MSG_file_save[];
Xextern    char    MSG_file_visit[];
Xextern    char    MSG_file_write[];
Xextern    char    MSG_swap_dot_and_mark[];
Xextern    char    MSG_shrink_window[];
Xextern    char    MSG_display_position[];
Xextern    char    MSG_start_macro[];
Xextern    char    MSG_end_macro[];
Xextern    char    MSG_help[];
Xextern    char    MSG_only_window[];
Xextern    char    MSG_split_window[];
Xextern    char    MSG_use_buffer[];
Xextern    char    MSG_spawn_cli[];
Xextern    char    MSG_execute_macro[];
Xextern    char    MSG_goto_line[];
Xextern    char    MSG_ins_unit[];
Xextern    char    MSG_kill_buffer[];
Xextern    char    MSG_load_bindings[];
Xextern    char    MSG_forw_window[];
Xextern    char    MSG_back_window[];
Xextern    char    MSG_view_file[];
Xextern    char    MSG_enlarge_window[];
Xextern    char    MSG_ascii_mode[];
Xextern    char    MSG_binary_mode[];
Xextern    char    MSG_buffer_name[];
Xextern    char    MSG_decimal_mode[];
Xextern    char    MSG_ebcdic_mode[];
Xextern    char    MSG_hex_mode[];
Xextern    char    MSG_back_del_unit[];
Xextern    char    MSG_octal_mode[];
Xextern    char    MSG_display_version[];
Xextern    char    MSG_unit_size1[];
Xextern    char    MSG_unit_size2[];
Xextern    char    MSG_unit_size4[];
Xextern    char    MSG_reposition_window[];
Xextern    char    MSG_set_mark[];
Xextern    char    MSG_goto_eob[];
Xextern    char    MSG_goto_bob[];
Xextern    char    MSG_next_buff[];
Xextern    char    MSG_prev_buff[];
Xextern    char    MSG_query_replace[];
Xextern    char    MSG_display_bindings[];
Xextern    char    MSG_auto_save[];
Xextern    char    MSG_back_unit[];
Xextern    char    MSG_compare[];
Xextern    char    MSG_forw_del_unit[];
Xextern    char    MSG_forw_unit[];
Xextern    char    MSG_link_windows[];
Xextern    char    MSG_print[];
Xextern    char    MSG_back_search[];
Xextern    char    MSG_forw_search[];
Xextern    char    MSG_back_page[];
Xextern    char    MSG_copy_region[];
Xextern    char    MSG_extended_command[];
Xextern    char    MSG_up_window[];
Xextern    char    MSG_search_again[];
Xextern    char    MSG_bind_to_key[];
Xextern    char    MSG_file_visit_split[];
Xextern    char    MSG_yank_buffer[];
Xextern    char    MSG_save_region[];
Xextern    char    MSG_use_buffer_split[];
Xextern    char    MSG_no_f_tb[];
X
X#define SPECIAL 0x1F            /* Special keys         */
X
Xtypedef    struct  key_name_array 
X{
X	int     key_code;
X	char    *func_name_str;
X	char    *key_name_str;
X}   KEY_NAME_ARRAY;
X#if MSDOS
Xextern  bool    wang_pc;
Xextern  bool    ibm_pc;
X#endif
X/*
X * The keyboard's special characters, those things that are prefixed with
X * a 0x1F, are placed into the keyboard tables as KCTRL || 0x80 || x, for some
X * x, i.e. they have both the control and 0x80 bits set, so they won't conflict
X * with anything else on the keyboard.
X */
X
X
X/*
X * Names for the keys with basic keycode
X * between KFIRST and KLAST (inclusive). This is used by
X * the key name routine in "kbd.c".
X */
X#if MSDOS
XKEY_NAME_ARRAY wang_keys[] =
X{
X	KCTRL | 0x80, MSG_bind_to_key, "Indent", 
X	    /*  KCTRL | 0x81, NULL, "Page", */
X	KCTRL | 0x82, MSG_reposition_window, "Center",
X	    /*  KCTRL | 0x83, NULL, "DecTab", */
X	/*  KCTRL | 0x84, NULL, "Format", */
X	/*  KCTRL | 0x85, NULL, "Merge", */
X	/*  KCTRL | 0x86, NULL, "Note", */
X	KCTRL | 0x87, MSG_set_mark, "Stop",
X	    KCTRL | 0x88, MSG_forw_search, "Search", 
X	    KCTRL | 0x89, MSG_yank, "Replace",
X	    KCTRL | 0x8A, MSG_copy_region, "Copy",
X	    KCTRL | 0x8B, MSG_kill_region, "Move",
X	    KCTRL | 0x8C, MSG_extended_command, "Command",
X	    KCTRL | 0x8D, MSG_forw_window, "UpDown",
X	    /*  KCTRL | 0x8E, NULL, "BlankKey", */
X	KCTRL | 0x8F, MSG_goto_line, "GoTo",
X	    /*  KCTRL | 0x90, NULL, "Sh-Indent", */
X	/*  KCTRL | 0x91, NULL, "Sh-Page", */
X	/*  KCTRL | 0x92, NULL, "Sh-Center", */
X	/*  KCTRL | 0x93, NULL, "Sh-DecTab", */
X	/*  KCTRL | 0x94, NULL, "Sh-Format", */
X	/*  KCTRL | 0x95, NULL, "Sh-Merge", */
X	/*  KCTRL | 0x96, NULL, "Sh-Note", */
X	/*  KCTRL | 0x97, NULL, "Sh-Stop", */
X	KCTRL | 0x98, MSG_search_again, "Sh-Search",
X	    KCTRL | 0x99, MSG_query_replace, "Sh-Replace",
X	    /*  KCTRL | 0x9A, NULL, "Sh-Copy", */
X	/*  KCTRL | 0x9B, NULL, "Sh-Move", */
X	/*  KCTRL | 0x9C, NULL, "Sh-Command", */
X	KCTRL | 0x9D, MSG_split_window, "Sh-UpDown",
X	    /*  KCTRL | 0x9E, NULL, "Sh-BlankKey", */
X	/*  KCTRL | 0x9F, NULL, "Sh-GoTo", */
X	KCTRL | 0xC0, MSG_back_line, "North",
X	    KCTRL | 0xC1, MSG_forw_char, "East",
X	    KCTRL | 0xC2, MSG_forw_line, "South",
X	    KCTRL | 0xC3, MSG_back_char, "West",
X	    KCTRL | 0xC4, MSG_byte_shift, "Home",
X	    /*  KCTRL | 0xC5, NULL, "Execute", */
X	KCTRL | 0xC6, MSG_ins_toggle, "Insert",
X	    KCTRL | 0xC7, MSG_forw_del_char, "Delete",
X	    KCTRL | 0xC8, MSG_back_page, "PrevPage",
X	    KCTRL | 0xC9, MSG_forw_page, "NextPage",
X	    /*  KCTRL | 0xCB, NULL, "Erase", */
X	/*  KCTRL | 0xCD, NULL, "BackTab", */
X	/*  KCTRL | 0xD0, NULL, "Sh-North", */
X	KCTRL | 0xD1, MSG_forw_unit, "Sh-East",
X	    /*  KCTRL | 0xD2, NULL, "Sh-South", */
X	KCTRL | 0xD3, MSG_back_unit, "Sh-West",
X	    /*  KCTRL | 0xD4, NULL, "Sh-Home", */
X	KCTRL | 0xD5, MSG_execute_macro, "Sh-Execute",
X	    /*  KCTRL | 0xD6, NULL, "Sh-Insert", */
X	KCTRL | 0xD7, MSG_forw_del_unit, "Sh-Delete",
X	    KCTRL | 0xD8, MSG_goto_bob, "Sh-PrevPage",
X	    KCTRL | 0xD9, MSG_goto_eob, "Sh-NextPage",
X	    /*  KCTRL | 0xDB, NULL, "Sh-Erase", */
X	/*  KCTRL | 0xDC, NULL, "Sh-Tab", */
X	/*  KCTRL | 0xDD, NULL, "Sh-BackTab", */
X	KCTRL | 0xE0, MSG_abort, "Cancel",
X	    KMETA | KCTRL | 0xE0, MSG_abort, "Cancel",
X	    KCTLX | KCTRL | 0xE0, MSG_abort, "Ctl-X Cancel",
X	    KCTRL | 0xE1, MSG_display_bindings, "Help",
X	    /*  KCTRL | 0xE2, NULL, "Glossary", */
X	KCTRL | 0xE3, MSG_print, "Print",
X	    KCTRL | 0xF1, MSG_help, "Sh-Help",
X	    /*  KCTRL | 0xF2, NULL, "Sh-Glossary", */
X	/*  KCTRL | 0xF3, NULL, "Sh-Print", */
X	0, NULL, NULL
X};
X
XKEY_NAME_ARRAY  ibm_keys[] =
X{
X	KCTLX | 0x80 | 0x3B, MSG_display_bindings, "F1",
X	    KCTLX | 0x80 | 0x3C, MSG_set_mark, "F2",
X	    KCTLX | 0x80 | 0x3D, MSG_forw_search, "F3",
X	    KCTLX | 0x80 | 0x3E, MSG_search_again, "F4",
X	    KCTLX | 0x80 | 0x3F, MSG_query_replace, "F5",
X	    KCTLX | 0x80 | 0x40, MSG_yank, "F6",
X	    KCTLX | 0x80 | 0x41, MSG_copy_region, "F7",
X	    KCTLX | 0x80 | 0x42, MSG_kill_region, "F8",
X	    KCTLX | 0x80 | 0x43, MSG_goto_line, "F9",
X	    KCTLX | 0x80 | 0x44, MSG_abort, "F10",
X	    KCTLX | 0x80 | 0x54, MSG_help, "Sh-F1",
X	    KCTLX | 0x80 | 0x55, MSG_file_read, "Sh-F2",
X	    KCTLX | 0x80 | 0x56, MSG_file_save, "Sh-F3",
X	    KCTLX | 0x80 | 0x57, MSG_file_visit, "Sh-F4",
X	    KCTLX | 0x80 | 0x58, MSG_file_write, "Sh-F5",
X	    KCTLX | 0x80 | 0x59, MSG_flush_all, "Sh-F6",
X	    KCTLX | 0x80 | 0x5A, MSG_set_file_name, "Sh-F7",
X	    KCTLX | 0x80 | 0x5B, MSG_file_insert, "Sh-F8",
X	    KCTLX | 0x80 | 0x5C, MSG_exit_flush_all, "Sh-F9",
X	    KCTLX | 0x80 | 0x5D, MSG_quit, "Sh-F10",
X	    KCTLX | 0x80 | 0x5E, MSG_display_buffers, "Ctl-F1",
X	    KCTLX | 0x80 | 0x5F, MSG_use_buffer, "Ctl-F2",
X	    KCTLX | 0x80 | 0x60, MSG_kill_buffer, "Ctl-F3",
X	    KCTLX | 0x80 | 0x61, MSG_next_buff, "Ctl-F4",
X	    KCTLX | 0x80 | 0x62, MSG_prev_buff, "Ctl-F5",
X	    KCTLX | 0x80 | 0x63, MSG_yank_buffer, "Ctl-F6",
X	    KCTLX | 0x80 | 0x64, MSG_set_file_name, "Ctl-F7",
X	    KCTLX | 0x80 | 0x65, MSG_file_insert, "Ctl-F8",
X	    KCTLX | 0x80 | 0x66, MSG_exit_flush_all, "Ctl-F9",
X	    KCTLX | 0x80 | 0x67, MSG_quit, "Ctl-F10",
X	    KCTLX | 0x80 | 0x48, MSG_back_line, "North",
X	    KCTLX | 0x80 | 0x4D, MSG_forw_char, "East",
X	    KCTLX | 0x80 | 0x74, MSG_forw_unit, "Ctl-East",
X	    KCTLX | 0x80 | 0x50, MSG_forw_line, "South",
X	    KCTLX | 0x80 | 0x4B, MSG_back_char, "West",
X	    KCTLX | 0x80 | 0x73, MSG_back_unit, "Ctl-West",
X	    KCTLX | 0x80 | 0x49, MSG_back_page, "PageDown",
X	    KCTLX | 0x80 | 0x47, MSG_goto_bob, "Home",
X	    KCTLX | 0x80 | 0x51, MSG_forw_page, "PageUp",
X	    KCTLX | 0x80 | 0x4F, MSG_goto_eob, "End",
X	    KCTLX | 0x80 | 0x52, MSG_ins_toggle, "Insert",
X	    KCTLX | 0x80 | 0x53, MSG_forw_del_char, "Delete",
X	    KCTLX | 0x80 | 0x76, MSG_forw_window, "Ctl-PageDown",
X	    KCTLX | 0x80 | 0x84, MSG_back_window, "Ctl-PageUp",
X	    KCTLX | 0x80 | 0x72, MSG_print, "Ctl-Print",
X	    KCTLX | 0x80 | 0x0F, MSG_forw_unit, "Sh-Tab",
X	    0, NULL, NULL
X};
X#endif
X/*
X * Read in a key, doing the low level mapping
X * of ASCII code to 11 bit code.  This level deals with
X * mapping the special keys into their spots in the C1
X * control area.  The C0 controls go right through, and
X * get remapped by "getkey".
X */
Xstatic int  unkey = KRANDOM;    /* jam - for ungetkey */
Xvoid ungetkey (k)
X{
X	unkey = k;
X}
X
Xint     getkbd ()
X{
X	register int    c;
X
X	if (unkey == KRANDOM)       /* jam */
X		c = ttgetc ();
X	else
X	{
X		c = unkey;
X		unkey = KRANDOM;
X	}
X	if (c == SPECIAL)
X	{
X		c = ttgetc ();
X		if ((c == 0xCD) || (c == 0xDD))/* Backtab is meta */
X			return (METACH);
X		return (c | KCTRL);
X	}
X	if (c == 0)
X	{
X		c = ttgetc ();
X		return (c | 0x80 | KCTLX);
X	}
X	return (c);
X}
X
X
X/*
X * Terminal specific keymap initialization.
X * Attach the special keys to the appropriate built
X * in functions.
X * As is the case of all the keymap routines, errors
X * are very fatal.
X */
Xvoid ttykeymapinit ()
X{
X	KEY_NAME_ARRAY  *ptr;
X	int     i;
X	char    buf[60];
X#if MSDOS
X	if (wang_pc)
X		ptr = wang_keys;
X
X	if (ibm_pc)
X		ptr = ibm_keys;
X
X	if (!wang_pc && !ibm_pc)
X		return;
X
X	i = 0;
X	while (ptr -> key_code != 0)
X	{
X		if (ptr -> func_name_str != NULL)
X			keydup (ptr -> key_code, ptr -> func_name_str);
X		ptr++;
X		i++;
X	}
X	sprintf (buf, MSG_sp_key, i);
X	writ_echo (buf);
X#endif
X}
X/* 
X*   Search key name array for given key code.
X*   return pointer to key name.
X*/
Xchar    *keystrings (key)
Xint     key;
X{
X#if MSDOS
X	KEY_NAME_ARRAY  *ptr;
X
X	if (wang_pc)
X		ptr = wang_keys;
X
X	if (ibm_pc)
X		ptr = ibm_keys;
X
X	if (!wang_pc && !ibm_pc)
X		return(NULL);
X
X	while (ptr -> key_code != 0)
X	{
X		if (key == ptr -> key_code)
X		{
X			return (ptr -> key_name_str);
X		}
X		ptr++;
X	}
X#endif
X	return (NULL);
X}
END_OF_FILE
if test 11161 -ne `wc -c <'ttykbd.c'`; then
    echo shar: \"'ttykbd.c'\" unpacked with wrong size!
fi
# end of 'ttykbd.c'
fi
echo shar: End of archive 3 \(of 9\).
cp /dev/null ark3isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 9 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 9 archives.
    rm -f ark[1-9]isdone ark[1-9][0-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0

-- 
>>>>>>>>>>>>>>>> Peter Reilley ..... pvr@wang.com <<<<<<<<<<<<<<<<<<<<<<<
                     Well, that about says it.

exit 0 # Just in case...
-- 
Kent Landfield                   INTERNET: kent@sparky.IMD.Sterling.COM
Sterling Software, IMD           UUCP:     uunet!sparky!kent
Phone:    (402) 291-8300         FAX:      (402) 291-4362
Please send comp.sources.misc-related mail to kent@uunet.uu.net.
