Elvis 1.4, part 8 of 8

Steve Kirkendall kirkenda at eecs.cs.pdx.edu
Tue Dec 4 08:36:52 AEST 1990


# --------------------------- cut here ----------------------------
# This is a shar archive.  To unpack it, save it to a file, and delete
# anything above the "cut here" line.  Then run sh on the file.
#
# -rw-r--r--  1 kirkenda     7638 Dec  2 17:57 refont.c
# -rw-r--r--  1 kirkenda     2957 Dec  2 17:57 vars.c
# -rw-r--r--  1 kirkenda    13459 Dec  2 17:57 vcmd.c
# -rw-r--r--  1 kirkenda    20322 Dec  2 17:57 vi.c
# -rw-r--r--  1 kirkenda    18110 Dec  2 17:57 vi.h
#

if test -f vars.c -a "$1" != -f
then
echo Will not overwrite vars.c
else
echo Extracting vars.c
sed 's/^X//' >vars.c <<\eof
X/* vars.c */
X
X/* Author:
X *	Steve Kirkendall
X *	14407 SW Teal Blvd. #C
X *	Beaverton, OR 97005
X *	kirkenda at cs.pdx.edu
X */
X
X
X/* This file contains variables which weren't happy anyplace else */
X
X#include "config.h"
X#include "vi.h"
X
X/*------------------------------------------------------------------------*/
X
X/* used to remember whether the file has been modified */
Xstruct _viflags	viflags;
X
X/* used to access the tmp file */
Xlong		lnum[MAXBLKS];
Xlong		nlines;
Xint		tmpfd = -1;
X
X/* used to keep track of the current file & alternate file */
Xlong		origtime;
Xchar		origname[256];
Xchar		prevorig[256];
Xlong		prevline = 1;
X
X/* used to track various places in the text */
XMARK		mark[NMARKS];	/* marks 'a through 'z, plus mark '' */
XMARK		cursor;		/* the cursor position within the file */
X
X/* which mode of the editor we're in */
Xint		mode;		/* vi mode? ex mode? quitting? */
X
X/* used to manage the args list */
Xchar		args[BLKSIZE];	/* list of filenames to edit */
Xint		argno;		/* index of current file in args list */
Xint		nargs;		/* number of filenames in args[] */
X
X/* dummy var, never explicitly referenced */
Xint		bavar;		/* used only in BeforeAfter macros */
X
X/* have we made a multi-line change? */
Xint		mustredraw;	/* must we redraw the whole screen? */
X
X/* used to detect changes that invalidate cached text/blocks */
Xlong		changes;	/* incremented when file is changed */
Xint		significant;	/* boolean: was a *REAL* change made? */
X
X/* used to support the pfetch() macro */
Xint		plen;		/* length of the line */
Xlong		pline;		/* line number that len refers to */
Xlong		pchgs;		/* "changes" level that len refers to */
Xchar		*ptext;		/* text of previous line, if valid */
X
X/* misc temporary storage - mostly for strings */
XBLK		tmpblk;		/* a block used to accumulate changes */
X
X/* screen oriented stuff */
Xlong		topline;	/* file line number of top line */
Xint		leftcol;	/* column number of left col */
Xint		physcol;	/* physical column number that cursor is on */
Xint		physrow;	/* physical row number that cursor is on */
X
X/* used to help minimize that "[Hit a key to continue]" message */
Xint		exwrote;	/* Boolean: was the last ex command wordy? */
X
X/* This variable affects the behaviour of certain functions -- most importantly
X * the input function.
X */
Xint		doingdot;	/* boolean: are we doing the "." command? */
X
X/* This variable affects the behaviour of the ":s" command, and it is also
X * used to detect & prohibit nesting of ":g" commands
X */
Xint		doingglobal;	/* boolean: are doing a ":g" command? */
X/* These are used for reporting multi-line changes to the user */
Xlong		rptlines;	/* number of lines affected by a command */
Xchar		*rptlabel;	/* description of how lines were affected */
X
X/* These store info that pertains to the shift-U command */
Xlong	U_line;			/* line# of the undoable line, or 0l for none */
Xchar	U_text[BLKSIZE];	/* contents of the undoable line */
X
X/* Bigger stack req'ed for TOS */
X
X#if TOS
Xlong	_stksize = 16384;
X#endif
eof
if test `wc -c <vars.c` -ne 2957
then
echo vars.c damaged!
fi
fi

if test -f vcmd.c -a "$1" != -f
then
echo Will not overwrite vcmd.c
else
echo Extracting vcmd.c
sed 's/^X//' >vcmd.c <<\eof
X/* vcmd.c */
X
X/* Author:
X *	Steve Kirkendall
X *	14407 SW Teal Blvd. #C
X *	Beaverton, OR 97005
X *	kirkenda at cs.pdx.edu
X */
X
X
X/* This file contains the functions that handle VI commands */
X
X
X#include "config.h"
X#include "vi.h"
X#if MSDOS
X#include <process.h>
X#include <string.h>
X#endif
X#if TOS
X#include <osbind.h>
X#include <string.h>
X#endif
X#if OSK
X# include <stdio.h>
X#endif
X
X
X/* This function puts the editor in EX mode */
XMARK v_quit()
X{
X	move(LINES - 1, 0);
X	mode = MODE_EX;
X	return cursor;
X}
X
X/* This function causes the screen to be redrawn */
XMARK v_redraw()
X{
X	redraw(MARK_UNSET, FALSE);
X	return cursor;
X}
X
X/* This function executes a single EX command, and waits for a user keystroke
X * before returning to the VI screen.  If that keystroke is another ':', then
X * another EX command is read and executed.
X */
X/*ARGSUSED*/
XMARK v_1ex(m, text)
X	MARK	m;	/* the current line */
X	char	*text;	/* the first command to execute */
X{
X	/* run the command.  be careful about modes & output */
X	exwrote = (mode == MODE_COLON);
X	doexcmd(text);
X	exrefresh();
X
X	/* if mode is no longer MODE_VI, then we should quit right away! */
X	if (mode != MODE_VI && mode != MODE_COLON)
X		return cursor;
X
X	/* The command did some output.  Wait for a keystoke. */
X	if (exwrote)
X	{
X		mode = MODE_VI;	
X		msg("[Hit <RETURN> to continue]");
X		if (getkey(0) == ':')
X		{	mode = MODE_COLON;
X			addch('\n');
X		}
X		else
X			redraw(MARK_UNSET, FALSE);
X	}
X
X	return cursor;
X}
X
X/* This function undoes the last change */
X/*ARGSUSED*/
XMARK v_undo(m)
X	MARK	m;	/* (ignored) */
X{
X	if (undo())
X	{
X		redraw(MARK_UNSET, FALSE);
X	}
X	return cursor;
X}
X
X/* This function deletes the character(s) that the cursor is on */
XMARK v_xchar(m, cnt, cmd)
X	MARK	m;	/* where to start deletions */
X	long	cnt;	/* number of chars to delete */
X	int	cmd;	/* either 'x' or 'X' */
X{
X	DEFAULT(1);
X
X	/* for 'X', adjust so chars are deleted *BEFORE* cursor */
X	if (cmd == 'X')
X	{
X		if (markidx(m) < cnt)
X			return MARK_UNSET;
X		m -= cnt;
X	}
X
X	/* make sure we don't try to delete more thars than there are */
X	pfetch(markline(m));
X	if (markidx(m + cnt) > plen)
X	{
X		cnt = plen - markidx(m);
X	}
X	if (cnt == 0L)
X	{
X		return MARK_UNSET;
X	}
X
X	/* do it */
X	ChangeText
X	{
X		cut(m, m + cnt);
X		delete(m, m + cnt);
X	}
X	return m;
X}
X
X/* This function defines a mark */
X/*ARGSUSED*/
XMARK v_mark(m, count, key)
X	MARK	m;	/* where the mark will be */
X	long	count;	/* (ignored) */
X	int	key;	/* the ASCII label of the mark */
X{
X	if (key < 'a' || key > 'z')
X	{
X		msg("Marks must be from a to z");
X	}
X	else
X	{
X		mark[key - 'a'] = m;
X	}
X	return m;
X}
X
X/* This function toggles upper & lower case letters */
XMARK v_ulcase(m, cnt)
X	MARK	m;	/* where to make the change */
X	long	cnt;	/* number of chars to flip */
X{
X	REG char 	*pos;
X	REG int		i, j;
X	static char	flip[] =
X		"aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ[](){}<>";
X
X	DEFAULT(1);
X
X	/* fetch the current version of the line */
X	pfetch(markline(m));
X
X	/* for each position in the line */
X	for (j = 0, i = markidx(m); j < cnt && ptext[i]; j++, i++)
X	{
X		tmpblk.c[j] = 0;
X
X		/* one of the standard chars? */
X		for (pos = flip; *pos && *pos != ptext[i]; pos++)
X		{
X		}
X		if (*pos)
X		{
X			tmpblk.c[j] = flip[(int)(pos - flip) ^ 1];
X		}
X#ifndef NO_DIGRAPH
X		else /* one of the non-standard chars? */
X		{
X			for (pos = o_flipcase; *pos && *pos != ptext[i]; pos++)
X			{
X			}
X			if (*pos)
X			{
X				tmpblk.c[j] = o_flipcase[(int)(pos - o_flipcase) ^ 1];
X			}
X		}
X#endif
X
X		/* if nothing special, then don't change it */
X		if (tmpblk.c[j] == 0)
X		{
X			tmpblk.c[j] = ptext[i];
X		}
X	}
X
X	/* if the new text is different from the old, then change it */
X	if (strncmp(tmpblk.c, &ptext[markidx(m)], j))
X	{
X		ChangeText
X		{
X			tmpblk.c[j] = '\0';
X			change(m, m + j, tmpblk.c);
X		}
X	}
X
X	return m + j;
X}
X
X
XMARK v_replace(m, cnt, key)
X	MARK	m;	/* first char to be replaced */
X	long	cnt;	/* number of chars to replace */
X	int	key;	/* what to replace them with */
X{
X	REG char	*text;
X	REG int		i;
X
X	DEFAULT(1);
X
X	/* map ^M to '\n' */
X	if (key == '\r')
X	{
X		key = '\n';
X	}
X
X	/* make sure the resulting line isn't too long */
X	if (cnt > BLKSIZE - 2 - markidx(m))
X	{
X		cnt = BLKSIZE - 2 - markidx(m);
X	}
X
X	/* build a string of the desired character with the desired length */
X	for (text = tmpblk.c, i = cnt; i > 0; i--)
X	{
X		*text++ = key;
X	}
X	*text = '\0';
X
X	/* make sure cnt doesn't extend past EOL */
X	pfetch(markline(m));
X	key = markidx(m);
X	if (key + cnt > plen)
X	{
X		cnt = plen - key;
X	}
X
X	/* do the replacement */
X	ChangeText
X	{
X		change(m, m + cnt, tmpblk.c);
X	}
X
X	if (*tmpblk.c == '\n')
X	{
X		return (m & ~(BLKSIZE - 1)) + cnt * BLKSIZE;
X	}
X	else
X	{
X		return m + cnt - 1;
X	}
X}
X
XMARK v_overtype(m)
X	MARK		m;	/* where to start overtyping */
X{
X	MARK		end;	/* end of a substitution */
X	static long	width;	/* width of a single-line replace */
X
X	/* the "doingdot" version of replace is really a substitution */
X	if (doingdot)
X	{
X		/* was the last one really repeatable? */
X		if (width < 0)
X		{
X			msg("Can't repeat a multi-line overtype command");
X			return MARK_UNSET;
X		}
X
X		/* replacing nothing by nothing?  Don't bother */
X		if (width == 0)
X		{
X			return m;
X		}
X
X		/* replace some chars by repeated text */
X		return v_subst(m, width);
X	}
X
X	/* Normally, we input starting here, in replace mode */
X	ChangeText
X	{
X		end = input(m, m, WHEN_VIREP);
X	}
X
X	/* if we ended on the same line we started on, then this
X	 * overtype is repeatable via the dot key.
X	 */
X	if (markline(end) == markline(m) && end >= m - 1L)
X	{
X		width = end - m + 1L;
X	}
X	else /* it isn't repeatable */
X	{
X		width = -1L;
X	}
X
X	return end;
X}
X
X
X/* This function selects which cut buffer to use */
X/*ARGSUSED*/
XMARK v_selcut(m, cnt, key)
X	MARK	m;
X	long	cnt;
X	int	key;
X{
X	cutname(key);
X	return m;
X}
X
X/* This function pastes text from a cut buffer */
X/*ARGSUSED*/
XMARK v_paste(m, cnt, cmd)
X	MARK	m;	/* where to paste the text */
X	long	cnt;	/* (ignored) */
X	int	cmd;	/* either 'p' or 'P' */
X{
X	ChangeText
X	{
X		m = paste(m, cmd == 'p', FALSE);
X	}
X	return m;
X}
X
X/* This function yanks text into a cut buffer */
XMARK v_yank(m, n)
X	MARK	m, n;	/* range of text to yank */
X{
X	cut(m, n);
X	return m;
X}
X
X/* This function deletes a range of text */
XMARK v_delete(m, n)
X	MARK	m, n;	/* range of text to delete */
X{
X	/* illegal to try and delete nothing */
X	if (n <= m)
X	{
X		return MARK_UNSET;
X	}
X
X	/* Do it */
X	ChangeText
X	{
X		cut(m, n);
X		delete(m, n);
X	}
X	return m;
X}
X
X
X/* This starts input mode without deleting anything */
XMARK v_insert(m, cnt, key)
X	MARK	m;	/* where to start (sort of) */
X	long	cnt;	/* repeat how many times? */
X	int	key;	/* what command is this for? {a,A,i,I,o,O} */
X{
X	int	wasdot;
X	long	reps;
X	int	after;	/* are we appending or inserting? */
X
X	DEFAULT(1);
X
X	ChangeText
X	{
X		/* tweak the insertion point, based on command key */
X		switch (key)
X		{
X		  case 'i':
X			after = FALSE;
X			break;
X
X		  case 'a':
X			pfetch(markline(m));
X			if (plen > 0)
X			{
X				m++;
X			}
X			after = TRUE;
X			break;
X
X		  case 'I':
X			m = m_front(m, 1L);
X			after = FALSE;
X			break;
X
X		  case 'A':
X			pfetch(markline(m));
X			m = (m & ~(BLKSIZE - 1)) + plen;
X			after = TRUE;
X			break;
X
X		  case 'O':
X			m &= ~(BLKSIZE - 1);
X			add(m, "\n");
X			after = FALSE;
X			break;
X
X		  case 'o':
X			m = (m & ~(BLKSIZE - 1)) + BLKSIZE;
X			add(m, "\n");
X			after = FALSE;
X			break;
X		}
X
X		/* insert the same text once or more */
X		for (reps = cnt, wasdot = doingdot; reps > 0; reps--, doingdot = TRUE)
X		{
X			m = input(m, m, WHEN_VIINP);
X			if (after)
X			{
X				m++;
X			}
X		}
X		if (after)
X		{
X			m--;
X		}
X
X		doingdot = wasdot;
X	}
X
X#ifndef CRUNCH
X# ifndef NO_EXTENSIONS
X	if (key == 'i' && *o_inputmode && mode == MODE_VI)
X	{
X		msg("Now in visual command mode!  To return to input mode, hit <i>.");
X	}
X# endif
X#endif
X
X	return m;
X}
X
X/* This starts input mode with some text deleted */
XMARK v_change(m, n)
X	MARK	m, n;	/* the range of text to change */
X{
X	int	lnmode;	/* is this a line-mode change? */
X
X	/* swap them if they're in reverse order */
X	if (m > n)
X	{
X		MARK	tmp;
X		tmp = m;
X		m = n;
X		n = tmp;
X	}
X
X	/* for line mode, retain the last newline char */
X	lnmode = (markidx(m) == 0 && markidx(n) == 0 && m != n);
X	if (lnmode)
X	{
X		n -= BLKSIZE;
X		pfetch(markline(n));
X		n = (n & ~(BLKSIZE - 1)) + plen;
X	}
X
X	ChangeText
X	{
X		cut(m, n);
X		m = input(m, n, WHEN_VIINP);
X	}
X
X	return m;
X}
X
X/* This function replaces a given number of characters with input */
XMARK v_subst(m, cnt)
X	MARK	m;	/* where substitutions start */
X	long	cnt;	/* number of chars to replace */
X{
X	DEFAULT(1);
X
X	/* make sure we don't try replacing past EOL */
X	pfetch(markline(m));
X	if (markidx(m) + cnt > plen)
X	{
X		cnt = plen - markidx(m);
X	}
X
X	/* Go for it! */
X	ChangeText
X	{
X		cut(m, m + cnt);
X		m = input(m, m + cnt, WHEN_VIINP);
X	}
X	return m;
X}
X
X/* This calls the ex "join" command to join some lines together */
XMARK v_join(m, cnt)
X	MARK	m;	/* the first line to be joined */
X	long	cnt;	/* number of other lines to join */
X{
X	MARK	joint;	/* where the lines were joined */
X
X	DEFAULT(1);
X
X	/* figure out where the joint will be */
X	pfetch(markline(m));
X	joint = (m & ~(BLKSIZE - 1)) + plen;
X
X	/* join the lines */
X	cmd_join(m, m + MARK_AT_LINE(cnt), CMD_JOIN, 0, "");
X	mustredraw = TRUE;
X
X	/* the cursor should be left at the joint */
X	return joint;
X}
X
X/* This calls the ex shifter command to shift some lines */
Xstatic MARK shift_help(m, n, excmd)
X	MARK	m, n;	/* range of lines to shift */
X	CMD	excmd;	/* which way do we shift? */
X{
X	/* adjust for inclusive endmarks in ex */
X	n -= BLKSIZE;
X
X	cmd_shift(m, n, excmd, 0, "");
X	return m;
X}
X
X/* This calls the ex "<" command to shift some lines left */
XMARK v_lshift(m, n)
X	MARK	m, n;	/* range of lines to shift */
X{
X	return shift_help(m, n, CMD_SHIFTL);
X}
X
X/* This calls the ex ">" command to shift some lines right */
XMARK v_rshift(m, n)
X	MARK	m, n;	/* range of lines to shift */
X{
X	return shift_help(m, n, CMD_SHIFTR);
X}
X
X/* This runs some lines through a filter program */
XMARK v_filter(m, n)
X	MARK	m, n;	/* range of lines to shift */
X{
X	char	cmdln[100];	/* a shell command line */
X
X	/* adjust for inclusive endmarks in ex */
X	n -= BLKSIZE;
X
X	if (vgets('!', cmdln, sizeof(cmdln)) > 0)
X	{
X		filter(m, n, cmdln);
X	}
X
X	redraw(MARK_UNSET, FALSE);
X	return m;
X}
X
X
X/* This function runs the ex "file" command to show the file's status */
XMARK v_status()
X{
X	cmd_file(cursor, cursor, CMD_FILE, 0, "");
X	return cursor;
X}
X
X
X/* This function runs the ":&" command to repeat the previous :s// */
XMARK v_again(m, n)
X	MARK	m, n;
X{
X	cmd_substitute(m, n - BLKSIZE, CMD_SUBAGAIN, TRUE, "");
X	return cursor;
X}
X
X
X
X/* This function switches to the previous file, if possible */
XMARK v_switch()
X{
X	if (!*prevorig)
X		msg("No previous file");
X	else
X	{	strcpy(tmpblk.c, prevorig);
X		cmd_edit(cursor, cursor, CMD_EDIT, 0, tmpblk.c);
X	}
X	return cursor;
X}
X
X/* This function does a tag search on a keyword */
X/*ARGSUSED*/
XMARK v_tag(keyword, m, cnt)
X	char	*keyword;
X	MARK	m;
X	long	cnt;
X{
X	/* move the cursor to the start of the tag name, where m is */
X	cursor = m;
X
X	/* perform the tag search */
X	cmd_tag(cursor, cursor, CMD_TAG, 0, keyword);
X
X	return cursor;
X}
X
X#ifndef NO_EXTENSIONS
X/* This function looks up a keyword by calling the helpprog program */
X/*ARGSUSED*/
XMARK v_keyword(keyword, m, cnt)
X	char	*keyword;
X	MARK	m;
X	long	cnt;
X{
X	int	waswarn;
X	char	cmdline[130];
X
X	move(LINES - 1, 0);
X	addstr("---------------------------------------------------------\n");
X	clrtoeol();
X	refresh();
X	sprintf(cmdline, "%s %s", o_keywordprg, keyword);
X	waswarn = *o_warn;
X	*o_warn = FALSE;
X	suspend_curses();
X	if (system(cmdline))
X	{
X		addstr("<<< failed >>>\n");
X	}
X	resume_curses(FALSE);
X	mode = MODE_VI;
X	redraw(MARK_UNSET, FALSE);
X	*o_warn = waswarn;
X
X	return m;
X}
X
X
X
XMARK v_increment(keyword, m, cnt)
X	char	*keyword;
X	MARK	m;
X	long	cnt;
X{
X	static	sign;
X	char	newval[12];
X	long	atol();
X
X	DEFAULT(1);
X
X	/* get one more keystroke, unless doingdot */
X	if (!doingdot)
X	{
X		sign = getkey(0);
X	}
X
X	/* adjust the number, based on that second keystroke */
X	switch (sign)
X	{
X	  case '+':
X	  case '#':
X		cnt = atol(keyword) + cnt;
X		break;
X
X	  case '-':
X		cnt = atol(keyword) - cnt;
X		break;
X
X	  case '=':
X		break;
X
X	  default:
X		return MARK_UNSET;
X	}
X	sprintf(newval, "%ld", cnt);
X
X	ChangeText
X	{
X		change(m, m + strlen(keyword), newval);
X	}
X
X	return m;
X}
X#endif
X
X
X/* This function acts like the EX command "xit" */
X/*ARGSUSED*/
XMARK v_xit(m, cnt, key)
X	MARK	m;	/* ignored */
X	long	cnt;	/* ignored */
X	int	key;	/* must be a second 'Z' */
X{
X	/* if second char wasn't 'Z', fail */
X	if (key != 'Z')
X	{
X		return MARK_UNSET;
X	}
X
X	/* move the cursor to the bottom of the screen */
X	move(LINES - 1, 0);
X	clrtoeol();
X
X	/* do the xit command */
X	cmd_xit(m, m, CMD_XIT, FALSE, "");
X
X	/* return the cursor */
X	return m;
X}
X
X
X/* This function undoes changes to a single line, if possible */
XMARK v_undoline(m)
X	MARK	m;	/* where we hope to undo the change */
X{
X	/* make sure we have the right line in the buffer */
X	if (markline(m) != U_line)
X	{
X		return MARK_UNSET;
X	}
X
X	/* fix it */
X	ChangeText
X	{
X		strcat(U_text, "\n");
X		change(MARK_AT_LINE(U_line), MARK_AT_LINE(U_line + 1), U_text);
X	}
X
X	/* nothing in the buffer anymore */
X	U_line = -1L;
X
X	/* return, with the cursor at the front of the line */
X	return m & ~(BLKSIZE - 1);
X}
X
X
X#ifndef NO_ERRLIST
XMARK v_errlist(m)
X	MARK	m;
X{
X	cmd_errlist(m, m, CMD_ERRLIST, FALSE, "");
X	return cursor;
X}
X#endif
X
X
X#ifndef NO_AT
X/*ARGSUSED*/
XMARK v_at(m, cnt, key)
X	MARK	m;
X	long	cnt;
X	int	key;
X{
X	if (!fromcutbuf(key))
X	{
X		return MARK_UNSET;
X	}
X	return cursor;
X}
X#endif
eof
if test `wc -c <vcmd.c` -ne 13459
then
echo vcmd.c damaged!
fi
fi

if test -f vi.c -a "$1" != -f
then
echo Will not overwrite vi.c
else
echo Extracting vi.c
sed 's/^X//' >vi.c <<\eof
X/* vi.c */
X
X/* Author:
X *	Steve Kirkendall
X *	14407 SW Teal Blvd. #C
X *	Beaverton, OR 97005
X *	kirkenda at cs.pdx.edu
X */
X
X
X#include "config.h"
X#include <ctype.h>
X#include "vi.h"
X
X
X
X/* This array describes what each key does */
X#define NO_FUNC		(MARK (*)())0
X#define NO_ARGS		0
X#define CURSOR_COUNT	1
X#define CURSOR		2
X#define CURSOR_CNT_KEY	3
X#define CURSOR_MOVED	4
X#define CURSOR_EOL	5
X#define ZERO		6
X#define DIGIT		7
X#define CURSOR_TEXT	8
X#define CURSOR_CNT_CMD	9
X#define KEYWORD		10
X#define NO_FLAGS	0x00
X#define	MVMT		0x01	/* this is a movement command */
X#define PTMV		0x02	/* this can be *part* of a movement command */
X#define FRNT		0x04	/* after move, go to front of line */
X#define INCL		0x08	/* include last char when used with c/d/y */
X#define LNMD		0x10	/* use line mode of c/d/y */
X#define NCOL		0x20	/* this command can't change the column# */
X#define NREL		0x40	/* this is "non-relative" -- set the '' mark */
X#define SDOT		0x80	/* set the "dot" variables, for the "." cmd */
Xstatic struct keystru
X{
X	MARK	(*func)();	/* the function to run */
X	uchar	args;		/* description of the args needed */
X	uchar	flags;		/* other stuff */
X}
X	vikeys[] =
X{
X/* NUL not defined	*/	{NO_FUNC,	NO_ARGS,	NO_FLAGS},
X/* ^A  not defined	*/	{NO_FUNC,	NO_ARGS,	NO_FLAGS},
X/* ^B  page backward	*/	{m_scroll,	CURSOR_CNT_CMD,	FRNT},
X/* ^C  not defined	*/	{NO_FUNC,	NO_ARGS,	NO_FLAGS},
X/* ^D  scroll dn 1/2page*/	{m_scroll,	CURSOR_CNT_CMD,	NCOL},
X/* ^E  scroll up	*/	{m_scroll,	CURSOR_CNT_CMD,	NCOL},
X/* ^F  page forward	*/	{m_scroll,	CURSOR_CNT_CMD,	FRNT},
X/* ^G  show file status	*/	{v_status,	NO_ARGS, 	NO_FLAGS},
X/* ^H  move left, like h*/	{m_left,	CURSOR_COUNT,	MVMT},
X/* ^I  not defined	*/	{NO_FUNC,	NO_ARGS,	NO_FLAGS},
X/* ^J  move down	*/	{m_updnto,	CURSOR_CNT_CMD,	MVMT|LNMD},
X/* ^K  not defined	*/	{NO_FUNC,	NO_ARGS,	NO_FLAGS},
X/* ^L  redraw screen	*/	{v_redraw,	NO_ARGS,	NO_FLAGS},
X/* ^M  mv front next ln */	{m_updnto,	CURSOR_CNT_CMD,	MVMT|FRNT|LNMD},
X/* ^N  move down	*/	{m_updnto,	CURSOR_CNT_CMD,	MVMT|LNMD},
X/* ^O  not defined	*/	{NO_FUNC,	NO_ARGS,	NO_FLAGS},
X/* ^P  move up		*/	{m_updnto,	CURSOR_CNT_CMD,	MVMT|LNMD},
X/* ^Q  not defined	*/	{NO_FUNC,	NO_ARGS,	NO_FLAGS},
X/* ^R  redraw screen	*/	{v_redraw,	NO_ARGS,	NO_FLAGS},
X/* ^S  not defined	*/	{NO_FUNC,	NO_ARGS,	NO_FLAGS},
X/* ^T  not defined	*/	{NO_FUNC,	NO_ARGS,	NO_FLAGS},
X/* ^U  scroll up 1/2page*/	{m_scroll,	CURSOR_CNT_CMD,	NCOL},
X/* ^V  not defined	*/	{NO_FUNC,	NO_ARGS,	NO_FLAGS},
X/* ^W  not defined	*/	{NO_FUNC,	NO_ARGS,	NO_FLAGS},
X/* ^X  not defined	*/	{NO_FUNC,	NO_ARGS,	NO_FLAGS},
X/* ^Y  scroll down	*/	{m_scroll,	CURSOR_CNT_CMD,	NCOL},
X/* ^Z  not defined	*/	{NO_FUNC,	NO_ARGS,	NO_FLAGS},
X/* ESC not defined	*/	{NO_FUNC,	NO_ARGS,	NO_FLAGS},
X/* ^\  not defined	*/	{NO_FUNC,	NO_ARGS,	NO_FLAGS},
X/* ^]  keyword is tag	*/	{v_tag,		KEYWORD,	NO_FLAGS},
X/* ^^  previous file	*/	{v_switch,	CURSOR,		NO_FLAGS},
X/* ^_  not defined	*/	{NO_FUNC,	NO_ARGS,	NO_FLAGS},
X/* SPC move right,like l*/	{m_right,	CURSOR_COUNT,	MVMT},
X/*  !  run thru filter	*/	{v_filter,	CURSOR_MOVED,	FRNT|LNMD|INCL},
X/*  "  select cut buffer*/	{v_selcut,	CURSOR_CNT_KEY,	PTMV},
X#ifndef NO_EXTENSIONS
X/*  #  increment number	*/	{v_increment,	KEYWORD,	SDOT},
X#else
X/*  #  not defined	*/	{NO_FUNC,	NO_ARGS,	NO_FLAGS},
X#endif
X/*  $  move to rear	*/	{m_rear,	CURSOR,		MVMT|INCL},
X/*  %  move to match	*/	{m_match,	CURSOR,		MVMT|INCL},
X/*  &  repeat subst	*/	{v_again,	CURSOR_MOVED,	SDOT|NCOL|LNMD|INCL},
X/*  '  move to a mark	*/	{m_tomark,	CURSOR_CNT_KEY,	MVMT|FRNT|NREL|LNMD|INCL},
X#ifndef NO_SENTENCE
X/*  (  mv back sentence	*/	{m_bsentence,	CURSOR_COUNT,	MVMT},
X/*  )  mv fwd sentence	*/	{m_fsentence,	CURSOR_COUNT,	MVMT},
X#else
X/*  (  not defined	*/	{NO_FUNC,	NO_ARGS,	NO_FLAGS},
X/*  )  not defined	*/	{NO_FUNC,	NO_ARGS,	NO_FLAGS},
X#endif
X#ifndef NO_ERRLIST
X/*  *  errlist		*/	{v_errlist,	CURSOR,		FRNT|NREL},
X#else
X/*  *  not defined	*/	{NO_FUNC,	NO_ARGS,	NO_FLAGS},
X#endif
X/*  +  mv front next ln */	{m_updnto,	CURSOR_CNT_CMD,	MVMT|FRNT|LNMD},
X#ifndef NO_CHARSEARCH
X/*  ,  reverse [fFtT] cmd*/	{m__ch,		CURSOR_CNT_CMD,	MVMT|INCL},
X#else
X/*  ,  not defined	*/	{NO_FUNC,	NO_ARGS,	NO_FLAGS},
X#endif
X/*  -  mv front prev ln	*/	{m_updnto,	CURSOR_CNT_CMD,	MVMT|FRNT|LNMD},
X/*  .  special...	*/	{NO_FUNC,	NO_ARGS,	NO_FLAGS},
X/*  /  forward search	*/	{m_fsrch,	CURSOR_TEXT,	MVMT|NREL},
X/*  0  part of count?	*/	{NO_FUNC,	ZERO,		MVMT|PTMV},
X/*  1  part of count	*/	{NO_FUNC,	DIGIT,		PTMV},
X/*  2  part of count	*/	{NO_FUNC,	DIGIT,		PTMV},
X/*  3  part of count	*/	{NO_FUNC,	DIGIT,		PTMV},
X/*  4  part of count	*/	{NO_FUNC,	DIGIT,		PTMV},
X/*  5  part of count	*/	{NO_FUNC,	DIGIT,		PTMV},
X/*  6  part of count	*/	{NO_FUNC,	DIGIT,		PTMV},
X/*  7  part of count	*/	{NO_FUNC,	DIGIT,		PTMV},
X/*  8  part of count	*/	{NO_FUNC,	DIGIT,		PTMV},
X/*  9  part of count	*/	{NO_FUNC,	DIGIT,		PTMV},
X/*  :  run single EX cmd*/	{v_1ex,		CURSOR_TEXT,	NO_FLAGS},
X#ifndef NO_CHARSEARCH
X/*  ;  repeat [fFtT] cmd*/	{m__ch,		CURSOR_CNT_CMD,	MVMT|INCL},
X#else
X/*  ;  not defined	*/	{NO_FUNC,	NO_ARGS,	NO_FLAGS},
X#endif
X/*  <  shift text left	*/	{v_lshift,	CURSOR_MOVED,	SDOT|FRNT|LNMD|INCL},
X/*  =  not defined	*/	{NO_FUNC,	NO_ARGS,	NO_FLAGS},
X/*  >  shift text right	*/	{v_rshift,	CURSOR_MOVED,	SDOT|FRNT|LNMD|INCL},
X/*  ?  backward search	*/	{m_bsrch,	CURSOR_TEXT,	MVMT|NREL},
X#ifndef NO_AT
X/*  @  execute a cutbuf */	{v_at,		CURSOR_CNT_KEY,	NO_FLAGS},
X#else
X/*  @  undefined	*/	{NO_FUNC,	NO_ARGS,	NO_FLAGS},
X#endif
X/*  A  append at EOL	*/	{v_insert,	CURSOR_CNT_CMD,	SDOT},
X/*  B  move back Word	*/	{m_bword,	CURSOR_CNT_CMD,	MVMT},
X/*  C  change to EOL	*/	{v_change,	CURSOR_EOL,	SDOT},
X/*  D  delete to EOL	*/	{v_delete,	CURSOR_EOL,	SDOT},
X/*  E  move end of Word	*/	{m_eword,	CURSOR_CNT_CMD,	MVMT|INCL},
X#ifndef NO_CHARSEARCH
X/*  F  move bk to char	*/	{m_Fch,		CURSOR_CNT_KEY,	MVMT|INCL},
X#else
X/*  F  not defined	*/	{NO_FUNC,	NO_ARGS,	NO_FLAGS},
X#endif
X/*  G  move to line #	*/	{m_updnto,	CURSOR_CNT_CMD,	MVMT|NREL|LNMD|FRNT|INCL},
X/*  H  move to row	*/	{m_row,		CURSOR_CNT_CMD,	MVMT|FRNT},
X/*  I  insert at front	*/	{v_insert,	CURSOR_CNT_CMD,	SDOT},
X/*  J  join lines	*/	{v_join,	CURSOR_COUNT,	SDOT},
X#ifndef NO_EXTENSIONS
X/*  K  look up keyword	*/	{v_keyword,	KEYWORD,	NO_FLAGS},
X#else
X/*  K  not defined	*/	{NO_FUNC,	NO_ARGS,	NO_FLAGS},
X#endif
X/*  L  move to last row	*/	{m_row,		CURSOR_CNT_CMD,	MVMT|FRNT},
X/*  M  move to mid row	*/	{m_row,		CURSOR_CNT_CMD,	MVMT|FRNT},
X/*  N  reverse prev srch*/	{m_Nsrch,	CURSOR,		MVMT},
X/*  O  insert above line*/	{v_insert,	CURSOR_CNT_CMD,	SDOT},
X/*  P  paste before	*/	{v_paste,	CURSOR_CNT_CMD,	NO_FLAGS},
X/*  Q  quit to EX mode	*/	{v_quit,	NO_ARGS,	NO_FLAGS},
X/*  R  overtype		*/	{v_overtype,	CURSOR,		SDOT},
X/*  S  change line	*/	{v_change,	CURSOR_MOVED,	SDOT},
X#ifndef NO_CHARSEARCH
X/*  T  move bk to char	*/	{m_Tch,		CURSOR_CNT_KEY,	MVMT|INCL},
X#else
X/*  T  not defined	*/	{NO_FUNC,	NO_ARGS,	NO_FLAGS},
X#endif
X/*  U  undo whole line	*/	{v_undoline,	CURSOR,		FRNT},
X/*  V  not defined	*/	{NO_FUNC,	NO_ARGS,	NO_FLAGS},
X/*  W  move forward Word*/	{m_fword,	CURSOR_CNT_CMD,	MVMT},
X/*  X  delete to left	*/	{v_xchar,	CURSOR_CNT_CMD,	SDOT},
X/*  Y  yank text	*/	{v_yank,	CURSOR_MOVED,	NCOL},
X/*  Z  save file & exit	*/	{v_xit,		CURSOR_CNT_KEY,	NO_FLAGS},
X/*  [  move back section*/	{m_bsection,	CURSOR_CNT_KEY,	MVMT|LNMD|NREL},
X/*  \  not defined	*/	{NO_FUNC,	NO_ARGS,	NO_FLAGS},
X/*  ]  move fwd section */	{m_fsection,	CURSOR_CNT_KEY,	MVMT|LNMD|NREL},
X/*  ^  move to front	*/	{m_front,	CURSOR,		MVMT},
X/*  _  not defined	*/	{NO_FUNC,	NO_ARGS,	NO_FLAGS},
X/*  `  move to mark	*/	{m_tomark,	CURSOR_CNT_KEY,	MVMT|NREL},
X/*  a  append at cursor	*/	{v_insert,	CURSOR_CNT_CMD,	SDOT},
X/*  b  move back word	*/	{m_bword,	CURSOR_CNT_CMD,	MVMT},
X/*  c  change text	*/	{v_change,	CURSOR_MOVED,	SDOT},
X/*  d  delete op	*/	{v_delete,	CURSOR_MOVED,	SDOT|NCOL},
X/*  e  move end word	*/	{m_eword,	CURSOR_CNT_CMD,	MVMT|INCL},
X#ifndef NO_CHARSEARCH
X/*  f  move fwd for char*/	{m_fch,		CURSOR_CNT_KEY,	MVMT|INCL},
X#else
X/*  f  not defined	*/	{NO_FUNC,	NO_ARGS,	NO_FLAGS},
X#endif
X/*  g  not defined	*/	{NO_FUNC,	NO_ARGS,	NO_FLAGS},
X/*  h  move left	*/	{m_left,	CURSOR_COUNT,	MVMT},
X/*  i  insert at cursor	*/	{v_insert,	CURSOR_CNT_CMD,	SDOT},
X/*  j  move down	*/	{m_updnto,	CURSOR_CNT_CMD,	MVMT|NCOL|LNMD},
X/*  k  move up		*/	{m_updnto,	CURSOR_CNT_CMD,	MVMT|NCOL|LNMD},
X/*  l  move right	*/	{m_right,	CURSOR_COUNT,	MVMT},
X/*  m  define a mark	*/	{v_mark,	CURSOR_CNT_KEY,	NO_FLAGS},
X/*  n  repeat prev srch	*/	{m_nsrch,	CURSOR, 	MVMT},
X/*  o  insert below line*/	{v_insert,	CURSOR_CNT_CMD,	SDOT},
X/*  p  paste after	*/	{v_paste,	CURSOR_CNT_CMD,	NO_FLAGS},
X/*  q  not defined	*/	{NO_FUNC,	NO_ARGS,	NO_FLAGS},
X/*  r  replace chars	*/	{v_replace,	CURSOR_CNT_KEY,	SDOT},
X/*  s  subst N chars	*/	{v_subst,	CURSOR_COUNT,	SDOT},
X#ifndef NO_CHARSEARCH
X/*  t  move fwd to char	*/	{m_tch,		CURSOR_CNT_KEY,	MVMT|INCL},
X#else
X/*  t  not defined	*/	{NO_FUNC,	NO_ARGS,	NO_FLAGS},
X#endif
X/*  u  undo		*/	{v_undo,	CURSOR,		NO_FLAGS},
X/*  v  not defined	*/	{NO_FUNC,	NO_ARGS,	NO_FLAGS},
X/*  w  move fwd word	*/	{m_fword,	CURSOR_CNT_CMD,	MVMT},
X/*  x  delete character	*/	{v_xchar,	CURSOR_CNT_CMD,	SDOT},
X/*  y  yank text	*/	{v_yank,	CURSOR_MOVED,	NCOL},
X/*  z  adjust scrn row	*/	{m_z, 		CURSOR_CNT_KEY,	NCOL},
X/*  {  back paragraph	*/	{m_bparagraph,	CURSOR_COUNT,	MVMT|LNMD},
X/*  |  move to column	*/	{m_tocol,	CURSOR_COUNT,	NREL},
X/*  }  fwd paragraph	*/	{m_fparagraph,	CURSOR_COUNT,	MVMT|LNMD},
X/*  ~  upper/lowercase	*/	{v_ulcase,	CURSOR_COUNT,	SDOT},
X/* DEL not defined	*/	{NO_FUNC,	NO_ARGS,	NO_FLAGS}
X};
X
X
X
Xvoid vi()
X{
X	REG int			key;	/* keystroke from user */
X	long			count;	/* numeric argument to some functions */
X	REG struct keystru	*keyptr;/* pointer to vikeys[] element */
X	MARK			tcurs;	/* temporary cursor */
X	int			prevkey;/* previous key, if d/c/y/</>/! */
X	MARK			range;	/* start of range for d/c/y/</>/! */
X	char			text[100];
X	int			dotkey;	/* last "key" of a change */
X	int			dotpkey;/* last "prevkey" of a change */
X	int			dotkey2;/* last extra "getkey()" of a change */
X	int			dotcnt;	/* last "count" of a change */
X	int			firstkey;
X	REG int			i;
X
X	/* tell the redraw() function to start from scratch */
X	redraw(MARK_UNSET, FALSE);
X
X#ifdef lint
X	/* lint says that "range" might be used before it is set.  This
X	 * can't really happen due to the way "range" and "prevkey" are used,
X	 * but lint doesn't know that.  This line is here ONLY to keep lint
X	 * happy.
X	 */
X	range = 0L;
X#endif
X
X	/* safeguard against '.' with no previous command */
X	dotkey = 0;
X
X	/* go immediately into insert mode, if ":set inputmode" */
X	firstkey = 0;
X#ifndef NO_EXTENSIONS
X	if (*o_inputmode)
X	{
X		firstkey = 'i';
X	}
X#endif
X
X	/* Repeatedly handle VI commands */
X	for (count = 0, prevkey = '\0'; mode == MODE_VI; )
X	{
X		/* if we've moved off the undoable line, then we can't undo it at all */
X		if (markline(cursor) != U_line)
X		{
X			U_line = 0L;
X		}
X
X		/* report any changes from the previous command */
X		if (rptlines >= *o_report)
X		{
X			redraw(cursor, FALSE);
X			msg("%ld lines %s", rptlines, rptlabel);
X		}
X		rptlines = 0L;
X
X		/* get the next command key.  It must be ASCII */
X		if (firstkey)
X		{
X			key = firstkey;
X			firstkey = 0;
X		}
X		else
X		{
X			do
X			{
X				key = getkey(WHEN_VICMD);
X			} while (key < 0 || key > 127);
X		}
X
X		/* change cw and cW commands to ce and cE, respectively */
X		/* (Why?  because the real vi does it that way!) */
X		if (prevkey == 'c')
X		{
X			if (key == 'w')
X				key = 'e';
X			else if (key == 'W')
X				key = 'E';
X
X			/* wouldn't work right at the end of a word unless we
X			 * backspace one character before doing the move.  This
X			 * will fix most cases.  !!! but not all.
X			 */
X			if (markidx(cursor) > 0 && (key == 'e' || key == 'E'))
X			{
X				cursor--;
X			}
X		}
X
X		/* look up the structure describing this command */
X		keyptr = &vikeys[key];
X
X		/* if we're in the middle of a d/c/y/</>/! command, reject
X		 * anything but movement or a doubled version like "dd".
X		 */
X		if (prevkey && key != prevkey && !(keyptr->flags & (MVMT|PTMV)))
X		{
X			beep();
X			prevkey = 0;
X			count = 0;
X			continue;
X		}
X
X		/* set the "dot" variables, if we're supposed to */
X		if ((keyptr->flags & SDOT)
X		 || (prevkey && vikeys[prevkey].flags & SDOT))
X		{
X			dotkey = key;
X			dotpkey = prevkey;
X			dotkey2 = '\0';
X			dotcnt = count;
X
X			/* remember the line before any changes are made */
X			if (U_line != markline(cursor))
X			{
X				U_line = markline(cursor);
X				strcpy(U_text, fetchline(U_line));
X			}
X		}
X
X		/* if this is "." then set other vars from the "dot" vars */
X		if (key == '.')
X		{
X			key = dotkey;
X			keyptr = &vikeys[key];
X			prevkey = dotpkey;
X			if (prevkey)
X			{
X				range = cursor;
X			}
X			if (count == 0)
X			{
X				count = dotcnt;
X			}
X			doingdot = TRUE;
X
X			/* remember the line before any changes are made */
X			if (U_line != markline(cursor))
X			{
X				U_line = markline(cursor);
X				strcpy(U_text, fetchline(U_line));
X			}
X		}
X		else
X		{
X			doingdot = FALSE;
X		}
X
X		/* process the key as a command */
X		tcurs = cursor;
X		switch (keyptr->args)
X		{
X		  case ZERO:
X			if (count == 0)
X			{
X				tcurs = cursor & ~(BLKSIZE - 1);
X				break;
X			}
X			/* else fall through & treat like other digits... */
X
X		  case DIGIT:
X			count = count * 10 + key - '0';
X			break;
X
X		  case KEYWORD:
X			/* if not on a keyword, fail */
X			pfetch(markline(cursor));
X			key = markidx(cursor);
X			if (isascii(ptext[key])
X				&& !isalnum(ptext[key]) && ptext[key] != '_')
X			{
X				tcurs = MARK_UNSET;
X				break;
X			}
X
X			/* find the start of the keyword */
X			while (key > 0 && (!isascii(ptext[key-1]) ||
X			isalnum(ptext[key - 1]) || ptext[key - 1] == '_'))
X			{
X				key--;
X			}
X			tcurs = (cursor & ~(BLKSIZE - 1)) + key;
X
X			/* copy it into a buffer, and NUL-terminate it */
X			i = 0;
X			do
X			{
X				text[i++] = ptext[key++];
X			} while (!isascii(ptext[key]) || isalnum(ptext[key]) || ptext[key] == '_');
X			text[i] = '\0';
X
X			/* call the function */
X			tcurs = (*keyptr->func)(text, tcurs, count);
X			count = 0L;
X			break;
X
X		  case NO_ARGS:
X			if (keyptr->func)
X			{
X				(*keyptr->func)();
X			}
X			else
X			{
X				beep();
X			}
X			count = 0L;
X			break;
X	
X		  case CURSOR_COUNT:
X			tcurs = (*keyptr->func)(cursor, count);
X			count = 0L;
X			break;
X	
X		  case CURSOR:
X			tcurs = (*keyptr->func)(cursor);
X			count = 0L;
X			break;
X
X		  case CURSOR_CNT_KEY:
X			if (doingdot)
X			{
X				tcurs = (*keyptr->func)(cursor, count, dotkey2);
X			}
X			else
X			{
X				/* get a key */
X				i = getkey(0);
X				if (i == '\033') /* ESC */
X				{
X					count = 0;
X					tcurs = MARK_UNSET;
X					break; /* exit from "case CURSOR_CNT_KEY" */
X				}
X				else if (i == ('V' & 0x1f))
X				{
X					i = getkey(0);
X				}
X
X				/* if part of an SDOT command, remember it */
X				 if (keyptr->flags & SDOT
X				 || (prevkey && vikeys[prevkey].flags & SDOT))
X				{
X					dotkey2 = i;
X				}
X
X				/* do it */
X				tcurs = (*keyptr->func)(cursor, count, i);
X			}
X			count = 0L;
X			break;
X	
X		  case CURSOR_MOVED:
X			/* '&' and uppercase keys always act like doubled */
X			if (key == '&' || isascii(key) && isupper(key))
X			{
X				prevkey = key;
X			}
X
X			if (prevkey)
X			{
X				/* doubling up a command */
X				if (!count) count = 1L;
X				range = cursor;
X				tcurs = range + MARK_AT_LINE(count - 1L);
X				count = 0L;
X			}
X			else
X			{
X				prevkey = key;
X				range = cursor;
X				key = -1; /* so we don't think we doubled yet */
X			}
X			break;
X
X		  case CURSOR_EOL:
X			prevkey = key;
X			/* a zero-length line needs special treatment */
X			pfetch(markline(cursor));
X			if (plen == 0)
X			{
X				/* act on a zero-length section of text */
X				range = tcurs = cursor;
X				key = ' ';
X			}
X			else
X			{
X				/* act like CURSOR_MOVED with '$' movement */
X				range = cursor;
X				tcurs = m_rear(cursor, 1L);
X				key = '$';
X			}
X			count = 0L;
X			keyptr = &vikeys[key];
X			break;
X
X		  case CURSOR_TEXT:
X		  	do
X		  	{	
X				text[0] = key;
X				if (vgets(key, text + 1, sizeof text - 1) >= 0)
X				{
X					/* reassure user that <CR> was hit */
X					qaddch('\r');
X					refresh();
X
X					/* call the function with the text */
X					tcurs = (*keyptr->func)(cursor, text);
X				}
X				else
X				{
X					if (exwrote || mode == MODE_COLON)
X					{
X						redraw(MARK_UNSET, FALSE);
X					}
X					mode = MODE_VI;
X				}
X			} while (mode == MODE_COLON);
X			count = 0L;
X			break;
X
X		  case CURSOR_CNT_CMD:
X			tcurs = (*keyptr->func)(cursor, count, key);
X			count = 0L;
X			break;
X		}
X
X		/* if that command took us out of vi mode, then exit the loop
X		 * NOW, without tweaking the cursor or anything.  This is very
X		 * important when mode == MODE_QUIT.
X		 */
X		if (mode != MODE_VI)
X		{
X			break;
X		}
X
X		/* now move the cursor, as appropriate */
X		if (keyptr->args == CURSOR_MOVED)
X		{
X			/* the < and > keys have FRNT,
X			 * but it shouldn't be applied yet
X			 */
X			tcurs = adjmove(cursor, tcurs, 0);
X		}
X		else
X		{
X			tcurs = adjmove(cursor, tcurs, (int)keyptr->flags);
X		}
X
X		/* was that the end of a d/c/y/</>/! command? */
X		if (prevkey && (prevkey == key || (keyptr->flags & MVMT)) && count == 0L)
X		{
X			/* if the movement command failed, cancel operation */
X			if (tcurs == MARK_UNSET)
X			{
X				prevkey = 0;
X				count = 0;
X				continue;
X			}
X
X			/* make sure range=front and tcurs=rear.  Either way,
X			 * leave cursor=range since that's where we started.
X			 */
X			cursor = range;
X			if (tcurs < range)
X			{
X				range = tcurs;
X				tcurs = cursor;
X			}
X
X
X			/* adjust for line mode & inclusion of last char/line */
X			i = (keyptr->flags | vikeys[prevkey].flags);
X			if (key == prevkey)
X			{
X				i |= (INCL|LNMD);
X			}
X			switch (i & (INCL|LNMD))
X			{
X			  case INCL:
X				tcurs++;
X				break;
X
X			  case INCL|LNMD:
X				tcurs += BLKSIZE;
X				/* fall through... */
X
X			  case LNMD:
X				range &= ~(BLKSIZE - 1);
X				tcurs &= ~(BLKSIZE - 1);
X				break;
X			}
X
X			/* run the function */
X			tcurs = (*vikeys[prevkey].func)(range, tcurs);
X			(void)adjmove(cursor, cursor, 0);
X			cursor = adjmove(cursor, tcurs, (int)vikeys[prevkey].flags);
X
X			/* cleanup */
X			prevkey = 0;
X		}
X		else if (!prevkey)
X		{
X			cursor = tcurs;
X		}
X	}
X}
X
X/* This function adjusts the MARK value that they return; here we make sure
X * it isn't past the end of the line, and that the column hasn't been
X * *accidentally* changed.
X */
XMARK adjmove(old, new, flags)
X	MARK		old;	/* the cursor position before the command */
X	REG MARK	new;	/* the cursor position after the command */
X	int		flags;	/* various flags regarding cursor mvmt */
X{
X	static int	colno;	/* the column number that we want */
X	REG char	*text;	/* used to scan through the line's text */
X	REG int		i;
X
X#ifdef DEBUG
X	watch();
X#endif
X
X	/* if the command failed, bag it! */
X	if (new == MARK_UNSET)
X	{
X		beep();
X		return old;
X	}
X
X	/* if this is a non-relative movement, set the '' mark */
X	if (flags & NREL)
X	{
X		mark[26] = old;
X	}
X
X	/* make sure it isn't past the end of the file */
X	if (markline(new) < 1)
X	{
X		new = MARK_FIRST;
X	}
X	else if (markline(new) > nlines)
X	{
X		new = MARK_LAST;
X	}
X
X	/* fetch the new line */
X	pfetch(markline(new));
X
X	/* move to the front, if we're supposed to */
X	if (flags & FRNT)
X	{
X		new = m_front(new, 1L);
X	}
X
X	/* change the column#, or change the mark to suit the column# */
X	if (!(flags & NCOL))
X	{
X		/* change the column# */
X		i = markidx(new);
X		if (i == BLKSIZE - 1)
X		{
X			new &= ~(BLKSIZE - 1);
X			if (plen > 0)
X			{
X				new += plen - 1;
X			}
X			colno = BLKSIZE * 8; /* one heck of a big colno */
X		}
X		else if (plen > 0)
X		{
X			if (i >= plen)
X			{
X				new = (new & ~(BLKSIZE - 1)) + plen - 1;
X			}
X			colno = idx2col(new, ptext, FALSE);
X		}
X		else
X		{
X			new &= ~(BLKSIZE - 1);
X			colno = 0;
X		}
X	}
X	else
X	{
X		/* adjust the mark to get as close as possible to column# */
X		for (i = 0, text = ptext; i <= colno && *text; text++)
X		{
X			if (*text == '\t' && !*o_list)
X			{
X				i += *o_tabstop - (i % *o_tabstop);
X			}
X			else if (UCHAR(*text) < ' ' || *text == 127)
X			{
X				i += 2;
X			}
X#ifndef NO_CHARATTR
X			else if (*o_charattr && text[0] == '\\' && text[1] == 'f' && text[2])
X			{
X				text += 2; /* plus one more in "for()" stmt */
X			}
X#endif
X			else
X			{
X				i++;
X			}
X		}
X		if (text > ptext)
X		{
X			text--;
X		}
X		new = (new & ~(BLKSIZE - 1)) + (int)(text - ptext);
X	}
X
X	return new;
X}
X
X
X#ifdef DEBUG
Xwatch()
X{
X	static wasset;
X
X	if (*origname)
X	{
X		wasset = TRUE;
X	}
X	else if (wasset)
X	{
X		msg("origname was clobbered");
X		endwin();
X		abort();
X	}
X
X	if (nlines == 0)
X	{
X		msg("nlines=0");
X		endwin();
X		abort();
X	}
X}
X#endif
eof
if test `wc -c <vi.c` -ne 20322
then
echo vi.c damaged!
fi
fi

if test -f vi.h -a "$1" != -f
then
echo Will not overwrite vi.h
else
echo Extracting vi.h
sed 's/^X//' >vi.h <<\eof
X/* vi.h */
X
X/* Author:
X *	Steve Kirkendall
X *	14407 SW Teal Blvd. #C
X *	Beaverton, OR 97005
X *	kirkenda at cs.pdx.edu
X */
X
X
X/* This is the header file for my version of vi. */
X
X#define VERSION "ELVIS 1.4, by Steve Kirkendall"
X#define COPYING	"This version of ELVIS is freely redistributable."
X
X#include <errno.h>
Xextern int errno;
X#if TOS
X#define ENOENT (-AEFILNF)
X#endif
X
X#if TOS
X# include <types.h>
X# define O_RDONLY	0
X# define O_WRONLY	1
X# define O_RDWR		2
X#else
X# if OSK
X#  include <modes.h>
X#  define O_RDONLY	S_IREAD
X#  define O_WRONLY	S_IWRITE
X#  define O_RDWR	(S_IREAD | S_IWRITE)
X#  define ENOENT	E_PNNF
X# else
X#  include <sys/types.h>
X#  if COHERENT
X#   include <sys/fcntl.h>
X#  else
X#   include <fcntl.h>
X#  endif
X# endif
X#endif
X
X#ifndef O_BINARY
X# define O_BINARY	0
X#endif
X
X#include "curses.h"
X
X/*------------------------------------------------------------------------*/
X/* Miscellaneous constants.						  */
X
X#define INFINITY	2000000001L	/* a very large integer */
X#define LONGKEY		10		/* longest possible raw :map key */
X#ifndef MAXRCLEN
X# define MAXRCLEN	1000		/* longest possible .exrc file */
X#endif
X
X/*------------------------------------------------------------------------*/
X/* These describe how temporary files are divided into blocks             */
X
X#define BLKSIZE	1024		/* size of blocks */
X#define MAXBLKS	(BLKSIZE / sizeof(unsigned short))
Xtypedef union
X{
X	char		c[BLKSIZE];	/* for text blocks */
X	unsigned short	n[MAXBLKS];	/* for the header block */
X}
X	BLK;
X
X/*------------------------------------------------------------------------*/
X/* These are used manipulate BLK buffers.                                 */
X
Xextern BLK	hdr;		/* buffer for the header block */
Xextern BLK	*blkget();	/* given index into hdr.c[], reads block */
Xextern BLK	*blkadd();	/* inserts a new block into hdr.c[] */
X
X/*------------------------------------------------------------------------*/
X/* These are used to keep track of various flags                          */
Xextern struct _viflags
X{
X	short	file;		/* file flags */
X}
X	viflags;
X
X/* file flags */
X#define NEWFILE		0x0001	/* the file was just created */
X#define READONLY	0x0002	/* the file is read-only */
X#define HADNUL		0x0004	/* the file contained NUL characters */
X#define MODIFIED	0x0008	/* the file has been modified */
X#define NOFILE		0x0010	/* no name is known for the current text */
X#define ADDEDNL		0x0020	/* newlines were added to the file */
X
X/* macros used to set/clear/test flags */
X#define setflag(x,y)	viflags.x |= y
X#define clrflag(x,y)	viflags.x &= ~y
X#define tstflag(x,y)	(viflags.x & y)
X#define initflags()	viflags.file = 0;
X
X/* The options */
Xextern char	o_autoindent[1];
Xextern char	o_autoprint[1];
Xextern char	o_autowrite[1];
X#ifndef NO_ERRLIST
Xextern char	o_cc[30];
X#endif
X#ifndef NO_CHARATTR
Xextern char	o_charattr[1];
X#endif
Xextern char	o_columns[3];
Xextern char	o_digraph[1];
Xextern char	o_directory[30];
Xextern char	o_edcompatible[1];
Xextern char	o_errorbells[1];
Xextern char	o_exrefresh[1];
X#ifndef NO_DIGRAPH
Xextern char	o_flipcase[80];
X#endif
X#ifndef NO_SENTENCE
Xextern char	o_hideformat[1];
X#endif
Xextern char	o_ignorecase[1];
X#ifndef NO_EXTENSIONS
Xextern char	o_inputmode[1];
X#endif
Xextern char	o_keytime[3];
Xextern char	o_keywordprg[80];
Xextern char	o_lines[3];
Xextern char	o_list[1];
X#ifndef NO_MAGIC
Xextern char	o_magic[1];
X#endif
X#ifndef NO_ERRLIST
Xextern char	o_make[30];
X#endif
X#ifndef NO_MODELINE
Xextern char	o_modeline[1];
X#endif
X#ifndef NO_SENTENCE
Xextern char	o_paragraphs[30];
X#endif
X#if MSDOS
Xextern char	o_pcbios[1];
X#endif
Xextern char	o_readonly[1];
Xextern char	o_report[3];
Xextern char	o_scroll[3];
X#ifndef NO_SENTENCE
Xextern char	o_sections[30];
X#endif
Xextern char	o_shell[60];
X#ifndef NO_SHOWMATCH
Xextern char	o_showmatch[1];
X#endif
X#ifndef NO_SHOWMODE
Xextern char	o_smd[1];
X#endif
Xextern char	o_shiftwidth[3];
Xextern char	o_sidescroll[3];
Xextern char	o_sync[1];
Xextern char	o_tabstop[3];
Xextern char	o_term[30];
Xextern char	o_vbell[1];
Xextern char	o_warn[1];
Xextern char	o_wrapmargin[3];
Xextern char	o_wrapscan[1];
X
X/*------------------------------------------------------------------------*/
X/* These help support the single-line multi-change "undo" -- shift-U      */
X
Xextern char	U_text[BLKSIZE];
Xextern long	U_line;
X
X/*------------------------------------------------------------------------*/
X/* These are used to refer to places in the text 			  */
X
Xtypedef long	MARK;
X#define markline(x)	(long)((x) / BLKSIZE)
X#define markidx(x)	(int)((x) & (BLKSIZE - 1))
X#define MARK_UNSET	((MARK)0)
X#define MARK_FIRST	((MARK)BLKSIZE)
X#define MARK_LAST	((MARK)(nlines * BLKSIZE))
X#define MARK_AT_LINE(x)	((MARK)((x) * BLKSIZE))
X
X#define NMARKS	29
Xextern MARK	mark[NMARKS];	/* marks a-z, plus mark ' and two temps */
Xextern MARK	cursor;		/* mark where line is */
X
X/*------------------------------------------------------------------------*/
X/* These are used to keep track of the current & previous files.	  */
X
Xextern long	origtime;	/* modification date&time of the current file */
Xextern char	origname[256];	/* name of the current file */
Xextern char	prevorig[256];	/* name of the preceding file */
Xextern long	prevline;	/* line number from preceding file */
X
X/*------------------------------------------------------------------------*/
X/* misc housekeeping variables & functions				  */
X
Xextern int	tmpfd;		/* fd used to access the tmp file */
Xextern long	lnum[MAXBLKS];	/* last line# of each block */
Xextern long	nlines;		/* number of lines in the file */
Xextern char	args[BLKSIZE];	/* file names given on the command line */
Xextern int	argno;		/* the current element of args[] */
Xextern int	nargs;		/* number of filenames in args */
Xextern long	changes;	/* counts changes, to prohibit short-cuts */
Xextern int	significant;	/* boolean: was a *REAL* change made? */
Xextern int	mustredraw;	/* boolean: force total redraw of screen? */
Xextern BLK	tmpblk;		/* a block used to accumulate changes */
Xextern long	topline;	/* file line number of top line */
Xextern int	leftcol;	/* column number of left col */
X#define		botline	 (topline + LINES - 2)
X#define		rightcol (leftcol + COLS - 1)
Xextern int	physcol;	/* physical column number that cursor is on */
Xextern int	physrow;	/* physical row number that cursor is on */
Xextern int	exwrote;	/* used to detect verbose ex commands */
Xextern int	doingdot;	/* boolean: are we doing the "." command? */
Xextern int	doingglobal;	/* boolean: are doing a ":g" command? */
Xextern long	rptlines;	/* number of lines affected by a command */
Xextern char	*rptlabel;	/* description of how lines were affected */
Xextern char	*fetchline();	/* read a given line from tmp file */
Xextern char	*parseptrn();	/* isolate a regexp in a line */
Xextern MARK	paste();	/* paste from cut buffer to a given point */
Xextern char	*wildcard();	/* expand wildcards in filenames */
Xextern MARK	input();	/* inserts characters from keyboard */
Xextern char	*linespec();	/* finds the end of a /regexp/ string */
X#define		ctrl(ch) ((ch)&037)
X#ifndef NO_RECYCLE
Xextern long	allocate();	/* allocate a free block of the tmp file */
X#endif
Xextern int	trapint();	/* trap handler for SIGINT */
Xextern void	blkdirty();	/* marks a block as being "dirty" */
Xextern void	blkflush();	/* writes a single dirty block to the disk */
Xextern void	blksync();	/* forces all "dirty" blocks to disk */
Xextern void	blkinit();	/* resets the block cache to "empty" state */
Xextern void	beep();		/* rings the terminal's bell */
Xextern void	exrefresh();	/* writes text to the screen */
Xextern void	msg();		/* writes a printf-style message to the screen */
Xextern void	reset_msg();	/* resets the "manymsgs" flag */
Xextern void	endmsgs();	/* if "manymsgs" is set, then scroll up 1 line */
Xextern void	garbage();	/* reclaims any garbage blocks */
Xextern void	redraw();	/* updates the screen after a change */
Xextern void	resume_curses();/* puts the terminal in "cbreak" mode */
Xextern void	beforedo();	/* saves current revision before a new change */
Xextern void	afterdo();	/* marks end of a beforedo() change */
Xextern void	abortdo();	/* like "afterdo()" followed by "undo()" */
Xextern int	undo();		/* restores file to previous undo() */
Xextern void	dumpkey();	/* lists key mappings to the screen */
Xextern void	mapkey();	/* defines a new key mapping */
Xextern void	savekeys();	/* lists key mappings to a file */
Xextern void	redrawrange();	/* records clues from modify.c */
Xextern void	cut();		/* saves text in a cut buffer */
Xextern void	delete();	/* deletes text */
Xextern void	add();		/* adds text */
Xextern void	change();	/* deletes text, and then adds other text */
Xextern void	cutswitch();	/* updates cut buffers when we switch files */
Xextern void	do_abbr();	/* defines or lists abbreviations */
Xextern void	do_digraph();	/* defines or lists digraphs */
Xextern void	exstring();	/* execute a string as EX commands */
Xextern void	dumpopts();
Xextern void	setopts();
Xextern void	saveopts();
X#ifndef NO_DIGRAPH
Xextern void	savedigs();
X#endif
X#ifndef NO_ABBR
Xextern void	saveabbr();
X#endif
Xextern void	cutname();
Xextern void	cutname();
Xextern void	initopts();
Xextern void	cutend();
X
X/*------------------------------------------------------------------------*/
X/* macros that are used as control structures                             */
X
X#define BeforeAfter(before, after) for((before),bavar=1;bavar;(after),bavar=0)
X#define ChangeText	BeforeAfter(beforedo(FALSE),afterdo())
X
Xextern int	bavar;		/* used only in BeforeAfter macros */
X
X/*------------------------------------------------------------------------*/
X/* These are the movement commands.  Each accepts a mark for the starting */
X/* location & number and returns a mark for the destination.		  */
X
Xextern MARK	m_updnto();		/* k j G */
Xextern MARK	m_right();		/* h */
Xextern MARK	m_left();		/* l */
Xextern MARK	m_tocol();		/* | */
Xextern MARK	m_front();		/* ^ */
Xextern MARK	m_rear();		/* $ */
Xextern MARK	m_fword();		/* w */
Xextern MARK	m_bword();		/* b */
Xextern MARK	m_eword();		/* e */
Xextern MARK	m_fWord();		/* W */
Xextern MARK	m_bWord();		/* B */
Xextern MARK	m_eWord();		/* E */
Xextern MARK	m_fparagraph();		/* } */
Xextern MARK	m_bparagraph();		/* { */
Xextern MARK	m_fsection();		/* ]] */
Xextern MARK	m_bsection();		/* [[ */
Xextern MARK	m_match();		/* % */
X#ifndef NO_SENTENCE
X extern MARK	m_fsentence();		/* ) */
X extern MARK	m_bsentence();		/* ( */
X#endif
Xextern MARK	m_tomark();		/* 'm */
Xextern MARK	m_nsrch();		/* n */
Xextern MARK	m_Nsrch();		/* N */
Xextern MARK	m_fsrch();		/* /regexp */
Xextern MARK	m_bsrch();		/* ?regexp */
X#ifndef NO_CHARSEARCH
X extern MARK	m__ch();		/* ; , */
X extern MARK	m_fch();		/* f */
X extern MARK	m_tch();		/* t */
X extern MARK	m_Fch();		/* F */
X extern MARK	m_Tch();		/* T */
X#endif
Xextern MARK	m_row();		/* H L M */
Xextern MARK	m_z();			/* z */
Xextern MARK	m_scroll();		/* ^B ^F ^E ^Y ^U ^D */
X
X/* Some stuff that is used by movement functions... */
X
Xextern MARK	adjmove();		/* a helper fn, used by move fns */
X
X/* This macro is used to set the default value of cnt */
X#define DEFAULT(val)	if (cnt < 1) cnt = (val)
X
X/* These are used to minimize calls to fetchline() */
Xextern int	plen;	/* length of the line */
Xextern long	pline;	/* line number that len refers to */
Xextern long	pchgs;	/* "changes" level that len refers to */
Xextern char	*ptext;	/* text of previous line, if valid */
Xextern void	pfetch();
Xextern char	digraph();
X
X/* This is used to build a MARK that corresponds to a specific point in the
X * line that was most recently pfetch'ed.
X */
X#define buildmark(text)	(MARK)(BLKSIZE * pline + (int)((text) - ptext))
X
X
X/*------------------------------------------------------------------------*/
X/* These are used to handle EX commands.				  */
X
X#define  CMD_NULL	0	/* NOT A VALID COMMAND */
X#define  CMD_ABBR	1	/* "define an abbreviation" */
X#define  CMD_ARGS	2	/* "show me the args" */
X#define  CMD_APPEND	3	/* "insert lines after this line" */
X#define  CMD_AT		4	/* "execute a cut buffer's contents via EX" */
X#define  CMD_BANG	5	/* "run a single shell command" */
X#define  CMD_CC		6	/* "run `cc` and then do CMD_ERRLIST" */
X#define  CMD_CD		7	/* "change directories" */
X#define  CMD_CHANGE	8	/* "change some lines" */
X#define  CMD_COPY	9	/* "copy the selected text to a given place" */
X#define  CMD_DELETE	10	/* "delete the selected text" */
X#define  CMD_DIGRAPH	11	/* "add a digraph, or display them all" */
X#define  CMD_EDIT	12	/* "switch to a different file" */
X#define  CMD_EQUAL	13	/* "display a line number" */
X#define  CMD_ERRLIST	14	/* "locate the next error in a list" */
X#define  CMD_FILE	15	/* "show the file's status" */
X#define  CMD_GLOBAL	16	/* "globally search & do a command" */
X#define  CMD_INSERT	17	/* "insert lines before the current line" */
X#define  CMD_JOIN	18	/* "join the selected line & the one after" */
X#define  CMD_LIST	19	/* "print lines, making control chars visible" */
X#define  CMD_MAKE	20	/* "run `make` and then do CMD_ERRLIST" */
X#define  CMD_MAP	21	/* "adjust the keyboard map" */
X#define  CMD_MARK	22	/* "mark this line" */
X#define  CMD_MKEXRC	23	/* "make a .exrc file" */
X#define  CMD_MOVE	24	/* "move the selected text to a given place" */
X#define  CMD_NEXT	25	/* "switch to next file in args" */
X#define  CMD_NUMBER	26	/* "print lines from the file w/ line numbers" */
X#define  CMD_PRESERVE	27	/* "act as though vi crashed" */
X#define  CMD_PREVIOUS	28	/* "switch to the previous file in args" */
X#define  CMD_PRINT	29	/* "print the selected text" */
X#define  CMD_PUT	30	/* "insert any cut lines before this line" */
X#define  CMD_QUIT	31	/* "quit without writing the file" */
X#define  CMD_READ	32	/* "append the given file after this line */
X#define  CMD_RECOVER	33	/* "recover file after vi crashes" - USE -r FLAG */
X#define  CMD_REWIND	34	/* "rewind to first file" */
X#define  CMD_SET	35	/* "set a variable's value" */
X#define  CMD_SHELL	36	/* "run some lines through a command" */
X#define  CMD_SHIFTL	37	/* "shift lines left" */
X#define  CMD_SHIFTR	38	/* "shift lines right" */
X#define  CMD_SOURCE	39	/* "interpret a file's contents as ex commands" */
X#define  CMD_STOP	40	/* same as CMD_SUSPEND */
X#define  CMD_SUBAGAIN	41	/* "repeat the previous substitution" */
X#define  CMD_SUBSTITUTE	42	/* "substitute text in this line" */
X#define  CMD_SUSPEND	43	/* "suspend the vi session" */
X#define  CMD_TR		44	/* "transliterate chars in the selected lines" */
X#define  CMD_TAG	45	/* "go to a particular tag" */
X#define  CMD_UNABBR	46	/* "remove an abbreviation definition" */
X#define  CMD_UNDO	47	/* "undo the previous command" */
X#define  CMD_UNMAP	48	/* "remove a key sequence map */
X#define  CMD_VERSION	49	/* "describe which version this is" */
X#define  CMD_VGLOBAL	50	/* "apply a cmd to lines NOT containing an RE" */
X#define  CMD_VISUAL	51	/* "go into visual mode" */
X#define  CMD_WQUIT	52	/* "write this file out (any case) & quit" */
X#define  CMD_WRITE	53	/* "write the selected(?) text to a given file" */
X#define  CMD_XIT	54	/* "write this file out (if modified) & quit" */
X#define  CMD_YANK	55	/* "copy the selected text into the cut buffer" */
X#ifdef DEBUG
X# define CMD_DEBUG	56	/* access to internal data structures */
X# define CMD_VALIDATE	57	/* check for internal consistency */
X#endif
Xtypedef int CMD;
X
Xextern void	ex();
Xextern void	vi();
Xextern void	doexcmd();
X
X#ifndef NO_ABBR
Xextern void	cmd_abbr();
X#endif
Xextern void	cmd_append();
Xextern void	cmd_args();
X#ifndef NO_AT
Xextern void	cmd_at();
X#endif
Xextern void	cmd_cd();
Xextern void	cmd_delete();
X#ifndef NO_DIGRAPH
Xextern void	cmd_digraph();
X#endif
Xextern void	cmd_edit();
X#ifndef NO_ERRLIST
Xextern void	cmd_errlist();
X#endif
Xextern void	cmd_file();
Xextern void	cmd_global();
Xextern void	cmd_join();
Xextern void	cmd_mark();
X#ifndef NO_ERRLIST
Xextern void	cmd_make();
X#endif
Xextern void	cmd_map();
X#ifndef NO_MKEXRC
Xextern void	cmd_mkexrc();
X#endif
Xextern void	cmd_next();
Xextern void	cmd_print();
Xextern void	cmd_put();
Xextern void	cmd_read();
Xextern void	cmd_set();
Xextern void	cmd_shell();
Xextern void	cmd_shift();
Xextern void	cmd_source();
Xextern void	cmd_substitute();
Xextern void	cmd_tag();
Xextern void	cmd_undo();
Xextern void	cmd_version();
Xextern void	cmd_visual();
Xextern void	cmd_write();
Xextern void	cmd_xit();
Xextern void	cmd_move();
X#ifdef DEBUG
Xextern void	cmd_debug();
Xextern void	cmd_validate();
X#endif
X
X/*----------------------------------------------------------------------*/
X/* These are used to handle VI commands 				*/
X
Xextern MARK	v_1ex();	/* : */
Xextern MARK	v_mark();	/* m */
Xextern MARK	v_quit();	/* Q */
Xextern MARK	v_redraw();	/* ^L ^R */
Xextern MARK	v_ulcase();	/* ~ */
Xextern MARK	v_undo();	/* u */
Xextern MARK	v_xchar();	/* x */
Xextern MARK	v_Xchar();	/* X */
Xextern MARK	v_replace();	/* r */
Xextern MARK	v_overtype();	/* R */
Xextern MARK	v_selcut();	/* " */
Xextern MARK	v_paste();	/* p P */
Xextern MARK	v_yank();	/* y Y */
Xextern MARK	v_delete();	/* d D */
Xextern MARK	v_join();	/* J */
Xextern MARK	v_insert();	/* a A i I o O */
Xextern MARK	v_change();	/* c C */
Xextern MARK	v_subst();	/* s */
Xextern MARK	v_lshift();	/* < */
Xextern MARK	v_rshift();	/* > */
Xextern MARK	v_filter();	/* ! */
Xextern MARK	v_status();	/* ^G */
Xextern MARK	v_switch();	/* ^^ */
Xextern MARK	v_tag();	/* ^] */
Xextern MARK	v_xit();	/* ZZ */
Xextern MARK	v_undoline();	/* U */
Xextern MARK	v_again();	/* & */
X#ifndef NO_EXTENSIONS
X extern MARK	v_keyword();	/* ^K */
X extern MARK	v_increment();	/* * */
X#endif
X#ifndef NO_ERRLIST
X extern MARK	v_errlist();	/* * */
X#endif
X#ifndef NO_AT
X extern MARK	v_at();		/* @ */
X#endif
X
X/*----------------------------------------------------------------------*/
X/* These describe what mode we're in */
X
X#define MODE_EX		1	/* executing ex commands */
X#define	MODE_VI		2	/* executing vi commands */
X#define	MODE_COLON	3	/* executing an ex command from vi mode */
X#define	MODE_QUIT	4
Xextern int	mode;
X
X#define WHEN_VICMD	1	/* getkey: we're reading a VI command */
X#define WHEN_VIINP	2	/* getkey: we're in VI's INPUT mode */
X#define WHEN_VIREP	4	/* getkey: we're in VI's REPLACE mode */
X#define WHEN_EX		8	/* getkey: we're in EX mode */
X#define WHEN_MSG	16	/* getkey: we're at a "more" prompt */
X#define WHEN_INMV	256	/* in input mode, interpret the key in VICMD mode */
eof
if test `wc -c <vi.h` -ne 18110
then
echo vi.h damaged!
fi
fi

if test -f refont.c -a "$1" != -f
then
echo Will not overwrite refont.c
else
echo Extracting refont.c
sed 's/^X//' >refont.c <<\eof
X/* refont.c */
X
X/* Author:
X *	Steve Kirkendall
X *	14407 SW Teal Blvd. #C
X *	Beaverton, OR 97005
X *	kirkenda at cs.pdx.edu
X */
X
X
X/* This file contains the complete source code for the refont program */
X
X/* The refont program converts font designations to the format of your choice.
X * Known font formats are:
X *	-b	overtype notation, using backspaces
X *	-c	overtype notation, using carriage returns
X *	-d	the "dot" command notation used by nroff (doesn't work well)
X *	-e	Epson-compatible line printer codes
X *	-f	the "\f" notation
X *	-x	none (strip out the font codes)
X *
X * Other flags are:
X *	-I	recognize \f and dot notations in input
X *	-F	output a formfeed character between files
X */
X
X#include <stdio.h>
X#include "config.h"
X
X/* the program name, for diagnostics */
Xchar	*progname;
X
X/* remembers which output format to use */
Xint outfmt = 'f';
X
X/* do we allow "dot" and "backslash-f" on input? */
Xint infmt = 0;
X
X/* do we insert formfeeds between input files? */
Xint add_form_feed = 0;
X
Xmain(argc, argv)
X	int	argc;	/* number of command-line args */
X	char	**argv;	/* values of the command line args */
X{
X	FILE	*fp;
X	int	i, j;
X	int	retcode;
X
X	progname = argv[0];
X
X	/* parse the flags */
X	i = 1;
X	if (i < argc && argv[i][0] == '-' && argv[i][1])
X	{
X		for (j = 1; argv[i][j]; j++)
X		{
X			switch (argv[i][j])
X			{
X			  case 'b':
X#if !OSK
X			  case 'c':
X#endif
X			  case 'd':
X			  case 'e':
X			  case 'f':
X			  case 'x':
X				outfmt = argv[i][j];
X				break;
X
X			  case 'I':
X				infmt = 'I';
X				break;
X
X			  case 'F':
X				add_form_feed = 1;
X				break;
X
X			  default:
X				usage();
X			}
X		}
X		i++;
X	}
X
X	retcode = 0;
X	if (i == argc)
X	{
X		/* probably shouldn't read from keyboard */
X		if (isatty(fileno(stdin)))
X		{
X			usage();
X		}
X
X		/* no files named, so use stdin */
X		refont(stdin);
X	}
X	else
X	{
X		for (; i < argc; i++)
X		{
X			fp = fopen(argv[i], "r");
X			if (!fp)
X			{
X				perror(argv[i]);
X				retcode = 1;
X			}
X			else
X			{
X				refont(fp);
X				if (i < argc - 1 && add_form_feed)
X				{
X					putchar('\f');
X				}
X				fclose(fp);
X			}
X		}
X	}
X
X	exit(retcode);
X}
X
Xusage()
X{
X	fputs("usage: ", stderr);
X	fputs(progname, stderr);
X	fputs(" [-bcdefxFI] [filename]...\n", stderr);
X	exit(2);
X}
X
X/* This function does the refont thing to a single file */
X/* I apologize for the length of this function.  It is gross. */
Xrefont(fp)
X	FILE	*fp;
X{
X	char	textbuf[1025];	/* chars of a line of text */
X	char	fontbuf[1025];	/* fonts of chars in fontbuf */
X	int	col;		/* where we are in the line */
X	int	font;		/* remembered font */
X	int	more;		/* more characters to be output? */
X	int	ch;
X
X	/* reset some stuff */
X	for (col = sizeof fontbuf; --col >= 0; )
X	{
X		fontbuf[col] = 'R';
X		textbuf[col] = '\0';
X	}
X	col = 0;
X	font = 'R';
X
X	/* get the first char - quit if eof */
X	while ((ch = getc(fp)) != EOF)
X	{
X		/* if "dot" command, read the rest of the command */
X		if (infmt == 'I' && ch == '.' && col == 0)
X		{
X
X			textbuf[col++] = '.';
X			textbuf[col++] = getc(fp);
X			textbuf[col++] = getc(fp);
X			textbuf[col++] = ch = getc(fp);
X
X			/* is it a font line? */
X			font = 0;
X			if (textbuf[1] == 'u' && textbuf[2] == 'l')
X			{
X				font = 'U';
X			}
X			else if (textbuf[1] == 'b' && textbuf[2] == 'o')
X			{
X				font = 'B';
X			}
X			else if (textbuf[1] == 'i' && textbuf[2] == 't')
X			{
X				font = 'I';
X			}
X
X			/* if it is, discard the stuff so far but remember font */
X			if (font)
X			{
X				while (col > 0)
X				{
X					textbuf[--col] = '\0';
X				}
X			}
X			else /* some other format line - write it literally */
X			{
X				while (ch != '\n')
X				{
X					textbuf[col++] = ch = getc(fp);
X				}
X				fputs(textbuf, fp);
X				while (col > 0)
X				{
X					textbuf[--col] = '\0';
X				}
X			}
X			continue;
X		}
X
X		/* is it a "\f" formatted font? */
X		if (infmt == 'I' && ch == '\\')
X		{
X			ch = getc(fp);
X			if (ch == 'f')
X			{
X				font = getc(fp);
X			}
X			else
X			{
X				textbuf[col++] = '\\';
X				textbuf[col++] = ch;
X			}
X			continue;
X		}
X
X		/* is it an Epson font? */
X		if (ch == '\033')
X		{
X			ch = getc(fp);
X			switch (ch)
X			{
X			  case '4':
X				font = 'I';
X				break;
X
X			  case 'E':
X			  case 'G':
X				font = 'B';
X				break;
X
X			  case '5':
X			  case 'F':
X			  case 'H':
X				font = 'R';
X				break;
X
X			  case '-':
X				font = (getc(fp) & 1) ? 'U' : 'R';
X				break;
X			}
X			continue;
X		}
X
X		/* control characters? */
X		if (ch == '\b')
X		{
X			if (col > 0)
X				col--;
X			continue;
X		}
X		else if (ch == '\t')
X		{
X			do
X			{
X				if (textbuf[col] == '\0')
X				{
X					textbuf[col] = ' ';
X				}
X				col++;
X			} while (col & 7);
X			continue;
X		}
X#if !OSK
X		else if (ch == '\r')
X		{
X			col = 0;
X			continue;
X		}
X#endif
X		else if (ch == ' ')
X		{
X			if (textbuf[col] == '\0')
X			{
X				textbuf[col] = ' ';
X				fontbuf[col] = font;
X				col++;
X			}
X			continue;
X		}
X
X		/* newline? */
X		if (ch == '\n')
X		{
X			more = 0;
X			for (col = 0, font = 'R'; textbuf[col]; col++)
X			{
X				if (fontbuf[col] != font)
X				{
X					switch (outfmt)
X					{
X					  case 'd':
X						putchar('\n');
X						switch (fontbuf[col])
X						{
X						  case 'B':
X							fputs(".bo\n", stdout);
X							break;
X
X						  case 'I':
X							fputs(".it\n", stdout);
X							break;
X
X						  case 'U':
X							fputs(".ul\n", stdout);
X							break;
X						}
X						while (textbuf[col] == ' ')
X						{
X							col++;
X						}
X						break;
X
X					  case 'e':
X						switch (fontbuf[col])
X						{
X						  case 'B':
X							fputs("\033E", stdout);
X							break;
X
X						  case 'I':
X							fputs("\0334", stdout);
X							break;
X
X						  case 'U':
X							fputs("\033-1", stdout);
X							break;
X
X						  default:
X							switch (font)
X							{
X							  case 'B':
X								fputs("\033F", stdout);
X								break;
X
X							  case 'I':
X							  	fputs("\0335", stdout);
X							  	break;
X
X							  case 'U':
X							  	fputs("\033-0", stdout);
X							  	break;
X							}
X						}
X						break;
X
X					  case 'f':
X					  	putchar('\\');
X					  	putchar('f');
X					  	putchar(fontbuf[col]);
X					  	break;
X					}
X
X					font = fontbuf[col];
X				}
X
X				if (fontbuf[col] != 'R' && textbuf[col] != ' ')
X				{
X					switch (outfmt)
X					{
X					  case 'b':
X						if (fontbuf[col] == 'B')
X						{
X							putchar(textbuf[col]);
X						}
X						else
X						{
X							putchar('_');
X						}
X						putchar('\b');
X						break;
X#if !OSK
X					  case 'c':
X					  	more = col + 1;
X					  	break;
X#endif
X					}
X				}
X
X				putchar(textbuf[col]);
X			}
X
X#if !OSK
X			/* another pass? */
X			if (more > 0)
X			{
X				putchar('\r');
X				for (col = 0; col < more; col++)
X				{
X					switch (fontbuf[col])
X					{
X					  case 'I':
X					  case 'U':
X						putchar('_');
X						break;
X
X					  case 'B':
X						putchar(textbuf[col]);
X						break;
X
X					  default:
X						putchar(' ');
X					}
X				}
X			}
X#endif /* not OSK */
X
X			/* newline */
X			if (font != 'R')
X			{
X				switch (outfmt)
X				{
X				  case 'f':
X					putchar('\\');
X					putchar('f');
X					putchar('R');
X					break;
X
X				  case 'e':
X					switch (font)
X					{
X					  case 'B':
X						fputs("\033F", stdout);
X						break;
X
X					  case 'I':
X					  	fputs("\0335", stdout);
X					  	break;
X
X					  case 'U':
X					  	fputs("\033-0", stdout);
X					  	break;
X					}
X				}
X			}
X			putchar('\n');
X
X			/* reset some stuff */
X			for (col = sizeof fontbuf; --col >= 0; )
X			{
X				fontbuf[col] = 'R';
X				textbuf[col] = '\0';
X			}
X			col = 0;
X			font = 'R';
X			continue;
X		}
X
X		/* normal character */
X		if (font != 'R')
X		{
X			textbuf[col] = ch;
X			fontbuf[col] = font;
X		}
X		else if (textbuf[col] == '_')
X		{
X			textbuf[col] = ch;
X			fontbuf[col] = 'U';
X		}
X		else if (textbuf[col] && textbuf[col] != ' ' && ch == '_')
X		{
X			fontbuf[col] = 'U';
X		}
X		else if (textbuf[col] == ch)
X		{
X			fontbuf[col] = 'B';
X		}
X		else
X		{
X			textbuf[col] = ch;
X		}
X		col++;
X	}
X}
eof
if test `wc -c <refont.c` -ne 7638
then
echo refont.c damaged!
fi
fi

exit 0
-------------------------------------------------------------------------------
Steve Kirkendall     kirkenda at cs.pdx.edu      Grad student at Portland State U.



More information about the Alt.sources mailing list